Skip to content

Commit

Permalink
add test
Browse files Browse the repository at this point in the history
  • Loading branch information
75lb committed Aug 23, 2024
1 parent f5e6da3 commit 3d20483
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 161 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name: Node.js CI

on:
push:
branches: [ master ]
branches: [ master, next ]
pull_request:
branches: [ master ]

Expand Down
113 changes: 1 addition & 112 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,118 +7,7 @@

# test-runner

***This project and documentation are a WIP***

Fully-featured, lightweight command-line test runner. Part of a suite of tools to help the full-stack JavaScript engineer create and test modern, isomorphic code.

## Synopsis

As input, test-runner takes one or more files each exporting a set of tests. The tests in each file are run with a controllable order and concurrency, a report is printed and the command exits with a non-zero code if anything failed.

This is the general syntax (see [here](https://github.com/test-runner-js/test-runner/wiki/test-runner-command-line-options) for the full usage guide):

```
$ test-runner [<options>] <file> ...
```

### Test file basics

A test file is a module (either CommonJS or ECMAScript) which must export a [test object model](https://github.com/test-runner-js/test-object-model) instance. This test file can be run natively (no build or transpilation step required) in Node.js, the browser (in headless Chromium) or both (isomorphic).

Add tests to the model by invoking [`tom.test`](https://github.com/test-runner-js/test-object-model/blob/master/docs/API.md#module_test-object-model--Tom+test) with a name and test function. Trivial example. **If a test function throws or returns a rejected promise it is considered a fail, otherwise a pass**.

```js
const { Tom } = require('test-runner')

const tom = new Tom()

tom.test('A successful sync test', function () {
return 'This passed'
})

tom.test('A failing sync test', function () {
throw new Error('This failed')
})

tom.test('A successful async test', async function () {
return 'This passed'
})

tom.test('A failing async test', async function () {
throw new Error('This failed')
})

tom.test('Also a failing async test', async function () {
return Promise.reject(new Error('This failed'))
})

module.exports = tom
```

### Test CommonJS JavaScript using Node.js

In reality, a typical test suite might look more like this. Save this as `test.js`.

```js
const { Tom } = require('test-runner')
const assert = require('assert').strict
const fetch = require('node-fetch')

const tom = new Tom()

tom.test('Math.random() should return a number between 0 and 1', function () {
const result = Math.random()
assert.equal(typeof result, 'number')
assert.ok(result >= 0 && result <= 1)
})

tom.test('REST API should return the current todo item', async function () {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1')
const todo = await response.json()
assert.equal(todo.userId, 1)
assert.equal(todo.title, 'delectus aut autem')
})

module.exports = tom
```

Run the test file using test-runner.

```
$ npx test-runner test.js
Start: 2 tests loaded
✓ synopsis Math.random() should return a number between 0 and 1
✓ synopsis REST API should return the current todo item
Completed in 199ms. Pass: 2, fail: 0, skip: 0.
```

### More examples

* [How to test ECMAScript modules using Node.js](https://github.com/test-runner-js/test-runner/wiki/How-to-test-ECMAScript-modules-using-Node.js)
* [How to test ECMAScript modules in the browser](https://github.com/test-runner-js/test-runner/wiki/How-to-test-ECMAScript-modules-in-the-browser)


## Install

```
$ npm install --save-dev test-runner
```

## Test-runner tool kit

Alternatively, you can run your tests with any of the following runners - each is compatible with test-object-model.

| Environment | Description | Tool |
| ----------- | ------------------------ | ------------- |
| Web | Run your tests in a headless Chromium browser from the command line | [web-runner](https://github.com/test-runner-js/web-runner) |
| Node.js | Test ECMAScript modules natively in Node.js | [esm-runner](https://github.com/test-runner-js/esm-runner) |

## See also

Please see [the wiki](https://github.com/test-runner-js/test-runner/wiki) for more examples.
**Rewrite in progress. This is a pre-release of the next major version.**

* * *

Expand Down
49 changes: 3 additions & 46 deletions bin/cli.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,5 @@
#!/usr/bin/env node
import TestRunner from 'test-runner'
import path from 'path'
import Test from '../lib/test.js'
import ansi from 'ansi-escape-sequences'
import Cli from '../lib/cli.js'

// process.on('uncaughtException', (err, origin) => {
// console.error(`\nAn ${origin} was thrown, possibly in a separate tick.\n`)
// console.error(err)
// process.exit(1)
// })
// process.on('unhandledRejection', (reason, promise) => {
// console.error('\nAn unhandledRejection was thrown. Please ensure the rejecting promise is returned from the test function.\n')
// console.error(reason)
// process.exit(1)
// })

const config = {
files: process.argv.slice(2)
}
const tests = []

function createTests (arr, map, file) {
for (const [name, testFn] of map) {
const test = new Test(name, testFn)
test.data.file = file
tests.push(test)
}
}

for (const file of config.files) {
const testModule = await import(path.resolve(file))
if (testModule?.skip?.size) {
for (const [name] of testModule.skip) {
console.log(`- ${ansi.format(name, ['grey'])}`)
}
}
if (testModule?.only?.size) {
createTests(tests, testModule.only, file)
} else if (testModule?.test?.size) {
createTests(tests, testModule.test, file)
}
}

const runner = new TestRunner(tests)
for await (const test of runner.run()) {
console.log(`${ansi.format('✔', ['green'])} ${ansi.format(test.data.file, ['magenta'])} ${test.name}`)
}
const cli = new Cli()
await cli.start(process.argv.slice(2))
8 changes: 8 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ class TestRunner {
yield test
}
}

async runAll () {
const result = []
for await (const test of this.run()) {
result.push(test)
}
return result
}
}

export default TestRunner
Expand Down
42 changes: 42 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import TestRunner from 'test-runner'
import path from 'path'
import Test from './test.js'
import ansi from 'ansi-escape-sequences'

class Cli {
async start (argv) {
const config = {
files: argv
}
const tests = []

function createTests (arr, map, file) {
for (const [name, testFn] of map) {
const test = new Test(name, testFn)
test.data.file = file
tests.push(test)
}
}

for (const file of config.files) {
const testModule = await import(path.resolve(file))
if (testModule?.skip?.size) {
for (const [name] of testModule.skip) {
console.log(`- ${ansi.format(name, ['grey'])}`)
}
}
if (testModule?.only?.size) {
createTests(tests, testModule.only, file)
} else if (testModule?.test?.size) {
createTests(tests, testModule.test, file)
}
}

const runner = new TestRunner(tests)
for await (const test of runner.run()) {
console.log(`${ansi.format('✔', ['green'])} ${ansi.format(test.data.file, ['magenta'])} ${test.name}`)
}
}
}

export default Cli
2 changes: 1 addition & 1 deletion lib/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class Test {
testFn
result
state
data = {} // optional associated metadata, consumed by runner user not the runner
data = {} // optional associated metadata, consumed by runner user (e.g. to store the test file name) not the runner itself

constructor (name, testFn, options = {}) {
this.name = name
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"index.js"
],
"scripts": {
"test": "node test/tests.js"
"test": "node test/test.js"
},
"standard": {
"ignore": [
Expand Down
15 changes: 15 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import TestRunner from 'test-runner'
import Test from '../lib/test.js'
import { strict as a } from 'assert'

{ /* Sync tess passes, storing the result */
const actuals = []
const test1 = new Test('one', function one () {
actuals.push('one')
return 'one'
})
const runner = new TestRunner([test1])
await runner.runAll()
a.equal(test1.result, 'one')
a.deepEqual(actuals, ['one'])
}

0 comments on commit 3d20483

Please sign in to comment.