diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index cf7193431..2912addc0 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -86,19 +86,9 @@ jobs: pip-${{ runner.os }}-py312- - name: Run E2E - # ExTester launches VS Code with --no-sandbox by default, so no AppArmor sysctl is needed. - # A small retry absorbs transient UI/launch flakiness (mocha already retries the test once). - run: | - attempt=1 - max=2 - until xvfb-run --auto-servernum --server-args='-screen 0 1920x1080x24' npm run test:e2e:prebuilt; do - if [ "$attempt" -ge "$max" ]; then - echo "E2E failed after $attempt attempt(s)" - exit 1 - fi - echo "E2E attempt $attempt failed — retrying…" - attempt=$((attempt + 1)) - done + # VS Code launches with --no-sandbox (no AppArmor sysctl needed). Runs once; Mocha's retries:1 + # and rootHooks.ts (dismiss toasts between tests) handle flakiness in the single shared instance. + run: xvfb-run --auto-servernum --server-args='-screen 0 1920x1080x24' npm run test:e2e:prebuilt - name: Upload failure screenshots if: failure() diff --git a/test/e2e/.mocharc.js b/test/e2e/.mocharc.js index c2a25f09a..14040de24 100644 --- a/test/e2e/.mocharc.js +++ b/test/e2e/.mocharc.js @@ -1,9 +1,14 @@ // Mocha configuration for the ExTester (vscode-extension-tester) E2E suite. // UI tests are slow: the 2s Mocha default is unusable. Individual waits inside the // tests are the real guard rails; this is a generous suite-level safety net. +const path = require('path'); + module.exports = { timeout: 1500000, // 25 min — env creation + first kernel start (venv + toolkit) can be slow retries: 1, // absorb transient UI flakiness with a single retry reporter: 'spec', - color: true + color: true, + // Dismiss notification toasts between tests (rootHooks) so they don't accumulate across the one + // shared VS Code instance. Points at compiled output, so compile-e2e must run first. + require: [path.resolve(__dirname, '..', '..', 'out', 'e2e', 'rootHooks.js')] }; diff --git a/test/e2e/rootHooks.ts b/test/e2e/rootHooks.ts new file mode 100644 index 000000000..c91408300 --- /dev/null +++ b/test/e2e/rootHooks.ts @@ -0,0 +1,9 @@ +import { dismissAllNotifications } from './helpers/notifications'; + +// Mocha root hooks (wired via .mocharc.js `require`). ExTester runs every spec in ONE shared VS Code +// instance; dismiss notification toasts between tests so they don't pile up and slow/overlap later specs. +export const mochaHooks = { + async afterEach(): Promise { + await dismissAllNotifications().catch(() => undefined); + } +}; diff --git a/test/e2e/suite/projectRename.e2e.test.ts b/test/e2e/suite/projectRename.e2e.test.ts index 4d123285c..0aba4869a 100644 --- a/test/e2e/suite/projectRename.e2e.test.ts +++ b/test/e2e/suite/projectRename.e2e.test.ts @@ -40,14 +40,27 @@ async function leaveUnsavedCellEdit(): Promise { await openWorkspaceFile(DIRTIED_FILE); - // Focus the first CODE cell's Monaco editor by clicking its visible source line (markdown cells - // render without an editor, so scope to code rows), then type a marker into the focused input. - const line = await driver.wait( - async () => (await driver.findElements(By.css('.notebookOverlay .code-cell-row .view-line')))[0], + // Click the first CODE cell's source line to focus its editor (markdown cells have none); locate + // and click in one retried step, since the cell re-renders on open and can stale a prior reference. + await driver.wait( + async () => { + const line = (await driver.findElements(By.css('.notebookOverlay .code-cell-row .view-line')))[0]; + + if (!line) { + return false; + } + + try { + await line.click(); + + return true; + } catch { + return false; + } + }, WORKBENCH_TIMEOUT, - 'the notebook code cell did not render' + 'the notebook code cell did not render or settle enough to focus' ); - await line.click(); await driver.sleep(400); await driver.switchTo().activeElement().sendKeys(DIRTY_MARKER);