fix(test runner): avoid dependency tracking colliding between esm and cjs (#29994)
When collecting dependencies both from CJS loader and from ESM loader, the latter would overwrite the dependencies set instead of appending. Also make sure cts/cjs/mts/mjs are all supported equally. References #29747.
This commit is contained in:
parent
c7b074d39e
commit
b41b802662
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
import util from 'util';
|
||||
import { serializeCompilationCache } from '../transform/compilationCache';
|
||||
import { type SerializedCompilationCache, serializeCompilationCache } from '../transform/compilationCache';
|
||||
import type { ConfigLocation, FullConfigInternal } from './config';
|
||||
import type { ReporterDescription, TestInfoError, TestStatus } from '../../types/test';
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ export type ConfigCLIOverrides = {
|
|||
export type SerializedConfig = {
|
||||
location: ConfigLocation;
|
||||
configCLIOverrides: ConfigCLIOverrides;
|
||||
compilationCache: any;
|
||||
compilationCache?: SerializedCompilationCache;
|
||||
};
|
||||
|
||||
export type TtyParams = {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export type MemoryCache = {
|
|||
moduleUrl?: string;
|
||||
};
|
||||
|
||||
type SerializedCompilationCache = {
|
||||
export type SerializedCompilationCache = {
|
||||
sourceMaps: [string, string][],
|
||||
memoryCache: [string, MemoryCache][],
|
||||
fileDependencies: [string, string[]][],
|
||||
|
|
@ -158,15 +158,19 @@ export function serializeCompilationCache(): SerializedCompilationCache {
|
|||
};
|
||||
}
|
||||
|
||||
export function addToCompilationCache(payload: any) {
|
||||
export function addToCompilationCache(payload: SerializedCompilationCache) {
|
||||
for (const entry of payload.sourceMaps)
|
||||
sourceMaps.set(entry[0], entry[1]);
|
||||
for (const entry of payload.memoryCache)
|
||||
memoryCache.set(entry[0], entry[1]);
|
||||
for (const entry of payload.fileDependencies)
|
||||
fileDependencies.set(entry[0], new Set(entry[1]));
|
||||
for (const entry of payload.externalDependencies)
|
||||
externalDependencies.set(entry[0], new Set(entry[1]));
|
||||
for (const entry of payload.fileDependencies) {
|
||||
const existing = fileDependencies.get(entry[0]) || [];
|
||||
fileDependencies.set(entry[0], new Set([...entry[1], ...existing]));
|
||||
}
|
||||
for (const entry of payload.externalDependencies) {
|
||||
const existing = externalDependencies.get(entry[0]) || [];
|
||||
externalDependencies.set(entry[0], new Set([...entry[1], ...existing]));
|
||||
}
|
||||
}
|
||||
|
||||
function calculateCachePath(filePath: string, hash: string): string {
|
||||
|
|
@ -249,9 +253,9 @@ const kPlaywrightCoveragePrefix = path.resolve(__dirname, '../../../../tests/con
|
|||
export function belongsToNodeModules(file: string) {
|
||||
if (file.includes(`${path.sep}node_modules${path.sep}`))
|
||||
return true;
|
||||
if (file.startsWith(kPlaywrightInternalPrefix) && file.endsWith('.js'))
|
||||
if (file.startsWith(kPlaywrightInternalPrefix) && (file.endsWith('.js') || file.endsWith('.mjs')))
|
||||
return true;
|
||||
if (file.startsWith(kPlaywrightCoveragePrefix) && file.endsWith('.js'))
|
||||
if (file.startsWith(kPlaywrightCoveragePrefix) && (file.endsWith('.js') || file.endsWith('.mjs')))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ function installTransform(): () => void {
|
|||
if (!shouldTransform(filename))
|
||||
return code;
|
||||
return transformHook(code, filename).code;
|
||||
}, { exts: ['.ts', '.tsx', '.js', '.jsx', '.mjs'] });
|
||||
}, { exts: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.mts', '.cjs', '.cts'] });
|
||||
|
||||
return () => {
|
||||
reverted = true;
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ export class TestInfoImpl implements TestInfo {
|
|||
this._timeoutManager = new TimeoutManager(this.project.timeout);
|
||||
|
||||
this.outputDir = (() => {
|
||||
const relativeTestFilePath = path.relative(this.project.testDir, this._requireFile.replace(/\.(spec|test)\.(js|ts|mjs)$/, ''));
|
||||
const relativeTestFilePath = path.relative(this.project.testDir, this._requireFile.replace(/\.(spec|test)\.(js|ts|jsx|tsx|mjs|mts|cjs|cts)$/, ''));
|
||||
const sanitizedRelativePath = relativeTestFilePath.replace(process.platform === 'win32' ? new RegExp('\\\\', 'g') : new RegExp('/', 'g'), '-');
|
||||
const fullTitleWithoutSpec = this.titlePath.slice(1).join(' ');
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,85 @@ test('should print dependencies in ESM mode', async ({ runInlineTest }) => {
|
|||
const output = result.output;
|
||||
const deps = JSON.parse(output.match(/###(.*)###/)![1]);
|
||||
expect(deps).toEqual({
|
||||
'a.test.ts': ['helperA.ts', 'index.mjs'],
|
||||
'b.test.ts': ['helperA.ts', 'helperB.ts', 'index.mjs'],
|
||||
'a.test.ts': ['helperA.ts'],
|
||||
'b.test.ts': ['helperA.ts', 'helperB.ts'],
|
||||
});
|
||||
});
|
||||
|
||||
test('should print dependencies in mixed CJS/ESM mode 1', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'package.json': `{ "type": "module" }`,
|
||||
'playwright.config.ts': `
|
||||
import { defineConfig } from '@playwright/test';
|
||||
export default defineConfig({
|
||||
globalTeardown: './globalTeardown.ts',
|
||||
});
|
||||
`,
|
||||
'helperA.cjs': `exports.foo = () => {}`,
|
||||
'helperB.cjs': `require('./helperA');`,
|
||||
'a.test.ts': `
|
||||
import './helperA';
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('passes', () => {});
|
||||
`,
|
||||
'b.test.cjs': `
|
||||
require('./helperB');
|
||||
const { test, expect } = require('@playwright/test');
|
||||
test('passes', () => {});
|
||||
`,
|
||||
'globalTeardown.ts': `
|
||||
import { fileDependencies } from 'playwright/lib/internalsForTest';
|
||||
export default () => {
|
||||
console.log('###' + JSON.stringify(fileDependencies()) + '###');
|
||||
};
|
||||
`
|
||||
}, {});
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.passed).toBe(2);
|
||||
const output = result.output;
|
||||
const deps = JSON.parse(output.match(/###(.*)###/)![1]);
|
||||
expect(deps).toEqual({
|
||||
'a.test.ts': ['helperA.cjs'],
|
||||
'b.test.cjs': ['helperA.cjs', 'helperB.cjs'],
|
||||
});
|
||||
});
|
||||
|
||||
test('should print dependencies in mixed CJS/ESM mode 2', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.mts': `
|
||||
import { defineConfig } from '@playwright/test';
|
||||
export default defineConfig({
|
||||
globalTeardown: './globalTeardown.ts',
|
||||
});
|
||||
`,
|
||||
'helperA.cjs': `exports.foo = () => {}`,
|
||||
'helperB.cts': `import './helperA';`,
|
||||
'a.test.mts': `
|
||||
import './helperA';
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('passes', () => {});
|
||||
`,
|
||||
'b.test.ts': `
|
||||
import './helperB';
|
||||
const { test, expect } = require('@playwright/test');
|
||||
test('passes', () => {});
|
||||
`,
|
||||
'globalTeardown.ts': `
|
||||
import { fileDependencies } from 'playwright/lib/internalsForTest';
|
||||
export default () => {
|
||||
console.log('###' + JSON.stringify(fileDependencies()) + '###');
|
||||
};
|
||||
`
|
||||
}, {});
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.passed).toBe(2);
|
||||
const output = result.output;
|
||||
const deps = JSON.parse(output.match(/###(.*)###/)![1]);
|
||||
expect(deps).toEqual({
|
||||
'a.test.mts': ['helperA.cjs'],
|
||||
'b.test.ts': ['helperA.cjs', 'helperB.cts'],
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue