fix(tests): #56 left main red — the schema mirror and three positional locators #320

Closed
opened 2026-09-08 14:09:13 -05:00 by bermudalamb · 0 comments
Owner

main is red. PR #317 was merged while its CI run was still failing (run 875), so the failures landed:

  • Backend integration: 447 passed, 1 failed
  • Playwright: 166 passed, 3 failed, 1 flaky

All four are consequences of #56 and none were caught locally, because the integration and e2e suites need a database and a browser that the dev machine cannot run.

1. The schema mirror was never regenerated

schemaMirror.integration.test.ts reports three columns present in Postgres and missing from src/db-kysely/schema.ts:

customers.analytics_consent
customers.analytics_consent_at
customers.analytics_consent_text

The migration added them; npm run db:types was never run. This is the drift guard from #305 doing exactly what it exists for — the mirror is generated from a live database, so adding a migration without regenerating it always produces this.

2. Three locators addressed controls by position, and the positions moved

This is the interesting one, because the same mistake appears three times and each failure pointed somewhere other than the cause.

Locator Was Broke because
AuthModal.marketingConsent getByRole('checkbox') A second checkbox on the register form makes it ambiguous in strict mode
AccountModal.favoriteAlertsSwitch getByRole('switch').last() The analytics switch is now last, so it silently retargeted
account-modal.spec.ts toHaveCount(2) Three switches now

The .last() case is the one worth dwelling on. It did not error — it toggled the wrong control and then failed on the resulting message (getByText('Turned off') not found, because turning analytics on says something else). The failure named a text assertion in favorites.spec.ts, which is neither the file nor the control at fault.

Root cause for the switches: antd's Switch renders a bare role="switch" with no accessible name — the adjacent Text is a sibling, not a label — so there was nothing to address them by, and position was the only option available.

The fix

  • Regenerate the mirror (hand-edited to match kysely-codegen output; alphabetical, Generated<> on the defaulted column).
  • Give each Switch in Account.tsx an explicit aria-label. This is what makes them addressable, and a screen reader needed it regardless.
  • Address every consent control by name rather than by position or count.
  • Keep the count assertion, but alongside naming each switch — a count on its own would pass if two were swapped for each other.
  • Add the two coverage gaps the compliance work depends on: the analytics checkbox is unchecked on the register form, and the account toggle is off for a new customer. Law 25 s.8.1 requires that, the integration suite asserts the server half, and nothing asserted the half a customer can see.

Not in scope

The fourth Playwright entry, auth.spec.ts:96 the logged-out header survives a reload, is reported as flaky rather than failed — it passed on retry. Unrelated to #56 and left alone; #257 covers the general problem of flakes in this suite.

Worth fixing separately

CI is badly backed up. Runs 878–883 are queued and one has been in progress for some time, which is how #317 and #319 both came to be merged without a completed run. A green tick that never arrives is indistinguishable from one nobody waited for.

`main` is red. PR #317 was merged while its CI run was still failing ([run 875](https://gitea.bermudalamb.synology.me/bermudalamb/redefined-designs/actions/runs/875)), so the failures landed: - **Backend integration: 447 passed, 1 failed** - **Playwright: 166 passed, 3 failed, 1 flaky** All four are consequences of #56 and none were caught locally, because the integration and e2e suites need a database and a browser that the dev machine cannot run. ## 1. The schema mirror was never regenerated `schemaMirror.integration.test.ts` reports three columns present in Postgres and missing from `src/db-kysely/schema.ts`: ``` customers.analytics_consent customers.analytics_consent_at customers.analytics_consent_text ``` The migration added them; `npm run db:types` was never run. This is the drift guard from #305 doing exactly what it exists for — the mirror is generated from a live database, so adding a migration without regenerating it always produces this. ## 2. Three locators addressed controls by position, and the positions moved This is the interesting one, because the same mistake appears three times and each failure pointed somewhere other than the cause. | Locator | Was | Broke because | | --- | --- | --- | | `AuthModal.marketingConsent` | `getByRole('checkbox')` | A second checkbox on the register form makes it ambiguous in strict mode | | `AccountModal.favoriteAlertsSwitch` | `getByRole('switch').last()` | The analytics switch is now last, so it **silently retargeted** | | `account-modal.spec.ts` | `toHaveCount(2)` | Three switches now | The `.last()` case is the one worth dwelling on. It did not error — it toggled the wrong control and then failed on the resulting message (`getByText('Turned off')` not found, because turning analytics *on* says something else). The failure named a text assertion in `favorites.spec.ts`, which is neither the file nor the control at fault. **Root cause for the switches:** antd's `Switch` renders a bare `role="switch"` with no accessible name — the adjacent `Text` is a sibling, not a label — so there was nothing to address them by, and position was the only option available. ## The fix - Regenerate the mirror (hand-edited to match `kysely-codegen` output; alphabetical, `Generated<>` on the defaulted column). - Give each `Switch` in `Account.tsx` an explicit `aria-label`. This is what makes them addressable, and a screen reader needed it regardless. - Address every consent control **by name** rather than by position or count. - Keep the count assertion, but alongside naming each switch — a count on its own would pass if two were swapped for each other. - Add the two coverage gaps the compliance work depends on: the analytics checkbox is unchecked on the register form, and the account toggle is off for a new customer. Law 25 s.8.1 requires that, the integration suite asserts the server half, and nothing asserted the half a customer can see. ## Not in scope The fourth Playwright entry, `auth.spec.ts:96 the logged-out header survives a reload`, is reported as **flaky** rather than failed — it passed on retry. Unrelated to #56 and left alone; #257 covers the general problem of flakes in this suite. ## Worth fixing separately **CI is badly backed up.** Runs 878–883 are queued and one has been in progress for some time, which is how #317 and #319 both came to be merged without a completed run. A green tick that never arrives is indistinguishable from one nobody waited for.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bermudalamb/redefined-designs#320