From a037ba8965bc4d49381bc834d12750e7dc2eb518 Mon Sep 17 00:00:00 2001 From: Sarah Fortune Date: Fri, 3 Oct 2025 20:49:00 +0000 Subject: [PATCH] Make the results of the GH test workflow easier to understand & fix windows tests (#6628) * Dont use continue-on-error in the GH workflow Using continue-on-error makes the tests appear as passed even when they failed and this is confusing * Increase timeout for getOpenTabs test * Dont run any tests if the build step failed * Update .github/workflows/test.yml Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * Fix getOpenTabs on tabs ``` Extension host test runner error 1 test failed. 1 failing 1) Hostbridge - Window - getOpenTabs should return all tabs including deleted files: Error: EBUSY: resource busy or locked, rmdir 'C:\Users\RUNNER~1\AppData\Local\Temp\vscode-test-O06Qnd' ``` The test is failing because the clean can't delete the temp directory it created, just surround it with try/catch. * Add debug logs to the openTabsTest * Increase the timeout on the e2e tests I see this test timing out, so try increasing the timeout https://github.com/cline/cline/actions/runs/18209633465/job/51847553463?pr=6628 --------- Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 27 +++++-------------- .../hostbridge/window/getOpenTabs.test.ts | 24 ++++++++++++----- src/test/e2e/utils/helpers.ts | 2 +- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 24ac19178e..a34cea6cc5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -103,53 +103,38 @@ jobs: # Build the extension and tests (without redundant checks) - name: Build Tests and Extension + id: build_step run: npm run ci:build - name: Unit Tests with coverage - Linux id: unit_tests_linux - continue-on-error: true - if: runner.os == 'Linux' + if: ${{ !cancelled() && steps.build_step.outcome == 'success' && runner.os == 'Linux' }} run: | npx nyc --nycrc-path .nycrc.unit.json --reporter=lcov npm run test:unit - name: Unit Tests - Non-Linux id: unit_tests_non_linux - continue-on-error: true - if: runner.os != 'Linux' + if: ${{ !cancelled() && steps.build_step.outcome == 'success' && runner.os != 'Linux' }} run: | npm run test:unit - name: Extension Integration Tests - Linux id: integration_tests_linux - continue-on-error: true - if: runner.os == 'Linux' + if: ${{ !cancelled() && steps.build_step.outcome == 'success' && runner.os == 'Linux' }} run: xvfb-run -a npm run test:coverage - name: Extension Integration Tests - Non-Linux id: integration_tests_non_linux - continue-on-error: true - if: runner.os != 'Linux' + if: ${{ !cancelled() && steps.build_step.outcome == 'success' && runner.os != 'Linux' }} run: npm run test:integration - name: Webview Tests with Coverage id: webview_tests - continue-on-error: true + if: ${{ !cancelled() && steps.build_step.outcome == 'success' }} run: | cd webview-ui npm run test:coverage - - name: Check Test Results - if: always() - run: | - failed="" - [[ "${{ steps.unit_tests_linux.outcome }}" == "failure" && "${{ runner.os }}" == "Linux" ]] && failed="$failed unit_tests_linux" - [[ "${{ steps.unit_tests_non_linux.outcome }}" == "failure" && "${{ runner.os }}" != "Linux" ]] && failed="$failed unit_tests_non_linux" - [[ "${{ steps.integration_tests_linux.outcome }}" == "failure" && "${{ runner.os }}" == "Linux" ]] && failed="$failed integration_tests_linux" - [[ "${{ steps.integration_tests_non_linux.outcome }}" == "failure" && "${{ runner.os }}" != "Linux" ]] && failed="$failed integration_tests_non_linux" - [[ "${{ steps.webview_tests.outcome }}" == "failure" ]] && failed="$failed webview_tests" - [[ -n "$failed" ]] && { echo "❌ The following test suites failed:$failed"; exit 1; } - echo "✅ All tests passed" - - name: Save Coverage Reports uses: actions/upload-artifact@v4 # Only upload artifacts on Linux - We only need coverage from one OS diff --git a/src/hosts/vscode/hostbridge/window/getOpenTabs.test.ts b/src/hosts/vscode/hostbridge/window/getOpenTabs.test.ts index a3b36e1111..53a0079c04 100644 --- a/src/hosts/vscode/hostbridge/window/getOpenTabs.test.ts +++ b/src/hosts/vscode/hostbridge/window/getOpenTabs.test.ts @@ -62,10 +62,13 @@ describe("Hostbridge - Window - getOpenTabs", () => { async () => { const request = GetOpenTabsRequest.create({}) const response = await getOpenTabs(request) + console.log( + `[DEBUG] Waiting for 2 tabs, currently found ${response.paths.length}: ${JSON.stringify(response.paths)}`, + ) return response.paths.length === 2 }, { - timeout: 4000, + timeout: 8000, interval: 50, }, ) @@ -92,10 +95,13 @@ describe("Hostbridge - Window - getOpenTabs", () => { async () => { const request = GetOpenTabsRequest.create({}) const response = await getOpenTabs(request) + console.log( + `[DEBUG] Waiting for 3 tabs, currently found ${response.paths.length}: ${JSON.stringify(response.paths)}`, + ) return response.paths.length === 3 }, { - timeout: 4000, + timeout: 8000, interval: 50, }, ) @@ -129,10 +135,13 @@ describe("Hostbridge - Window - getOpenTabs", () => { async () => { const request = GetOpenTabsRequest.create({}) const response = await getOpenTabs(request) + console.log( + `[DEBUG] Waiting for 2 tabs (temp file + untitled), currently found ${response.paths.length}: ${JSON.stringify(response.paths)}`, + ) return response.paths.length === 2 }, { - timeout: 4000, + timeout: 8000, interval: 50, }, ) @@ -150,8 +159,11 @@ describe("Hostbridge - Window - getOpenTabs", () => { 2, `Host bridge should return all tabs including deleted files. Found tabs: ${JSON.stringify(response.paths)}`, ) - - // Clean up temp directory - await fs.rmdir(tempDir, { recursive: true }) + try { + // Clean up temp directory + await fs.rmdir(tempDir, { recursive: true }) + } catch (error) { + console.error(error) + } }) }) diff --git a/src/test/e2e/utils/helpers.ts b/src/test/e2e/utils/helpers.ts index e855a89158..2e25754a2b 100644 --- a/src/test/e2e/utils/helpers.ts +++ b/src/test/e2e/utils/helpers.ts @@ -57,7 +57,7 @@ export class E2ETestHelper { return `${baseName}${projectSuffix}` } - public static async waitUntil(predicate: () => boolean | Promise, maxDelay = 5000): Promise { + public static async waitUntil(predicate: () => boolean | Promise, maxDelay = 10000): Promise { let delay = 10 const start = Date.now()