diff --git a/vscode/extension/tests/fixtures.ts b/vscode/extension/tests/fixtures.ts index 6ce92c3266..c96bb23044 100644 --- a/vscode/extension/tests/fixtures.ts +++ b/vscode/extension/tests/fixtures.ts @@ -8,6 +8,33 @@ import { CodeServerContext, } from './utils_code_server' +const REMOVE_RETRY_DELAYS_MS = [100, 250, 500, 1000, 2000] + +/** + * Remove a directory, retrying with a backoff. + * + * When a test finishes, the extension host may still be writing into its + * temporary directory - the language server is shutting down, or uv is + * finishing off a virtual environment it created there. A single `fs.remove` + * then fails with `ENOTEMPTY`, which fails an otherwise passing test. + */ +const removeWithRetry = async (dir: string): Promise => { + for (let attempt = 0; ; attempt++) { + try { + await fs.remove(dir) + return + } catch (error) { + if (attempt >= REMOVE_RETRY_DELAYS_MS.length) { + console.warn(`Failed to remove directory ${dir}:`, error) + return + } + await new Promise(resolve => + setTimeout(resolve, REMOVE_RETRY_DELAYS_MS[attempt]), + ) + } + } +} + // Worker-scoped fixture to start/stop VS Code server once per worker export const test = base.extend< // eslint-disable-next-line @typescript-eslint/no-empty-object-type @@ -52,7 +79,7 @@ export const test = base.extend< // Clean up after each test console.log(`Cleaning up temporary directory: ${tempDir}`) - await fs.remove(tempDir) + await removeWithRetry(tempDir) }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error