From 386b11160500c7eccfbfcca0794d8d845c230843 Mon Sep 17 00:00:00 2001 From: claneo Date: Fri, 19 Dec 2025 20:11:49 +0800 Subject: [PATCH 1/2] perf: use advanced serialization --- .vscode/tasks.json | 14 ---------- packages/browser/src/protocol.ts | 4 +-- packages/core/src/browserRuntime.ts | 1 + packages/core/src/core/listTests.ts | 4 +-- packages/core/src/pool/forks.ts | 4 +-- packages/core/src/pool/index.ts | 9 +++---- packages/core/src/runtime/api/index.ts | 4 +-- packages/core/src/runtime/runner/index.ts | 31 ++++++++++++---------- packages/core/src/runtime/runner/runner.ts | 2 ++ packages/core/src/runtime/worker/index.ts | 14 ++++++---- packages/core/src/runtime/worker/rpc.ts | 5 ---- packages/core/src/types/core.ts | 4 +-- packages/core/src/types/testSuite.ts | 8 +++--- 13 files changed, 46 insertions(+), 58 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 92f9faf60..f5a6b0b16 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,20 +2,6 @@ // for the documentation about the tasks.json format { "version": "2.0.0", - "problemMatchers": [ - { - "name": "rslib-watch", - "owner": "rslib", - "background": { - "activeOnStart": true, - "beginsPattern": "build started...", - "endsPattern": "build completed, watching for changes..." - }, - "pattern": { - "regexp": "build failed in" - } - } - ], "tasks": [ { "label": "core dev", diff --git a/packages/browser/src/protocol.ts b/packages/browser/src/protocol.ts index 400090c23..36ca1ffda 100644 --- a/packages/browser/src/protocol.ts +++ b/packages/browser/src/protocol.ts @@ -1,8 +1,8 @@ import type { DevicePreset } from '@rstest/core/browser'; import type { RuntimeConfig, - Test, TestFileResult, + TestInfo, TestResult, } from '@rstest/core/browser-runtime'; import type { SnapshotUpdateState } from '@vitest/snapshot'; @@ -96,7 +96,7 @@ export type BrowserClientMessage = // Collect mode messages | { type: 'collect-result'; - payload: { testPath: string; project: string; tests: Test[] }; + payload: { testPath: string; project: string; tests: TestInfo[] }; } | { type: 'collect-complete' } // Unified RPC envelope for all runner -> container/host capability calls. diff --git a/packages/core/src/browserRuntime.ts b/packages/core/src/browserRuntime.ts index 96039094c..98adfb6c6 100644 --- a/packages/core/src/browserRuntime.ts +++ b/packages/core/src/browserRuntime.ts @@ -20,6 +20,7 @@ export type { RuntimeConfig, Test, TestFileResult, + TestInfo, TestResult, WorkerState, } from './types'; diff --git a/packages/core/src/core/listTests.ts b/packages/core/src/core/listTests.ts index 534dcc89b..cc2c45d7e 100644 --- a/packages/core/src/core/listTests.ts +++ b/packages/core/src/core/listTests.ts @@ -8,7 +8,7 @@ import type { Location, ProjectContext, RstestContext, - Test, + TestInfo, } from '../types'; import { bgColor, @@ -348,7 +348,7 @@ export async function listTests( type: 'file' | 'suite' | 'case'; }[] = []; - const traverseTests = (test: Test) => { + const traverseTests = (test: TestInfo) => { if (['skip', 'todo'].includes(test.runMode)) { return; } diff --git a/packages/core/src/pool/forks.ts b/packages/core/src/pool/forks.ts index ef0b96431..eb34a9abc 100644 --- a/packages/core/src/pool/forks.ts +++ b/packages/core/src/pool/forks.ts @@ -1,6 +1,5 @@ import EventEmitter from 'node:events'; import { fileURLToPath } from 'node:url'; -import v8 from 'node:v8'; import { createBirpc } from 'birpc'; import { dirname, resolve } from 'pathe'; import { type Options, Tinypool } from 'tinypool'; @@ -50,8 +49,6 @@ export function createForksChannel( }; const rpc = createBirpcImpl(rpcMethods, { - serialize: v8.serialize, - deserialize: (v) => v8.deserialize(Buffer.from(v)), timeout: -1, post(v) { emitter.emit(events.message, v); @@ -103,6 +100,7 @@ export const createForksPool = (poolOptions: { minThreads, concurrentTasksPerWorker: 1, isolateWorkers: isolate, + serialization: 'advanced', }; const pool = new Tinypool(options); diff --git a/packages/core/src/pool/index.ts b/packages/core/src/pool/index.ts index 46031a1a3..03974f777 100644 --- a/packages/core/src/pool/index.ts +++ b/packages/core/src/pool/index.ts @@ -9,10 +9,10 @@ import type { RstestContext, RuntimeConfig, RuntimeRPC, - Test, TestCaseInfo, TestFileInfo, TestFileResult, + TestInfo, TestResult, TestSuiteInfo, UserConsoleLog, @@ -22,7 +22,6 @@ import { getForceColorEnv, isDeno, needFlagExperimentalDetectModule, - serializableConfig, } from '../utils'; import { isMemorySufficient } from '../utils/memory'; import { createForksPool } from './forks'; @@ -158,7 +157,7 @@ export const createPool = async ({ project: ProjectContext; }) => Promise< { - tests: Test[]; + tests: TestInfo[]; testPath: string; errors?: FormattedError[]; project: string; @@ -309,7 +308,7 @@ export const createPool = async ({ project: projectName, rootPath: context.rootPath, projectRoot: project.rootPath, - runtimeConfig: serializableConfig(runtimeConfig), + runtimeConfig, }, type: 'run', setupEntries, @@ -417,7 +416,7 @@ export const createPool = async ({ outputModule: project.outputModule, rootPath: context.rootPath, projectRoot: project.rootPath, - runtimeConfig: serializableConfig(runtimeConfig), + runtimeConfig, }, type: 'collect', setupEntries, diff --git a/packages/core/src/runtime/api/index.ts b/packages/core/src/runtime/api/index.ts index cc4cfa617..562b9180c 100644 --- a/packages/core/src/runtime/api/index.ts +++ b/packages/core/src/runtime/api/index.ts @@ -2,9 +2,9 @@ import type { Rstest, RstestExpect, RunnerHooks, - Test, TestCase, TestFileResult, + TestInfo, WorkerState, } from '../../types'; import { createRunner } from '../runner'; @@ -20,7 +20,7 @@ export const createRstestRuntime = async ( hooks: RunnerHooks, api: Rstest, ) => Promise; - collectTests: () => Promise; + collectTests: () => Promise; getCurrentTest: () => TestCase | undefined; }; api: Rstest; diff --git a/packages/core/src/runtime/runner/index.ts b/packages/core/src/runtime/runner/index.ts index bd2174dc1..ae23f2943 100644 --- a/packages/core/src/runtime/runner/index.ts +++ b/packages/core/src/runtime/runner/index.ts @@ -19,7 +19,7 @@ export function createRunner({ workerState }: { workerState: WorkerState }): { hooks: RunnerHooks, api: Rstest, ) => Promise; - collectTests: () => Promise; + collectTests: () => Promise; getCurrentTest: TestRunner['getCurrentTest']; }; } { @@ -55,18 +55,7 @@ export function createRunner({ workerState }: { workerState: WorkerState }): { traverseUpdateTest(tests, testNamePattern); hooks.onTestFileReady?.({ testPath, - tests: tests.map(function toTestInfo(test: Test): TestInfo { - return { - testId: test.testId, - name: test.name, - parentNames: test.parentNames, - testPath: test.testPath, - project: test.project, - type: test.type, - location: test.location, - tests: test.type === 'suite' ? test.tests.map(toTestInfo) : [], - }; - }), + tests: tests.map(toTestInfo), }); runtime.instance.updateStatus('running'); @@ -85,9 +74,23 @@ export function createRunner({ workerState }: { workerState: WorkerState }): { const tests = await runtime.instance.getTests(); traverseUpdateTest(tests, testNamePattern); - return tests; + return tests.map(toTestInfo); }, getCurrentTest: () => testRunner.getCurrentTest(), }, }; } + +function toTestInfo(test: Test): TestInfo { + return { + testId: test.testId, + name: test.name, + parentNames: test.parentNames, + testPath: test.testPath, + project: test.project, + type: test.type, + location: test.location, + tests: test.type === 'suite' ? test.tests.map(toTestInfo) : [], + runMode: test.runMode, + }; +} diff --git a/packages/core/src/runtime/runner/runner.ts b/packages/core/src/runtime/runner/runner.ts index 04fe8697f..78b3ca596 100644 --- a/packages/core/src/runtime/runner/runner.ts +++ b/packages/core/src/runtime/runner/runner.ts @@ -302,6 +302,7 @@ export class TestRunner { testId: test.testId, type: 'suite', location: test.location, + runMode: test.runMode, }); if (test.tests.length === 0) { @@ -393,6 +394,7 @@ export class TestRunner { project: test.project, type: 'case', location: test.location, + runMode: test.runMode, }); do { diff --git a/packages/core/src/runtime/worker/index.ts b/packages/core/src/runtime/worker/index.ts index b06077e49..45361b2d7 100644 --- a/packages/core/src/runtime/worker/index.ts +++ b/packages/core/src/runtime/worker/index.ts @@ -2,16 +2,16 @@ import type { MaybePromise, Rstest, RunWorkerOptions, - Test, TestFileResult, + TestInfo, WorkerState, } from '../../types'; import './setup'; +import type { FileCoverageData } from 'istanbul-lib-coverage'; import { install } from 'source-map-support'; import { createCoverageProvider } from '../../coverage'; import { createWorkerMetaMessage } from '../../pool/workerMeta'; import { globalApis } from '../../utils/constants'; -import { undoSerializableConfig } from '../../utils/helper'; import { color } from '../../utils/logger'; import { formatTestError, getRealTimers, setRealTimers } from '../util'; import { createForksRpcOptions, createRuntimeRpc } from './rpc'; @@ -65,7 +65,6 @@ const preparePool = async ({ globalCleanups.length = 0; setRealTimers(); - context.runtimeConfig = undoSerializableConfig(context.runtimeConfig); // Prefer public env var from tinypool, fallback to context.taskId process.env.RSTEST_WORKER_ID = String( @@ -273,7 +272,7 @@ const runInPool = async ( options: RunWorkerOptions['options'], ): Promise< | { - tests: Test[]; + tests: TestInfo[]; testPath: string; } | TestFileResult @@ -462,7 +461,12 @@ const runInPool = async ( const coverageMap = coverageProvider.collect(); if (coverageMap) { // Attach coverage data to test result - results.coverage = coverageMap.toJSON(); + results.coverage = {}; + Object.entries(coverageMap.toJSON()).forEach(([key, value]) => { + if ('toJSON' in value) + results.coverage![key] = value.toJSON() as FileCoverageData; + else results.coverage![key] = value; + }); } // Cleanup coverageProvider.cleanup(); diff --git a/packages/core/src/runtime/worker/rpc.ts b/packages/core/src/runtime/worker/rpc.ts index 67aabc0f1..1676ca77f 100644 --- a/packages/core/src/runtime/worker/rpc.ts +++ b/packages/core/src/runtime/worker/rpc.ts @@ -1,4 +1,3 @@ -import v8 from 'node:v8'; import { type BirpcOptions, type BirpcReturn, createBirpc } from 'birpc'; import type { TinypoolWorkerMessage } from 'tinypool'; import type { RuntimeRPC, ServerRPC } from '../../types'; @@ -15,15 +14,11 @@ export type WorkerRpcOptions = Pick< >; export function createForksRpcOptions({ - nodeV8 = v8, dispose = [], }: { - nodeV8?: typeof v8; dispose?: (() => void)[]; }): WorkerRpcOptions { return { - serialize: nodeV8.serialize, - deserialize: (v) => nodeV8.deserialize(Buffer.from(v)), post(v) { processSend(v); }, diff --git a/packages/core/src/types/core.ts b/packages/core/src/types/core.ts index 5174e4575..f37de746d 100644 --- a/packages/core/src/types/core.ts +++ b/packages/core/src/types/core.ts @@ -8,9 +8,9 @@ import type { import type { Reporter } from './reporter'; import type { FormattedError, - Test, TestCaseInfo, TestFileResult, + TestInfo, TestResult, } from './testSuite'; @@ -93,7 +93,7 @@ export type ListCommandOptions = { }; export type ListCommandResult = { - tests: Test[]; + tests: TestInfo[]; testPath: string; project: string; errors?: FormattedError[]; diff --git a/packages/core/src/types/testSuite.ts b/packages/core/src/types/testSuite.ts index 79a705893..808ddf0b3 100644 --- a/packages/core/src/types/testSuite.ts +++ b/packages/core/src/types/testSuite.ts @@ -1,11 +1,11 @@ import type { SnapshotResult } from '@vitest/snapshot'; +import type { FileCoverageData } from 'istanbul-lib-coverage'; import type { NormalizedFixtures, OnTestFailedHandler, OnTestFinishedHandler, TestContext, } from './api'; -import type { CoverageMapData } from './coverage'; import type { MaybePromise, TestPath } from './utils'; export type TestRunMode = 'run' | 'skip' | 'todo' | 'only'; @@ -43,12 +43,12 @@ export type TestCaseInfo = { /** Only included when `includeTaskLocation` config is enabled */ location?: Location; type: 'case'; + runMode: TestRunMode; }; export type TestCase = TestCaseInfo & { originalFn?: (context: TestContext) => void | Promise; fn?: (context: TestContext) => void | Promise; - runMode: TestRunMode; fails?: boolean; each?: boolean; fixtures?: NormalizedFixtures; @@ -98,10 +98,10 @@ export type TestSuiteInfo = { type: 'suite'; /** Only included when `includeTaskLocation` config is enabled */ location?: Location; + runMode: TestRunMode; }; export type TestSuite = TestSuiteInfo & { - runMode: TestRunMode; each?: boolean; inTestEach?: boolean; concurrent?: boolean; @@ -159,7 +159,7 @@ export type TestResult = { export type TestFileResult = TestResult & { results: TestResult[]; snapshotResult?: SnapshotResult; - coverage?: CoverageMapData; + coverage?: Record; }; export interface UserConsoleLog { From 8b017790b20f64c9b5bef01041a8097566bfc37f Mon Sep 17 00:00:00 2001 From: claneo Date: Fri, 27 Feb 2026 00:46:25 +0800 Subject: [PATCH 2/2] globalSetup --- packages/core/src/core/globalSetup.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/src/core/globalSetup.ts b/packages/core/src/core/globalSetup.ts index 05f3644a1..ada6e50af 100644 --- a/packages/core/src/core/globalSetup.ts +++ b/packages/core/src/core/globalSetup.ts @@ -33,6 +33,7 @@ function createSetupPool() { minThreads: 1, concurrentTasksPerWorker: 1, isolateWorkers: false, + serialization: 'advanced', env: { NODE_ENV: 'test', ...getForceColorEnv(),