Make notifications action sweep wait for cold-load shell
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
# Sprint 20260311_012 - FE Live Notifications Harness Truthful Waits
|
||||
|
||||
## Topic & Scope
|
||||
- Remove the remaining cold-load false negatives from the live ops/policy Playwright sweep.
|
||||
- Wait for the real notifications operator shell before asserting `New channel` and `New rule` availability on `/ops/operations/notifications`.
|
||||
- Keep the harness truthful so page/action failures represent product defects rather than premature DOM checks.
|
||||
- Working directory: `src/Web/StellaOps.Web`.
|
||||
- Expected evidence: updated live sweep harness, clean rerun on the live stack, and a local QA-only commit.
|
||||
|
||||
## Dependencies & Concurrency
|
||||
- Depends on the authenticated live stack already being healthy at `https://stella-ops.local`.
|
||||
- Safe parallelism: none while the live sweep is running because it mutates auth state and captures shared Playwright output.
|
||||
|
||||
## Documentation Prerequisites
|
||||
- `AGENTS.md`
|
||||
- `docs/qa/feature-checks/FLOW.md`
|
||||
- `docs/implplan/SPRINT_20260309_002_FE_live_frontdoor_canonical_route_sweep.md`
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
### FE-NOTIFY-HARNESS-012-001 - Wait for the real notifications shell before checking actions
|
||||
Status: DONE
|
||||
Dependency: none
|
||||
Owners: QA, Developer
|
||||
Task description:
|
||||
- Live manual probes showed `/ops/operations/notifications` was healthy while the sweep still reported `New channel` and `New rule` as missing. The remaining gap was harness timing: the script checked for buttons before the operator notifications panel finished hydrating on cold loads.
|
||||
- Add a notifications-shell wait gate to the live ops/policy action sweep so the harness only evaluates those actions once the real operator surface is present.
|
||||
|
||||
Completion criteria:
|
||||
- [x] The harness waits for the notifications shell before probing `New channel` and `New rule`.
|
||||
- [x] Live rerun confirms the previous notifications false negatives are gone.
|
||||
- [x] The scoped QA harness repair is committed locally.
|
||||
|
||||
## Execution Log
|
||||
| Date (UTC) | Update | Owner |
|
||||
| --- | --- | --- |
|
||||
| 2026-03-11 | Sprint created after direct manual probes on `/ops/operations/notifications` showed the product surface was healthy while the live ops/policy sweep still flagged `New channel` and `New rule` as missing. | QA |
|
||||
| 2026-03-11 | Added a notifications-shell wait gate to `live-ops-policy-action-sweep.mjs`, reran the full live sweep, and confirmed `flow:New channel` plus `flow:New rule` now pass. The completed run ended with `failedActionCount=0` and `runtimeIssueCount=0`. | QA / Developer |
|
||||
|
||||
## Decisions & Risks
|
||||
- Decision: treat the notifications miss as a harness defect, not a product defect, because manual probes already proved the buttons existed and worked on the live stack.
|
||||
- Risk: the live sweep writes shared Playwright artifacts under `src/Web/StellaOps.Web/output/playwright`; clear them before the next iteration so stale evidence does not bleed into later audits.
|
||||
|
||||
## Next Checkpoints
|
||||
- Archive on local commit, then clear Playwright output and start the next full scratch rebuild iteration.
|
||||
@@ -161,6 +161,19 @@ async function navigate(page, route) {
|
||||
return url;
|
||||
}
|
||||
|
||||
async function waitForNotificationsPanel(page, timeoutMs = 12_000) {
|
||||
await page.waitForFunction(() => {
|
||||
if (document.querySelector('.notify-panel')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Array.from(document.querySelectorAll('h1, h2, [data-testid="page-title"], .page-title'))
|
||||
.map((node) => (node.textContent || '').trim().toLowerCase())
|
||||
.some((text) => text.includes('notify control plane') || text === 'channels' || text === 'rules');
|
||||
}, { timeout: timeoutMs }).catch(() => {});
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
|
||||
async function findNavigationTarget(page, name, index = 0) {
|
||||
const candidates = [
|
||||
{ role: 'link', locator: page.getByRole('link', { name }) },
|
||||
@@ -461,6 +474,7 @@ async function notificationsFormProbe(context, page) {
|
||||
|
||||
actions.push(await runAction(page, route, 'flow:New channel', async () => {
|
||||
await navigate(page, route);
|
||||
await waitForNotificationsPanel(page);
|
||||
const newChannel = page.getByRole('button', { name: 'New channel' }).first();
|
||||
if ((await newChannel.count()) === 0) {
|
||||
return {
|
||||
@@ -516,6 +530,7 @@ async function notificationsFormProbe(context, page) {
|
||||
|
||||
actions.push(await runAction(page, route, 'flow:New rule', async () => {
|
||||
await navigate(page, route);
|
||||
await waitForNotificationsPanel(page);
|
||||
const newRule = page.getByRole('button', { name: 'New rule' }).first();
|
||||
if ((await newRule.count()) === 0) {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user