fix(test runner): avoid dependency tracking colliding between esm and cjs
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.
This commit is contained in:
parent
0db1d40abc
commit
1dcc04bb6a
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import util from 'util';
|
import util from 'util';
|
||||||
import { serializeCompilationCache } from '../transform/compilationCache';
|
import { type SerializedCompilationCache, serializeCompilationCache } from '../transform/compilationCache';
|
||||||
import type { ConfigLocation, FullConfigInternal } from './config';
|
import type { ConfigLocation, FullConfigInternal } from './config';
|
||||||
import type { ReporterDescription, TestInfoError, TestStatus } from '../../types/test';
|
import type { ReporterDescription, TestInfoError, TestStatus } from '../../types/test';
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ export type ConfigCLIOverrides = {
|
||||||
export type SerializedConfig = {
|
export type SerializedConfig = {
|
||||||
location: ConfigLocation;
|
location: ConfigLocation;
|
||||||
configCLIOverrides: ConfigCLIOverrides;
|
configCLIOverrides: ConfigCLIOverrides;
|
||||||
compilationCache: any;
|
compilationCache?: SerializedCompilationCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TtyParams = {
|
export type TtyParams = {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export type MemoryCache = {
|
||||||
moduleUrl?: string;
|
moduleUrl?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SerializedCompilationCache = {
|
export type SerializedCompilationCache = {
|
||||||
sourceMaps: [string, string][],
|
sourceMaps: [string, string][],
|
||||||
memoryCache: [string, MemoryCache][],
|
memoryCache: [string, MemoryCache][],
|
||||||
fileDependencies: [string, string[]][],
|
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)
|
for (const entry of payload.sourceMaps)
|
||||||
sourceMaps.set(entry[0], entry[1]);
|
sourceMaps.set(entry[0], entry[1]);
|
||||||
for (const entry of payload.memoryCache)
|
for (const entry of payload.memoryCache)
|
||||||
memoryCache.set(entry[0], entry[1]);
|
memoryCache.set(entry[0], entry[1]);
|
||||||
for (const entry of payload.fileDependencies)
|
for (const entry of payload.fileDependencies) {
|
||||||
fileDependencies.set(entry[0], new Set(entry[1]));
|
const existing = fileDependencies.get(entry[0]) || [];
|
||||||
for (const entry of payload.externalDependencies)
|
fileDependencies.set(entry[0], new Set([...entry[1], ...existing]));
|
||||||
externalDependencies.set(entry[0], new Set(entry[1]));
|
}
|
||||||
|
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 {
|
function calculateCachePath(filePath: string, hash: string): string {
|
||||||
|
|
@ -249,9 +253,9 @@ const kPlaywrightCoveragePrefix = path.resolve(__dirname, '../../../../tests/con
|
||||||
export function belongsToNodeModules(file: string) {
|
export function belongsToNodeModules(file: string) {
|
||||||
if (file.includes(`${path.sep}node_modules${path.sep}`))
|
if (file.includes(`${path.sep}node_modules${path.sep}`))
|
||||||
return true;
|
return true;
|
||||||
if (file.startsWith(kPlaywrightInternalPrefix) && file.endsWith('.js'))
|
if (file.startsWith(kPlaywrightInternalPrefix) && (file.endsWith('.js') || file.endsWith('.mjs')))
|
||||||
return true;
|
return true;
|
||||||
if (file.startsWith(kPlaywrightCoveragePrefix) && file.endsWith('.js'))
|
if (file.startsWith(kPlaywrightCoveragePrefix) && (file.endsWith('.js') || file.endsWith('.mjs')))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,7 @@ function installTransform(): () => void {
|
||||||
if (!shouldTransform(filename))
|
if (!shouldTransform(filename))
|
||||||
return code;
|
return code;
|
||||||
return transformHook(code, filename).code;
|
return transformHook(code, filename).code;
|
||||||
}, { exts: ['.ts', '.tsx', '.js', '.jsx', '.mjs'] });
|
}, { exts: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.mts', '.cjs', '.cts'] });
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
reverted = true;
|
reverted = true;
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ export class TestInfoImpl implements TestInfo {
|
||||||
this._timeoutManager = new TimeoutManager(this.project.timeout);
|
this._timeoutManager = new TimeoutManager(this.project.timeout);
|
||||||
|
|
||||||
this.outputDir = (() => {
|
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 sanitizedRelativePath = relativeTestFilePath.replace(process.platform === 'win32' ? new RegExp('\\\\', 'g') : new RegExp('/', 'g'), '-');
|
||||||
const fullTitleWithoutSpec = this.titlePath.slice(1).join(' ');
|
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 output = result.output;
|
||||||
const deps = JSON.parse(output.match(/###(.*)###/)![1]);
|
const deps = JSON.parse(output.match(/###(.*)###/)![1]);
|
||||||
expect(deps).toEqual({
|
expect(deps).toEqual({
|
||||||
'a.test.ts': ['helperA.ts', 'index.mjs'],
|
'a.test.ts': ['helperA.ts'],
|
||||||
'b.test.ts': ['helperA.ts', 'helperB.ts', 'index.mjs'],
|
'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