[OPIK-8204] [QA] test: cover the alerts CRUD lifecycle with E2E tests - #8117
Conversation
The alerts area had all 8 taxonomy capabilities uncovered — only the empty-state screenshot and the workspace-role permission matrix touched it, neither exercising a list row or the alert editor. Adds tests/alerts/ with the happy-path spine (list, create, edit, event-triggers, enable-disable, delete), the two page objects, and an SDK-seeded fixture. Teardown is mandatory rather than tidiness: alerts hold project_id as a plain indexed column with no FK and ProjectService.delete only touches ProjectDAO, so they outlive the project that scoped them. Four data-testids are added alongside. The bulk-delete button is icon-only with no accessible name, and the Name/Endpoint URL inputs render labels without htmlFor over React-generated ids, so getByLabel cannot reach them; the per-trigger block needs one because its title also appears in the test-webhook panel. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Already covered by a test in this PR. The five frontend files are test affordances only — three Not testable yet. areas: Advisory, from the QA test radar. Nothing here blocks this PR, and anything it proposes is a draft for review. Re-checked after a push on 03 Sep 10:13 UTC — nothing the verdict depends on changed. |
⏱️ pre-commit per-hook timing
⏭️ 42 skipped (no matching files changed)
|
… slug Trigger titles were asserted as one comma-joined string, but AlertDAO.FIND aggregates triggers with JSON_ARRAYAGG and no ORDER BY and AlertsEventsCell joins them in API order, so the order is not guaranteed — a latent flake that happened to pass locally. Now asserted as membership. registerAlertCleanup took an id read off the rendered row, so a failure between the create and the registration left the alert to the run-level sweep. Replaced with uiAlertCleanup, which discovers alerts by the test's namespace prefix at teardown — verified by injecting a failure immediately after the create and confirming global-teardown finds nothing to sweep. The event-type map defined 4 of 10 types, so configureThresholdTrigger rejected trace:errors and trace:latency despite both rendering the threshold controls it exists to fill. Trigger test ids now normalize the wire value's colon via a shared alertTriggerTestId helper, so the selector reads alert-trigger-trace-cost. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The editor cannot create two triggers of the same event type — its popover binds each checkbox to selectedEventTypes.has(type) — but the create API accepts a duplicate pair, and an alert seeded that way renders two identical config blocks that triggerConfig matches at once. No spec reaches that state, so this is a POM contract hazard rather than a live bug. Guarded rather than resolved with .first(), which would silently drive one of two indistinguishable triggers; configureThresholdTrigger now explains the shape instead of surfacing a bare strict-mode violation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ger case uiAlertCleanup deleted every alert matching the test's namespace prefix. testNamespace truncates the test title to 40 characters, so two similarly named tests share a prefix and one teardown could delete the other's alerts. The test now declares the names it will create before creating them, and teardown deletes only exact matches — the prefix survives purely to narrow the workspace-wide read. Declaring up front keeps the property that a mid-flow failure cannot skip cleanup, re-verified by injecting a throw immediately after the create. assertSingleTriggerConfig let a zero count through, so a missing trigger surfaced as a fill against a zero-match locator rather than as an explanation. Now rejects count !== 1 with a distinct message per case. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Conflict in fixtures/index.ts: main's id-aged-traces fixture and this branch's alert fixture both extended dashboard-cleanup and both claimed the chain tail, so index.ts re-pointed line 1 two different ways. Resolved by chaining rather than choosing — alert.fixture now extends id-aged-traces, making the chain dashboard-cleanup -> id-aged-traces -> alert, and index.ts re-exports from alert with both sides' type exports kept. Picking either side alone would have silently dropped the other fixture from every spec's `test` object. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Details
The
alertsarea had all 8 taxonomy capabilities uncovered — the only alerts coverage was the empty-state screenshot (empty-states.spec.tsE12) and the workspace-role permission matrix, neither of which exercises a list row or the alert editor. Alerts fire webhooks at customer endpoints, so an untested CRUD path is a real gap. This addstests/alerts/covering the happy-path spine, the two page objects, and an SDK-seeded fixture.alerts.project_idis a nullableCHAR(36)with an index and no FK (migration000060), andProjectService.deleteonly touchesProjectDAO, so an alert outlives the project that scoped it and surfaces in the next spec's list — the same hazardautomationRulesCleanupdocuments for rules.alerts.test-alertis deliberately left uncovered: "Test connection" POSTs the draft alert to whatever endpoint is in the form, so againstexample.comthe mutation answers failure. A passing test there would only pin an error toast, so the reason is recorded in the taxonomy instead of claiming coverage. Needs a follow-up that stands up a receiver.alerts.list-alerts,alerts.create-alert,alerts.webhook-destination@t1-smokealerts.edit-alert,alerts.event-triggers,alerts.enable-disable,alerts.delete-alert@t2-cujFrontend changes
Four
data-testids, all additive — no behavior change:alerts-bulk-delete-button— icon-only button with no accessible name and noaria-label; there was no viable stable selector at all.alert-name-input,alert-webhook-url-input— these<Label>s render withouthtmlForover React-generated ids (:r1o:-form-item), sogetByLabelcannot reach either field and the only available name is placeholder copy. Worth noting this is a genuine a11y gap a screen-reader user would hit, not just a test-tooling inconvenience — flagging for a separate fix rather than papering over it here.alert-trigger-<eventType>— a trigger's title also renders in the test-webhook panel's accordion, so a text-scoped lookup resolves there and finds none of the config controls.Change checklist
Issues
AI-WATERMARK
AI-WATERMARK: yes
data-testidadditions, and the taxonomy update.Testing
Local OSS stack built from this branch (
docker compose --profile opik up -d, frontend image rebuilt so the new testids are served), workspacedefault.Mutation-tested, not just green. Breaking the Status column (
accessorFn: () => true) and rebuilding the FE fails exactly the two status-asserting tests ontoBeVisibleand leaves the other two passing — so these assertions catch a real regression rather than passing vacuously. Verified again after the review refactor to confirm the wider timeouts didn't mask it.Cold-start behaviour. An early version used the default 15s action timeout and failed reproducibly on a cold backend: the first concurrent burst after idle takes ~18-20s (measured 17.7s/18.7s response times on plain GETs, all
200s — the backend answers, just slowly), so every worker's opening step timed out with the page still on skeleton rows. The readiness waits now allow 30s, the same allowanceexperiment-detail,online-evaluationandconfigurationalready use. Verified against a deliberately cold stack (docker restart opik-backend-1): 4/4 pass at 14-17s, precisely the window that previously failed. Then 24/24 across repeat runs.Teardown verified by
global-teardownreportingno alerts to sweepon every run — the fixture cleans up rather than leaning on the run-prefix backstop.Not run: the full suite. Scoped to the new specs plus a sibling directory, since
fixtures/index.tsis on every spec's import path;npx playwright test --listconfirms all 115 tests across 52 files still enumerate.Pre-existing, not touched:
tests_end_to_end/e2e/tsconfig.jsonstill setsbaseUrl, removed in TypeScript 7, so a barenpx tsc --noEmitfails on a clean tree (confirmed by stashing this branch's changes). Typechecking with that line dropped shows 0 errors in the new files. Probably worth its own cleanup ticket.Documentation
None — internal test coverage only.
🤖 Generated with Claude Code