From 8d9e401a66d9b521194b40a980bbbe82b98256dc Mon Sep 17 00:00:00 2001 From: yen0304 Date: Thu, 4 Jun 2026 21:25:11 +0800 Subject: [PATCH] fix(test): convert resolved paths to file:// URLs for ESM on Windows The synchronous module hooks resolve function passes absolute paths directly to nextResolve. On Windows, paths like "C:\..." are parsed as having URL protocol "c:", causing ESM resolution to fail with "Only URLs with a scheme in: file, data, and node are supported". Use context.conditions to distinguish ESM from CJS contexts and convert to file:// URLs only for ESM imports, preserving the absolute path behavior for CJS require() which rejects file:// specifiers. Fixes: https://github.com/microsoft/playwright/issues/41121 --- .../playwright/src/transform/esmLoaderSync.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/playwright/src/transform/esmLoaderSync.ts b/packages/playwright/src/transform/esmLoaderSync.ts index 13457a7979fce..9b2238e295e5e 100644 --- a/packages/playwright/src/transform/esmLoaderSync.ts +++ b/packages/playwright/src/transform/esmLoaderSync.ts @@ -21,15 +21,19 @@ import { currentFileDepsCollector } from './compilationCache'; import { resolveHook, shouldTransform, transformHook } from './transform'; import { fileIsModule } from '../util'; -export function resolve(specifier: string, context: { parentURL?: string }, nextResolve: Function) { +export function resolve(specifier: string, context: { parentURL?: string, conditions?: string[] }, nextResolve: Function) { if (context.parentURL && context.parentURL.startsWith('file://')) { const filename = url.fileURLToPath(context.parentURL); const resolved = resolveHook(filename, specifier); - // Pass the resolved absolute path (not a file:// URL) to nextResolve: unlike the - // ESM-only asynchronous loader, these hooks also serve require(), whose default - // resolver rejects file:// specifiers but accepts absolute paths for both kinds. - if (resolved !== undefined) - specifier = resolved; + if (resolved !== undefined) { + // ESM resolver on Windows requires file:// URLs — absolute paths like "C:\..." + // are parsed as having URL protocol "c:". CJS resolver accepts absolute paths + // directly. Use context.conditions to pick the right form. + if (context.conditions?.includes('import')) + specifier = url.pathToFileURL(resolved).toString(); + else + specifier = resolved; + } } const result = nextResolve(specifier, context); if (result?.url && result.url.startsWith('file://'))