Skip to content

Instantly share code, notes, and snippets.

@jcayzac
Last active July 25, 2022 00:49
Show Gist options
  • Save jcayzac/dfa46d0fc1797c716ee07b920b7ce577 to your computer and use it in GitHub Desktop.
Save jcayzac/dfa46d0fc1797c716ee07b920b7ce577 to your computer and use it in GitHub Desktop.
A minimal test framework for node/typescript. Handles sync and async tests and subtests all the same. This could also work in deno pending https://github.com/denoland/deno_std/issues/1627#issuecomment-976757905
import chalk from 'chalk'
import ora from 'ora'
import process from 'node:process'
const success = chalk.green.bold(`OK`)
const failure = chalk.red.bold(`FAILED`)
const excludeStackFragment = `(${new URL(import.meta.url).pathname}:`
type TestBlock = (params: { test: TestFunction }) => unknown
type TestFunction = (description: string, body: TestBlock) => void
const testWithContext = (body: TestBlock, context: string[]) => {
const title = chalk.bold(context.join(' ❯ '))
const progress = ora({discardStdin: true}).start(title)
const test: TestFunction = (description, body) => testWithContext(body, [...context, description])
const successHandler = () => progress.succeed(`${title}: ${success}`)
const errorHandler = (error: Error) => {
process.exitCode = 1
const { stack: s, message: m } = error
const message = chalk.red(m)
const stack = s
?.split(/[\r\n]+/g)
?.filter(x => /^\s*at\s/.test(x) && x.indexOf(excludeStackFragment) < 0)
?.map(x => `\n ${x.trim()}`)
?.join() ?? ''
progress.fail(`${title}: ${failure}\n ${message}${stack}`)
}
new Promise((ok, ng) => setTimeout(() => {
try {
const r = body({ test })
if (r instanceof Promise) r.then(ok, ng)
else ok(undefined)
}
catch (e) {
ng(e)
}
}, 0)).then(successHandler, errorHandler)
}
export const test: TestFunction = (description, body) => testWithContext(body, [description])
@jcayzac
Copy link
Author

jcayzac commented Jul 24, 2022

Example usage:

#!/usr/bin/env tsx
import { test } from './test'
import { expect } from 'chai'

test('test 1', async ({ test }) => {
  test(`test 1.1`, async ({ test }) => {
    test(`test 1.1.1`, async () => {
      await new Promise((ok) => setTimeout(ok, 5000))
      expect([]).to.have.lengthOf(3)
    })
    await new Promise((ok, ng) => setTimeout(() => ng(new Error('Oh no')), 3000))
  })
  test(`test 1.2`, async () => {
    expect([]).to.have.lengthOf(3)
  })
  test(`test 1.3`, () => {
    throw new Error(`Test failed`)
  })
})

Screen Shot 2022-07-24 at 22 37 45

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment