From d5c5598c4260bf477364e05893529a2d8ca3bc96 Mon Sep 17 00:00:00 2001 From: neverland Date: Mon, 13 Jul 2026 12:05:33 +0800 Subject: [PATCH 1/3] test: use shared test utilities --- packages/rstack/package.json | 1 + .../test/cli/specify-config/index.test.ts | 11 +- .../test/config/define-app/index.test.ts | 9 +- .../test/config/define-doc/index.test.ts | 10 +- .../test/config/define-lib/index.test.ts | 10 +- .../config/reload-app-config/index.test.ts | 16 +- packages/rstack/test/helpers/cli.ts | 2 +- packages/rstack/test/helpers/cliTest.ts | 14 +- packages/rstack/test/helpers/constants.ts | 1 - packages/rstack/test/helpers/file.ts | 78 -------- packages/rstack/test/helpers/index.ts | 4 - packages/rstack/test/helpers/logs.ts | 180 ------------------ packages/rstack/test/helpers/utils.ts | 61 ------ pnpm-lock.yaml | 11 ++ pnpm-workspace.yaml | 1 + 15 files changed, 52 insertions(+), 357 deletions(-) delete mode 100644 packages/rstack/test/helpers/constants.ts delete mode 100644 packages/rstack/test/helpers/file.ts delete mode 100644 packages/rstack/test/helpers/logs.ts delete mode 100644 packages/rstack/test/helpers/utils.ts diff --git a/packages/rstack/package.json b/packages/rstack/package.json index 16679b0..2072971 100644 --- a/packages/rstack/package.json +++ b/packages/rstack/package.json @@ -63,6 +63,7 @@ }, "devDependencies": { "@rspress/core": "catalog:", + "@rstackjs/test-utils": "catalog:", "@rstest/adapter-rsbuild": "catalog:", "@rstest/adapter-rslib": "catalog:", "@types/node": "catalog:", diff --git a/packages/rstack/test/cli/specify-config/index.test.ts b/packages/rstack/test/cli/specify-config/index.test.ts index 1c29f88..99a4d5e 100644 --- a/packages/rstack/test/cli/specify-config/index.test.ts +++ b/packages/rstack/test/cli/specify-config/index.test.ts @@ -1,13 +1,12 @@ -import { rm } from 'node:fs/promises'; -import path from 'node:path'; -import { getDistFiles, getFileContent, test } from '#test-helpers'; +import { getDistFiles, getFileContent } from '@rstackjs/test-utils'; +import { test } from '#test-helpers'; -test('should build with rstack --config', async ({ cwd, execCli, expect }) => { - await rm(path.join(cwd, 'dist'), { recursive: true, force: true }); +test('should build with rstack --config', async ({ prepareDist, execCli, expect }) => { + const distPath = await prepareDist(); execCli('build --config ./custom.config.ts'); - const files = await getDistFiles(path.join(cwd, 'dist')); + const files = await getDistFiles(distPath); const output = getFileContent(files, 'static/js/index.js'); expect(output).toContain('specify config works'); diff --git a/packages/rstack/test/config/define-app/index.test.ts b/packages/rstack/test/config/define-app/index.test.ts index f74cc13..73bbe51 100644 --- a/packages/rstack/test/config/define-app/index.test.ts +++ b/packages/rstack/test/config/define-app/index.test.ts @@ -1,12 +1,11 @@ import { rm } from 'node:fs/promises'; -import path from 'node:path'; -import { getDistFiles, getFileContent, test } from '#test-helpers'; +import { getDistFiles, getFileContent } from '@rstackjs/test-utils'; +import { test } from '#test-helpers'; const expectedText = 'define.app works'; -test('should build app with define.app config', async ({ cwd, execCli, expect }) => { - const distPath = path.join(cwd, 'dist'); - await rm(distPath, { recursive: true, force: true }); +test('should build app with define.app config', async ({ prepareDist, execCli, expect }) => { + const distPath = await prepareDist(); try { execCli('build'); diff --git a/packages/rstack/test/config/define-doc/index.test.ts b/packages/rstack/test/config/define-doc/index.test.ts index 9ae0ae6..464e758 100644 --- a/packages/rstack/test/config/define-doc/index.test.ts +++ b/packages/rstack/test/config/define-doc/index.test.ts @@ -1,12 +1,10 @@ -import { rm } from 'node:fs/promises'; -import path from 'node:path'; -import { getDistFiles, getFileContent, test } from '#test-helpers'; +import { getDistFiles, getFileContent } from '@rstackjs/test-utils'; +import { test } from '#test-helpers'; const expectedText = 'define.doc works'; -test('should build docs with define.doc config', async ({ cwd, execCli, expect }) => { - const distPath = path.join(cwd, 'doc_build'); - await rm(distPath, { recursive: true, force: true }); +test('should build docs with define.doc config', async ({ prepareDist, execCli, expect }) => { + const distPath = await prepareDist('doc_build'); execCli('doc build'); diff --git a/packages/rstack/test/config/define-lib/index.test.ts b/packages/rstack/test/config/define-lib/index.test.ts index 24f5c67..53435b7 100644 --- a/packages/rstack/test/config/define-lib/index.test.ts +++ b/packages/rstack/test/config/define-lib/index.test.ts @@ -1,12 +1,10 @@ -import { rm } from 'node:fs/promises'; -import path from 'node:path'; -import { getDistFiles, getFileContent, test } from '#test-helpers'; +import { getDistFiles, getFileContent } from '@rstackjs/test-utils'; +import { test } from '#test-helpers'; const expectedText = 'define.lib works'; -test('should build lib with define.lib config', async ({ cwd, execCli, expect }) => { - const distPath = path.join(cwd, 'dist'); - await rm(distPath, { recursive: true, force: true }); +test('should build lib with define.lib config', async ({ prepareDist, execCli, expect }) => { + const distPath = await prepareDist(); execCli('lib'); diff --git a/packages/rstack/test/config/reload-app-config/index.test.ts b/packages/rstack/test/config/reload-app-config/index.test.ts index d7c6c10..cc7d4d2 100644 --- a/packages/rstack/test/config/reload-app-config/index.test.ts +++ b/packages/rstack/test/config/reload-app-config/index.test.ts @@ -1,16 +1,16 @@ import { rm, writeFile } from 'node:fs/promises'; import path from 'node:path'; -import { expectFile, getRandomPort, test } from '#test-helpers'; +import { getRandomPort, waitForFile } from '@rstackjs/test-utils'; +import { test } from '#test-helpers'; test('should restart dev server and reload config when Rstack config changes', async ({ + prepareDist, execCliAsync, }) => { - const dist1 = path.join(import.meta.dirname, 'dist'); - const dist2 = path.join(import.meta.dirname, 'dist-2'); + const dist1 = await prepareDist(); + const dist2 = await prepareDist('dist-2'); const configFile = path.join(import.meta.dirname, 'test-temp-rstack.config.ts'); - await rm(dist1, { recursive: true, force: true }); - await rm(dist2, { recursive: true, force: true }); await rm(configFile, { force: true }); await writeFile( @@ -28,7 +28,7 @@ define.app({ execCliAsync('dev --config test-temp-rstack.config.ts'); - await expectFile(dist1); + await waitForFile(dist1, { interval: 50 }); await writeFile( configFile, @@ -46,7 +46,7 @@ define.app({ `, ); - await expectFile(dist2); + await waitForFile(dist2, { interval: 50 }); }, 30_000); test('should reload config when an imported file changes', async ({ execCliAsync, logHelper }) => { @@ -66,7 +66,7 @@ define.app({ ); execCliAsync('dev --config test-temp-import.config.ts'); - await logHelper.expectBuildEnd(); + await logHelper.expectLog('built in'); logHelper.clearLogs(); await writeFile(importedFile, '// changed\n'); diff --git a/packages/rstack/test/helpers/cli.ts b/packages/rstack/test/helpers/cli.ts index 9693df5..6046db4 100644 --- a/packages/rstack/test/helpers/cli.ts +++ b/packages/rstack/test/helpers/cli.ts @@ -1,6 +1,6 @@ import { type ExecSyncOptions, execSync } from 'node:child_process'; import path from 'node:path'; -import type { LogHelper } from './logs.ts'; +import type { LogHelper } from '@rstackjs/test-utils'; export const RSTACK_BIN_PATH: string = path.join(import.meta.dirname, '../../bin/rs.js'); diff --git a/packages/rstack/test/helpers/cliTest.ts b/packages/rstack/test/helpers/cliTest.ts index df0ba85..1ef4c2f 100644 --- a/packages/rstack/test/helpers/cliTest.ts +++ b/packages/rstack/test/helpers/cliTest.ts @@ -1,8 +1,12 @@ import { type ChildProcess, type SpawnOptions, spawn as nodeSpawn } from 'node:child_process'; import path from 'node:path'; +import { + type ExtendedLogHelper, + prepareDist as basePrepareDist, + proxyConsole, +} from '@rstackjs/test-utils'; import { test as baseTest } from 'rstack/test'; import { execCli as baseExecCli, type ExecCli, RSTACK_BIN_PATH } from './cli.ts'; -import { type ExtendedLogHelper, proxyConsole } from './logs.ts'; type Exec = ( command: string, @@ -11,12 +15,15 @@ type Exec = ( childProcess: ChildProcess; }; +type PrepareDist = (distFolderName?: string) => Promise; + export type CliTestFixtures = { cwd: string; exec: Exec; execCli: ExecCli; execCliAsync: Exec; logHelper: ExtendedLogHelper; + prepareDist: PrepareDist; }; type CliTest = ReturnType>; @@ -49,6 +56,11 @@ export const test: CliTest = baseTest.extend({ await use(path.dirname(testPath)); }, + prepareDist: async ({ cwd }, use) => { + const prepareDist: PrepareDist = (distFolderName = 'dist') => + basePrepareDist(path.join(cwd, distFolderName)); + await use(prepareDist); + }, logHelper: [ async ({ onTestFailed, task }, use) => { const logHelper = proxyConsole(); diff --git a/packages/rstack/test/helpers/constants.ts b/packages/rstack/test/helpers/constants.ts deleted file mode 100644 index 5cac85f..0000000 --- a/packages/rstack/test/helpers/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const BUILD_END_LOG = 'built in'; diff --git a/packages/rstack/test/helpers/file.ts b/packages/rstack/test/helpers/file.ts deleted file mode 100644 index 4786ce0..0000000 --- a/packages/rstack/test/helpers/file.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { readdir, readFile } from 'node:fs/promises'; -import path from 'node:path'; -import { styleText } from 'node:util'; - -export type DistFiles = Record; -export type FileMatcher = string | RegExp | ((file: string) => boolean); -export type FindFileOptions = { - ignoreHash?: boolean; -}; - -const HASH_PATTERN = /\.[0-9a-z]{8,}(?=\.)/gi; - -const toPosixPath = (filePath: string) => filePath.replace(/\\/g, '/'); - -const toMatcherFn = (matcher: FileMatcher): ((file: string) => boolean) => { - if (typeof matcher === 'function') { - return matcher; - } - if (typeof matcher === 'string') { - return (file) => file.endsWith(toPosixPath(matcher)); - } - return (file) => matcher.test(file); -}; - -export const getDistFiles = async (distPath: string, sourceMaps = false): Promise => { - const files: DistFiles = {}; - const root = path.resolve(distPath); - - const readDir = async (dir: string) => { - const entries = (await readdir(dir, { withFileTypes: true })).sort((a, b) => - a.name.localeCompare(b.name), - ); - - await Promise.all( - entries.map(async (entry) => { - const filePath = path.join(dir, entry.name); - - if (entry.isDirectory()) { - await readDir(filePath); - return; - } - if (!entry.isFile() || (!sourceMaps && filePath.endsWith('.map'))) { - return; - } - - files[toPosixPath(filePath)] = await readFile(filePath, 'utf-8'); - }), - ); - }; - - await readDir(root); - return files; -}; - -export const findFile = ( - files: DistFiles, - matcher: FileMatcher, - options: FindFileOptions = {}, -): string => { - const { ignoreHash = true } = options; - const matcherFn = toMatcherFn(matcher); - - for (const file of Object.keys(files).sort()) { - const comparable = ignoreHash ? file.replace(HASH_PATTERN, '') : file; - - if (matcherFn(comparable)) { - return file; - } - } - - throw new Error(`Unable to find file matching "${styleText('cyan', matcher.toString())}"`); -}; - -export const getFileContent = ( - files: DistFiles, - matcher: FileMatcher, - options?: FindFileOptions, -): string => files[findFile(files, matcher, options)]; diff --git a/packages/rstack/test/helpers/index.ts b/packages/rstack/test/helpers/index.ts index 54dafdf..a6fc95b 100644 --- a/packages/rstack/test/helpers/index.ts +++ b/packages/rstack/test/helpers/index.ts @@ -1,6 +1,2 @@ export * from './cli.ts'; export * from './cliTest.ts'; -export * from './constants.ts'; -export * from './file.ts'; -export * from './logs.ts'; -export * from './utils.ts'; diff --git a/packages/rstack/test/helpers/logs.ts b/packages/rstack/test/helpers/logs.ts deleted file mode 100644 index 5fc6ded..0000000 --- a/packages/rstack/test/helpers/logs.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { stripVTControlCharacters as stripAnsi, styleText } from 'node:util'; -import type { ConsoleType } from '@rsbuild/core'; -import { BUILD_END_LOG } from './constants.ts'; -import { toPosixPath } from './utils.ts'; - -export type LogPattern = string | RegExp | ((log: string) => boolean); - -export type MatchPatternOptions = { - /** - * Whether to use exact line matching instead of substring matching - * @default false - */ - strict?: boolean; - /** - * Whether to convert file paths to POSIX format before matching - * @default false - */ - posix?: boolean; -}; - -const matchPattern = (log: string, pattern: LogPattern, options: MatchPatternOptions = {}) => { - const logToCheck = options.posix ? toPosixPath(log) : log; - if (typeof pattern === 'string') { - return options.strict - ? logToCheck.split('\n').some((line) => line.trim() === pattern.trim()) - : logToCheck.includes(pattern); - } - if (pattern instanceof RegExp) { - return pattern.test(logToCheck); - } - return pattern(logToCheck); -}; - -export type LogHelper = { - logs: string[]; - originalLogs: string[]; - addLog: (input: string) => void; - clearLogs: () => void; - expectLog: (pattern: LogPattern, options?: MatchPatternOptions) => Promise; - expectNoLog: (pattern: LogPattern, options?: MatchPatternOptions) => void; - expectBuildEnd: () => Promise; -}; - -export const createLogHelper = (): LogHelper => { - const logs: string[] = []; - const originalLogs: string[] = []; - - const logPatterns = new Set<{ - pattern: LogPattern; - resolve: (value: boolean) => void; - options: MatchPatternOptions; - }>(); - - const clearLogs = () => { - logs.splice(0); - }; - - const addLog = (input: string) => { - const log = stripAnsi(input); - logs.push(log); - originalLogs.push(input); - - for (const { pattern, resolve, options } of logPatterns) { - if (matchPattern(log, pattern, options)) { - resolve(true); - } - } - }; - - const expectLog = async (pattern: LogPattern, options: MatchPatternOptions = {}) => { - if (logs.some((log) => matchPattern(log, pattern, options))) { - return true; - } - - return new Promise((resolve, reject) => { - const timeoutId = setTimeout(() => { - const title = styleText( - ['bold', 'red'], - 'Timeout: Expected log not found within 5 seconds.', - ); - const expect = styleText('yellow', pattern.toString()); - reject(new Error(`${title}\nExpect: ${expect}\nGet:\n${originalLogs.join('\n')}`)); - }, 5000); - - const patternEntry = { - pattern, - options, - resolve: (value: boolean) => { - clearTimeout(timeoutId); - logPatterns.delete(patternEntry); - resolve(value); - }, - }; - - logPatterns.add(patternEntry); - }); - }; - - const expectNoLog = (pattern: LogPattern, options: MatchPatternOptions = {}) => { - const result = logs.some((log) => matchPattern(log, pattern, options)); - - if (result) { - const title = styleText(['bold', 'red'], 'Unexpected log found.'); - const unexpected = styleText('yellow', pattern.toString()); - throw new Error(`${title}\nUnexpected: ${unexpected}\nGet:\n${originalLogs.join('\n')}`); - } - }; - - const expectBuildEnd = async () => expectLog(BUILD_END_LOG); - - return { - logs, - originalLogs, - addLog, - clearLogs, - expectLog, - expectNoLog, - expectBuildEnd, - }; -}; - -export type ProxyConsoleOptions = { - types?: ConsoleType | ConsoleType[]; -}; - -export type ExtendedLogHelper = LogHelper & { - /** - * Restore the original console methods - */ - restore: () => void; - /** - * Restore the original console methods and print the captured logs - */ - printCapturedLogs: () => void; -}; - -/** - * Proxy the console methods to capture the logs - */ -export const proxyConsole = ({ - types = ['log', 'warn', 'info', 'error'], -}: ProxyConsoleOptions = {}): ExtendedLogHelper => { - const restores: Array<() => void> = []; - const logHelper = createLogHelper(); - - for (const type of Array.isArray(types) ? types : [types]) { - const method = console[type]; - restores.push(() => { - console[type] = method; - }); - console[type] = (...args: unknown[]) => { - const logMessage = args - .map((arg) => { - if (typeof arg === 'string') { - return arg; - } - return typeof arg === 'object' ? JSON.stringify(arg) : String(arg); - }) - .join(' '); - logHelper.addLog(logMessage); - }; - } - - const restore = () => { - for (const restore of restores) { - restore(); - } - }; - - const printCapturedLogs = () => { - restore(); - console.log(logHelper.originalLogs.join('\n')); - }; - - return { - restore, - printCapturedLogs, - ...logHelper, - }; -}; diff --git a/packages/rstack/test/helpers/utils.ts b/packages/rstack/test/helpers/utils.ts deleted file mode 100644 index e50b1fa..0000000 --- a/packages/rstack/test/helpers/utils.ts +++ /dev/null @@ -1,61 +0,0 @@ -import fs from 'node:fs'; -import net from 'node:net'; -import { expect } from 'rstack/test'; - -export const toPosixPath: (filePath: string) => string = (filePath) => filePath.replace(/\\/g, '/'); - -function isPortAvailable(port: number) { - try { - const server = net.createServer().listen(port); - return new Promise((resolve) => { - server.on('listening', () => { - server.close(() => { - resolve(true); - }); - }); - server.on('error', () => { - resolve(false); - }); - }); - } catch { - return Promise.resolve(false); - } -} - -const portMap = new Map(); - -/** - * Get a random port - * Available port ranges: 1024 ~ 65535 - * `10080` is not available on macOS CI, `> 50000` get 'permission denied' on Windows. - * so we use `15000` ~ `45000`. - */ -export async function getRandomPort( - defaultPort: number = Math.ceil(Math.random() * 30000) + 15000, -): Promise { - let port = defaultPort; - while (port <= 65535) { - if (!portMap.get(port) && (await isPortAvailable(port))) { - portMap.set(port, 1); - return port; - } - port++; - } - throw new Error('No available ports found in the valid range.'); -} - -/** - * Expect a file to exist - */ -export const expectFile = (dir: string): Promise => - expectPoll(() => fs.existsSync(dir)).toBeTruthy(); - -/** - * A faster `expect.poll` - */ -export const expectPoll: typeof expect.poll = (fn) => { - return expect.poll(fn, { - interval: 50, - timeout: 5_000, - }); -}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3b7d3dd..a34be86 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,6 +25,9 @@ catalogs: '@rstackjs/load-config': specifier: ^0.1.2 version: 0.1.2 + '@rstackjs/test-utils': + specifier: ^0.2.0 + version: 0.2.0 '@rstest/adapter-rsbuild': specifier: ~0.11.0 version: 0.11.0 @@ -255,6 +258,9 @@ importers: '@rspress/core': specifier: 'catalog:' version: 2.0.17(@types/mdast@4.0.4)(@types/react@19.2.17)(micromark-util-types@2.0.2)(micromark@4.0.2) + '@rstackjs/test-utils': + specifier: 'catalog:' + version: 0.2.0 '@rstest/adapter-rsbuild': specifier: 'catalog:' version: 0.11.0(@rsbuild/core@2.1.4)(@rstest/core@0.11.0) @@ -778,6 +784,9 @@ packages: jiti: optional: true + '@rstackjs/test-utils@0.2.0': + resolution: {integrity: sha512-P+LOo1WE3xYeGkHmEthyq2cIpN69k4LhiB/4UBSceD+nW9hDlhWv8MC0LTLWokZXccWl4ntcfOBjQFllkcBlPA==} + '@rstest/adapter-rsbuild@0.11.0': resolution: {integrity: sha512-otrR3yqQ5Uyskm0hu8c0fjP1eFk6bMJALnYhUl6V1CKp/monoowFMa6XEqdY2d4aHv6oa8XWGLfU4LWne1Vg9A==} peerDependencies: @@ -2244,6 +2253,8 @@ snapshots: '@rstackjs/load-config@0.1.2': {} + '@rstackjs/test-utils@0.2.0': {} + '@rstest/adapter-rsbuild@0.11.0(@rsbuild/core@2.1.4)(@rstest/core@0.11.0)': dependencies: '@rsbuild/core': 2.1.4 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 05cee34..ac224e0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -17,6 +17,7 @@ catalog: '@rslint/core': '~0.6.5' '@rspress/core': '^2.0.17' '@rstackjs/load-config': ^0.1.2 + '@rstackjs/test-utils': ^0.2.0 '@rstest/adapter-rsbuild': '~0.11.0' '@rstest/adapter-rslib': '~0.11.0' '@rstest/core': '~0.11.0' From d087f148c3dd287cbb8ba7be5ed06f8b03391123 Mon Sep 17 00:00:00 2001 From: neverland Date: Mon, 13 Jul 2026 12:13:01 +0800 Subject: [PATCH 2/3] test: add expectBuildEnd log helper --- .../config/reload-app-config/index.test.ts | 2 +- packages/rstack/test/helpers/cliTest.ts | 7 ++---- packages/rstack/test/helpers/constants.ts | 1 + packages/rstack/test/helpers/index.ts | 1 + packages/rstack/test/helpers/logs.ts | 24 +++++++++++++++++++ 5 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 packages/rstack/test/helpers/constants.ts create mode 100644 packages/rstack/test/helpers/logs.ts diff --git a/packages/rstack/test/config/reload-app-config/index.test.ts b/packages/rstack/test/config/reload-app-config/index.test.ts index cc7d4d2..babe021 100644 --- a/packages/rstack/test/config/reload-app-config/index.test.ts +++ b/packages/rstack/test/config/reload-app-config/index.test.ts @@ -66,7 +66,7 @@ define.app({ ); execCliAsync('dev --config test-temp-import.config.ts'); - await logHelper.expectLog('built in'); + await logHelper.expectBuildEnd(); logHelper.clearLogs(); await writeFile(importedFile, '// changed\n'); diff --git a/packages/rstack/test/helpers/cliTest.ts b/packages/rstack/test/helpers/cliTest.ts index 1ef4c2f..cb583d4 100644 --- a/packages/rstack/test/helpers/cliTest.ts +++ b/packages/rstack/test/helpers/cliTest.ts @@ -1,12 +1,9 @@ import { type ChildProcess, type SpawnOptions, spawn as nodeSpawn } from 'node:child_process'; import path from 'node:path'; -import { - type ExtendedLogHelper, - prepareDist as basePrepareDist, - proxyConsole, -} from '@rstackjs/test-utils'; +import { prepareDist as basePrepareDist } from '@rstackjs/test-utils'; import { test as baseTest } from 'rstack/test'; import { execCli as baseExecCli, type ExecCli, RSTACK_BIN_PATH } from './cli.ts'; +import { type ExtendedLogHelper, proxyConsole } from './logs.ts'; type Exec = ( command: string, diff --git a/packages/rstack/test/helpers/constants.ts b/packages/rstack/test/helpers/constants.ts new file mode 100644 index 0000000..5cac85f --- /dev/null +++ b/packages/rstack/test/helpers/constants.ts @@ -0,0 +1 @@ +export const BUILD_END_LOG = 'built in'; diff --git a/packages/rstack/test/helpers/index.ts b/packages/rstack/test/helpers/index.ts index a6fc95b..691324c 100644 --- a/packages/rstack/test/helpers/index.ts +++ b/packages/rstack/test/helpers/index.ts @@ -1,2 +1,3 @@ export * from './cli.ts'; export * from './cliTest.ts'; +export * from './constants.ts'; diff --git a/packages/rstack/test/helpers/logs.ts b/packages/rstack/test/helpers/logs.ts new file mode 100644 index 0000000..2a0d19f --- /dev/null +++ b/packages/rstack/test/helpers/logs.ts @@ -0,0 +1,24 @@ +import { + type ExtendedLogHelper as BaseExtendedLogHelper, + type LogHelper as BaseLogHelper, + proxyConsole as baseProxyConsole, + type ProxyConsoleOptions, +} from '@rstackjs/test-utils'; +import { BUILD_END_LOG } from './constants.ts'; + +type ExpectBuildEnd = { + expectBuildEnd: () => Promise; +}; + +export type LogHelper = BaseLogHelper & ExpectBuildEnd; + +export type ExtendedLogHelper = BaseExtendedLogHelper & ExpectBuildEnd; + +export const proxyConsole = (options?: ProxyConsoleOptions): ExtendedLogHelper => { + const logHelper = baseProxyConsole(options); + + return { + ...logHelper, + expectBuildEnd: async () => logHelper.expectLog(BUILD_END_LOG), + }; +}; From f6ac23ced93c114b046c243199d80ffa82a3f8dd Mon Sep 17 00:00:00 2001 From: neverland Date: Mon, 13 Jul 2026 12:56:35 +0800 Subject: [PATCH 3/3] test: use default waitForFile interval --- packages/rstack/test/config/reload-app-config/index.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rstack/test/config/reload-app-config/index.test.ts b/packages/rstack/test/config/reload-app-config/index.test.ts index babe021..d4bcfb3 100644 --- a/packages/rstack/test/config/reload-app-config/index.test.ts +++ b/packages/rstack/test/config/reload-app-config/index.test.ts @@ -28,7 +28,7 @@ define.app({ execCliAsync('dev --config test-temp-rstack.config.ts'); - await waitForFile(dist1, { interval: 50 }); + await waitForFile(dist1); await writeFile( configFile, @@ -46,7 +46,7 @@ define.app({ `, ); - await waitForFile(dist2, { interval: 50 }); + await waitForFile(dist2); }, 30_000); test('should reload config when an imported file changes', async ({ execCliAsync, logHelper }) => {