diff --git a/examples/dot.ts b/examples/dot.ts index c3dbfc7..d9fe408 100644 --- a/examples/dot.ts +++ b/examples/dot.ts @@ -1,5 +1,5 @@ -import { runner } from '../factories/main.js' import { dot } from '../src/reporters/main.js' +import { createDiverseTests, runner } from '../factories/main.js' await runner() .configure({ @@ -9,4 +9,4 @@ await runner() activated: ['dot'], }, }) - .run() + .runSuites(createDiverseTests) diff --git a/examples/ndjson.ts b/examples/ndjson.ts index 56edb54..471ba7f 100644 --- a/examples/ndjson.ts +++ b/examples/ndjson.ts @@ -1,5 +1,5 @@ -import { runner } from '../factories/main.js' import { ndjson } from '../src/reporters/main.js' +import { createDiverseTests, runner } from '../factories/main.js' await runner() .configure({ @@ -9,4 +9,4 @@ await runner() activated: ['ndjson'], }, }) - .run() + .runSuites(createDiverseTests) diff --git a/examples/spec.ts b/examples/spec.ts index 6de54a2..83fa856 100644 --- a/examples/spec.ts +++ b/examples/spec.ts @@ -1,5 +1,5 @@ -import { runner } from '../factories/main.js' import { spec } from '../src/reporters/main.js' +import { createDiverseTests, runner } from '../factories/main.js' await runner() .configure({ @@ -9,4 +9,4 @@ await runner() activated: ['spec'], }, }) - .run() + .runSuites(createDiverseTests) diff --git a/factories/create_diverse_tests.ts b/factories/create_diverse_tests.ts new file mode 100644 index 0000000..7f2c63c --- /dev/null +++ b/factories/create_diverse_tests.ts @@ -0,0 +1,120 @@ +import assert from 'node:assert' +import { Suite, Emitter, Refiner } from '../modules/core/main.js' +import { createTest, createTestGroup } from '../src/create_test.js' + +/** + * Creates a unit tests suite with bunch of dummy tests + * reproducing different tests behavior + */ +function createUnitTestsSuite(emitter: Emitter, refiner: Refiner, file?: string) { + const suite = new Suite('unit', emitter, refiner) + const group = createTestGroup('Maths#add', emitter, refiner, { + suite, + file, + }) + + createTest('A top level test inside a suite', emitter, refiner, { + suite, + file, + }).run(() => {}) + + createTest('add two numbers', emitter, refiner, { group, file }).run(() => { + assert.equal(2 + 2, 4) + }) + createTest('add three numbers', emitter, refiner, { + group, + file, + }).run(() => { + assert.equal(2 + 2 + 2, 6) + }) + + createTest('add group of numbers', emitter, refiner, { group, file }) + createTest('use math.js lib', emitter, refiner, { group, file }).skip( + true, + 'Library work pending' + ) + createTest('add multiple numbers', emitter, refiner, { + file, + group, + }).run(() => { + assert.equal(2 + 2 + 2 + 2, 6) + }) + createTest('add floating numbers', emitter, refiner, { group, file }) + .run(() => { + assert.equal(2 + 2.2 + 2.1, 6) + }) + .fails('Have to add support for floating numbers') + createTest('A test with an error that is not an AssertionError', emitter, refiner, { + group, + file, + }).run(() => { + throw new Error('This is an error') + }) + + return suite +} + +/** + * Creates a unit functional suite with bunch of dummy tests + * reproducing different tests behavior + */ +function createFunctionalTestsSuite(emitter: Emitter, refiner: Refiner, file?: string) { + const suite = new Suite('functional', emitter, refiner) + + const group = createTestGroup('Users/store', emitter, refiner, { + suite, + file: file, + }) + createTest('Validate user data', emitter, refiner, { + group, + file: file, + }).run(() => {}) + createTest('Disallow duplicate emails', emitter, refiner, { + group, + file: file, + }).run(() => {}) + createTest('Disallow duplicate emails across tenants', emitter, refiner, { + group, + file: file, + }).run(() => { + const users = ['', ''] + assert.equal(users.length, 1) + }) + createTest('Normalize email before persisting it', emitter, refiner, { + group, + file: file, + }).skip(true, 'Have to build a normalizer') + createTest('Send email verification mail', emitter, refiner, { + group, + file: file, + }) + + const usersListGroup = createTestGroup('Users/list', emitter, refiner, { + suite, + file: file, + }) + usersListGroup.setup(() => { + throw new Error('Unable to cleanup database') + }) + createTest('A test that will never because the group hooks fails', emitter, refiner, { + group: usersListGroup, + }) + + createTest('A top level test inside functional suite', emitter, refiner, { + suite, + file: file, + }).run(() => {}) + + return suite +} + +/** + * Returns an array of suites with dummy tests reproducting + * different test behavior + */ +export function createDiverseTests(emitter: Emitter, refiner: Refiner, file?: string): Suite[] { + return [ + createUnitTestsSuite(emitter, refiner, file), + createFunctionalTestsSuite(emitter, refiner, file), + ] +} diff --git a/factories/main.ts b/factories/main.ts index 4ef43b7..fe36eac 100644 --- a/factories/main.ts +++ b/factories/main.ts @@ -7,9 +7,22 @@ * file that was distributed with this source code. */ +import { ReporterContract } from '../src/types.js' import { RunnerFactory } from './runner.js' /** * Create an instance of the runner factory */ export const runner = () => new RunnerFactory() +export { createDiverseTests } from './create_diverse_tests.js' +export const syncReporter: ReporterContract = { + name: 'sync', + handler(r, emitter) { + emitter.on('runner:end', function () { + const summary = r.getSummary() + if (summary.hasError) { + throw summary.failureTree[0].children[0].errors[0].error + } + }) + }, +} diff --git a/factories/runner.ts b/factories/runner.ts index a69c23f..bcb0a14 100644 --- a/factories/runner.ts +++ b/factories/runner.ts @@ -7,15 +7,14 @@ * file that was distributed with this source code. */ -import assert from 'node:assert' import { fileURLToPath } from 'node:url' import { Planner } from '../src/planner.js' import { GlobalHooks } from '../src/hooks.js' import { CliParser } from '../src/cli_parser.js' +import { createTest } from '../src/create_test.js' import { ConfigManager } from '../src/config_manager.js' -import { createTest, createTestGroup } from '../src/create_test.js' -import { Group, Suite, Runner, Emitter, TestContext } from '../modules/core/main.js' +import { Suite, Runner, Emitter, TestContext, Refiner } from '../modules/core/main.js' import type { Config, CLIArgs, @@ -33,138 +32,12 @@ export class RunnerFactory { #emitter = new Emitter() #config?: NormalizedConfig #cliArgs?: CLIArgs - #suites?: Suite[] #file = fileURLToPath(import.meta.url) get #refiner() { return this.#config!.refiner } - /** - * Creating unit and functional suites - */ - #createSuites() { - return [ - new Suite('unit', this.#emitter, this.#refiner), - new Suite('functional', this.#emitter, this.#refiner), - ] - } - - /** - * Creates a variety of tests for Maths.add method - */ - #createAdditionTests(group: Group) { - createTest('add two numbers', this.#emitter, this.#refiner, { group, file: this.#file }).run( - () => { - assert.equal(2 + 2, 4) - } - ) - createTest('add three numbers', this.#emitter, this.#refiner, { - group, - file: this.#file, - }).run(() => { - assert.equal(2 + 2 + 2, 6) - }) - createTest('add group of numbers', this.#emitter, this.#refiner, { group, file: this.#file }) - createTest('use math.js lib', this.#emitter, this.#refiner, { group, file: this.#file }).skip( - true, - 'Library work pending' - ) - createTest('add multiple numbers', this.#emitter, this.#refiner, { - file: this.#file, - group, - }).run(() => { - assert.equal(2 + 2 + 2 + 2, 6) - }) - createTest('add floating numbers', this.#emitter, this.#refiner, { group, file: this.#file }) - .run(() => { - assert.equal(2 + 2.2 + 2.1, 6) - }) - .fails('Have to add support for floating numbers') - createTest('A test with an error that is not an AssertionError', this.#emitter, this.#refiner, { - group, - file: this.#file, - }).run(() => { - throw new Error('This is an error') - }) - } - - /** - * Creates a variety of dummy tests for creating - * a new user - */ - #createUserStoreTests(group: Group) { - createTest('Validate user data', this.#emitter, this.#refiner, { - group, - file: this.#file, - }).run(() => {}) - createTest('Disallow duplicate emails', this.#emitter, this.#refiner, { - group, - file: this.#file, - }).run(() => {}) - createTest('Disallow duplicate emails across tenants', this.#emitter, this.#refiner, { - group, - file: this.#file, - }).run(() => { - const users = ['', ''] - assert.equal(users.length, 1) - }) - createTest('Normalize email before persisting it', this.#emitter, this.#refiner, { - group, - file: this.#file, - }).skip(true, 'Have to build a normalizer') - createTest('Send email verification mail', this.#emitter, this.#refiner, { - group, - file: this.#file, - }) - } - - /** - * Creates tests for the unit tests suite - */ - #createUnitTests(suite: Suite) { - const additionGroup = createTestGroup('Maths#add', this.#emitter, this.#refiner, { - suite, - file: this.#file, - }) - this.#createAdditionTests(additionGroup) - - createTest('A top level test inside a suite', this.#emitter, this.#refiner, { - suite, - file: this.#file, - }).run(() => {}) - } - - /** - * Creates tests for the functional tests suite - */ - #createFunctionalTests(suite: Suite) { - const usersStoreGroup = createTestGroup('Users/store', this.#emitter, this.#refiner, { - suite, - file: this.#file, - }) - this.#createUserStoreTests(usersStoreGroup) - - const usersListGroup = createTestGroup('Users/list', this.#emitter, this.#refiner, { - suite, - file: this.#file, - }) - usersListGroup.setup(() => { - throw new Error('Unable to cleanup database') - }) - createTest( - 'A test that will never because the group hooks fails', - this.#emitter, - this.#refiner, - { group: usersListGroup } - ) - - createTest('A top level test inside functional suite', this.#emitter, this.#refiner, { - suite, - file: this.#file, - }).run(() => {}) - } - /** * Registers plugins */ @@ -188,15 +61,6 @@ export class RunnerFactory { return this } - /** - * Register custom suites to execute instead - * of the dummy one's - */ - withSuites(suites: Suite[]) { - this.#suites = suites - return this - } - /** * Define a custom emitter instance to use */ @@ -212,24 +76,24 @@ export class RunnerFactory { title: string, callback: TestExecutor ): Promise { - const defaultSuite = new Suite('default', this.#emitter, this.#refiner) - const test = createTest(title, this.#emitter, this.#refiner, { - suite: defaultSuite, - file: this.#file, - }).run(callback) - - defaultSuite.add(test) - - this.withSuites([defaultSuite]) - return this.run() + return this.runSuites((emitter, refiner, file) => { + const defaultSuite = new Suite('default', emitter, refiner) + createTest(title, emitter, refiner, { + suite: defaultSuite, + file: file, + }).run(callback) + + return [defaultSuite] + }) } /** * Run dummy tests. You might use */ - async run(): Promise { + async runSuites( + suites: (emitter: Emitter, refiner: Refiner, file?: string) => Suite[] + ): Promise { const runner = new Runner(this.#emitter) - await this.#registerPlugins(runner) const { config, reporters, refinerFilters } = await new Planner(this.#config!).plan() @@ -239,21 +103,12 @@ export class RunnerFactory { reporters.forEach((reporter) => { runner.registerReporter(reporter) }) + refinerFilters.forEach((filter) => { config.refiner.add(filter.layer, filter.filters) }) - if (this.#suites) { - this.#suites.forEach((suite) => runner.add(suite)) - } else { - const [unit, functional] = this.#createSuites() - - this.#createUnitTests(unit) - runner.add(unit) - - this.#createFunctionalTests(functional) - runner.add(functional) - } + suites(this.#emitter, this.#refiner, this.#file).forEach((suite) => runner.add(suite)) await globalHooks.setup(runner) await runner.start() diff --git a/tests/runner.spec.ts b/tests/runner.spec.ts index 27139dd..2e4e0e1 100644 --- a/tests/runner.spec.ts +++ b/tests/runner.spec.ts @@ -367,8 +367,7 @@ test.describe('Runner | retryPlugin', () => { plugins: [retryPlugin], }) .useEmitter(emitter) - .withSuites([suite]) - .run() + .runSuites(() => [suite]) await wrapAssertions(async () => { assert.deepEqual(await getFailedTests(), { tests: ['failing test'] }) @@ -412,16 +411,15 @@ test.describe('Runner | retryPlugin', () => { argv ) .useEmitter(emitter) - .withSuites([getSuite()]) } - await getExecutor().run() + await getExecutor().runSuites(() => [getSuite()]) await wrapAssertions(async () => { assert.deepEqual(await getFailedTests(), { tests: ['failing test'] }) assert.deepEqual(stack, ['executing failing test', 'executing passing test']) }) - await getExecutor(['--failed']).run() + await getExecutor(['--failed']).runSuites(() => [getSuite()]) await wrapAssertions(async () => { assert.deepEqual(await getFailedTests(), { tests: ['failing test'] }) assert.deepEqual(stack, [ @@ -468,16 +466,15 @@ test.describe('Runner | retryPlugin', () => { argv ) .useEmitter(emitter) - .withSuites([getSuite()]) } - await getExecutor().run() + await getExecutor().runSuites(() => [getSuite()]) await wrapAssertions(async () => { assert.deepEqual(await getFailedTests(), { tests: ['failing test'] }) assert.deepEqual(stack, ['executing failing test', 'executing passing test']) }) - await getExecutor([]).run() + await getExecutor([]).runSuites(() => [getSuite()]) await wrapAssertions(async () => { assert.deepEqual(await getFailedTests(), { tests: ['failing test'] }) assert.deepEqual(stack, [ @@ -521,16 +518,15 @@ test.describe('Runner | retryPlugin', () => { argv ) .useEmitter(emitter) - .withSuites([getSuite()]) } - await getExecutor().run() + await getExecutor().runSuites(() => [getSuite()]) await wrapAssertions(async () => { assert.deepEqual(await getFailedTests(), { tests: [] }) assert.deepEqual(stack, ['executing passing test']) }) - await getExecutor(['--failed']).run() + await getExecutor(['--failed']).runSuites(() => [getSuite()]) await wrapAssertions(async () => { assert.deepEqual(await getFailedTests(), { tests: [] }) assert.deepEqual(stack, ['executing passing test', 'executing passing test'])