Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions packages/playwright/src/transform/esmLoaderSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { currentFileDepsCollector } from './compilationCache';
import { resolveHook, shouldTransform, transformHook } from './transform';
import { fileIsModule } from '../util';

export function resolve(specifier: string, context: { parentURL?: string, conditions?: string[] }, nextResolve: Function) {
export function resolve(specifier: string, context: { parentURL?: string, conditions?: string[] | Set<string> }, nextResolve: Function) {
if (context.parentURL && context.parentURL.startsWith('file://')) {
const filename = url.fileURLToPath(context.parentURL);
const resolved = resolveHook(filename, specifier);
Expand All @@ -32,7 +32,13 @@ export function resolve(specifier: string, context: { parentURL?: string, condit
// - the ESM resolver wants a file:// URL and, on Windows, mistakes an absolute path's
// drive letter for a URL scheme ("Received protocol 'c:'").
// The `import` condition is present only for ESM resolution, so use it to pick the form.
specifier = context.conditions?.includes('import') ? url.pathToFileURL(resolved).toString() : resolved;
// Node registerHooks may pass `conditions` as a Set (instead of Array) in some
// require-initiated sync hook paths on Node 22.15-22.16 (see #41311, related #41138).
const conditions = context.conditions;
const isImport = conditions && (typeof (conditions as any).has === 'function'
? (conditions as any).has('import')
: (conditions as any).includes('import'));
specifier = isImport ? url.pathToFileURL(resolved).toString() : resolved;
}
}
const result = nextResolve(specifier, context);
Expand Down
21 changes: 21 additions & 0 deletions tests/playwright-test/loader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1317,3 +1317,24 @@ test('preflight should survive faulty ESM loader ahead of playwright', {
expect(result.output).toContain('Failed to load preflight');
expect(result.output).toContain('what the heck is preflight');
});

test('esm sync loader resolve should handle conditions as Set or Array (Node 22.15 registerHooks regression)', {
annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/41311' },
}, async ({ runInlineTest }) => {
// Exercises the resolve hook path (file:// parent + 'import' condition) that was
// introduced in #41138 and is now robust to conditions being a Set (as Node's
// registerHooks can pass on some 22.15-22.16 require-initiated sync paths).
// The linked issue has the full repro requiring Node 22.15; this covers the code path
// in our test matrix.
const result = await runInlineTest({
'package.json': JSON.stringify({ type: 'module' }),
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('pass', () => {
expect(1 + 1).toBe(2);
});
`,
}, { workers: 1 });
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(1);
});