diff --git a/src/create-test.ts b/src/create-test.ts index 6203cc4..959ae7b 100644 --- a/src/create-test.ts +++ b/src/create-test.ts @@ -42,6 +42,32 @@ const runTest = async (testMeta: TestMeta) => { }, }; + const handleError = async (error: Error) => { + // Remove "jest assertion error" matcherResult object + if ( + error + && typeof error === 'object' + && 'matcherResult' in error + && error.constructor.name === 'JestAssertionError' + ) { + delete error.matcherResult; + } + + consoleError(error); + process.exitCode = 1; + + for (const onTestFail of callbacks.onTestFail) { + try { + await onTestFail(error as Error); + } catch (hookError) { + consoleError('[onTestFail]', testMeta.title); + consoleError(hookError); + } + } + + return error; + }; + testMeta.startTime = Date.now(); try { if (timeout) { @@ -58,31 +84,21 @@ const runTest = async (testMeta: TestMeta) => { await testFunction(api); } } catch (error) { - testMeta.error = error as Error; - - // Remove "jest assertion error" matcherResult object - if ( - error - && typeof error === 'object' - && 'matcherResult' in error - && error.constructor.name === 'JestAssertionError' - ) { - delete error.matcherResult; + testMeta.error = await handleError(error as Error); + } finally { + for (const onTestFinish of callbacks.onTestFinish) { + try { + await onTestFinish(); + } catch (_error) { + const error = await handleError(_error as Error); + if (!testMeta.error) { + testMeta.error = error; + } + } } - consoleError(error); - process.exitCode = 1; - - for (const onTestFail of callbacks.onTestFail) { - await onTestFail(error as Error); - } - } finally { testMeta.endTime = Date.now(); logTestResult(testMeta); - - for (const onTestFinish of callbacks.onTestFinish) { - await onTestFinish(); - } } }; diff --git a/tests/index.ts b/tests/index.ts index da12799..2955ec3 100644 --- a/tests/index.ts +++ b/tests/index.ts @@ -5,12 +5,20 @@ const expectMatchInOrder = ( stdout: string, expectedOrder: string[], ) => { - const matches = expectedOrder - .map(line => [line, stdout.indexOf(line)] as const) - .sort((lineA, lineB) => lineA[1] - lineB[1]) - .map(([line]) => line); - - expect(matches).toStrictEqual(expectedOrder); + let remainingStdout = stdout; + for (let i = 0; i < expectedOrder.length; i += 1) { + const previousElement = i > 0 ? expectedOrder[i - 1] : undefined; + const currentElement = expectedOrder[i]; + const index = remainingStdout.indexOf(currentElement); + if (index === -1) { + console.log({ + remainingStdout, + stdout, + }); + throw new Error(`Expected ${JSON.stringify(currentElement)} ${previousElement ? `to be after ${JSON.stringify(previousElement)}` : ''}`); + } + remainingStdout = remainingStdout.slice(index + currentElement.length); + } }; const env = { NODE_DISABLE_COLORS: '0' }; @@ -111,4 +119,14 @@ test('hooks', async () => { 'describe finish', 'test suite finish', ]); + expectMatchInOrder(testProcess.stderr, [ + 'Error: hello\n', + '✖ describe › hooks\n', + 'Error: hello\n', + '[onTestFail] describe › failing hooks\n', + 'Error: hello\n', + 'Error: goodbye\n', + '[onTestFail] describe › failing hooks\n', + '✖ describe › failing hooks', + ]); }); diff --git a/tests/specs/hooks.ts b/tests/specs/hooks.ts index fd8da08..4a8cc1e 100644 --- a/tests/specs/hooks.ts +++ b/tests/specs/hooks.ts @@ -1,11 +1,11 @@ import { describe, testSuite } from '#manten'; -describe('describe', ({ test, onFinish, runTestSuite }) => { +describe('describe', async ({ test, onFinish, runTestSuite }) => { onFinish(() => { console.log('describe finish'); }); - test('hooks', ({ onTestFail, onTestFinish }) => { + await test('hooks', ({ onTestFail, onTestFinish }) => { console.log('test start'); onTestFail((error) => { console.log('test error', error.message); @@ -18,7 +18,19 @@ describe('describe', ({ test, onFinish, runTestSuite }) => { throw new Error('hello'); }); - runTestSuite(testSuite(({ describe, onFinish }) => { + await test('failing hooks', ({ onTestFail, onTestFinish }) => { + onTestFail((error) => { + throw error; + }); + + onTestFinish(() => { + throw new Error('goodbye'); + }); + + throw new Error('hello'); + }); + + await runTestSuite(testSuite(({ describe, onFinish }) => { console.log('test suite start'); onFinish(() => {