From 1d60a21cbdfbc8a9257672bc84b4de08aece5be6 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Wed, 14 Oct 2026 20:33:42 -0700 Subject: [PATCH] test: consolidate automations page suites (#28953) --- .../automations/AutomationsPage.behavior.test.tsx | 9 +++++++++ ... => AutomationsPage.cross-authority-actions.spec.tsx} | 4 ++-- ...st.tsx => AutomationsPage.escape-precedence.spec.tsx} | 4 ++-- ....test.tsx => AutomationsPage.external-scope.spec.tsx} | 4 ++-- ...test.tsx => AutomationsPage.notice-recovery.spec.tsx} | 4 ++-- ...st.tsx => AutomationsPage.refresh-selection.spec.tsx} | 8 ++++++-- ....test.tsx => AutomationsPage.run-visibility.spec.tsx} | 4 ++-- ...test.tsx => AutomationsPage.save-visibility.spec.tsx} | 4 ++-- ...AutomationsPage.strict-mode-save-visibility.spec.tsx} | 4 ++-- .../automations/automations-page-test-harness.tsx | 2 +- 10 files changed, 30 insertions(+), 17 deletions(-) create mode 100644 src/renderer/src/components/automations/AutomationsPage.behavior.test.tsx rename src/renderer/src/components/automations/{AutomationsPage.cross-authority-actions.test.tsx => AutomationsPage.cross-authority-actions.spec.tsx} (99%) rename src/renderer/src/components/automations/{AutomationsPage.escape-precedence.test.tsx => AutomationsPage.escape-precedence.spec.tsx} (98%) rename src/renderer/src/components/automations/{AutomationsPage.external-scope.test.tsx => AutomationsPage.external-scope.spec.tsx} (99%) rename src/renderer/src/components/automations/{AutomationsPage.notice-recovery.test.tsx => AutomationsPage.notice-recovery.spec.tsx} (99%) rename src/renderer/src/components/automations/{AutomationsPage.refresh-selection.test.tsx => AutomationsPage.refresh-selection.spec.tsx} (98%) rename src/renderer/src/components/automations/{AutomationsPage.run-visibility.test.tsx => AutomationsPage.run-visibility.spec.tsx} (98%) rename src/renderer/src/components/automations/{AutomationsPage.save-visibility.test.tsx => AutomationsPage.save-visibility.spec.tsx} (99%) rename src/renderer/src/components/automations/{AutomationsPage.strict-mode-save-visibility.test.tsx => AutomationsPage.strict-mode-save-visibility.spec.tsx} (99%) diff --git a/src/renderer/src/components/automations/AutomationsPage.behavior.test.tsx b/src/renderer/src/components/automations/AutomationsPage.behavior.test.tsx new file mode 100644 index 00000000000..1c9abcfb077 --- /dev/null +++ b/src/renderer/src/components/automations/AutomationsPage.behavior.test.tsx @@ -0,0 +1,9 @@ +// @vitest-environment happy-dom +import './AutomationsPage.cross-authority-actions.spec' +import './AutomationsPage.escape-precedence.spec' +import './AutomationsPage.external-scope.spec' +import './AutomationsPage.notice-recovery.spec' +import './AutomationsPage.refresh-selection.spec' +import './AutomationsPage.run-visibility.spec' +import './AutomationsPage.save-visibility.spec' +import './AutomationsPage.strict-mode-save-visibility.spec' diff --git a/src/renderer/src/components/automations/AutomationsPage.cross-authority-actions.test.tsx b/src/renderer/src/components/automations/AutomationsPage.cross-authority-actions.spec.tsx similarity index 99% rename from src/renderer/src/components/automations/AutomationsPage.cross-authority-actions.test.tsx rename to src/renderer/src/components/automations/AutomationsPage.cross-authority-actions.spec.tsx index 8193502cb36..a6bff65240e 100644 --- a/src/renderer/src/components/automations/AutomationsPage.cross-authority-actions.test.tsx +++ b/src/renderer/src/components/automations/AutomationsPage.cross-authority-actions.spec.tsx @@ -25,8 +25,6 @@ import { import { listedRows } from './automations-page-listed-items' import { makeAutomation } from './automations-page-fixtures' -installAutomationsPageHarness() - /** Desktop and runtime both hold `a-1`; the runtime's row is committed last. */ async function collidingHosts(): Promise { runtimeHost([makeAutomation({ id: 'a-1', name: 'Remote nightly' })], []) @@ -52,6 +50,8 @@ function runtimeAutomationCalls(): string[] { } describe('AutomationsPage row actions under a colliding automation id', () => { + installAutomationsPageHarness() + it('names the selected row’s own host, not the desktop that listed it', async () => { await collidingHosts() await renderPage() diff --git a/src/renderer/src/components/automations/AutomationsPage.escape-precedence.test.tsx b/src/renderer/src/components/automations/AutomationsPage.escape-precedence.spec.tsx similarity index 98% rename from src/renderer/src/components/automations/AutomationsPage.escape-precedence.test.tsx rename to src/renderer/src/components/automations/AutomationsPage.escape-precedence.spec.tsx index df0aa39a9aa..a8c9a6443f9 100644 --- a/src/renderer/src/components/automations/AutomationsPage.escape-precedence.test.tsx +++ b/src/renderer/src/components/automations/AutomationsPage.escape-precedence.spec.tsx @@ -15,8 +15,6 @@ import { settleHostQueries } from './automations-page-test-harness' -installAutomationsPageHarness() - function pressEscape(target: EventTarget): KeyboardEvent { const event = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true }) target.dispatchEvent(event) @@ -32,6 +30,8 @@ async function renderWithCloseSpy(): Promise> { } describe('automations page Escape precedence', () => { + installAutomationsPageHarness() + it('closes the page when nothing is layered above it', async () => { const closeAutomationsPage = await renderWithCloseSpy() diff --git a/src/renderer/src/components/automations/AutomationsPage.external-scope.test.tsx b/src/renderer/src/components/automations/AutomationsPage.external-scope.spec.tsx similarity index 99% rename from src/renderer/src/components/automations/AutomationsPage.external-scope.test.tsx rename to src/renderer/src/components/automations/AutomationsPage.external-scope.spec.tsx index f86cdd174fa..f447d2bddea 100644 --- a/src/renderer/src/components/automations/AutomationsPage.external-scope.test.tsx +++ b/src/renderer/src/components/automations/AutomationsPage.external-scope.spec.tsx @@ -23,8 +23,6 @@ import { import { listedExternalEntries } from './automations-page-listed-items' import { makeExternalManager } from './automations-page-fixtures' -installAutomationsPageHarness() - const DESKTOP_SELF_FILTER = { kind: 'host' as const, host: { authority: { kind: 'desktop' as const }, selector: { kind: 'self' as const } } @@ -67,6 +65,8 @@ function openclawOnly(): void { } describe('AutomationsPage external manager probes', () => { + installAutomationsPageHarness() + it('probes no SSH host when the selection is the local desktop', async () => { withSshHosts('staging', 'web-01', 'web-02') mocks.state.automationHostFilter = DESKTOP_SELF_FILTER diff --git a/src/renderer/src/components/automations/AutomationsPage.notice-recovery.test.tsx b/src/renderer/src/components/automations/AutomationsPage.notice-recovery.spec.tsx similarity index 99% rename from src/renderer/src/components/automations/AutomationsPage.notice-recovery.test.tsx rename to src/renderer/src/components/automations/AutomationsPage.notice-recovery.spec.tsx index 69c27640be1..972414c24ac 100644 --- a/src/renderer/src/components/automations/AutomationsPage.notice-recovery.test.tsx +++ b/src/renderer/src/components/automations/AutomationsPage.notice-recovery.spec.tsx @@ -28,8 +28,6 @@ import { import { listedRow } from './automations-page-listed-items' import { makeAutomation } from './automations-page-fixtures' -installAutomationsPageHarness() - const FENCING_REQUIRED = 'The host changed: automation_owner_fencing_required' /** Fails one runtime RPC the way an under-versioned server does, leaving the rest answering. */ @@ -54,6 +52,8 @@ function watchSettings(): { open: ReturnType; target: ReturnType { + installAutomationsPageHarness() + it('sends the create dialog Update server to where that destination host is versioned', async () => { api.automations.list.mockResolvedValue([]) scopedList([]) diff --git a/src/renderer/src/components/automations/AutomationsPage.refresh-selection.test.tsx b/src/renderer/src/components/automations/AutomationsPage.refresh-selection.spec.tsx similarity index 98% rename from src/renderer/src/components/automations/AutomationsPage.refresh-selection.test.tsx rename to src/renderer/src/components/automations/AutomationsPage.refresh-selection.spec.tsx index f33c4d09d6c..d1bf2fef228 100644 --- a/src/renderer/src/components/automations/AutomationsPage.refresh-selection.test.tsx +++ b/src/renderer/src/components/automations/AutomationsPage.refresh-selection.spec.tsx @@ -25,8 +25,6 @@ import { import { listedRows } from './automations-page-listed-items' import { makeAutomation, makeRun } from './automations-page-fixtures' -installAutomationsPageHarness() - async function openAutomationRow(container: HTMLElement, name: string): Promise { const row = [ ...container.querySelectorAll('[data-testid="automation-row"]') @@ -37,6 +35,8 @@ async function openAutomationRow(container: HTMLElement, name: string): Promise< } describe('AutomationsPage refresh', () => { + installAutomationsPageHarness() + it('never asks a host for every run it has retained', async () => { const run = makeRun({ id: 'run-1', automationId: 'a-1' }) api.automations.list.mockResolvedValue([makeAutomation({ id: 'a-1' })]) @@ -120,6 +120,8 @@ describe('AutomationsPage refresh', () => { }) describe('AutomationsPage selection', () => { + installAutomationsPageHarness() + it('loads the first automation into the detail pane and fetches its runs', async () => { const run = makeRun({ id: 'run-1', automationId: 'a-1' }) api.automations.list.mockResolvedValue([makeAutomation({ id: 'a-1', name: 'Nightly' })]) @@ -164,6 +166,8 @@ describe('AutomationsPage selection', () => { }) describe('AutomationsPage multi-host selection', () => { + installAutomationsPageHarness() + it('keeps a selection that lives on another host when the window regains focus', async () => { runtimeHost([makeAutomation({ id: 'a-remote', name: 'Remote nightly' })], []) const desktop = makeAutomation({ id: 'a-desktop', name: 'Desktop nightly' }) diff --git a/src/renderer/src/components/automations/AutomationsPage.run-visibility.test.tsx b/src/renderer/src/components/automations/AutomationsPage.run-visibility.spec.tsx similarity index 98% rename from src/renderer/src/components/automations/AutomationsPage.run-visibility.test.tsx rename to src/renderer/src/components/automations/AutomationsPage.run-visibility.spec.tsx index 5e605a4487a..5a29c450b64 100644 --- a/src/renderer/src/components/automations/AutomationsPage.run-visibility.test.tsx +++ b/src/renderer/src/components/automations/AutomationsPage.run-visibility.spec.tsx @@ -24,8 +24,6 @@ import { import { listedRow, listedRows } from './automations-page-listed-items' import { makeAutomation } from './automations-page-fixtures' -installAutomationsPageHarness() - const DESKTOP_SELF_FILTER = { kind: 'host' as const, host: { authority: { kind: 'desktop' as const }, selector: { kind: 'self' as const } } @@ -46,6 +44,8 @@ function listedNextRunAt(): number | null | undefined { } describe('AutomationsPage run visibility', () => { + installAutomationsPageHarness() + it('shows the post-run schedule the host reports, not the row the run started from', async () => { desktopStoreHolds([BEFORE_RUN]) mocks.state.automationHostFilter = DESKTOP_SELF_FILTER diff --git a/src/renderer/src/components/automations/AutomationsPage.save-visibility.test.tsx b/src/renderer/src/components/automations/AutomationsPage.save-visibility.spec.tsx similarity index 99% rename from src/renderer/src/components/automations/AutomationsPage.save-visibility.test.tsx rename to src/renderer/src/components/automations/AutomationsPage.save-visibility.spec.tsx index 4581a5fee7e..e3f6ed6e062 100644 --- a/src/renderer/src/components/automations/AutomationsPage.save-visibility.test.tsx +++ b/src/renderer/src/components/automations/AutomationsPage.save-visibility.spec.tsx @@ -24,8 +24,6 @@ import { } from './automations-page-test-harness' import { makeAutomation, REPO_ID, WORKSPACE_ID } from './automations-page-fixtures' -installAutomationsPageHarness() - const DESKTOP_SELF_FILTER = { kind: 'host' as const, host: { authority: { kind: 'desktop' as const }, selector: { kind: 'self' as const } } @@ -60,6 +58,8 @@ async function createSweep(): Promise { } describe('AutomationsPage save visibility', () => { + installAutomationsPageHarness() + it('lists a newly created automation on the host it was saved to', async () => { desktopStoreHolds([]) mocks.state.automationHostFilter = DESKTOP_SELF_FILTER diff --git a/src/renderer/src/components/automations/AutomationsPage.strict-mode-save-visibility.test.tsx b/src/renderer/src/components/automations/AutomationsPage.strict-mode-save-visibility.spec.tsx similarity index 99% rename from src/renderer/src/components/automations/AutomationsPage.strict-mode-save-visibility.test.tsx rename to src/renderer/src/components/automations/AutomationsPage.strict-mode-save-visibility.spec.tsx index e1387e88631..1eea8483e2b 100644 --- a/src/renderer/src/components/automations/AutomationsPage.strict-mode-save-visibility.test.tsx +++ b/src/renderer/src/components/automations/AutomationsPage.strict-mode-save-visibility.spec.tsx @@ -31,8 +31,6 @@ import { } from './automations-page-test-harness' import { makeAutomation, REPO_ID, WORKSPACE_ID } from './automations-page-fixtures' -installAutomationsPageHarness() - const CREATED = makeAutomation({ id: 'a-new', name: 'Sweep' }) const RUNTIME_SELF_KEY = hostStableKey({ @@ -66,6 +64,8 @@ async function createSweep(): Promise { } describe('AutomationsPage save visibility under StrictMode', () => { + installAutomationsPageHarness() + it('lists a newly created automation without a reload', async () => { desktopStoreHolds([]) api.automations.create.mockResolvedValue(CREATED) diff --git a/src/renderer/src/components/automations/automations-page-test-harness.tsx b/src/renderer/src/components/automations/automations-page-test-harness.tsx index 50d77e55319..f23b0b421ca 100644 --- a/src/renderer/src/components/automations/automations-page-test-harness.tsx +++ b/src/renderer/src/components/automations/automations-page-test-harness.tsx @@ -399,7 +399,7 @@ export function rows(container: HTMLElement, testId: string): string[] { ) } -/** Registers the reset both page test files depend on; call once per file. */ +/** Registers the per-case store reset and renderer cleanup for the current suite. */ export function installAutomationsPageHarness(): void { beforeEach(() => { globalThis.IS_REACT_ACT_ENVIRONMENT = true