diff --git a/.changeset/fair-melons-taste.md b/.changeset/fair-melons-taste.md new file mode 100644 index 000000000..8fe2e92e8 --- /dev/null +++ b/.changeset/fair-melons-taste.md @@ -0,0 +1,6 @@ +--- +'@web/test-runner-core': minor +'@web/test-runner': minor +--- + +Added a command line flag to allow the command to pass when no tests are present. diff --git a/.gitignore b/.gitignore index 1d8925996..24843f93a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,9 @@ coverage/ npm-debug.log yarn-error.log +## environment +.env* + ## temp folders /.tmp/ diff --git a/docs/docs/test-runner/cli-and-configuration.md b/docs/docs/test-runner/cli-and-configuration.md index b02c6ac17..25909115b 100644 --- a/docs/docs/test-runner/cli-and-configuration.md +++ b/docs/docs/test-runner/cli-and-configuration.md @@ -114,6 +114,8 @@ interface TestRunnerGroupConfig { name: string; // globs of files to test in this group, if unset it will be inherited from the main config files?: string | string[]; + // allow tests to pass even if there are no test files found + allowPassWithoutTests?: boolean; // browsers to test in this group, if unset it will be inherited from the main config browsers?: BrowserLauncher[]; // HTML used for running HTML tests for this group @@ -127,6 +129,8 @@ interface TestRunnerGroupConfig { interface TestRunnerConfig { // globs of files to test files: string | string[]; + // allow tests to pass even if there are no test files found + allowPassWithoutTests?: boolean; // test group configs, can be an array of configs or a string or string array of glob patterns // which specify where to find the configs groups?: string | string[] | TestRunnerGroupConfig[]; diff --git a/packages/test-runner-core/src/config/TestRunnerCoreConfig.ts b/packages/test-runner-core/src/config/TestRunnerCoreConfig.ts index 6a17dacf8..ca5512bb0 100644 --- a/packages/test-runner-core/src/config/TestRunnerCoreConfig.ts +++ b/packages/test-runner-core/src/config/TestRunnerCoreConfig.ts @@ -27,6 +27,7 @@ export interface CoverageConfig { export interface TestRunnerCoreConfig { rootDir: string; files?: string | string[]; + allowPassWithoutTests?: boolean; concurrentBrowsers: number; concurrency: number; diff --git a/packages/test-runner-core/src/config/TestRunnerGroupConfig.ts b/packages/test-runner-core/src/config/TestRunnerGroupConfig.ts index f768e3b80..9e6dcdedc 100644 --- a/packages/test-runner-core/src/config/TestRunnerGroupConfig.ts +++ b/packages/test-runner-core/src/config/TestRunnerGroupConfig.ts @@ -5,6 +5,7 @@ export interface TestRunnerGroupConfig { name: string; configFilePath?: string; files?: string | string[]; + allowPassWithoutTests?: boolean; browsers?: BrowserLauncher[]; testRunnerHtml?: ( testRunnerImport: string, diff --git a/packages/test-runner-core/src/runner/TestRunner.ts b/packages/test-runner-core/src/runner/TestRunner.ts index f2b486244..6c6909e67 100644 --- a/packages/test-runner-core/src/runner/TestRunner.ts +++ b/packages/test-runner-core/src/runner/TestRunner.ts @@ -128,6 +128,7 @@ export class TestRunner extends EventEmitter { this.pendingSessions.clear(); if (sessionsToRun.length === 0) { + this.stop(); return; } diff --git a/packages/test-runner-core/src/runner/createSessionGroups.ts b/packages/test-runner-core/src/runner/createSessionGroups.ts index 40d8e134f..043f19f48 100644 --- a/packages/test-runner-core/src/runner/createSessionGroups.ts +++ b/packages/test-runner-core/src/runner/createSessionGroups.ts @@ -26,6 +26,7 @@ export function createTestSessions( groups.push({ name: 'default', files: config.files, + allowPassWithoutTests: config.allowPassWithoutTests, browsers: config.browsers, }); } @@ -52,6 +53,10 @@ export function createTestSessions( mergedGroupConfig.files = groupConfig.files; } + if (groupConfig.allowPassWithoutTests != null) { + mergedGroupConfig.allowPassWithoutTests = groupConfig.allowPassWithoutTests; + } + if (groupConfig.testRunnerHtml != null) { mergedGroupConfig.testRunnerHtml = groupConfig.testRunnerHtml; } @@ -71,7 +76,7 @@ export function createTestSessions( // C:/foo/bar -> C:\foo\bar .map(testFile => path.normalize(testFile)); - if (testFilesForGroup.length === 0) { + if (testFilesForGroup.length === 0 && !group.allowPassWithoutTests) { throw new Error(`Could not find any test files with pattern(s): ${group.files}`); } @@ -112,7 +117,7 @@ export function createTestSessions( } } - if (testFiles.size === 0 || testSessions.length === 0) { + if ((testFiles.size === 0 || testSessions.length === 0) && !config.allowPassWithoutTests) { throw new Error('Did not find any tests to run.'); } diff --git a/packages/test-runner/src/config/parseConfig.ts b/packages/test-runner/src/config/parseConfig.ts index f8f058c5b..ac4fdd3b5 100644 --- a/packages/test-runner/src/config/parseConfig.ts +++ b/packages/test-runner/src/config/parseConfig.ts @@ -188,8 +188,10 @@ export async function parseConfig( // we can improve this by relying only on groups inside the test runner itself if (groupConfig.files == null) { groupConfig.files = finalConfig.files; + groupConfig.allowPassWithoutTests = finalConfig.allowPassWithoutTests; } finalConfig.files = undefined; + finalConfig.allowPassWithoutTests = undefined; groupConfigs = [groupConfig]; } diff --git a/packages/test-runner/src/config/readCliArgs.ts b/packages/test-runner/src/config/readCliArgs.ts index 3a37a223f..dd847b834 100644 --- a/packages/test-runner/src/config/readCliArgs.ts +++ b/packages/test-runner/src/config/readCliArgs.ts @@ -9,6 +9,7 @@ export interface TestRunnerCliArgs Pick< TestRunnerConfig, | 'files' + | 'allowPassWithoutTests' | 'rootDir' | 'watch' | 'coverage' @@ -41,6 +42,11 @@ const options: OptionDefinition[] = [ defaultOption: true, description: 'Test files to run', }, + { + name: 'allowPassWithoutTests', + type: Boolean, + description: 'Allow pass without any tests', + }, { name: 'root-dir', type: String,