From bf35da3656c7b44f69f2531a8c103774e508dd86 Mon Sep 17 00:00:00 2001 From: Joel Einbinder Date: Mon, 13 Sep 2021 12:09:38 -0400 Subject: [PATCH] fix(test-runner): accept unix separators even on windows (#8881) . --- package-lock.json | 4 +++ src/test/runner.ts | 12 ++++----- src/test/util.ts | 32 +++++++++++++++++++---- tests/playwright-test/test-ignore.spec.ts | 25 ++++++++++++++++++ 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 91e8ee875e..f106b0f9fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8894,6 +8894,7 @@ }, "node_modules/socksv5/node_modules/ipv6": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/ipv6/-/ipv6-3.1.1.tgz", "dev": true, "inBundle": true, "license": "MIT", @@ -8912,6 +8913,7 @@ }, "node_modules/socksv5/node_modules/ipv6/node_modules/sprintf": { "version": "0.1.3", + "resolved": "https://registry.npmjs.org/sprintf/-/sprintf-0.1.3.tgz", "dev": true, "inBundle": true, "engines": { @@ -17858,6 +17860,7 @@ "dependencies": { "ipv6": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/ipv6/-/ipv6-3.1.1.tgz", "bundled": true, "dev": true, "requires": { @@ -17868,6 +17871,7 @@ "dependencies": { "sprintf": { "version": "0.1.3", + "resolved": "https://registry.npmjs.org/sprintf/-/sprintf-0.1.3.tgz", "bundled": true, "dev": true } diff --git a/src/test/runner.ts b/src/test/runner.ts index 49ad02bc23..b2b907bfcb 100644 --- a/src/test/runner.ts +++ b/src/test/runner.ts @@ -21,7 +21,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { promisify } from 'util'; import { Dispatcher, TestGroup } from './dispatcher'; -import { createMatcher, FilePatternFilter, monotonicTime } from './util'; +import { createFileMatcher, createTitleMatcher, FilePatternFilter, monotonicTime } from './util'; import { TestCase, Suite } from './test'; import { Loader } from './loader'; import { Reporter } from '../../types/testReporter'; @@ -131,7 +131,7 @@ export class Runner { } async _run(list: boolean, testFileReFilters: FilePatternFilter[], projectNames?: string[]): Promise { - const testFileFilter = testFileReFilters.length ? createMatcher(testFileReFilters.map(e => e.re)) : () => true; + const testFileFilter = testFileReFilters.length ? createFileMatcher(testFileReFilters.map(e => e.re)) : () => true; const config = this._loader.fullConfig(); let projectsToFind: Set | undefined; @@ -169,8 +169,8 @@ export class Runner { if (!fs.statSync(testDir).isDirectory()) throw new Error(`${testDir} is not a directory`); const allFiles = await collectFiles(project.config.testDir); - const testMatch = createMatcher(project.config.testMatch); - const testIgnore = createMatcher(project.config.testIgnore); + const testMatch = createFileMatcher(project.config.testMatch); + const testIgnore = createFileMatcher(project.config.testIgnore); const testFileExtension = (file: string) => ['.js', '.ts', '.mjs'].includes(path.extname(file)); const testFiles = allFiles.filter(file => !testIgnore(file) && testMatch(file) && testFileFilter(file) && testFileExtension(file)); files.set(project, testFiles); @@ -210,8 +210,8 @@ export class Runner { fileSuites.set(fileSuite._requireFile, fileSuite); const outputDirs = new Set(); - const grepMatcher = createMatcher(config.grep); - const grepInvertMatcher = config.grepInvert ? createMatcher(config.grepInvert) : null; + const grepMatcher = createTitleMatcher(config.grep); + const grepInvertMatcher = config.grepInvert ? createTitleMatcher(config.grepInvert) : null; const rootSuite = new Suite(''); for (const project of projects) { const projectSuite = new Suite(project.config.name); diff --git a/src/test/util.ts b/src/test/util.ts index 98ec3acbb1..13be2b2943 100644 --- a/src/test/util.ts +++ b/src/test/util.ts @@ -17,6 +17,7 @@ import type { TestInfoImpl } from './types'; import util from 'util'; import path from 'path'; +import url from 'url'; import type { TestError, Location } from './types'; import { default as minimatch } from 'minimatch'; import { errors } from '../..'; @@ -91,7 +92,7 @@ export type FilePatternFilter = { line: number | null; }; -export function createMatcher(patterns: string | RegExp | (string | RegExp)[]): Matcher { +export function createFileMatcher(patterns: string | RegExp | (string | RegExp)[]): Matcher { const reList: RegExp[] = []; const filePatterns: string[] = []; for (const pattern of Array.isArray(patterns) ? patterns : [patterns]) { @@ -104,17 +105,38 @@ export function createMatcher(patterns: string | RegExp | (string | RegExp)[]): filePatterns.push(pattern); } } + return (filePath: string) => { + for (const re of reList) { + re.lastIndex = 0; + if (re.test(filePath)) + return true; + } + // Windows might still recieve unix style paths from Cygwin or Git Bash. + // Check against the file url as well. + if (path.sep === '\\') { + const fileURL = url.pathToFileURL(filePath).href; + for (const re of reList) { + re.lastIndex = 0; + if (re.test(fileURL)) + return true; + } + } + for (const pattern of filePatterns) { + if (minimatch(filePath, pattern, { nocase: true, dot: true })) + return true; + } + return false; + }; +} +export function createTitleMatcher(patterns: RegExp | RegExp[]): Matcher { + const reList = Array.isArray(patterns) ? patterns : [patterns]; return (value: string) => { for (const re of reList) { re.lastIndex = 0; if (re.test(value)) return true; } - for (const pattern of filePatterns) { - if (minimatch(value, pattern, { nocase: true, dot: true })) - return true; - } return false; }; } diff --git a/tests/playwright-test/test-ignore.spec.ts b/tests/playwright-test/test-ignore.spec.ts index e2ca689303..b79d10ec14 100644 --- a/tests/playwright-test/test-ignore.spec.ts +++ b/tests/playwright-test/test-ignore.spec.ts @@ -418,3 +418,28 @@ test('should match in dot-directories', async ({ runInlineTest }) => { expect(result.report.suites.map(s => s.file).sort()).toEqual(['.dir/a.test.ts', '.dir/b.test.js']); expect(result.exitCode).toBe(0); }); + +test('should always work with unix separators', async ({ runInlineTest }) => { + // Cygwin or Git Bash might send us a path with unix separators. + const result = await runInlineTest({ + 'playwright.config.ts': ` + import * as path from 'path'; + module.exports = { testDir: path.join(__dirname, 'dir') }; + `, + 'dir/a.test.ts': ` + const { test } = pwt; + test('pass', ({}) => {}); + `, + 'dir/b.test.ts': ` + const { test } = pwt; + test('pass', ({}) => {}); + `, + 'a.test.ts': ` + const { test } = pwt; + test('pass', ({}) => {}); + ` + }, { args: [`dir/a`] }); + expect(result.passed).toBe(1); + expect(result.report.suites.map(s => s.file).sort()).toEqual(['a.test.ts']); + expect(result.exitCode).toBe(0); +}); \ No newline at end of file