feat: each support (#13)
* feat: add each support for test, describe * docs: document test * feat: label templating basic support * refactor: group test exports together * refactor: leverage each in repetitive tests * chore: pinned node -> alias * test: coverage for it, test
This commit is contained in:
parent
711d0097ce
commit
2bc6d94507
10 changed files with 145 additions and 88 deletions
2
.nvmrc
2
.nvmrc
|
@ -1 +1 @@
|
|||
18.15.0
|
||||
lts/hydrogen
|
||||
|
|
3
src/index.ts
Normal file
3
src/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export { default as test, it } from './testComponents/test'
|
||||
export { default as describe } from './testComponents/describe'
|
||||
export { default as expect } from './testComponents/expect'
|
|
@ -1,36 +0,0 @@
|
|||
import { promises as fs } from 'fs'
|
||||
|
||||
import expect from './expect'
|
||||
import { greenText, redText } from './utils'
|
||||
import { type TestCaseLabel, type TestCaseFunction, type TestCaseGroup } from './types'
|
||||
|
||||
function describe(label: TestCaseLabel, testGroup: TestCaseGroup) {
|
||||
if (process.env.COLLECT) {
|
||||
testGroup()
|
||||
return
|
||||
}
|
||||
|
||||
console.group(greenText(label))
|
||||
testGroup()
|
||||
console.groupEnd()
|
||||
}
|
||||
|
||||
function test(label: TestCaseLabel, testCase: TestCaseFunction): void {
|
||||
if (process.env.COLLECT) {
|
||||
console.log(label)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
testCase()
|
||||
console.log(greenText(`[PASSED] ${label}`))
|
||||
} catch (e) {
|
||||
console.group(redText(`[FAILED] ${label}`))
|
||||
console.log(redText(String(e)))
|
||||
console.groupEnd()
|
||||
}
|
||||
}
|
||||
|
||||
const it = test
|
||||
|
||||
export { it, test, expect, describe }
|
43
src/testComponents/describe.ts
Normal file
43
src/testComponents/describe.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { promises as fs } from 'fs'
|
||||
|
||||
import { greenText, redText } from '../utils'
|
||||
import { type TestCaseLabel, type TestCaseFunction, type TestCaseGroup } from '../types'
|
||||
|
||||
/*
|
||||
* `describe` facilitates grouping tests together.
|
||||
*
|
||||
* ```
|
||||
* describe('My test group', () => {
|
||||
* test('My first test', ...)
|
||||
*
|
||||
* test('My second test', ...)
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
function describe(label: TestCaseLabel, testGroup: TestCaseGroup) {
|
||||
if (process.env.COLLECT) {
|
||||
testGroup()
|
||||
return
|
||||
}
|
||||
|
||||
console.group(greenText(label))
|
||||
testGroup()
|
||||
console.groupEnd()
|
||||
}
|
||||
|
||||
Object.defineProperty(describe, 'each', {
|
||||
value: function (values: Array<unknown>) {
|
||||
return (label: TestCaseLabel, testGroup: TestCaseGroup) => {
|
||||
values.forEach((value: unknown, index: number) => {
|
||||
describe(label.replace(/%s/g, String(value)), () => testGroup(value))
|
||||
})
|
||||
}
|
||||
},
|
||||
enumerable: true,
|
||||
})
|
||||
|
||||
type extendedDescribe = typeof describe & { [key: string]: (...args: Array<unknown>) => extendedDescribe }
|
||||
|
||||
const extDescribe = describe as extendedDescribe
|
||||
|
||||
export default extDescribe
|
|
@ -9,7 +9,7 @@ import {
|
|||
type RawComparisonMatcher,
|
||||
type RawMatchersMap,
|
||||
type MatcherName,
|
||||
} from './types'
|
||||
} from '../types'
|
||||
|
||||
import matchers from './matchers'
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
import assert from 'assert'
|
||||
|
||||
import { type MatcherReport } from './types'
|
||||
import { type MatcherReport } from '../types'
|
||||
|
||||
/*
|
||||
* Asserts whether value and other are strictly equal.
|
53
src/testComponents/test.ts
Normal file
53
src/testComponents/test.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
import { promises as fs } from 'fs'
|
||||
|
||||
import { greenText, redText } from '../utils'
|
||||
import { type TestCaseLabel, type TestCaseFunction, type TestCaseGroup } from '../types'
|
||||
|
||||
/*
|
||||
* `test` defines a single test case.
|
||||
*
|
||||
* ```
|
||||
* test('My test', () => {
|
||||
* // Assert things.
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
function test(label: TestCaseLabel, testCase: TestCaseFunction): void {
|
||||
if (process.env.COLLECT) {
|
||||
console.log(label)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
testCase()
|
||||
console.log(greenText(`[PASSED] ${label}`))
|
||||
} catch (e) {
|
||||
console.group(redText(`[FAILED] ${label}`))
|
||||
console.log(redText(String(e)))
|
||||
console.groupEnd()
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(test, 'each', {
|
||||
value: function (values: Array<unknown>) {
|
||||
return (label: TestCaseLabel, testCase: TestCaseFunction) => {
|
||||
values.forEach((value: unknown, index: number) => {
|
||||
test(label.replace(/%s/g, String(value)), () => testCase(value))
|
||||
})
|
||||
}
|
||||
},
|
||||
enumerable: true,
|
||||
})
|
||||
|
||||
type extendedTest = typeof test & { [key: string]: (...args: Array<unknown>) => extendedTest }
|
||||
|
||||
const extTest = test as extendedTest
|
||||
|
||||
/*
|
||||
* `it` is an alias of `test`.
|
||||
*/
|
||||
const it = extTest
|
||||
|
||||
export { it }
|
||||
|
||||
export default extTest
|
|
@ -2,8 +2,8 @@ import { type Server } from 'net'
|
|||
|
||||
export type TestCaseLabel = string
|
||||
export type TestFilePath = string
|
||||
export type TestCaseFunction = () => void
|
||||
export type TestCaseGroup = () => void
|
||||
export type TestCaseFunction = (...args: Array<unknown>) => void
|
||||
export type TestCaseGroup = (...args: Array<unknown>) => void
|
||||
|
||||
export interface TestServer extends Server {
|
||||
failure?: boolean
|
||||
|
|
|
@ -1,55 +1,17 @@
|
|||
import assert from 'assert'
|
||||
import { describe, test, expect } from '../src/testCaseUtils'
|
||||
import { describe, test, expect } from '../src'
|
||||
|
||||
describe('Equality', () => {
|
||||
test('Equality (number)', () => {
|
||||
assert.doesNotThrow(() => expect(1).toEqual(1))
|
||||
test.each([1, 'expectations', true])('Equality (value=%s)', (value: unknown) => {
|
||||
assert.doesNotThrow(() => expect(value).toEqual(value))
|
||||
})
|
||||
|
||||
test('Equality (string)', () => {
|
||||
assert.doesNotThrow(() => expect('expectations').toEqual('expectations'))
|
||||
})
|
||||
|
||||
test('Equality (boolean)', () => {
|
||||
assert.doesNotThrow(() => expect(true).toEqual(true))
|
||||
})
|
||||
|
||||
test('Equality (failed - number)', () => {
|
||||
assert.throws(() => expect(1).toEqual(2))
|
||||
})
|
||||
|
||||
test('Equality (failed - string)', () => {
|
||||
assert.throws(() => expect('expectation').toEqual('something else'))
|
||||
})
|
||||
|
||||
test('Equality (failed - boolean)', () => {
|
||||
assert.throws(() => expect(true).toEqual(false))
|
||||
})
|
||||
})
|
||||
|
||||
describe('Identity', () => {
|
||||
test('Identity comparison (number)', () => {
|
||||
assert.doesNotThrow(() => expect(1).toBe(1))
|
||||
})
|
||||
|
||||
test('Identity comparison (boolean)', () => {
|
||||
assert.doesNotThrow(() => expect(true).toBe(true))
|
||||
})
|
||||
|
||||
test('Identity comparison (string)', () => {
|
||||
assert.doesNotThrow(() => expect('identity').toBe('identity'))
|
||||
})
|
||||
|
||||
test('Identity comparison (failed - number)', () => {
|
||||
assert.throws(() => expect(1).toEqual(2))
|
||||
})
|
||||
|
||||
test('Identity comparison (failed - boolean)', () => {
|
||||
assert.throws(() => expect(false).toBe(true))
|
||||
})
|
||||
|
||||
test('Identity comparison (failed - string)', () => {
|
||||
assert.throws(() => expect('yes').toBe('no'))
|
||||
test.each([
|
||||
[1, 2],
|
||||
['expectation', 'something else'],
|
||||
[true, false],
|
||||
])('Equality (failed - values=%s)', (...pair: Array<unknown>) => {
|
||||
assert.throws(() => expect(pair[0]).toEqual(pair[1]))
|
||||
})
|
||||
|
||||
test('Equality negation', () => {
|
||||
|
@ -57,6 +19,24 @@ describe('Identity', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('Identity', () => {
|
||||
test.each([1, true, 'identity'])('Identity comparison (value=%s)', (value: unknown) => {
|
||||
assert.doesNotThrow(() => expect(value).toBe(value))
|
||||
})
|
||||
|
||||
test.each([
|
||||
[1, 2],
|
||||
[false, true],
|
||||
['yes', 'no'],
|
||||
])('Identity comparison (failed - value=%s)', (...pair: Array<unknown>) => {
|
||||
assert.throws(() => expect(pair[0]).toBe(pair[1]))
|
||||
})
|
||||
|
||||
test('Identity negation', () => {
|
||||
assert.doesNotThrow(() => expect('yes').not.toBe('no'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('Exception expectation', () => {
|
||||
test('Expects error', () => {
|
||||
const err = new Error('err')
|
||||
|
|
14
tests/it.test.ts
Normal file
14
tests/it.test.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import assert from 'assert'
|
||||
|
||||
import { it, test, expect, describe } from '../src'
|
||||
|
||||
describe.each([it, test])('Runs tests', (fn: unknown) => {
|
||||
const testFn = fn as typeof test
|
||||
testFn('Runs a test', () => {
|
||||
assert.doesNotThrow(() => expect(1).toEqual(1))
|
||||
})
|
||||
|
||||
testFn.each([1, 2, 3])('Supports parametrization (value=%s)', (value: unknown) => {
|
||||
assert.doesNotThrow(() => expect(value).toEqual(value))
|
||||
})
|
||||
})
|
Reference in a new issue