diff --git a/e2e/lifecycle/fixtures/beforeEach.test.ts b/e2e/lifecycle/fixtures/beforeEach.test.ts index 2c477493..fc1a12f5 100644 --- a/e2e/lifecycle/fixtures/beforeEach.test.ts +++ b/e2e/lifecycle/fixtures/beforeEach.test.ts @@ -34,7 +34,8 @@ describe('level A', () => { expect(2 + 2).toBe(4); }); - beforeEach(() => { + beforeEach((ctx) => { + expect(ctx.task.name).toBe('it in level B-B'); console.log('[beforeEach] in level B-B'); }); }); diff --git a/e2e/lifecycle/fixtures/onTestFailed.test.ts b/e2e/lifecycle/fixtures/onTestFailed.test.ts index c0199168..49a3101f 100644 --- a/e2e/lifecycle/fixtures/onTestFailed.test.ts +++ b/e2e/lifecycle/fixtures/onTestFailed.test.ts @@ -9,7 +9,7 @@ import { beforeEach(() => { onTestFailed(({ task }) => { - console.log('[onTestFailed]', task.result.name); + console.log('[onTestFailed]', task.result?.name); }); }); describe('level A', () => { diff --git a/e2e/scripts/index.ts b/e2e/scripts/index.ts index 3186c3e6..129900a2 100644 --- a/e2e/scripts/index.ts +++ b/e2e/scripts/index.ts @@ -107,7 +107,7 @@ export async function runRstestCli({ }); onTestFailed?.(({ task }) => { - if (task.result.errors?.[0]) { + if (task.result?.errors?.[0]) { task.result.errors![0]!.message += `\n\n--- CLI Log Start ---\n${cli.log}\n--- CLI Log End ---\n`; } diff --git a/packages/core/src/runtime/runner/runner.ts b/packages/core/src/runtime/runner/runner.ts index 508490fc..b37a1edf 100644 --- a/packages/core/src/runtime/runner/runner.ts +++ b/packages/core/src/runtime/runner/runner.ts @@ -100,9 +100,15 @@ export class TestRunner { const cleanups: AfterEachListener[] = []; + const fixtureCleanups = await this.beforeRunTest( + test, + snapshotClient.getSnapshotState(testPath), + ); + cleanups.push(...fixtureCleanups); + try { for (const fn of parentHooks.beforeEachListeners) { - const cleanupFn = await fn(); + const cleanupFn = await fn(test.context); cleanupFn && cleanups.push(cleanupFn); } } catch (error) { @@ -120,11 +126,6 @@ export class TestRunner { if (result?.status !== 'fail') { if (test.fails) { try { - const fixtureCleanups = await this.beforeRunTest( - test, - snapshotClient.getSnapshotState(testPath), - ); - cleanups.push(...fixtureCleanups); await test.fn?.(test.context); this.afterRunTest(test); @@ -153,11 +154,6 @@ export class TestRunner { } } else { try { - const fixtureCleanups = await this.beforeRunTest( - test, - snapshotClient.getSnapshotState(testPath), - ); - cleanups.push(...fixtureCleanups); if (test.fn) { const fn = wrapTimeout({ name: 'test', @@ -203,9 +199,10 @@ export class TestRunner { .concat(cleanups) .concat(test.onFinished); + test.context.task.result = result; try { for (const fn of afterEachFns) { - await fn({ task: { result } }); + await fn(test.context); } } catch (error) { result.status = 'fail'; @@ -216,7 +213,7 @@ export class TestRunner { if (result.status === 'fail') { for (const fn of [...test.onFailed].reverse()) { try { - await fn({ task: { result } }); + await fn(test.context); } catch (error) { result.errors ??= []; result.errors.push(...formatTestError(error)); @@ -520,7 +517,7 @@ export class TestRunner { } } - private createTestContext(): TestContext { + private createTestContext(test: TestCase): TestContext { const context = (() => { throw new Error('done() callback is deprecated, use promise instead'); }) as unknown as TestContext; @@ -529,6 +526,8 @@ export class TestRunner { const current = this._test; + context.task = { name: test.name }; + Object.defineProperty(context, 'expect', { get: () => { if (!_expect) { @@ -620,7 +619,7 @@ export class TestRunner { (globalThis as any)[GLOBAL_EXPECT], ); - const context = this.createTestContext(); + const context = this.createTestContext(test); const { cleanups } = await handleFixtures(test, context); diff --git a/packages/core/src/types/api.ts b/packages/core/src/types/api.ts index 865969f6..8be3ecb5 100644 --- a/packages/core/src/types/api.ts +++ b/packages/core/src/types/api.ts @@ -11,6 +11,15 @@ import type { import type { MaybePromise } from './utils'; export type TestContext = { + /** + * Metadata of the current test + */ + task: { + /** Test name provided by user */ + name: string; + /** Result of the current test, undefined if the test is not run yet */ + result?: TestResult; + }; expect: RstestExpect; onTestFinished: RunnerAPI['onTestFinished']; onTestFailed: RunnerAPI['onTestFailed']; @@ -157,13 +166,9 @@ export type TestAPIs = TestAPI & { }>; }; -export type OnTestFinishedHandler = (params: { - task: { result: Readonly }; -}) => MaybePromise; +export type OnTestFinishedHandler = (ctx: TestContext) => MaybePromise; -export type OnTestFailedHandler = (params: { - task: { result: Readonly }; -}) => MaybePromise; +export type OnTestFailedHandler = (ctx: TestContext) => MaybePromise; export type RunnerAPI = { describe: DescribeAPI; diff --git a/packages/core/src/types/testSuite.ts b/packages/core/src/types/testSuite.ts index 575eb981..79a70589 100644 --- a/packages/core/src/types/testSuite.ts +++ b/packages/core/src/types/testSuite.ts @@ -78,13 +78,16 @@ export type SuiteContext = { }; export type AfterAllListener = (ctx: SuiteContext) => MaybePromise; + export type BeforeAllListener = ( ctx: SuiteContext, ) => MaybePromise; -export type AfterEachListener = (params: { - task: { result: Readonly }; -}) => MaybePromise; -export type BeforeEachListener = () => MaybePromise; + +export type AfterEachListener = (ctx: TestContext) => MaybePromise; + +export type BeforeEachListener = ( + ctx: TestContext, +) => MaybePromise; export type TestSuiteInfo = { testId: string; diff --git a/website/docs/en/api/test-api/hooks.mdx b/website/docs/en/api/test-api/hooks.mdx index bb4277aa..429e9a8d 100644 --- a/website/docs/en/api/test-api/hooks.mdx +++ b/website/docs/en/api/test-api/hooks.mdx @@ -52,7 +52,7 @@ afterAll(async (ctx) => { ## beforeEach -- **Type:** `(fn: () => void | Promise, timeout?: number) => void` +- **Type:** `(fn: (ctx: TestContext) => void | Promise, timeout?: number) => void` Runs before each test in the current suite. @@ -81,7 +81,7 @@ beforeEach(async () => { ## afterEach -- **Type:** `(fn: (ctx: { task: { result: Readonly } }) => void | Promise, timeout?: number) => void` +- **Type:** `(fn: (ctx: TestContext) => void | Promise, timeout?: number) => void` Runs after each test in the current suite. @@ -139,7 +139,7 @@ test('test server', () => { const server = startServer(); onTestFailed(({ task }) => { - console.log(task.result.errors); + console.log(task.result?.errors); }); server.listen(3000, () => { diff --git a/website/docs/en/api/test-api/test.mdx b/website/docs/en/api/test-api/test.mdx index 0ee5fe2a..0ce7bdc1 100644 --- a/website/docs/en/api/test-api/test.mdx +++ b/website/docs/en/api/test-api/test.mdx @@ -239,6 +239,15 @@ testWithUser('has user in context', ({ user, expect }) => { ```ts export interface TestContext { + /** + * Metadata of the current test + */ + task: { + /** Test name provided by user */ + name: string; + /** Result of the current test, undefined if the test is not run yet */ + result?: TestResult; + }; /** The `expect` API bound to the current test */ expect: Expect; /** The `onTestFinished` hook bound to the current test */ diff --git a/website/docs/zh/api/test-api/hooks.mdx b/website/docs/zh/api/test-api/hooks.mdx index 9577b515..b4cbaea1 100644 --- a/website/docs/zh/api/test-api/hooks.mdx +++ b/website/docs/zh/api/test-api/hooks.mdx @@ -52,7 +52,7 @@ afterAll(async (ctx) => { ## beforeEach -- **类型:** `(fn: () => void | Promise, timeout?: number) => void` +- **类型:** `(fn: (ctx: TestContext) => void | Promise, timeout?: number) => void` 在当前套件的每个测试之前运行。 @@ -81,7 +81,7 @@ beforeEach(async () => { ## afterEach -- **类型:** `(fn: (ctx: { task: { result: Readonly } }) => void | Promise, timeout?: number) => void` +- **类型:** `(fn: (ctx: TestContext) => void | Promise, timeout?: number) => void` 在当前套件的每个测试之后运行。 @@ -139,7 +139,7 @@ test('test server', () => { const server = startServer(); onTestFailed(({ task }) => { - console.log(task.result.errors); + console.log(task.result?.errors); }); server.listen(3000, () => { diff --git a/website/docs/zh/api/test-api/test.mdx b/website/docs/zh/api/test-api/test.mdx index c114f6e8..322a2964 100644 --- a/website/docs/zh/api/test-api/test.mdx +++ b/website/docs/zh/api/test-api/test.mdx @@ -228,6 +228,15 @@ testWithUser('has user in context', ({ user, expect }) => { ```ts export interface TestContext { + /** + * Metadata of the current test + */ + task: { + /** Test name provided by user */ + name: string; + /** Result of the current test, undefined if the test is not run yet */ + result?: TestResult; + }; /** The `expect` API bound to the current test */ expect: Expect; /** The `onTestFinished` hook bound to the current test */