mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(runner): ignore .gitignore if testDir is explicitly configured (#14430)
If the tests are in an explicitly configured testDir (either at the global config level or per project) .gitignore filters are not applied. Fixes #14381
This commit is contained in:
parent
6efb1ec40c
commit
b164d82ba3
@ -239,6 +239,7 @@ export class Loader {
|
|||||||
projectConfig.snapshotDir = path.resolve(this._configDir, projectConfig.snapshotDir);
|
projectConfig.snapshotDir = path.resolve(this._configDir, projectConfig.snapshotDir);
|
||||||
|
|
||||||
const testDir = takeFirst(projectConfig.testDir, config.testDir, this._configDir);
|
const testDir = takeFirst(projectConfig.testDir, config.testDir, this._configDir);
|
||||||
|
const respectGitIgnore = !projectConfig.testDir && !config.testDir;
|
||||||
|
|
||||||
const outputDir = takeFirst(projectConfig.outputDir, config.outputDir, path.join(throwawayArtifactsPath, 'test-results'));
|
const outputDir = takeFirst(projectConfig.outputDir, config.outputDir, path.join(throwawayArtifactsPath, 'test-results'));
|
||||||
const snapshotDir = takeFirst(projectConfig.snapshotDir, config.snapshotDir, testDir);
|
const snapshotDir = takeFirst(projectConfig.snapshotDir, config.snapshotDir, testDir);
|
||||||
@ -256,6 +257,7 @@ export class Loader {
|
|||||||
metadata: takeFirst(projectConfig.metadata, config.metadata, undefined),
|
metadata: takeFirst(projectConfig.metadata, config.metadata, undefined),
|
||||||
name,
|
name,
|
||||||
testDir,
|
testDir,
|
||||||
|
_respectGitIgnore: respectGitIgnore,
|
||||||
snapshotDir,
|
snapshotDir,
|
||||||
_screenshotsDir: screenshotsDir,
|
_screenshotsDir: screenshotsDir,
|
||||||
testIgnore: takeFirst(projectConfig.testIgnore, config.testIgnore, []),
|
testIgnore: takeFirst(projectConfig.testIgnore, config.testIgnore, []),
|
||||||
|
@ -244,7 +244,7 @@ export class Runner {
|
|||||||
|
|
||||||
const files = new Map<FullProjectInternal, string[]>();
|
const files = new Map<FullProjectInternal, string[]>();
|
||||||
for (const project of projects) {
|
for (const project of projects) {
|
||||||
const allFiles = await collectFiles(project.testDir);
|
const allFiles = await collectFiles(project.testDir, project._respectGitIgnore);
|
||||||
const testMatch = createFileMatcher(project.testMatch);
|
const testMatch = createFileMatcher(project.testMatch);
|
||||||
const testIgnore = createFileMatcher(project.testIgnore);
|
const testIgnore = createFileMatcher(project.testIgnore);
|
||||||
const extensions = ['.js', '.ts', '.mjs', '.tsx', '.jsx'];
|
const extensions = ['.js', '.ts', '.mjs', '.tsx', '.jsx'];
|
||||||
@ -534,7 +534,7 @@ function filterSuite(suite: Suite, suiteFilter: (suites: Suite) => boolean, test
|
|||||||
suite._entries = suite._entries.filter(e => entries.has(e)); // Preserve the order.
|
suite._entries = suite._entries.filter(e => entries.has(e)); // Preserve the order.
|
||||||
}
|
}
|
||||||
|
|
||||||
async function collectFiles(testDir: string): Promise<string[]> {
|
async function collectFiles(testDir: string, respectGitIgnore: boolean): Promise<string[]> {
|
||||||
if (!fs.existsSync(testDir))
|
if (!fs.existsSync(testDir))
|
||||||
return [];
|
return [];
|
||||||
if (!fs.statSync(testDir).isDirectory())
|
if (!fs.statSync(testDir).isDirectory())
|
||||||
@ -574,25 +574,29 @@ async function collectFiles(testDir: string): Promise<string[]> {
|
|||||||
const entries = await readDirAsync(dir, { withFileTypes: true });
|
const entries = await readDirAsync(dir, { withFileTypes: true });
|
||||||
entries.sort((a, b) => a.name.localeCompare(b.name));
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
|
||||||
const gitignore = entries.find(e => e.isFile() && e.name === '.gitignore');
|
if (respectGitIgnore) {
|
||||||
if (gitignore) {
|
const gitignore = entries.find(e => e.isFile() && e.name === '.gitignore');
|
||||||
const content = await readFileAsync(path.join(dir, gitignore.name), 'utf8');
|
if (gitignore) {
|
||||||
const newRules: Rule[] = content.split(/\r?\n/).map(s => {
|
const content = await readFileAsync(path.join(dir, gitignore.name), 'utf8');
|
||||||
s = s.trim();
|
const newRules: Rule[] = content.split(/\r?\n/).map(s => {
|
||||||
if (!s)
|
s = s.trim();
|
||||||
return;
|
if (!s)
|
||||||
// Use flipNegate, because we handle negation ourselves.
|
return;
|
||||||
const rule = new minimatch.Minimatch(s, { matchBase: true, dot: true, flipNegate: true }) as any;
|
// Use flipNegate, because we handle negation ourselves.
|
||||||
if (rule.comment)
|
const rule = new minimatch.Minimatch(s, { matchBase: true, dot: true, flipNegate: true }) as any;
|
||||||
return;
|
if (rule.comment)
|
||||||
rule.dir = dir;
|
return;
|
||||||
return rule;
|
rule.dir = dir;
|
||||||
}).filter(rule => !!rule);
|
return rule;
|
||||||
rules = [...rules, ...newRules];
|
}).filter(rule => !!rule);
|
||||||
|
rules = [...rules, ...newRules];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
if (entry === gitignore || entry.name === '.' || entry.name === '..')
|
if (entry.name === '.' || entry.name === '..')
|
||||||
|
continue;
|
||||||
|
if (entry.isFile() && entry.name === '.gitignore')
|
||||||
continue;
|
continue;
|
||||||
if (entry.isDirectory() && entry.name === 'node_modules')
|
if (entry.isDirectory() && entry.name === 'node_modules')
|
||||||
continue;
|
continue;
|
||||||
|
@ -58,4 +58,5 @@ export interface FullProjectInternal extends FullProjectPublic {
|
|||||||
_fullyParallel: boolean;
|
_fullyParallel: boolean;
|
||||||
_expect: Project['expect'];
|
_expect: Project['expect'];
|
||||||
_screenshotsDir: string;
|
_screenshotsDir: string;
|
||||||
|
_respectGitIgnore: boolean;
|
||||||
}
|
}
|
||||||
|
@ -109,3 +109,51 @@ test('should respect negations and comments in .gitignore', async ({ runInlineTe
|
|||||||
'%%dir3/a.spec.js',
|
'%%dir3/a.spec.js',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should ignore .gitignore inside globally configured testDir', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'tests/.gitignore': `
|
||||||
|
*.js
|
||||||
|
`,
|
||||||
|
'playwright.config.js': `
|
||||||
|
module.exports = {
|
||||||
|
testDir: './tests',
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'tests/a.spec.js': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('pass', ({}) => {});
|
||||||
|
`,
|
||||||
|
'tests/foo/b.spec.js': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('pass', ({}) => {});
|
||||||
|
`
|
||||||
|
});
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('should ignore .gitignore inside project testDir', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'tests/.gitignore': `
|
||||||
|
*.js
|
||||||
|
`,
|
||||||
|
'playwright.config.js': `
|
||||||
|
module.exports = { projects: [
|
||||||
|
{ testDir: './tests' },
|
||||||
|
] };
|
||||||
|
`,
|
||||||
|
'tests/a.spec.js': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('pass', ({}) => {});
|
||||||
|
`,
|
||||||
|
'tests/foo/b.spec.js': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('pass', ({}) => {});
|
||||||
|
`
|
||||||
|
});
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user