ワンクリックで
sif-playwright
Standard for Playwright e2e-oppsett i app-workspaces (config, scripts, scenario-flyt, første tester, a11y med axe).
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Standard for Playwright e2e-oppsett i app-workspaces (config, scripts, scenario-flyt, første tester, a11y med axe).
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | sif-playwright |
| type | action |
| description | Standard for Playwright e2e-oppsett i app-workspaces (config, scripts, scenario-flyt, første tester, a11y med axe). |
playwright.config.tsvite.e2e.config.tsplaywright/playwrightAppSettings.tsplaywright/utils/scenario.ts ved behovplaywright/utils/testAccessibility.tsplaywright/files/* ved behov for opplastingstesterplaywright/tests/*.spec.ts med minst to testerpackage.json: pw:dev, pw:run, pw:run:headedtsconfig.json oppdatert med Playwright-filer i include<app>/
playwright.config.ts
vite.e2e.config.ts
playwright/
playwrightAppSettings.ts
tests/
files/
utils/
scenario.ts
For BrowserRouter-apper må base path være samme verdi i alle relevante steder. Dette er et av de viktigste ferdigkriteriene for et stabilt e2e-oppsett.
src/App.tsx eller tilsvarende: BrowserRouter basenamevite.dev.config.ts: basevite.e2e.config.ts: basevite.e2e.config.ts: proxy-rewrite for mockServiceWorker.jsplaywright.config.ts: use.baseURLplaywright.config.ts: webServer.urlplaywright/playwrightAppSettings.ts: PUBLIC_PATH når appen leser path fra app settingsHvis én av disse peker til en annen path, blir navigasjon, kvittering og MSW-ressurser ustabile i Playwright.
Playwright-filer dekkes ikke av den eksisterende include-listen i appens tsconfig.json. Legg til:
"include": [
"./playwright/**/*",
"./playwright.config.ts",
"./vite.e2e.config.ts",
// ... eksisterende entries
]
Sjekk også at lib i tsconfig-kjeden inkluderer minst ES2020. Hvis delt config har en eldre lib (f.eks. es2017), overstyr lokalt:
"compilerOptions": {
"lib": ["ES2020", "DOM", "DOM.Iterable"]
}
@playwright/test@axe-core/playwright{
"pw:dev": "vite --config vite.e2e.config.ts",
"pw:run": "playwright test",
"pw:run:headed": "playwright test --headed"
}
playwright.config.tsTilpass testDir, baseURL og webServer.url til appens base-path.
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './playwright/tests',
fullyParallel: true,
retries: process.env.CI ? 2 : 0,
reporter: process.env.CI ? 'github' : 'list',
use: {
baseURL: 'http://127.0.0.1:4173/<app-base-path>/',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
webServer: {
command: 'pnpm pw:dev',
url: 'http://127.0.0.1:4173/<app-base-path>/',
reuseExistingServer: !process.env.CI,
timeout: 120_000,
},
});
vite.e2e.config.tsBruk mode: 'msw' for å aktivere MSW-mocking. Viktige punkter:
__IS_DEMO__: false for å bruke BrowserRouter (ikke HashRouter/demo-modus).__USE_FIXED_MOCKED_DATE__: true for deterministisk datodata.mockServiceWorker.js som rewrites til base-path.html-transform-plugin som erstatter {{{APP_SETTINGS}}}.import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import { resolve } from 'path';
import { defineConfig } from 'vite';
import checker from 'vite-plugin-checker';
import { getPlaywrightAppSettings } from './playwright/playwrightAppSettings';
export default defineConfig({
mode: 'msw',
plugins: [
tailwindcss(),
react({ include: '**/*.{tsx}' }),
checker({ typescript: true }),
{
name: 'crossorigin',
transformIndexHtml(html) {
return html.replace(/<link rel="stylesheet" crossorigin/g, '<link rel="stylesheet" type="text/css"');
},
},
{
name: 'html-transform',
transformIndexHtml: (html) => {
return html.replace('{{{APP_SETTINGS}}}', JSON.stringify(getPlaywrightAppSettings()));
},
},
],
resolve: {
alias: {
'@app': resolve(__dirname, './src/app'),
},
},
base: '/<app-base-path>/',
define: {
__IS_DEMO__: false,
__INJECT_DECORATOR_CLIENT_SIDE__: false,
__USE_FIXED_MOCKED_DATE__: true,
__IS_GITHUB_PAGES__: false,
},
server: {
host: '127.0.0.1',
port: 4173,
proxy: {
'/mockServiceWorker.js': {
target: 'http://127.0.0.1:4173',
rewrite: () => '/<app-base-path>/mockServiceWorker.js',
},
},
},
build: {
sourcemap: true,
},
});
playwright/playwrightAppSettings.tsBygger videre på appens getDevAppSettings() og skrur av analytics/faro:
import { AppEnv } from '../env.schema';
import { getDevAppSettings } from '../mock/devAppSettings';
export const getPlaywrightAppSettings = (): AppEnv => ({
...getDevAppSettings(),
PUBLIC_PATH: '/<app-base-path>',
SIF_PUBLIC_USE_ANALYTICS: 'false',
SIF_PUBLIC_USE_FARO: 'false',
});
Hvis appen bruker PUBLIC_PATH i routing, dekorator eller lenkebygging, skal Playwright-varianten alltid sette denne eksplisitt til samme base path som resten av e2e-oppsettet.
playwright/utils/scenario.tsSetter scenario-key i localStorage via addInitScript (kjører før appen).
Appen bruker localStorageStore.init() som leser denne keyen og genererer mockdata.
Gjenbruk alltid ScenarioType fra mock/scenarios/types i stedet for string for å sikre at testene kun kan bruke gyldige scenarioer.
import { Page } from '@playwright/test';
import { ScenarioType } from '../../mock/scenarios/types';
const SCENARIO_KEY = '<APP>_MOCK_SCENARIO';
export const setScenario = async (page: Page, scenario: ScenarioType) => {
await page.addInitScript(
({ scenarioKey, selectedScenario }) => {
window.localStorage.setItem(scenarioKey, selectedScenario);
},
{ scenarioKey: SCENARIO_KEY, selectedScenario: scenario },
);
};
SCENARIO_KEY må matche keyen appen bruker i sin localStorageStore.
⚠️
localStorageStore.initmust not overwrite Playwright-set scenario Playwright setter kun scenario-key viaaddInitScript— ikke mockdata.init()kjøres etterpå i appen. Sørg for atinit()kun skriver data hvis data mangler — aldri hvis scenario-key allerede er satt:init: (defaultScenario) => { const current = localStorage.getItem(SCENARIO_KEY); const hasData = localStorage.getItem(STORAGE_KEY) !== null; if (!current) { setScenario(defaultScenario); // ingen key satt — bruk default return; } if (!hasData) { setScenario(current); // key finnes (satt av Playwright), men data mangler } // key og data finnes — ikke gjør noe };Feilen
if (current !== defaultScenario) { setScenario(defaultScenario); }overskriver Playwright-scenario med default.
Flyten er:
setScenario(page, 'scenarioNavn') — setter kun scenario-key i localStorage.page.goto('/') starter appen — MSW aktiveres og localStorageStore.init() kjøres.init() finner scenario-key, genererer mockdata fra scenario-definisjonen og lagrer til localStorage.localStorage og returnerer korrekte API-svar.Viktig: localStorageStore.init() må håndtere tilfellet der scenario-key finnes men data mangler (Playwright setter kun key). Sørg for at init-logikken genererer data fra key alene.
For apper med mock/scenario-oppsett skal lokal/demo-kjøring ha en synlig scenariovelger, typisk src/demo/ScenarioHeader.tsx.
Hold denne delen kort og kontraktsstyrt:
ScenarioType som Playwright-testenesetScenario(page, ...)PUBLIC_PATH som resten av appenDetaljer for implementasjon og montering av ScenarioHeader hører hjemme i sif-soknad-setup eller appens eksisterende demo-oppsett, ikke i denne skillen.
Når appen bruker mellomlagring, bør første Playwright-runde inkludere én test som verifiserer gjenopptak.
Anbefalt mønster:
currentStepId og søknadsdata lagres./ på nytt eller reload siden.Dette er særlig nyttig i referanseapper, fordi det bekrefter at useInitialData, mellomlagring og routing spiller sammen.
Når appen har vedleggssteg:
playwright/files/Målet er å teste hele UI-flyten for opplasting, ikke filinnholdet.
Når appen er en referanseapp eller demo-app med forenklet lokal DTO, fungerer det best å holde innsendingen enkel og mockbar i e2e.
Anbefalt mønster:
fetchDette gjør Playwright-flyten stabil uten å binde referanseappen til runtime-validering i genererte API-klienter.
pw:dev (Vite dev med MSW og BrowserRouter).setScenario() for å velge testdata før page.goto('/').getByRole, getByLabel, getByText med tydelig tekst).goto('/').For apper med mock/scenario-støtte forventes en synlig scenariovelger i lokal/demo, men Playwright-skillen trenger bare å sikre at den følger samme scenario-kontrakt som testene.
Accessibility-sjekker er en del av standard Playwright-oppsettet.
testAccessibility helperOpprett playwright/utils/testAccessibility.ts:
import AxeBuilder from '@axe-core/playwright';
import { expect, Page } from '@playwright/test';
export const testAccessibility = async (page: Page) => {
const accessibilityScanResults = await new AxeBuilder({ page }).analyze();
await expect(accessibilityScanResults.violations).toEqual([]);
};
testAccessibility(page) etter at siden er ferdig rendret.page.goto() uten å vente på et element først.Riktig:
await page.goto('/');
await page.locator('input[type="checkbox"]').waitFor();
await testAccessibility(page);
Feil:
await page.goto('/');
await testAccessibility(page); // for tidlig — siden kan være tom
Kjør i app-workspace:
pnpm pw:run
pnpm check:types
pnpm pw:run passerer lokalt.pnpm check:types passerer lokalt.pnpm pw:run og pnpm check:types.Mønster for å kombinere flere API-hooks til én asynkron laster (useInitialData + InitialDataLoader) i sif-soknad-apper.
Legg til et nytt steg i en søknadsapp som bruker @sif/soknad og @sif/rhf — oppretter alle filer og oppdaterer config/routing/i18n.
Arkitekturreferanse og beslutningslogg for @sif/soknad-app — rammeverket for søknadsapper i sif-brukerdialog.
Sett opp OppsummeringSteg i en v2-app — DTO-basert oppsummering med FormSummary, bekreftelsescheckbox og i18n-nøkler.
Veiledning for oppsett av en ny søknadsapp med @sif/soknad-app — SøknadRouter, SøknadAppProvider, AppContext og routing shell.
Implementer et vedleggssteg i en v2-app — VedleggPanel, PersistedVedlegg, hydration og MSW-handlere.