From 699994e86d8ce30733fe8947eb537f1a7981cab3 Mon Sep 17 00:00:00 2001 From: userquin Date: Fri, 4 Oct 2024 17:34:34 +0200 Subject: [PATCH 1/8] feat(vitest,ui): allow run individual tests/suites from the UI --- .../components/explorer/ExplorerItem.vue | 17 ++++++++-- .../ui/client/composables/client/index.ts | 31 ++++++++++++++++--- packages/vitest/src/api/setup.ts | 3 ++ packages/vitest/src/api/types.ts | 1 + packages/vitest/src/node/core.ts | 24 ++++++++++++++ 5 files changed, 69 insertions(+), 7 deletions(-) diff --git a/packages/ui/client/components/explorer/ExplorerItem.vue b/packages/ui/client/components/explorer/ExplorerItem.vue index 8cb5b95c189e..cb940ca6cc17 100644 --- a/packages/ui/client/components/explorer/ExplorerItem.vue +++ b/packages/ui/client/components/explorer/ExplorerItem.vue @@ -3,7 +3,7 @@ import type { Task, TaskState } from '@vitest/runner' import { nextTick } from 'vue' import { hasFailedSnapshot } from '@vitest/ws-client' import { Tooltip as VueTooltip } from 'floating-vue' -import { client, isReport, runFiles } from '~/composables/client' +import { client, isReport, runFiles, runTestOrSuite } from '~/composables/client' import { coverageEnabled } from '~/composables/navigation' import type { TaskTreeNodeType } from '~/composables/explorer/types' import { explorerTree } from '~/composables/explorer' @@ -24,6 +24,7 @@ const { disableTaskLocation, onItemClick, projectNameColor, + state, } = defineProps<{ taskId: string name: string @@ -68,12 +69,22 @@ function toggleOpen() { } async function onRun(task: Task) { + if (!state || state === 'skip' || state === 'todo') { + return + } + onItemClick?.(task) if (coverageEnabled.value) { disableCoverage.value = true await nextTick() } - await runFiles([task.file]) + + if (type === 'file') { + await runFiles([task.file]) + } + else { + await runTestOrSuite(task) + } } function updateSnapshot(task: Task) { @@ -224,7 +235,7 @@ const projectNameTextColor = computed(() => { title="Run current test" icon="i-carbon:play-filled-alt" text-green5 - :disabled="type !== 'file'" + :disabled="!state || state === 'skip' || state === 'todo'" @click.prevent.stop="onRun(task)" /> diff --git a/packages/ui/client/composables/client/index.ts b/packages/ui/client/composables/client/index.ts index ebb629e6ef33..e81d75517888 100644 --- a/packages/ui/client/composables/client/index.ts +++ b/packages/ui/client/composables/client/index.ts @@ -1,19 +1,20 @@ import { createClient, getTasks } from '@vitest/ws-client' import type { WebSocketStatus } from '@vueuse/core' -import type { File, SerializedConfig, TaskResultPack } from 'vitest' +import type { File, SerializedConfig, Task, TaskResultPack } from 'vitest' import { reactive as reactiveVue } from 'vue' import { createFileTask } from '@vitest/runner/utils' import type { BrowserRunnerState } from '../../../types' -import { ENTRY_URL, isReport } from '../../constants' import { parseError } from '../error' import { activeFileId } from '../params' -import { ui } from '../../composables/api' import { createStaticClient } from './static' import { testRunState, unhandledErrors } from './state' +import { ui } from '~/composables/api' +import { ENTRY_URL, isReport } from '~/constants' import { explorerTree } from '~/composables/explorer' import { isFileNode } from '~/composables/explorer/utils' +import { isSuite as isTaskSuite } from '~/utils/task' -export { ENTRY_URL, PORT, HOST, isReport } from '../../constants' +export { ENTRY_URL, PORT, HOST, isReport } from '~/constants' export const client = (function createVitestClient() { if (isReport) { @@ -68,6 +69,19 @@ export function runAll() { return runFiles(client.state.getFiles()/* , true */) } +function clearTaskResult(patterns: string[], task: Task) { + patterns.push(task.name) + delete task.result + const node = explorerTree.nodes.get(task.id) + if (node) { + node.state = undefined + node.duration = undefined + if (isTaskSuite(task)) { + getTasks(task.tasks).forEach(t => clearTaskResult(patterns, t)) + } + } +} + function clearResults(useFiles: File[]) { const map = explorerTree.nodes useFiles.forEach((f) => { @@ -101,6 +115,15 @@ export function runFiles(useFiles: File[]) { return client.rpc.rerun(useFiles.map(i => i.filepath)) } +export function runTestOrSuite(task: Task) { + const patterns: string[] = [] + clearTaskResult(patterns, task) + + explorerTree.startRun() + + return client.rpc.rerunTestOrSuite(task.file.filepath, patterns, task.file.projectName) +} + export function runCurrent() { if (current.value) { return runFiles([current.value]) diff --git a/packages/vitest/src/api/setup.ts b/packages/vitest/src/api/setup.ts index 5cf47139a272..795413a15117 100644 --- a/packages/vitest/src/api/setup.ts +++ b/packages/vitest/src/api/setup.ts @@ -73,6 +73,9 @@ export function setup(ctx: Vitest, _server?: ViteDevServer) { async rerun(files) { await ctx.rerunFiles(files) }, + async rerunTestOrSuite(filename, names, projectName) { + await ctx.rerunTestOrSuite(filename, names, projectName) + }, getConfig() { return ctx.getCoreWorkspaceProject().getSerializableConfig() }, diff --git a/packages/vitest/src/api/types.ts b/packages/vitest/src/api/types.ts index aee2462e9ecc..476d9acd9b03 100644 --- a/packages/vitest/src/api/types.ts +++ b/packages/vitest/src/api/types.ts @@ -45,6 +45,7 @@ export interface WebSocketHandlers { readTestFile: (id: string) => Promise saveTestFile: (id: string, content: string) => Promise rerun: (files: string[]) => Promise + rerunTestOrSuite: (filename: string, names: string[], projectName?: string) => Promise updateSnapshot: (file?: File) => Promise getUnhandledErrors: () => unknown[] } diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 93d0c885e5ce..42ba6c916665 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -688,6 +688,30 @@ export class Vitest { await this.report('onWatcherStart', this.state.getFiles(files)) } + async rerunTestOrSuite(filename: string, names: string[], projectName?: string, trigger?: string) { + console.log('rerunTestOrSuite', { filename, names, projectName }) + const useProjects = projectName ? this.projects.filter(p => p.getName() === projectName) : this.projects + const files: WorkspaceSpec[] = [] + await Promise.all(useProjects.map(async (project) => { + const { testFiles, typecheckTestFiles } = await project.globTestFiles(names) + testFiles.forEach((file) => { + const pool = getFilePoolName(project, file) + const spec = project.createSpec(file, pool) + this.ensureSpecCached(spec) + files.push(spec) + }) + typecheckTestFiles.forEach((file) => { + const spec = project.createSpec(file, 'typescript') + this.ensureSpecCached(spec) + files.push(spec) + }) + })) + + await this.report('onWatcherRerun', [filename], trigger) + await this.runFiles(files, !trigger) + await this.report('onWatcherStart', this.state.getFiles([filename])) + } + async changeProjectName(pattern: string) { if (pattern === '') { delete this.configOverride.project From 4d0f6dab17fbc352dba18cfb04d04ed49a11da51 Mon Sep 17 00:00:00 2001 From: userquin Date: Sat, 5 Oct 2024 14:18:33 +0200 Subject: [PATCH 2/8] chore: update logic --- .../components/explorer/ExplorerItem.vue | 4 +-- .../ui/client/composables/client/index.ts | 34 +++++++++++++++--- packages/vitest/src/api/setup.ts | 4 +-- packages/vitest/src/api/types.ts | 2 +- packages/vitest/src/node/core.ts | 36 ++++++++----------- 5 files changed, 48 insertions(+), 32 deletions(-) diff --git a/packages/ui/client/components/explorer/ExplorerItem.vue b/packages/ui/client/components/explorer/ExplorerItem.vue index cb940ca6cc17..3ebfeb19b19e 100644 --- a/packages/ui/client/components/explorer/ExplorerItem.vue +++ b/packages/ui/client/components/explorer/ExplorerItem.vue @@ -69,7 +69,7 @@ function toggleOpen() { } async function onRun(task: Task) { - if (!state || state === 'skip' || state === 'todo') { + if (!state || state === 'todo') { return } @@ -235,7 +235,7 @@ const projectNameTextColor = computed(() => { title="Run current test" icon="i-carbon:play-filled-alt" text-green5 - :disabled="!state || state === 'skip' || state === 'todo'" + :disabled="!state || state === 'todo'" @click.prevent.stop="onRun(task)" /> diff --git a/packages/ui/client/composables/client/index.ts b/packages/ui/client/composables/client/index.ts index e81d75517888..bb30d9911fde 100644 --- a/packages/ui/client/composables/client/index.ts +++ b/packages/ui/client/composables/client/index.ts @@ -70,14 +70,16 @@ export function runAll() { } function clearTaskResult(patterns: string[], task: Task) { - patterns.push(task.name) + patterns.push(task.id) delete task.result const node = explorerTree.nodes.get(task.id) if (node) { node.state = undefined node.duration = undefined if (isTaskSuite(task)) { - getTasks(task.tasks).forEach(t => clearTaskResult(patterns, t)) + for (const t of task.tasks) { + clearTaskResult(patterns, t) + } } } } @@ -116,12 +118,34 @@ export function runFiles(useFiles: File[]) { } export function runTestOrSuite(task: Task) { - const patterns: string[] = [] - clearTaskResult(patterns, task) + const ids: string[] = [] + clearTaskResult(ids, task) + + // we also need to send the parent ids: the state doesn't have the parent ids + let parent = explorerTree.nodes.get(task.id)?.parentId + while (parent) { + const node = explorerTree.nodes.get(parent) + if (node) { + const parentTask = client.state.idMap.get(node.id) + if (parentTask) { + ids.unshift(parentTask.id) + delete parentTask.result + node.state = undefined + node.duration = undefined + } + else { + break + } + parent = explorerTree.nodes.get(node.id)?.parentId + } + else { + break + } + } explorerTree.startRun() - return client.rpc.rerunTestOrSuite(task.file.filepath, patterns, task.file.projectName) + return client.rpc.rerunTestOrSuite(task.file.filepath, ids) } export function runCurrent() { diff --git a/packages/vitest/src/api/setup.ts b/packages/vitest/src/api/setup.ts index 795413a15117..dc97086693fb 100644 --- a/packages/vitest/src/api/setup.ts +++ b/packages/vitest/src/api/setup.ts @@ -73,8 +73,8 @@ export function setup(ctx: Vitest, _server?: ViteDevServer) { async rerun(files) { await ctx.rerunFiles(files) }, - async rerunTestOrSuite(filename, names, projectName) { - await ctx.rerunTestOrSuite(filename, names, projectName) + async rerunTestOrSuite(filename, ids) { + await ctx.rerunTestOrSuite(filename, ids) }, getConfig() { return ctx.getCoreWorkspaceProject().getSerializableConfig() diff --git a/packages/vitest/src/api/types.ts b/packages/vitest/src/api/types.ts index 476d9acd9b03..b1eef1a09780 100644 --- a/packages/vitest/src/api/types.ts +++ b/packages/vitest/src/api/types.ts @@ -45,7 +45,7 @@ export interface WebSocketHandlers { readTestFile: (id: string) => Promise saveTestFile: (id: string, content: string) => Promise rerun: (files: string[]) => Promise - rerunTestOrSuite: (filename: string, names: string[], projectName?: string) => Promise + rerunTestOrSuite: (filename: string, ids: string[]) => Promise updateSnapshot: (file?: File) => Promise getUnhandledErrors: () => unknown[] } diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 42ba6c916665..a46e78adc718 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -677,6 +677,7 @@ export class Vitest { } async rerunFiles(files: string[] = this.state.getFilepaths(), trigger?: string) { + this.configOverride.testNamePattern = undefined if (this.filenamePattern) { const filteredFiles = await this.globTestFiles([this.filenamePattern]) files = files.filter(file => filteredFiles.some(f => f[1] === file)) @@ -688,28 +689,19 @@ export class Vitest { await this.report('onWatcherStart', this.state.getFiles(files)) } - async rerunTestOrSuite(filename: string, names: string[], projectName?: string, trigger?: string) { - console.log('rerunTestOrSuite', { filename, names, projectName }) - const useProjects = projectName ? this.projects.filter(p => p.getName() === projectName) : this.projects - const files: WorkspaceSpec[] = [] - await Promise.all(useProjects.map(async (project) => { - const { testFiles, typecheckTestFiles } = await project.globTestFiles(names) - testFiles.forEach((file) => { - const pool = getFilePoolName(project, file) - const spec = project.createSpec(file, pool) - this.ensureSpecCached(spec) - files.push(spec) - }) - typecheckTestFiles.forEach((file) => { - const spec = project.createSpec(file, 'typescript') - this.ensureSpecCached(spec) - files.push(spec) - }) - })) - - await this.report('onWatcherRerun', [filename], trigger) - await this.runFiles(files, !trigger) - await this.report('onWatcherStart', this.state.getFiles([filename])) + async rerunTestOrSuite(filename: string, ids: string[]) { + const patterns: string[] = [] + for (const id of ids) { + const task = this.state.idMap.get(id) + if (task) { + patterns.push(task.name) + } + } + await this.changeNamePattern( + patterns.length ? patterns.join('|') : '', + [filename], + patterns.length ? 'rerun test or suite' : 'rerun test file', + ) } async changeProjectName(pattern: string) { From cbea8a89ee42c6d370ae918b5347ed5e126340ee Mon Sep 17 00:00:00 2001 From: userquin Date: Sat, 5 Oct 2024 17:21:07 +0200 Subject: [PATCH 3/8] chore: . --- .../components/explorer/ExplorerItem.vue | 4 +- .../ui/client/composables/client/index.ts | 34 +++------------ packages/vitest/src/api/setup.ts | 8 ++-- packages/vitest/src/api/types.ts | 4 +- packages/vitest/src/node/core.ts | 42 ++++++++++++++----- 5 files changed, 45 insertions(+), 47 deletions(-) diff --git a/packages/ui/client/components/explorer/ExplorerItem.vue b/packages/ui/client/components/explorer/ExplorerItem.vue index 3ebfeb19b19e..cb940ca6cc17 100644 --- a/packages/ui/client/components/explorer/ExplorerItem.vue +++ b/packages/ui/client/components/explorer/ExplorerItem.vue @@ -69,7 +69,7 @@ function toggleOpen() { } async function onRun(task: Task) { - if (!state || state === 'todo') { + if (!state || state === 'skip' || state === 'todo') { return } @@ -235,7 +235,7 @@ const projectNameTextColor = computed(() => { title="Run current test" icon="i-carbon:play-filled-alt" text-green5 - :disabled="!state || state === 'todo'" + :disabled="!state || state === 'skip' || state === 'todo'" @click.prevent.stop="onRun(task)" /> diff --git a/packages/ui/client/composables/client/index.ts b/packages/ui/client/composables/client/index.ts index bb30d9911fde..d92ec2d1c5e1 100644 --- a/packages/ui/client/composables/client/index.ts +++ b/packages/ui/client/composables/client/index.ts @@ -69,8 +69,7 @@ export function runAll() { return runFiles(client.state.getFiles()/* , true */) } -function clearTaskResult(patterns: string[], task: Task) { - patterns.push(task.id) +function clearTaskResult(task: Task) { delete task.result const node = explorerTree.nodes.get(task.id) if (node) { @@ -78,7 +77,7 @@ function clearTaskResult(patterns: string[], task: Task) { node.duration = undefined if (isTaskSuite(task)) { for (const t of task.tasks) { - clearTaskResult(patterns, t) + clearTaskResult(t) } } } @@ -114,38 +113,15 @@ export function runFiles(useFiles: File[]) { explorerTree.startRun() - return client.rpc.rerun(useFiles.map(i => i.filepath)) + return client.rpc.rerun(useFiles.map(i => i.filepath), true) } export function runTestOrSuite(task: Task) { - const ids: string[] = [] - clearTaskResult(ids, task) - - // we also need to send the parent ids: the state doesn't have the parent ids - let parent = explorerTree.nodes.get(task.id)?.parentId - while (parent) { - const node = explorerTree.nodes.get(parent) - if (node) { - const parentTask = client.state.idMap.get(node.id) - if (parentTask) { - ids.unshift(parentTask.id) - delete parentTask.result - node.state = undefined - node.duration = undefined - } - else { - break - } - parent = explorerTree.nodes.get(node.id)?.parentId - } - else { - break - } - } + clearTaskResult(task) explorerTree.startRun() - return client.rpc.rerunTestOrSuite(task.file.filepath, ids) + return client.rpc.rerunTestOrSuite(task.id, task.file.filepath) } export function runCurrent() { diff --git a/packages/vitest/src/api/setup.ts b/packages/vitest/src/api/setup.ts index dc97086693fb..55b59d5469d1 100644 --- a/packages/vitest/src/api/setup.ts +++ b/packages/vitest/src/api/setup.ts @@ -70,11 +70,11 @@ export function setup(ctx: Vitest, _server?: ViteDevServer) { } return fs.writeFile(id, content, 'utf-8') }, - async rerun(files) { - await ctx.rerunFiles(files) + async rerun(files, resetTestNamePattern) { + await ctx.rerunFiles(files, undefined, resetTestNamePattern) }, - async rerunTestOrSuite(filename, ids) { - await ctx.rerunTestOrSuite(filename, ids) + async rerunTestOrSuite(id, filename) { + await ctx.rerunTestOrSuite(id, filename) }, getConfig() { return ctx.getCoreWorkspaceProject().getSerializableConfig() diff --git a/packages/vitest/src/api/types.ts b/packages/vitest/src/api/types.ts index b1eef1a09780..5c27d24b16cb 100644 --- a/packages/vitest/src/api/types.ts +++ b/packages/vitest/src/api/types.ts @@ -44,8 +44,8 @@ export interface WebSocketHandlers { ) => Promise readTestFile: (id: string) => Promise saveTestFile: (id: string, content: string) => Promise - rerun: (files: string[]) => Promise - rerunTestOrSuite: (filename: string, ids: string[]) => Promise + rerun: (files: string[], resetTestNamePattern?: boolean) => Promise + rerunTestOrSuite: (id: string, filename: string) => Promise updateSnapshot: (file?: File) => Promise getUnhandledErrors: () => unknown[] } diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index a46e78adc718..735f8f37de1e 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -8,6 +8,7 @@ import { SnapshotManager } from '@vitest/snapshot/manager' import type { CancelReason, File, TaskResultPack } from '@vitest/runner' import { ViteNodeServer } from 'vite-node/server' import type { defineWorkspace } from 'vitest/config' +import type { RunnerTask, RunnerTestSuite } from '../public' import { version } from '../../package.json' with { type: 'json' } import { getTasks, hasFailed, noop, slash, toArray, wildcardPatternToRegExp } from '../utils' import { getCoverageProvider } from '../integrations/coverage' @@ -676,8 +677,11 @@ export class Vitest { await Promise.all(this._onCancelListeners.splice(0).map(listener => listener(reason))) } - async rerunFiles(files: string[] = this.state.getFilepaths(), trigger?: string) { - this.configOverride.testNamePattern = undefined + async rerunFiles(files: string[] = this.state.getFilepaths(), trigger?: string, resetTestNamePattern = false) { + if (resetTestNamePattern) { + this.configOverride.testNamePattern = undefined + } + if (this.filenamePattern) { const filteredFiles = await this.globTestFiles([this.filenamePattern]) files = files.filter(file => filteredFiles.some(f => f[1] === file)) @@ -689,18 +693,34 @@ export class Vitest { await this.report('onWatcherStart', this.state.getFiles(files)) } - async rerunTestOrSuite(filename: string, ids: string[]) { - const patterns: string[] = [] - for (const id of ids) { - const task = this.state.idMap.get(id) - if (task) { - patterns.push(task.name) + private isSuite(task: RunnerTask): task is RunnerTestSuite { + return Object.hasOwnProperty.call(task, 'tasks') + } + + private collectTasks(task: RunnerTask, patterns: string[]) { + if (this.isSuite(task)) { + for (const child of task.tasks) { + this.collectTasks(child, patterns) } } + else { + patterns.push(task.name) + } + } + + async rerunTestOrSuite(id: string, filename: string) { + const patterns: string[] = [] + const task = this.state.idMap.get(id) + let trigger = 'rerun test file' + if (task) { + trigger = this.isSuite(task) ? 'rerun suite' : 'rerun test' + // this.collectTasks(task, patterns) + patterns.push(task.name) + } await this.changeNamePattern( patterns.length ? patterns.join('|') : '', [filename], - patterns.length ? 'rerun test or suite' : 'rerun test file', + trigger, ) } @@ -708,7 +728,9 @@ export class Vitest { if (pattern === '') { delete this.configOverride.project } - else { this.configOverride.project = pattern } + else { + this.configOverride.project = pattern + } this.projects = this.resolvedProjects.filter(p => p.getName() === pattern) const files = (await this.globTestSpecs()).map(spec => spec.moduleId) From c0c0f852780371351023d411384ff5860da7bb86 Mon Sep 17 00:00:00 2001 From: userquin Date: Sun, 6 Oct 2024 11:30:52 +0200 Subject: [PATCH 4/8] chore: allow rerun test/suite/file when state is not `todo` chore: update run button title based on type --- .../client/components/explorer/ExplorerItem.vue | 16 ++++++++++++---- test/ui/test/ui.spec.ts | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/ui/client/components/explorer/ExplorerItem.vue b/packages/ui/client/components/explorer/ExplorerItem.vue index cb940ca6cc17..c5e2e17ab3c4 100644 --- a/packages/ui/client/components/explorer/ExplorerItem.vue +++ b/packages/ui/client/components/explorer/ExplorerItem.vue @@ -69,7 +69,7 @@ function toggleOpen() { } async function onRun(task: Task) { - if (!state || state === 'skip' || state === 'todo') { + if (state === 'todo') { return } @@ -119,6 +119,14 @@ const gridStyles = computed(() => { } ${gridColumns.join(' ')};` }) +const runButtonTitle = computed(() => { + return type === 'file' + ? 'Run current file' + : type === 'suite' + ? 'Run all tests in this suite' + : 'Run current test' +}) + const escapedName = computed(() => escapeHtml(name)) const highlighted = computed(() => { const regex = highlightRegex.value @@ -230,12 +238,12 @@ const projectNameTextColor = computed(() => { diff --git a/test/ui/test/ui.spec.ts b/test/ui/test/ui.spec.ts index f042de6aa78e..5eee9e6ecc8d 100644 --- a/test/ui/test/ui.spec.ts +++ b/test/ui/test/ui.spec.ts @@ -172,7 +172,7 @@ test.describe('standalone', () => { // run single file await page.getByText('fixtures/sample.test.ts').hover() - await page.getByRole('button', { name: 'Run current test' }).click() + await page.getByRole('button', { name: 'Run current file' }).click() // check results await page.getByText('PASS (1)').click() From d62b4350d44faeb7d1fdbc4efa004dafdeff1539 Mon Sep 17 00:00:00 2001 From: userquin Date: Sun, 6 Oct 2024 12:59:09 +0200 Subject: [PATCH 5/8] chore: cleanup core module --- packages/vitest/src/node/core.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 735f8f37de1e..3cc9f7caaf98 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -697,24 +697,12 @@ export class Vitest { return Object.hasOwnProperty.call(task, 'tasks') } - private collectTasks(task: RunnerTask, patterns: string[]) { - if (this.isSuite(task)) { - for (const child of task.tasks) { - this.collectTasks(child, patterns) - } - } - else { - patterns.push(task.name) - } - } - async rerunTestOrSuite(id: string, filename: string) { const patterns: string[] = [] const task = this.state.idMap.get(id) let trigger = 'rerun test file' if (task) { trigger = this.isSuite(task) ? 'rerun suite' : 'rerun test' - // this.collectTasks(task, patterns) patterns.push(task.name) } await this.changeNamePattern( From a7a902dad9b82fceb419e7d4409477944c128853 Mon Sep 17 00:00:00 2001 From: userquin Date: Tue, 8 Oct 2024 14:35:14 +0200 Subject: [PATCH 6/8] chore: apply requested changes --- .../client/components/explorer/ExplorerItem.vue | 9 ++------- packages/ui/client/composables/client/index.ts | 6 +++--- packages/vitest/src/api/setup.ts | 4 ++-- packages/vitest/src/api/types.ts | 2 +- packages/vitest/src/node/core.ts | 16 ++++++---------- 5 files changed, 14 insertions(+), 23 deletions(-) diff --git a/packages/ui/client/components/explorer/ExplorerItem.vue b/packages/ui/client/components/explorer/ExplorerItem.vue index c5e2e17ab3c4..008cd5bf4e04 100644 --- a/packages/ui/client/components/explorer/ExplorerItem.vue +++ b/packages/ui/client/components/explorer/ExplorerItem.vue @@ -3,7 +3,7 @@ import type { Task, TaskState } from '@vitest/runner' import { nextTick } from 'vue' import { hasFailedSnapshot } from '@vitest/ws-client' import { Tooltip as VueTooltip } from 'floating-vue' -import { client, isReport, runFiles, runTestOrSuite } from '~/composables/client' +import { client, isReport, runFiles, runTask } from '~/composables/client' import { coverageEnabled } from '~/composables/navigation' import type { TaskTreeNodeType } from '~/composables/explorer/types' import { explorerTree } from '~/composables/explorer' @@ -69,10 +69,6 @@ function toggleOpen() { } async function onRun(task: Task) { - if (state === 'todo') { - return - } - onItemClick?.(task) if (coverageEnabled.value) { disableCoverage.value = true @@ -83,7 +79,7 @@ async function onRun(task: Task) { await runFiles([task.file]) } else { - await runTestOrSuite(task) + await runTask(task) } } @@ -243,7 +239,6 @@ const projectNameTextColor = computed(() => { :title="runButtonTitle" icon="i-carbon:play-filled-alt" text-green5 - :disabled="state === 'todo'" @click.prevent.stop="onRun(task)" /> diff --git a/packages/ui/client/composables/client/index.ts b/packages/ui/client/composables/client/index.ts index d92ec2d1c5e1..7ca8f1487679 100644 --- a/packages/ui/client/composables/client/index.ts +++ b/packages/ui/client/composables/client/index.ts @@ -66,7 +66,7 @@ export const isConnecting = computed(() => status.value === 'CONNECTING') export const isDisconnected = computed(() => status.value === 'CLOSED') export function runAll() { - return runFiles(client.state.getFiles()/* , true */) + return runFiles(client.state.getFiles()) } function clearTaskResult(task: Task) { @@ -116,12 +116,12 @@ export function runFiles(useFiles: File[]) { return client.rpc.rerun(useFiles.map(i => i.filepath), true) } -export function runTestOrSuite(task: Task) { +export function runTask(task: Task) { clearTaskResult(task) explorerTree.startRun() - return client.rpc.rerunTestOrSuite(task.id, task.file.filepath) + return client.rpc.rerunTask(task.id) } export function runCurrent() { diff --git a/packages/vitest/src/api/setup.ts b/packages/vitest/src/api/setup.ts index 55b59d5469d1..c108406c177e 100644 --- a/packages/vitest/src/api/setup.ts +++ b/packages/vitest/src/api/setup.ts @@ -73,8 +73,8 @@ export function setup(ctx: Vitest, _server?: ViteDevServer) { async rerun(files, resetTestNamePattern) { await ctx.rerunFiles(files, undefined, resetTestNamePattern) }, - async rerunTestOrSuite(id, filename) { - await ctx.rerunTestOrSuite(id, filename) + async rerunTask(id) { + await ctx.rerunTask(id) }, getConfig() { return ctx.getCoreWorkspaceProject().getSerializableConfig() diff --git a/packages/vitest/src/api/types.ts b/packages/vitest/src/api/types.ts index 5c27d24b16cb..17c1f8008f94 100644 --- a/packages/vitest/src/api/types.ts +++ b/packages/vitest/src/api/types.ts @@ -45,7 +45,7 @@ export interface WebSocketHandlers { readTestFile: (id: string) => Promise saveTestFile: (id: string, content: string) => Promise rerun: (files: string[], resetTestNamePattern?: boolean) => Promise - rerunTestOrSuite: (id: string, filename: string) => Promise + rerunTask: (id: string) => Promise updateSnapshot: (file?: File) => Promise getUnhandledErrors: () => unknown[] } diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 3cc9f7caaf98..07bfafa93080 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -697,19 +697,15 @@ export class Vitest { return Object.hasOwnProperty.call(task, 'tasks') } - async rerunTestOrSuite(id: string, filename: string) { - const patterns: string[] = [] + async rerunTask(id: string) { const task = this.state.idMap.get(id) - let trigger = 'rerun test file' if (task) { - trigger = this.isSuite(task) ? 'rerun suite' : 'rerun test' - patterns.push(task.name) + await this.changeNamePattern( + task.name, + [task.file.filepath], + this.isSuite(task) ? 'rerun suite' : 'rerun test', + ) } - await this.changeNamePattern( - patterns.length ? patterns.join('|') : '', - [filename], - trigger, - ) } async changeProjectName(pattern: string) { From e1d7c3eff9238f7f5253e4ae402bcd4296b7dd2f Mon Sep 17 00:00:00 2001 From: userquin Date: Tue, 8 Oct 2024 17:06:20 +0200 Subject: [PATCH 7/8] chore: throw error when missing task --- packages/vitest/src/node/core.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 07bfafa93080..d7d059b0faed 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -699,13 +699,14 @@ export class Vitest { async rerunTask(id: string) { const task = this.state.idMap.get(id) - if (task) { - await this.changeNamePattern( - task.name, - [task.file.filepath], - this.isSuite(task) ? 'rerun suite' : 'rerun test', - ) + if (!task) { + throw new Error(`Task ${id} was not found`) } + await this.changeNamePattern( + task.name, + [task.file.filepath], + this.isSuite(task) ? 'rerun suite' : 'rerun test', + ) } async changeProjectName(pattern: string) { From 6873a7c3b648c4f2057b3a1fb011b3ad84507dc0 Mon Sep 17 00:00:00 2001 From: userquin Date: Thu, 7 Nov 2024 19:30:38 +0100 Subject: [PATCH 8/8] chore: update logic --- packages/ui/client/composables/client/index.ts | 4 ++-- packages/vitest/src/api/setup.ts | 2 +- packages/vitest/src/node/core.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ui/client/composables/client/index.ts b/packages/ui/client/composables/client/index.ts index 42c21a7d25b6..d633533dae26 100644 --- a/packages/ui/client/composables/client/index.ts +++ b/packages/ui/client/composables/client/index.ts @@ -1,18 +1,18 @@ import type { WebSocketStatus } from '@vueuse/core' -import type { File, SerializedConfig, TaskResultPack } from 'vitest' +import type { File, SerializedConfig, Task, TaskResultPack } from 'vitest' import type { BrowserRunnerState } from '../../../types' import { createFileTask } from '@vitest/runner/utils' import { createClient, getTasks } from '@vitest/ws-client' import { reactive as reactiveVue } from 'vue' import { explorerTree } from '~/composables/explorer' import { isFileNode } from '~/composables/explorer/utils' +import { isSuite as isTaskSuite } from '~/utils/task' import { ui } from '../../composables/api' import { ENTRY_URL, isReport } from '../../constants' import { parseError } from '../error' import { activeFileId } from '../params' import { testRunState, unhandledErrors } from './state' import { createStaticClient } from './static' -import { isSuite as isTaskSuite } from '~/utils/task' export { ENTRY_URL, HOST, isReport, PORT } from '../../constants' diff --git a/packages/vitest/src/api/setup.ts b/packages/vitest/src/api/setup.ts index d74f37e21d1b..bccf237a2d32 100644 --- a/packages/vitest/src/api/setup.ts +++ b/packages/vitest/src/api/setup.ts @@ -73,7 +73,7 @@ export function setup(ctx: Vitest, _server?: ViteDevServer) { return fs.writeFile(id, content, 'utf-8') }, async rerun(files, resetTestNamePattern) { - await ctx.rerunFiles(files, undefined, resetTestNamePattern) + await ctx.rerunFiles(files, undefined, true, resetTestNamePattern) }, async rerunTask(id) { await ctx.rerunTask(id) diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 999598054541..775a7c4f989e 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -2,10 +2,10 @@ import type { CancelReason, File, TaskResultPack } from '@vitest/runner' import type { Writable } from 'node:stream' import type { ViteDevServer } from 'vite' import type { defineWorkspace } from 'vitest/config' +import type { RunnerTask, RunnerTestSuite } from '../public' import type { SerializedCoverageConfig } from '../runtime/config' import type { ArgumentsType, OnServerRestartHandler, ProvidedContext, UserConsoleLog } from '../types/general' import type { ProcessPool, WorkspaceSpec } from './pool' -import type { RunnerTask, RunnerTestSuite } from '../public' import type { TestSpecification } from './spec' import type { ResolvedConfig, UserConfig, VitestRunMode } from './types/config' import type { CoverageProvider } from './types/coverage'