From 7ecbaf9af451a33c57fe78aab7d79a22abb67404 Mon Sep 17 00:00:00 2001 From: patak Date: Sat, 4 Dec 2021 14:06:05 +0100 Subject: [PATCH] feat: tasks mode (#3) --- src/run.ts | 71 +++++++++++++++++++++++++--------------------- src/suite.ts | 39 +++++++++++++++++++------ src/types.ts | 18 +++++++++--- test/modes.test.ts | 10 ++++++- 4 files changed, 92 insertions(+), 46 deletions(-) diff --git a/src/run.ts b/src/run.ts index 0b8e4a456d22..b9c51e9a7f64 100644 --- a/src/run.ts +++ b/src/run.ts @@ -5,26 +5,20 @@ import chai from 'chai' import fg from 'fast-glob' import { clearContext, defaultSuite } from './suite' import { context } from './context' -import { File, Options, Suite, Task, TaskResult } from './types' +import { File, Options, Suite, Task } from './types' import { afterEachHook, afterFileHook, afterAllHook, afterSuiteHook, beforeEachHook, beforeFileHook, beforeAllHook, beforeSuiteHook } from './hooks' import { SnapshotPlugin } from './snapshot/index' -export async function runTasks(tasks: Task[]) { - const results: TaskResult[] = [] - - for (const task of tasks) { - await beforeEachHook.fire(task) - task.result = {} - try { - await task.fn() - } - catch (e) { - task.result.error = e - } - await afterEachHook.fire(task) +export async function runTask(task: Task) { + await beforeEachHook.fire(task) + task.result = {} + try { + await task.fn() } - - return results + catch (e) { + task.result.error = e + } + await afterEachHook.fire(task) } // TODO: REPORTER @@ -76,28 +70,35 @@ export async function runFile(file: File, options: RunOptions = {}) { indent += 1 } - if ((suite.mode === 'run' && !options?.onlyMode) || suite.mode === 'only') { - // TODO: If there is a task with 'only', skip all others - await runTasks(tasks) + if (suite.mode === 'todo') { + // TODO: In Jest, these suites are collected and printed together at the end of the report + log(`${' '.repeat(indent * 2)}${c.inverse(c.gray(' TODO '))}`) + } + else { + const runSuite = (suite.mode === 'run' && !options?.onlyMode) || suite.mode === 'only' || tasks.find(t => t.mode === 'only') + for (const t of tasks) { - if (t.result && t.result.error === undefined) { - log(`${' '.repeat(indent * 2)}${c.inverse(c.green(' PASS '))} ${c.green(t.name)}`) + if (runSuite && (((t.mode === 'run' && !options?.onlyMode) || t.mode === 'only') || suite.mode === 'only')) { + await runTask(t) + + if (t.result && t.result.error === undefined) { + log(`${' '.repeat(indent * 2)}${c.inverse(c.green(' PASS '))} ${c.green(t.name)}`) + } + else { + console.error(`${' '.repeat(indent * 2)}${c.inverse(c.red(' FAIL '))} ${c.red(t.name)}`) + console.error(' '.repeat((indent + 2) * 2) + c.red(String(t.result!.error))) + process.exitCode = 1 + } + } + else if (t.mode === 'todo') { + log(`${' '.repeat(indent * 2)}${c.inverse(c.gray(' TODO '))} ${c.green(t.name)}`) } else { - console.error(`${' '.repeat(indent * 2)}${c.inverse(c.red(' FAIL '))} ${c.red(t.name)}`) - console.error(' '.repeat((indent + 2) * 2) + c.red(String(t.result!.error))) - process.exitCode = 1 + // Only mode or direct skip + log(`${' '.repeat(indent * 2)}${c.inverse(c.gray(' SKIP '))} ${c.green(t.name)}`) } } } - else if (suite.mode === 'todo') { - // TODO: In Jest, these suites are collected and printed together at the end of the report - log(`${' '.repeat(indent * 2)}${c.inverse(c.gray(' TODO '))}`) - } - else { - // suite.mode is 'skip' or 'run' in onlyMode - log(`${' '.repeat(indent * 2)}${c.inverse(c.gray(' SKIP '))}`) - } if (suite.name) indent -= 1 @@ -158,5 +159,9 @@ export async function run(options: Options = {}) { } function isOnlyMode(files: File[]) { - return !!files.find(file => file.suites.find(suite => suite.mode === 'only')) + return !!files.find( + file => file.collected.find( + ([suite, tasks]) => suite.mode === 'only' || tasks.find(t => t.mode === 'only'), + ), + ) } diff --git a/src/suite.ts b/src/suite.ts index 089f0ccd5290..4a7ed682387b 100644 --- a/src/suite.ts +++ b/src/suite.ts @@ -1,8 +1,17 @@ import { context } from './context' -import { Task, Suite, SuiteMode, TestFactory } from './types' +import { Task, Suite, RunMode, TestFactory, TestFunction } from './types' export const defaultSuite = suite('') -export const test = (name: string, fn: () => Promise | void) => (context.currentSuite || defaultSuite).test(name, fn) +export const test = (name: string, fn: TestFunction) => (context.currentSuite || defaultSuite).test(name, fn) +test.skip = function skip(name: string, fn: TestFunction) { + (context.currentSuite || defaultSuite).test.skip(name, fn) +} +test.only = function only(name: string, fn: TestFunction) { + (context.currentSuite || defaultSuite).test.only(name, fn) +} +test.todo = function todo(name: string) { + (context.currentSuite || defaultSuite).test.todo(name) +} export function clearContext() { context.suites.length = 0 @@ -10,7 +19,7 @@ export function clearContext() { context.currentSuite = defaultSuite } -function processSuite(mode: SuiteMode, suiteName: string, factory?: TestFactory) { +function createSuite(mode: RunMode, suiteName: string, factory?: TestFactory) { const queue: Task[] = [] const factoryQueue: Task[] = [] @@ -22,15 +31,29 @@ function processSuite(mode: SuiteMode, suiteName: string, factory?: TestFactory) clear, } - function test(name: string, fn: () => Promise | void) { + function createTask(mode: RunMode, name: string, fn: TestFunction) { const task: Task = { suite, + mode, name, fn, } queue.push(task) } + function test(name: string, fn: TestFunction) { + createTask(mode, name, fn) + } + test.skip = function skip(name: string, fn: TestFunction) { + createTask('skip', name, fn) + } + test.only = function only(name: string, fn: TestFunction) { + createTask('only', name, fn) + } + test.todo = function todo(name: string) { + createTask('todo', name, () => { }) + } + function clear() { queue.length = 0 factoryQueue.length = 0 @@ -50,19 +73,19 @@ function processSuite(mode: SuiteMode, suiteName: string, factory?: TestFactory) } export function suite(suiteName: string, factory?: TestFactory) { - return processSuite('run', suiteName, factory) + return createSuite('run', suiteName, factory) } suite.skip = function skip(suiteName: string, factory?: TestFactory) { - return processSuite('skip', suiteName, factory) + return createSuite('skip', suiteName, factory) } suite.only = function skip(suiteName: string, factory?: TestFactory) { - return processSuite('only', suiteName, factory) + return createSuite('only', suiteName, factory) } suite.todo = function skip(suiteName: string) { - return processSuite('todo', suiteName) + return createSuite('todo', suiteName) } // alias diff --git a/src/types.ts b/src/types.ts index 03a2aab31253..31b7d8ee08e3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,25 +14,35 @@ export interface TaskResult { error?: unknown } +export type RunMode = 'run' | 'skip' | 'only' | 'todo' + export interface Task { name: string + mode: RunMode suite: Suite fn: () => Promise | void file?: File result?: TaskResult } -export type SuiteMode = 'run' | 'skip' | 'only' | 'todo' +export type TestFunction = () => Promise | void + +export interface Test { + (name: string, fn: TestFunction): void + only: (name: string, fn: TestFunction) => void + skip: (name: string, fn: TestFunction) => void + todo: (name: string) => void +} export interface Suite { name: string - mode: SuiteMode - test: (name: string, fn: () => Promise | void) => void + mode: RunMode + test: Test collect: () => Promise clear: () => void } -export type TestFactory = (test: Suite['test']) => Promise | void +export type TestFactory = (test: (name: string, fn: TestFunction) => void) => Promise | void export interface File { filepath: string diff --git a/test/modes.test.ts b/test/modes.test.ts index 3cf7528d9fcd..ffda2f385cf6 100644 --- a/test/modes.test.ts +++ b/test/modes.test.ts @@ -1,9 +1,17 @@ import { it, describe, assert } from '../src' describe.skip('skipped suite', () => { - it('no fail as it is skipped', () => { + it('no fail as suite is skipped', () => { assert.equal(Math.sqrt(4), 3) }) }) describe.todo('unimplemented suite') + +describe('task modes', () => { + it.skip('no fail as it task is skipped', () => { + assert.equal(Math.sqrt(4), 3) + }) + + it.todo('unimplemented task') +})