Debug failing E2E Playwright tests in melosys-e2e-tests-claude. Use when: (1) E2E tests fail with timeout errors or unexpected behavior, (2) Need to check database state (prosessinstans, behandling, vedtak), (3) Need to understand why UI buttons are disabled or actions fail, (4) Tracing issues from frontend through API to database, (5) Process instance timeout errors in cleanup fixture.
Debug failing Playwright E2E tests by checking database state, analyzing screenshots, and tracing UI to API issues.
npx playwright test "test-name" --project=chromium --reporter=list
Key output patterns:
TimeoutError: locator.click + element is not enabled → Button disabled, check screenshotProcess instances timed out → Check database for missing/stuck prosessinstanspage.waitForResponse: Test ended → API call never happened# Read screenshot from test-results
test-results/{test-name}-chromium/test-failed-1.png
Look for:
docker exec melosys-oracle bash -c "sqlplus -s MELOSYS/melosyspwd@//localhost:1521/freepdb1 << 'EOF'
SELECT RAWTOHEX(UUID), PROSESS_TYPE, STATUS, SIST_FULLFORT_STEG
FROM PROSESSINSTANS ORDER BY REGISTRERT_DATO DESC FETCH FIRST 5 ROWS ONLY;
EOF"
See references/database-queries.md for more queries.
Symptom: Step transition timed out after 90s. API responded OK but heading is still "X"
Root cause: Frontend rendering stall — backend processes the step but React doesn't re-render.
Key facts (confirmed March 2026):
verifyHeadingChange: true)What NOT to do:
What helps (in priority order):
waitForContent to klikkBekreftOgFortsett — this is the single most
effective fix. Pass a locator for an element on the NEXT step (radio, checkbox, button).
clickStepButtonWithRetry uses it as an alternative success signal via Promise.race
when the heading check fails. Without it, the only detection mechanism is the fragile
heading visibility check.
// GOOD — gives fallback detection
await behandling.klikkBekreftOgFortsett({
waitForContent: page.getByRole('checkbox', { name: 'Ståles Stål AS' }),
});
// BAD — only heading check, will timeout if React stalls
await behandling.klikkBekreftOgFortsett();
clickStepButtonWithRetry
now does this automatically in heading-change mode.Race condition with radio auto-save: Radio selections on step wizard pages trigger immediate API saves. If you click "Bekreft og fortsett" before the auto-save completes, two concurrent API calls can cause React to batch state updates without flushing a re-render. Tests with TWO radio selections before clicking (e.g. "direkte til" tests) are less flaky because the second selection gives the first one's API call time to complete.
How to investigate CI failures:
error-context.md from test-results/ — shows page snapshot at failuretest-summary.json totalAttempts vs failedAttempts for flaky rategh workflow run -f test_grep="test name" -f repeat_each=5 -f disable_retries=trueSymptom: element is not enabled in timeout error
Cause: Required dropdown not selected
Fix: Add selection step before clicking button
// Example fix - select institution before vedtak
await this.institusjonDropdown.selectOption({ index: 1 });
await this.fattVedtakButton.click();
Symptom: Process instances timed out: Timeout after 30s
This is usually a secondary error — the test already failed (e.g., step transition timeout), and the cleanup fixture times out because the test left things in an unfinished state. Check the FIRST error in the annotation, not this one.
| Database State | Meaning | Action |
|---|---|---|
| No IVERKSETT_VEDTAK_EOS | API never called | Button was disabled - check screenshot |
| Status = KLAR | Step stuck | Check API logs for errors |
| Status = FERDIG | All done | Timing issue - check if button click failed |
Symptom: BEHANDLING.STATUS = UNDER_BEHANDLING, BEHANDLINGSRESULTAT.RESULTAT_TYPE = IKKE_FASTSATT
This means the vedtak API endpoint was never called. Check:
Symptom: locator.waitFor: Timeout Xms exceeded. waiting for getByRole('radio/checkbox', ...)
Cause: The step transition completed but dependent UI elements haven't rendered yet on slow CI.
Fix: Increase waitFor timeout in POM methods to 30-45s (not default 10s):
// BAD - default 10s too short for CI
await this.skipRadio.waitFor({ state: 'visible' });
// GOOD - explicit 30s timeout
await this.skipRadio.waitFor({ state: 'visible', timeout: 30000 });
Query these tables in order when debugging:
-- 1. Check process instances
SELECT PROSESS_TYPE, STATUS FROM PROSESSINSTANS;
-- 2. Check behandling status
SELECT ID, STATUS, BEH_TEMA FROM BEHANDLING;
-- 3. Check if vedtak was created
SELECT BEHANDLING_ID, RESULTAT_TYPE FROM BEHANDLINGSRESULTAT;
-- 4. Check vedtak metadata exists
SELECT * FROM VEDTAK_METADATA;