From e78b3d0dfb29a9580064a8690d53ec789be3e044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=BCller?= Date: Wed, 2 Feb 2022 14:06:13 +0100 Subject: [PATCH 1/9] feat(cli): add `--failOnOnly` option --- packages/vitest/src/node/cli.ts | 1 + packages/vitest/src/types/config.ts | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/packages/vitest/src/node/cli.ts b/packages/vitest/src/node/cli.ts index 5864b23f3ab6..a81bc12e6765 100644 --- a/packages/vitest/src/node/cli.ts +++ b/packages/vitest/src/node/cli.ts @@ -30,6 +30,7 @@ cli .option('--dom', 'mock browser api with happy-dom') .option('--environment ', 'runner environment', { default: 'node' }) .option('--passWithNoTests', 'pass when no tests found') + .option('--failOnOnly', 'fail when a test or suite is marked as only') .help() cli diff --git a/packages/vitest/src/types/config.ts b/packages/vitest/src/types/config.ts index cbe79f253c1c..6adb7959f56c 100644 --- a/packages/vitest/src/types/config.ts +++ b/packages/vitest/src/types/config.ts @@ -305,6 +305,11 @@ export interface UserConfig extends InlineConfig { */ passWithNoTests?: boolean + /** + * Fail when a test or suite is marked as only + */ + failOnOnly?: boolean + /** * Run tests that cover a list of source files */ From 463b0edcc973a0d4bf7a5e19670f13fd7436b109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=BCller?= Date: Wed, 2 Feb 2022 14:06:23 +0100 Subject: [PATCH 2/9] docs: add `--failOnOnly` option --- docs/guide/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/guide/index.md b/docs/guide/index.md index 8b979021f9a8..a6c5ccec67c5 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -116,6 +116,7 @@ You can specify additional CLI options like `--port` or `--https`. For a full li | `--dom` | Mock browser api with happy-dom | | `--environment ` | Runner environment (default: node) | | `--passWithNoTests` | Pass when no tests found | +| `--failOnOnly` | Fail when a test or suite is marked as `only` | | `-h, --help` | Display available CLI options | ## Examples From fda180d76cf2f8ac6b35264d68c849daaf323186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=BCller?= Date: Wed, 2 Feb 2022 15:11:57 +0100 Subject: [PATCH 3/9] feat: fail on `only` if enabled --- packages/vitest/src/runtime/collect.ts | 34 +++++++++++++++++--------- packages/vitest/src/runtime/run.ts | 2 +- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/packages/vitest/src/runtime/collect.ts b/packages/vitest/src/runtime/collect.ts index 894ed7ad06fc..488fbf95b7b1 100644 --- a/packages/vitest/src/runtime/collect.ts +++ b/packages/vitest/src/runtime/collect.ts @@ -1,6 +1,6 @@ import { createHash } from 'crypto' import { relative } from 'pathe' -import type { File, ResolvedConfig, Suite } from '../types' +import type { File, ResolvedConfig, Suite, TaskBase } from '../types' import { clearContext, defaultSuite } from './suite' import { getHooks, setHooks } from './map' import { processError } from './error' @@ -64,7 +64,8 @@ export async function collectTests(paths: string[], config: ResolvedConfig) { calculateHash(file) - interpretTaskModes(file, config.testNamePattern) + const hasOnlyTasks = someTasksAreOnly(file) + interpretTaskModes(file, config.testNamePattern, hasOnlyTasks, false, config.failOnOnly) files.push(file) } @@ -72,26 +73,37 @@ export async function collectTests(paths: string[], config: ResolvedConfig) { return files } +function checkFailOnOnly(task: TaskBase, failOnOnly?: boolean) { + if (failOnOnly) { + task.result = { + state: 'fail', + error: processError(new Error('failOnOnly is enabled')), + } + } +} + /** * If any tasks been marked as `only`, mark all other tasks as `skip`. */ -function interpretTaskModes(suite: Suite, namePattern?: string | RegExp, onlyMode?: boolean, isIncluded?: boolean) { - if (onlyMode === undefined) { - onlyMode = someTasksAreOnly(suite) - isIncluded ||= suite.mode === 'only' - } +function interpretTaskModes(suite: Suite, namePattern?: string | RegExp, onlyMode?: boolean, parentIsOnly?: boolean, failOnOnly?: boolean) { + const suiteIsOnly = parentIsOnly || suite.mode === 'only' suite.tasks.forEach((t) => { // Check if either the parent suite or the task itself are marked as included - const includeTask = isIncluded || t.mode === 'only' + const includeTask = suiteIsOnly || t.mode === 'only' if (onlyMode) { if (t.type === 'suite' && (includeTask || someTasksAreOnly(t))) { // Don't skip this suite - if (t.mode === 'only') + if (t.mode === 'only') { + checkFailOnOnly(t, failOnOnly) t.mode = 'run' + } } else if (t.mode === 'run' && !includeTask) { t.mode = 'skip' } - else if (t.mode === 'only') { t.mode = 'run' } + else if (t.mode === 'only') { + checkFailOnOnly(t, failOnOnly) + t.mode = 'run' + } } if (t.type === 'test') { if (namePattern && !t.name.match(namePattern)) @@ -101,7 +113,7 @@ function interpretTaskModes(suite: Suite, namePattern?: string | RegExp, onlyMod if (t.mode === 'skip') skipAllTasks(t) else - interpretTaskModes(t, namePattern, onlyMode, includeTask) + interpretTaskModes(t, namePattern, onlyMode, includeTask, failOnOnly) } }) diff --git a/packages/vitest/src/runtime/run.ts b/packages/vitest/src/runtime/run.ts index c4df6b379e2e..d24e96035cc9 100644 --- a/packages/vitest/src/runtime/run.ts +++ b/packages/vitest/src/runtime/run.ts @@ -44,7 +44,7 @@ async function sendTasksUpdate() { } export async function runTest(test: Test) { - if (test.mode !== 'run') + if (test.mode !== 'run' || test.result) return const start = performance.now() From 5a34c4741d72c501cb8148c47b79872a93b3833e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=BCller?= Date: Wed, 2 Feb 2022 16:59:03 +0100 Subject: [PATCH 4/9] feat: replace `failOnOnly` with `allowOnly` --- docs/guide/index.md | 2 +- packages/vitest/src/node/cli.ts | 2 +- packages/vitest/src/runtime/collect.ts | 27 +++++++++++++------------- packages/vitest/src/types/config.ts | 4 ++-- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/guide/index.md b/docs/guide/index.md index a6c5ccec67c5..5f362e513ce1 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -116,7 +116,7 @@ You can specify additional CLI options like `--port` or `--https`. For a full li | `--dom` | Mock browser api with happy-dom | | `--environment ` | Runner environment (default: node) | | `--passWithNoTests` | Pass when no tests found | -| `--failOnOnly` | Fail when a test or suite is marked as `only` | +| `--allowOnly` | Allow tests and suites that are marked as `only` (default: false in CI, true otherwise) | | `-h, --help` | Display available CLI options | ## Examples diff --git a/packages/vitest/src/node/cli.ts b/packages/vitest/src/node/cli.ts index a81bc12e6765..c2490619d179 100644 --- a/packages/vitest/src/node/cli.ts +++ b/packages/vitest/src/node/cli.ts @@ -30,7 +30,7 @@ cli .option('--dom', 'mock browser api with happy-dom') .option('--environment ', 'runner environment', { default: 'node' }) .option('--passWithNoTests', 'pass when no tests found') - .option('--failOnOnly', 'fail when a test or suite is marked as only') + .option('--allowOnly', 'Allow tests and suites that are marked as only', { default: !process.env.CI }) .help() cli diff --git a/packages/vitest/src/runtime/collect.ts b/packages/vitest/src/runtime/collect.ts index 488fbf95b7b1..1a06963e16b5 100644 --- a/packages/vitest/src/runtime/collect.ts +++ b/packages/vitest/src/runtime/collect.ts @@ -65,7 +65,7 @@ export async function collectTests(paths: string[], config: ResolvedConfig) { calculateHash(file) const hasOnlyTasks = someTasksAreOnly(file) - interpretTaskModes(file, config.testNamePattern, hasOnlyTasks, false, config.failOnOnly) + interpretTaskModes(file, config.testNamePattern, hasOnlyTasks, false, config.allowOnly) files.push(file) } @@ -73,19 +73,10 @@ export async function collectTests(paths: string[], config: ResolvedConfig) { return files } -function checkFailOnOnly(task: TaskBase, failOnOnly?: boolean) { - if (failOnOnly) { - task.result = { - state: 'fail', - error: processError(new Error('failOnOnly is enabled')), - } - } -} - /** * If any tasks been marked as `only`, mark all other tasks as `skip`. */ -function interpretTaskModes(suite: Suite, namePattern?: string | RegExp, onlyMode?: boolean, parentIsOnly?: boolean, failOnOnly?: boolean) { +function interpretTaskModes(suite: Suite, namePattern?: string | RegExp, onlyMode?: boolean, parentIsOnly?: boolean, allowOnly?: boolean) { const suiteIsOnly = parentIsOnly || suite.mode === 'only' suite.tasks.forEach((t) => { @@ -95,13 +86,13 @@ function interpretTaskModes(suite: Suite, namePattern?: string | RegExp, onlyMod if (t.type === 'suite' && (includeTask || someTasksAreOnly(t))) { // Don't skip this suite if (t.mode === 'only') { - checkFailOnOnly(t, failOnOnly) + checkAllowOnly(t, allowOnly) t.mode = 'run' } } else if (t.mode === 'run' && !includeTask) { t.mode = 'skip' } else if (t.mode === 'only') { - checkFailOnOnly(t, failOnOnly) + checkAllowOnly(t, allowOnly) t.mode = 'run' } } @@ -113,7 +104,7 @@ function interpretTaskModes(suite: Suite, namePattern?: string | RegExp, onlyMod if (t.mode === 'skip') skipAllTasks(t) else - interpretTaskModes(t, namePattern, onlyMode, includeTask, failOnOnly) + interpretTaskModes(t, namePattern, onlyMode, includeTask, allowOnly) } }) @@ -138,6 +129,14 @@ function skipAllTasks(suite: Suite) { }) } +function checkAllowOnly(task: TaskBase, allowOnly?: boolean) { + if (allowOnly) return + task.result = { + state: 'fail', + error: processError(new Error('only is not allowed')), + } +} + function calculateHash(parent: Suite) { parent.tasks.forEach((t, idx) => { t.id = `${parent.id}_${idx}` diff --git a/packages/vitest/src/types/config.ts b/packages/vitest/src/types/config.ts index 6adb7959f56c..43b67f57b84f 100644 --- a/packages/vitest/src/types/config.ts +++ b/packages/vitest/src/types/config.ts @@ -306,9 +306,9 @@ export interface UserConfig extends InlineConfig { passWithNoTests?: boolean /** - * Fail when a test or suite is marked as only + * Allow tests and suites that are marked as only */ - failOnOnly?: boolean + allowOnly?: boolean /** * Run tests that cover a list of source files From 5a1338765604b8f877db175ba1749856a3bc79c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=BCller?= Date: Wed, 2 Feb 2022 17:06:29 +0100 Subject: [PATCH 5/9] chore: add `--allowOnly` to test scripts --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7876d4729b6e..ae57b964fdd4 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "release": "bumpp package.json packages/*/package.json --commit --push --tag && pnpm -r publish --access public", "test": "vitest --api -r test/core", "test:run": "vitest run -r test/core", - "test:all": "cross-env CI=true pnpm -r --stream --filter !@vitest/monorepo run test --", - "test:ci": "cross-env CI=true pnpm -r --stream --filter !@vitest/monorepo --filter !test-fails run test --", + "test:all": "cross-env CI=true pnpm -r --stream --filter !@vitest/monorepo run test -- --allowOnly", + "test:ci": "cross-env CI=true pnpm -r --stream --filter !@vitest/monorepo --filter !test-fails run test -- --allowOnly", "typecheck": "tsc --noEmit", "ui:build": "vite build packages/ui", "ui:dev": "vite packages/ui" From b23be4ddd013b71828e90851fa6c6d9ddc98a692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=BCller?= Date: Wed, 2 Feb 2022 17:31:30 +0100 Subject: [PATCH 6/9] fix: mark tasks of pre-failed suite as skipped --- packages/vitest/src/runtime/run.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/vitest/src/runtime/run.ts b/packages/vitest/src/runtime/run.ts index d24e96035cc9..fd90c92f427d 100644 --- a/packages/vitest/src/runtime/run.ts +++ b/packages/vitest/src/runtime/run.ts @@ -114,9 +114,20 @@ export async function runTest(test: Test) { updateTask(test) } +function markTasksAsSkipped(suite: Suite) { + suite.tasks.forEach((t) => { + t.mode = 'skip' + t.result = { ...t.result, state: 'skip' } + updateTask(t) + if (t.type === 'suite') markTasksAsSkipped(t) + }) +} + export async function runSuite(suite: Suite) { - if (suite.result?.state === 'fail') + if (suite.result?.state === 'fail') { + markTasksAsSkipped(suite) return + } const start = performance.now() From a564538222b2ab76909f5b24fa41ba217bee4354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=BCller?= Date: Wed, 2 Feb 2022 17:32:48 +0100 Subject: [PATCH 7/9] fix(ui): show correct icon for skipped tasks --- packages/ui/client/components/StatusIcon.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/client/components/StatusIcon.vue b/packages/ui/client/components/StatusIcon.vue index 9dcd6b82f3be..121c3d17d7d7 100644 --- a/packages/ui/client/components/StatusIcon.vue +++ b/packages/ui/client/components/StatusIcon.vue @@ -33,7 +33,7 @@ defineProps<{ task: Task }>() i-carbon:document-blank />
Date: Wed, 2 Feb 2022 17:46:41 +0100 Subject: [PATCH 8/9] fix: update pre-failed tasks during run --- packages/vitest/src/runtime/run.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/vitest/src/runtime/run.ts b/packages/vitest/src/runtime/run.ts index fd90c92f427d..d92145981a14 100644 --- a/packages/vitest/src/runtime/run.ts +++ b/packages/vitest/src/runtime/run.ts @@ -44,9 +44,14 @@ async function sendTasksUpdate() { } export async function runTest(test: Test) { - if (test.mode !== 'run' || test.result) + if (test.mode !== 'run') return + if (test.result?.state === 'fail') { + updateTask(test) + return + } + const start = performance.now() test.result = { @@ -126,6 +131,7 @@ function markTasksAsSkipped(suite: Suite) { export async function runSuite(suite: Suite) { if (suite.result?.state === 'fail') { markTasksAsSkipped(suite) + updateTask(suite) return } From 674c035679d7241009155771f0c22d2fea3a5901 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Thu, 3 Feb 2022 10:18:40 +0800 Subject: [PATCH 9/9] Update packages/vitest/src/runtime/collect.ts --- packages/vitest/src/runtime/collect.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vitest/src/runtime/collect.ts b/packages/vitest/src/runtime/collect.ts index 1a06963e16b5..550d9fb9aa83 100644 --- a/packages/vitest/src/runtime/collect.ts +++ b/packages/vitest/src/runtime/collect.ts @@ -133,7 +133,7 @@ function checkAllowOnly(task: TaskBase, allowOnly?: boolean) { if (allowOnly) return task.result = { state: 'fail', - error: processError(new Error('only is not allowed')), + error: processError(new Error('[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly arguement to bypass this error')), } }