mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: respect source map sources when filtering in CLI (#22180)
Fixes #22123
This commit is contained in:
parent
8bc7ed0469
commit
87acda74ff
@ -14,9 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import readline from 'readline';
|
||||
import type { Reporter, TestError } from '../../types/testReporter';
|
||||
import { InProcessLoaderHost, OutOfProcessLoaderHost } from './loaderHost';
|
||||
import { Suite } from '../common/test';
|
||||
@ -29,6 +27,8 @@ import { requireOrImport } from '../common/transform';
|
||||
import { buildFileSuiteForProject, filterByFocusedLine, filterByTestIds, filterOnly, filterTestsRemoveEmptySuites } from '../common/suiteUtils';
|
||||
import { createTestGroups, filterForShard, type TestGroup } from './testGroups';
|
||||
import { dependenciesForTestFile } from '../common/compilationCache';
|
||||
import { sourceMapSupport } from '../utilsBundle';
|
||||
import type { RawSourceMap } from 'source-map';
|
||||
|
||||
export async function collectProjectsAndTestFiles(config: FullConfigInternal, projectsToIgnore: Set<FullProjectInternal>, additionalFileMatcher: Matcher | undefined) {
|
||||
const fsCache = new Map();
|
||||
@ -47,15 +47,16 @@ export async function collectProjectsAndTestFiles(config: FullConfigInternal, pr
|
||||
// Filter files based on the file filters, eliminate the empty projects.
|
||||
const filesToRunByProject = new Map<FullProjectInternal, string[]>();
|
||||
for (const [project, files] of allFilesForProject) {
|
||||
const matchedFiles = await Promise.all(files.map(async file => {
|
||||
if (additionalFileMatcher && !additionalFileMatcher(file))
|
||||
return;
|
||||
if (cliFileMatcher) {
|
||||
if (!cliFileMatcher(file) && !await isPotentiallyJavaScriptFileWithSourceMap(file, sourceMapCache))
|
||||
return;
|
||||
}
|
||||
return file;
|
||||
}));
|
||||
const matchedFiles = files.filter(file => {
|
||||
const hasMatchingSources = sourceMapSources(file, sourceMapCache).some(source => {
|
||||
if (additionalFileMatcher && !additionalFileMatcher(source))
|
||||
return false;
|
||||
if (cliFileMatcher && !cliFileMatcher(source))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
return hasMatchingSources;
|
||||
});
|
||||
const filteredFiles = matchedFiles.filter(Boolean) as string[];
|
||||
if (filteredFiles.length)
|
||||
filesToRunByProject.set(project, filteredFiles);
|
||||
@ -263,29 +264,20 @@ export function loadReporter(config: FullConfigInternal, file: string): Promise<
|
||||
return requireOrImportDefaultFunction(path.resolve(config.rootDir, file), true);
|
||||
}
|
||||
|
||||
async function isPotentiallyJavaScriptFileWithSourceMap(file: string, cache: Map<string, boolean>): Promise<boolean> {
|
||||
function sourceMapSources(file: string, cache: Map<string, string[]>): string[] {
|
||||
let sources = [file];
|
||||
if (!file.endsWith('.js'))
|
||||
return false;
|
||||
return sources;
|
||||
if (cache.has(file))
|
||||
return cache.get(file)!;
|
||||
|
||||
try {
|
||||
const stream = fs.createReadStream(file);
|
||||
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
||||
let lastLine: string | undefined;
|
||||
rl.on('line', line => {
|
||||
lastLine = line;
|
||||
});
|
||||
await new Promise((fulfill, reject) => {
|
||||
rl.on('close', fulfill);
|
||||
rl.on('error', reject);
|
||||
stream.on('error', reject);
|
||||
});
|
||||
const hasSourceMap = !!lastLine && lastLine.startsWith('//# sourceMappingURL=');
|
||||
cache.set(file, hasSourceMap);
|
||||
return hasSourceMap;
|
||||
} catch (e) {
|
||||
cache.set(file, true);
|
||||
return true;
|
||||
const sourceMap = sourceMapSupport.retrieveSourceMap(file);
|
||||
const sourceMapData: RawSourceMap | undefined = typeof sourceMap?.map === 'string' ? JSON.parse(sourceMap.map) : sourceMap?.map;
|
||||
if (sourceMapData?.sources)
|
||||
sources = sourceMapData.sources.map(source => path.resolve(path.dirname(file), source));
|
||||
} finally {
|
||||
cache.set(file, sources);
|
||||
return sources;
|
||||
}
|
||||
}
|
||||
|
||||
@ -503,21 +503,26 @@ test('should not load tests not matching filter', async ({ runInlineTest }) => {
|
||||
});
|
||||
|
||||
test('should filter by sourcemapped file names', async ({ runInlineTest }) => {
|
||||
const fileWithSourceMap = `` +
|
||||
`import {test} from '@playwright/test';
|
||||
test.describe('Some describe', ()=>{
|
||||
test('Some test', async ()=>{
|
||||
console.log('test')
|
||||
})
|
||||
})
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImdoZXJraW4uZmVhdHVyZSJdLCJuYW1lcyI6WyJOb25lIl0sIm1hcHBpbmdzIjoiQUFBQUE7QUFBQUE7QUFBQUE7QUFBQUE7QUFBQUE7QUFBQUEiLCJmaWxlIjoiZ2hlcmtpbi5mZWF0dXJlIiwic291cmNlc0NvbnRlbnQiOlsiVGVzdCJdfQ==`;
|
||||
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.js': `export default { projects: [{}, {}] }`,
|
||||
'a.spec.js': fileWithSourceMap,
|
||||
'gherkin.spec.js': `
|
||||
|
||||
import { test } from '@playwright/test';
|
||||
test('should run', () => {});
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImdoZXJraW4uZmVhdHVyZSJdLCJuYW1lcyI6WyJOb25lIl0sIm1hcHBpbmdzIjoiQUFBQUE7QUFBQUE7QUFBQUE7QUFBQUE7QUFBQUE7QUFBQUEiLCJmaWxlIjoiZ2hlcmtpbi5mZWF0dXJlIiwic291cmNlc0NvbnRlbnQiOlsiVGVzdCJdfQ==`,
|
||||
|
||||
'another.spec.js': `
|
||||
|
||||
throw new Error('should not load another.spec.js');
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFub3RoZXIuZmVhdHVyZSJdLCJuYW1lcyI6WyJOb25lIl0sIm1hcHBpbmdzIjoiQUFBQUE7QUFBQUE7QUFBQUE7QUFBQUE7QUFBQUE7QUFBQUEiLCJmaWxlIjoiZ2hlcmtpbi5mZWF0dXJlIiwic291cmNlc0NvbnRlbnQiOlsiVGVzdCJdfQ==`,
|
||||
|
||||
'nomap.spec.js': `
|
||||
|
||||
throw new Error('should not load nomap.spec.js');`,
|
||||
}, {}, {}, { additionalArgs: ['gherkin.feature'] });
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.passed).toBe(2);
|
||||
expect(result.output).not.toContain('a.spec.js');
|
||||
expect(result.passed).toBe(1);
|
||||
expect(result.output).not.toContain('spec.js');
|
||||
expect(result.output).not.toContain('another.feature.js');
|
||||
expect(result.output).not.toContain('should not load');
|
||||
expect(result.output).toContain('gherkin.feature:1');
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user