From 451eacac3ca71907fc5604398630e14f7a7804ce Mon Sep 17 00:00:00 2001 From: Simon Siefke Date: Sat, 18 Jul 2026 10:32:24 +0000 Subject: [PATCH 1/2] test: reproduce markdown preview switch failure --- .github/workflows/pr.yml | 63 +++++----------------------------------- 1 file changed, 8 insertions(+), 55 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index d38a27ccec..73a92bb156 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -6,12 +6,14 @@ on: - main jobs: - pr: - runs-on: ${{ matrix.os }} + reproduce-markdown-preview-switch: + name: markdown-preview-switch (attempt ${{ matrix.attempt }}) + runs-on: ubuntu-24.04 strategy: fail-fast: false + max-parallel: 1 matrix: - os: [ubuntu-24.04, macos-26, windows-2022] + attempt: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] timeout-minutes: 240 steps: - uses: actions/checkout@v7 @@ -34,66 +36,17 @@ jobs: **/.vscode-ffmpeg **/.vscode-resolve-source-map-cache key: ${{ runner.os }}-cacheNodeModules-${{ steps.nodeModulesCacheKey.outputs.value }} - - name: Compute source maps cache key - id: sourceMapsCacheKey - run: echo "value=$(node packages/build/src/computeSourceMapsCacheKey.ts)" >> $GITHUB_OUTPUT - shell: bash - - uses: actions/cache@v6 - id: source-maps-cache - with: - path: | - **/.vscode-source-maps - **/.vscode-sources - key: ${{ runner.os }}-cacheSourceMaps-${{ steps.sourceMapsCacheKey.outputs.value }} - name: npm ci run: npm ci --ignore-scripts && npm run postinstall if: steps.npm-cache.outputs.cache-hit != 'true' - - run: npm run type-check - - run: npm run lint - run: npm run build - - run: npx lerna run test --since origin/main - - name: Run headless test (with videos) - if: matrix.os != 'macos-26' - uses: coactions/setup-xvfb@v1 - with: - run: node packages/cli/bin/test.js --cwd packages/e2e --record-video - - name: Run headless test - uses: coactions/setup-xvfb@v1 - with: - run: npm run e2e - - name: Run headless test (flakyness check) - if: matrix.os != 'macos-26' - uses: coactions/setup-xvfb@v1 - with: - run: npm run e2e:check-flakyness - - name: Run headless test (second flakyness check) - if: matrix.os != 'macos-26' - uses: coactions/setup-xvfb@v1 - with: - run: npm run e2e:check-flakyness - - name: Run headless test (check leaks, event listener count) - if: matrix.os != 'macos-26' - uses: coactions/setup-xvfb@v1 - with: - run: node packages/cli/bin/test.js --cwd packages/e2e --check-leaks --measure-after - - name: Run headless test (check leaks, event listeners) - if: matrix.os == 'ubuntu-24.04' - uses: coactions/setup-xvfb@v1 - with: - run: node packages/cli/bin/test.js --cwd packages/e2e --check-leaks --measure event-listeners - - name: Run Memory City smoke test - if: matrix.os == 'ubuntu-24.04' + - name: Run markdown-preview-switch uses: coactions/setup-xvfb@v1 with: - run: node packages/cli/bin/test.js --cwd packages/e2e --check-leaks --measure memory-city --only ^editor-open.ts --workers 1 - - name: Generate charts - run: node packages/charts/src/main.ts - - name: Validate Memory City artifact - if: matrix.os == 'ubuntu-24.04' - run: node packages/visualizations/src/validate.ts + run: node packages/cli/bin/test.js --cwd packages/e2e --record-video --only ^markdown-preview-switch.ts --workers 1 --run-skipped-tests-anyway - uses: actions/upload-artifact@v7 if: always() with: - name: vscode-videos-${{ runner.os }} + name: markdown-preview-switch-attempt-${{ matrix.attempt }} path: ./.vscode-videos include-hidden-files: true From 33cc9e13826eddc6fbaef39738f9bb3168bb10ed Mon Sep 17 00:00:00 2001 From: Simon Siefke Date: Sat, 18 Jul 2026 10:38:37 +0000 Subject: [PATCH 2/2] fix: reattach markdown preview after navigation --- .../parts/MarkdownPreview/MarkdownPreview.ts | 73 +++++++++++++------ 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/packages/page-object/src/parts/MarkdownPreview/MarkdownPreview.ts b/packages/page-object/src/parts/MarkdownPreview/MarkdownPreview.ts index 846bce7bb1..f8ca898eb8 100644 --- a/packages/page-object/src/parts/MarkdownPreview/MarkdownPreview.ts +++ b/packages/page-object/src/parts/MarkdownPreview/MarkdownPreview.ts @@ -1,28 +1,48 @@ import type { CreateParams } from '../CreateParams/CreateParams.ts' +const isPreviewNavigationError = (error: unknown): boolean => { + const message = String((error as any)?.message || error || '') + return ( + message.includes('Execution context was destroyed') || + message.includes('uniqueContextId not found') || + message.includes('Cannot find context with specified id') + ) +} + export const create = ({ expect, page, VError }: CreateParams) => { + const getVisibleSubFrame = async () => { + await page.waitForIdle() + const webView = page.locator('.webview') + await expect(webView).toBeVisible() + await page.waitForIdle() + await expect(webView).toHaveClass('ready') + await page.waitForIdle() + const childPage = await page.waitForIframe({ + injectUtilityScript: false, + url: /extensionId=vscode.markdown-language-features/, + }) + // TODO double iframe... + const subFrame = await childPage.waitForSubIframe({ + url: /extensionId=vscode.markdown-language-features/, + }) + await subFrame.waitForIdle() + const markDown = subFrame.locator('.markdown-body') + await expect(markDown).toBeVisible() + await page.waitForIdle() + return subFrame + } + + const checkHeading = async (subFrame: any, id: string) => { + await page.waitForIdle() + const heading = subFrame.locator(`#${id}`) + await expect(heading).toBeVisible() + await page.waitForIdle() + } + return { async shouldBeVisible() { try { - await page.waitForIdle() - const webView = page.locator('.webview') - await expect(webView).toBeVisible() - await page.waitForIdle() - await expect(webView).toHaveClass('ready') - await page.waitForIdle() - const childPage = await page.waitForIframe({ - injectUtilityScript: false, - url: /extensionId=vscode.markdown-language-features/, - }) - // TODO double iframe... - const subFrame = await childPage.waitForSubIframe({ - url: /extensionId=vscode.markdown-language-features/, - }) - await subFrame.waitForIdle() - const markDown = subFrame.locator('.markdown-body') - await expect(markDown).toBeVisible() - await page.waitForIdle() - return subFrame + return await getVisibleSubFrame() } catch (error) { throw new VError(error, `Failed to check that markdown preview is visible`) } @@ -49,12 +69,17 @@ export const create = ({ expect, page, VError }: CreateParams) => { }, async shouldHaveHeading(subFrame: any, id: string) { try { - await page.waitForIdle() - const heading = subFrame.locator(`#${id}`) - await expect(heading).toBeVisible() - await page.waitForIdle() + await checkHeading(subFrame, id) } catch (error) { - throw new VError(error, `Failed to check that markdown preview has heading ${id}`) + if (!isPreviewNavigationError(error)) { + throw new VError(error, `Failed to check that markdown preview has heading ${id}`) + } + try { + const currentSubFrame = await getVisibleSubFrame() + await checkHeading(currentSubFrame, id) + } catch (navigationError) { + throw new VError(navigationError, `Failed to check that markdown preview has heading ${id}`) + } } }, }