Skip to content

feat(test): add Playwright E2E test suite#367

Open
dnplkndll wants to merge 22 commits intoChurchApps:mainfrom
dnplkndll:feat/playwright-e2e-tests
Open

feat(test): add Playwright E2E test suite#367
dnplkndll wants to merge 22 commits intoChurchApps:mainfrom
dnplkndll:feat/playwright-e2e-tests

Conversation

@dnplkndll
Copy link

Summary

  • Add global auth setup (tests/global-setup.ts) — single login, saves storageState for reuse across all specs
  • Rework playwright.config.ts to support BASE_URL env var override (defaults to demo.b1.church)
  • Split monolithic serving.spec.ts into focused files: serving-lessons, serving-plans, serving-songs-tasks
  • Reduce flaky waitForTimeout values across all specs (5000ms → 200-1000ms)
  • Fix settings.spec.ts selectors for SVG edit buttons and form interactions
  • Add .auth-state.json to .gitignore

Test plan

  • Run npx playwright test against demo.b1.church (default)
  • Run BASE_URL=http://localhost:3101 npx playwright test against local dev
  • Verify global auth setup works (single login reused across specs)

🤖 Generated with Claude Code

@dnplkndll dnplkndll force-pushed the feat/playwright-e2e-tests branch from 1077a59 to f231a18 Compare March 6, 2026 19:40
@jzongker jzongker requested a review from KZongker March 9, 2026 14:27
dnplkndll and others added 17 commits March 11, 2026 16:10
- Add global-setup.ts for single login + storageState reuse across workers
- Add playwright.config.ts with project dependencies (settings runs first)
- Fix settings.spec.ts: use dispatchEvent for toolbar-intercepted clicks,
  update SVG selectors for mobile edit buttons, fix form edit selectors
- Skip delete-form-questions test (upstream API 500 bug on sort column)
- Split serving.spec.ts into 3 focused files (lessons, plans, songs-tasks)
- Update all spec files to use shared auth helper with storageState
- Add .auth-state.json to .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- global-setup.ts: replace networkidle wait with emailInput visibility
  check; fixes WebSocket preventing networkidle from settling
- auth.ts: use Promise.race(navButton, emailInput) instead of sequential
  isLoginPage check; prevents false-positive re-login when React briefly
  flashes login form before reading stored JWT
- settings.spec.ts:
  - Replace all networkidle waits with specific element visibility checks
  - Add pre-cleanup loop targeting form rows by name (tr filter) so
    leftover Octav forms are deleted regardless of list order
  - Add explicit visibility waits for Add Question button and Form Members
    tab; both depend on async memberPermission query completing after
    navigation to the form detail page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Navigation refactored to use SiteHeader from @churchapps/apphelper.
#primaryNavButton no longer exists in the DOM.
Replaced #site-header/#primaryNavButton selectors with login form
visibility checks. Auth is confirmed by the login form disappearing
after submit, not by detecting a specific nav element.
This is resilient to nav refactors upstream.
After a successful login, the SelectChurchModal always appears on a fresh
session (no lastChurchId cookie). The login form stays mounted while the
dialog is open, so waiting for emailInput to be hidden always times out.

Fix: use Promise.race to wait for either the church dialog or navigation,
then handle the dialog by clicking the church and waiting for URL change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously login() waited 8s for emailInput timeout when already
authenticated (storageState), leaving only 5s (actionTimeout) for
#primaryNavButton to render. Race navButton vs emailInput instead:
return immediately when authenticated and nav is provably ready.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add console.log debugging to Mobile Settings and Form Questions tests
to capture browser state during CI: secondary menu content, API
failures, and console errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mobile Settings tests were failing because they looked for "Mobile Apps"
in the settings secondary menu, but "Mobile" is actually a primary nav
item (gated by ContentApi permissions). Fixed to navigate via the
primary nav dropdown instead. Also removed debug instrumentation from
form questions test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
NavItem renders <a href="about:blank"> with programmatic onClick
navigation, so a[href="/mobile"] never matches. Use the NavItem's
auto-generated data-testid="nav-item-mobile" instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Intercept login API response and log nav items to diagnose why
ContentApi permissions aren't reflected in the primary nav in CI.
Only runs when CI=true env var is set.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All settings tests (Mobile, Forms, General) now pass in CI.
The diagnostic logging was only needed to debug the failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
actionTimeout 5s → 15s fixes 132 test failures where MUI components
need extra render cycles. Dashboard beforeEach now navigates directly
to /dashboard instead of clicking nav-item which routes to / (onboarding).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ision

The edit form and cancel edit tests were clicking the first Edit button
on the page, which could be a seed data form (contentType=person) instead
of the test-created form (contentType=form). This caused the Form Members
tab to never appear since it requires contentType=form.

Now targets the specific form row by name instead of using .first().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Same .first() ambiguity as the edit/cancel tests — now targets
the specific "Octavius Test Form" row.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dnplkndll dnplkndll force-pushed the feat/playwright-e2e-tests branch from c55ccb6 to a887a89 Compare March 11, 2026 22:11
dnplkndll and others added 5 commits March 12, 2026 15:46
- edit form questions: fix race condition — wait for edit form to load
  question data before filling title (prevents API fetch from overwriting
  the fill). Use waitForResponse to confirm POST /questions completes.
- create/edit/delete form: handle duplicate test forms from previous runs
  using .first() selectors, improved pre-cleanup loop, and loop-based
  deletion. Relax assertions to toBeVisible() instead of toHaveCount(1).
- cancel editing form questions: add .first() for duplicate question text.
- form restriction: use 'Restricted' (actual dropdown option, not
  'Public' which was the original incorrect value).
- delete form: loop to delete all matching test forms, not just one.
- playwright.config: increase timeout/navigationTimeout for remote envs.

Skip 3 tests blocked by upstream issues:
- add person to role: /users/loadOrCreate returns 400 because person
  search results have undefined name.first/name.last fields.
- add/remove form members: Form Members tab requires forms.admin
  permission that the test user doesn't have (unrelated to restricted flag).

Verified: 17 pass, 4 skip on both MySQL and PostgreSQL environments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Un-skip "add person to role" (API double-conversion bug fixed in PersonRepo)
- Un-skip "delete form questions" (sort column bug fixed in Drizzle QuestionRepo)
- Un-skip "add/remove form members" (demo user has forms.admin permission)
- Add /mobile and /site/pages to Header.tsx test ID mappings (mobile tests were
  failing because nav-item-mobile data-testid was never assigned)
- Use waitForResponse and proper timeouts instead of fixed delays

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace waitForTimeout(200) with proper data-load assertions:
- Wait for form name field to have expected value before editing
- Wait for role name field to load before editing
- Wait for mobile tab name to load before editing
- Wait for question title to load before cancelling
- Fix "add person to role" to search for "Jennifer Williams" (exists in demo data)
- Fix form edit test: wait for API data to prevent contentType reset from "form" to "person"

The contentType bug caused Form Members tab to not appear — the edit form's
default state has contentType:"person", and saving before API data loads
overwrites the original "form" contentType.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prior runs can leave up to 10+ Octav* forms. Increase cleanup loop
from 5 to 10 iterations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…Playwright waits

- Replace ~120 waitForTimeout() calls with element visibility/assertion waits
- Replace all SVG d="..." path selectors with partial-match or text-based selectors
- Remove .catch(() => {}) from waitForResponse calls (let failures propagate)
- Fix missing await on waitForTimeout (serving-plans, website)
- Fix invalid locators (page.locator('text') → page.getByText())
- Replace hardcoded .nth(N) with .last() for dynamic lists (donations chart, website blocks)
- Fix expect(primitive).toBe() → expect(locator).toHaveCount() (people)
- Scope edit buttons to specific rows to avoid ambiguous .first() selectors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant