Skip to content

Commit 7789b2f

Browse files
Reconcile browser-contract specs with the redesigned portal
The post-merge Validate Backend Browser E2E run went red (30 failed / 67 passed): the browser-contract specs still asserted the pre-redesign UI. They now assert the accepted redesign: - bare page titles (Work Queue, Cards, Templates, Recurring, Assistants, Artifacts) and the promoted h1 elements; - the four-segment Home status strip (its counts partition the headline) and the Showing/expanded count copy; - human queue context dates, artifact provenance copy ("Needs review · report · no file saved yet"), assistant input references ("Card: link" fallback), diagnostics "quality findings?" copy; - desktop Process Docs hiding the sidebar filter disclosure (it lives in the mobile drawer); only grid activity buttons open the calendar editor; keyboard reachability of the cards board scroller; - relaxed mobile fold thresholds for the taller redesigned Home.
1 parent 671fc13 commit 7789b2f

14 files changed

Lines changed: 111 additions & 74 deletions

backend/e2e/calendar-seams.spec.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ test("production portal calendar covers month/week, layers, overlay, dismiss/rea
158158
});
159159
await page.goto(frontendBase);
160160
await page.getByRole("button", { name: "Calendar" }).click();
161-
await expect(page.locator(".calendar-surface [role='status']")).toHaveText(
162-
"Calendar ready.",
163-
);
161+
// The planner status line carries only warnings (stale holidays, holiday
162+
// horizon, unavailable newsletter overlays); empty means loaded clean.
163+
await expect(page.locator(".calendar-surface [role='status']")).toHaveText("");
164164
await expect(page.getByText("Synthetic Webinar").first()).toBeVisible();
165165
await expect(page.getByText("Synthetic Newsletter").first()).toBeVisible();
166166
await expect(page.getByText("Synthetic public holiday").first()).toBeVisible();
@@ -205,7 +205,7 @@ test("production portal calendar covers month/week, layers, overlay, dismiss/rea
205205
await surface.locator("[data-today]").click();
206206
await surface.locator('[data-layer="school"]').check();
207207
await surface.locator('[data-layer="overlay"]').check();
208-
await expect(surface.getByText("Calendar ready.")).toBeVisible();
208+
await expect(surface.locator("[role='status']")).toHaveText("");
209209
await surface.evaluate((element) => {
210210
element.querySelector(".calendar-controls").style.display = "none";
211211
element.querySelector('[role="status"]').style.display = "none";
@@ -253,9 +253,7 @@ test("production calendar renders cross-year ISO weeks and Berlin DST boundary d
253253
await page.goto(frontendBase);
254254
await page.getByRole("button", { name: "Calendar" }).click();
255255
const surface = page.locator(".calendar-surface");
256-
await expect(surface.locator("[role='status']")).toHaveText(
257-
"Calendar ready.",
258-
);
256+
await expect(surface.locator("[role='status']")).toHaveText("");
259257
await surface.locator("select[data-view]").selectOption("week");
260258
await expect(surface.getByText("Cross-year activity").first()).toBeVisible();
261259
await expect(surface.locator('time[datetime="2027-01-01"]')).toBeVisible();

backend/e2e/canonical-capability-behavior.spec.js

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,8 @@ test.describe('canonical frontend capability behavior', () => {
475475
await expect(attention.getByRole('button')).toBeEnabled();
476476
await expect(attention.getByRole('button', { name: 'View all tasks' })).toBeVisible();
477477
const dailySummary = page.getByRole('region', { name: 'Daily work summary' });
478-
await expect(dailySummary.locator('.home-status-item[data-state="ready"]')).toHaveCount(3);
479-
await expect(dailySummary.locator('.home-status-item > strong')).toHaveText(['0', '0', '0']);
478+
await expect(dailySummary.locator('.home-status-item[data-state="ready"]')).toHaveCount(4);
479+
await expect(dailySummary.locator('.home-status-item > strong')).toHaveText(['0', '0', '0', '0']);
480480
await expect(page.locator('#work-bell-button .work-bell-count')).toHaveText('0');
481481

482482
await page.getByRole('button', { name: 'New task', exact: true }).click();
@@ -490,12 +490,12 @@ test.describe('canonical frontend capability behavior', () => {
490490

491491
await attention.getByRole('button', { name: 'View all tasks' }).click();
492492
await expect(page).toHaveURL(/\/\#\/tasks$/);
493-
await expect(page.getByRole('heading', { name: 'Tasks - Work Queue' })).toBeVisible();
493+
await expect(page.getByRole('heading', { name: 'Work Queue' })).toBeVisible();
494494
await page.goto('/#/');
495495
await expect(page.locator('.operations-home[data-operations-work-loaded="true"]')).toBeVisible();
496496
await page.setViewportSize({ width: 390, height: 844 });
497497
await closeMobileSidebar(page);
498-
await expect(page.locator('.home-daily-header h2')).toBeVisible();
498+
await expect(page.locator('.home-daily-header h1')).toBeVisible();
499499
await page.screenshot({
500500
path: path.join(ISSUE_161_SCREENSHOTS, 'source-home-empty-mobile-390x844.png'),
501501
fullPage: true,
@@ -535,7 +535,7 @@ test.describe('canonical frontend capability behavior', () => {
535535
const homeTaskRow = populatedAttention.locator('.home-attention-row', { hasText: title });
536536
await expect(homeTaskRow).toBeVisible();
537537
await expect(homeTaskRow.getByRole('button')).toHaveAttribute('aria-label', `Open: ${title}`);
538-
await expect(page.getByRole('region', { name: 'Daily work summary' }).locator('.home-status-item > strong')).toHaveText(['1', '1', '1']);
538+
await expect(page.getByRole('region', { name: 'Daily work summary' }).locator('.home-status-item > strong')).toHaveText(['1', '1', '0', '0']);
539539
await expect(page.locator('#work-bell-button .work-bell-count')).toHaveText('1');
540540
await page.screenshot({
541541
path: path.join(ISSUE_161_SCREENSHOTS, 'source-home-ready-desktop-1440x900.png'),
@@ -597,7 +597,9 @@ test.describe('canonical frontend capability behavior', () => {
597597
await page.setViewportSize({ width: 1440, height: 900 });
598598
await page.goto('/#/processes');
599599
await expect(page.locator('.ops-surface-docs')).toBeVisible();
600-
await expect(page.locator('#filters-section')).toBeVisible();
600+
// Desktop Docs is content-first: the sidebar filter disclosure is
601+
// intentionally hidden at desktop widths and lives in the mobile drawer.
602+
await expect(page.locator('#filters-section')).toBeHidden();
601603
await page.screenshot({
602604
path: path.join(ISSUE_161_SCREENSHOTS, 'source-docs-controls-retained-desktop-1440x900.png'),
603605
fullPage: true,
@@ -728,7 +730,7 @@ test.describe('canonical frontend capability behavior', () => {
728730
expect(unavailableArtifactResponse.status()).toBe(201);
729731
await page.reload();
730732
const unavailableArtifact = page.locator('.ops-state-list .ops-data-row', { hasText: 'Unavailable proof artifact' });
731-
await expect(unavailableArtifact).toContainText('needs-review · report · storage missing');
733+
await expect(unavailableArtifact).toContainText('Needs review · report · no file saved yet');
732734
await expect(unavailableArtifact.getByRole('link')).toHaveCount(0);
733735

734736
const id = unique('assistant-baseline');
@@ -752,7 +754,10 @@ test.describe('canonical frontend capability behavior', () => {
752754
await expect(page.getByText('Loading job events and artifacts…')).toBeVisible();
753755
await expect(page.locator('.assistant-detail h3')).toHaveText(`Synthetic assistant ${id}`);
754756
await expect(page.locator('.assistant-queue .assistant-job-row', { hasText: `Synthetic assistant ${id}` })).toBeVisible();
755-
await expect(page.locator('.assistant-ref-list')).toContainText(card.id);
757+
// Input references are labeled in operator language, never as a raw
758+
// UUID: until the work snapshot resolves the card title the ref degrades
759+
// to the honest "Card: link" fallback.
760+
await expect(page.locator('.assistant-ref-list')).toContainText('Card: link');
756761
await page.reload();
757762
await expect(page.locator('.assistant-detail h3')).toHaveText(`Synthetic assistant ${id}`);
758763
const after = await json(await context.request.get(`/api/assistant-jobs/${assistant.id}`));
@@ -764,8 +769,10 @@ test.describe('canonical frontend capability behavior', () => {
764769
await expect(artifactSurface).toBeVisible();
765770
const artifactRow = artifactSurface.locator('.ops-data-row', { hasText: `Synthetic artifact ${id}` });
766771
await expect(artifactRow).toBeVisible();
767-
await expect(artifactSurface.locator('.ops-data-row', { hasText: card.id })).toBeVisible();
768-
const artifactLink = artifactRow.getByRole('link', { name: `Open Synthetic artifact ${id} for card ${card.id}` });
772+
// The row names the related card in operator language — its title once
773+
// the work snapshot resolves, or the honest fallback — never a raw UUID.
774+
await expect(artifactRow).not.toContainText(card.id);
775+
const artifactLink = artifactRow.getByRole('link');
769776
await expect(artifactLink).toHaveAttribute('href', 'https://example.invalid/synthetic-output');
770777
await expect(artifactLink).toHaveAttribute('rel', 'noopener');
771778
await page.goto('/#/assistants?assistantJobId=stale-synthetic-assistant');
@@ -1017,7 +1024,9 @@ test.describe('canonical frontend capability behavior', () => {
10171024
expect(await calendarDialog.getByLabel('Title').evaluate((input) => input.validity.valid)).toBe(false);
10181025
await calendarDialog.getByRole('button', { name: 'Cancel' }).click();
10191026

1020-
await page.getByText(`Updated calendar ${id}`).first().click();
1027+
// Only grid activity buttons open the editor; alerts and overlays echo
1028+
// item titles without carrying [data-edit].
1029+
await page.locator('.calendar-surface [data-edit]', { hasText: `Updated calendar ${id}` }).first().click();
10211030
const currentCalendarPayload = await json(await context.request.get(`/api/calendar-items/${calendarItem.id}`));
10221031
const currentCalendar = currentCalendarPayload.item || currentCalendarPayload;
10231032
expect((await context.request.put(`/api/calendar-items/${calendarItem.id}`, { data: {
@@ -1031,7 +1040,7 @@ test.describe('canonical frontend capability behavior', () => {
10311040
await page.reload();
10321041
await page.clock.setFixedTime(new Date('2026-09-03T12:00:00Z'));
10331042
await page.locator('[data-today]').click();
1034-
await page.getByText(`Server calendar ${id}`).first().click();
1043+
await page.locator('.calendar-surface [data-edit]', { hasText: `Server calendar ${id}` }).first().click();
10351044
await page.locator('.calendar-surface dialog').getByLabel('Title').fill(`Browser calendar ${id}`);
10361045
await page.locator('.calendar-surface dialog').getByRole('button', { name: 'Save activity' }).click();
10371046
await expect(page.getByText(`Browser calendar ${id}`).first()).toBeVisible();
@@ -1053,8 +1062,9 @@ test.describe('canonical frontend capability behavior', () => {
10531062
const noConfig = await portalContext(browser, servers.noMailingConfig);
10541063
const noConfigPage = await noConfig.newPage();
10551064
await noConfigPage.goto('/#/mailing-exports');
1056-
await expect(noConfigPage.locator('[data-export-state="no-config"]')).toContainText('No export configurations');
1057-
await expect(noConfigPage.getByRole('status')).toContainText('No export configurations are enabled');
1065+
const noConfigState = noConfigPage.locator('[data-export-state="no-config"]');
1066+
await expect(noConfigState).toContainText('No export configurations');
1067+
await expect(noConfigState).toContainText('No secret values belong in the portal.');
10581068
await noConfig.close();
10591069

10601070
const { context, page } = await portalPage(browser);
@@ -1184,7 +1194,7 @@ test.describe('canonical frontend capability behavior', () => {
11841194
await expect(emptyDiagnostics.locator('[data-diagnostic="quality"]')).toContainText('Loading local validation');
11851195
await expect(emptyDiagnostics.locator('[data-diagnostic="git-status"]')).toContainText('Loading availability');
11861196
await expect(emptyDiagnostics.locator('[data-diagnostic="git-history"]')).toContainText('Loading availability');
1187-
await expect(emptyDiagnostics.locator('[data-diagnostic="quality"]')).toContainText('0 finding(s); 0 validation error(s)');
1197+
await expect(emptyDiagnostics.locator('[data-diagnostic="quality"]')).toContainText('0 quality findings; no validation errors.');
11881198
await expect(emptyDiagnostics.locator('[data-diagnostic="git-status"]')).toContainText(/unavailable/i);
11891199
await expect(emptyDiagnostics.locator('[data-diagnostic="git-history"]')).toContainText(/unavailable/i);
11901200
await clearFaults(empty.request);
@@ -1222,6 +1232,12 @@ test.describe('canonical frontend capability behavior', () => {
12221232
await page.locator('#docs-nav-button').click();
12231233
await expect(page.locator('body')).toHaveAttribute('data-view', 'library');
12241234

1235+
// The shell keeps document filters in the mobile drawer; desktop Docs is
1236+
// content-first and hides the sidebar disclosure entirely. Open the
1237+
// drawer once and filter inside it.
1238+
await page.setViewportSize({ width: 390, height: 844 });
1239+
await page.locator('#mobile-menu-button').click();
1240+
await expect(page.locator('#sidebar')).toBeVisible();
12251241
await page.locator('#filters-section summary').click();
12261242
const documentFilters = page.locator('#filter-row .custom-select');
12271243
await expect(documentFilters).toHaveCount(4);
@@ -1239,14 +1255,15 @@ test.describe('canonical frontend capability behavior', () => {
12391255
await expect(page.locator('.ops-surface-docs')).toBeVisible();
12401256
await expect(page.locator('#filter-count')).toHaveText('4');
12411257
await captureIssue200Screenshot(page, 'process-docs-filtered');
1242-
await page.setViewportSize({ width: 390, height: 844 });
1243-
await captureIssue200Screenshot(page, 'process-docs-filtered');
12441258
await page.setViewportSize({ width: 1440, height: 900 });
12451259

12461260
await page.reload();
12471261
await expect(page.locator('.ops-surface-docs')).toBeVisible();
12481262
await expect(page).toHaveURL(canonicalFilterUrl);
12491263
await expect(page.locator('#filter-count')).toHaveText('4');
1264+
await page.setViewportSize({ width: 390, height: 844 });
1265+
await page.locator('#mobile-menu-button').click();
1266+
await expect(page.locator('#sidebar')).toBeVisible();
12501267
await page.locator('#filters-section summary').click();
12511268
await page.locator('#clear-filters-button').click();
12521269
await expect(page).toHaveURL(/\/#\/processes$/);
@@ -1261,6 +1278,7 @@ test.describe('canonical frontend capability behavior', () => {
12611278
await chooseDocumentFilter(2, 'Dataops');
12621279
await chooseDocumentFilter(3, 'Synthetic');
12631280
await expect(page).toHaveURL(canonicalFilterUrl);
1281+
await page.setViewportSize({ width: 1440, height: 900 });
12641282
const filteredSearch = page.waitForRequest((request) => {
12651283
const url = new URL(request.url());
12661284
return request.method() === 'GET' && url.pathname === '/search';
@@ -1442,7 +1460,7 @@ test.describe('canonical frontend capability behavior', () => {
14421460
await expect(page.locator('.ops-admin-card', { hasText: 'Diagnostics' })).toBeVisible();
14431461
const diagnostics = page.getByRole('region', { name: 'Read-only diagnostics' });
14441462
await expect(diagnostics).toContainText('No pull, commit, publish, or provider action is available here');
1445-
await expect(diagnostics.locator('[data-diagnostic="quality"]')).toContainText(/finding\(s\); \d+ validation error\(s\)/);
1463+
await expect(diagnostics.locator('[data-diagnostic="quality"]')).toContainText(/quality findings?; (no|\d+) validation errors?/);
14461464
await expect(diagnostics.locator('[data-diagnostic="git-status"]')).toContainText('Git diagnostics are unavailable in the packaged runtime');
14471465
await expect(diagnostics.locator('[data-diagnostic="git-history"]')).toContainText('Git history is unavailable in the packaged runtime');
14481466

@@ -1455,7 +1473,7 @@ test.describe('canonical frontend capability behavior', () => {
14551473
await expect(page.locator('.ops-admin-diagnostics')).toContainText('Unavailable: Synthetic route failure (503)');
14561474
await clearFaults(context.request);
14571475
await page.reload();
1458-
await expect(page.locator('[data-diagnostic="quality"]')).toContainText(/finding\(s\); \d+ validation error\(s\)/);
1476+
await expect(page.locator('[data-diagnostic="quality"]')).toContainText(/quality findings?; (no|\d+) validation errors?/);
14591477
await context.close();
14601478
recordCapabilityEvidence(testInfo, [
14611479
{ route: '/#/processes', roleId: 'admin', stateIds: ['process-docs.loading', 'process-docs.empty', 'process-docs.filters.url-reload-clear-search', 'process-docs.result-detail', 'process-docs.create-read-edit', 'process-docs.draft-management', 'process-docs.partial-save-failure', 'process-docs.backlinks', 'process-docs.validation', 'process-docs.git-failure'] },
@@ -1690,7 +1708,7 @@ test.describe('canonical frontend capability behavior', () => {
16901708
await clearFaults(context.request);
16911709
await page.reload();
16921710
await expect(page.getByText('Artifact review index not connected')).toHaveCount(0);
1693-
await expect(page.getByRole('heading', { name: 'Tasks - Artifacts', exact: true }).first()).toBeVisible();
1711+
await expect(page.getByRole('heading', { name: 'Artifacts', exact: true }).first()).toBeVisible();
16941712
await context.close();
16951713
recordCapabilityEvidence(testInfo, [{
16961714
route: '/#/notifications',

backend/e2e/canonical-frontend.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ test.describe('canonical DataOps frontend', () => {
1616
await expect(page.locator('[data-tasks-section="workflows"]')).toHaveAttribute('aria-current', 'page');
1717

1818
await page.goto('/#/recurring');
19-
await expect(page.getByRole('heading', { name: 'Tasks - Recurring', exact: true })).toBeVisible();
19+
await expect(page.getByRole('heading', { name: 'Recurring', exact: true })).toBeVisible();
2020
await expect(page.locator('[data-tasks-section="recurring"]')).toHaveAttribute('aria-current', 'page');
2121

2222
await page.goto('/#/notifications');
@@ -91,7 +91,7 @@ test.describe('canonical DataOps frontend', () => {
9191
const job = (await jobResponse.json()).job;
9292

9393
await page.goto(`/#/assistants?assistantJobId=${job.id}`);
94-
await expect(page.getByRole('heading', { name: 'Tasks - Assistants', exact: true })).toBeVisible();
94+
await expect(page.getByRole('heading', { name: 'Assistants', exact: true })).toBeVisible();
9595
await expect(page.locator('.assistant-detail h3')).toHaveText(`Canonical assistant ${id}`);
9696
await expect(page.locator('[data-assistant-save]')).toBeVisible();
9797
await expect(page.locator('[data-assistant-lifecycle="submit"]')).toBeVisible();

0 commit comments

Comments
 (0)