Skip to content

Commit

Permalink
feat: tasks mode (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
patak-dev committed Dec 4, 2021
1 parent 9fcf735 commit 7ecbaf9
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 46 deletions.
71 changes: 38 additions & 33 deletions src/run.ts
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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'),
),
)
}
39 changes: 31 additions & 8 deletions src/suite.ts
@@ -1,16 +1,25 @@
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> | 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
defaultSuite.clear()
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[] = []

Expand All @@ -22,15 +31,29 @@ function processSuite(mode: SuiteMode, suiteName: string, factory?: TestFactory)
clear,
}

function test(name: string, fn: () => Promise<void> | 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
Expand All @@ -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
Expand Down
18 changes: 14 additions & 4 deletions src/types.ts
Expand Up @@ -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> | void
file?: File
result?: TaskResult
}

export type SuiteMode = 'run' | 'skip' | 'only' | 'todo'
export type TestFunction = () => Promise<void> | 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) => void
mode: RunMode
test: Test
collect: () => Promise<Task[]>
clear: () => void
}

export type TestFactory = (test: Suite['test']) => Promise<void> | void
export type TestFactory = (test: (name: string, fn: TestFunction) => void) => Promise<void> | void

export interface File {
filepath: string
Expand Down
10 changes: 9 additions & 1 deletion 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')
})

0 comments on commit 7ecbaf9

Please sign in to comment.