From 85af7dd4cb5e81a40d2c574a3ccfe8f6a8113ee0 Mon Sep 17 00:00:00 2001 From: Marc Cataford Date: Sat, 15 Apr 2023 22:50:21 -0400 Subject: [PATCH] feat: basic beforeEach, afterEach support (#28) --- src/index.ts | 1 + src/testComponents/hooks.ts | 9 +++++++++ src/testContext.ts | 29 +++++++++++++++++++++++++++++ tests/hooks.test.ts | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 src/testComponents/hooks.ts create mode 100644 tests/hooks.test.ts diff --git a/src/index.ts b/src/index.ts index c8ba9c2..908e7dd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ export { default as test, it } from './testComponents/test' export { default as describe } from './testComponents/describe' export { default as expect } from './testComponents/expect' +export { beforeEach, afterEach } from './testComponents/hooks' diff --git a/src/testComponents/hooks.ts b/src/testComponents/hooks.ts new file mode 100644 index 0000000..7c591a9 --- /dev/null +++ b/src/testComponents/hooks.ts @@ -0,0 +1,9 @@ +import { getTestContext } from '../testContext' + +export function beforeEach(func: () => void) { + getTestContext().addBeforeEach(func) +} + +export function afterEach(func: () => void) { + getTestContext().addAfterEach(func) +} diff --git a/src/testContext.ts b/src/testContext.ts index 9df1b9d..7828ebd 100644 --- a/src/testContext.ts +++ b/src/testContext.ts @@ -21,6 +21,8 @@ export function setContext(context: TestContext | null) { export class TestContext { children: Map tests: Map + beforeEach?: () => void + afterEach?: () => void parentContext?: TestContext | null constructor(parentContext: TestContext | null = null) { @@ -39,11 +41,38 @@ export class TestContext { return childContext } + addBeforeEach(func: () => void) { + if (this.beforeEach) throw new Error('beforeEach is already defined on context.') + this.beforeEach = func + } + + addAfterEach(func: () => void) { + if (this.afterEach) throw new Error('afterEach is already defined on context.') + this.afterEach = func + } + + get allBeforeEach(): Array<() => void> { + if (!this.beforeEach) return this.parentContext?.allBeforeEach ?? [() => {}] + + const parentBeforeEach = !this.parentContext ? [] : this.parentContext.allBeforeEach + + return [...parentBeforeEach, this.beforeEach] + } + + get allAfterEach(): Array<() => void> { + if (!this.afterEach) return this.parentContext?.allAfterEach ?? [() => {}] + + const parentAfterEach = !this.parentContext ? [] : this.parentContext.allAfterEach + + return [...parentAfterEach, this.afterEach] + } runTest(label: TestCaseLabel, test: TestCaseFunction) { performance.mark(`test-${label}:start`) let hasFailed = false try { + this.allBeforeEach.forEach((func) => func()) test() + this.allAfterEach.forEach((func) => func()) } catch (e) { hasFailed = true logger.logError(String(e)) diff --git a/tests/hooks.test.ts b/tests/hooks.test.ts new file mode 100644 index 0000000..3f0ca0c --- /dev/null +++ b/tests/hooks.test.ts @@ -0,0 +1,32 @@ +import assert from 'assert' + +import { test, describe, beforeEach, afterEach, expect } from 'works-on-my-machine' + +describe('Test group lifecycle hooks', () => { + let outer: boolean = false + + beforeEach(() => { + outer = true + }) + + afterEach(() => { + outer = false + }) + + describe('beforeEach', () => { + let inner: boolean = false + + beforeEach(() => { + inner = true + }) + + afterEach(() => { + inner = false + }) + + test('all beforeEach side-effects run before each test runs', () => { + expect(inner).toBe(true) + expect(outer).toBe(true) + }) + }) +})