diff --git a/examples/lit/package.json b/examples/lit/package.json index ef389c0ec047..17eda52490fd 100644 --- a/examples/lit/package.json +++ b/examples/lit/package.json @@ -10,6 +10,7 @@ "coverage": "vitest run --coverage", "dev": "vite", "test": "vitest", + "list": "vitest list", "test:ui": "vitest --ui" }, "dependencies": { diff --git a/examples/lit/vite.config.ts b/examples/lit/vite.config.ts index 8a822fecb113..72ea883e64b2 100644 --- a/examples/lit/vite.config.ts +++ b/examples/lit/vite.config.ts @@ -9,8 +9,10 @@ export default defineConfig({ // https://lit.dev/docs/tools/testing/#testing-in-the-browser browser: { enabled: true, - name: 'chromium', provider: 'playwright', + instances: [ + { browser: 'chromium' }, + ], }, }, }) diff --git a/packages/browser/src/client/client.ts b/packages/browser/src/client/client.ts index b6fa768adcb1..34fff8aea11b 100644 --- a/packages/browser/src/client/client.ts +++ b/packages/browser/src/client/client.ts @@ -12,9 +12,10 @@ export const RPC_ID = PAGE_TYPE === 'orchestrator' ? getBrowserState().sessionId : getBrowserState().testerId +const METHOD = getBrowserState().method export const ENTRY_URL = `${ location.protocol === 'https:' ? 'wss:' : 'ws:' -}//${HOST}/__vitest_browser_api__?type=${PAGE_TYPE}&rpcId=${RPC_ID}&sessionId=${getBrowserState().sessionId}&projectName=${getBrowserState().config.name || ''}` +}//${HOST}/__vitest_browser_api__?type=${PAGE_TYPE}&rpcId=${RPC_ID}&sessionId=${getBrowserState().sessionId}&projectName=${getBrowserState().config.name || ''}&method=${METHOD}` let setCancel = (_: CancelReason) => {} export const onCancel = new Promise((resolve) => { diff --git a/packages/browser/src/client/public/esm-client-injector.js b/packages/browser/src/client/public/esm-client-injector.js index a3eae26951bb..23d931e2165b 100644 --- a/packages/browser/src/client/public/esm-client-injector.js +++ b/packages/browser/src/client/public/esm-client-injector.js @@ -27,6 +27,7 @@ sessionId: { __VITEST_SESSION_ID__ }, testerId: { __VITEST_TESTER_ID__ }, provider: { __VITEST_PROVIDER__ }, + method: { __VITEST_METHOD__ }, providedContext: { __VITEST_PROVIDED_CONTEXT__ }, }; diff --git a/packages/browser/src/client/utils.ts b/packages/browser/src/client/utils.ts index 1eba8160656c..1b16ca9adfce 100644 --- a/packages/browser/src/client/utils.ts +++ b/packages/browser/src/client/utils.ts @@ -74,6 +74,7 @@ export interface BrowserRunnerState { iframeId?: string sessionId: string testerId: string + method: 'run' | 'collect' runTests?: (tests: string[]) => Promise createTesters?: (files: string[]) => Promise cdp?: { diff --git a/packages/browser/src/node/rpc.ts b/packages/browser/src/node/rpc.ts index d4de0a2345f7..75cf0f779d94 100644 --- a/packages/browser/src/node/rpc.ts +++ b/packages/browser/src/node/rpc.ts @@ -50,6 +50,13 @@ export function setupBrowserRpc(globalServer: ParentBrowserProject) { ) } + const method = searchParams.get('method') as 'run' | 'collect' + if (method !== 'run' && method !== 'collect') { + return error( + new Error(`[vitest] Method query in ${request.url} is invalid. Method should be either "run" or "collect".`), + ) + } + if (type === 'orchestrator') { const session = vitest._browserSessions.getSession(sessionId) // it's possible the session was already resolved by the preview provider @@ -67,7 +74,7 @@ export function setupBrowserRpc(globalServer: ParentBrowserProject) { wss.handleUpgrade(request, socket, head, (ws) => { wss.emit('connection', ws, request) - const rpc = setupClient(project, rpcId, ws) + const rpc = setupClient(project, rpcId, ws, method) const state = project.browser!.state as BrowserServerState const clients = type === 'tester' ? state.testers : state.orchestrators clients.set(rpcId, rpc) @@ -96,7 +103,7 @@ export function setupBrowserRpc(globalServer: ParentBrowserProject) { } } - function setupClient(project: TestProject, rpcId: string, ws: WebSocket) { + function setupClient(project: TestProject, rpcId: string, ws: WebSocket, method: 'run' | 'collect') { const mockResolver = new ServerMockResolver(globalServer.vite, { moduleDirectories: project.config.server?.deps?.moduleDirectories, }) @@ -111,19 +118,39 @@ export function setupBrowserRpc(globalServer: ParentBrowserProject) { vitest.state.catchError(error, type) }, async onQueued(file) { - await vitest._testRun.enqueued(project, file) + if (method === 'collect') { + vitest.state.collectFiles(project, [file]) + } + else { + await vitest._testRun.enqueued(project, file) + } }, async onCollected(files) { - await vitest._testRun.collected(project, files) + if (method === 'collect') { + vitest.state.collectFiles(project, files) + } + else { + await vitest._testRun.collected(project, files) + } }, async onTaskUpdate(packs, events) { - await vitest._testRun.updated(packs, events) + if (method === 'collect') { + vitest.state.updateTasks(packs) + } + else { + await vitest._testRun.updated(packs, events) + } }, onAfterSuiteRun(meta) { vitest.coverageProvider?.onAfterSuiteRun(meta) }, - sendLog(log) { - return vitest._testRun.log(log) + async sendLog(log) { + if (method === 'collect') { + vitest.state.updateUserLog(log) + } + else { + await vitest._testRun.log(log) + } }, resolveSnapshotPath(testPath) { return vitest.snapshot.resolvePath(testPath, { diff --git a/packages/browser/src/node/serverOrchestrator.ts b/packages/browser/src/node/serverOrchestrator.ts index f1d61fd713ef..b853e9386e21 100644 --- a/packages/browser/src/node/serverOrchestrator.ts +++ b/packages/browser/src/node/serverOrchestrator.ts @@ -36,6 +36,7 @@ export async function resolveOrchestrator( __VITEST_VITE_CONFIG__: JSON.stringify({ root: browserProject.vite.config.root, }), + __VITEST_METHOD__: JSON.stringify(session?.method || 'run'), __VITEST_FILES__: JSON.stringify(files), __VITEST_TYPE__: '"orchestrator"', __VITEST_SESSION_ID__: JSON.stringify(sessionId), diff --git a/packages/browser/src/node/serverTester.ts b/packages/browser/src/node/serverTester.ts index 182997506e2d..c6d2687c25c8 100644 --- a/packages/browser/src/node/serverTester.ts +++ b/packages/browser/src/node/serverTester.ts @@ -57,13 +57,14 @@ export async function resolveTester( : await globalServer.injectorJs const injector = replacer(injectorJs, { - __VITEST_PROVIDER__: JSON.stringify(project.browser!.provider!.name), + __VITEST_PROVIDER__: JSON.stringify(project.browser!.provider.name), __VITEST_CONFIG__: JSON.stringify(browserProject.wrapSerializedConfig()), __VITEST_FILES__: JSON.stringify(files), __VITEST_VITE_CONFIG__: JSON.stringify({ root: browserProject.vite.config.root, }), __VITEST_TYPE__: '"tester"', + __VITEST_METHOD__: JSON.stringify(method), __VITEST_SESSION_ID__: JSON.stringify(sessionId), __VITEST_TESTER_ID__: JSON.stringify(crypto.randomUUID()), __VITEST_PROVIDED_CONTEXT__: JSON.stringify(stringify(project.getProvidedContext())), diff --git a/packages/vitest/src/node/pools/forks.ts b/packages/vitest/src/node/pools/forks.ts index cba773dde790..f0293256e1fc 100644 --- a/packages/vitest/src/node/pools/forks.ts +++ b/packages/vitest/src/node/pools/forks.ts @@ -17,7 +17,7 @@ import { wrapSerializableConfig } from '../../utils/config-helpers' import { envsOrder, groupFilesByEnv } from '../../utils/test-helpers' import { createMethodsRPC } from './rpc' -function createChildProcessChannel(project: TestProject) { +function createChildProcessChannel(project: TestProject, collect = false) { const emitter = new EventEmitter() const cleanup = () => emitter.removeAllListeners() @@ -27,7 +27,7 @@ function createChildProcessChannel(project: TestProject) { postMessage: message => emitter.emit(events.response, message), } - const rpc = createBirpc(createMethodsRPC(project, { cacheFs: true }), { + const rpc = createBirpc(createMethodsRPC(project, { cacheFs: true, collect }), { eventNames: ['onCancel'], serialize: v8.serialize, deserialize: v => v8.deserialize(Buffer.from(v)), @@ -109,7 +109,7 @@ export function createForksPool( const paths = files.map(f => f.filepath) ctx.state.clearFiles(project, paths) - const { channel, cleanup } = createChildProcessChannel(project) + const { channel, cleanup } = createChildProcessChannel(project, name === 'collect') const workerId = ++id const data: ContextRPC = { pool: 'forks', diff --git a/packages/vitest/src/node/pools/rpc.ts b/packages/vitest/src/node/pools/rpc.ts index 0ba3a675b393..6dedcf73ccba 100644 --- a/packages/vitest/src/node/pools/rpc.ts +++ b/packages/vitest/src/node/pools/rpc.ts @@ -11,6 +11,8 @@ const promises = new Map>() interface MethodsOptions { cacheFs?: boolean + // do not report files + collect?: boolean } export function createMethodsRPC(project: TestProject, options: MethodsOptions = {}): RuntimeRPC { @@ -74,24 +76,40 @@ export function createMethodsRPC(project: TestProject, options: MethodsOptions = transform(id, environment) { return project.vitenode.transformModule(id, environment).catch(handleRollupError) }, - onPathsCollected(paths) { - ctx.state.collectPaths(paths) - return ctx.report('onPathsCollected', paths) - }, async onQueued(file) { - await ctx._testRun.enqueued(project, file) + if (options.collect) { + ctx.state.collectFiles(project, [file]) + } + else { + await ctx._testRun.enqueued(project, file) + } }, async onCollected(files) { - await ctx._testRun.collected(project, files) + if (options.collect) { + ctx.state.collectFiles(project, files) + } + else { + await ctx._testRun.collected(project, files) + } }, onAfterSuiteRun(meta) { ctx.coverageProvider?.onAfterSuiteRun(meta) }, async onTaskUpdate(packs, events) { - await ctx._testRun.updated(packs, events) + if (options.collect) { + ctx.state.updateTasks(packs) + } + else { + await ctx._testRun.updated(packs, events) + } }, async onUserConsoleLog(log) { - await ctx._testRun.log(log) + if (options.collect) { + ctx.state.updateUserLog(log) + } + else { + await ctx._testRun.log(log) + } }, onUnhandledError(err, type) { ctx.state.catchError(err, type) diff --git a/packages/vitest/src/node/pools/threads.ts b/packages/vitest/src/node/pools/threads.ts index e800ee14d0a4..9a8ae875cb6a 100644 --- a/packages/vitest/src/node/pools/threads.ts +++ b/packages/vitest/src/node/pools/threads.ts @@ -16,12 +16,12 @@ import { groupBy } from '../../utils/base' import { envsOrder, groupFilesByEnv } from '../../utils/test-helpers' import { createMethodsRPC } from './rpc' -function createWorkerChannel(project: TestProject) { +function createWorkerChannel(project: TestProject, collect: boolean) { const channel = new MessageChannel() const port = channel.port2 const workerPort = channel.port1 - const rpc = createBirpc(createMethodsRPC(project), { + const rpc = createBirpc(createMethodsRPC(project, { collect }), { eventNames: ['onCancel'], post(v) { port.postMessage(v) @@ -103,7 +103,7 @@ export function createThreadsPool( const paths = files.map(f => f.filepath) ctx.state.clearFiles(project, paths) - const { workerPort, port } = createWorkerChannel(project) + const { workerPort, port } = createWorkerChannel(project, name === 'collect') const workerId = ++id const data: WorkerContext = { pool: 'threads', diff --git a/packages/vitest/src/node/pools/vmForks.ts b/packages/vitest/src/node/pools/vmForks.ts index 75085af560ae..2b5934ff055d 100644 --- a/packages/vitest/src/node/pools/vmForks.ts +++ b/packages/vitest/src/node/pools/vmForks.ts @@ -20,7 +20,7 @@ import { createMethodsRPC } from './rpc' const suppressWarningsPath = resolve(rootDir, './suppress-warnings.cjs') -function createChildProcessChannel(project: TestProject) { +function createChildProcessChannel(project: TestProject, collect: boolean) { const emitter = new EventEmitter() const cleanup = () => emitter.removeAllListeners() @@ -31,7 +31,7 @@ function createChildProcessChannel(project: TestProject) { } const rpc = createBirpc( - createMethodsRPC(project, { cacheFs: true }), + createMethodsRPC(project, { cacheFs: true, collect }), { eventNames: ['onCancel'], serialize: v8.serialize, @@ -117,7 +117,7 @@ export function createVmForksPool( const paths = files.map(f => f.filepath) ctx.state.clearFiles(project, paths) - const { channel, cleanup } = createChildProcessChannel(project) + const { channel, cleanup } = createChildProcessChannel(project, name === 'collect') const workerId = ++id const data: ContextRPC = { pool: 'forks', diff --git a/packages/vitest/src/node/pools/vmThreads.ts b/packages/vitest/src/node/pools/vmThreads.ts index 44c085a8aae2..72478992f2ea 100644 --- a/packages/vitest/src/node/pools/vmThreads.ts +++ b/packages/vitest/src/node/pools/vmThreads.ts @@ -19,12 +19,12 @@ import { createMethodsRPC } from './rpc' const suppressWarningsPath = resolve(rootDir, './suppress-warnings.cjs') -function createWorkerChannel(project: TestProject) { +function createWorkerChannel(project: TestProject, collect: boolean) { const channel = new MessageChannel() const port = channel.port2 const workerPort = channel.port1 - const rpc = createBirpc(createMethodsRPC(project), { + const rpc = createBirpc(createMethodsRPC(project, { collect }), { eventNames: ['onCancel'], post(v) { port.postMessage(v) @@ -108,7 +108,7 @@ export function createVmThreadsPool( const paths = files.map(f => f.filepath) ctx.state.clearFiles(project, paths) - const { workerPort, port } = createWorkerChannel(project) + const { workerPort, port } = createWorkerChannel(project, name === 'collect') const workerId = ++id const data: WorkerContext = { pool: 'vmThreads', diff --git a/packages/vitest/src/types/rpc.ts b/packages/vitest/src/types/rpc.ts index 344e076a1523..156fd7dae3c0 100644 --- a/packages/vitest/src/types/rpc.ts +++ b/packages/vitest/src/types/rpc.ts @@ -35,7 +35,6 @@ export interface RuntimeRPC { force?: boolean ) => Promise - onPathsCollected: (paths: string[]) => void onUserConsoleLog: (log: UserConsoleLog) => void onUnhandledError: (err: unknown, type: string) => void onQueued: (file: File) => void diff --git a/test/cli/fixtures/list/math.test.ts b/test/cli/fixtures/list/math.test.ts index c39601812ac5..792c121416fa 100644 --- a/test/cli/fixtures/list/math.test.ts +++ b/test/cli/fixtures/list/math.test.ts @@ -1,5 +1,7 @@ import { expect, it } from 'vitest' +console.log('logging during collection') + it('1 plus 1', () => { expect(1 + 1).toBe(2) }) diff --git a/test/cli/test/list.test.ts b/test/cli/test/list.test.ts index ad3c8a03267b..545e0ac8d1fe 100644 --- a/test/cli/test/list.test.ts +++ b/test/cli/test/list.test.ts @@ -177,7 +177,7 @@ test('correctly prints project name and locations in json report', async () => { "file": "/fixtures/list/math.test.ts", "projectName": "custom", "location": { - "line": 3, + "line": 5, "column": 1 } }, @@ -186,7 +186,7 @@ test('correctly prints project name and locations in json report', async () => { "file": "/fixtures/list/math.test.ts", "projectName": "custom", "location": { - "line": 7, + "line": 9, "column": 1 } }