diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 286e785a..ca948feb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,6 +59,10 @@ jobs: if: steps.changes.outputs.changed == 'true' run: pnpm install + - name: Run Type Check + if: steps.changes.outputs.changed == 'true' + run: pnpm run typecheck + - name: Run Test if: steps.changes.outputs.changed == 'true' run: pnpm run test diff --git a/.gitignore b/.gitignore index 97f3de4f..a905f345 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ test-temp-* # ignore directory for artifacts produced by tests test-results/ fixtures-test/ +.rslib/ diff --git a/biome.json b/biome.json index 8faba951..435c860b 100644 --- a/biome.json +++ b/biome.json @@ -1,16 +1,6 @@ { - "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", - "organizeImports": { - "enabled": true, - "include": [ - "./**/*.js", - "./**/*.jsx", - "./**/*.ts", - "./**/*.tsx", - "./**/*.mjs", - "./**/*.cjs" - ] - }, + "$schema": "https://biomejs.dev/schemas/2.0.6/schema.json", + "assist": { "actions": { "source": { "organizeImports": "on" } } }, "vcs": { "enabled": true, "defaultBranch": "main", @@ -21,7 +11,7 @@ "ignoreUnknown": true }, "formatter": { - "ignore": [], + "includes": ["**", "!**/*.vue"], "indentStyle": "space" }, "javascript": { @@ -42,6 +32,7 @@ }, "linter": { "enabled": true, + "includes": ["**", "!**/*.vue"], "rules": { "recommended": true, "style": { @@ -51,7 +42,17 @@ "options": { "filenameCases": ["camelCase", "PascalCase", "export"] } - } + }, + "noParameterAssign": "error", + "useAsConstAssertion": "error", + "useDefaultParameterLast": "error", + "useEnumInitializers": "error", + "useSelfClosingElements": "error", + "useSingleVarDeclarator": "error", + "noUnusedTemplateLiteral": "error", + "useNumberNamespace": "error", + "noInferrableTypes": "error", + "noUselessElse": "error" }, "suspicious": { "noExplicitAny": "off", @@ -59,6 +60,9 @@ }, "performance": { "noDelete": "off" + }, + "correctness": { + "useHookAtTopLevel": "off" } } } diff --git a/examples/react/package.json b/examples/react/package.json index 939d8ab5..0e1e44f4 100644 --- a/examples/react/package.json +++ b/examples/react/package.json @@ -13,7 +13,7 @@ "react-dom": "^19.1.0" }, "devDependencies": { - "@rsbuild/core": "1.4.0-rc.0", + "@rsbuild/core": "1.4.2", "@rsbuild/plugin-react": "^1.3.2", "@testing-library/dom": "^10.4.0", "@testing-library/react": "^16.3.0", diff --git a/nx.json b/nx.json index 4029b1f0..36b9d6ea 100644 --- a/nx.json +++ b/nx.json @@ -1,5 +1,8 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", + "tui": { + "enabled": false + }, "namedInputs": { "default": ["{projectRoot}/src/**/*"], "build": [ diff --git a/package.json b/package.json index 5bea5f81..435ad490 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "rstest-monorepo", "private": true, "scripts": { + "typecheck": "cross-env NX_DAEMON=false nx run-many -t typecheck --exclude @examples/* --parallel=10", "build": "cross-env NX_DAEMON=false nx run-many -t build --exclude @examples/* --parallel=10", "e2e": "cd tests && pnpm test", "test": "rstest run", @@ -29,9 +30,9 @@ "pnpm-lock.yaml": "pnpm dedupe --check" }, "devDependencies": { - "@biomejs/biome": "^1.9.4", + "@biomejs/biome": "^2.0.6", "@changesets/cli": "^2.29.5", - "@rsdoctor/rspack-plugin": "^1.1.4", + "@rsdoctor/rspack-plugin": "^1.1.5", "@rstest/core": "workspace:*", "@types/fs-extra": "^11.0.4", "@types/node": "^22.13.8", @@ -43,8 +44,8 @@ "nano-staged": "^0.8.0", "nx": "^21.2.1", "path-serializer": "0.5.0", - "prettier": "^3.6.0", - "prettier-plugin-packagejson": "^2.5.15", + "prettier": "^3.6.2", + "prettier-plugin-packagejson": "^2.5.17", "simple-git-hooks": "^2.13.0", "typescript": "^5.8.3" }, diff --git a/packages/core/LICENSE b/packages/core/LICENSE index 502859ea..de587c44 100644 --- a/packages/core/LICENSE +++ b/packages/core/LICENSE @@ -139,9 +139,9 @@ Licensed under MIT license in the repository at https://github.com/jestjs/jest.g ### @jridgewell/trace-mapping -Licensed under MIT license in the repository at git+https://github.com/jridgewell/trace-mapping.git. +Licensed under MIT license in the repository at git+https://github.com/jridgewell/sourcemaps.git. -> Copyright 2022 Justin Ridgewell +> Copyright 2024 Justin Ridgewell > > Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal diff --git a/packages/core/README.md b/packages/core/README.md index 086f98b4..1cb245d6 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -6,6 +6,14 @@ Rstest is a testing framework powered by Rspack. -## 📖 License +## Documentation + +See [Documentation](https://rstest.rs). + +## Contributing + +Please read the [Contributing Guide](https://github.com/web-infra-dev/rstest/blob/main/CONTRIBUTING.md). + +## License Rstest is licensed under the [MIT License](https://github.com/web-infra-dev/rstest/blob/main/LICENSE). diff --git a/packages/core/package.json b/packages/core/package.json index 2779cebd..436aec19 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@rstest/core", - "version": "0.0.3", + "version": "0.0.4", "description": "The Rsbuild-based test tool.", "bugs": { "url": "https://github.com/web-infra-dev/rstest/issues" @@ -49,11 +49,12 @@ ], "scripts": { "build": "rslib build", + "typecheck": "tsc --noEmit", "dev": "rslib build --watch", "test": "npx rstest run --globals" }, "dependencies": { - "@rsbuild/core": "1.4.0-rc.0", + "@rsbuild/core": "1.4.2", "@types/chai": "^5.2.2", "@vitest/expect": "^3.2.4", "@vitest/snapshot": "^3.2.4", @@ -66,9 +67,9 @@ "devDependencies": { "@sinonjs/fake-timers": "^14.0.0", "@babel/code-frame": "^7.27.1", - "@jridgewell/trace-mapping": "0.3.25", + "@jridgewell/trace-mapping": "0.3.27", "@microsoft/api-extractor": "^7.52.8", - "@rslib/core": "0.10.2", + "@rslib/core": "0.10.4", "@rstest/tsconfig": "workspace:*", "@types/babel__code-frame": "^7.0.6", "@types/sinonjs__fake-timers": "^8.1.5", @@ -76,7 +77,7 @@ "jsdom": "^26.1.0", "@types/source-map-support": "^0.5.10", "cac": "^6.7.14", - "jest-diff": "^30.0.2", + "jest-diff": "^30.0.3", "license-webpack-plugin": "^4.0.2", "picocolors": "^1.1.1", "rslog": "^1.2.8", diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 66468385..9968f4aa 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -7,11 +7,11 @@ import { import { dirname, isAbsolute, join } from 'pathe'; import type { NormalizedConfig, RstestConfig } from './types'; import { + color, DEFAULT_CONFIG_EXTENSIONS, DEFAULT_CONFIG_NAME, - TEMP_RSTEST_OUTPUT_DIR_GLOB, - color, logger, + TEMP_RSTEST_OUTPUT_DIR_GLOB, } from './utils'; const findConfig = (basePath: string): string | undefined => { diff --git a/packages/core/src/core/listTests.ts b/packages/core/src/core/listTests.ts index 62cc7983..cce67f66 100644 --- a/packages/core/src/core/listTests.ts +++ b/packages/core/src/core/listTests.ts @@ -52,6 +52,7 @@ export async function listTests( const getRsbuildStats = await createRsbuildServer({ name, globTestSourceEntries, + normalizedConfig: context.normalizedConfig, setupFiles, rsbuildInstance, rootPath, diff --git a/packages/core/src/core/plugins/entry.ts b/packages/core/src/core/plugins/entry.ts index 24027aaf..4f720f10 100644 --- a/packages/core/src/core/plugins/entry.ts +++ b/packages/core/src/core/plugins/entry.ts @@ -1,5 +1,5 @@ import type { RsbuildPlugin, Rspack } from '@rsbuild/core'; -import { TEMP_RSTEST_OUTPUT_DIR_GLOB, castArray } from '../../utils'; +import { castArray, TEMP_RSTEST_OUTPUT_DIR_GLOB } from '../../utils'; class TestFileWatchPlugin { private contextToWatch: string | null = null; diff --git a/packages/core/src/core/rsbuild.ts b/packages/core/src/core/rsbuild.ts index 6b2ba473..25855933 100644 --- a/packages/core/src/core/rsbuild.ts +++ b/packages/core/src/core/rsbuild.ts @@ -1,16 +1,22 @@ import fs from 'node:fs'; import { + createRsbuild, type ManifestData, type RsbuildInstance, logger as RsbuildLogger, type RsbuildPlugin, type Rspack, - createRsbuild, rspack, } from '@rsbuild/core'; import path from 'pathe'; import type { EntryInfo, RstestContext, SourceMapInput } from '../types'; -import { TEMP_RSTEST_OUTPUT_DIR, getNodeVersion, isDebug } from '../utils'; +import { + castArray, + getNodeVersion, + isDebug, + NODE_BUILTINS, + TEMP_RSTEST_OUTPUT_DIR, +} from '../utils'; import { pluginEntryWatch } from './plugins/entry'; import { pluginIgnoreResolveError } from './plugins/ignoreResolveError'; @@ -31,7 +37,7 @@ const autoExternalNodeModules: ( type?: Rspack.ExternalsType, ) => void, ) => void = ({ context, request, dependencyType, getResolve }, callback) => { - if (!request || request.startsWith('node:')) { + if (!request) { return callback(); } @@ -67,6 +73,37 @@ const autoExternalNodeModules: ( }); }; +const autoExternalNodeBuiltin: ( + data: Rspack.ExternalItemFunctionData, + callback: ( + err?: Error, + result?: Rspack.ExternalItemValue, + type?: Rspack.ExternalsType, + ) => void, +) => void = ({ request, dependencyType }, callback) => { + if (!request) { + return callback(); + } + + const isNodeBuiltin = NODE_BUILTINS.some((builtin) => { + if (typeof builtin === 'string') { + return builtin === request; + } + + return builtin.test(request); + }); + + if (isNodeBuiltin) { + callback( + undefined, + request, + dependencyType === 'commonjs' ? 'commonjs' : 'module-import', + ); + } else { + callback(); + } +}; + export const prepareRsbuild = async ( context: RstestContext, globTestSourceEntries: () => Promise>, @@ -82,12 +119,14 @@ export const prepareRsbuild = async ( output, tools, testEnvironment, + performance, + dev = {}, }, } = context; const debugMode = isDebug(); RsbuildLogger.level = debugMode ? 'verbose' : 'error'; - const writeToDisk = debugMode; + const writeToDisk = dev.writeToDisk || debugMode; const rsbuildInstance = await createRsbuild({ rsbuildConfig: { @@ -101,6 +140,7 @@ export const prepareRsbuild = async ( strictPort: false, middlewareMode: true, }, + performance, environments: { [name]: { dev: { @@ -120,19 +160,14 @@ export const prepareRsbuild = async ( distPath: { root: TEMP_RSTEST_OUTPUT_DIR, }, - externals: [ - { - '@rstest/core': 'global @rstest/core', - }, - testEnvironment === 'node' ? autoExternalNodeModules : {}, - ], target: 'node', }, tools: { rspack: (config) => { config.output ??= {}; config.output.iife = false; - config.externalsPresets = { node: true }; + // polyfill interop + config.output.importFunctionName = '__rstest_dynamic_import__'; config.output.devtoolModuleFilenameTemplate = '[absolute-resource-path]'; config.plugins.push( @@ -144,6 +179,21 @@ export const prepareRsbuild = async ( }), ); + // Avoid externals configuration being modified by users + config.externals = castArray(config.externals) || []; + + config.externals.unshift({ + '@rstest/core': 'global @rstest/core', + }); + + if (testEnvironment === 'node') { + config.externals.push(autoExternalNodeModules); + } + + config.externalsPresets ??= {}; + config.externalsPresets.node = false; + config.externals.push(autoExternalNodeBuiltin); + config.module.parser ??= {}; config.module.parser.javascript = { // Keep dynamic import expressions. @@ -169,18 +219,13 @@ export const prepareRsbuild = async ( } config.optimization = { - ...(config.optimization || {}), moduleIds: 'named', chunkIds: 'named', + ...(config.optimization || {}), // make sure setup file and test file share the runtime runtimeChunk: { name: 'runtime', }, - splitChunks: { - chunks: 'all', - minSize: 0, - maxInitialRequests: Number.POSITIVE_INFINITY, - }, }; }, }, @@ -205,9 +250,11 @@ export const createRsbuildServer = async ({ globTestSourceEntries, setupFiles, rsbuildInstance, + normalizedConfig, }: { rsbuildInstance: RsbuildInstance; name: string; + normalizedConfig: RstestContext['normalizedConfig']; globTestSourceEntries: () => Promise>; setupFiles: Record; rootPath: string; @@ -242,7 +289,12 @@ export const createRsbuildServer = async ({ }); if (isDebug()) { - await rsbuildInstance.inspectConfig({ writeToDisk: true }); + await rsbuildInstance.inspectConfig({ + writeToDisk: true, + extraConfigs: { + retest: normalizedConfig, + }, + }); } const outputFileSystem = diff --git a/packages/core/src/core/runTests.ts b/packages/core/src/core/runTests.ts index 72553dbb..a6b590c8 100644 --- a/packages/core/src/core/runTests.ts +++ b/packages/core/src/core/runTests.ts @@ -55,6 +55,7 @@ export async function runTests( const getRsbuildStats = await createRsbuildServer({ name, + normalizedConfig: context.normalizedConfig, // TODO: Try not to call globTestSourceEntries again. globTestSourceEntries, setupFiles, diff --git a/packages/core/src/node.ts b/packages/core/src/node.ts index e3a7be03..7ab00e8a 100644 --- a/packages/core/src/node.ts +++ b/packages/core/src/node.ts @@ -1 +1,8 @@ -export type { RstestConfig, Reporter, RstestCommand } from './types'; +export type { + Reporter, + RstestCommand, + RstestConfig, + TestFileInfo, + TestFileResult, + TestResult, +} from './types'; diff --git a/packages/core/src/pool/forks.ts b/packages/core/src/pool/forks.ts index 6e8dda04..74b3d5c5 100644 --- a/packages/core/src/pool/forks.ts +++ b/packages/core/src/pool/forks.ts @@ -6,8 +6,8 @@ import { dirname, resolve } from 'pathe'; import { type Options, Tinypool } from 'tinypool'; import type { FormattedError, - RunWorkerOptions, RuntimeRPC, + RunWorkerOptions, ServerRPC, Test, TestFileResult, diff --git a/packages/core/src/reporter/index.ts b/packages/core/src/reporter/index.ts index 31db25f3..f62772b3 100644 --- a/packages/core/src/reporter/index.ts +++ b/packages/core/src/reporter/index.ts @@ -112,8 +112,11 @@ export class DefaultReporter implements Reporter { typeof result.duration !== 'undefined' ? ` (${prettyTime(result.duration, false)})` : ''; + const retry = result.retryCount + ? color.yellow(` (retry x${result.retryCount})`) + : ''; - console.log(` ${icon} ${nameStr}${color.gray(duration)}`); + console.log(` ${icon} ${nameStr}${color.gray(duration)}${retry}`); if (result.errors) { for (const error of result.errors) { diff --git a/packages/core/src/reporter/summary.ts b/packages/core/src/reporter/summary.ts index e1ea467a..b64a6715 100644 --- a/packages/core/src/reporter/summary.ts +++ b/packages/core/src/reporter/summary.ts @@ -7,13 +7,13 @@ import type { TestResult, } from '../types'; import { - TEST_DELIMITER, color, formatTestPath, getTaskNameWithPrefix, logger, prettyTestPath, prettyTime, + TEST_DELIMITER, } from '../utils'; export const getSummaryStatusString = ( diff --git a/packages/core/src/runtime/api/expect.ts b/packages/core/src/runtime/api/expect.ts index c1b152b9..ae681404 100644 --- a/packages/core/src/runtime/api/expect.ts +++ b/packages/core/src/runtime/api/expect.ts @@ -2,19 +2,19 @@ * This method is modified based on source found in * https://github.com/vitest-dev/vitest/blob/e8ce94cfb5520a8b69f9071cc5638a53129130d6/packages/vitest/src/integrations/chai/poll.ts */ -import * as chai from 'chai'; import { ASYMMETRIC_MATCHERS_OBJECT, + addCustomEqualityTesters, + customMatchers, GLOBAL_EXPECT, + getState, JestAsymmetricMatchers, JestChaiExpect, JestExtend, - addCustomEqualityTesters, - customMatchers, - getState, setState, } from '@vitest/expect'; +import * as chai from 'chai'; import type { Assertion, MatcherState, diff --git a/packages/core/src/runtime/api/index.ts b/packages/core/src/runtime/api/index.ts index f1295f45..f56da418 100644 --- a/packages/core/src/runtime/api/index.ts +++ b/packages/core/src/runtime/api/index.ts @@ -8,7 +8,7 @@ import type { WorkerState, } from '../../types'; import { createRunner } from '../runner'; -import { assert, GLOBAL_EXPECT, createExpect } from './expect'; +import { assert, createExpect, GLOBAL_EXPECT } from './expect'; import { createRstestUtilities } from './utilities'; export const createRstestRuntime = ( diff --git a/packages/core/src/runtime/api/poll.ts b/packages/core/src/runtime/api/poll.ts index 88e87b36..f86cc392 100644 --- a/packages/core/src/runtime/api/poll.ts +++ b/packages/core/src/runtime/api/poll.ts @@ -71,7 +71,7 @@ export function createExpectPoll(expect: RstestExpect): RstestExpect['poll'] { const promise = () => new Promise((resolve, reject) => { let intervalId: any; - // biome-ignore lint/style/useConst: + // biome-ignore lint/style/useConst: let let timeoutId: any; let lastError: any; // TODO: use timeout manager @@ -128,7 +128,7 @@ export function createExpectPoll(expect: RstestExpect): RstestExpect['poll'] { // only .then is enough to check awaited, but we type this as `Promise` in global types // so let's follow it return { - // biome-ignore lint/suspicious/noThenProperty: + // biome-ignore lint/suspicious/noThenProperty: promise-like then(onFulfilled, onRejected) { awaited = true; resultPromise ||= promise(); diff --git a/packages/core/src/runtime/api/public.ts b/packages/core/src/runtime/api/public.ts index 87a65d26..49eb2e23 100644 --- a/packages/core/src/runtime/api/public.ts +++ b/packages/core/src/runtime/api/public.ts @@ -1,4 +1,5 @@ import type { Rstest, RstestUtilities } from '../../types'; + export type { Assertion } from '../../types/expect'; export declare const expect: Rstest['expect']; diff --git a/packages/core/src/runtime/api/snapshot.ts b/packages/core/src/runtime/api/snapshot.ts index bd10dfe7..f7e675fe 100644 --- a/packages/core/src/runtime/api/snapshot.ts +++ b/packages/core/src/runtime/api/snapshot.ts @@ -5,8 +5,8 @@ import type { ChaiPlugin } from '@vitest/expect'; import { equals, iterableEquality, subsetEquality } from '@vitest/expect'; import { - SnapshotClient, addSerializer, + SnapshotClient, stripSnapshotIndentation, } from '@vitest/snapshot'; import type { Assertion, TestCase } from '../../types'; @@ -298,13 +298,13 @@ export const SnapshotPlugin: ChaiPlugin = (chai, utils) => { ); } const test = getTest('toThrowErrorMatchingInlineSnapshot', this); - // TODO - // const isInsideEach = test.each || test.suite?.each; - // if (isInsideEach) { - // throw new Error( - // 'InlineSnapshot cannot be used inside of test.each or describe.each', - // ); - // } + + const isInsideEach = test.each || test.inTestEach; + if (isInsideEach) { + throw new Error( + 'InlineSnapshot cannot be used inside of test.each or describe.each', + ); + } const expected = utils.flag(this, 'object'); const error = utils.flag(this, 'error'); const promise = utils.flag(this, 'promise') as string | undefined; diff --git a/packages/core/src/runtime/api/spy.ts b/packages/core/src/runtime/api/spy.ts index 57f49f44..f5e50866 100644 --- a/packages/core/src/runtime/api/spy.ts +++ b/packages/core/src/runtime/api/spy.ts @@ -1,10 +1,11 @@ -import { type SpyInternalImpl, getInternalState, internalSpyOn } from 'tinyspy'; +import { getInternalState, internalSpyOn, type SpyInternalImpl } from 'tinyspy'; import type { FunctionLike, Mock, MockContext, MockFn, MockInstance, + NormalizedProcedure, } from '../../types'; let callOrder = 0; @@ -14,7 +15,7 @@ export const mocks: Set = new Set(); const wrapSpy = ( obj: Record, methodName: string, - mockFn?: T, + mockFn?: NormalizedProcedure, ): Mock => { const spyImpl = internalSpyOn(obj, methodName, mockFn) as SpyInternalImpl< Parameters, @@ -23,7 +24,7 @@ const wrapSpy = ( const spyFn = spyImpl as unknown as Mock; - let mockImplementationOnce: T[] = []; + let mockImplementationOnce: NormalizedProcedure[] = []; let implementation = mockFn; let mockName = mockFn?.name; diff --git a/packages/core/src/runtime/runner/runner.ts b/packages/core/src/runtime/runner/runner.ts index 7b2be49d..66647e1f 100644 --- a/packages/core/src/runtime/runner/runner.ts +++ b/packages/core/src/runtime/runner/runner.ts @@ -85,7 +85,7 @@ export class TestRunner { return result; } - let result: TestResult | undefined = undefined; + let result: TestResult | undefined; this.beforeEach(test, state, api); @@ -128,7 +128,7 @@ export class TestRunner { }, ], }; - } catch (error) { + } catch (_err) { result = { status: 'pass' as const, parentNames: test.parentNames, @@ -300,7 +300,7 @@ export class TestRunner { } } else { const start = RealDate.now(); - let result: TestResult | undefined = undefined; + let result: TestResult | undefined; let retryCount = 0; do { @@ -318,6 +318,7 @@ export class TestRunner { } while (retryCount <= retry && result.status === 'fail'); result.duration = RealDate.now() - start; + result.retryCount = retryCount - 1; hooks.onTestCaseResult?.(result); results.push(result); } diff --git a/packages/core/src/runtime/runner/runtime.ts b/packages/core/src/runtime/runner/runtime.ts index 0384a56b..1b1072c8 100644 --- a/packages/core/src/runtime/runner/runtime.ts +++ b/packages/core/src/runtime/runner/runtime.ts @@ -20,7 +20,7 @@ import type { TestRunMode, TestSuite, } from '../../types'; -import { ROOT_SUITE_NAME, castArray } from '../../utils'; +import { castArray, ROOT_SUITE_NAME } from '../../utils'; import { formatName } from '../util'; import { normalizeFixtures } from './fixtures'; import { registerTestSuiteListener, wrapTimeout } from './task'; @@ -427,7 +427,10 @@ export class RunnerRuntime { export const createRuntimeAPI = ({ testPath, testTimeout, -}: { testPath: string; testTimeout: number }): { +}: { + testPath: string; + testTimeout: number; +}): { api: RunnerAPI; instance: RunnerRuntime; } => { diff --git a/packages/core/src/runtime/runner/task.ts b/packages/core/src/runtime/runner/task.ts index 090264e9..81968bb4 100644 --- a/packages/core/src/runtime/runner/task.ts +++ b/packages/core/src/runtime/runner/task.ts @@ -8,7 +8,7 @@ import type { TestSuite, TestSuiteListeners, } from '../../types'; -import { ROOT_SUITE_NAME, getTaskNameWithPrefix } from '../../utils'; +import { getTaskNameWithPrefix, ROOT_SUITE_NAME } from '../../utils'; export const getTestStatus = ( results: TestResult[], diff --git a/packages/core/src/runtime/worker/console.ts b/packages/core/src/runtime/worker/console.ts index 35420242..1a85aca4 100644 --- a/packages/core/src/runtime/worker/console.ts +++ b/packages/core/src/runtime/worker/console.ts @@ -1,9 +1,9 @@ -import { strict as assert, AssertionError } from 'node:assert'; +import { AssertionError, strict as assert } from 'node:assert'; import { Console } from 'node:console'; import { - type InspectOptions, format, formatWithOptions, + type InspectOptions, inspect, } from 'node:util'; import { color, prettyTime } from '../../utils'; @@ -23,7 +23,11 @@ export function createCustomConsole({ rpc, testPath, printConsoleTrace, -}: { rpc: WorkerRPC; testPath: string; printConsoleTrace: boolean }): Console { +}: { + rpc: WorkerRPC; + testPath: string; + printConsoleTrace: boolean; +}): Console { const getConsoleTrace = () => { const limit = Error.stackTraceLimit; Error.stackTraceLimit = 4; diff --git a/packages/core/src/runtime/worker/env/jsdom.ts b/packages/core/src/runtime/worker/env/jsdom.ts index b72e3de3..6488ccb5 100644 --- a/packages/core/src/runtime/worker/env/jsdom.ts +++ b/packages/core/src/runtime/worker/env/jsdom.ts @@ -1,6 +1,6 @@ import type { ConstructorOptions } from 'jsdom'; import type { TestEnvironment } from '../../../types'; -import { SKIP_KEYS, getWindowKeys } from './jsdomKeys'; +import { getWindowKeys, SKIP_KEYS } from './jsdomKeys'; type JSDOMOptions = ConstructorOptions & { html?: string | ArrayBufferLike; diff --git a/packages/core/src/runtime/worker/index.ts b/packages/core/src/runtime/worker/index.ts index 811537d2..8e50ea56 100644 --- a/packages/core/src/runtime/worker/index.ts +++ b/packages/core/src/runtime/worker/index.ts @@ -227,7 +227,11 @@ const runInPool = async ( } } + const exit = process.exit; try { + process.exit = (code = process.exitCode || 0): never => { + throw new Error(`process.exit unexpectedly called with "${code}"`); + }; const { rstestContext, runner, @@ -282,6 +286,7 @@ const runInPool = async ( }; } finally { await Promise.all(cleanups.map((fn) => fn())); + process.exit = exit; } }; diff --git a/packages/core/src/runtime/worker/interop.ts b/packages/core/src/runtime/worker/interop.ts index d6d20033..25678f89 100644 --- a/packages/core/src/runtime/worker/interop.ts +++ b/packages/core/src/runtime/worker/interop.ts @@ -4,7 +4,11 @@ export const shouldInterop = ({ interopDefault = true, modulePath, mod, -}: { interopDefault?: boolean; modulePath: string; mod: any }): boolean => { +}: { + interopDefault?: boolean; + modulePath: string; + mod: any; +}): boolean => { if (interopDefault === false) { return false; } diff --git a/packages/core/src/runtime/worker/loadModule.ts b/packages/core/src/runtime/worker/loadModule.ts index e780c797..722b0eb4 100644 --- a/packages/core/src/runtime/worker/loadModule.ts +++ b/packages/core/src/runtime/worker/loadModule.ts @@ -50,6 +50,78 @@ const createRequire = ( return require; }; +const defineRstestDynamicImport = + ({ + testPath, + interopDefault, + returnModule = false, + }: { + returnModule?: boolean; + testPath: string; + interopDefault: boolean; + }) => + async (specifier: string, importAttributes: ImportCallOptions) => { + const resolvedPath = isAbsolute(specifier) + ? pathToFileURL(specifier) + : await import.meta.resolve(specifier, pathToFileURL(testPath)); + + const modulePath = + typeof resolvedPath === 'string' ? resolvedPath : resolvedPath.pathname; + + const importedModule = await import( + modulePath, + importAttributes as ImportCallOptions + ); + + if ( + shouldInterop({ + interopDefault, + modulePath, + mod: importedModule, + }) + ) { + const { mod, defaultExport } = interopModule(importedModule); + + if (returnModule) { + return asModule(mod, defaultExport); + } + + return new Proxy(mod, { + get(mod, prop) { + if (prop === 'default') { + return defaultExport; + } + /** + * interop invalid named exports. eg: + * exports: module.exports = { a: 1 } + * import: import { a } from 'mod'; + */ + return mod[prop] ?? defaultExport?.[prop]; + }, + has(mod, prop) { + if (prop === 'default') { + return defaultExport !== undefined; + } + return prop in mod || (defaultExport && prop in defaultExport); + }, + getOwnPropertyDescriptor(mod, prop): any { + const descriptor = Reflect.getOwnPropertyDescriptor(mod, prop); + if (descriptor) { + return descriptor; + } + if (prop === 'default' && defaultExport !== undefined) { + return { + value: defaultExport, + enumerable: true, + configurable: true, + }; + } + }, + }); + } + return importedModule; + }; + const loadModule = ({ codeContent, distPath, @@ -87,6 +159,10 @@ const loadModule = ({ assetFiles, interopDefault, ), + __rstest_dynamic_import__: defineRstestDynamicImport({ + testPath, + interopDefault, + }), __dirname: fileDir, __filename: testPath, ...rstestContext, @@ -100,35 +176,12 @@ const loadModule = ({ filename: distPath, lineOffset: 0, columnOffset: -codeDefinition.length, - importModuleDynamically: async ( - specifier, - _referencer, - importAttributes, - ) => { - const resolvedPath = isAbsolute(specifier) - ? pathToFileURL(specifier) - : await import.meta.resolve(specifier, pathToFileURL(testPath)); - - const modulePath = - typeof resolvedPath === 'string' ? resolvedPath : resolvedPath.pathname; - - const importedModule = await import( - modulePath, - importAttributes as ImportCallOptions - ); - - if ( - shouldInterop({ - interopDefault, - modulePath, - mod: importedModule, - }) - ) { - const { mod, defaultExport } = interopModule(importedModule); - - return asModule(mod, defaultExport); - } - return importedModule; + importModuleDynamically: (specifier, _referencer, importAttributes) => { + return defineRstestDynamicImport({ + testPath, + interopDefault, + returnModule: true, + })(specifier, importAttributes as ImportCallOptions); }, }); fn(...Object.values(context)); diff --git a/packages/core/src/types/config.ts b/packages/core/src/types/config.ts index 419d31e8..07437e64 100644 --- a/packages/core/src/types/config.ts +++ b/packages/core/src/types/config.ts @@ -60,7 +60,7 @@ export interface RstestConfig { */ retry?: number; /** - * Allows the test suite to pass when no files are found. + * Pass when no tests are found. * * @default false */ @@ -186,7 +186,17 @@ export interface RstestConfig { 'define' | 'tsconfigPath' | 'decorators' | 'include' | 'exclude' >; - output?: Pick, 'cssModules'>; + performance?: Pick< + NonNullable, + 'bundleAnalyze' + >; + + dev?: Pick, 'writeToDisk'>; + + output?: Pick< + NonNullable, + 'cssModules' | 'externals' | 'cleanDistPath' + >; resolve?: RsbuildConfig['resolve']; @@ -203,7 +213,9 @@ type OptionalKeys = | 'source' | 'resolve' | 'output' + | 'performance' | 'tools' + | 'dev' | 'onConsoleLog'; export type NormalizedConfig = Required< diff --git a/packages/core/src/types/expect.ts b/packages/core/src/types/expect.ts index 8c6bc748..2a059b4d 100644 --- a/packages/core/src/types/expect.ts +++ b/packages/core/src/types/expect.ts @@ -8,7 +8,7 @@ import type { ExpectStatic as VitestExpectStatic, MatcherState as VitestMatcherState, } from '@vitest/expect'; -import type { SnapshotState, addSerializer } from '@vitest/snapshot'; +import type { addSerializer, SnapshotState } from '@vitest/snapshot'; interface SnapshotMatcher { ( diff --git a/packages/core/src/types/index.ts b/packages/core/src/types/index.ts index 19039ce5..0ac0e93d 100644 --- a/packages/core/src/types/index.ts +++ b/packages/core/src/types/index.ts @@ -1,11 +1,11 @@ +export type * from './api'; export type * from './config'; export type * from './core'; -export type * from './worker'; export type * from './environment'; -export type * from './testSuite'; -export type * from './api'; export type * from './expect'; export type * from './mock'; -export type * from './runner'; export type * from './reporter'; +export type * from './runner'; +export type * from './testSuite'; export type * from './utils'; +export type * from './worker'; diff --git a/packages/core/src/types/mock.ts b/packages/core/src/types/mock.ts index ca4b7b49..749c82e1 100644 --- a/packages/core/src/types/mock.ts +++ b/packages/core/src/types/mock.ts @@ -34,15 +34,6 @@ interface MockSettledResultRejected { value: any; } -interface MockSettledResultFulfilled { - type: 'fulfilled'; - value: T; -} -interface MockSettledResultRejected { - type: 'rejected'; - value: any; -} - type MockSettledResult = | MockSettledResultFulfilled | MockSettledResultRejected; @@ -82,6 +73,12 @@ export type MockContext = { settledResults: MockSettledResult>>[]; }; +type Procedure = (...args: any[]) => any; +// pick a single function type from function overloads, unions, etc... +export type NormalizedProcedure = ( + ...args: Parameters +) => ReturnType; + export interface MockInstance { _isMockFunction: true; /** @@ -108,20 +105,20 @@ export interface MockInstance { /** * Returns current mock implementation if there is one. */ - getMockImplementation(): T | undefined; + getMockImplementation(): NormalizedProcedure | undefined; /** * Accepts a function that should be used as the implementation of the mock. */ - mockImplementation(fn: T): this; + mockImplementation(fn: NormalizedProcedure): this; /** * Accepts a function that will be used as an implementation of the mock for one call to the mocked function. */ - mockImplementationOnce(fn: T): this; + mockImplementationOnce(fn: NormalizedProcedure): this; /** * Accepts a function which should be temporarily used as the implementation of the mock while the callback is being executed. */ withImplementation( - fn: T, + fn: NormalizedProcedure, callback: () => T2, ): T2 extends Promise ? Promise : void; /** diff --git a/packages/core/src/types/testSuite.ts b/packages/core/src/types/testSuite.ts index b1a7b2be..5b7da4e6 100644 --- a/packages/core/src/types/testSuite.ts +++ b/packages/core/src/types/testSuite.ts @@ -1,8 +1,6 @@ import type { SnapshotResult } from '@vitest/snapshot'; import type { NormalizedFixtures, TestContext } from './api'; -import type { TestPath } from './utils'; - -import type { MaybePromise } from './utils'; +import type { MaybePromise, TestPath } from './utils'; export type TestRunMode = 'run' | 'skip' | 'todo' | 'only'; @@ -111,6 +109,7 @@ export type TestResult = { parentNames?: string[]; duration?: number; errors?: FormattedError[]; + retryCount?: number; }; export type TestFileResult = TestResult & { diff --git a/packages/core/src/utils/error.ts b/packages/core/src/utils/error.ts index b721f024..d1c1047c 100644 --- a/packages/core/src/utils/error.ts +++ b/packages/core/src/utils/error.ts @@ -1,5 +1,5 @@ import fs from 'node:fs'; -import { TraceMap, originalPositionFor } from '@jridgewell/trace-mapping'; +import { originalPositionFor, TraceMap } from '@jridgewell/trace-mapping'; import { type StackFrame, parse as stackTraceParse } from 'stacktrace-parser'; import type { FormattedError, GetSourcemap } from '../types'; import { color, formatTestPath, logger } from '../utils'; diff --git a/packages/core/src/utils/helper.ts b/packages/core/src/utils/helper.ts index f16a44b6..8e39f26b 100644 --- a/packages/core/src/utils/helper.ts +++ b/packages/core/src/utils/helper.ts @@ -143,4 +143,67 @@ export const getNodeVersion = (): number[] => { : [0, 0, 0]; }; +// Ported from https://github.com/webpack/webpack/blob/21b28a82f7a6ec677752e1c8fb722a830a2adf69/lib/node/NodeTargetPlugin.js. +export const NODE_BUILTINS: (string | RegExp)[] = [ + 'assert', + 'assert/strict', + 'async_hooks', + 'buffer', + 'child_process', + 'cluster', + 'console', + 'constants', + 'crypto', + 'dgram', + 'diagnostics_channel', + 'dns', + 'dns/promises', + 'domain', + 'events', + 'fs', + 'fs/promises', + 'http', + 'http2', + 'https', + 'inspector', + 'inspector/promises', + 'module', + 'net', + 'os', + 'path', + 'path/posix', + 'path/win32', + 'perf_hooks', + 'process', + 'punycode', + 'querystring', + 'readline', + 'readline/promises', + 'repl', + 'stream', + 'stream/consumers', + 'stream/promises', + 'stream/web', + 'string_decoder', + 'sys', + 'timers', + 'timers/promises', + 'tls', + 'trace_events', + 'tty', + 'url', + 'util', + 'util/types', + 'v8', + 'vm', + 'wasi', + 'worker_threads', + 'zlib', + /^node:/, + + // cspell:word pnpapi + // Yarn PnP adds pnpapi as "builtin" + 'pnpapi', +]; + export { color }; diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 1af9ed9c..7f54ff24 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -1,4 +1,4 @@ +export * from './constants'; export * from './helper'; export * from './logger'; export * from './testFiles'; -export * from './constants'; diff --git a/packages/core/tests/core/__snapshots__/rsbuild.test.ts.snap b/packages/core/tests/core/__snapshots__/rsbuild.test.ts.snap index 7f97e49b..1fbb7303 100644 --- a/packages/core/tests/core/__snapshots__/rsbuild.test.ts.snap +++ b/packages/core/tests/core/__snapshots__/rsbuild.test.ts.snap @@ -1,21 +1,26 @@ // Rstest Snapshot v1 -exports[`prepareRsbuild > should generate rspack config correctly 1`] = ` +exports[`prepareRsbuild > should generate rspack config correctly (jsdom) 1`] = ` { "context": "", "devtool": "source-map", "entry": {}, "experiments": { "asyncWebAssembly": true, + "rspackFuture": { + "bundlerInfo": { + "force": false, + }, + }, }, "externals": [ { "@rstest/core": "global @rstest/core", }, - {}, + [Function], ], "externalsPresets": { - "node": true, + "node": false, }, "ignoreWarnings": [ /Module not found/, @@ -110,7 +115,7 @@ exports[`prepareRsbuild > should generate rspack config correctly 1`] = ` /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, ], "resourceQuery": { - "not": /raw\\|inline/, + "not": /raw/, }, "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, "type": "javascript/auto", @@ -350,11 +355,459 @@ exports[`prepareRsbuild > should generate rspack config correctly 1`] = ` "runtimeChunk": { "name": "runtime", }, - "splitChunks": { - "chunks": "all", - "maxInitialRequests": Infinity, - "minSize": 0, + "splitChunks": false, + }, + "output": { + "assetModuleFilename": "static/assets/[name].[contenthash:8][ext]", + "chunkFilename": "[name].js", + "devtoolModuleFilenameTemplate": "[absolute-resource-path]", + "filename": "[name].js", + "hashFunction": "xxhash64", + "iife": false, + "importFunctionName": "__rstest_dynamic_import__", + "library": { + "type": "commonjs2", + }, + "path": "/dist/.rstest-temp", + "pathinfo": false, + "publicPath": "/", + "webassemblyModuleFilename": "static/wasm/[hash].module.wasm", + }, + "performance": { + "hints": false, + }, + "plugins": [ + { + "name": "RsbuildCorePlugin", + }, + DefinePlugin { + "_args": [ + { + "import.meta.env.ASSET_PREFIX": """", + "import.meta.env.BASE_URL": ""/"", + "import.meta.env.DEV": false, + "import.meta.env.MODE": ""none"", + "import.meta.env.PROD": false, + "import.meta.rstest": "global['@rstest/core']", + "process.env.ASSET_PREFIX": """", + "process.env.BASE_URL": ""/"", + }, + ], + "affectedHooks": "compilation", + "name": "DefinePlugin", + }, + WebpackManifestPlugin { + "options": { + "assetHookStage": Infinity, + "basePath": "", + "fileName": "manifest.json", + "filter": [Function], + "generate": [Function], + "map": null, + "publicPath": null, + "removeKeyHash": /\\(\\[a-f0-9\\]\\{16,32\\}\\\\\\.\\?\\)/gi, + "seed": undefined, + "serialize": [Function], + "sort": null, + "transformExtensions": /\\^\\(gz\\|map\\)\\$/i, + "useEntryKeys": false, + "useLegacyEmit": false, + "writeToFileEmit": false, + }, + }, + IgnoreModuleNotFoundErrorPlugin {}, + RstestPlugin { + "_args": [ + { + "hoistMockModule": true, + "importMetaPathName": true, + "injectModulePathName": true, + "manualMockRoot": undefined, + }, + ], + "affectedHooks": undefined, + "name": "RstestPlugin", + }, + ], + "resolve": { + "alias": { + "@swc/helpers": "/node_modules//@swc/helpers", + }, + "extensions": [ + ".ts", + ".tsx", + ".mjs", + ".js", + ".jsx", + ".json", + ], + }, + "target": "node", + "watch": false, + "watchOptions": { + "aggregateTimeout": 0, + "ignored": "**/**", + }, +} +`; + +exports[`prepareRsbuild > should generate rspack config correctly (node) 1`] = ` +{ + "context": "", + "devtool": "source-map", + "entry": {}, + "experiments": { + "asyncWebAssembly": true, + "rspackFuture": { + "bundlerInfo": { + "force": false, + }, + }, + }, + "externals": [ + { + "@rstest/core": "global @rstest/core", + }, + [Function], + [Function], + ], + "externalsPresets": { + "node": false, + }, + "ignoreWarnings": [ + /Module not found/, + ], + "infrastructureLogging": { + "level": "error", + }, + "mode": "none", + "module": { + "parser": { + "javascript": { + "exportsPresence": "error", + "importDynamic": false, + "requireAsExpression": false, + "requireDynamic": false, + }, + }, + "rules": [ + { + "resolve": { + "fullySpecified": false, + }, + "test": /\\\\\\.m\\?js/, + }, + { + "dependency": { + "not": "url", + }, + "resolve": { + "preferRelative": true, + }, + "resourceQuery": { + "not": /raw\\|inline/, + }, + "sideEffects": true, + "test": /\\\\\\.css\\$/, + "type": "javascript/auto", + "use": [ + { + "loader": "/node_modules//@rsbuild/core/dist/ignoreCssLoader.mjs", + }, + { + "loader": "/node_modules//@rsbuild/core/compiled/css-loader/index.js", + "options": { + "importLoaders": 0, + "modules": { + "auto": true, + "exportGlobals": false, + "exportLocalsConvention": "camelCase", + "exportOnlyLocals": true, + "localIdentName": "[path][name]__[local]-[hash:base64:6]", + "namedExport": false, + }, + "sourceMap": false, + }, + }, + ], + }, + { + "resolve": { + "preferRelative": true, + }, + "resourceQuery": /inline/, + "sideEffects": true, + "test": /\\\\\\.css\\$/, + "type": "javascript/auto", + "use": [ + { + "loader": "/node_modules//@rsbuild/core/compiled/css-loader/index.js", + "options": { + "exportType": "string", + "importLoaders": 0, + "modules": false, + "sourceMap": false, + }, + }, + ], + }, + { + "resourceQuery": /raw/, + "test": /\\\\\\.css\\$/, + "type": "asset/source", + }, + { + "dependency": { + "not": "url", + }, + "include": [ + { + "not": /\\[\\\\\\\\/\\]node_modules\\[\\\\\\\\/\\]/, + }, + /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, + ], + "resourceQuery": { + "not": /raw/, + }, + "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, + "type": "javascript/auto", + "use": [ + { + "loader": "builtin:swc-loader", + "options": { + "env": { + "targets": [ + "node >= 16", + ], + }, + "isModule": "unknown", + "jsc": { + "experimental": { + "cacheRoot": "/node_modules/.cache/.swc", + "keepImportAttributes": true, + }, + "externalHelpers": true, + "output": { + "charset": "utf8", + }, + "parser": { + "decorators": true, + "syntax": "typescript", + "tsx": false, + }, + "transform": { + "decoratorVersion": "2022-03", + "legacyDecorator": false, + }, + }, + }, + }, + ], + }, + { + "resourceQuery": /raw/, + "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, + "type": "asset/source", + }, + { + "mimetype": { + "or": [ + "text/javascript", + "application/javascript", + ], + }, + "resolve": { + "fullySpecified": false, + }, + "use": [ + { + "loader": "builtin:swc-loader", + "options": { + "env": { + "targets": [ + "node >= 16", + ], + }, + "isModule": "unknown", + "jsc": { + "experimental": { + "cacheRoot": "/node_modules/.cache/.swc", + "keepImportAttributes": true, + }, + "externalHelpers": true, + "output": { + "charset": "utf8", + }, + "parser": { + "decorators": true, + "syntax": "typescript", + "tsx": false, + }, + "transform": { + "decoratorVersion": "2022-03", + "legacyDecorator": false, + }, + }, + }, + }, + ], + }, + { + "oneOf": [ + { + "generator": { + "filename": "static/image/[name].[contenthash:8][ext]", + }, + "resourceQuery": /\\(__inline=false\\|url\\)/, + "type": "asset/resource", + }, + { + "resourceQuery": /inline/, + "type": "asset/inline", + }, + { + "resourceQuery": /raw/, + "type": "asset/source", + }, + { + "generator": { + "filename": "static/image/[name].[contenthash:8][ext]", + }, + "parser": { + "dataUrlCondition": { + "maxSize": 4096, + }, + }, + "type": "asset", + }, + ], + "test": /\\\\\\.\\(\\?:png\\|jpg\\|jpeg\\|pjpeg\\|pjp\\|gif\\|bmp\\|webp\\|ico\\|apng\\|avif\\|tif\\|tiff\\|jfif\\|cur\\)\\$/i, + }, + { + "oneOf": [ + { + "generator": { + "filename": "static/svg/[name].[contenthash:8].svg", + }, + "resourceQuery": /\\(__inline=false\\|url\\)/, + "type": "asset/resource", + }, + { + "resourceQuery": /inline/, + "type": "asset/inline", + }, + { + "resourceQuery": /raw/, + "type": "asset/source", + }, + { + "generator": { + "filename": "static/svg/[name].[contenthash:8].svg", + }, + "parser": { + "dataUrlCondition": { + "maxSize": 4096, + }, + }, + "type": "asset", + }, + ], + "test": /\\\\\\.svg\\$/i, + }, + { + "oneOf": [ + { + "generator": { + "filename": "static/media/[name].[contenthash:8][ext]", + }, + "resourceQuery": /\\(__inline=false\\|url\\)/, + "type": "asset/resource", + }, + { + "resourceQuery": /inline/, + "type": "asset/inline", + }, + { + "resourceQuery": /raw/, + "type": "asset/source", + }, + { + "generator": { + "filename": "static/media/[name].[contenthash:8][ext]", + }, + "parser": { + "dataUrlCondition": { + "maxSize": 4096, + }, + }, + "type": "asset", + }, + ], + "test": /\\\\\\.\\(\\?:mp4\\|webm\\|ogg\\|mov\\|mp3\\|wav\\|flac\\|aac\\|m4a\\|opus\\)\\$/i, + }, + { + "oneOf": [ + { + "generator": { + "filename": "static/font/[name].[contenthash:8][ext]", + }, + "resourceQuery": /\\(__inline=false\\|url\\)/, + "type": "asset/resource", + }, + { + "resourceQuery": /inline/, + "type": "asset/inline", + }, + { + "resourceQuery": /raw/, + "type": "asset/source", + }, + { + "generator": { + "filename": "static/font/[name].[contenthash:8][ext]", + }, + "parser": { + "dataUrlCondition": { + "maxSize": 4096, + }, + }, + "type": "asset", + }, + ], + "test": /\\\\\\.\\(\\?:woff\\|woff2\\|eot\\|ttf\\|otf\\|ttc\\)\\$/i, + }, + { + "dependency": "url", + "generator": { + "filename": "static/wasm/[hash].module.wasm", + }, + "test": /\\\\\\.wasm\\$/, + "type": "asset/resource", + }, + { + "test": /\\\\\\.node\\$/, + "use": [ + { + "loader": "/node_modules//@rsbuild/core/dist/transformRawLoader.mjs", + "options": { + "getEnvironment": [Function], + "id": "rsbuild-transform-0", + }, + }, + ], + }, + ], + }, + "name": "test", + "optimization": { + "chunkIds": "named", + "emitOnErrors": true, + "minimize": false, + "moduleIds": "named", + "runtimeChunk": { + "name": "runtime", }, + "splitChunks": false, }, "output": { "assetModuleFilename": "static/assets/[name].[contenthash:8][ext]", @@ -363,6 +816,7 @@ exports[`prepareRsbuild > should generate rspack config correctly 1`] = ` "filename": "[name].js", "hashFunction": "xxhash64", "iife": false, + "importFunctionName": "__rstest_dynamic_import__", "library": { "type": "commonjs2", }, @@ -469,7 +923,7 @@ exports[`prepareRsbuild > should generate swc config correctly with user customi /node_modules\\[\\\\\\\\/\\]query-string\\[\\\\\\\\/\\]/, ], "resourceQuery": { - "not": /raw\\|inline/, + "not": /raw/, }, "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, "type": "javascript/auto", diff --git a/packages/core/tests/core/rsbuild.test.ts b/packages/core/tests/core/rsbuild.test.ts index d99ad12e..7d8fef61 100644 --- a/packages/core/tests/core/rsbuild.test.ts +++ b/packages/core/tests/core/rsbuild.test.ts @@ -2,7 +2,7 @@ import { prepareRsbuild } from '../../src/core/rsbuild'; import type { RstestContext } from '../../src/types'; describe('prepareRsbuild', () => { - it('should generate rspack config correctly', async () => { + it('should generate rspack config correctly (jsdom)', async () => { const rsbuildInstance = await prepareRsbuild( { normalizedConfig: { @@ -12,6 +12,31 @@ describe('prepareRsbuild', () => { source: {}, output: {}, tools: {}, + testEnvironment: 'jsdom', + }, + } as unknown as RstestContext, + async () => ({}), + {}, + ); + expect(rsbuildInstance).toBeDefined(); + const { + origin: { bundlerConfigs }, + } = await rsbuildInstance.inspectConfig(); + + expect(bundlerConfigs[0]).toMatchSnapshot(); + }); + + it('should generate rspack config correctly (node)', async () => { + const rsbuildInstance = await prepareRsbuild( + { + normalizedConfig: { + name: 'test', + plugins: [], + resolve: {}, + source: {}, + output: {}, + tools: {}, + testEnvironment: 'node', }, } as unknown as RstestContext, async () => ({}), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7dcc6ce4..5551c51d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,14 +9,14 @@ importers: .: devDependencies: '@biomejs/biome': - specifier: ^1.9.4 - version: 1.9.4 + specifier: ^2.0.6 + version: 2.0.6 '@changesets/cli': specifier: ^2.29.5 version: 2.29.5 '@rsdoctor/rspack-plugin': - specifier: ^1.1.4 - version: 1.1.4(@rsbuild/core@1.3.22)(@rspack/core@1.3.12(@swc/helpers@0.5.17)) + specifier: ^1.1.5 + version: 1.1.5(@rsbuild/core@1.4.2)(@rspack/core@1.4.1(@swc/helpers@0.5.17)) '@rstest/core': specifier: workspace:* version: link:packages/core @@ -51,11 +51,11 @@ importers: specifier: 0.5.0 version: 0.5.0 prettier: - specifier: ^3.6.0 - version: 3.6.0 + specifier: ^3.6.2 + version: 3.6.2 prettier-plugin-packagejson: - specifier: ^2.5.15 - version: 2.5.15(prettier@3.6.0) + specifier: ^2.5.17 + version: 2.5.17(prettier@3.6.2) simple-git-hooks: specifier: ^2.13.0 version: 2.13.0 @@ -85,11 +85,11 @@ importers: version: 19.1.0(react@19.1.0) devDependencies: '@rsbuild/core': - specifier: 1.4.0-rc.0 - version: 1.4.0-rc.0 + specifier: 1.4.2 + version: 1.4.2 '@rsbuild/plugin-react': specifier: ^1.3.2 - version: 1.3.2(@rsbuild/core@1.4.0-rc.0) + version: 1.3.2(@rsbuild/core@1.4.2) '@testing-library/dom': specifier: ^10.4.0 version: 10.4.0 @@ -112,8 +112,8 @@ importers: packages/core: dependencies: '@rsbuild/core': - specifier: 1.4.0-rc.0 - version: 1.4.0-rc.0 + specifier: 1.4.2 + version: 1.4.2 '@types/chai': specifier: ^5.2.2 version: 5.2.2 @@ -143,14 +143,14 @@ importers: specifier: ^7.27.1 version: 7.27.1 '@jridgewell/trace-mapping': - specifier: 0.3.25 - version: 0.3.25 + specifier: 0.3.27 + version: 0.3.27 '@microsoft/api-extractor': specifier: ^7.52.8 version: 7.52.8(@types/node@22.13.8) '@rslib/core': - specifier: 0.10.2 - version: 0.10.2(@microsoft/api-extractor@7.52.8(@types/node@22.13.8))(typescript@5.8.3) + specifier: 0.10.4 + version: 0.10.4(@microsoft/api-extractor@7.52.8(@types/node@22.13.8))(typescript@5.8.3) '@rstest/tsconfig': specifier: workspace:* version: link:../../scripts/tsconfig @@ -173,8 +173,8 @@ importers: specifier: ^6.7.14 version: 6.7.14 jest-diff: - specifier: ^30.0.2 - version: 30.0.2 + specifier: ^30.0.3 + version: 30.0.3 jsdom: specifier: ^26.1.0 version: 26.1.0 @@ -205,14 +205,20 @@ importers: tests: devDependencies: '@rsbuild/core': - specifier: 1.4.0-rc.0 - version: 1.4.0-rc.0 + specifier: 1.4.2 + version: 1.4.2 '@rslib/core': - specifier: 0.10.2 - version: 0.10.2(@microsoft/api-extractor@7.52.8(@types/node@22.13.8))(typescript@5.8.3) + specifier: 0.10.4 + version: 0.10.4(@microsoft/api-extractor@7.52.8(@types/node@22.13.8))(typescript@5.8.3) '@rstest/core': specifier: workspace:* version: link:../packages/core + '@rstest/tsconfig': + specifier: workspace:* + version: link:../scripts/tsconfig + '@types/jest-image-snapshot': + specifier: ^6.4.0 + version: 6.4.0 jest-image-snapshot: specifier: ^6.5.1 version: 6.5.1 @@ -253,6 +259,8 @@ importers: tests/externals/fixtures/test-interop: {} + tests/externals/fixtures/test-lodash: {} + tests/externals/fixtures/test-module-field: {} tests/externals/fixtures/test-pkg: @@ -280,11 +288,11 @@ importers: version: 19.1.0(react@19.1.0) devDependencies: '@rsbuild/core': - specifier: 1.4.0-rc.0 - version: 1.4.0-rc.0 + specifier: 1.4.2 + version: 1.4.2 '@rsbuild/plugin-react': specifier: ^1.3.2 - version: 1.3.2(@rsbuild/core@1.4.0-rc.0) + version: 1.3.2(@rsbuild/core@1.4.2) '@testing-library/dom': specifier: ^10.4.0 version: 10.4.0 @@ -342,7 +350,7 @@ importers: devDependencies: '@rsbuild/plugin-react': specifier: ^1.3.2 - version: 1.3.2(@rsbuild/core@1.4.0-rc.0) + version: 1.3.2(@rsbuild/core@1.4.2) '@types/react': specifier: ^19.1.8 version: 19.1.8 @@ -363,10 +371,10 @@ importers: devDependencies: '@rsbuild/plugin-sass': specifier: ^1.3.2 - version: 1.3.2(@rsbuild/core@1.4.0-rc.0) + version: 1.3.2(@rsbuild/core@1.4.2) '@rspress/plugin-llms': - specifier: 2.0.0-beta.16 - version: 2.0.0-beta.16(@rspress/core@2.0.0-beta.16(@types/react@19.1.8)(acorn@8.14.1)) + specifier: 2.0.0-beta.18 + version: 2.0.0-beta.18(@rspress/core@2.0.0-beta.18(@types/react@19.1.8)(acorn@8.14.1)) '@rstack-dev/doc-ui': specifier: 1.10.6 version: 1.10.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -390,13 +398,13 @@ importers: version: 19.1.0(react@19.1.0) rsbuild-plugin-google-analytics: specifier: ^1.0.3 - version: 1.0.3(@rsbuild/core@1.4.0-rc.0) + version: 1.0.3(@rsbuild/core@1.4.2) rsbuild-plugin-open-graph: specifier: ^1.0.2 - version: 1.0.2(@rsbuild/core@1.4.0-rc.0) + version: 1.0.2(@rsbuild/core@1.4.2) rspress: - specifier: ^2.0.0-beta.16 - version: 2.0.0-beta.16(@types/react@19.1.8)(acorn@8.14.1) + specifier: ^2.0.0-beta.18 + version: 2.0.0-beta.18(@types/react@19.1.8)(acorn@8.14.1) rspress-plugin-font-open-sans: specifier: ^1.0.0 version: 1.0.0 @@ -489,55 +497,55 @@ packages: resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} engines: {node: '>=6.9.0'} - '@biomejs/biome@1.9.4': - resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} + '@biomejs/biome@2.0.6': + resolution: {integrity: sha512-RRP+9cdh5qwe2t0gORwXaa27oTOiQRQvrFf49x2PA1tnpsyU7FIHX4ZOFMtBC4QNtyWsN7Dqkf5EDbg4X+9iqA==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@1.9.4': - resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==} + '@biomejs/cli-darwin-arm64@2.0.6': + resolution: {integrity: sha512-AzdiNNjNzsE6LfqWyBvcL29uWoIuZUkndu+wwlXW13EKcBHbbKjNQEZIJKYDc6IL+p7bmWGx3v9ZtcRyIoIz5A==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@1.9.4': - resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==} + '@biomejs/cli-darwin-x64@2.0.6': + resolution: {integrity: sha512-wJjjP4E7bO4WJmiQaLnsdXMa516dbtC6542qeRkyJg0MqMXP0fvs4gdsHhZ7p9XWTAmGIjZHFKXdsjBvKGIJJQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@1.9.4': - resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==} + '@biomejs/cli-linux-arm64-musl@2.0.6': + resolution: {integrity: sha512-CVPEMlin3bW49sBqLBg2x016Pws7eUXA27XYDFlEtponD0luYjg2zQaMJ2nOqlkKG9fqzzkamdYxHdMDc2gZFw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@1.9.4': - resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} + '@biomejs/cli-linux-arm64@2.0.6': + resolution: {integrity: sha512-ZSVf6TYo5rNMUHIW1tww+rs/krol7U5A1Is/yzWyHVZguuB0lBnIodqyFuwCNqG9aJGyk7xIMS8HG0qGUPz0SA==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@1.9.4': - resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} + '@biomejs/cli-linux-x64-musl@2.0.6': + resolution: {integrity: sha512-mKHE/e954hR/hSnAcJSjkf4xGqZc/53Kh39HVW1EgO5iFi0JutTN07TSjEMg616julRtfSNJi0KNyxvc30Y4rQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@1.9.4': - resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} + '@biomejs/cli-linux-x64@2.0.6': + resolution: {integrity: sha512-geM1MkHTV1Kh2Cs/Xzot9BOF3WBacihw6bkEmxkz4nSga8B9/hWy5BDiOG3gHDGIBa8WxT0nzsJs2f/hPqQIQw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@1.9.4': - resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} + '@biomejs/cli-win32-arm64@2.0.6': + resolution: {integrity: sha512-290V4oSFoKaprKE1zkYVsDfAdn0An5DowZ+GIABgjoq1ndhvNxkJcpxPsiYtT7slbVe3xmlT0ncdfOsN7KruzA==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@1.9.4': - resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==} + '@biomejs/cli-win32-x64@2.0.6': + resolution: {integrity: sha512-bfM1Bce0d69Ao7pjTjUS+AWSZ02+5UHdiAP85Th8e9yV5xzw6JrHXbL5YWlcEKQ84FIZMdDc7ncuti1wd2sdbw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -645,10 +653,18 @@ packages: resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/expect-utils@30.0.3': + resolution: {integrity: sha512-SMtBvf2sfX2agcT0dA9pXwcUrKvOSDqBY4e4iRfT+Hya33XzV35YVg+98YQFErVGA/VR1Gto5Y2+A6G9LSQ3Yg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/get-type@30.0.1': resolution: {integrity: sha512-AyYdemXCptSRFirI5EPazNxyPwAL0jXt3zceFjaj8NFiKP9pOi0bfXonf6qkf82z2t3QWPeLCWWw4stPBzctLw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/pattern@30.0.1': + resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/schemas@29.6.3': resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -657,6 +673,10 @@ packages: resolution: {integrity: sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/types@30.0.1': + resolution: {integrity: sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -664,8 +684,8 @@ packages: '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.27': + resolution: {integrity: sha512-VO95AxtSFMelbg3ouljAYnfvTEwSWVt/2YLf+U5Ejd8iT5mXE2Sa/1LGyvySMne2CGsepGLI7KpF3EzE3Aq9Mg==} '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -708,39 +728,21 @@ packages: '@microsoft/tsdoc@0.15.1': resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} - '@module-federation/error-codes@0.14.0': - resolution: {integrity: sha512-GGk+EoeSACJikZZyShnLshtq9E2eCrDWbRiB4QAFXCX4oYmGgFfzXlx59vMNwqTKPJWxkEGnPYacJMcr2YYjag==} - '@module-federation/error-codes@0.15.0': resolution: {integrity: sha512-CFJSF+XKwTcy0PFZ2l/fSUpR4z247+Uwzp1sXVkdIfJ/ATsnqf0Q01f51qqSEA6MYdQi6FKos9FIcu3dCpQNdg==} - '@module-federation/runtime-core@0.14.0': - resolution: {integrity: sha512-fGE1Ro55zIFDp/CxQuRhKQ1pJvG7P0qvRm2N+4i8z++2bgDjcxnCKUqDJ8lLD+JfJQvUJf0tuSsJPgevzueD4g==} - '@module-federation/runtime-core@0.15.0': resolution: {integrity: sha512-RYzI61fRDrhyhaEOXH3AgIGlHiot0wPFXu7F43cr+ZnTi+VlSYWLdlZ4NBuT9uV6JSmH54/c+tEZm5SXgKR2sQ==} - '@module-federation/runtime-tools@0.14.0': - resolution: {integrity: sha512-y/YN0c2DKsLETE+4EEbmYWjqF9G6ZwgZoDIPkaQ9p0pQu0V4YxzWfQagFFxR0RigYGuhJKmSU/rtNoHq+qF8jg==} - '@module-federation/runtime-tools@0.15.0': resolution: {integrity: sha512-kzFn3ObUeBp5vaEtN1WMxhTYBuYEErxugu1RzFUERD21X3BZ+b4cWwdFJuBDlsmVjctIg/QSOoZoPXRKAO0foA==} - '@module-federation/runtime@0.14.0': - resolution: {integrity: sha512-kR3cyHw/Y64SEa7mh4CHXOEQYY32LKLK75kJOmBroLNLO7/W01hMNAvGBYTedS7hWpVuefPk1aFZioy3q2VLdQ==} - '@module-federation/runtime@0.15.0': resolution: {integrity: sha512-dTPsCNum9Bhu3yPOcrPYq0YnM9eCMMMNB1wuiqf1+sFbQlNApF0vfZxooqz3ln0/MpgE0jerVvFsLVGfqvC9Ug==} - '@module-federation/sdk@0.14.0': - resolution: {integrity: sha512-lg/OWRsh18hsyTCamOOhEX546vbDiA2O4OggTxxH2wTGr156N6DdELGQlYIKfRdU/0StgtQS81Goc0BgDZlx9A==} - '@module-federation/sdk@0.15.0': resolution: {integrity: sha512-PWiYbGcJrKUD6JZiEPihrXhV3bgXdll4bV7rU+opV7tHaun+Z0CdcawjZ82Xnpb8MCPGmqHwa1MPFeUs66zksw==} - '@module-federation/webpack-bundler-runtime@0.14.0': - resolution: {integrity: sha512-POWS6cKBicAAQ3DNY5X7XEUSfOfUsRaBNxbuwEfSGlrkTE9UcWheO06QP2ndHi8tHQuUKcIHi2navhPkJ+k5xg==} - '@module-federation/webpack-bundler-runtime@0.15.0': resolution: {integrity: sha512-i+3wu2Ljh2TmuUpsnjwZVupOVqV50jP0ndA8PSP4gwMKlgdGeaZ4VH5KkHAXGr2eiYUxYLMrJXz1+eILJqeGDg==} @@ -823,18 +825,8 @@ packages: resolution: {integrity: sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==} engines: {node: '>=14.0.0'} - '@rsbuild/core@1.3.22': - resolution: {integrity: sha512-FGB7m8Tn/uiOhvqk0lw+NRMyD+VYJ+eBqVfpn0X11spkJDiPWn8UkMRvfzCX4XFcNZwRKYuuKJaZK1DNU8UG+w==} - engines: {node: '>=16.10.0'} - hasBin: true - - '@rsbuild/core@1.4.0-beta.4': - resolution: {integrity: sha512-bX8sbNFkleBuD4k8Nd/o0/ChkSuhFhVFWBnjECs5XTLiz4qutKUvoO5gWD5hHErMIcvPSUMlny4TTiRsqJPIKQ==} - engines: {node: '>=16.10.0'} - hasBin: true - - '@rsbuild/core@1.4.0-rc.0': - resolution: {integrity: sha512-GgiHay9R5AdYXgboMwhKoaCZibfy39pZ+jlnAA9YQiorIgvPDZe58U/RWMx4q7amWzgTyge/wvMkNM1ifZR/3w==} + '@rsbuild/core@1.4.2': + resolution: {integrity: sha512-46rcBPYz2kIdDQ1en40yDRT7ZGOKUB0+NqeOAvMAg4DU7TCfgK1qJdmznVasagTWKN9RjjzNpy5encS6W7gUOQ==} engines: {node: '>=16.10.0'} hasBin: true @@ -856,28 +848,28 @@ packages: peerDependencies: '@rsbuild/core': 1.x - '@rsdoctor/client@1.1.4': - resolution: {integrity: sha512-Fl/v4Z58YKGEfS44H57qiTWYA2evyjOG/sxMmEWdzuIJ+XAagoJ0sV+Ry7+zlsXnGdo5mn0bVxjeVOs9/MDQEw==} + '@rsdoctor/client@1.1.5': + resolution: {integrity: sha512-6Qyoy2APXENrJXkAqWGHwoPWLdYZq8nPnMhvCdg3MbKXcIINQdmm2tdSbjFQc9Yopsgx8aimrtuLyYIMgsS2sg==} - '@rsdoctor/core@1.1.4': - resolution: {integrity: sha512-z3TJgEd0jX4J3A6oI1RZHGJlDBUQJ7ssXwvFDq/OZC9gQ20eG6l00xjpIo9b+o4kuPOJeHR+ZDx7YFbHQEsbFQ==} + '@rsdoctor/core@1.1.5': + resolution: {integrity: sha512-EgXnsLpy+7xS3iohKJFryQErX5/HWho3y3O1M/og2bCwY/QcTj+ExMH3MCeC4wTU1pPshfbHrsBNoNlYWOfsXA==} - '@rsdoctor/graph@1.1.4': - resolution: {integrity: sha512-MhQkAZUnf5099mKOuHg74UInEPQhFMoudkQFEwA9rq+YoFgbQiHsqz/G2hjdjXk9EDJh7/Azva4tfLZPkbbLDg==} + '@rsdoctor/graph@1.1.5': + resolution: {integrity: sha512-fWzl4vDKrD0HBAlI5blS0xltKhBIYsmUQDQdLt46UaKlVvYqHEjI5afGrPGqj2rSG5fJVtVsUoD58Sq+FMxnAA==} - '@rsdoctor/rspack-plugin@1.1.4': - resolution: {integrity: sha512-fEL83mAKF0EZjfK8lv1PKQzhGSuUiVTyZftOiyuyTVLE5vDDcoxkCucUQcyTG9QcV4gF8+XnMpFS8k9T6DQx+A==} + '@rsdoctor/rspack-plugin@1.1.5': + resolution: {integrity: sha512-GwOpzQxdjXueIiE4qUour4F0MEZPLNq83tfRVXwUE0h5kqel8MGi1m7PQCQJc9Nu8qNSIsArIsANnd5qUUZPcw==} peerDependencies: '@rspack/core': '*' peerDependenciesMeta: '@rspack/core': optional: true - '@rsdoctor/sdk@1.1.4': - resolution: {integrity: sha512-5JOpCnQN2qWa1NAbU5y+uFY/cY4C5MpRcLKhLMNWHHEIGt5UnkVorK9EsHttKf9S6vb/NXklqNz6yATM06qdWQ==} + '@rsdoctor/sdk@1.1.5': + resolution: {integrity: sha512-2DYRZ46NQb0wkyELfC6XRiEOOEgqLuDsV9my4JpRsr2HNfHsn5WcxvWYJ9j1MXl5W42TORjzbOOKxLjSwuN0mQ==} - '@rsdoctor/types@1.1.4': - resolution: {integrity: sha512-HUh2GFAYib0JEMV5ew59hMSkwy0nGJiMBDlmewfaH9XHlkpmRapHVF4n3E+2OcWmtzKgADoy3E1NAxmZ4TFthQ==} + '@rsdoctor/types@1.1.5': + resolution: {integrity: sha512-Z3ywzA8yN1k70KQi2mFg3DpGDYaZAygcdLZ180tokCGl4CSYQVaF1m9qGOsCMkbhHE2pOQmu7oWxwhxMqRcZ4A==} peerDependencies: '@rspack/core': '*' webpack: 5.x @@ -887,11 +879,11 @@ packages: webpack: optional: true - '@rsdoctor/utils@1.1.4': - resolution: {integrity: sha512-50NUgNCVx5tXG+4VRLoQuLWSZYzAj0359J9uBCo5vbdHK/kUjR0akfWKd1uIbewlAEglEBF1WORTSC7yZHzzvg==} + '@rsdoctor/utils@1.1.5': + resolution: {integrity: sha512-EKjYD+OVo9UdsG1RT/D5RWva2RYn51cZ70e0PAHav0J9EGOWa7dAkKr0ygn4AaRUBdviWJap8W9+NAaI20YyqA==} - '@rslib/core@0.10.2': - resolution: {integrity: sha512-qDXXCMPNqoWyKdssm8djYD59dy1745rhr6jz3D+MSm46/k2Uxi1NZvgGDHS9xiikZUZbwZmGgJNg4m2ytur5uQ==} + '@rslib/core@0.10.4': + resolution: {integrity: sha512-/+cVo+orheZZyyALwyrOvYIRmd7dPKOrP4kfKQrr8VHwJlHS1975iW7/pSesmKT44Jv+wjmTWc5JZbjzCS5K0w==} engines: {node: '>=16.7.0'} hasBin: true peerDependencies: @@ -903,178 +895,60 @@ packages: typescript: optional: true - '@rspack/binding-darwin-arm64@1.3.12': - resolution: {integrity: sha512-8hKjVTBeWPqkMzFPNWIh72oU9O3vFy3e88wRjMPImDCXBiEYrKqGTTLd/J0SO+efdL3SBD1rX1IvdJpxCv6Yrw==} + '@rspack/binding-darwin-arm64@1.4.1': + resolution: {integrity: sha512-enh5DYbpaexdEmjbcxj3BJDauP3w+20jFKWvKROtAQV350PUw0bf2b4WOgngIH9hBzlfjpXNYAk6T5AhVAlY3Q==} cpu: [arm64] os: [darwin] - '@rspack/binding-darwin-arm64@1.4.0-beta.1': - resolution: {integrity: sha512-Ge4PaeWkbzDu/9eqzpR1knUrjyEEIIICE/4g0lqz5YlpghJGupjVo02NRaQiE29+vqQz/80jip+RejoYL75Kiw==} - cpu: [arm64] - os: [darwin] - - '@rspack/binding-darwin-arm64@1.4.0-rc.0': - resolution: {integrity: sha512-4fJ577AVWSHHsY+FEozxhYpnSGZmIneusFhIpbkf7l3x8hh5SdL6hE2y3lNeE9BHgjHPfdMJogoz/VNYcTWG/A==} - cpu: [arm64] - os: [darwin] - - '@rspack/binding-darwin-x64@1.3.12': - resolution: {integrity: sha512-Sj4m+mCUxL7oCpdu7OmWT7fpBM7hywk5CM9RDc3D7StaBZbvNtNftafCrTZzTYKuZrKmemTh5SFzT5Tz7tf6GA==} - cpu: [x64] - os: [darwin] - - '@rspack/binding-darwin-x64@1.4.0-beta.1': - resolution: {integrity: sha512-MadQU+i4aseveEcX+UJ+EbpEaKuVaL4H064Hl0vJE/83VMX/ICPLc4rfl3rrUfStji+jB+7FSFykPqtarUnQAQ==} - cpu: [x64] - os: [darwin] - - '@rspack/binding-darwin-x64@1.4.0-rc.0': - resolution: {integrity: sha512-6r4l/2VhPuHrQrDYazQl4GNTSPvPPXEZwee2fYVO6YeWiPPJFNAUyIT0DjXtAMuJ2zDBOH0DkJ6dqkLf9/kn8Q==} + '@rspack/binding-darwin-x64@1.4.1': + resolution: {integrity: sha512-KoehyhBji4TLXhn4mqOUw6xsQNRzNVA9XcCm1Jx+M1Qb0dhMTNfduvBSyXuRV5+/QaRbk7+4UJbyRNFUtt96kA==} cpu: [x64] os: [darwin] - '@rspack/binding-linux-arm64-gnu@1.3.12': - resolution: {integrity: sha512-7MuOxf3/Mhv4mgFdLTvgnt/J+VouNR65DEhorth+RZm3LEWojgoFEphSAMAvpvAOpYSS68Sw4SqsOZi719ia2w==} + '@rspack/binding-linux-arm64-gnu@1.4.1': + resolution: {integrity: sha512-PJ5cHqvrj1bK7jH5DVrdKoR8Fy+p6l9baxXajq/6xWTxP+4YTdEtLsRZnpLMS1Ho2RRpkxDWJn+gdlKuleNioQ==} cpu: [arm64] os: [linux] - '@rspack/binding-linux-arm64-gnu@1.4.0-beta.1': - resolution: {integrity: sha512-y29G+6/xg1ogNl3tMwE4DLskPJHD37AEFoIpvCB6mb5XbJxF3RIPtpRaMuDXfEz3tgJMiZv9gnhuZzf4tDgpTQ==} + '@rspack/binding-linux-arm64-musl@1.4.1': + resolution: {integrity: sha512-cpDz+z3FwVQfK6VYfXQEb0ym6fFIVmvK4y3R/2VAbVGWYVxZB5I6AcSdOWdDnpppHmcHpf+qQFlwhHvbpMMJNQ==} cpu: [arm64] os: [linux] - '@rspack/binding-linux-arm64-gnu@1.4.0-rc.0': - resolution: {integrity: sha512-K6VLea9StRkOltXqyxNzKeNR3cAFsOpHoNDc8lg0zZNAr1Rn1f+8THqFlWfDV1djXvhM/LsBM+rG97yQFYh/zg==} - cpu: [arm64] - os: [linux] - - '@rspack/binding-linux-arm64-musl@1.3.12': - resolution: {integrity: sha512-s6KKj20T9Z1bA8caIjU6EzJbwyDo1URNFgBAlafCT2UC6yX7flstDJJ38CxZacA9A2P24RuQK2/jPSZpWrTUFA==} - cpu: [arm64] - os: [linux] - - '@rspack/binding-linux-arm64-musl@1.4.0-beta.1': - resolution: {integrity: sha512-zJ6/F4KCiREVSeDC4/4x4CSRge7ymBeRG7S4zVR4EeYyWPBVVqzzextJhyozPPgeEat9eagUMYZRys3ON4DEVQ==} - cpu: [arm64] - os: [linux] - - '@rspack/binding-linux-arm64-musl@1.4.0-rc.0': - resolution: {integrity: sha512-/xAgd0ObvI9ggJWMHDI8WHFCeuqi7gMnzdeN8QWO82dzlwO/0rgBqQkULS1hUDlV47Hh03BwjUz9sbuXCnelqg==} - cpu: [arm64] - os: [linux] - - '@rspack/binding-linux-x64-gnu@1.3.12': - resolution: {integrity: sha512-0w/sRREYbRgHgWvs2uMEJSLfvzbZkPHUg6CMcYQGNVK6axYRot6jPyKetyFYA9pR5fB5rsXegpnFaZaVrRIK2g==} - cpu: [x64] - os: [linux] - - '@rspack/binding-linux-x64-gnu@1.4.0-beta.1': - resolution: {integrity: sha512-xz3KMDWIdDuhpi0bBUeNN2xohCoIROFUSLK+6YoGgjScZ1S20vKBtu4+0ztGkZ8C5gI5lphQb5rtRh634BD4AQ==} - cpu: [x64] - os: [linux] - - '@rspack/binding-linux-x64-gnu@1.4.0-rc.0': - resolution: {integrity: sha512-2u6ytaatpksqUfEn16M/8ppkYaurQpPgZ7cCy3iFpVi6w+7loXWz0X+xklsuBH8H0ie4CZkLmiJIhkW2hFn8KA==} + '@rspack/binding-linux-x64-gnu@1.4.1': + resolution: {integrity: sha512-jjTx53CpiYWK7fAv5qS8xHEytFK6gLfZRk+0kt2YII6uqez/xQ3SRcboreH8XbJcBoxINBzMNMf5/SeMBZ939A==} cpu: [x64] os: [linux] - '@rspack/binding-linux-x64-musl@1.3.12': - resolution: {integrity: sha512-jEdxkPymkRxbijDRsBGdhopcbGXiXDg59lXqIRkVklqbDmZ/O6DHm7gImmlx5q9FoWbz0gqJuOKBz4JqWxjWVA==} + '@rspack/binding-linux-x64-musl@1.4.1': + resolution: {integrity: sha512-FAyR3Og81Smtr/CnsuTiW4ZCYAPCqeV73lzMKZ9xdVUgM9324ryEgqgX38GZLB5Mo7cvQhv7/fpMeHQo16XQCw==} cpu: [x64] os: [linux] - '@rspack/binding-linux-x64-musl@1.4.0-beta.1': - resolution: {integrity: sha512-9DTo9gGKuc19LSipkEUUklG2Bl0cvNuSUP1HV25fWN269tfrELy7uQ6HFytZxQob5c5q9eRgulvEmepeL7m8lg==} - cpu: [x64] - os: [linux] - - '@rspack/binding-linux-x64-musl@1.4.0-rc.0': - resolution: {integrity: sha512-ilSb6GDz/0A+qlnPFZJuw9DtFH/ENf09f7raXxye3faZw/GH8aJ9H3X8VNeMR1QrYwFFk8LLB402EtZHETyz7Q==} - cpu: [x64] - os: [linux] - - '@rspack/binding-wasm32-wasi@1.4.0-beta.1': - resolution: {integrity: sha512-B1+gtkjvXnXcoUU5+ETO3NEiH4Zub3bFJu38sSNp4blsG9cRSbHtyNTpZ3M81LttltMJpcwlprXvfu42RSbfSA==} - cpu: [wasm32] - - '@rspack/binding-wasm32-wasi@1.4.0-rc.0': - resolution: {integrity: sha512-NsnAfBrQDlZTgudxG2YNgnOsZgaE4Vqm1pM0OXWd6NOhSGwGQ6T/rka99dHiUTxxAb6AOqI/avVn1NYsPHsqIQ==} + '@rspack/binding-wasm32-wasi@1.4.1': + resolution: {integrity: sha512-3Q1VICIQP4GsaTJEmmwfowQ48NvhlL0CKH88l5+mbji2rBkGx7yR67pPdfCVNjXcCtFoemTYw98eaumJTjC++g==} cpu: [wasm32] - '@rspack/binding-win32-arm64-msvc@1.3.12': - resolution: {integrity: sha512-ZRvUCb3TDLClAqcTsl/o9UdJf0B5CgzAxgdbnYJbldyuyMeTUB4jp20OfG55M3C2Nute2SNhu2bOOp9Se5Ongw==} + '@rspack/binding-win32-arm64-msvc@1.4.1': + resolution: {integrity: sha512-DdLPOy1J98kn45uEhiEqlBKgMvet+AxOzX2OcrnU0wQXthGM9gty1YXYNryOhlK+X+eOcwcP3GbnDOAKi8nKqw==} cpu: [arm64] os: [win32] - '@rspack/binding-win32-arm64-msvc@1.4.0-beta.1': - resolution: {integrity: sha512-sI809RYsqjNzoIB+xvUjU1oVL19rr3Zcyk9d/MOFy0oMeFqKPBQYJy6li9/tUu1oACYpA1QtPjL8RpaLS//KWQ==} - cpu: [arm64] - os: [win32] - - '@rspack/binding-win32-arm64-msvc@1.4.0-rc.0': - resolution: {integrity: sha512-dT7FZz0dbWKzb3Ka6OD0TkOhGS/qC2/tWJ98nIxXMFCW2ZcULJhwcnRe95KBEwVDzwHgcTTzVa3fUFuTmcL87w==} - cpu: [arm64] - os: [win32] - - '@rspack/binding-win32-ia32-msvc@1.3.12': - resolution: {integrity: sha512-1TKPjuXStPJr14f3ZHuv40Xc/87jUXx10pzVtrPnw+f3hckECHrbYU/fvbVzZyuXbsXtkXpYca6ygCDRJAoNeQ==} + '@rspack/binding-win32-ia32-msvc@1.4.1': + resolution: {integrity: sha512-13s8fYtyC9DyvKosD2Kvzd6fVZDZZyPp91L4TEXWaO0CFhaCbtLTYIntExq9MwtKHYKKx7bchIFw93o0xjKjUg==} cpu: [ia32] os: [win32] - '@rspack/binding-win32-ia32-msvc@1.4.0-beta.1': - resolution: {integrity: sha512-jUlvSBEM9I4WiXS/a8YJJvigdJvnq7R3iItD92XfNbF1cndgkE9zGuG8csyefgdCOMKDJdK9qtuCliHmQ5LheA==} - cpu: [ia32] - os: [win32] - - '@rspack/binding-win32-ia32-msvc@1.4.0-rc.0': - resolution: {integrity: sha512-0Q8+vWvT6zZPkNqaUvBIfXUSC3ZHsu/2on1bX9bGWLVfG4Or1QWY9vNA3vPX8DsK3XiHwixX+iLo95tmQgasNw==} - cpu: [ia32] - os: [win32] - - '@rspack/binding-win32-x64-msvc@1.3.12': - resolution: {integrity: sha512-lCR0JfnYKpV+a6r2A2FdxyUKUS4tajePgpPJN5uXDgMGwrDtRqvx+d0BHhwjFudQVJq9VVbRaL89s2MQ6u+xYw==} + '@rspack/binding-win32-x64-msvc@1.4.1': + resolution: {integrity: sha512-ubQW8FcLnwljDanwTzkC9Abyo59gmX8m9uVr1GHOEuEU9Cua0KMijX2j/MYfiziz4nuQgv1saobY7K1I5nE3YA==} cpu: [x64] os: [win32] - '@rspack/binding-win32-x64-msvc@1.4.0-beta.1': - resolution: {integrity: sha512-qvY6C8NBetv4l9cBTgUkZXdWyAhEMQLbac/YbDIqVqTgACj19vweBlJiu9SWi1emhL4vybNlbss630cbsuL7Tg==} - cpu: [x64] - os: [win32] - - '@rspack/binding-win32-x64-msvc@1.4.0-rc.0': - resolution: {integrity: sha512-bsKJGM6Tu6aqyt6QTDEPL0BCtJ/HWHF3phdCP9XBUcmlSvjIwemekTs/QO/k2ZKXQ93j9Sz8J92WWmNQp0Mp8w==} - cpu: [x64] - os: [win32] - - '@rspack/binding@1.3.12': - resolution: {integrity: sha512-4Ic8lV0+LCBfTlH5aIOujIRWZOtgmG223zC4L3o8WY/+ESAgpdnK6lSSMfcYgRanYLAy3HOmFIp20jwskMpbAg==} - - '@rspack/binding@1.4.0-beta.1': - resolution: {integrity: sha512-cHtpiH0Iv7MrTrQCTPGwm0ourL6X82BCSK4tfmkwEOodMfCVkezG16bC0MCRKdaJCG/dehj594TnghwGldzj1A==} - - '@rspack/binding@1.4.0-rc.0': - resolution: {integrity: sha512-kBEzks6RymjBLYF84TkUP895yCqqlodHDmBsWKbJGOokNKx+0ohnoWxXws5oZca/j9DSKCdEsA8VyROtqdMujw==} - - '@rspack/core@1.3.12': - resolution: {integrity: sha512-mAPmV4LPPRgxpouUrGmAE4kpF1NEWJGyM5coebsjK/zaCMSjw3mkdxiU2b5cO44oIi0Ifv5iGkvwbdrZOvMyFA==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@swc/helpers': '>=0.5.1' - peerDependenciesMeta: - '@swc/helpers': - optional: true - - '@rspack/core@1.4.0-beta.1': - resolution: {integrity: sha512-9CeiopvdgUP+TOWx/pkDbPYG0xEammaVJAvDx13MH2qVdFPr5im1/D/D9yc0LOHirTEQ9txfzEtkriWHevhcSw==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@swc/helpers': '>=0.5.1' - peerDependenciesMeta: - '@swc/helpers': - optional: true + '@rspack/binding@1.4.1': + resolution: {integrity: sha512-zYgOmI+LC2zxB/LIcnaeK66ElFHaPChdWzRruTT1LAFFwpgGkBGAwFoP27PDnxQW0Aejci21Ld8X9tyxm08QFw==} - '@rspack/core@1.4.0-rc.0': - resolution: {integrity: sha512-yO4AP7sgptepks2kNLFvLipdonGv6OKDUIKEl0c7SpbBmPEspd3vsYxE/T5hruFVDnq0GPEePKA1GOjRCKGR8A==} + '@rspack/core@1.4.1': + resolution: {integrity: sha512-UTRCTQk2G8YiPBiMvfn8FcysxeO4Muek6a/Z39Cw2r4ZI8k5iPnKiyZboTJLS7120PwWBw2SO+QQje35Z44x0g==} engines: {node: '>=16.0.0'} peerDependencies: '@swc/helpers': '>=0.5.1' @@ -1095,8 +969,8 @@ packages: webpack-hot-middleware: optional: true - '@rspress/core@2.0.0-beta.16': - resolution: {integrity: sha512-Jy1mZH/VirwoelFv7kfJaeQXeW/EQfmfPSVmPDMvLLUHSBJdRFgPNOSZbIz6sKOWQp0af9TpHxApHnVNVMkJRA==} + '@rspress/core@2.0.0-beta.18': + resolution: {integrity: sha512-crLnWGmU8E8rZLsL7zGrbBzQNXbwhI8ZLQ+xUzLJSfnRl1sqL2bhhm2MJu4Dm8qgiwUzGbPmchp+wr41jx8pDw==} engines: {node: '>=18.0.0'} '@rspress/mdx-rs-darwin-arm64@0.6.6': @@ -1151,39 +1025,31 @@ packages: resolution: {integrity: sha512-NpNhTKBIlV3O6ADhoZkgHvBFvXMW2TYlIWmIT1ysJESUBqDpaN9H3Teve5fugjU2pQ2ORBZO6SQGKliMw/8m/Q==} engines: {node: '>= 10'} - '@rspress/plugin-auto-nav-sidebar@2.0.0-beta.16': - resolution: {integrity: sha512-6dP/DHyl0uWlIOG+89xE7Fm5r9/XQ7LtHZRHiD9f2AWXzkq2R2wbs3s3/nEgcEx5e7uu8cYrhRdcoZhzUVXUig==} + '@rspress/plugin-last-updated@2.0.0-beta.18': + resolution: {integrity: sha512-0uUaLSrHNlu50kQv6wYlBc/KOEEZamY9btbmlk2aFRRXGbPTYAmTOVpab0CtXl3xCPjFcshdNKgwDteggAja+Q==} engines: {node: '>=18.0.0'} - '@rspress/plugin-container-syntax@2.0.0-beta.16': - resolution: {integrity: sha512-xrZc/ALNKldwnjtK5MjoEZQbHsbWP0/cPTPNhUKreq10MoPeWJ9kyC2nUbjLuA9geDIIcZV7Zj0a/Di1Qw8kDA==} - engines: {node: '>=18.0.0'} - - '@rspress/plugin-last-updated@2.0.0-beta.16': - resolution: {integrity: sha512-O9YQpxEKnzL56lzd/kyYX9uIupe/4xHn2CGyoCnIFgy4QGUsi+TEw+nbCiDby6ClIUEofo+DzqFb/S8Rz7+mug==} - engines: {node: '>=18.0.0'} - - '@rspress/plugin-llms@2.0.0-beta.16': - resolution: {integrity: sha512-NzN/I3KAMt7/P7Z2zNbMIbne9Api9aqkdvJpHeWQss0WU2dJBepZ9MdB4Gb6yZ0BwCtYaaeLfvJNMhYCVK5Gfg==} + '@rspress/plugin-llms@2.0.0-beta.18': + resolution: {integrity: sha512-r/f/iog/D/lG0A6vJU7xTtrOGibGrybSLTb2So+zdKbL4LWT/LslC57ARepsmhc8vuQfZKzWVbDv1VulVvrznQ==} engines: {node: '>=18.0.0'} peerDependencies: - '@rspress/core': ^2.0.0-beta.16 + '@rspress/core': ^2.0.0-beta.18 - '@rspress/plugin-medium-zoom@2.0.0-beta.16': - resolution: {integrity: sha512-vB1jfW2kOiQPt6QJNx/jWo2lTi8pzpUm4gIUBZRvMcLA4HALqbJVkXTNhxBgSYmRihuQ2Hz7jPpRVqUhitJNWg==} + '@rspress/plugin-medium-zoom@2.0.0-beta.18': + resolution: {integrity: sha512-+WlMYxQtidOfWc5JJ8mGsHIjy5AY135eC6tSnY/ud8RZxxvHPgy8gWBpsd6mtlQcaju2yckTPW8W/P/hiZ3kpQ==} engines: {node: '>=18.0.0'} peerDependencies: - '@rspress/runtime': ^2.0.0-beta.16 + '@rspress/runtime': ^2.0.0-beta.18 - '@rspress/runtime@2.0.0-beta.16': - resolution: {integrity: sha512-S4ainpE+O5l4ct1XCbaQh0vvzh5IJPwlCKPdHQi7VJ4oHfED3OCqpz0LsU3rDtRmviVt9FBUXdvniUkf1SIicQ==} + '@rspress/runtime@2.0.0-beta.18': + resolution: {integrity: sha512-H6WZNxiYPysxfHJCjB/G2IDvAMotXhfaQZKaMMwdq8LvVczFIYeY4DgwUSsDyHCaZTlwZ6NINF/FK7tDcU99Qw==} engines: {node: '>=18.0.0'} - '@rspress/shared@2.0.0-beta.16': - resolution: {integrity: sha512-eSbWPKfhTSMgpl2p37SiXO+uds4r8FHIFIsHwdtTO882xozX8RbVQWO6smMv1/Jxnpww8j0hSGPIuwbSfya9rg==} + '@rspress/shared@2.0.0-beta.18': + resolution: {integrity: sha512-BW4f2M7vx0rm3+WMUKVvNW/ZqAwlBK01Vw8LJztj/laAf5yiLI2fCPbfSrSBBl2vzAxC/ct7GYjnQv8NFThlUg==} - '@rspress/theme-default@2.0.0-beta.16': - resolution: {integrity: sha512-2L1gY0Iq4fCD+uFmIdiWdBJqEz8hiaL5XJSf84UAXxPZ6xeM1sHAk8ajZ+oPJBjWy7NRAsGc5RrWnuDpyZttBg==} + '@rspress/theme-default@2.0.0-beta.18': + resolution: {integrity: sha512-Yxje26/RCl/8etaFNhKzoWcwPw7Kmu9p9thn9jaROAkXCqpfrKoUva1SQJyxSdrpRSsuW1HIGb8VO5L2BLQCNQ==} engines: {node: '>=18.0.0'} '@rstack-dev/doc-ui@1.10.6': @@ -1322,6 +1188,21 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest-image-snapshot@6.4.0': + resolution: {integrity: sha512-8TQ/EgqFCX0UWSpH488zAc21fCkJNpZPnnp3xWFMqElxApoJV5QOoqajnVRV7AhfF0rbQWTVyc04KG7tXnzCPA==} + + '@types/jest@30.0.0': + resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==} + '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} @@ -1346,6 +1227,9 @@ packages: '@types/node@22.13.8': resolution: {integrity: sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==} + '@types/pixelmatch@5.2.6': + resolution: {integrity: sha512-wC83uexE5KGuUODn6zkm9gMzTwdY5L0chiK+VrKcDfEjzxh1uadlWTvOmAbCpnM9zx/Ww3f8uKlYQVnO/TrqVg==} + '@types/react-dom@19.1.6': resolution: {integrity: sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==} peerDependencies: @@ -1360,6 +1244,9 @@ packages: '@types/source-map-support@0.5.10': resolution: {integrity: sha512-tgVP2H469x9zq34Z0m/fgPewGhg/MLClalNOiPIzQlXrSS2YrKu/xCdSCKnEDwkFha51VKEKB6A9wW26/ZNwzA==} + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/tapable@2.2.7': resolution: {integrity: sha512-D6QzACV9vNX3r8HQQNTOnpG+Bv1rko+yEA82wKs3O9CQ5+XW7HI7TED17/UE7+5dIxyxZIWTxKbsBeF6uKFCwA==} @@ -1372,6 +1259,12 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} @@ -1649,6 +1542,10 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + ci-info@4.2.0: + resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==} + engines: {node: '>=8'} + cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -1711,9 +1608,6 @@ packages: copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} - core-js@3.42.0: - resolution: {integrity: sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==} - core-js@3.43.0: resolution: {integrity: sha512-N6wEbTTZSYOY2rYAn85CuvWWkCK6QweMn7/4Nr3w+gDBeBhk/x4EJeY6FPo4QzDoJZxVTv8U7CMvgWk6pOHHqA==} @@ -1976,6 +1870,10 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -2010,6 +1908,10 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + expect@30.0.3: + resolution: {integrity: sha512-HXg6NvK35/cSYZCUKAtmlgCFyqKM4frEPbzrav5hRqb0GMz0E0lS5hfzYjSaiaE5ysnp/qI2aeZkeyeIAOeXzQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -2433,8 +2335,8 @@ packages: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-diff@30.0.2: - resolution: {integrity: sha512-2UjrNvDJDn/oHFpPrUTVmvYYDNeNtw2DlY3er8bI6vJJb9Fb35ycp/jFLd5RdV59tJ8ekVXX3o/nwPcscgXZJQ==} + jest-diff@30.0.3: + resolution: {integrity: sha512-Q1TAV0cUcBTic57SVnk/mug0/ASyAqtSIOkr7RAlxx97llRYsM74+E8N5WdGJUlwCKwgxPAkVjKh653h1+HA9A==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-get-type@29.6.3: @@ -2450,6 +2352,26 @@ packages: jest: optional: true + jest-matcher-utils@30.0.3: + resolution: {integrity: sha512-hMpVFGFOhYmIIRGJ0HgM9htC5qUiJ00famcc9sRFchJJiLZbbVKrAztcgE6VnXLRxA3XZ0bvNA7hQWh3oHXo/A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-message-util@30.0.2: + resolution: {integrity: sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-mock@30.0.2: + resolution: {integrity: sha512-PnZOHmqup/9cT/y+pXIVbbi8ID6U1XHRmbvR7MvUy4SLqhCbwpkmXhLbsWbGewHrV5x/1bF7YDjs+x24/QSvFA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-regex-util@30.0.1: + resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-util@30.0.2: + resolution: {integrity: sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jiti@2.4.2: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true @@ -2996,8 +2918,8 @@ packages: resolution: {integrity: sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==} engines: {node: ^10 || ^12 || >=14} - prettier-plugin-packagejson@2.5.15: - resolution: {integrity: sha512-2QSx6y4IT6LTwXtCvXAopENW5IP/aujC8fobEM2pDbs0IGkiVjW/ipPuYAHuXigbNe64aGWF7vIetukuzM3CBw==} + prettier-plugin-packagejson@2.5.17: + resolution: {integrity: sha512-1WYvhTix+4EMYZQYSjAxb6+KTCULINuHUTBcxYa2ipoUS9Y2zJVjE3kuZ5I7ZWIFqyK8xpwYIunXqN5eiT7Hew==} peerDependencies: prettier: '>= 1.16.0' peerDependenciesMeta: @@ -3009,8 +2931,8 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.6.0: - resolution: {integrity: sha512-ujSB9uXHJKzM/2GBuE0hBOUgC77CN3Bnpqa+g80bkv3T3A93wL/xlzDATHhnhkzifz/UE2SNOvmbTz5hSkDlHw==} + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} hasBin: true @@ -3193,8 +3115,8 @@ packages: rrweb-cssom@0.8.0: resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} - rsbuild-plugin-dts@0.10.2: - resolution: {integrity: sha512-Fjh8TXBMHhoSpWclfk6JoNZskUfc7b4ywwVSqXKEWbpXdpuInAchYLb6HKk8ZPcOGY+y5tLP6Ro6M6sWJ1qAgA==} + rsbuild-plugin-dts@0.10.4: + resolution: {integrity: sha512-/Zl9hgo1L2cpeKnMvAi0ws57Heo6X9wE07dUwdgb5NMEQSXQaHRv1eeRDKpzNYedaWl+yAIvL2IYK4GcCR0y4w==} engines: {node: '>=16.7.0'} peerDependencies: '@microsoft/api-extractor': ^7 @@ -3234,8 +3156,8 @@ packages: rspress-plugin-sitemap@1.2.0: resolution: {integrity: sha512-fX5i0GLvrxRibKbL9rcBXA8PFDkhoB51bNrFpAuW0mkHg39Ji92SFzzURKvROpuwaGLZ+EP039zJNhx3kYYezA==} - rspress@2.0.0-beta.16: - resolution: {integrity: sha512-0796hRpcOHi6YNUo6aL6EwBmC0yl7VMYCoXr72ZfLRchwJDnIhrEHouaSuyPIjR2hkpjqZylenkVHTAjpcVa9A==} + rspress@2.0.0-beta.18: + resolution: {integrity: sha512-P3qEqzfDH860ZbFrxTAf836QDeUbTy2NSZOeqYN/WPwXom9Pojf2PL+LTrqIvcl/6sbLG+/TnCAbxE9dQYeqmg==} hasBin: true run-applescript@7.0.0: @@ -3478,8 +3400,9 @@ packages: sort-object-keys@1.1.3: resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==} - sort-package-json@3.2.1: - resolution: {integrity: sha512-rTfRdb20vuoAn7LDlEtCqOkYfl2X+Qze6cLbNOzcDpbmKEhJI30tTN44d5shbKJnXsvz24QQhlCm81Bag7EOKg==} + sort-package-json@3.3.1: + resolution: {integrity: sha512-awjhQR2Iy5UN3NuguAK5+RezcEuUg9Ra4O8y2Aj+DlJa7MywyHaipAPf9bu4qqFj0hsYHHoT9sS3aV7Ucu728g==} + engines: {node: '>=20'} hasBin: true source-map-js@1.2.1: @@ -3509,6 +3432,10 @@ packages: ssim.js@3.5.0: resolution: {integrity: sha512-Aj6Jl2z6oDmgYFFbQqK7fght19bXdOxY7Tj03nF+03M9gCBAjeIiO8/PlEGMfKDwYpw4q6iBqVq2YuREorGg/g==} + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + stackframe@1.3.4: resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} @@ -3984,39 +3911,39 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 - '@biomejs/biome@1.9.4': + '@biomejs/biome@2.0.6': optionalDependencies: - '@biomejs/cli-darwin-arm64': 1.9.4 - '@biomejs/cli-darwin-x64': 1.9.4 - '@biomejs/cli-linux-arm64': 1.9.4 - '@biomejs/cli-linux-arm64-musl': 1.9.4 - '@biomejs/cli-linux-x64': 1.9.4 - '@biomejs/cli-linux-x64-musl': 1.9.4 - '@biomejs/cli-win32-arm64': 1.9.4 - '@biomejs/cli-win32-x64': 1.9.4 - - '@biomejs/cli-darwin-arm64@1.9.4': + '@biomejs/cli-darwin-arm64': 2.0.6 + '@biomejs/cli-darwin-x64': 2.0.6 + '@biomejs/cli-linux-arm64': 2.0.6 + '@biomejs/cli-linux-arm64-musl': 2.0.6 + '@biomejs/cli-linux-x64': 2.0.6 + '@biomejs/cli-linux-x64-musl': 2.0.6 + '@biomejs/cli-win32-arm64': 2.0.6 + '@biomejs/cli-win32-x64': 2.0.6 + + '@biomejs/cli-darwin-arm64@2.0.6': optional: true - '@biomejs/cli-darwin-x64@1.9.4': + '@biomejs/cli-darwin-x64@2.0.6': optional: true - '@biomejs/cli-linux-arm64-musl@1.9.4': + '@biomejs/cli-linux-arm64-musl@2.0.6': optional: true - '@biomejs/cli-linux-arm64@1.9.4': + '@biomejs/cli-linux-arm64@2.0.6': optional: true - '@biomejs/cli-linux-x64-musl@1.9.4': + '@biomejs/cli-linux-x64-musl@2.0.6': optional: true - '@biomejs/cli-linux-x64@1.9.4': + '@biomejs/cli-linux-x64@2.0.6': optional: true - '@biomejs/cli-win32-arm64@1.9.4': + '@biomejs/cli-win32-arm64@2.0.6': optional: true - '@biomejs/cli-win32-x64@1.9.4': + '@biomejs/cli-win32-x64@2.0.6': optional: true '@bufbuild/protobuf@2.4.0': {} @@ -4200,8 +4127,17 @@ snapshots: '@jest/diff-sequences@30.0.1': {} + '@jest/expect-utils@30.0.3': + dependencies: + '@jest/get-type': 30.0.1 + '@jest/get-type@30.0.1': {} + '@jest/pattern@30.0.1': + dependencies: + '@types/node': 22.13.8 + jest-regex-util: 30.0.1 + '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.8 @@ -4210,11 +4146,21 @@ snapshots: dependencies: '@sinclair/typebox': 0.34.33 + '@jest/types@30.0.1': + dependencies: + '@jest/pattern': 30.0.1 + '@jest/schemas': 30.0.1 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.13.8 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/trace-mapping@0.3.25': + '@jridgewell/trace-mapping@0.3.27': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 @@ -4320,51 +4266,26 @@ snapshots: '@microsoft/tsdoc@0.15.1': {} - '@module-federation/error-codes@0.14.0': {} - '@module-federation/error-codes@0.15.0': {} - '@module-federation/runtime-core@0.14.0': - dependencies: - '@module-federation/error-codes': 0.14.0 - '@module-federation/sdk': 0.14.0 - '@module-federation/runtime-core@0.15.0': dependencies: '@module-federation/error-codes': 0.15.0 '@module-federation/sdk': 0.15.0 - '@module-federation/runtime-tools@0.14.0': - dependencies: - '@module-federation/runtime': 0.14.0 - '@module-federation/webpack-bundler-runtime': 0.14.0 - '@module-federation/runtime-tools@0.15.0': dependencies: '@module-federation/runtime': 0.15.0 '@module-federation/webpack-bundler-runtime': 0.15.0 - '@module-federation/runtime@0.14.0': - dependencies: - '@module-federation/error-codes': 0.14.0 - '@module-federation/runtime-core': 0.14.0 - '@module-federation/sdk': 0.14.0 - '@module-federation/runtime@0.15.0': dependencies: '@module-federation/error-codes': 0.15.0 '@module-federation/runtime-core': 0.15.0 '@module-federation/sdk': 0.15.0 - '@module-federation/sdk@0.14.0': {} - '@module-federation/sdk@0.15.0': {} - '@module-federation/webpack-bundler-runtime@0.14.0': - dependencies: - '@module-federation/runtime': 0.14.0 - '@module-federation/sdk': 0.14.0 - '@module-federation/webpack-bundler-runtime@0.15.0': dependencies: '@module-federation/runtime': 0.15.0 @@ -4431,31 +4352,15 @@ snapshots: '@remix-run/router@1.23.0': {} - '@rsbuild/core@1.3.22': - dependencies: - '@rspack/core': 1.3.12(@swc/helpers@0.5.17) - '@rspack/lite-tapable': 1.0.1 - '@swc/helpers': 0.5.17 - core-js: 3.42.0 - jiti: 2.4.2 - - '@rsbuild/core@1.4.0-beta.4': + '@rsbuild/core@1.4.2': dependencies: - '@rspack/core': 1.4.0-beta.1(@swc/helpers@0.5.17) + '@rspack/core': 1.4.1(@swc/helpers@0.5.17) '@rspack/lite-tapable': 1.0.1 '@swc/helpers': 0.5.17 core-js: 3.43.0 jiti: 2.4.2 - '@rsbuild/core@1.4.0-rc.0': - dependencies: - '@rspack/core': 1.4.0-rc.0(@swc/helpers@0.5.17) - '@rspack/lite-tapable': 1.0.1 - '@swc/helpers': 0.5.17 - core-js: 3.43.0 - jiti: 2.4.2 - - '@rsbuild/plugin-check-syntax@1.3.0(@rsbuild/core@1.3.22)': + '@rsbuild/plugin-check-syntax@1.3.0(@rsbuild/core@1.4.2)': dependencies: acorn: 8.14.1 browserslist-to-es-version: 1.0.0 @@ -4463,42 +4368,34 @@ snapshots: picocolors: 1.1.1 source-map: 0.7.4 optionalDependencies: - '@rsbuild/core': 1.3.22 + '@rsbuild/core': 1.4.2 - '@rsbuild/plugin-react@1.3.2(@rsbuild/core@1.3.22)': + '@rsbuild/plugin-react@1.3.2(@rsbuild/core@1.4.2)': dependencies: - '@rsbuild/core': 1.3.22 + '@rsbuild/core': 1.4.2 '@rspack/plugin-react-refresh': 1.4.3(react-refresh@0.17.0) react-refresh: 0.17.0 transitivePeerDependencies: - webpack-hot-middleware - '@rsbuild/plugin-react@1.3.2(@rsbuild/core@1.4.0-rc.0)': + '@rsbuild/plugin-sass@1.3.2(@rsbuild/core@1.4.2)': dependencies: - '@rsbuild/core': 1.4.0-rc.0 - '@rspack/plugin-react-refresh': 1.4.3(react-refresh@0.17.0) - react-refresh: 0.17.0 - transitivePeerDependencies: - - webpack-hot-middleware - - '@rsbuild/plugin-sass@1.3.2(@rsbuild/core@1.4.0-rc.0)': - dependencies: - '@rsbuild/core': 1.4.0-rc.0 + '@rsbuild/core': 1.4.2 deepmerge: 4.3.1 loader-utils: 2.0.4 postcss: 8.5.4 reduce-configs: 1.1.0 sass-embedded: 1.89.0 - '@rsdoctor/client@1.1.4': {} + '@rsdoctor/client@1.1.5': {} - '@rsdoctor/core@1.1.4(@rsbuild/core@1.3.22)(@rspack/core@1.3.12(@swc/helpers@0.5.17))': + '@rsdoctor/core@1.1.5(@rsbuild/core@1.4.2)(@rspack/core@1.4.1(@swc/helpers@0.5.17))': dependencies: - '@rsbuild/plugin-check-syntax': 1.3.0(@rsbuild/core@1.3.22) - '@rsdoctor/graph': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) - '@rsdoctor/sdk': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) - '@rsdoctor/types': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) - '@rsdoctor/utils': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) + '@rsbuild/plugin-check-syntax': 1.3.0(@rsbuild/core@1.4.2) + '@rsdoctor/graph': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) + '@rsdoctor/sdk': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) + '@rsdoctor/types': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) + '@rsdoctor/utils': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) axios: 1.10.0 browserslist-load-config: 1.0.0 enhanced-resolve: 5.12.0 @@ -4518,10 +4415,10 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/graph@1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17))': + '@rsdoctor/graph@1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17))': dependencies: - '@rsdoctor/types': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) - '@rsdoctor/utils': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) + '@rsdoctor/types': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) + '@rsdoctor/utils': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) lodash.unionby: 4.8.0 socket.io: 4.8.1 source-map: 0.7.4 @@ -4532,16 +4429,16 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/rspack-plugin@1.1.4(@rsbuild/core@1.3.22)(@rspack/core@1.3.12(@swc/helpers@0.5.17))': + '@rsdoctor/rspack-plugin@1.1.5(@rsbuild/core@1.4.2)(@rspack/core@1.4.1(@swc/helpers@0.5.17))': dependencies: - '@rsdoctor/core': 1.1.4(@rsbuild/core@1.3.22)(@rspack/core@1.3.12(@swc/helpers@0.5.17)) - '@rsdoctor/graph': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) - '@rsdoctor/sdk': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) - '@rsdoctor/types': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) - '@rsdoctor/utils': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) + '@rsdoctor/core': 1.1.5(@rsbuild/core@1.4.2)(@rspack/core@1.4.1(@swc/helpers@0.5.17)) + '@rsdoctor/graph': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) + '@rsdoctor/sdk': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) + '@rsdoctor/types': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) + '@rsdoctor/utils': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) lodash: 4.17.21 optionalDependencies: - '@rspack/core': 1.3.12(@swc/helpers@0.5.17) + '@rspack/core': 1.4.1(@swc/helpers@0.5.17) transitivePeerDependencies: - '@rsbuild/core' - bufferutil @@ -4550,12 +4447,12 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/sdk@1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17))': + '@rsdoctor/sdk@1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17))': dependencies: - '@rsdoctor/client': 1.1.4 - '@rsdoctor/graph': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) - '@rsdoctor/types': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) - '@rsdoctor/utils': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) + '@rsdoctor/client': 1.1.5 + '@rsdoctor/graph': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) + '@rsdoctor/types': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) + '@rsdoctor/utils': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) '@types/fs-extra': 11.0.4 body-parser: 1.20.3 cors: 2.8.5 @@ -4575,19 +4472,19 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/types@1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17))': + '@rsdoctor/types@1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17))': dependencies: '@types/connect': 3.4.38 '@types/estree': 1.0.5 '@types/tapable': 2.2.7 source-map: 0.7.4 optionalDependencies: - '@rspack/core': 1.3.12(@swc/helpers@0.5.17) + '@rspack/core': 1.4.1(@swc/helpers@0.5.17) - '@rsdoctor/utils@1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17))': + '@rsdoctor/utils@1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17))': dependencies: '@babel/code-frame': 7.26.2 - '@rsdoctor/types': 1.1.4(@rspack/core@1.3.12(@swc/helpers@0.5.17)) + '@rsdoctor/types': 1.1.5(@rspack/core@1.4.1(@swc/helpers@0.5.17)) '@types/estree': 1.0.5 acorn: 8.14.1 acorn-import-attributes: 1.9.5(acorn@8.14.1) @@ -4608,165 +4505,64 @@ snapshots: - supports-color - webpack - '@rslib/core@0.10.2(@microsoft/api-extractor@7.52.8(@types/node@22.13.8))(typescript@5.8.3)': + '@rslib/core@0.10.4(@microsoft/api-extractor@7.52.8(@types/node@22.13.8))(typescript@5.8.3)': dependencies: - '@rsbuild/core': 1.4.0-beta.4 - rsbuild-plugin-dts: 0.10.2(@microsoft/api-extractor@7.52.8(@types/node@22.13.8))(@rsbuild/core@1.4.0-beta.4)(typescript@5.8.3) + '@rsbuild/core': 1.4.2 + rsbuild-plugin-dts: 0.10.4(@microsoft/api-extractor@7.52.8(@types/node@22.13.8))(@rsbuild/core@1.4.2)(typescript@5.8.3) tinyglobby: 0.2.14 optionalDependencies: '@microsoft/api-extractor': 7.52.8(@types/node@22.13.8) typescript: 5.8.3 - '@rspack/binding-darwin-arm64@1.3.12': - optional: true - - '@rspack/binding-darwin-arm64@1.4.0-beta.1': - optional: true - - '@rspack/binding-darwin-arm64@1.4.0-rc.0': - optional: true - - '@rspack/binding-darwin-x64@1.3.12': - optional: true - - '@rspack/binding-darwin-x64@1.4.0-beta.1': - optional: true - - '@rspack/binding-darwin-x64@1.4.0-rc.0': - optional: true - - '@rspack/binding-linux-arm64-gnu@1.3.12': - optional: true - - '@rspack/binding-linux-arm64-gnu@1.4.0-beta.1': - optional: true - - '@rspack/binding-linux-arm64-gnu@1.4.0-rc.0': - optional: true - - '@rspack/binding-linux-arm64-musl@1.3.12': - optional: true - - '@rspack/binding-linux-arm64-musl@1.4.0-beta.1': - optional: true - - '@rspack/binding-linux-arm64-musl@1.4.0-rc.0': + '@rspack/binding-darwin-arm64@1.4.1': optional: true - '@rspack/binding-linux-x64-gnu@1.3.12': + '@rspack/binding-darwin-x64@1.4.1': optional: true - '@rspack/binding-linux-x64-gnu@1.4.0-beta.1': + '@rspack/binding-linux-arm64-gnu@1.4.1': optional: true - '@rspack/binding-linux-x64-gnu@1.4.0-rc.0': + '@rspack/binding-linux-arm64-musl@1.4.1': optional: true - '@rspack/binding-linux-x64-musl@1.3.12': + '@rspack/binding-linux-x64-gnu@1.4.1': optional: true - '@rspack/binding-linux-x64-musl@1.4.0-beta.1': + '@rspack/binding-linux-x64-musl@1.4.1': optional: true - '@rspack/binding-linux-x64-musl@1.4.0-rc.0': - optional: true - - '@rspack/binding-wasm32-wasi@1.4.0-beta.1': + '@rspack/binding-wasm32-wasi@1.4.1': dependencies: '@napi-rs/wasm-runtime': 0.2.11 optional: true - '@rspack/binding-wasm32-wasi@1.4.0-rc.0': - dependencies: - '@napi-rs/wasm-runtime': 0.2.11 + '@rspack/binding-win32-arm64-msvc@1.4.1': optional: true - '@rspack/binding-win32-arm64-msvc@1.3.12': + '@rspack/binding-win32-ia32-msvc@1.4.1': optional: true - '@rspack/binding-win32-arm64-msvc@1.4.0-beta.1': + '@rspack/binding-win32-x64-msvc@1.4.1': optional: true - '@rspack/binding-win32-arm64-msvc@1.4.0-rc.0': - optional: true - - '@rspack/binding-win32-ia32-msvc@1.3.12': - optional: true - - '@rspack/binding-win32-ia32-msvc@1.4.0-beta.1': - optional: true - - '@rspack/binding-win32-ia32-msvc@1.4.0-rc.0': - optional: true - - '@rspack/binding-win32-x64-msvc@1.3.12': - optional: true - - '@rspack/binding-win32-x64-msvc@1.4.0-beta.1': - optional: true - - '@rspack/binding-win32-x64-msvc@1.4.0-rc.0': - optional: true - - '@rspack/binding@1.3.12': - optionalDependencies: - '@rspack/binding-darwin-arm64': 1.3.12 - '@rspack/binding-darwin-x64': 1.3.12 - '@rspack/binding-linux-arm64-gnu': 1.3.12 - '@rspack/binding-linux-arm64-musl': 1.3.12 - '@rspack/binding-linux-x64-gnu': 1.3.12 - '@rspack/binding-linux-x64-musl': 1.3.12 - '@rspack/binding-win32-arm64-msvc': 1.3.12 - '@rspack/binding-win32-ia32-msvc': 1.3.12 - '@rspack/binding-win32-x64-msvc': 1.3.12 - - '@rspack/binding@1.4.0-beta.1': - optionalDependencies: - '@rspack/binding-darwin-arm64': 1.4.0-beta.1 - '@rspack/binding-darwin-x64': 1.4.0-beta.1 - '@rspack/binding-linux-arm64-gnu': 1.4.0-beta.1 - '@rspack/binding-linux-arm64-musl': 1.4.0-beta.1 - '@rspack/binding-linux-x64-gnu': 1.4.0-beta.1 - '@rspack/binding-linux-x64-musl': 1.4.0-beta.1 - '@rspack/binding-wasm32-wasi': 1.4.0-beta.1 - '@rspack/binding-win32-arm64-msvc': 1.4.0-beta.1 - '@rspack/binding-win32-ia32-msvc': 1.4.0-beta.1 - '@rspack/binding-win32-x64-msvc': 1.4.0-beta.1 - - '@rspack/binding@1.4.0-rc.0': + '@rspack/binding@1.4.1': optionalDependencies: - '@rspack/binding-darwin-arm64': 1.4.0-rc.0 - '@rspack/binding-darwin-x64': 1.4.0-rc.0 - '@rspack/binding-linux-arm64-gnu': 1.4.0-rc.0 - '@rspack/binding-linux-arm64-musl': 1.4.0-rc.0 - '@rspack/binding-linux-x64-gnu': 1.4.0-rc.0 - '@rspack/binding-linux-x64-musl': 1.4.0-rc.0 - '@rspack/binding-wasm32-wasi': 1.4.0-rc.0 - '@rspack/binding-win32-arm64-msvc': 1.4.0-rc.0 - '@rspack/binding-win32-ia32-msvc': 1.4.0-rc.0 - '@rspack/binding-win32-x64-msvc': 1.4.0-rc.0 - - '@rspack/core@1.3.12(@swc/helpers@0.5.17)': - dependencies: - '@module-federation/runtime-tools': 0.14.0 - '@rspack/binding': 1.3.12 - '@rspack/lite-tapable': 1.0.1 - caniuse-lite: 1.0.30001718 - optionalDependencies: - '@swc/helpers': 0.5.17 - - '@rspack/core@1.4.0-beta.1(@swc/helpers@0.5.17)': + '@rspack/binding-darwin-arm64': 1.4.1 + '@rspack/binding-darwin-x64': 1.4.1 + '@rspack/binding-linux-arm64-gnu': 1.4.1 + '@rspack/binding-linux-arm64-musl': 1.4.1 + '@rspack/binding-linux-x64-gnu': 1.4.1 + '@rspack/binding-linux-x64-musl': 1.4.1 + '@rspack/binding-wasm32-wasi': 1.4.1 + '@rspack/binding-win32-arm64-msvc': 1.4.1 + '@rspack/binding-win32-ia32-msvc': 1.4.1 + '@rspack/binding-win32-x64-msvc': 1.4.1 + + '@rspack/core@1.4.1(@swc/helpers@0.5.17)': dependencies: '@module-federation/runtime-tools': 0.15.0 - '@rspack/binding': 1.4.0-beta.1 - '@rspack/lite-tapable': 1.0.1 - optionalDependencies: - '@swc/helpers': 0.5.17 - - '@rspack/core@1.4.0-rc.0(@swc/helpers@0.5.17)': - dependencies: - '@module-federation/runtime-tools': 0.15.0 - '@rspack/binding': 1.4.0-rc.0 + '@rspack/binding': 1.4.1 '@rspack/lite-tapable': 1.0.1 optionalDependencies: '@swc/helpers': 0.5.17 @@ -4779,21 +4575,19 @@ snapshots: html-entities: 2.6.0 react-refresh: 0.17.0 - '@rspress/core@2.0.0-beta.16(@types/react@19.1.8)(acorn@8.14.1)': + '@rspress/core@2.0.0-beta.18(@types/react@19.1.8)(acorn@8.14.1)': dependencies: '@mdx-js/loader': 3.1.0(acorn@8.14.1) '@mdx-js/mdx': 3.1.0(acorn@8.14.1) '@mdx-js/react': 3.1.0(@types/react@19.1.8)(react@19.1.0) - '@rsbuild/core': 1.3.22 - '@rsbuild/plugin-react': 1.3.2(@rsbuild/core@1.3.22) + '@rsbuild/core': 1.4.2 + '@rsbuild/plugin-react': 1.3.2(@rsbuild/core@1.4.2) '@rspress/mdx-rs': 0.6.6 - '@rspress/plugin-auto-nav-sidebar': 2.0.0-beta.16 - '@rspress/plugin-container-syntax': 2.0.0-beta.16 - '@rspress/plugin-last-updated': 2.0.0-beta.16 - '@rspress/plugin-medium-zoom': 2.0.0-beta.16(@rspress/runtime@2.0.0-beta.16) - '@rspress/runtime': 2.0.0-beta.16 - '@rspress/shared': 2.0.0-beta.16 - '@rspress/theme-default': 2.0.0-beta.16 + '@rspress/plugin-last-updated': 2.0.0-beta.18 + '@rspress/plugin-medium-zoom': 2.0.0-beta.18(@rspress/runtime@2.0.0-beta.18) + '@rspress/runtime': 2.0.0-beta.18 + '@rspress/shared': 2.0.0-beta.18 + '@rspress/theme-default': 2.0.0-beta.18 '@shikijs/rehype': 3.4.2 '@types/unist': 3.0.3 '@unhead/react': 2.0.10(react@19.1.0) @@ -4861,22 +4655,14 @@ snapshots: '@rspress/mdx-rs-win32-arm64-msvc': 0.6.6 '@rspress/mdx-rs-win32-x64-msvc': 0.6.6 - '@rspress/plugin-auto-nav-sidebar@2.0.0-beta.16': - dependencies: - '@rspress/shared': 2.0.0-beta.16 - - '@rspress/plugin-container-syntax@2.0.0-beta.16': - dependencies: - '@rspress/shared': 2.0.0-beta.16 - - '@rspress/plugin-last-updated@2.0.0-beta.16': + '@rspress/plugin-last-updated@2.0.0-beta.18': dependencies: - '@rspress/shared': 2.0.0-beta.16 + '@rspress/shared': 2.0.0-beta.18 - '@rspress/plugin-llms@2.0.0-beta.16(@rspress/core@2.0.0-beta.16(@types/react@19.1.8)(acorn@8.14.1))': + '@rspress/plugin-llms@2.0.0-beta.18(@rspress/core@2.0.0-beta.18(@types/react@19.1.8)(acorn@8.14.1))': dependencies: - '@rspress/core': 2.0.0-beta.16(@types/react@19.1.8)(acorn@8.14.1) - '@rspress/shared': 2.0.0-beta.16 + '@rspress/core': 2.0.0-beta.18(@types/react@19.1.8)(acorn@8.14.1) + '@rspress/shared': 2.0.0-beta.18 remark-mdx: 3.1.0 remark-parse: 11.0.0 remark-stringify: 11.0.0 @@ -4886,32 +4672,32 @@ snapshots: transitivePeerDependencies: - supports-color - '@rspress/plugin-medium-zoom@2.0.0-beta.16(@rspress/runtime@2.0.0-beta.16)': + '@rspress/plugin-medium-zoom@2.0.0-beta.18(@rspress/runtime@2.0.0-beta.18)': dependencies: - '@rspress/runtime': 2.0.0-beta.16 + '@rspress/runtime': 2.0.0-beta.18 medium-zoom: 1.1.0 - '@rspress/runtime@2.0.0-beta.16': + '@rspress/runtime@2.0.0-beta.18': dependencies: - '@rspress/shared': 2.0.0-beta.16 + '@rspress/shared': 2.0.0-beta.18 '@unhead/react': 2.0.10(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) react-router-dom: 6.30.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@rspress/shared@2.0.0-beta.16': + '@rspress/shared@2.0.0-beta.18': dependencies: - '@rsbuild/core': 1.3.22 + '@rsbuild/core': 1.4.2 '@shikijs/rehype': 3.4.2 gray-matter: 4.0.3 lodash-es: 4.17.21 unified: 11.0.5 - '@rspress/theme-default@2.0.0-beta.16': + '@rspress/theme-default@2.0.0-beta.18': dependencies: '@mdx-js/react': 2.3.0(react@19.1.0) - '@rspress/runtime': 2.0.0-beta.16 - '@rspress/shared': 2.0.0-beta.16 + '@rspress/runtime': 2.0.0-beta.18 + '@rspress/shared': 2.0.0-beta.18 '@unhead/react': 2.0.10(react@19.1.0) body-scroll-lock: 4.0.0-beta.0 copy-to-clipboard: 3.3.3 @@ -5109,6 +4895,27 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest-image-snapshot@6.4.0': + dependencies: + '@types/jest': 30.0.0 + '@types/pixelmatch': 5.2.6 + ssim.js: 3.5.0 + + '@types/jest@30.0.0': + dependencies: + expect: 30.0.3 + pretty-format: 30.0.2 + '@types/js-yaml@4.0.9': {} '@types/jsdom@21.1.7': @@ -5135,6 +4942,10 @@ snapshots: dependencies: undici-types: 6.20.0 + '@types/pixelmatch@5.2.6': + dependencies: + '@types/node': 22.13.8 + '@types/react-dom@19.1.6(@types/react@19.1.8)': dependencies: '@types/react': 19.1.8 @@ -5149,6 +4960,8 @@ snapshots: dependencies: source-map: 0.6.1 + '@types/stack-utils@2.0.3': {} + '@types/tapable@2.2.7': dependencies: tapable: 2.2.2 @@ -5159,6 +4972,12 @@ snapshots: '@types/unist@3.0.3': {} + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + '@ungap/structured-clone@1.3.0': {} '@unhead/react@2.0.10(react@19.1.0)': @@ -5458,6 +5277,8 @@ snapshots: ci-info@3.9.0: {} + ci-info@4.2.0: {} + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -5511,8 +5332,6 @@ snapshots: dependencies: toggle-selection: 1.0.6 - core-js@3.42.0: {} - core-js@3.43.0: {} cors@2.8.5: @@ -5751,6 +5570,8 @@ snapshots: escape-string-regexp@1.0.5: {} + escape-string-regexp@2.0.0: {} + escape-string-regexp@4.0.0: {} escape-string-regexp@5.0.0: {} @@ -5790,6 +5611,15 @@ snapshots: dependencies: '@types/estree': 1.0.5 + expect@30.0.3: + dependencies: + '@jest/expect-utils': 30.0.3 + '@jest/get-type': 30.0.1 + jest-matcher-utils: 30.0.3 + jest-message-util: 30.0.2 + jest-mock: 30.0.2 + jest-util: 30.0.2 + extend-shallow@2.0.1: dependencies: is-extendable: 0.1.1 @@ -6278,7 +6108,7 @@ snapshots: jest-get-type: 29.6.3 pretty-format: 29.7.0 - jest-diff@30.0.2: + jest-diff@30.0.3: dependencies: '@jest/diff-sequences': 30.0.1 '@jest/get-type': 30.0.1 @@ -6297,6 +6127,42 @@ snapshots: pngjs: 3.4.0 ssim.js: 3.5.0 + jest-matcher-utils@30.0.3: + dependencies: + '@jest/get-type': 30.0.1 + chalk: 4.1.2 + jest-diff: 30.0.3 + pretty-format: 30.0.2 + + jest-message-util@30.0.2: + dependencies: + '@babel/code-frame': 7.27.1 + '@jest/types': 30.0.1 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 30.0.2 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@30.0.2: + dependencies: + '@jest/types': 30.0.1 + '@types/node': 22.13.8 + jest-util: 30.0.2 + + jest-regex-util@30.0.1: {} + + jest-util@30.0.2: + dependencies: + '@jest/types': 30.0.1 + '@types/node': 22.13.8 + chalk: 4.1.2 + ci-info: 4.2.0 + graceful-fs: 4.2.11 + picomatch: 4.0.2 + jiti@2.4.2: {} jju@1.4.0: {} @@ -7104,16 +6970,16 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - prettier-plugin-packagejson@2.5.15(prettier@3.6.0): + prettier-plugin-packagejson@2.5.17(prettier@3.6.2): dependencies: - sort-package-json: 3.2.1 + sort-package-json: 3.3.1 synckit: 0.11.8 optionalDependencies: - prettier: 3.6.0 + prettier: 3.6.2 prettier@2.8.8: {} - prettier@3.6.0: {} + prettier@3.6.2: {} pretty-format@27.5.1: dependencies: @@ -7349,10 +7215,10 @@ snapshots: rrweb-cssom@0.8.0: {} - rsbuild-plugin-dts@0.10.2(@microsoft/api-extractor@7.52.8(@types/node@22.13.8))(@rsbuild/core@1.4.0-beta.4)(typescript@5.8.3): + rsbuild-plugin-dts@0.10.4(@microsoft/api-extractor@7.52.8(@types/node@22.13.8))(@rsbuild/core@1.4.2)(typescript@5.8.3): dependencies: '@ast-grep/napi': 0.37.0 - '@rsbuild/core': 1.4.0-beta.4 + '@rsbuild/core': 1.4.2 magic-string: 0.30.17 picocolors: 1.1.1 tinyglobby: 0.2.14 @@ -7361,13 +7227,13 @@ snapshots: '@microsoft/api-extractor': 7.52.8(@types/node@22.13.8) typescript: 5.8.3 - rsbuild-plugin-google-analytics@1.0.3(@rsbuild/core@1.4.0-rc.0): + rsbuild-plugin-google-analytics@1.0.3(@rsbuild/core@1.4.2): optionalDependencies: - '@rsbuild/core': 1.4.0-rc.0 + '@rsbuild/core': 1.4.2 - rsbuild-plugin-open-graph@1.0.2(@rsbuild/core@1.4.0-rc.0): + rsbuild-plugin-open-graph@1.0.2(@rsbuild/core@1.4.2): optionalDependencies: - '@rsbuild/core': 1.4.0-rc.0 + '@rsbuild/core': 1.4.2 rslog@1.2.8: {} @@ -7379,11 +7245,11 @@ snapshots: rspress-plugin-sitemap@1.2.0: {} - rspress@2.0.0-beta.16(@types/react@19.1.8)(acorn@8.14.1): + rspress@2.0.0-beta.18(@types/react@19.1.8)(acorn@8.14.1): dependencies: - '@rsbuild/core': 1.3.22 - '@rspress/core': 2.0.0-beta.16(@types/react@19.1.8)(acorn@8.14.1) - '@rspress/shared': 2.0.0-beta.16 + '@rsbuild/core': 1.4.2 + '@rspress/core': 2.0.0-beta.18(@types/react@19.1.8)(acorn@8.14.1) + '@rspress/shared': 2.0.0-beta.18 cac: 6.7.14 chokidar: 3.6.0 picocolors: 1.1.1 @@ -7627,7 +7493,7 @@ snapshots: sort-object-keys@1.1.3: {} - sort-package-json@3.2.1: + sort-package-json@3.3.1: dependencies: detect-indent: 7.0.1 detect-newline: 4.0.1 @@ -7659,6 +7525,10 @@ snapshots: ssim.js@3.5.0: {} + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + stackframe@1.3.4: {} stacktrace-parser@0.1.11: diff --git a/tests/build/fixtures/plugin/rstest.config.ts b/tests/build/fixtures/plugin/rstest.config.ts index 05951032..f88e4fdf 100644 --- a/tests/build/fixtures/plugin/rstest.config.ts +++ b/tests/build/fixtures/plugin/rstest.config.ts @@ -1,4 +1,5 @@ -import path from 'node:path'; +// TODO: @rsbuild/core is a phantom dependency, remove it when we can reexport Rsbuild types from @rstest/core +import type { RsbuildPlugin } from '@rsbuild/core'; import { defineConfig } from '@rstest/core'; export default defineConfig({ @@ -11,6 +12,6 @@ export default defineConfig({ return code.replace('count = 1', 'count = 2'); }); }, - }, + } as RsbuildPlugin, ], }); diff --git a/tests/build/index.test.ts b/tests/build/index.test.ts index e6c54a63..a1638603 100644 --- a/tests/build/index.test.ts +++ b/tests/build/index.test.ts @@ -1,6 +1,6 @@ import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { describe, expect, it } from '@rstest/core'; +import { describe, it } from '@rstest/core'; import { runRstestCli } from '../scripts/'; const __filename = fileURLToPath(import.meta.url); @@ -14,7 +14,7 @@ describe('test build config', () => { { name: 'tools/rspack' }, { name: 'decorators' }, ])('$name config should work correctly', async ({ name }) => { - const { cli, expectExecSuccess } = await runRstestCli({ + const { expectExecSuccess } = await runRstestCli({ command: 'rstest', args: [ 'run', diff --git a/tests/describe/for.test.ts b/tests/describe/for.test.ts index 3b63cf1e..c1d5d86c 100644 --- a/tests/describe/for.test.ts +++ b/tests/describe/for.test.ts @@ -23,7 +23,7 @@ describe.for([ [3, 1, 4], ])('add two numbers correctly', ([a, b, expected]) => { it(`should return ${expected}`, () => { - expect(a + b).toBe(expected); + expect(a! + b!).toBe(expected); logs.push('executed'); }); }); diff --git a/tests/describe/only.test.ts b/tests/describe/only.test.ts index c3755c8f..7b63a88e 100644 --- a/tests/describe/only.test.ts +++ b/tests/describe/only.test.ts @@ -23,7 +23,6 @@ describe('level A', () => { expect(1 + 1).toBe(2); }); - // biome-ignore lint/suspicious/noFocusedTests: describe.only('level B', () => { it('it in level B-A', () => { logs.push('[test] in level B-A'); @@ -56,7 +55,6 @@ describe('level A', () => { }); }); -// biome-ignore lint/suspicious/noFocusedTests: describe.only('level E', () => { it('it in level E-A', () => { logs.push('[test] in level E-A'); diff --git a/tests/externals/fixtures/interop.test.ts b/tests/externals/fixtures/interopDefault.test.ts similarity index 71% rename from tests/externals/fixtures/interop.test.ts rename to tests/externals/fixtures/interopDefault.test.ts index ffa1610c..13acd9cc 100644 --- a/tests/externals/fixtures/interop.test.ts +++ b/tests/externals/fixtures/interopDefault.test.ts @@ -1,5 +1,5 @@ import { expect, it } from '@rstest/core'; -import { test } from './test-pkg/importInterop'; +import { test } from './test-pkg/interopDefault'; it('should interop correctly', () => { expect(test()).toBe('hello world'); diff --git a/tests/externals/fixtures/interopLodash.test.ts b/tests/externals/fixtures/interopLodash.test.ts new file mode 100644 index 00000000..843663c2 --- /dev/null +++ b/tests/externals/fixtures/interopLodash.test.ts @@ -0,0 +1,6 @@ +import { expect, it } from '@rstest/core'; +import { lodash, VERSION } from './test-pkg/importLodash'; + +it('should load lodash correctly', () => { + expect(lodash.VERSION).toBe(VERSION); +}); diff --git a/tests/externals/fixtures/test-lodash/index.js b/tests/externals/fixtures/test-lodash/index.js new file mode 100644 index 00000000..676e0d66 --- /dev/null +++ b/tests/externals/fixtures/test-lodash/index.js @@ -0,0 +1,59 @@ +// Reference lodash/lodash.js +(() => { + /** Used as the semantic version number. */ + const VERSION = '4.17.21'; + + /** Detect free variable `global` from Node.js. */ + const freeGlobal = + typeof global === 'object' && global && global.Object === Object && global; + + /** Detect free variable `self`. */ + const freeSelf = + typeof self === 'object' && self && self.Object === Object && self; + + /** Used as a reference to the global object. */ + const root = freeGlobal || freeSelf || Function('return this')(); + + /** Detect free variable `exports`. */ + const freeExports = + typeof exports === 'object' && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + const freeModule = + freeExports && + typeof module === 'object' && + module && + !module.nodeType && + module; + + function lodash(_value) {} + + lodash.VERSION = VERSION; + + // Some AMD build optimizers, like r.js, check for condition patterns like: + if ( + typeof define === 'function' && + typeof define.amd === 'object' && + define.amd + ) { + // Expose Lodash on the global object to prevent errors when Lodash is + // loaded by a script tag in the presence of an AMD loader. + // See http://requirejs.org/docs/errors.html#mismatch for more details. + // Use `_.noConflict` to remove Lodash from the global object. + root._ = lodash; + + // Define as an anonymous module so, through path mapping, it can be + // referenced as the "underscore" module. + define(() => lodash); + } + // Check for `exports` after `define` in case a build optimizer adds it. + else if (freeModule) { + // Export for Node.js. + freeModule.exports = lodash; + // Export for CommonJS support. + freeExports._ = lodash; + } else { + // Export to the global object. + root._ = lodash; + } +}).call(this); diff --git a/tests/externals/fixtures/test-lodash/package.json b/tests/externals/fixtures/test-lodash/package.json new file mode 100644 index 00000000..0e3be9e9 --- /dev/null +++ b/tests/externals/fixtures/test-lodash/package.json @@ -0,0 +1,6 @@ +{ + "private": true, + "name": "@rstest/tests-lodash", + "main": "index.js", + "version": "1.0.0" +} diff --git a/tests/externals/fixtures/test-pkg/importInterop.ts b/tests/externals/fixtures/test-pkg/importInterop.ts deleted file mode 100644 index b5fcd940..00000000 --- a/tests/externals/fixtures/test-pkg/importInterop.ts +++ /dev/null @@ -1,3 +0,0 @@ -import test from 'test-interop'; - -export { test }; diff --git a/tests/externals/fixtures/test-pkg/importLodash.ts b/tests/externals/fixtures/test-pkg/importLodash.ts new file mode 100644 index 00000000..a77fffa0 --- /dev/null +++ b/tests/externals/fixtures/test-pkg/importLodash.ts @@ -0,0 +1,4 @@ +// @ts-expect-error: the package is alongside, only for testing purposes +import lodash, { VERSION } from 'test-lodash'; + +export { lodash, VERSION }; diff --git a/tests/externals/fixtures/test-pkg/importModule.ts b/tests/externals/fixtures/test-pkg/importModule.ts index 1308837b..6666a1f3 100644 --- a/tests/externals/fixtures/test-pkg/importModule.ts +++ b/tests/externals/fixtures/test-pkg/importModule.ts @@ -1,3 +1,4 @@ +// @ts-expect-error: the package is alongside, only for testing purposes import { a } from 'test-module-field'; export { a }; diff --git a/tests/externals/fixtures/test-pkg/interopDefault.ts b/tests/externals/fixtures/test-pkg/interopDefault.ts new file mode 100644 index 00000000..d3a36a34 --- /dev/null +++ b/tests/externals/fixtures/test-pkg/interopDefault.ts @@ -0,0 +1,4 @@ +// @ts-expect-error: the package is alongside, only for testing purposes +import test from 'test-interop'; + +export { test }; diff --git a/tests/externals/index.test.ts b/tests/externals/index.test.ts index a6ff597e..b36ac19c 100644 --- a/tests/externals/index.test.ts +++ b/tests/externals/index.test.ts @@ -1,6 +1,6 @@ import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { describe, expect, it } from '@rstest/core'; +import { describe, it } from '@rstest/core'; import { runRstestCli } from '../scripts/'; const __filename = fileURLToPath(import.meta.url); diff --git a/tests/externals/interop.test.ts b/tests/externals/interop.test.ts index 82ddf948..7a2260b2 100644 --- a/tests/externals/interop.test.ts +++ b/tests/externals/interop.test.ts @@ -1,8 +1,7 @@ import { dirname, join } from 'node:path'; -import fse from 'fs-extra'; - import { fileURLToPath } from 'node:url'; -import { beforeAll, describe, expect, it } from '@rstest/core'; +import { beforeAll, describe, it } from '@rstest/core'; +import fse from 'fs-extra'; import { runRstestCli } from '../scripts/'; const __filename = fileURLToPath(import.meta.url); @@ -14,12 +13,16 @@ describe('test interop', () => { join(__dirname, './fixtures/test-interop'), join(__dirname, './fixtures/test-pkg/node_modules/test-interop'), ); + fse.copySync( + join(__dirname, './fixtures/test-lodash'), + join(__dirname, './fixtures/test-pkg/node_modules/test-lodash'), + ); }); it('should interopDefault correctly in jsdom test environment', async () => { const { expectExecSuccess } = await runRstestCli({ command: 'rstest', - args: ['run', './fixtures/interop', '--testEnvironment=jsdom'], + args: ['run', './fixtures/interopDefault', '--testEnvironment=jsdom'], options: { nodeOptions: { cwd: __dirname, @@ -33,7 +36,21 @@ describe('test interop', () => { it('should interopDefault correctly in node test environment', async () => { const { expectExecSuccess } = await runRstestCli({ command: 'rstest', - args: ['run', './fixtures/interop', '--testEnvironment=node'], + args: ['run', './fixtures/interopDefault', '--testEnvironment=node'], + options: { + nodeOptions: { + cwd: __dirname, + }, + }, + }); + + await expectExecSuccess(); + }); + + it('should interop invalid named exports correctly', async () => { + const { expectExecSuccess } = await runRstestCli({ + command: 'rstest', + args: ['run', './fixtures/interopLodash', '--testEnvironment=node'], options: { nodeOptions: { cwd: __dirname, diff --git a/tests/externals/moduleField.test.ts b/tests/externals/moduleField.test.ts index b71d4cae..ebe03185 100644 --- a/tests/externals/moduleField.test.ts +++ b/tests/externals/moduleField.test.ts @@ -1,8 +1,7 @@ import { dirname, join } from 'node:path'; -import fse from 'fs-extra'; - import { fileURLToPath } from 'node:url'; -import { beforeAll, describe, expect, it } from '@rstest/core'; +import { beforeAll, describe, it } from '@rstest/core'; +import fse from 'fs-extra'; import { runRstestCli } from '../scripts/'; const __filename = fileURLToPath(import.meta.url); diff --git a/tests/filter/default.test.ts b/tests/filter/default.test.ts index ef7df21f..c599192a 100644 --- a/tests/filter/default.test.ts +++ b/tests/filter/default.test.ts @@ -1,6 +1,6 @@ import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { describe, expect, it } from '@rstest/core'; +import { expect, it } from '@rstest/core'; import { runRstestCli } from '../scripts/'; const __filename = fileURLToPath(import.meta.url); diff --git a/tests/filter/fixtures/testNamePattern.test.ts b/tests/filter/fixtures/testNamePattern.test.ts index 7eda79a6..fa24c4b8 100644 --- a/tests/filter/fixtures/testNamePattern.test.ts +++ b/tests/filter/fixtures/testNamePattern.test.ts @@ -1,6 +1,5 @@ import { describe, expect, it } from '@rstest/core'; -// biome-ignore lint/suspicious/noFocusedTests: describe.only('level-A', () => { describe('level-B', () => { it('it in level-B-A', () => { diff --git a/tests/globals/index.test.ts b/tests/globals/index.test.ts index 42757d33..9ce9b8c4 100644 --- a/tests/globals/index.test.ts +++ b/tests/globals/index.test.ts @@ -1,6 +1,6 @@ import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { describe, expect, it } from '@rstest/core'; +import { describe, it } from '@rstest/core'; import { runRstestCli } from '../scripts/'; const __filename = fileURLToPath(import.meta.url); diff --git a/tests/isolate/test/index1.test.ts b/tests/isolate/test/index1.test.ts index 08f47390..647743b2 100644 --- a/tests/isolate/test/index1.test.ts +++ b/tests/isolate/test/index1.test.ts @@ -2,6 +2,11 @@ import { describe, expect, it } from '@rstest/core'; import { sleep } from '../../scripts/utils'; import { getCount, increment } from '../src/index'; +declare global { + var index: string | undefined; + var index1: string | undefined; +} + process.env.index1 = '1'; globalThis.index1 = '1'; diff --git a/tests/jsdom/fixtures/package.json b/tests/jsdom/fixtures/package.json index 79434378..88cef007 100644 --- a/tests/jsdom/fixtures/package.json +++ b/tests/jsdom/fixtures/package.json @@ -11,7 +11,7 @@ "react-dom": "^19.1.0" }, "devDependencies": { - "@rsbuild/core": "1.4.0-rc.0", + "@rsbuild/core": "1.4.2", "@rsbuild/plugin-react": "^1.3.2", "@testing-library/jest-dom": "^6.6.3", "@testing-library/dom": "^10.4.0", diff --git a/tests/jsdom/fixtures/rstest.config.ts b/tests/jsdom/fixtures/rstest.config.ts index 7addc948..0237e2ae 100644 --- a/tests/jsdom/fixtures/rstest.config.ts +++ b/tests/jsdom/fixtures/rstest.config.ts @@ -1,4 +1,4 @@ -import { type RstestConfig, defineConfig } from '@rstest/core'; +import { defineConfig, type RstestConfig } from '@rstest/core'; import rsbuildConfig from './rsbuild.config'; export default defineConfig({ diff --git a/tests/jsdom/fixtures/rstest.externals.config.ts b/tests/jsdom/fixtures/rstest.externals.config.ts new file mode 100644 index 00000000..7c861613 --- /dev/null +++ b/tests/jsdom/fixtures/rstest.externals.config.ts @@ -0,0 +1,11 @@ +import { defineConfig, type RstestConfig } from '@rstest/core'; +import rsbuildConfig from './rsbuild.config'; + +export default defineConfig({ + ...(rsbuildConfig as RstestConfig), + testEnvironment: 'jsdom', + setupFiles: ['./test/setup.ts'], + output: { + externals: [/react/], + }, +}); diff --git a/tests/jsdom/handledError.test.ts b/tests/jsdom/handledError.test.ts index 496b945b..a939c0ca 100644 --- a/tests/jsdom/handledError.test.ts +++ b/tests/jsdom/handledError.test.ts @@ -1,6 +1,6 @@ import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { describe, expect, it } from '@rstest/core'; +import { it } from '@rstest/core'; import { runRstestCli } from '../scripts'; const __filename = fileURLToPath(import.meta.url); diff --git a/tests/jsdom/index.test.ts b/tests/jsdom/index.test.ts index 6b0b3488..9e11c26b 100644 --- a/tests/jsdom/index.test.ts +++ b/tests/jsdom/index.test.ts @@ -1,6 +1,6 @@ import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { describe, expect, it } from '@rstest/core'; +import { it } from '@rstest/core'; import { runRstestCli } from '../scripts'; const __filename = fileURLToPath(import.meta.url); @@ -20,6 +20,20 @@ it('should run jsdom test correctly', async () => { await expectExecSuccess(); }); +it('should run jsdom test correctly with custom externals', async () => { + const { expectExecSuccess } = await runRstestCli({ + command: 'rstest', + args: ['run', 'test/App', '--config', 'rstest.externals.config.ts'], + options: { + nodeOptions: { + cwd: join(__dirname, 'fixtures'), + }, + }, + }); + + await expectExecSuccess(); +}); + it('should run jsdom test correctly with jest-dom', async () => { const { expectExecSuccess } = await runRstestCli({ command: 'rstest', diff --git a/tests/lifecycle/fixtures/error/afterAll.test.ts b/tests/lifecycle/fixtures/error/afterAll.test.ts index 5e8e81c3..967ea3a7 100644 --- a/tests/lifecycle/fixtures/error/afterAll.test.ts +++ b/tests/lifecycle/fixtures/error/afterAll.test.ts @@ -10,12 +10,10 @@ describe('test afterAll error', () => { console.log('[afterAll - 2] should not run'); }); - // biome-ignore lint/suspicious/noDuplicateTestHooks: test afterAll(() => { throw new Error('afterAll error'); }); - // biome-ignore lint/suspicious/noDuplicateTestHooks: test afterAll(() => { console.log('[afterAll - 0] should run'); }); diff --git a/tests/lifecycle/fixtures/error/afterEach.test.ts b/tests/lifecycle/fixtures/error/afterEach.test.ts index 1ad20d24..07fd1685 100644 --- a/tests/lifecycle/fixtures/error/afterEach.test.ts +++ b/tests/lifecycle/fixtures/error/afterEach.test.ts @@ -14,12 +14,10 @@ describe('test afterEach error', () => { console.log('[afterEach - 2] should not run'); }); - // biome-ignore lint/suspicious/noDuplicateTestHooks: test afterEach(() => { throw new Error('afterEach error'); }); - // biome-ignore lint/suspicious/noDuplicateTestHooks: test afterEach(() => { console.log('[afterEach - 0] should run'); }); diff --git a/tests/lifecycle/fixtures/error/beforeAll.test.ts b/tests/lifecycle/fixtures/error/beforeAll.test.ts index bdd99534..a4654a06 100644 --- a/tests/lifecycle/fixtures/error/beforeAll.test.ts +++ b/tests/lifecycle/fixtures/error/beforeAll.test.ts @@ -13,12 +13,10 @@ describe('test beforeAll error', () => { console.log('[beforeAll - 0] should run'); }); - // biome-ignore lint/suspicious/noDuplicateTestHooks: test beforeAll(() => { throw new Error('beforeAll error'); }); - // biome-ignore lint/suspicious/noDuplicateTestHooks: test beforeAll(() => { console.log('[beforeAll - 2] should not run'); }); diff --git a/tests/lifecycle/fixtures/error/beforeEach.test.ts b/tests/lifecycle/fixtures/error/beforeEach.test.ts index 170f4b20..2a951809 100644 --- a/tests/lifecycle/fixtures/error/beforeEach.test.ts +++ b/tests/lifecycle/fixtures/error/beforeEach.test.ts @@ -22,12 +22,10 @@ describe('test beforeEach error', () => { console.log('[beforeEach - 0] should run'); }); - // biome-ignore lint/suspicious/noDuplicateTestHooks: test beforeEach(() => { throw new Error('beforeEach error'); }); - // biome-ignore lint/suspicious/noDuplicateTestHooks: test beforeEach(() => { console.log('[beforeEach - 2] should not run'); }); diff --git a/tests/list/index.test.ts b/tests/list/index.test.ts index 3d1d19e8..02c21af8 100644 --- a/tests/list/index.test.ts +++ b/tests/list/index.test.ts @@ -1,4 +1,3 @@ -import fs from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from '@rstest/core'; diff --git a/tests/list/json.test.ts b/tests/list/json.test.ts index 0e112643..ecbce5ab 100644 --- a/tests/list/json.test.ts +++ b/tests/list/json.test.ts @@ -81,7 +81,7 @@ describe('test list command with --json', () => { fs.rmSync(outputPath, { force: true }); - const { cli, expectExecSuccess } = await runRstestCli({ + const { expectExecSuccess } = await runRstestCli({ command: 'rstest', args: ['list', '--json', 'output.json'], options: { diff --git a/tests/package.json b/tests/package.json index 2f3c1294..393f5771 100644 --- a/tests/package.json +++ b/tests/package.json @@ -3,12 +3,15 @@ "name": "@rstest/tests", "version": "1.0.0", "scripts": { - "test": "rstest run" + "test": "rstest run", + "typecheck": "tsc --noEmit" }, "devDependencies": { - "@rsbuild/core": "1.4.0-rc.0", - "@rslib/core": "0.10.2", + "@rsbuild/core": "1.4.2", + "@rslib/core": "0.10.4", "@rstest/core": "workspace:*", + "@rstest/tsconfig": "workspace:*", + "@types/jest-image-snapshot": "^6.4.0", "jest-image-snapshot": "^6.5.1", "pathe": "^2.0.3", "strip-ansi": "^7.1.0", diff --git a/tests/reporter/rstest.customReporterConfig.ts b/tests/reporter/rstest.customReporterConfig.ts index 7f4e4eb6..02936775 100644 --- a/tests/reporter/rstest.customReporterConfig.ts +++ b/tests/reporter/rstest.customReporterConfig.ts @@ -1,18 +1,29 @@ import { defineConfig } from '@rstest/core'; -import type { Reporter } from '@rstest/core/node'; +import type { + Reporter, + TestFileInfo, + TestFileResult, + TestResult, +} from '@rstest/core/node'; export const reporterResult: string[] = []; class MyReporter implements Reporter { - onTestFileStart(file) { + onTestFileStart(_file: TestFileInfo) { reporterResult.push('[custom reporter] onTestFileStart'); } - onTestCaseResult(result) { + onTestCaseResult(_result: TestResult) { reporterResult.push('[custom reporter] onTestCaseResult'); } - onTestRunEnd({ results, testResults }) { + onTestRunEnd({ + results: _results, + testResults: _testResults, + }: { + results: TestFileResult[]; + testResults: TestResult[]; + }) { reporterResult.push('[custom reporter] onTestRunEnd'); console.log(reporterResult); } diff --git a/tests/rstestEnv.d.ts b/tests/rstestEnv.d.ts new file mode 100644 index 00000000..38b3bc93 --- /dev/null +++ b/tests/rstestEnv.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/tests/runner/test/processExit.test.ts b/tests/runner/test/processExit.test.ts new file mode 100644 index 00000000..7e649499 --- /dev/null +++ b/tests/runner/test/processExit.test.ts @@ -0,0 +1,12 @@ +import { expect, it } from '@rstest/core'; + +it('Calling process.exit will turn to throw an error', () => { + let err: Error | null = null; + try { + process.exit(42); + } catch (error) { + err = error as Error; + } + + expect(err?.message).toBe('process.exit unexpectedly called with "42"'); +}); diff --git a/tests/scripts/index.ts b/tests/scripts/index.ts index 40e587b4..07fa8775 100644 --- a/tests/scripts/index.ts +++ b/tests/scripts/index.ts @@ -73,7 +73,11 @@ export async function runRstestCli({ command, options, args = [], -}: { command: string; options?: Partial; args?: string[] }) { +}: { + command: string; + options?: Partial; + args?: string[]; +}) { const process = x(command, args, options as Options); const cli = new Cli(process); @@ -93,7 +97,9 @@ export async function runRstestCli({ export async function prepareFixtures({ fixturesPath, -}: { fixturesPath: string }) { +}: { + fixturesPath: string; +}) { const root = path.dirname(fixturesPath); const distPath = path.resolve(`${fixturesPath}-test`); fs.rmSync(distPath, { recursive: true, force: true }); diff --git a/tests/scripts/utils.ts b/tests/scripts/utils.ts index 066766c1..d94ec07f 100644 --- a/tests/scripts/utils.ts +++ b/tests/scripts/utils.ts @@ -2,7 +2,7 @@ import fs from 'node:fs'; import { expect } from '@rstest/core'; export const getTestName = (log: string, prefix: string) => - log.slice(0, log.lastIndexOf('(')).split(prefix)[1].trim(); + log.slice(0, log.lastIndexOf('(')).split(prefix)[1]!.trim(); export const expectFile = (filePath: string, timeout = 3000) => expect diff --git a/tests/setup/index.test.ts b/tests/setup/index.test.ts index 70fed364..14ca61e0 100644 --- a/tests/setup/index.test.ts +++ b/tests/setup/index.test.ts @@ -1,4 +1,4 @@ -import { dirname, join, sep } from 'node:path'; +import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from '@rstest/core'; import { runRstestCli } from '../scripts'; diff --git a/tests/snapshot/extend.test.ts b/tests/snapshot/extend.test.ts index 6b87f446..861e90c6 100644 --- a/tests/snapshot/extend.test.ts +++ b/tests/snapshot/extend.test.ts @@ -3,7 +3,7 @@ import { join } from 'node:path'; import { expect, it } from '@rstest/core'; declare module '@rstest/core' { - interface Assertion { + interface Assertion { toMatchImageSnapshot(): void; } } diff --git a/tests/snapshot/index.test.ts b/tests/snapshot/index.test.ts index 80e4abb3..cab9a77e 100644 --- a/tests/snapshot/index.test.ts +++ b/tests/snapshot/index.test.ts @@ -1,5 +1,4 @@ -import path from 'node:path'; -import { dirname } from 'node:path'; +import path, { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from '@rstest/core'; import { createSnapshotSerializer } from 'path-serializer'; diff --git a/tests/snapshot/obsolete.test.ts b/tests/snapshot/obsolete.test.ts index 252a0937..b17097de 100644 --- a/tests/snapshot/obsolete.test.ts +++ b/tests/snapshot/obsolete.test.ts @@ -1,8 +1,6 @@ -import path from 'node:path'; import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from '@rstest/core'; -import { createSnapshotSerializer } from 'path-serializer'; import { runRstestCli } from '../scripts'; const __filename = fileURLToPath(import.meta.url); diff --git a/tests/spy/config.test.ts b/tests/spy/config.test.ts index 6f84b1a8..66f80b20 100644 --- a/tests/spy/config.test.ts +++ b/tests/spy/config.test.ts @@ -1,6 +1,6 @@ import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { expect, it } from '@rstest/core'; +import { it } from '@rstest/core'; import { runRstestCli } from '../scripts'; const __filename = fileURLToPath(import.meta.url); diff --git a/tests/spy/index.test.ts b/tests/spy/index.test.ts index 450f967d..310f9235 100644 --- a/tests/spy/index.test.ts +++ b/tests/spy/index.test.ts @@ -90,6 +90,24 @@ describe('test spy', () => { expect(sayHi).toHaveBeenCalledTimes(4); }); + it('mockImplementation types', async () => { + // overload + const fs = { readFileSync() {} } as any as typeof import('node:fs'); + rstest.spyOn(fs, 'readFileSync').mockImplementation(() => 'str'); + rstest + .spyOn(fs, 'readFileSync') + .mockImplementation(() => Buffer.from('buf')); + rstest.fn(fs.readFileSync).mockImplementation(() => 'str'); + rstest.fn(fs.readFileSync).mockImplementation(() => Buffer.from('buf')); + + // union + interface Handler { + (v: number): number; + other: (v: number) => number; + } + rstest.fn().mockImplementation((v) => v + 1); + }); + it('isMockFunction', () => { const sayHi = rstest.fn(); expect(rstest.isMockFunction(sayHi)).toBeTruthy(); diff --git a/tests/spy/stubGlobal.test.ts b/tests/spy/stubGlobal.test.ts index 5e235177..17aba959 100644 --- a/tests/spy/stubGlobal.test.ts +++ b/tests/spy/stubGlobal.test.ts @@ -1,7 +1,10 @@ import { expect, it, rstest } from '@rstest/core'; +declare global { + var __test_flag__: boolean | undefined; +} + function checkGlobalThis() { - // @ts-expect-error expect(__test_flag__).toBeTruthy(); } diff --git a/tests/spy/withImplementation.test.ts b/tests/spy/withImplementation.test.ts index 88bfe7be..2afbef63 100644 --- a/tests/spy/withImplementation.test.ts +++ b/tests/spy/withImplementation.test.ts @@ -1,4 +1,5 @@ import { afterAll, describe, expect, it, rstest } from '@rstest/core'; + const logs: string[] = []; afterAll(() => { diff --git a/tests/ssr/index.test.ts b/tests/ssr/index.test.ts index 954eaaa1..f076226e 100644 --- a/tests/ssr/index.test.ts +++ b/tests/ssr/index.test.ts @@ -1,6 +1,6 @@ import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { describe, expect, it } from '@rstest/core'; +import { describe, it } from '@rstest/core'; import { runRstestCli } from '../scripts/'; const __filename = fileURLToPath(import.meta.url); diff --git a/tests/test-api/chain.test.ts b/tests/test-api/chain.test.ts index 6c117b49..329a8e55 100644 --- a/tests/test-api/chain.test.ts +++ b/tests/test-api/chain.test.ts @@ -1,10 +1,4 @@ -import { dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; import { describe, expect, it } from '@rstest/core'; -import { runRstestCli } from '../scripts'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); describe('Test Chain', () => { it('chain API enumerable', async () => { diff --git a/tests/test-api/concurrent.test.ts b/tests/test-api/concurrent.test.ts index f878e0de..2c2676a3 100644 --- a/tests/test-api/concurrent.test.ts +++ b/tests/test-api/concurrent.test.ts @@ -1,4 +1,5 @@ import { afterAll, describe, expect, it } from '@rstest/core'; + const logs: string[] = []; afterAll(() => { diff --git a/tests/test-api/concurrentIsolated.test.ts b/tests/test-api/concurrentIsolated.test.ts index c036523d..c53ac030 100644 --- a/tests/test-api/concurrentIsolated.test.ts +++ b/tests/test-api/concurrentIsolated.test.ts @@ -1,4 +1,5 @@ import { afterAll, describe, expect, it } from '@rstest/core'; + const logs: string[] = []; afterAll(() => { diff --git a/tests/test-api/concurrentNested.test.ts b/tests/test-api/concurrentNested.test.ts index 9b77bc94..9b8f2eb9 100644 --- a/tests/test-api/concurrentNested.test.ts +++ b/tests/test-api/concurrentNested.test.ts @@ -1,4 +1,5 @@ import { afterAll, describe, expect, it } from '@rstest/core'; + const logs: string[] = []; afterAll(() => { diff --git a/tests/test-api/edgeCase.test.ts b/tests/test-api/edgeCase.test.ts index b3743d9c..b5dafe10 100644 --- a/tests/test-api/edgeCase.test.ts +++ b/tests/test-api/edgeCase.test.ts @@ -25,7 +25,8 @@ describe('Test Edge Cases', () => { expect(logs.find((log) => log.includes('Error: Symbol('))).toBeFalsy(); }); - it('test module not found', async () => { + // TODO: Throw user friendly error message in webpack runtime. + it.todo('test module not found', async () => { // Module not found errors should be silent at build time, and throw errors at runtime const { cli, expectExecSuccess } = await runRstestCli({ command: 'rstest', diff --git a/tests/test-api/fixtures/lessError.test.ts b/tests/test-api/fixtures/lessError.test.ts index 79c96bd0..ab06daed 100644 --- a/tests/test-api/fixtures/lessError.test.ts +++ b/tests/test-api/fixtures/lessError.test.ts @@ -1,5 +1,4 @@ import { expect, it } from '@rstest/core'; -// @ts-expect-error import style from './index.module.less'; it('test', () => { diff --git a/tests/test-api/fixtures/moduleNotFound.test.ts b/tests/test-api/fixtures/moduleNotFound.test.ts index 74e58927..93ea66ad 100644 --- a/tests/test-api/fixtures/moduleNotFound.test.ts +++ b/tests/test-api/fixtures/moduleNotFound.test.ts @@ -5,7 +5,7 @@ const expectNotFound = async () => { // @ts-expect-error const res = await import('404'); return res; - } catch (err) { + } catch (_err) { return null; } }; @@ -21,6 +21,6 @@ it('test expectNotFound error', async () => { it('test expectNotFound error', async () => { await expect(unexpectNotFound()).rejects.toThrowError( - /Cannot find module \'aaa\'/, + /Cannot find module 'aaa'/, ); }); diff --git a/tests/test-api/fixtures/onlyInSkip.test.ts b/tests/test-api/fixtures/onlyInSkip.test.ts index 377d48d8..61cd7467 100644 --- a/tests/test-api/fixtures/onlyInSkip.test.ts +++ b/tests/test-api/fixtures/onlyInSkip.test.ts @@ -1,7 +1,6 @@ import { describe, expect, it } from '@rstest/core'; describe.skip('level A', () => { - // biome-ignore lint/suspicious/noFocusedTests: it.only('it in level A', () => { console.log('[test] in level A'); expect(1 + 1).toBe(2); diff --git a/tests/test-api/for.test.ts b/tests/test-api/for.test.ts index c3b7bed1..134505f5 100644 --- a/tests/test-api/for.test.ts +++ b/tests/test-api/for.test.ts @@ -20,6 +20,6 @@ it.for([ [2, 2, 4], [3, 1, 4], ])('case-%# add(%i, %i) -> %i', ([a, b, expected], { expect }) => { - expect(a + b).toBe(expected); + expect(a! + b!).toBe(expected); logs.push('executed'); }); diff --git a/tests/test-api/only.each.test.ts b/tests/test-api/only.each.test.ts index e2e52e57..d821050e 100644 --- a/tests/test-api/only.each.test.ts +++ b/tests/test-api/only.each.test.ts @@ -1,4 +1,5 @@ import { afterAll, expect, it } from '@rstest/core'; + const logs: string[] = []; afterAll(() => { diff --git a/tests/test-api/only.fails.test.ts b/tests/test-api/only.fails.test.ts index 2e152fed..53d1d785 100644 --- a/tests/test-api/only.fails.test.ts +++ b/tests/test-api/only.fails.test.ts @@ -1,4 +1,5 @@ import { afterAll, expect, it } from '@rstest/core'; + const logs: string[] = []; afterAll(() => { diff --git a/tests/test-api/only.test.ts b/tests/test-api/only.test.ts index 1ca14ba1..6cab2d93 100644 --- a/tests/test-api/only.test.ts +++ b/tests/test-api/only.test.ts @@ -18,7 +18,6 @@ beforeEach(() => { }); describe('level A', () => { - // biome-ignore lint/suspicious/noFocusedTests: it.only('it in level A', () => { logs.push('[test] in level A'); expect(1 + 1).toBe(2); @@ -30,7 +29,6 @@ describe('level A', () => { expect(2 + 1).toBe(3); }); - // biome-ignore lint/suspicious/noFocusedTests: it.only('it in level B-B', () => { logs.push('[test] in level B-B'); expect(2 + 1).toBe(3); @@ -43,7 +41,6 @@ describe('level A', () => { }); }); -// biome-ignore lint/suspicious/noFocusedTests: it.only('it in level D', () => { logs.push('[test] in level D'); expect(1 + 1).toBe(2); diff --git a/tests/test-api/sequential.test.ts b/tests/test-api/sequential.test.ts index 5a92eee6..88ffcbea 100644 --- a/tests/test-api/sequential.test.ts +++ b/tests/test-api/sequential.test.ts @@ -1,4 +1,5 @@ import { afterAll, describe, expect, it } from '@rstest/core'; + const logs: string[] = []; afterAll(() => { diff --git a/tests/tsconfig.json b/tests/tsconfig.json new file mode 100644 index 00000000..97474cf8 --- /dev/null +++ b/tests/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@rstest/tsconfig/base", + "compilerOptions": { + "outDir": "./dist", + "baseUrl": "./", + "rootDir": "./", + "declarationDir": "./dist-types", + "composite": true, + "noEmit": true, + "allowImportingTsExtensions": true + }, + "include": ["./"] +} diff --git a/website/docs/en/_meta.json b/website/docs/en/_nav.json similarity index 100% rename from website/docs/en/_meta.json rename to website/docs/en/_nav.json diff --git a/website/docs/en/api/_meta.json b/website/docs/en/api/_meta.json index 03890893..02fd1a8f 100644 --- a/website/docs/en/api/_meta.json +++ b/website/docs/en/api/_meta.json @@ -4,6 +4,11 @@ "name": "index", "label": "Overview" }, + { + "type": "dir", + "name": "test-api", + "label": "Test API" + }, { "type": "dir", "name": "rstest", diff --git a/website/docs/en/api/rstest/_meta.json b/website/docs/en/api/rstest/_meta.json new file mode 100644 index 00000000..f6eb67ef --- /dev/null +++ b/website/docs/en/api/rstest/_meta.json @@ -0,0 +1 @@ +["mockFunctions", "fakeTimers"] diff --git a/website/docs/en/api/rstest/fakeTimers.mdx b/website/docs/en/api/rstest/fakeTimers.mdx new file mode 100644 index 00000000..3d528534 --- /dev/null +++ b/website/docs/en/api/rstest/fakeTimers.mdx @@ -0,0 +1,144 @@ +--- +title: Fake timers +--- + +# Fake timers + +The fake timers may be useful when a piece of code sets a long timeout that we don't want to wait for in a test. + +Rstest provides some utility functions to help you fake timers powered by [@sinonjs/fake-timers](https://github.com/node-fake-timers/fake-timers). + +## rstest.useFakeTimers + +- **Type:** `(config?: FakeTimerInstallOpts) => Rstest` + +To enable mocking timers, you need to call this method. It uses [@sinonjs/fake-timers](https://github.com/node-fake-timers/fake-timers) under the hood. + +```ts +rstest.useFakeTimers(); +``` + +You can also pass a configuration object to customize the behavior of the fake timers. + +## rstest.useRealTimers + +- **Type:** `() => Rstest` + +Restores the original timer functions (such as `setTimeout`, `setInterval`, etc.), disabling the fake timers. + +```ts +rstest.useRealTimers(); +``` + +## rstest.isFakeTimers + +- **Type:** `() => boolean` + +Returns `true` if fake timers are currently enabled, otherwise `false`. + +```ts +if (rstest.isFakeTimers()) { + // Fake timers are active +} +``` + +## rstest.setSystemTime + +- **Type:** `(now?: number | Date) => Rstest` + +Sets the current system time used by fake timers. Useful for testing code that depends on the current date or time. + +```ts +rstest.useFakeTimers(); +rstest.setSystemTime(new Date('2020-01-01T00:00:00Z')); +``` + +## rstest.getRealSystemTime + +- **Type:** `() => number` + +Returns the real system time (as a timestamp), even when fake timers are enabled. + +```ts +const realTime = rstest.getRealSystemTime(); +``` + +## rstest.runAllTicks + +- **Type:** `() => Rstest` + +Runs all queued microtasks (e.g., `process.nextTick`). + +## rstest.runAllTimers + +- **Type:** `() => Rstest` + +Executes all pending timers (both timeouts and intervals). + +## rstest.runAllTimersAsync + +- **Type:** `() => Promise` + +Asynchronously executes all pending timers. + +## rstest.runOnlyPendingTimers + +- **Type:** `() => Rstest` + +Runs only the currently pending timers (does not schedule new ones). + +## rstest.runOnlyPendingTimersAsync + +- **Type:** `() => Promise` + +Asynchronously runs only the currently pending timers. + +## rstest.advanceTimersByTime + +- **Type:** `(ms: number) => Rstest` + +Advances the fake timers by the specified milliseconds, executing any timers scheduled within that time. + +## rstest.advanceTimersByTimeAsync + +- **Type:** `(ms: number) => Promise` + +Asynchronously advances the fake timers by the specified milliseconds. + +## rstest.advanceTimersToNextTimer + +- **Type:** `(steps?: number) => Rstest` + +Advances the timers to the next scheduled timer, optionally for a given number of steps. + +## rstest.advanceTimersToNextTimerAsync + +- **Type:** `(steps?: number) => Promise` + +Asynchronously advances the timers to the next scheduled timer. + +## rstest.advanceTimersToNextFrame + +- **Type:** `() => Rstest` + +Advances the timers to the next animation frame. + +## rstest.getTimerCount + +- **Type:** `() => number` + +Returns the number of fake timers still left to run. + +```ts +const count = rstest.getTimerCount(); +``` + +## rstest.clearAllTimers + +- **Type:** `() => Rstest` + +Removes all timers that are scheduled to run. + +```ts +rstest.clearAllTimers(); +``` diff --git a/website/docs/en/api/test-api/_meta.json b/website/docs/en/api/test-api/_meta.json new file mode 100644 index 00000000..9442282a --- /dev/null +++ b/website/docs/en/api/test-api/_meta.json @@ -0,0 +1 @@ +["describe", "test", "hooks"] diff --git a/website/docs/en/api/test-api/describe.mdx b/website/docs/en/api/test-api/describe.mdx new file mode 100644 index 00000000..db2519d5 --- /dev/null +++ b/website/docs/en/api/test-api/describe.mdx @@ -0,0 +1,138 @@ +--- +title: Describe +--- + +# Describe + +`describe` defines a test suite. It supports chainable modifiers and parameterized methods for flexible and organized test grouping. + +## describe + +- **Type:** `(name: string, fn: () => void | Promise) => void` + +Defines a test suite that can contain multiple test cases or nested describe blocks. + +```ts +import { describe, test } from '@rstest/core'; + +describe('math', () => { + test('add', () => { + // ... + }); + test('sub', () => { + // ... + }); +}); +``` + +## describe.only + +Only run the describe block(s) marked with `only`. + +```ts +describe.only('only this suite', () => { + // ... +}); +``` + +## describe.skip + +Skip the describe block(s) marked with `skip`. + +```ts +describe.skip('skip this suite', () => { + // ... +}); +``` + +## describe.todo + +Mark a describe block as todo. + +```ts +describe.todo('should implement this suite'); +``` + +## describe.each + +- **Type:** `describe.each(cases: ReadonlyArray)(name: string, fn: (param: T) => void | Promise) => void` + +Creates a describe block for each item in the provided array. + +```ts +describe.each([ + { a: 1, b: 2 }, + { a: 2, b: 3 }, +])('math $a + $b', ({ a, b }) => { + test('add', () => { + // ... + }); +}); +``` + +## describe.for + +- **Type:** `describe.for(cases: ReadonlyArray)(name: string, fn: (param: T) => void | Promise) => void` + +Alternative to `describe.each` for more flexible parameter types. + +```ts +describe.for([ + [1, 2], + [2, 3], +])('math $0 + $1', ([a, b]) => { + test('add', () => { + // ... + }); +}); +``` + +## describe.runIf + +Run the describe block only if the condition is true. + +```ts +describe.runIf(process.env.RUN_EXTRA === '1')('conditionally run', () => { + // ... +}); +``` + +## describe.skipIf + +Skip the describe block if the condition is true. + +```ts +describe.skipIf(process.platform === 'win32')('skip on Windows', () => { + // ... +}); +``` + +## describe.concurrent + +Run the tests in the describe block concurrently. + +```ts +describe.concurrent('concurrent suite', () => { + test('test 1', async () => { + /* ... */ + }); + test('test 2', async () => { + /* ... */ + }); +}); +``` + +## describe.sequential + +Run the tests in the describe block sequentially (default behavior). + +```ts +describe.sequential('sequential suite', () => { + test('test 1', async () => { + /* ... */ + }); + test('test 2', async () => { + /* ... */ + }); +}); +``` diff --git a/website/docs/en/api/test-api/hooks.mdx b/website/docs/en/api/test-api/hooks.mdx new file mode 100644 index 00000000..131ae460 --- /dev/null +++ b/website/docs/en/api/test-api/hooks.mdx @@ -0,0 +1,64 @@ +--- +title: Hooks +--- + +# Hooks + +Hooks allow you to run setup and teardown logic before or after your tests or test suites. + +## beforeAll + +- **Type:** `(fn: (ctx: SuiteContext) => void | Promise, timeout?: number) => void` + +Runs once before all tests in the current suite. + +```ts +import { beforeAll } from '@rstest/core'; + +beforeAll(async (ctx) => { + // Setup logic before all tests + // ctx.filepath gives the current test file path +}); +``` + +## afterAll + +- **Type:** `(fn: (ctx: SuiteContext) => void | Promise, timeout?: number) => void` + +Runs once after all tests in the current suite. + +```ts +import { afterAll } from '@rstest/core'; + +afterAll(async (ctx) => { + // Cleanup logic after all tests +}); +``` + +## beforeEach + +- **Type:** `(fn: () => void | Promise, timeout?: number) => void` + +Runs before each test in the current suite. + +```ts +import { beforeEach } from '@rstest/core'; + +beforeEach(async () => { + // Setup logic before each test +}); +``` + +## afterEach + +- **Type:** `(fn: () => void | Promise, timeout?: number) => void` + +Runs after each test in the current suite. + +```ts +import { afterEach } from '@rstest/core'; + +afterEach(async () => { + // Cleanup logic after each test +}); +``` diff --git a/website/docs/en/api/test-api/test.mdx b/website/docs/en/api/test-api/test.mdx new file mode 100644 index 00000000..1bbc5908 --- /dev/null +++ b/website/docs/en/api/test-api/test.mdx @@ -0,0 +1,166 @@ +--- +title: Test +--- + +# Test + +`test` defines a test case. It supports chainable modifiers and fixture extension for flexible and powerful test definitions. + +Alias: `it`. + +## test + +- **Type:** `(name: string, fn: (context) => void | Promise, timeout?: number) => void` + +Defines a test case. + +```ts +import { expect, test } from '@rstest/core'; + +test('should add two numbers correctly', () => { + expect(1 + 1).toBe(2); + expect(1 + 2).toBe(3); +}); +``` + +## test.only + +Only run certain tests in a test file. + +```ts +test.only('run only this test', () => { + // ... +}); +``` + +## test.skip + +Skips certain tests. + +```ts +test.skip('skip this test', () => { + // ... +}); +``` + +## test.todo + +Marks certain tests as todo. + +```ts +test.todo('should implement this test'); +``` + +## test.each + +- **Type:** `test.each(cases: ReadonlyArray)(name: string, fn: (param: T) => void | Promise, timeout?: number) => void` + +Runs the same test logic for each item in the provided array. + +```ts +test.each([ + { a: 1, b: 2, sum: 3 }, + { a: 2, b: 2, sum: 4 }, +])('adds $a + $b', ({ a, b, sum }) => { + expect(a + b).toBe(sum); +}); +``` + +## test.for + +- **Type:** `test.for(cases: ReadonlyArray)(name: string, fn: (param: T, context) => void | Promise, timeout?: number) => void` + +Alternative to `test.each` to provide `TestContext`. + +```ts +test.for([ + { a: 1, b: 2 }, + { a: 2, b: 2 }, +])('adds $a + $b', ({ a, b }, { expect }) => { + expect(a + b).matchSnapshot(); +}); +``` + +## test.fails + +Marks the test as expected to fail. + +```ts +test.fails('should fail', () => { + throw new Error('This test is expected to fail'); +}); +``` + +## test.concurrent + +Runs the test concurrently with consecutive `concurrent` flags. + +```ts +describe('suite', () => { + test('serial test', async () => { + /* ... */ + }); + test.concurrent('concurrent test 1', async () => { + /* ... */ + }); + test.concurrent('concurrent test 2', async () => { + /* ... */ + }); + test('serial test 1', async () => { + /* ... */ + }); +}); +``` + +## test.sequential + +Runs the test sequentially (default behavior). + +```ts +describe('suite', () => { + test('serial test', async () => { + /* ... */ + }); + test('serial test 1', async () => { + /* ... */ + }); +}); +``` + +## test.runIf + +Runs the test only if the condition is true. + +```ts +test.runIf(process.env.RUN_EXTRA === '1')('conditionally run', () => { + // ... +}); +``` + +## test.skipIf + +Skips the test if the condition is true. + +```ts +test.skipIf(process.platform === 'win32')('skip on Windows', () => { + // ... +}); +``` + +## test.extend + +- **Type:** `test.extend(fixtures: Fixtures)` + +Extends the test context with custom fixtures. + +```ts +const testWithUser = test.extend({ + user: async ({}, use) => { + await use({ name: 'Alice' }); + }, +}); + +testWithUser('has user in context', ({ user, expect }) => { + expect(user.name).toBe('Alice'); +}); +``` diff --git a/website/docs/en/config/_meta.json b/website/docs/en/config/_meta.json index 6eb31477..a4e2ae87 100644 --- a/website/docs/en/config/_meta.json +++ b/website/docs/en/config/_meta.json @@ -8,5 +8,10 @@ "type": "dir", "name": "test", "label": "Test Configurations" + }, + { + "type": "dir", + "name": "build", + "label": "Build Configurations" } ] diff --git a/website/docs/en/config/build/_meta.json b/website/docs/en/config/build/_meta.json new file mode 100644 index 00000000..07ac5963 --- /dev/null +++ b/website/docs/en/config/build/_meta.json @@ -0,0 +1 @@ +["plugins", "source", "output", "resolve", "tools", "dev", "performance"] diff --git a/website/docs/en/config/build/dev.mdx b/website/docs/en/config/build/dev.mdx new file mode 100644 index 00000000..40d7cfdc --- /dev/null +++ b/website/docs/en/config/build/dev.mdx @@ -0,0 +1,9 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# dev + +Options for local development. + +## dev.writeToDisk + +By default, Rstest does not write test temporary files to disk, and this configuration item may be required when you debug rstest outputs. diff --git a/website/docs/en/config/build/output.mdx b/website/docs/en/config/build/output.mdx new file mode 100644 index 00000000..ba321776 --- /dev/null +++ b/website/docs/en/config/build/output.mdx @@ -0,0 +1,32 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# output + +## output.externals + +Prevent some `import` dependencies from being packed into bundles in your code, and instead Rstest will `import` them at runtime. + +- In the Node.js test environment, all packages in `node_modules` are externalized by default. +- In the browser-like (jsdom, etc) test environment, all packages are bundled by default. + +If you want a dependency to be externalized, you can configure it in `output.externals`. + +```ts title="rstest.config.ts" +import { defineConfig } from '@rstest/core'; + +export default defineConfig({ + output: { + externals: ['react'], + }, +}); +``` + +## output.cssModules + +For custom CSS Modules configuration. + +## output.cleanDistPath + +Whether to clean up all test temporary files under the output directory before the test starts. + +By default, rstest does not write test temporary files to disk, and this configuration item may be required when you debug rstest outputs. diff --git a/website/docs/en/config/build/performance.mdx b/website/docs/en/config/build/performance.mdx new file mode 100644 index 00000000..8ba8b219 --- /dev/null +++ b/website/docs/en/config/build/performance.mdx @@ -0,0 +1,9 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# performance + +Options for build performance and runtime performance. + +## performance.bundleAnalyze + +Used to enable the [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) plugin to analyze the size of the output. diff --git a/website/docs/en/config/build/plugins.mdx b/website/docs/en/config/build/plugins.mdx new file mode 100644 index 00000000..166c6746 --- /dev/null +++ b/website/docs/en/config/build/plugins.mdx @@ -0,0 +1,98 @@ +--- +overviewHeaders: [] +--- + +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# plugins + +`plugins` is used to register Rsbuild plugins. + +Rstest and Rsbuild share the same plugin system, so you can use Rsbuild plugins in Rstest. + +## Using plugins + +You can register Rsbuild plugins in `rstest.config.*` using the `plugins` option, see [Rsbuild - plugins](https://rsbuild.rs/config/plugins). + +```ts title="rstest.config.ts" +import { defineConfig } from '@rstest/core'; +import { pluginReact } from '@rsbuild/plugin-react'; + +export default defineConfig({ + plugins: [pluginReact()], +}); +``` + +## Official plugins + +The following are official plugins that can be used in Rsbuild, and applicable to Rstest. + +### For React + +Plugins available for React: + +- [React Plugin](https://rsbuild.rs/plugins/list/plugin-react): Provides support for React. +- [SVGR Plugin](https://rsbuild.rs/plugins/list/plugin-svgr): Support convert SVG to React components. +- [Styled Components Plugin](https://github.com/rsbuild-contrib/rsbuild-plugin-styled-components): Provide compile-time support for styled-components. + +### For Vue + +Plugins available for Vue: + +- [Vue Plugin](https://github.com/rspack-contrib/rsbuild-plugin-unplugin-vue): Based on [unplugin-vue](https://github.com/unplugin/unplugin-vue), provides support for Vue 3 SFC (Single File Components). +- [Vue Plugin](https://rsbuild.rs/plugins/list/plugin-vue): Based on [vue-loader](https://github.com/vuejs/vue-loader), provides support for Vue 3 SFC (Single File Components) (Recommend using the implementation based on [unplugin-vue](https://github.com/unplugin/unplugin-vue), as vue-loader is no longer maintained). +- [Vue JSX Plugin](https://github.com/rspack-contrib/rsbuild-plugin-vue-jsx): Provides support for Vue 3 JSX / TSX syntax. +- [Vue2 Plugin](https://github.com/rspack-contrib/rsbuild-plugin-vue2): Provides support for Vue 2 SFC (Single File Components). +- [Vue2 JSX Plugin](https://github.com/rspack-contrib/rsbuild-plugin-vue2-jsx): Provides support for Vue 2 JSX / TSX syntax. + +### For Preact + +Plugins available for Preact: + +- [Preact Plugin](https://rsbuild.rs/plugins/list/plugin-preact): Provides support for Preact. + +### For Svelte + +Plugins available for Svelte: + +- [Svelte Plugin](https://rsbuild.rs/plugins/list/plugin-svelte): Provides support for Svelte components (`.svelte` files). + +### For Solid + +Plugins available for Solid: + +- [Solid Plugin](https://rsbuild.rs/plugins/list/plugin-solid): Provides support for Solid. + +### Common + +The following are common framework-agnostic plugins: + +- [Babel Plugin](https://rsbuild.rs/plugins/list/plugin-babel): Provides support for Babel transpilation capabilities. +- [Sass Plugin](https://rsbuild.rs/plugins/list/plugin-sass): Use Sass as the CSS preprocessor. +- [Less Plugin](https://rsbuild.rs/plugins/list/plugin-less): Use Less as the CSS preprocessor. +- [Stylus Plugin](https://rsbuild.rs/plugins/list/plugin-stylus): Use Stylus as the CSS preprocessor. +- [ESLint Plugin](https://github.com/rspack-contrib/rsbuild-plugin-eslint): Run ESLint checks during the compilation. +- [Type Check Plugin](https://github.com/rspack-contrib/rsbuild-plugin-type-check): Run TypeScript type checker on a separate process. +- [publint Plugin](https://github.com/rspack-contrib/rsbuild-plugin-publint): Run `publint` to lint npm packages after the build. +- [Image Compress Plugin](https://github.com/rspack-contrib/rsbuild-plugin-image-compress): Compress the image assets. +- [MDX Plugin](https://github.com/rspack-contrib/rsbuild-plugin-mdx): Provide support for MDX. +- [Node Polyfill Plugin](https://github.com/rspack-contrib/rsbuild-plugin-node-polyfill): Used to inject polyfills of Node core modules in the browser side. +- [Source Build Plugin](https://github.com/rspack-contrib/rsbuild-plugin-source-build): This plugin is designed for the monorepo scenario. It supports referencing source code from other subdirectories and performs build and hot update. +- [Check Syntax Plugin](https://github.com/rspack-contrib/rsbuild-plugin-check-syntax): Check the syntax compatibility of output files and determine if there are any advanced syntaxes that could cause compatibility issues. +- [CSS Minimizer Plugin](https://github.com/rspack-contrib/rsbuild-plugin-css-minimizer): Used to customize CSS minimizer, switch to [cssnano](https://github.com/cssnano/cssnano) or other tools for CSS compression. +- [Typed CSS Modules Plugin](https://github.com/rspack-contrib/rsbuild-plugin-typed-css-modules): Generate TypeScript declaration file for CSS Modules. +- [Pug Plugin](https://github.com/rspack-contrib/rsbuild-plugin-pug): Provides support for the Pug template engine. +- [Rem Plugin](https://github.com/rspack-contrib/rsbuild-plugin-rem): Implements the rem adaptive layout for mobile pages. +- [UMD Plugin](https://github.com/rspack-contrib/rsbuild-plugin-umd): Generate outputs in UMD format. +- [YAML Plugin](https://github.com/rspack-contrib/rsbuild-plugin-yaml): Import YAML files and convert them into JavaScript objects. +- [TOML Plugin](https://github.com/rspack-contrib/rsbuild-plugin-toml): Import TOML files and convert them into JavaScript objects. + +:::tip +You can find the source code of all official plugins in [web-infra-dev/rsbuild](https://github.com/web-infra-dev/rsbuild) and [rspack-contrib](https://github.com/rspack-contrib). +::: + +## Community plugins + +You can check out the Rsbuild plugins provided by the community at [awesome-rspack - Rsbuild Plugins](https://github.com/web-infra-dev/awesome-rspack?tab=readme-ov-file#rsbuild-plugins). + +You can also discover more Rsbuild plugins on npm by searching for the keyword [rsbuild-plugin](https://www.npmjs.com/search?q=rsbuild-plugin&ranking=popularity). diff --git a/website/docs/en/config/build/resolve.mdx b/website/docs/en/config/build/resolve.mdx new file mode 100644 index 00000000..51562138 --- /dev/null +++ b/website/docs/en/config/build/resolve.mdx @@ -0,0 +1,23 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# resolve + +Options for module resolution. + +## resolve.aliasStrategy + +Control the priority between the `resolve.alias` option and the `paths` option in `tsconfig.json`. + +## resolve.alias + +Set the alias for the module path, which is used to simplify the import path or redirect the module reference, similar to the [resolve.alias](https://rspack.rs/config/resolve#resolvealias) config of Rspack. + +For TypeScript projects, you only need to configure [compilerOptions.paths](https://www.typescriptlang.org/tsconfig/#paths) in the `tsconfig.json` file. Rstest will automatically recognize it, so there is no need to configure the `resolve.alias` option separately. + +## resolve.dedupe + +Force Rstest to resolve the specified packages from project root, which is useful for deduplicating packages and reducing the bundle size. + +## resolve.extensions + +Automatically resolve file extensions when importing modules. This means you can import files without explicitly writing their extensions. diff --git a/website/docs/en/config/build/source.mdx b/website/docs/en/config/build/source.mdx new file mode 100644 index 00000000..dab80757 --- /dev/null +++ b/website/docs/en/config/build/source.mdx @@ -0,0 +1,33 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# source + +Options for input source code. + +## source.decorators + +Used to configure the decorators syntax. + +## source.define + +Replaces variables in your code with other values or expressions at compile time. This can be useful for injecting env variables and other information to the code during build time. + +## source.exclude + +Exclude JavaScript or TypeScript files that do not need to be transformed by [SWC](https://rsbuild.rs/guide/configuration/swc). + +::: note + +Files configured in `source.exclude` will not be transformed by SWC, but the referenced files will still be bundled into the outputs. + +If you want certain files not to be bundled into the outputs, you can use [output.externals](/config/build/output#outputexternals) or Rspack's [IgnorePlugin](https://rspack.rs/plugins/webpack/ignore-plugin). + +::: + +## source.include + +Specify additional JavaScript files that need to be compiled. + +## source.tsconfigPath + +Configure a custom `tsconfig.json` file path to use, can be a relative or absolute path. diff --git a/website/docs/en/config/build/tools.mdx b/website/docs/en/config/build/tools.mdx new file mode 100644 index 00000000..bc209b8e --- /dev/null +++ b/website/docs/en/config/build/tools.mdx @@ -0,0 +1,17 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# tools + +Options for low-level tools. + +## tools.bundlerChain + +[rspack-chain](https://github.com/rspack-contrib/rspack-chain) is a utility library for configuring Rspack. By using `rspack-chain`, you can more easily modify and extend Rspack configurations. + +## tools.rspack + +`tools.rspack` is used to configure [Rspack](https://rspack.rs/config/index). + +## tools.swc + +You can set the options of [builtin:swc-loader](https://rspack.rs/guide/features/builtin-swc-loader) through `tools.swc`. diff --git a/website/docs/en/config/test/_meta.json b/website/docs/en/config/test/_meta.json index 8bc2ccdc..88d7e809 100644 --- a/website/docs/en/config/test/_meta.json +++ b/website/docs/en/config/test/_meta.json @@ -4,5 +4,8 @@ "includeSource", "globals", "setupFiles", - "testEnvironment" + "testEnvironment", + "retry", + "root", + "passWithNoTests" ] diff --git a/website/docs/en/config/test/passWithNoTests.mdx b/website/docs/en/config/test/passWithNoTests.mdx new file mode 100644 index 00000000..d4aa0d98 --- /dev/null +++ b/website/docs/en/config/test/passWithNoTests.mdx @@ -0,0 +1,16 @@ +# passWithNoTests + +- **Type:** `boolean` +- **Default:** `false` + +Pass when no tests are found. + +By default, Rstest marks test failures when no test suites are found. You can allow the test to pass when no tests are found by setting `passWithNoTests` to `true`. + +```ts title="rstest.config.ts" +import { defineConfig } from '@rstest/core'; + +export default defineConfig({ + passWithNoTests: true, +}); +``` diff --git a/website/docs/en/config/test/retry.mdx b/website/docs/en/config/test/retry.mdx new file mode 100644 index 00000000..4eb10db3 --- /dev/null +++ b/website/docs/en/config/test/retry.mdx @@ -0,0 +1,14 @@ +# retry + +- **Type:** `number` +- **Default:** `0` + +Retry the test specific number of times if it fails. + +```ts title="rstest.config.ts" +import { defineConfig } from '@rstest/core'; + +export default defineConfig({ + retry: 2, +}); +``` diff --git a/website/docs/en/config/test/root.mdx b/website/docs/en/config/test/root.mdx new file mode 100644 index 00000000..459da464 --- /dev/null +++ b/website/docs/en/config/test/root.mdx @@ -0,0 +1,6 @@ +# root + +- **Type:** `string` +- **Default:** [process.cwd()](https://nodejs.org/api/process.html#processcwd) + +Specify the project root directory. Can be an absolute path, or a path relative to `process.cwd()`. diff --git a/website/docs/en/guide/advanced/_meta.json b/website/docs/en/guide/advanced/_meta.json index a8ba5eff..1f5d11b1 100644 --- a/website/docs/en/guide/advanced/_meta.json +++ b/website/docs/en/guide/advanced/_meta.json @@ -1 +1 @@ -["profiling"] +["debug-mode", "profiling"] diff --git a/website/docs/en/guide/advanced/debug-mode.mdx b/website/docs/en/guide/advanced/debug-mode.mdx new file mode 100644 index 00000000..1a073e2b --- /dev/null +++ b/website/docs/en/guide/advanced/debug-mode.mdx @@ -0,0 +1,46 @@ +# Debug mode + +Rstest provides a debug mode to troubleshoot problems, you can add the `DEBUG=rstest` environment variable when building to enable Rstest's debug mode. + +```bash +DEBUG=rstest pnpm test +``` + +In debug mode, Rstest will write test outputs to disk, and write the Rstest config, Rsbuild config and Rspack config to the dist directory, which is convenient for developers to view and debug. + +## Rstest config file + +In debug mode, Rstest will automatically generate `dist/.rsbuild/rstest.config.mjs` file, which contains the final generated Rstest config. In this file, you can know the final result of the Rstest config you passed in after being processed by the framework and Rstest. + +The content of the file is as follows: + +```js title="rstest.config.mjs" +export default { + name: 'rstest', + include: ['**/*.{test,spec}.?(c|m)[jt]s?(x)'], + exclude: [ + '**/node_modules/**', + '**/dist/**', + '**/.{idea,git,cache,output,temp}/**', + '**/dist/.rstest-temp', + ], + includeSource: [], + pool: { + type: 'forks', + }, + isolate: true, + globals: false, + passWithNoTests: false, + update: false, + testTimeout: 5000, + testEnvironment: 'node', + retry: 0, + clearMocks: false, + resetMocks: false, + restoreMocks: false, + slowTestThreshold: 300, + // other configs... +}; +``` + +For a complete introduction to Rstest config, please see the [Configure Rstest](/guide/basic/configure-rstest) chapter. diff --git a/website/docs/zh/_meta.json b/website/docs/zh/_nav.json similarity index 100% rename from website/docs/zh/_meta.json rename to website/docs/zh/_nav.json diff --git a/website/docs/zh/api/_meta.json b/website/docs/zh/api/_meta.json index 03890893..02fd1a8f 100644 --- a/website/docs/zh/api/_meta.json +++ b/website/docs/zh/api/_meta.json @@ -4,6 +4,11 @@ "name": "index", "label": "Overview" }, + { + "type": "dir", + "name": "test-api", + "label": "Test API" + }, { "type": "dir", "name": "rstest", diff --git a/website/docs/zh/api/rstest/_meta.json b/website/docs/zh/api/rstest/_meta.json new file mode 100644 index 00000000..f6eb67ef --- /dev/null +++ b/website/docs/zh/api/rstest/_meta.json @@ -0,0 +1 @@ +["mockFunctions", "fakeTimers"] diff --git a/website/docs/zh/api/rstest/fakeTimers.mdx b/website/docs/zh/api/rstest/fakeTimers.mdx new file mode 100644 index 00000000..8b62bb28 --- /dev/null +++ b/website/docs/zh/api/rstest/fakeTimers.mdx @@ -0,0 +1,144 @@ +--- +title: Fake timers +--- + +# Fake timers + +当你的代码中设置了很长的定时器(timeout),而你又不想在测试中等待它们时,fake timers 会非常有用。 + +Rstest 提供了一些实用函数,基于 [@sinonjs/fake-timers](https://github.com/node-fake-timers/fake-timers) 实现定时器的模拟。 + +## rstest.useFakeTimers + +- **类型:** `(config?: FakeTimerInstallOpts) => Rstest` + +调用此方法可以启用定时器的模拟。底层使用 [@sinonjs/fake-timers](https://github.com/node-fake-timers/fake-timers)。 + +```ts +rstest.useFakeTimers(); +``` + +你也可以传递配置对象以自定义 fake timers 的行为。 + +## rstest.useRealTimers + +- **类型:** `() => Rstest` + +恢复原生的定时器函数(如 `setTimeout`、`setInterval` 等),关闭 fake timers。 + +```ts +rstest.useRealTimers(); +``` + +## rstest.isFakeTimers + +- **类型:** `() => boolean` + +如果当前启用了 fake timers,则返回 `true`,否则返回 `false`。 + +```ts +if (rstest.isFakeTimers()) { + // Fake timers 已启用 +} +``` + +## rstest.setSystemTime + +- **类型:** `(now?: number | Date) => Rstest` + +设置 fake timers 使用的当前系统时间。适用于需要测试依赖当前日期或时间的代码。 + +```ts +rstest.useFakeTimers(); +rstest.setSystemTime(new Date('2020-01-01T00:00:00Z')); +``` + +## rstest.getRealSystemTime + +- **类型:** `() => number` + +即使在启用 fake timers 时,也可以返回真实系统时间(时间戳)。 + +```ts +const realTime = rstest.getRealSystemTime(); +``` + +## rstest.runAllTicks + +- **类型:** `() => Rstest` + +运行所有已排队的微任务(如 `process.nextTick`)。 + +## rstest.runAllTimers + +- **类型:** `() => Rstest` + +执行所有待运行的定时器(包括 timeout 和 interval)。 + +## rstest.runAllTimersAsync + +- **类型:** `() => Promise` + +异步执行所有待运行的定时器。 + +## rstest.runOnlyPendingTimers + +- **类型:** `() => Rstest` + +只运行当前待运行的定时器(不会调度新的定时器)。 + +## rstest.runOnlyPendingTimersAsync + +- **类型:** `() => Promise` + +异步只运行当前待运行的定时器。 + +## rstest.advanceTimersByTime + +- **类型:** `(ms: number) => Rstest` + +将 fake timers 快进指定的毫秒数,并执行在此期间计划的所有定时器。 + +## rstest.advanceTimersByTimeAsync + +- **类型:** `(ms: number) => Promise` + +异步快进 fake timers 指定的毫秒数。 + +## rstest.advanceTimersToNextTimer + +- **类型:** `(steps?: number) => Rstest` + +将定时器推进到下一个计划的定时器,可选地指定推进的步数。 + +## rstest.advanceTimersToNextTimerAsync + +- **类型:** `(steps?: number) => Promise` + +异步将定时器推进到下一个计划的定时器。 + +## rstest.advanceTimersToNextFrame + +- **类型:** `() => Rstest` + +将定时器推进到下一个动画帧。 + +## rstest.getTimerCount + +- **类型:** `() => number` + +返回当前 fake timers 中还剩多少个待运行的定时器。 + +```ts +const count = rstest.getTimerCount(); +``` + +## rstest.clearAllTimers + +- **类型:** `() => Rstest` + +移除所有已计划但尚未执行的定时器。 + +```ts +rstest.clearAllTimers(); +``` diff --git a/website/docs/zh/api/test-api/_meta.json b/website/docs/zh/api/test-api/_meta.json new file mode 100644 index 00000000..9442282a --- /dev/null +++ b/website/docs/zh/api/test-api/_meta.json @@ -0,0 +1 @@ +["describe", "test", "hooks"] diff --git a/website/docs/zh/api/test-api/describe.mdx b/website/docs/zh/api/test-api/describe.mdx new file mode 100644 index 00000000..9e6b58c4 --- /dev/null +++ b/website/docs/zh/api/test-api/describe.mdx @@ -0,0 +1,138 @@ +--- +title: Describe +--- + +# Describe + +`describe` 用于定义测试套件(test suite),支持链式修饰符和参数化方法,便于灵活有序地组织测试。 + +## describe + +- **类型:** `(name: string, fn: () => void | Promise) => void` + +定义一个测试套件,可以包含多个测试用例或嵌套的 describe。 + +```ts +import { describe, test } from '@rstest/core'; + +describe('math', () => { + test('add', () => { + // ... + }); + test('sub', () => { + // ... + }); +}); +``` + +## describe.only + +只运行被 only 标记的 describe 块。 + +```ts +describe.only('只运行这个套件', () => { + // ... +}); +``` + +## describe.skip + +跳过被 skip 标记的 describe 块。 + +```ts +describe.skip('跳过这个套件', () => { + // ... +}); +``` + +## describe.todo + +标记为待办的 describe 块。 + +```ts +describe.todo('should implement this suite'); +``` + +## describe.each + +- **类型:** `describe.each(cases: ReadonlyArray)(name: string, fn: (param: T) => void | Promise) => void` + +为数组中的每一项生成一个 describe 块。 + +```ts +describe.each([ + { a: 1, b: 2 }, + { a: 2, b: 3 }, +])('math $a + $b', ({ a, b }) => { + test('add', () => { + // ... + }); +}); +``` + +## describe.for + +- **类型:** `describe.for(cases: ReadonlyArray)(name: string, fn: (param: T) => void | Promise) => void` + +类似 each,但参数类型更灵活。 + +```ts +describe.for([ + [1, 2], + [2, 3], +])('math $0 + $1', ([a, b]) => { + test('add', () => { + // ... + }); +}); +``` + +## describe.runIf + +仅当条件为 true 时运行该 describe 块。 + +```ts +describe.runIf(process.env.RUN_EXTRA === '1')('有条件地运行', () => { + // ... +}); +``` + +## describe.skipIf + +当条件为 true 时跳过该 describe 块。 + +```ts +describe.skipIf(process.platform === 'win32')('Windows 下跳过', () => { + // ... +}); +``` + +## describe.concurrent + +并发运行该 describe 下的测试。 + +```ts +describe.concurrent('并发套件', () => { + test('test 1', async () => { + /* ... */ + }); + test('test 2', async () => { + /* ... */ + }); +}); +``` + +## describe.sequential + +顺序运行该 describe 下的测试(默认行为)。 + +```ts +describe.sequential('顺序套件', () => { + test('test 1', async () => { + /* ... */ + }); + test('test 2', async () => { + /* ... */ + }); +}); +``` diff --git a/website/docs/zh/api/test-api/hooks.mdx b/website/docs/zh/api/test-api/hooks.mdx new file mode 100644 index 00000000..dedc5aca --- /dev/null +++ b/website/docs/zh/api/test-api/hooks.mdx @@ -0,0 +1,64 @@ +--- +title: Hooks +--- + +# Hooks + +Hooks 允许你在测试或测试套件执行之前或之后运行初始化和清理逻辑。 + +## beforeAll + +- **类型:** `(fn: (ctx: SuiteContext) => void | Promise, timeout?: number) => void` + +在当前套件的所有测试之前运行。 + +```ts +import { beforeAll } from '@rstest/core'; + +beforeAll(async (ctx) => { + // 在所有测试前的初始化逻辑 + // ctx.filepath 表示当前测试文件路径 +}); +``` + +## afterAll + +- **类型:** `(fn: (ctx: SuiteContext) => void | Promise, timeout?: number) => void` + +在当前套件的所有测试之后运行。 + +```ts +import { afterAll } from '@rstest/core'; + +afterAll(async (ctx) => { + // 在所有测试后的清理逻辑 +}); +``` + +## beforeEach + +- **类型:** `(fn: () => void | Promise, timeout?: number) => void` + +在当前套件的每个测试之前运行。 + +```ts +import { beforeEach } from '@rstest/core'; + +beforeEach(async () => { + // 每个测试前的初始化逻辑 +}); +``` + +## afterEach + +- **类型:** `(fn: () => void | Promise, timeout?: number) => void` + +在当前套件的每个测试之后运行。 + +```ts +import { afterEach } from '@rstest/core'; + +afterEach(async () => { + // 每个测试后的清理逻辑 +}); +``` diff --git a/website/docs/zh/api/test-api/test.mdx b/website/docs/zh/api/test-api/test.mdx new file mode 100644 index 00000000..3f752fcd --- /dev/null +++ b/website/docs/zh/api/test-api/test.mdx @@ -0,0 +1,166 @@ +--- +title: Test +--- + +# Test + +`test` 用于定义一个测试用例,支持链式调用和 fixture 扩展。 + +别名:`it`。 + +## test + +- **类型:** `(name: string, fn: (context) => void | Promise, timeout?: number) => void` + +定义一个测试用例。 + +```ts +import { expect, test } from '@rstest/core'; + +test('should add two numbers correctly', () => { + expect(1 + 1).toBe(2); + expect(1 + 2).toBe(3); +}); +``` + +## test.only + +只运行测试文件中的某些测试。 + +```ts +test.only('run only this test', () => { + // ... +}); +``` + +## test.skip + +跳过某些测试。 + +```ts +test.skip('skip this test', () => { + // ... +}); +``` + +## test.todo + +将某些测试标记为待办。 + +```ts +test.todo('should implement this test'); +``` + +## test.each + +- **类型:** `test.each(cases: ReadonlyArray)(name: string, fn: (param: T) => void | Promise, timeout?: number) => void` + +对提供的数组中的每一项运行相同的测试逻辑。 + +```ts +test.each([ + { a: 1, b: 2, sum: 3 }, + { a: 2, b: 2, sum: 4 }, +])('adds $a + $b', ({ a, b, sum }) => { + expect(a + b).toBe(sum); +}); +``` + +## test.for + +- **类型:** `test.for(cases: ReadonlyArray)(name: string, fn: (param: T, context) => void | Promise, timeout?: number) => void` + +`test.each` 的替代方案,提供 `TestContext`。 + +```ts +test.for([ + { a: 1, b: 2 }, + { a: 2, b: 2 }, +])('adds $a + $b', ({ a, b }, { expect }) => { + expect(a + b).matchSnapshot(); +}); +``` + +## test.fails + +标记该测试预期会失败。 + +```ts +test.fails('should fail', () => { + throw new Error('This test is expected to fail'); +}); +``` + +## test.concurrent + +并发运行连续带有 `concurrent` 标记的测试。 + +```ts +describe('suite', () => { + test('serial test', async () => { + /* ... */ + }); + test.concurrent('concurrent test 1', async () => { + /* ... */ + }); + test.concurrent('concurrent test 2', async () => { + /* ... */ + }); + test('serial test 1', async () => { + /* ... */ + }); +}); +``` + +## test.sequential + +顺序(串行)运行测试(默认行为)。 + +```ts +describe('suite', () => { + test('serial test', async () => { + /* ... */ + }); + test('serial test 1', async () => { + /* ... */ + }); +}); +``` + +## test.runIf + +仅当条件为真时才运行该测试。 + +```ts +test.runIf(process.env.RUN_EXTRA === '1')('conditionally run', () => { + // ... +}); +``` + +## test.skipIf + +当条件为真时跳过该测试。 + +```ts +test.skipIf(process.platform === 'win32')('skip on Windows', () => { + // ... +}); +``` + +## test.extend + +- **类型:** `test.extend(fixtures: Fixtures)` + +通过自定义 fixture 扩展测试上下文。 + +```ts +const testWithUser = test.extend({ + user: async ({}, use) => { + await use({ name: 'Alice' }); + }, +}); + +testWithUser('has user in context', ({ user, expect }) => { + expect(user.name).toBe('Alice'); +}); +``` diff --git a/website/docs/zh/config/_meta.json b/website/docs/zh/config/_meta.json index 6eb31477..a4e2ae87 100644 --- a/website/docs/zh/config/_meta.json +++ b/website/docs/zh/config/_meta.json @@ -8,5 +8,10 @@ "type": "dir", "name": "test", "label": "Test Configurations" + }, + { + "type": "dir", + "name": "build", + "label": "Build Configurations" } ] diff --git a/website/docs/zh/config/build/_meta.json b/website/docs/zh/config/build/_meta.json new file mode 100644 index 00000000..07ac5963 --- /dev/null +++ b/website/docs/zh/config/build/_meta.json @@ -0,0 +1 @@ +["plugins", "source", "output", "resolve", "tools", "dev", "performance"] diff --git a/website/docs/zh/config/build/dev.mdx b/website/docs/zh/config/build/dev.mdx new file mode 100644 index 00000000..737d7871 --- /dev/null +++ b/website/docs/zh/config/build/dev.mdx @@ -0,0 +1,9 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# dev + +与本地开发调试有关的选项。 + +## dev.writeToDisk + +默认情况下,Rstest 不会将测试临时文件写入磁盘,当你需要调试 Rstest 产物时可能需要此配置项。 diff --git a/website/docs/zh/config/build/output.mdx b/website/docs/zh/config/build/output.mdx new file mode 100644 index 00000000..a6dec3de --- /dev/null +++ b/website/docs/zh/config/build/output.mdx @@ -0,0 +1,32 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# output + +## output.externals + +配置代码中的某些 `import` 的依赖不被打包,而是由 Rstest 在运行时去获取这些依赖。 + +- 在 Node.js 测试环境中,默认将 `node_modules` 下的所有包都进行 external。 +- 在类浏览器(jsdom 等)测试环境中,默认打包所有依赖。 + +如果你想某个依赖不被打包,可以在 `output.externals` 中进行配置。 + +```ts title="rstest.config.ts" +import { defineConfig } from '@rstest/core'; + +export default defineConfig({ + output: { + externals: ['react'], + }, +}); +``` + +## output.cssModules + +用于自定义 CSS Modules 的配置。 + +## output.cleanDistPath + +是否在测试开始前,清空输出目录下的所有测试临时文件。 + +默认情况下,Rstest 不会将测试临时文件写入磁盘,当你开启 Rstest 产物调试时可能需要此配置项。 diff --git a/website/docs/zh/config/build/performance.mdx b/website/docs/zh/config/build/performance.mdx new file mode 100644 index 00000000..033b2feb --- /dev/null +++ b/website/docs/zh/config/build/performance.mdx @@ -0,0 +1,9 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# performance + +与构建性能、运行时性能有关的选项。 + +## performance.bundleAnalyze + +用于开启 [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) 插件来分析产物体积。 diff --git a/website/docs/zh/config/build/plugins.mdx b/website/docs/zh/config/build/plugins.mdx new file mode 100644 index 00000000..9190b3c0 --- /dev/null +++ b/website/docs/zh/config/build/plugins.mdx @@ -0,0 +1,98 @@ +--- +overviewHeaders: [] +--- + +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# plugins + +`plugins` 选项用于注册 Rsbuild 插件。 + +Rstest 与 Rsbuild 共享同一套插件系统,因此你可以在 Rstest 中使用 Rsbuild 插件。 + +## 使用插件 + +你可以在 `rstest.config.*` 中通过 `plugins` 选项来注册 Rsbuild 插件,详见 [Rsbuild - plugins](https://rsbuild.rs/zh/config/plugins)。 + +```ts title="rstest.config.ts" +import { defineConfig } from '@rstest/core'; +import { pluginReact } from '@rsbuild/plugin-react'; + +export default defineConfig({ + plugins: [pluginReact()], +}); +``` + +## 官方插件 + +下面是 Rsbuild 官方提供的插件,适用于 Rsbuild 和 Rstest。 + +### React + +适用于 React 的插件有: + +- [React 插件](https://rsbuild.rs/zh/plugins/list/plugin-react):提供对 React 的支持。 +- [SVGR 插件](https://rsbuild.rs/zh/plugins/list/plugin-svgr):支持将 SVG 图片转换为一个 React 组件使用。 +- [Styled Components 插件](https://github.com/rspack-contrib/rsbuild-plugin-styled-components):提供对 styled-components 的编译时支持。 + +### Vue + +适用于 Vue 的插件有: + +- [Vue 插件](https://github.com/rspack-contrib/rsbuild-plugin-unplugin-vue):基于 [unplugin-vue](https://github.com/unplugin/unplugin-vue) 实现的为 Vue 3 SFC(单文件组件)提供支持的插件。 +- [Vue 插件](https://rsbuild.rs/zh/plugins/list/plugin-vue):基于 [vue-loader](https://github.com/vuejs/vue-loader) 实现的为 Vue 3 SFC(单文件组件)提供支持的插件(推荐使用基于 [unplugin-vue](https://github.com/unplugin/unplugin-vue) 的实现,vue-loader 已不再维护)。 +- [Vue JSX 插件](https://github.com/rspack-contrib/rsbuild-plugin-vue-jsx):提供对 Vue 3 JSX / TSX 语法的支持。 +- [Vue 2 插件](https://github.com/rspack-contrib/rsbuild-plugin-vue2):提供对 Vue 2 SFC(单文件组件)的支持。 +- [Vue 2 JSX 插件](https://github.com/rspack-contrib/rsbuild-plugin-vue2-jsx):提供对 Vue 2 JSX / TSX 语法的支持。 + +### Preact + +适用于 Preact 的插件有: + +- [Preact 插件](https://rsbuild.rs/zh/plugins/list/plugin-preact):提供对 Preact 的支持。 + +### Svelte + +适用于 Svelte 的插件有: + +- [Svelte 插件](https://rsbuild.rs/zh/plugins/list/plugin-svelte):提供对 Svelte 组件(`.svelte` 文件)的支持。 + +### Solid + +适用于 Solid 的插件有: + +- [Solid 插件](https://rsbuild.rs/zh/plugins/list/plugin-solid):提供对 Solid 的支持。 + +### Common + +以下是与框架无关的通用插件: + +- [Babel 插件](https://rsbuild.rs/zh/plugins/list/plugin-babel):提供对 Babel 转译能力的支持。 +- [Sass 插件](https://rsbuild.rs/zh/plugins/list/plugin-sass):使用 Sass 作为 CSS 预处理器。 +- [Less 插件](https://rsbuild.rs/zh/plugins/list/plugin-less):使用 Less 作为 CSS 预处理器。 +- [Stylus 插件](https://rsbuild.rs/zh/plugins/list/plugin-stylus):使用 Stylus 作为 CSS 预处理器。 +- [ESLint 插件](https://github.com/rspack-contrib/rsbuild-plugin-eslint):用于在编译过程中运行 ESLint 检查。 +- [publint 插件](https://github.com/rspack-contrib/rsbuild-plugin-publint):在构建后运行 `publint` 来检查 npm 包。 +- [Type Check 插件](https://github.com/rspack-contrib/rsbuild-plugin-type-check):用于在单独的进程中运行 TypeScript 类型检查。 +- [Image Compress 插件](https://github.com/rspack-contrib/rsbuild-plugin-image-compress):压缩图片资源。 +- [MDX 插件](https://github.com/rspack-contrib/rsbuild-plugin-mdx):提供 MDX 支持。 +- [Node Polyfill 插件](https://github.com/rspack-contrib/rsbuild-plugin-node-polyfill):用于注入 Node 核心模块在浏览器端的 polyfills。 +- [Source Build 插件](https://github.com/rspack-contrib/rsbuild-plugin-source-build):用于 monorepo 场景,支持引用其他子目录的源代码,并完成构建和热更新。 +- [Check Syntax 插件](https://github.com/rspack-contrib/rsbuild-plugin-check-syntax):检查构建产物的语法兼容性,判断是否存在导致兼容性问题的高级语法。 +- [CSS Minimizer 插件](https://github.com/rspack-contrib/rsbuild-plugin-css-minimizer):用于自定义 CSS 压缩工具,切换到 [cssnano](https://github.com/cssnano/cssnano) 或其他工具进行 CSS 压缩。 +- [Typed CSS Modules 插件](https://github.com/rspack-contrib/rsbuild-plugin-typed-css-modules):用于为 CSS Modules 文件生成类型声明。 +- [Pug 插件](https://github.com/rspack-contrib/rsbuild-plugin-pug):提供对 Pug 模板引擎的支持。 +- [Rem 插件](https://github.com/rspack-contrib/rsbuild-plugin-rem):用于实现移动端页面的 rem 自适应布局。 +- [UMD 插件](https://github.com/rspack-contrib/rsbuild-plugin-umd):用于构建 UMD 格式的产物。 +- [YAML 插件](https://github.com/rspack-contrib/rsbuild-plugin-yaml):引用 YAML 文件,并将其转换为 JavaScript 对象。 +- [TOML 插件](https://github.com/rspack-contrib/rsbuild-plugin-toml):引用 TOML 文件,并将其转换为 JavaScript 对象。 + +:::tip +你可以在 [web-infra-dev/rsbuild](https://github.com/web-infra-dev/rsbuild) 和 [rspack-contrib](https://github.com/rspack-contrib) 中找到这些插件的源代码。 +::: + +## 社区插件 + +你可以在 [awesome-rspack - Rsbuild Plugins](https://github.com/web-infra-dev/awesome-rspack?tab=readme-ov-file#rsbuild-plugins) 中查看社区提供的 Rsbuild 插件。 + +也可以在 npm 上搜索 [rsbuild-plugin](https://www.npmjs.com/search?q=rsbuild-plugin&ranking=popularity) 关键词来发现更多 Rsbuild 插件。 diff --git a/website/docs/zh/config/build/resolve.mdx b/website/docs/zh/config/build/resolve.mdx new file mode 100644 index 00000000..dfa85a2a --- /dev/null +++ b/website/docs/zh/config/build/resolve.mdx @@ -0,0 +1,23 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# resolve + +与模块解析相关的选项。 + +## resolve.aliasStrategy + +控制 `resolve.alias` 选项与 `tsconfig.json` 中的 `paths` 选项的优先级。 + +## resolve.alias + +设置模块路径的别名,用于简化导入路径或重定向模块引用,类似于 Rspack 的 [resolve.alias](https://rspack.rs/zh/config/resolve#resolvealias) 配置。 + +对于 TypeScript 项目,你只需要在 `tsconfig.json` 中配置 [compilerOptions.paths](https://www.typescriptlang.org/tsconfig/#paths) 即可,Rstest 会自动识别它,不需要额外配置 `resolve.alias` 字段。 + +## resolve.dedupe + +强制 Rstest 从项目根目录解析指定的包,这可以用于移除重复包和减少包大小。 + +## resolve.extensions + +自动添加导入文件的扩展名。这意味着你可以导入文件,而不需要显式地写它们的扩展名。 diff --git a/website/docs/zh/config/build/source.mdx b/website/docs/zh/config/build/source.mdx new file mode 100644 index 00000000..32ae00a0 --- /dev/null +++ b/website/docs/zh/config/build/source.mdx @@ -0,0 +1,32 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# source + +与输入的源代码相关的选项。 + +## source.decorators + +用于配置装饰器语法。 + +## source.define + +构建时将代码中的变量替换成其它值或者表达式,可以用于在构建时向代码注入环境变量等信息。 + +## source.exclude + +排除不需要被 [SWC](https://rsbuild.rs/zh/guide/configuration/swc) 转译的 JavaScript 或 TypeScript 文件。 + +::: note + +在 `source.exclude` 中配置的文件不会经过 SWC 转译,但被引用的文件仍然会被打包到产物中。 + +如果你希望某些文件不被打包到产物中,可以使用 [output.externals](/config/build/output#outputexternals) 配置项或 Rspack 的 [IgnorePlugin](https://rspack.rs/zh/plugins/webpack/ignore-plugin)。 +::: + +## source.include + +指定额外需要编译的 JavaScript 文件。 + +## source.tsconfigPath + +配置自定义的 `tsconfig.json` 文件路径,可以是相对路径或绝对路径。 diff --git a/website/docs/zh/config/build/tools.mdx b/website/docs/zh/config/build/tools.mdx new file mode 100644 index 00000000..adb9e874 --- /dev/null +++ b/website/docs/zh/config/build/tools.mdx @@ -0,0 +1,17 @@ +import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; + +# tools + +与底层工具相关的选项。 + +## tools.bundlerChain + +[rspack-chain](https://github.com/rspack-contrib/rspack-chain) 是一个用于配置 Rspack 的工具库,通过 `tools.bundlerChain` 可以调用 `rspack-chain` 以修改默认的 Rspack 配置。 + +## tools.rspack + +`tools.rspack` 选项用于修改 [Rspack](https://rspack.rs/zh/config/index) 的配置项。 + +## tools.swc + +通过 `tools.swc` 可以设置 [builtin:swc-loader](https://rspack.rs/zh/guide/features/builtin-swc-loader) 的选项。 diff --git a/website/docs/zh/config/test/_meta.json b/website/docs/zh/config/test/_meta.json index 8bc2ccdc..88d7e809 100644 --- a/website/docs/zh/config/test/_meta.json +++ b/website/docs/zh/config/test/_meta.json @@ -4,5 +4,8 @@ "includeSource", "globals", "setupFiles", - "testEnvironment" + "testEnvironment", + "retry", + "root", + "passWithNoTests" ] diff --git a/website/docs/zh/config/test/passWithNoTests.mdx b/website/docs/zh/config/test/passWithNoTests.mdx new file mode 100644 index 00000000..7aca78e0 --- /dev/null +++ b/website/docs/zh/config/test/passWithNoTests.mdx @@ -0,0 +1,16 @@ +# passWithNoTests + +- **类型:** `boolean` +- **默认值:** `false` + +标记测试通过当未找到测试用例时。 + +默认情况下,当未找到测试用例时,Rstest 会将测试标记为失败。你可以将 `passWithNoTests` 设置为 `true` 来允许测试在未找到测试用例时通过。 + +```ts title="rstest.config.ts" +import { defineConfig } from '@rstest/core'; + +export default defineConfig({ + passWithNoTests: true, +}); +``` diff --git a/website/docs/zh/config/test/retry.mdx b/website/docs/zh/config/test/retry.mdx new file mode 100644 index 00000000..0ea56815 --- /dev/null +++ b/website/docs/zh/config/test/retry.mdx @@ -0,0 +1,14 @@ +# retry + +- **类型:** `number` +- **默认值:** `0` + +如果测试执行失败,则重试特定次数。 + +```ts title="rstest.config.ts" +import { defineConfig } from '@rstest/core'; + +export default defineConfig({ + retry: 2, +}); +``` diff --git a/website/docs/zh/config/test/root.mdx b/website/docs/zh/config/test/root.mdx new file mode 100644 index 00000000..abeeaf1a --- /dev/null +++ b/website/docs/zh/config/test/root.mdx @@ -0,0 +1,6 @@ +# root + +- **类型:** `string` +- **默认值:** [process.cwd()](https://nodejs.org/api/process.html#processcwd) + +指定项目根目录。可以是绝对路径,也可以是相对于 `process.cwd()` 的路径。 diff --git a/website/docs/zh/guide/advanced/_meta.json b/website/docs/zh/guide/advanced/_meta.json index a8ba5eff..1f5d11b1 100644 --- a/website/docs/zh/guide/advanced/_meta.json +++ b/website/docs/zh/guide/advanced/_meta.json @@ -1 +1 @@ -["profiling"] +["debug-mode", "profiling"] diff --git a/website/docs/zh/guide/advanced/debug-mode.mdx b/website/docs/zh/guide/advanced/debug-mode.mdx new file mode 100644 index 00000000..87594be7 --- /dev/null +++ b/website/docs/zh/guide/advanced/debug-mode.mdx @@ -0,0 +1,46 @@ +# 开启调试模式 + +为了便于排查问题,Rstest 提供了调试模式,你可以在执行构建时添加 `DEBUG=rstest` 环境变量来开启 Rstest 的调试模式。 + +```bash +DEBUG=rstest pnpm test +``` + +在调试模式下,Rstest 会将测试中间产物输出到磁盘,并将内部最终生成的 Rstest 配置、Rsbuild 配置和 Rspack 配置写入到产物目录下,便于开发者查看和调试。 + +## Rstest 配置文件 + +在调试模式下,Rstest 会自动生成 `dist/.rsbuild/rstest.config.mjs` 文件,这里面包含了最终生成的 Rstest 配置。在这个文件里,你可以了解到你传入的 Rstest 配置在经过框架层和 Rstest 处理后的最终结果。 + +该文件的大致内容如下: + +```js title="rstest.config.mjs" +export default { + name: 'rstest', + include: ['**/*.{test,spec}.?(c|m)[jt]s?(x)'], + exclude: [ + '**/node_modules/**', + '**/dist/**', + '**/.{idea,git,cache,output,temp}/**', + '**/dist/.rstest-temp', + ], + includeSource: [], + pool: { + type: 'forks', + }, + isolate: true, + globals: false, + passWithNoTests: false, + update: false, + testTimeout: 5000, + testEnvironment: 'node', + retry: 0, + clearMocks: false, + resetMocks: false, + restoreMocks: false, + slowTestThreshold: 300, + // other configs... +}; +``` + +关于 Rstest 配置项的完整介绍,请查看[配置 Rstest](/guide/basic/configure-rstest) 章节。 diff --git a/website/package.json b/website/package.json index 8a2e3966..2572f62c 100644 --- a/website/package.json +++ b/website/package.json @@ -10,7 +10,7 @@ }, "devDependencies": { "@rsbuild/plugin-sass": "^1.3.2", - "@rspress/plugin-llms": "2.0.0-beta.16", + "@rspress/plugin-llms": "2.0.0-beta.18", "@rstack-dev/doc-ui": "1.10.6", "@rstest/tsconfig": "workspace:*", "@types/node": "^22.13.8", @@ -20,7 +20,7 @@ "react-dom": "^19.1.0", "rsbuild-plugin-google-analytics": "^1.0.3", "rsbuild-plugin-open-graph": "^1.0.2", - "rspress": "^2.0.0-beta.16", + "rspress": "^2.0.0-beta.18", "rspress-plugin-font-open-sans": "^1.0.0", "rspress-plugin-sitemap": "^1.2.0", "typescript": "^5.8.3" diff --git a/website/rspress.config.ts b/website/rspress.config.ts index 95dab32d..dcd61bbe 100644 --- a/website/rspress.config.ts +++ b/website/rspress.config.ts @@ -3,9 +3,9 @@ import { pluginSass } from '@rsbuild/plugin-sass'; import { pluginLlms } from '@rspress/plugin-llms'; import { pluginGoogleAnalytics } from 'rsbuild-plugin-google-analytics'; import { pluginOpenGraph } from 'rsbuild-plugin-open-graph'; +import { defineConfig } from 'rspress/config'; import { pluginFontOpenSans } from 'rspress-plugin-font-open-sans'; import pluginSitemap from 'rspress-plugin-sitemap'; -import { defineConfig } from 'rspress/config'; const siteUrl = 'https://rstest.rs'; const description = 'The Rspack-based testing framework'; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy