├── doc
├── reporter_dot.png
├── reporter_base.png
└── reporter_spec.png
├── .babelrc
├── test
├── cli
│ ├── require-a.js
│ ├── gc.js
│ ├── require-b.js
│ ├── no-timeout.js
│ ├── sigint.js
│ ├── reset_tests.js
│ ├── global.js
│ ├── timeout.js
│ ├── reset.js
│ ├── grep-exclude.js
│ ├── mocha.js
│ ├── reporters.js
│ └── test-in-src.js
├── browser
│ ├── index.html
│ ├── index-error.html
│ ├── index-async.html
│ ├── test-error.js
│ ├── test.js
│ └── test-async.js
├── coffee
│ └── simple.coffee
├── es2015
│ ├── async-hook.js
│ └── async-test.js
├── typings.test.ts
├── index.js
└── others.js
├── .travis.yml
├── tsconfig.json
├── .gitignore
├── bin
├── options.js
├── tman
└── _tman
├── lib
├── browser.js
├── format.js
├── reporters
│ ├── dot.js
│ ├── base.js
│ ├── spec.js
│ ├── browser.js
│ └── diff.js
├── tman.js
└── core.js
├── browser
└── tman.css
├── Makefile
├── example
├── simple.coffee
├── es-next.es
├── test_in_source_code.js
├── mocha.js
├── simple.ts
├── simple.js
├── only-case.js
├── error-case.js
└── nested.js
├── LICENSE
├── package.json
├── index.d.ts
└── README.md
/doc/reporter_dot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thunks/tman/HEAD/doc/reporter_dot.png
--------------------------------------------------------------------------------
/doc/reporter_base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thunks/tman/HEAD/doc/reporter_base.png
--------------------------------------------------------------------------------
/doc/reporter_spec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thunks/tman/HEAD/doc/reporter_spec.png
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015"],
3 | "plugins": ["transform-async-to-generator"]
4 | }
5 |
--------------------------------------------------------------------------------
/test/cli/require-a.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | // `bin/tman -r test/cli/require-a test/cli/require-b`
7 |
8 | global.testRequire = 'tman'
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8"
4 | - "10"
5 | - "12"
6 | - "13"
7 | sudo: false
8 | script: "npm run test-cov"
9 | after_script: "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls"
10 |
--------------------------------------------------------------------------------
/test/cli/gc.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global it */
6 |
7 | // `bin/tman test/cli/gc --gc`
8 |
9 | it('expose gc extension', function () {
10 | global.gc()
11 | })
12 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "moduleResolution": "node"
6 | },
7 | "exclude": [
8 | "coverage",
9 | "debug",
10 | "node_modules"
11 | ],
12 | "compileOnSave": false
13 | }
14 |
--------------------------------------------------------------------------------
/test/browser/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | T-man tests
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/browser/index-error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | T-man tests with errors
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/browser/index-async.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | T-man tests with async/await
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/cli/require-b.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global suite, it, testRequire */
6 |
7 | // `bin/tman -r test/cli/require-a test/cli/require-b`
8 |
9 | const assert = require('assert')
10 |
11 | suite('require', function () {
12 | it('require-a should be "tman"', function () {
13 | assert.strictEqual(testRequire, 'tman')
14 | })
15 | })
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # node-waf configuration
17 | .lock-wscript
18 |
19 | # Dependency directory
20 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
21 | node_modules
22 |
23 | typings
24 | debug
25 | yarn.lock
26 |
--------------------------------------------------------------------------------
/test/cli/no-timeout.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global suite, it */
6 |
7 | // `bin/tman --no-timeout test/cli/no-timeout`
8 |
9 | const thunk = require('thunks')()
10 |
11 | suite('no timeout', function () {
12 | it('test 1100 should ok', function * () {
13 | yield thunk.delay(1100)
14 | })
15 |
16 | it('test 2100 should ok', function * () {
17 | yield thunk.delay(2100)
18 | })
19 |
20 | it('test 3000 should ok', function (done) {
21 | setTimeout(done, 3000)
22 | })
23 | })
24 |
--------------------------------------------------------------------------------
/test/cli/sigint.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global suite, it, after */
6 |
7 | // `bin/tman test/cli/sigint`
8 | // then `control + c`
9 |
10 | const thunk = require('thunks')()
11 |
12 | suite('Should finish graceful when "SIGINT"', function () {
13 | var i = 0
14 | var count = 0
15 |
16 | after(function () {
17 | console.log('End:', i)
18 | })
19 |
20 | while (count++ < 1000) {
21 | it('test ' + count, function * () {
22 | yield thunk.delay(200)
23 | i++
24 | })
25 | }
26 | })
27 |
--------------------------------------------------------------------------------
/test/cli/reset_tests.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global suite, it, before, after */
6 |
7 | const assert = require('assert')
8 | var count = 0
9 |
10 | before(function () {
11 | assert.strictEqual(count++, 0)
12 | })
13 |
14 | after(function () {
15 | assert.strictEqual(count++, 4)
16 | })
17 |
18 | suite('suite', function () {
19 | it('test 1', function () {
20 | assert.strictEqual(count++, 1)
21 | })
22 |
23 | it('test 2', function () {
24 | assert.strictEqual(count++, 2)
25 | })
26 | })
27 |
28 | it('test 3', function () {
29 | assert.strictEqual(count++, 3)
30 | })
31 |
--------------------------------------------------------------------------------
/bin/options.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Modified from https://github.com/mochajs/mocha
3 |
4 | const fs = require('fs')
5 |
6 | module.exports = function () {
7 | const optsPath = process.argv.indexOf('--opts') !== -1
8 | ? process.argv[process.argv.indexOf('--opts') + 1] : 'test/tman.opts'
9 |
10 | try {
11 | const opts = fs.readFileSync(optsPath, 'utf8')
12 | .replace(/\\\s/g, '%20')
13 | .split(/\s/)
14 | .filter(Boolean)
15 | .map((value) => value.replace(/%20/g, ' '))
16 |
17 | process.argv = process.argv
18 | .slice(0, 2)
19 | .concat(opts.concat(process.argv.slice(2)))
20 | } catch (_) {}
21 |
22 | process.env.LOADED_TMAN_OPTS = true
23 | }
24 |
--------------------------------------------------------------------------------
/lib/browser.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | const core = require('./core')
7 | const info = require('../package.json')
8 | const Reporter = require('./reporters/base')
9 | require('./reporters/browser') // mount "browser" as default reporter
10 |
11 | const env = {}
12 | const tm = module.exports = tmanFactroy()
13 | tm.NAME = info.name
14 | tm.VERSION = info.version
15 | tm.Test = core.Test
16 | tm.Suite = core.Suite
17 | tm.Reporter = Reporter
18 | tm.createTman = tmanFactroy
19 | tm.tman = tm
20 | tm.env = env
21 | tm.env.TEST = window.TEST
22 |
23 | function tmanFactroy () {
24 | const tman = core.Tman(env)
25 | tman.setReporter(Reporter.defaultReporter)
26 | return tman
27 | }
28 |
--------------------------------------------------------------------------------
/test/cli/global.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global tman, it */
6 |
7 | // `bin/tman test/cli/global --globals suite,it,before,after`
8 |
9 | const assert = require('assert')
10 | const tman1 = require('../..')
11 |
12 | it('assert global tman', function () {
13 | assert.strictEqual(tman, tman1)
14 | assert.strictEqual(global.tman, tman1)
15 | assert.strictEqual(global.describe, undefined)
16 | assert.strictEqual(global.suite, tman1.suite)
17 | assert.strictEqual(global.test, undefined)
18 | assert.strictEqual(global.it, tman1.it)
19 | assert.strictEqual(global.before, tman1.before)
20 | assert.strictEqual(global.after, tman1.after)
21 | assert.strictEqual(global.beforeEach, undefined)
22 | assert.strictEqual(global.afterEach, undefined)
23 | })
24 |
--------------------------------------------------------------------------------
/test/cli/timeout.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global suite, it */
6 |
7 | // `bin/tman -t 650 test/cli/timeout`
8 |
9 | const thunk = require('thunks')()
10 |
11 | suite('some timeout tests', function () {
12 | it('test 500 should ok', function * () {
13 | yield thunk.delay(500)
14 | })
15 |
16 | it('test 600 should ok', function * () {
17 | yield thunk.delay(600)
18 | })
19 |
20 | it('test 700 should timeout', function * () {
21 | yield thunk.delay(700)
22 | })
23 |
24 | it('test 800 should timeout', function * () {
25 | yield thunk.delay(800)
26 | })
27 |
28 | it('test 900 should ok', function * () {
29 | this.timeout(1000)
30 | yield thunk.delay(900)
31 | })
32 |
33 | it('test 1000 should timeout', function * () {
34 | yield thunk.delay(1000)
35 | })
36 | })
37 |
--------------------------------------------------------------------------------
/browser/tman.css:
--------------------------------------------------------------------------------
1 | #tman {
2 | width: 96%;
3 | max-width: 1024px;
4 | margin: 20px auto 0;
5 | line-height: 28px;
6 | }
7 |
8 | #tman .tman-header {
9 | text-align: center;
10 | }
11 |
12 | #tman .tman-suite h3 {
13 | margin: 0;
14 | font-size: 1.1em;
15 | border-bottom: 1px solid #D0D0D0;
16 | }
17 |
18 | #tman .tman-test {}
19 |
20 | #tman .tman-footer {
21 | margin-top: 20px;
22 | padding-top: 10px;
23 | border-top: 2px solid #9E9E9E;
24 | }
25 |
26 | #tman .tman-statistics {
27 | font-size: 1.2em;
28 | margin-top: 10px;
29 | }
30 |
31 | #tman .tman-statistics span {
32 | padding-right: 12px;
33 | }
34 |
35 | #tman .tman-error h4 {
36 | margin: 0;
37 | }
38 |
39 | #tman .tman-error p {
40 | margin: 0;
41 | }
42 |
43 | #tman .success {
44 | color: #009688;
45 | }
46 |
47 | #tman .error {
48 | color: #E91E63;
49 | }
50 |
51 | #tman .ignored {
52 | color: #03A9F4;
53 | }
54 |
--------------------------------------------------------------------------------
/test/coffee/simple.coffee:
--------------------------------------------------------------------------------
1 | # `bin/tman -r coffee-script/register test/coffee`
2 |
3 | assert = require('assert')
4 | tman = require('../..')
5 |
6 | count = 0
7 |
8 | tman.it 'synchronous test', ->
9 | assert.strictEqual(count++, 0)
10 | return
11 |
12 | tman.it 'callback style asynchronous test', (done) ->
13 | assert.strictEqual(count++, 1)
14 | setTimeout(done, 100)
15 | return
16 |
17 | tman.it 'promise style asynchronous test', ->
18 | assert.strictEqual(count++, 2)
19 | return new Promise((resolve) ->
20 | assert.strictEqual(count++, 3)
21 | setTimeout(resolve, 100)
22 | )
23 |
24 | tman.it 'thunk style asynchronous test', ->
25 | assert.strictEqual(count++, 4)
26 | return (done) ->
27 | assert.strictEqual(count++, 5)
28 | setTimeout(done, 100)
29 |
30 | tman.it 'generator style asynchronous test', ->
31 | assert.strictEqual(count++, 6)
32 | yield (done) -> setTimeout(done, 50)
33 | yield new Promise((resolve) -> setTimeout(resolve, 50))
34 | assert.strictEqual(count++, 7)
35 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | test:
2 | bin/tman 'test/*.js'
3 | bin/tman test/cli/gc -gc
4 | bin/tman test/cli/gc --expose-gc
5 | bin/tman test/cli/global --globals tman,suite,it,before,after
6 | bin/tman -g api -e ignore test/cli/grep-exclude
7 | bin/tman --mocha test/cli/mocha
8 | bin/tman --no-timeout test/cli/no-timeout
9 | !(bin/tman --reporter base test/cli/reporters.js)
10 | !(bin/tman -R dot test/cli/reporters.js)
11 | !(bin/tman --reporter spec test/cli/reporters.js)
12 | bin/tman -r test/cli/require-a test/cli/require-b
13 | bin/tman test/cli/reset
14 | !(bin/tman -t 650 test/cli/timeout)
15 | bin/tman test/cli/test-in-src
16 | node test/cli/test-in-src --test
17 | TEST=* node test/cli/test-in-src
18 | bin/tman -r coffee-script/register test/coffee
19 | bin/tman -r ts-node/register test/typings.test.ts
20 | open test/browser/index-error.html
21 | sleep 2s
22 | open test/browser/index.html
23 | sleep 2s
24 | open test/browser/index-async.html -a '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'
25 |
26 | .PHONY: test
27 |
--------------------------------------------------------------------------------
/test/cli/reset.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global tman */
6 |
7 | // `bin/tman test/cli/reset`
8 |
9 | const path = require('path')
10 | const assert = require('assert')
11 | const thunk = require('thunks')()
12 |
13 | const tests = path.join(__dirname, './reset_tests.js')
14 |
15 | thunk(function * () {
16 | // process don't exit
17 | tman.setExit(false)
18 | tman.loadFiles(tests)
19 | let res = yield tman.run()
20 | assert.strictEqual(res.passed, 3)
21 | assert.strictEqual(res.ignored, 0)
22 |
23 | tman.reset()
24 | // no test
25 | res = yield tman.run()
26 | assert.strictEqual(res.passed, 0)
27 | assert.strictEqual(res.ignored, 0)
28 |
29 | tman.reset()
30 | tman.loadFiles(tests)
31 | tman.it('should error', function () {
32 | throw new Error('some error')
33 | })
34 | res = yield tman.run()
35 | assert.strictEqual(res.passed, 3)
36 | assert.strictEqual(res.ignored, 0)
37 | assert.strictEqual(res.errors.length, 1)
38 |
39 | process.exit(0)
40 | })()
41 |
--------------------------------------------------------------------------------
/example/simple.coffee:
--------------------------------------------------------------------------------
1 | # **Github:** https://github.com/thunks/tman
2 | #
3 | # **License:** MIT
4 |
5 | # `bin/tman -r coffee-script/register example/simple.coffee`
6 |
7 | assert = require('assert')
8 | tman = require('..')
9 |
10 | count = 0
11 |
12 | tman.it 'synchronous test', ->
13 | assert.strictEqual(count++, 0)
14 | return
15 |
16 | tman.it 'callback style asynchronous test', (done) ->
17 | assert.strictEqual(count++, 1)
18 | setTimeout(done, 100)
19 | return
20 |
21 | tman.it 'promise style asynchronous test', ->
22 | assert.strictEqual(count++, 2)
23 | return new Promise((resolve) ->
24 | assert.strictEqual(count++, 3)
25 | setTimeout(resolve, 100)
26 | )
27 |
28 | tman.it 'thunk style asynchronous test', ->
29 | assert.strictEqual(count++, 4)
30 | return (done) ->
31 | assert.strictEqual(count++, 5)
32 | setTimeout(done, 100)
33 |
34 | tman.it 'generator style asynchronous test', ->
35 | assert.strictEqual(count++, 6)
36 | yield (done) -> setTimeout(done, 50)
37 | yield new Promise((resolve) -> setTimeout(resolve, 50))
38 | assert.strictEqual(count++, 7)
39 |
--------------------------------------------------------------------------------
/example/es-next.es:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | // `babel-node --presets es2015 --plugins transform-async-to-generator bin/tman example/es-next.es`
7 | // or (with .babelrc)
8 | // `tman -r babel-register -r babel-polyfill example/es-next.es`
9 |
10 | import assert from 'assert'
11 | import tman from '..'
12 |
13 | var count = 0
14 | // async "after hook"
15 | tman.after(async () => {
16 | assert.strictEqual(await Promise.resolve(count++), 4)
17 | })
18 |
19 | tman.it('async/await asynchronous test', async function () {
20 | assert.strictEqual(await Promise.resolve(count++), 0)
21 | assert.strictEqual(await new Promise((resolve, reject) => {
22 | setTimeout(() => {
23 | resolve(count++)
24 | }, 100)
25 | }), 1)
26 | })
27 |
28 | tman.it('generator asynchronous test', function * () {
29 | // yield Promise
30 | assert.strictEqual(yield Promise.resolve(count++), 2)
31 | // yield thunk function
32 | assert.strictEqual(yield (done) => {
33 | setTimeout(() => {
34 | done(null, count++)
35 | }, 100)
36 | }, 3)
37 | })
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016-2020 thunks
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/test/es2015/async-hook.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | const assert = require('assert')
7 | const thunk = require('thunks')()
8 |
9 | module.exports = function (t) {
10 | var count = 0
11 | t.after(function * () {
12 | assert.strictEqual(count++, 6)
13 | yield function (done) {
14 | assert.strictEqual(count++, 7)
15 | setTimeout(function () {
16 | assert.strictEqual(count++, 8)
17 | done()
18 | }, 10)
19 | }
20 | assert.strictEqual(count++, 9)
21 | yield new Promise(function (resolve) {
22 | assert.strictEqual(count++, 10)
23 | setTimeout(function () {
24 | assert.strictEqual(count++, 11)
25 | resolve()
26 | }, 10)
27 | })
28 | assert.strictEqual(count++, 12)
29 | })
30 |
31 | t.beforeEach(function * () {
32 | yield thunk.delay(10)
33 | count++
34 | })
35 |
36 | t.afterEach(function () {
37 | count++
38 | return thunk.delay(10)
39 | })
40 |
41 | t.it('test 1-1', function () {
42 | assert.strictEqual(count++, 1)
43 | })
44 |
45 | t.it('test 1-2', function () {
46 | assert.strictEqual(count++, 4)
47 | })
48 | }
49 |
--------------------------------------------------------------------------------
/example/test_in_source_code.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | // Run by 3 way:
7 | // tman example/test_in_source_code.js
8 | // node example/test_in_source_code.js --test
9 | // TEST=* node example/test_in_source_code.js
10 |
11 | const tman = require('..')
12 |
13 | // example API 1
14 | exports.indent = function (len) {
15 | var ch = ' '
16 | var pad = ''
17 |
18 | while (len > 0) {
19 | if (len & 1) pad += ch
20 | if ((len >>= 1)) ch = ch + ch
21 | }
22 | return pad
23 | }
24 |
25 | // example API 2
26 | exports.stringify = function (val) {
27 | return val == null ? '' : String(val)
28 | }
29 |
30 | // T-man tests
31 | tman('test in source code', function () {
32 | const assert = require('assert')
33 |
34 | tman.it('indent', function () {
35 | assert.strictEqual(exports.indent(2), ' ')
36 | })
37 |
38 | tman.it('stringify', function () {
39 | assert.strictEqual(exports.stringify(), '')
40 | assert.strictEqual(exports.stringify(null), '')
41 | assert.strictEqual(exports.stringify(0), '0')
42 | assert.strictEqual(exports.stringify(false), 'false')
43 | assert.strictEqual(exports.stringify(true), 'true')
44 | assert.strictEqual(exports.stringify(NaN), 'NaN')
45 | })
46 | })
47 |
--------------------------------------------------------------------------------
/example/mocha.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global describe, it, before, after */
6 |
7 | // `tman example/mocha.js`
8 |
9 | const assert = require('assert')
10 |
11 | var count = 0
12 |
13 | describe('mocha style', function () {
14 | before(function () {
15 | assert.strictEqual(count++, 0)
16 | })
17 |
18 | after(function () {
19 | assert.strictEqual(count++, 9)
20 | })
21 |
22 | it('synchronous test', function () {
23 | assert.strictEqual(count++, 1)
24 | })
25 |
26 | it('callback style asynchronous test', function (done) {
27 | assert.strictEqual(count++, 2)
28 | setTimeout(done, 100)
29 | })
30 |
31 | it('promise style asynchronous test', function () {
32 | assert.strictEqual(count++, 3)
33 | return new Promise(function (resolve) {
34 | assert.strictEqual(count++, 4)
35 | setTimeout(resolve, 100)
36 | })
37 | })
38 |
39 | it('thunk style asynchronous test', function () {
40 | assert.strictEqual(count++, 5)
41 | return function (done) {
42 | assert.strictEqual(count++, 6)
43 | setTimeout(done, 100)
44 | }
45 | })
46 |
47 | it('generator style asynchronous test', function * () {
48 | assert.strictEqual(count++, 7)
49 | yield function (done) { setTimeout(done, 100) }
50 | assert.strictEqual(count++, 8)
51 | })
52 | })
53 |
--------------------------------------------------------------------------------
/test/cli/grep-exclude.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global suite, it, before, after */
6 |
7 | // `bin/tman -g api -e ignore test/cli/grep-exclude`
8 |
9 | const assert = require('assert')
10 | var count = 0
11 |
12 | before(function () {
13 | assert.strictEqual(count++, 0)
14 | })
15 |
16 | after(function () {
17 | assert.strictEqual(count++, 4)
18 | })
19 |
20 | it('should not run', function () {
21 | assert.strictEqual(true, false)
22 | })
23 |
24 | it('api test', function () {
25 | assert.strictEqual(count++, 1)
26 | })
27 |
28 | it('api should ignore', function () {
29 | assert.strictEqual(true, false)
30 | })
31 |
32 | suite('suite', function () {
33 | it('test not run', function () {
34 | assert.strictEqual(true, false)
35 | })
36 |
37 | it('api 1', function () {
38 | assert.strictEqual(count++, 2)
39 | })
40 |
41 | it('ignore 1', function () {
42 | assert.strictEqual(true, false)
43 | })
44 | })
45 |
46 | suite('suite api', function () {
47 | it('test 1', function () {
48 | assert.strictEqual(count++, 3)
49 | })
50 |
51 | it('ignore', function () {
52 | assert.strictEqual(true, false)
53 | })
54 |
55 | it('api ignore', function () {
56 | assert.strictEqual(true, false)
57 | })
58 | })
59 |
60 | suite('ignore suite', function () {
61 | it('test 2', function () {
62 | assert.strictEqual(true, false)
63 | })
64 |
65 | it('api 2', function () {
66 | assert.strictEqual(true, false)
67 | })
68 | })
69 |
70 | it.skip('skip api', function () {
71 | assert.strictEqual(true, false)
72 | })
73 |
--------------------------------------------------------------------------------
/test/es2015/async-test.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | const assert = require('assert')
7 |
8 | module.exports = function (t) {
9 | var count = 0
10 |
11 | t.it('promise style asynchronous test', function () {
12 | assert.strictEqual(count++, 0)
13 | return new Promise(function (resolve) {
14 | assert.strictEqual(count++, 1)
15 | setTimeout(resolve, 10)
16 | })
17 | })
18 |
19 | t.it('generator style asynchronous test', function * () {
20 | assert.strictEqual(count++, 2)
21 | yield function (done) {
22 | assert.strictEqual(count++, 3)
23 | setTimeout(function () {
24 | assert.strictEqual(count++, 4)
25 | done()
26 | }, 10)
27 | }
28 | assert.strictEqual(count++, 5)
29 | yield new Promise(function (resolve) {
30 | assert.strictEqual(count++, 6)
31 | setTimeout(function () {
32 | assert.strictEqual(count++, 7)
33 | resolve()
34 | }, 10)
35 | })
36 | assert.strictEqual(count++, 8)
37 | })
38 |
39 | t.it('generator style asynchronous test, return generator function', function () {
40 | assert.strictEqual(count++, 9)
41 |
42 | return function * () {
43 | assert.strictEqual(count++, 10)
44 | yield function (done) {
45 | assert.strictEqual(count++, 11)
46 | setTimeout(done, 10)
47 | }
48 | assert.strictEqual(count++, 12)
49 | yield new Promise(function (resolve) {
50 | assert.strictEqual(count++, 13)
51 | setTimeout(resolve, 10)
52 | })
53 | assert.strictEqual(count++, 14)
54 | }
55 | })
56 | }
57 |
--------------------------------------------------------------------------------
/example/simple.ts:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | // `ts-node example/simple.ts`
7 |
8 | import * as assert from 'assert'
9 | import { thunk } from 'thunks'
10 | import { run, suite, it } from '..'
11 |
12 | const Rx = require('rxjs')
13 |
14 | var count = 0
15 |
16 | it('synchronous test', function () {
17 | assert.strictEqual(count++, 0)
18 | })
19 |
20 | it('callback style asynchronous test', function (done) {
21 | assert.strictEqual(count++, 1)
22 | setTimeout(done, 100)
23 | })
24 |
25 | it('promise style asynchronous test', function () {
26 | assert.strictEqual(count++, 2)
27 | return new Promise(function (resolve) {
28 | assert.strictEqual(count++, 3)
29 | setTimeout(resolve, 100)
30 | })
31 | })
32 |
33 | it('thunk style asynchronous test', function () {
34 | assert.strictEqual(count++, 4)
35 | return function (done) {
36 | assert.strictEqual(count++, 5)
37 | setTimeout(done, 100)
38 | }
39 | })
40 |
41 | it('generator style asynchronous test', function * () {
42 | assert.strictEqual(count++, 6)
43 | yield (done) => setTimeout(done, 50)
44 | assert.strictEqual(count++, 7)
45 | })
46 |
47 | it('async/await style asynchronous test', async function () {
48 | assert.strictEqual(count++, 8)
49 | await new Promise((resolve) => setTimeout(resolve, 50))
50 | assert.strictEqual(count++, 9)
51 | })
52 |
53 | it('Rx.Observable asynchronous test', function () {
54 | assert.strictEqual(count++, 10)
55 | return Rx.Observable.fromPromise(new Promise(function (resolve) {
56 | assert.strictEqual(count++, 11)
57 | setTimeout(resolve, 100)
58 | }))
59 | })
60 |
61 | run()
62 |
--------------------------------------------------------------------------------
/example/simple.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | // `tman example/simple.js`
7 |
8 | const assert = require('assert')
9 | const tman = require('..')
10 | const Rx = require('rxjs')
11 |
12 | var count = 0
13 |
14 | tman.it('synchronous test', function () {
15 | assert.strictEqual(count++, 0)
16 | })
17 |
18 | tman.it('callback style asynchronous test', function (done) {
19 | assert.strictEqual(count++, 1)
20 | setTimeout(done, 100)
21 | })
22 |
23 | tman.it('promise style asynchronous test', function () {
24 | assert.strictEqual(count++, 2)
25 | return new Promise(function (resolve) {
26 | assert.strictEqual(count++, 3)
27 | setTimeout(resolve, 100)
28 | })
29 | })
30 |
31 | tman.it('thunk style asynchronous test', function () {
32 | assert.strictEqual(count++, 4)
33 | return function (done) {
34 | assert.strictEqual(count++, 5)
35 | setTimeout(done, 100)
36 | }
37 | })
38 |
39 | tman.it('generator style asynchronous test', function * () {
40 | assert.strictEqual(count++, 6)
41 | yield function (done) { setTimeout(done, 50) }
42 | yield new Promise(function (resolve) { setTimeout(resolve, 50) })
43 | assert.strictEqual(count++, 7)
44 | })
45 |
46 | tman.it('Rx.Observable asynchronous test', function () {
47 | assert.strictEqual(count++, 8)
48 | return Rx.Observable.fromPromise(new Promise(function (resolve) {
49 | assert.strictEqual(count++, 9)
50 | setTimeout(resolve, 100)
51 | }))
52 | })
53 |
54 | tman.it('async/await style asynchronous test', async function () {
55 | assert.strictEqual(count++, 10)
56 | await new Promise(function (resolve) { setTimeout(resolve, 50) })
57 | assert.strictEqual(count++, 11)
58 | })
59 |
60 | // tman.run()
61 |
--------------------------------------------------------------------------------
/test/cli/mocha.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global describe, it, before, after, beforeEach, afterEach */
6 |
7 | // `bin/tman --mocha test/cli/mocha`
8 |
9 | const assert = require('assert')
10 | var count = 0
11 |
12 | before(function () {
13 | assert.strictEqual(count++, 0)
14 | })
15 |
16 | after(function () {
17 | assert.strictEqual(count++, 34)
18 | })
19 |
20 | beforeEach(function () {
21 | count++
22 | })
23 |
24 | afterEach(function () {
25 | count++
26 | })
27 |
28 | it('test 1-1', function () {
29 | assert.strictEqual(count++, 2)
30 | })
31 |
32 | it('test 1-2', function () {
33 | assert.strictEqual(count++, 5)
34 | })
35 |
36 | it.skip('test 1-3', function () {
37 | assert.strictEqual(true, false)
38 | })
39 |
40 | describe('suite 1-1', function () {
41 | beforeEach(function () {
42 | count++
43 | })
44 |
45 | it('test 2-1', function () {
46 | assert.strictEqual(count++, 9)
47 | })
48 |
49 | it('test 2-2', function () {
50 | assert.strictEqual(count++, 13)
51 | })
52 |
53 | it('test 2-3', function () {
54 | assert.strictEqual(count++, 17)
55 | })
56 | })
57 |
58 | describe('suite 1-2', function () {
59 | it('test 2-1', function () {
60 | assert.strictEqual(count++, 20)
61 | })
62 | })
63 |
64 | describe('suite 1-3', function () {
65 | afterEach(function () {
66 | count++
67 | })
68 |
69 | it('test 2-1', function () {
70 | assert.strictEqual(count++, 23)
71 | })
72 |
73 | it('test 2-2', function () {
74 | assert.strictEqual(count++, 27)
75 | })
76 |
77 | describe('suite 1-3-1', function () {
78 | it('test 3-1', function () {
79 | assert.strictEqual(count++, 31)
80 | })
81 | })
82 | })
83 |
--------------------------------------------------------------------------------
/example/only-case.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | // `tman example/only-case.js`
7 |
8 | const assert = require('assert')
9 | const thunk = require('thunks')()
10 | const tman = require('..')
11 |
12 | var count = 0
13 |
14 | tman.before(function () {
15 | assert.strictEqual(count++, 0)
16 | console.log('Start only tests')
17 | })
18 |
19 | tman.after(function () {
20 | assert.strictEqual(count++, 5)
21 | console.log('End only tests')
22 | })
23 |
24 | tman.suite('suite 1', function () {
25 | tman.beforeEach(function * () {
26 | yield thunk.delay(10)
27 | })
28 |
29 | tman.it.only('only test 1-1', function () {
30 | assert.strictEqual(count++, 1)
31 | })
32 |
33 | tman.it.skip('skip test', function () {
34 | assert.strictEqual(true, false)
35 | })
36 |
37 | tman.it('assert error', function () {
38 | assert.strictEqual(true, false)
39 | })
40 |
41 | tman.it('throw error', function () {
42 | throw new Error('throw error')
43 | })
44 |
45 | tman.suite.only('only suite 1-2', function () {
46 | tman.it.only('only test 1-2-1', function * () {
47 | assert.strictEqual(count++, 2)
48 | })
49 |
50 | tman.suite('suite 1-2-1', function () {
51 | tman.it('assert error', function () {
52 | assert.strictEqual(true, false)
53 | })
54 |
55 | tman.it('throw error', function () {
56 | throw new Error('throw error')
57 | })
58 |
59 | tman.it.only('only test 1-2-1-1', function () {
60 | assert.strictEqual(count++, 3)
61 | })
62 | })
63 | })
64 | })
65 |
66 | tman.it.only('only test 1-1', function () {
67 | assert.strictEqual(count++, 4)
68 | })
69 |
70 | tman.it('throw error', function () {
71 | throw new Error('throw error')
72 | })
73 |
74 | // tman.run()
75 |
--------------------------------------------------------------------------------
/lib/format.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | var supportsColor = require('supports-color')
7 |
8 | exports.useColors = function (useColors) {
9 | supportsColor = !!useColors
10 | }
11 | exports.indent = function (len) {
12 | let ch = ' '
13 | let pad = ''
14 |
15 | while (len > 0) {
16 | if (len & 1) pad += ch
17 | if ((len >>= 1)) ch = ch + ch // avoid "standard" lint
18 | }
19 | return pad
20 | }
21 |
22 | // https://en.wikipedia.org/wiki/ANSI_escape_code
23 |
24 | // 30–37: set text color to one of the colors 0 to 7,
25 | // 40–47: set background color to one of the colors 0 to 7,
26 | // 39: reset text color to default,
27 | // 49: reset background color to default,
28 | // 1: make text bold / bright (this is the standard way to access the bright color variants),
29 | // 22: turn off bold / bright effect, and
30 | // 0: reset all text properties (color, background, brightness, etc.) to their default values.
31 | // For example, one could select bright purple text on a green background (eww!) with the code `\x1B[35;1;42m`
32 | const styles = { red: 31, green: 32, yellow: 33, cyan: 36, white: 37, gray: 90 }
33 | Object.keys(styles).forEach((key) => {
34 | exports[key] = (str, bright) => style(styles[key], str, bright)
35 | })
36 |
37 | exports.reset = function (str) {
38 | return !supportsColor ? str : ('\x1b[0m' + str)
39 | }
40 |
41 | function style (code, str, bright) {
42 | /* istanbul ignore next */
43 | if (!supportsColor) return str
44 | if (bright) code += ';1'
45 | return '\x1b[' + code + 'm' + str + '\x1b[39;22m'
46 | }
47 |
48 | /**
49 | * Color lines for `str`, using the color `name`.
50 | *
51 | * @api private
52 | * @param {string} name
53 | * @param {string} str
54 | * @return {string}
55 | */
56 | exports.colorLines = function (name, str) {
57 | return str.split('\n').map((str) => exports[name](str)).join('\n')
58 | }
59 |
--------------------------------------------------------------------------------
/example/error-case.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | // `tman example/error-case.js`
7 |
8 | const assert = require('assert')
9 | const thunk = require('thunks')()
10 | const tman = require('..')
11 |
12 | var count = 0
13 |
14 | tman.before(function () {
15 | assert.strictEqual(count++, 0)
16 | console.log('Start error tests')
17 | })
18 |
19 | tman.after(function () {
20 | assert.strictEqual(count++, 8)
21 | console.log('End error tests')
22 | })
23 |
24 | tman.suite('error suite 1', function () {
25 | tman.beforeEach(function * () {
26 | count++
27 | yield thunk.delay(10)
28 | })
29 |
30 | tman.it('success test', function () {
31 | assert.strictEqual(count++, 2)
32 | })
33 |
34 | tman.it.skip('skip test', function () {
35 | assert.strictEqual(count++, 4)
36 | })
37 |
38 | tman.it('assert error', function () {
39 | assert.strictEqual(true, false)
40 | })
41 |
42 | tman.it('throw error', function () {
43 | throw new Error('throw error')
44 | })
45 |
46 | tman.suite('error suite 2', function () {
47 | tman.it('assert error', function * () {
48 | assert.strictEqual(true, false)
49 | yield thunk.delay(100)
50 | })
51 |
52 | tman.suite('error suite 3', function () {
53 | tman.it('assert error', function * () {
54 | yield thunk.delay(100)
55 | assert.strictEqual(true, false)
56 | })
57 |
58 | tman.it('throw error', function () {
59 | throw new Error('throw error')
60 | })
61 |
62 | tman.it('time out error', function * () {
63 | this.timeout(100)
64 | yield thunk.delay(1000)
65 | })
66 | })
67 | })
68 | })
69 |
70 | tman.it('assert error', function () {
71 | assert.strictEqual(true, false)
72 | })
73 |
74 | tman.it('throw error', function () {
75 | throw new Error('throw error')
76 | })
77 |
78 | tman.it('success test', function () {
79 | assert.strictEqual(count++, 7)
80 | })
81 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tman",
3 | "version": "1.10.0",
4 | "description": "T-man: Super test manager for JavaScript.",
5 | "authors": [
6 | "Yan Qing "
7 | ],
8 | "main": "lib/tman.js",
9 | "typings": "index.d.ts",
10 | "bin": {
11 | "tman": "./bin/tman",
12 | "_tman": "./bin/_tman"
13 | },
14 | "scripts": {
15 | "test": "standard && bin/tman 'test/*.js'",
16 | "test-all": "make test",
17 | "test-cov": "standard && istanbul cover bin/_tman 'test/*.js'",
18 | "test-typings": "bin/tman -r ts-node/register test/typings.test.ts",
19 | "browser": "browserify lib/browser.js -s tman -o browser/tman.js"
20 | },
21 | "repository": {
22 | "type": "git",
23 | "url": "git@github.com:thunks/tman.git"
24 | },
25 | "keywords": [
26 | "T-man",
27 | "tman",
28 | "test",
29 | "thunk",
30 | "bdd",
31 | "tdd",
32 | "ava",
33 | "mocha"
34 | ],
35 | "engines": {
36 | "node": ">= 6"
37 | },
38 | "license": "MIT",
39 | "bugs": {
40 | "url": "https://github.com/thunks/tman/issues"
41 | },
42 | "homepage": "https://github.com/thunks/tman",
43 | "dependencies": {
44 | "commander": "^5.0.0",
45 | "diff": "~4.0.2",
46 | "glob": "~7.1.6",
47 | "supports-color": "^7.1.0",
48 | "thunks": "~4.9.6"
49 | },
50 | "devDependencies": {
51 | "@types/mocha": "^7.0.2",
52 | "@types/node": "^13.9.3",
53 | "babel-plugin-transform-async-to-generator": "^6.24.1",
54 | "babel-polyfill": "^6.26.0",
55 | "babel-preset-es2015": "^6.24.1",
56 | "babel-register": "^6.26.0",
57 | "coffee-script": "^1.12.7",
58 | "istanbul": "^0.4.5",
59 | "minimist": "^1.2.5",
60 | "standard": "^14.3.3",
61 | "ts-node": "^8.8.1",
62 | "typescript": "^3.8.3"
63 | },
64 | "files": [
65 | "README.md",
66 | "bin",
67 | "lib",
68 | "browser",
69 | "index.d.ts"
70 | ],
71 | "standard": {
72 | "ignore": [
73 | "browser"
74 | ]
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/lib/reporters/dot.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | const util = require('util')
7 | const Reporter = require('./base')
8 | const Diff = require('./diff')
9 | const format = require('../format')
10 |
11 | module.exports = Dot
12 | Reporter.defaultReporter = Dot
13 |
14 | function Dot (ctx) {
15 | Diff.call(this, ctx)
16 | }
17 |
18 | util.inherits(Dot, Diff)
19 |
20 | Dot.prototype.log = function (str) {
21 | process.stdout.write(str)
22 | }
23 |
24 | Dot.prototype.onStart = function () {
25 | this.log('\n')
26 | }
27 |
28 | Dot.prototype.onTestFinish = function (test) {
29 | let str = ''
30 | if (test.state === null) {
31 | str = format.cyan('-', true)
32 | } else if (test.state === true) {
33 | const time = test.endTime - test.startTime
34 | if (time > 50) str = format.yellow('•', true)
35 | else str = format.green('•', true)
36 | } else {
37 | str = format.red('!', true)
38 | }
39 | this.log(str)
40 | }
41 |
42 | Dot.prototype.onFinish = function (rootSuite) {
43 | let message = '\n'
44 |
45 | if (rootSuite.abort) message += format.yellow('\nTest is terminated by SIGINT!\n', true)
46 | message += format.reset('\nTest ' + (rootSuite.errors.length ? 'failed: ' : 'finished: '))
47 | message += format[rootSuite.passed ? 'green' : 'gray'](rootSuite.passed + ' passed; ', true)
48 | message += format[rootSuite.errors.length ? 'red' : 'gray'](rootSuite.errors.length + ' failed; ', true)
49 | message += format[rootSuite.ignored ? 'cyan' : 'gray'](rootSuite.ignored + ' ignored.', true)
50 | message += format.yellow(' (' + (rootSuite.endTime - rootSuite.startTime) + 'ms)', true)
51 | this.log(message)
52 | this.log(format.reset('\n\n'))
53 |
54 | this.logError(rootSuite)
55 | if (rootSuite.errors.length) this.log(format.reset('\n'))
56 | if (rootSuite.exit) process.exit((rootSuite.errors.length || !rootSuite.passed) ? 1 : 0)
57 | }
58 |
59 | // Result:
60 | // ```
61 | //
62 | // ∙∙∙∙∙∙--∙∙-∙∙!∙
63 | //
64 | // Test failed: 11 passed; 1 failed; 3 ignored. (605ms)
65 | //
66 | // 1) /test level 1-2: AssertionError: 22 === 21
67 | // at Test.fn (/Users/zensh/git/js/thunkjs/tman/example/nested.js:116:10)
68 | // at Test. (/Users/zensh/git/js/thunkjs/tman/lib/core.js:557:37)
69 | //
70 | // ```
71 |
--------------------------------------------------------------------------------
/bin/tman:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | * Modified from https://github.com/mochajs/mocha
4 | *
5 | * This tiny wrapper file checks for known node flags and appends them
6 | * when found, before invoking the "real" _tman(1) executable.
7 | */
8 | 'use strict'
9 |
10 | const path = require('path')
11 | const spawn = require('child_process').spawn
12 | const getOptions = require('./options')
13 | const args = [path.join(__dirname, '_tman')]
14 |
15 | // Load tman.opts into process.argv
16 | // Must be loaded here to handle node-specific options
17 | getOptions()
18 |
19 | process.argv.slice(2).forEach((arg) => {
20 | let flag = arg.split('=')[0]
21 |
22 | switch (flag) {
23 | case '-d':
24 | args.unshift('--debug')
25 | args.push('--no-timeout')
26 | break
27 | case 'debug':
28 | case '--debug':
29 | case '--debug-brk':
30 | args.unshift(arg)
31 | args.push('--no-timeout')
32 | break
33 | case '--inspect':
34 | case '--inspect-brk':
35 | args.unshift(arg)
36 | args.push('--no-timeout')
37 | break
38 | case '-gc':
39 | case '--expose-gc':
40 | args.unshift('--expose-gc')
41 | break
42 | case '--gc-global':
43 | case '--es_staging':
44 | case '--no-deprecation':
45 | case '--prof':
46 | case '--log-timer-events':
47 | case '--throw-deprecation':
48 | case '--trace-deprecation':
49 | case '--use_strict':
50 | case '--allow-natives-syntax':
51 | case '--perf-basic-prof':
52 | args.unshift(arg)
53 | break
54 | default:
55 | if (arg.indexOf('--harmony') === 0) args.unshift(arg)
56 | else if (arg.indexOf('--trace') === 0) args.unshift(arg)
57 | else if (arg.indexOf('--icu-data-dir') === 0) args.unshift(arg)
58 | else if (arg.indexOf('--max-old-space-size') === 0) args.unshift(arg)
59 | else if (arg.indexOf('--preserve-symlinks') === 0) args.unshift(arg)
60 | else args.push(arg)
61 | break
62 | }
63 | })
64 |
65 | const proc = spawn(process.execPath, args, {stdio: 'inherit'})
66 | // listen children exit
67 | proc.once('exit', handleExit)
68 | process.once('exit', handleExit)
69 | function handleExit (code, signal) {
70 | if (signal) process.kill(process.pid, signal)
71 | else process.exit(code)
72 | }
73 | // terminate children.
74 | process.once('SIGINT', () => {
75 | // force to exit in 3.1 seconds.
76 | setTimeout(() => process.exit(1), 3100)
77 | })
78 |
--------------------------------------------------------------------------------
/lib/reporters/base.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | module.exports = Reporter
7 | module.exports.defaultReporter = Reporter
8 |
9 | function Reporter (ctx) {
10 | this.ctx = ctx
11 | this.count = 0
12 | }
13 |
14 | Reporter.prototype.log = function () {
15 | console.log.apply(console, arguments)
16 | }
17 |
18 | Reporter.prototype.onStart = function () {
19 | this.count = 0
20 | this.log('\n')
21 | }
22 |
23 | Reporter.prototype.onSuiteStart = function (suite) {}
24 |
25 | Reporter.prototype.onSuiteFinish = function (suite) {}
26 |
27 | Reporter.prototype.onTestStart = function (test) {}
28 |
29 | Reporter.prototype.onTestFinish = function (test) {
30 | if (test.state) {
31 | const state = test.state === true ? 'pass' : 'fail'
32 | this.log(++this.count + '\t' + test.fullTitle + '\t' + state)
33 | }
34 | }
35 |
36 | Reporter.prototype.onFinish = function (rootSuite) {
37 | let message = '\nTest ' + (rootSuite.errors.length ? 'failed: ' : 'finished: ')
38 | message += rootSuite.passed + ' passed; '
39 | message += rootSuite.errors.length + ' failed; '
40 | message += rootSuite.ignored + ' ignored.'
41 | message += ' (' + (rootSuite.endTime - rootSuite.startTime) + 'ms)\n'
42 | this.log(message)
43 |
44 | rootSuite.errors.forEach((err) => {
45 | this.log(err.order + ') ' + err.title + ':')
46 | this.log(err.stack ? err.stack : String(err))
47 | })
48 | if (rootSuite.exit && process.exit) process.exit((rootSuite.errors.length || !rootSuite.passed) ? 1 : 0)
49 | }
50 |
51 | // Result: order + TAB + fulltitle + TAB + state
52 | // ```
53 | //
54 | // 1 /suite level 1-1/test level 2-1 pass
55 | // 2 /suite level 1-1/test level 2-2 pass
56 | // 3 /suite level 1-1/suite level 2-1/test level 3-1 pass
57 | // 4 /suite level 1-1/suite level 2-1/test level 3-2 pass
58 | // 5 /suite level 1-1/suite level 2-2/test level 3-1 pass
59 | // 6 /suite level 1-1/suite level 2-2/test level 3-2 pass
60 | // 7 /suite level 1-1/suite level 2-2/suite level 3-2/test level 4-1 pass
61 | // 8 /suite level 1-1/suite level 2-2/suite level 3-2/test level 4-2 pass
62 | // 9 /suite level 1-1/suite level 2-2/suite level 3-2/test level 4-4 pass
63 | // 10 /test level 1-1 pass
64 | // 11 /test level 1-2 fail
65 | // 12 /test level 1-3 pass
66 | //
67 | // Test failed: 11 passed; 1 failed; 3 ignored. (608ms)
68 | //
69 | // 1) /test level 1-2:
70 | // Expected: 21
71 | // Actual: 22
72 | // AssertionError: 22 === 21
73 | // at Test.fn (/Users/zensh/git/js/thunkjs/tman/example/nested.js:116:10)
74 | // at Test. (/Users/zensh/git/js/thunkjs/tman/lib/core.js:557:37)
75 | //
76 | // ```
77 |
--------------------------------------------------------------------------------
/example/nested.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | // `tman example/nested.js`
7 |
8 | const assert = require('assert')
9 | const thunk = require('thunks')()
10 | const tman = require('..')
11 |
12 | var count = 0
13 |
14 | tman.before(function () {
15 | assert.strictEqual(count++, 0)
16 | })
17 |
18 | tman.after(function () {
19 | assert.strictEqual(count++, 24)
20 | })
21 |
22 | tman.suite('suite level 1-1', function () {
23 | tman.beforeEach(function * () {
24 | count++
25 | yield thunk.delay(10)
26 | })
27 |
28 | tman.it('test level 2-1', function () {
29 | assert.strictEqual(count++, 2)
30 | })
31 |
32 | tman.it('test level 2-2', function () {
33 | assert.strictEqual(count++, 4)
34 | })
35 |
36 | tman.suite('suite level 2-1', function () {
37 | tman.beforeEach(function * () {
38 | count++
39 | yield thunk.delay(20)
40 | })
41 |
42 | tman.it('test level 3-1', function * () {
43 | assert.strictEqual(count++, 7)
44 | yield thunk.delay(100)
45 | })
46 |
47 | tman.it('test level 3-2', function () {
48 | assert.strictEqual(count++, 9)
49 | })
50 | })
51 |
52 | tman.suite('suite level 2-2', function () {
53 | tman.afterEach(function * () {
54 | count++
55 | yield thunk.delay(20)
56 | })
57 |
58 | tman.it('test level 3-1', function * () {
59 | assert.strictEqual(count++, 11)
60 | yield thunk.delay(100)
61 | })
62 |
63 | tman.it('test level 3-2', function () {
64 | assert.strictEqual(count++, 13)
65 | })
66 |
67 | tman.suite.skip('suite level 3-1', function () {
68 | tman.afterEach(function * () {
69 | assert.strictEqual('skip', false)
70 | })
71 |
72 | tman.it('test level 4-1', function * () {
73 | assert.strictEqual('skip', false)
74 | })
75 |
76 | tman.it('test level 4-2', function () {
77 | assert.strictEqual('skip', false)
78 | })
79 | })
80 |
81 | tman.suite('suite level 3-2', function () {
82 | tman.before(function () {
83 | assert.strictEqual(count++, 15)
84 | })
85 |
86 | tman.after(function () {
87 | assert.strictEqual(count++, 19)
88 | })
89 |
90 | tman.it('test level 4-1', function * () {
91 | assert.strictEqual(count++, 16)
92 | yield thunk.delay(100)
93 | })
94 |
95 | tman.it('test level 4-2', function () {
96 | assert.strictEqual(count++, 17)
97 | })
98 |
99 | tman.it.skip('test level 4-3', function () {
100 | assert.strictEqual('skip', false)
101 | })
102 |
103 | tman.it('test level 4-4', function () {
104 | assert.strictEqual(count++, 18)
105 | })
106 | })
107 | })
108 | })
109 |
110 | tman.it('test level 1-1', function * () {
111 | assert.strictEqual(count++, 21)
112 | yield thunk.delay(100)
113 | })
114 |
115 | tman.it('test level 1-2', function () {
116 | assert.strictEqual(count++, 21) // will error
117 | })
118 |
119 | tman.it('test level 1-3', function () {
120 | assert.strictEqual(count++, 23)
121 | })
122 |
--------------------------------------------------------------------------------
/test/cli/reporters.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | // `tman --reporter dot test/cli/reporters.js`
7 |
8 | const assert = require('assert')
9 | const thunk = require('thunks')()
10 | const tman = require('../..')
11 |
12 | var count = 0
13 |
14 | tman.before(function () {
15 | assert.strictEqual(count++, 0)
16 | })
17 |
18 | tman.after(function () {
19 | assert.strictEqual(count++, 24)
20 | })
21 |
22 | tman.suite('suite level 1-1', function () {
23 | tman.beforeEach(function * () {
24 | count++
25 | yield thunk.delay(10)
26 | })
27 |
28 | tman.it('test level 2-1', function () {
29 | assert.strictEqual(count++, 2)
30 | })
31 |
32 | tman.it('test level 2-2', function () {
33 | assert.strictEqual(count++, 4)
34 | })
35 |
36 | tman.suite('suite level 2-1', function () {
37 | tman.beforeEach(function * () {
38 | count++
39 | yield thunk.delay(20)
40 | })
41 |
42 | tman.it('test level 3-1', function * () {
43 | assert.strictEqual(count++, 7)
44 | yield thunk.delay(100)
45 | })
46 |
47 | tman.it('test level 3-2', function () {
48 | assert.strictEqual(count++, 9)
49 | })
50 | })
51 |
52 | tman.suite('suite level 2-2', function () {
53 | tman.afterEach(function * () {
54 | count++
55 | yield thunk.delay(20)
56 | })
57 |
58 | tman.it('test level 3-1', function * () {
59 | assert.strictEqual(count++, 11)
60 | yield thunk.delay(100)
61 | })
62 |
63 | tman.it('test level 3-2', function () {
64 | assert.strictEqual(count++, 13)
65 | })
66 |
67 | tman.suite.skip('suite level 3-1', function () {
68 | tman.afterEach(function * () {
69 | assert.strictEqual('skip', false)
70 | })
71 |
72 | tman.it('test level 4-1', function * () {
73 | assert.strictEqual('skip', false)
74 | })
75 |
76 | tman.it('test level 4-2', function () {
77 | assert.strictEqual('skip', false)
78 | })
79 | })
80 |
81 | tman.suite('suite level 3-2', function () {
82 | tman.before(function () {
83 | assert.strictEqual(count++, 15)
84 | })
85 |
86 | tman.after(function () {
87 | assert.strictEqual(count++, 19)
88 | })
89 |
90 | tman.it('test level 4-1', function * () {
91 | assert.strictEqual(count++, 16)
92 | yield thunk.delay(100)
93 | })
94 |
95 | tman.it('test level 4-2', function () {
96 | assert.strictEqual(count++, 17)
97 | })
98 |
99 | tman.it.skip('test level 4-3', function () {
100 | assert.strictEqual('skip', false)
101 | })
102 |
103 | tman.it('test level 4-4', function () {
104 | assert.strictEqual(count++, 18)
105 | })
106 | })
107 | })
108 | })
109 |
110 | tman.it('test level 1-1', function * () {
111 | assert.strictEqual(count++, 20) // will error
112 | yield thunk.delay(100)
113 | })
114 |
115 | tman.it('test level 1-2', function () {
116 | assert.strictEqual(count++, 21) // will error
117 | })
118 |
119 | tman.it('test level 1-3', function () {
120 | assert.strictEqual(count++, 23)
121 | })
122 |
--------------------------------------------------------------------------------
/test/browser/test-error.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global tman */
6 |
7 | var count = 0
8 | var assert = {
9 | strictEqual: function (a, b) {
10 | if (a !== b) throw new Error(String(a) + ' not equal ' + String(b))
11 | }
12 | }
13 |
14 | function delay (n) {
15 | return function (done) {
16 | setTimeout(done, n)
17 | }
18 | }
19 |
20 | tman.before(function () {
21 | assert.strictEqual(count++, 0)
22 | console.log('Start practical tests')
23 | })
24 |
25 | tman.after(function () {
26 | assert.strictEqual(count++, 25)
27 | console.log('End practical tests')
28 | })
29 |
30 | tman.suite('suite level 1-1', function () {
31 | tman.beforeEach(function * () {
32 | count++
33 | yield delay(10)
34 | })
35 |
36 | tman.it('test level 2-1', function () {
37 | assert.strictEqual(count++, 2)
38 | })
39 |
40 | tman.it('test level 2-2', function () {
41 | assert.strictEqual(count++, 4)
42 | })
43 |
44 | tman.suite('suite level 2-1', function () {
45 | tman.beforeEach(function * () {
46 | count++
47 | yield delay(20)
48 | })
49 |
50 | tman.it('test level 3-1', function * () {
51 | assert.strictEqual(count++, 7)
52 | yield delay(100)
53 | })
54 |
55 | tman.it('test level 3-2', function () {
56 | assert.strictEqual(count++, 9)
57 | })
58 | })
59 |
60 | tman.suite('suite level 2-2', function () {
61 | tman.afterEach(function * () {
62 | count++
63 | yield delay(20)
64 | })
65 |
66 | tman.it('test level 3-1', function * () {
67 | assert.strictEqual(count++, 11)
68 | yield delay(100)
69 | })
70 |
71 | tman.it('test level 3-2', function () {
72 | assert.strictEqual(count++, 13)
73 | })
74 |
75 | tman.suite('suite level 3-1', function () {
76 | tman.afterEach(function * () {
77 | assert.strictEqual('skip', false)
78 | })
79 |
80 | tman.it('test level 4-1', function * () {
81 | assert.strictEqual('skip', 'skip')
82 | })
83 |
84 | tman.it('test level 4-2', function () {
85 | assert.strictEqual('skip', false)
86 | })
87 | })
88 |
89 | tman.suite('suite level 3-2', function () {
90 | tman.before(function () {
91 | assert.strictEqual(count++, 16)
92 | })
93 |
94 | tman.after(function () {
95 | assert.strictEqual(count++, 20)
96 | })
97 |
98 | tman.it('test level 4-1', function * () {
99 | assert.strictEqual(count++, 17)
100 | yield delay(100)
101 | })
102 |
103 | tman.it('test level 4-2', function () {
104 | assert.strictEqual(count++, 18)
105 | })
106 |
107 | tman.it('test level 4-3', function () {
108 | assert.strictEqual('test error', false)
109 | })
110 |
111 | tman.it('test level 4-4', function () {
112 | assert.strictEqual(count++, 19)
113 | })
114 | })
115 | })
116 | })
117 |
118 | tman.it('test level 1-1', function * () {
119 | assert.strictEqual(count++, 22)
120 | yield delay(100)
121 | })
122 |
123 | tman.it('test level 1-2', function () {
124 | assert.strictEqual(count++, 23)
125 | })
126 |
127 | tman.it('test level 1-3', function () {
128 | assert.strictEqual(count++, 24)
129 | })
130 |
131 | tman.run()
132 |
--------------------------------------------------------------------------------
/test/browser/test.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global tman */
6 |
7 | var count = 0
8 | var assert = {
9 | strictEqual: function (a, b) {
10 | if (a !== b) throw new Error(String(a) + ' not equal ' + String(b))
11 | }
12 | }
13 |
14 | function delay (n) {
15 | return function (done) {
16 | setTimeout(done, n)
17 | }
18 | }
19 |
20 | tman.before(function () {
21 | assert.strictEqual(count++, 0)
22 | console.log('Start practical tests')
23 | })
24 |
25 | tman.after(function () {
26 | assert.strictEqual(count++, 24)
27 | console.log('End practical tests')
28 | })
29 |
30 | tman.suite('suite level 1-1', function () {
31 | tman.beforeEach(function * () {
32 | count++
33 | yield delay(10)
34 | })
35 |
36 | tman.it('test level 2-1', function () {
37 | assert.strictEqual(count++, 2)
38 | })
39 |
40 | tman.it('test level 2-2', function () {
41 | assert.strictEqual(count++, 4)
42 | })
43 |
44 | tman.suite('suite level 2-1', function () {
45 | tman.beforeEach(function * () {
46 | count++
47 | yield delay(20)
48 | })
49 |
50 | tman.it('test level 3-1', function * () {
51 | assert.strictEqual(count++, 7)
52 | yield delay(100)
53 | })
54 |
55 | tman.it('test level 3-2', function () {
56 | assert.strictEqual(count++, 9)
57 | })
58 | })
59 |
60 | tman.suite('suite level 2-2', function () {
61 | tman.afterEach(function * () {
62 | count++
63 | yield delay(20)
64 | })
65 |
66 | tman.it('test level 3-1', function * () {
67 | assert.strictEqual(count++, 11)
68 | yield delay(100)
69 | })
70 |
71 | tman.it('test level 3-2', function () {
72 | assert.strictEqual(count++, 13)
73 | })
74 |
75 | tman.suite.skip('suite level 3-1', function () {
76 | tman.afterEach(function * () {
77 | assert.strictEqual('skip', false)
78 | })
79 |
80 | tman.it('test level 4-1', function * () {
81 | assert.strictEqual('skip', false)
82 | })
83 |
84 | tman.it('test level 4-2', function () {
85 | assert.strictEqual('skip', false)
86 | })
87 | })
88 |
89 | tman.suite('suite level 3-2', function () {
90 | tman.before(function () {
91 | assert.strictEqual(count++, 15)
92 | })
93 |
94 | tman.after(function () {
95 | assert.strictEqual(count++, 19)
96 | })
97 |
98 | tman.it('test level 4-1', function * () {
99 | assert.strictEqual(count++, 16)
100 | yield delay(100)
101 | })
102 |
103 | tman.it('test level 4-2', function () {
104 | assert.strictEqual(count++, 17)
105 | })
106 |
107 | tman.it.skip('test level 4-3', function () {
108 | assert.strictEqual('skip', false)
109 | })
110 |
111 | tman.it('test level 4-4', function () {
112 | assert.strictEqual(count++, 18)
113 | })
114 | })
115 | })
116 | })
117 |
118 | tman.it('test level 1-1', function * () {
119 | assert.strictEqual(count++, 21)
120 | yield delay(100)
121 | })
122 |
123 | tman.it('test level 1-2', function () {
124 | assert.strictEqual(count++, 22)
125 | })
126 |
127 | tman.it('test level 1-3', function () {
128 | assert.strictEqual(count++, 23)
129 | })
130 |
131 | tman.run()
132 |
--------------------------------------------------------------------------------
/lib/reporters/spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | const util = require('util')
7 | const Reporter = require('./base')
8 | const Diff = require('./diff')
9 | const format = require('../format')
10 |
11 | module.exports = Spec
12 | Reporter.defaultReporter = Spec
13 |
14 | function Spec (ctx) {
15 | Diff.call(this, ctx)
16 | }
17 |
18 | util.inherits(Spec, Diff)
19 |
20 | Spec.prototype.onSuiteStart = function (suite) {
21 | if (this.ctx === suite.ctx) return // It is rootSuite
22 | let title = '✢ ' + suite.title
23 | title = format[suite.mode === 'skip' ? 'cyan' : 'white'](title, true)
24 | this.log(format.indent(suite.depth) + title)
25 | }
26 |
27 | Spec.prototype.onSuiteFinish = function (suite) {
28 | if (suite.state instanceof Error) {
29 | const title = format.red('✗ ' + suite.state.title + ' (' + suite.state.order + ')', true)
30 | this.log(format.indent(suite.depth + 1) + title)
31 | }
32 | }
33 |
34 | Spec.prototype.onTestFinish = function (test) {
35 | let title = test.title
36 | if (test.state === null) {
37 | title = format.cyan('‒ ' + title, true)
38 | } else if (test.state === true) {
39 | title = format.green('✓ ') + format.gray(title)
40 | const time = test.endTime - test.startTime
41 | if (time > 50) title += format.red(' (' + time + 'ms)')
42 | } else {
43 | title = format.red('✗ ' + title + ' (' + test.state.order + ')', true)
44 | }
45 | this.log(format.indent(test.depth) + title)
46 | }
47 |
48 | Spec.prototype.onFinish = function (rootSuite) {
49 | let message = ''
50 |
51 | if (rootSuite.abort) message += format.yellow('\nTest is terminated by SIGINT!\n', true)
52 | message += format.reset('\nTest ' + (rootSuite.errors.length ? 'failed: ' : 'finished: '))
53 | message += format[rootSuite.passed ? 'green' : 'gray'](rootSuite.passed + ' passed; ', true)
54 | message += format[rootSuite.errors.length ? 'red' : 'gray'](rootSuite.errors.length + ' failed; ', true)
55 | message += format[rootSuite.ignored ? 'cyan' : 'gray'](rootSuite.ignored + ' ignored.', true)
56 | message += format.yellow(' (' + (rootSuite.endTime - rootSuite.startTime) + 'ms)', true)
57 | this.log(message, format.reset('\n'))
58 |
59 | this.logError(rootSuite)
60 | if (rootSuite.errors.length) this.log(format.reset('\n'))
61 | if (rootSuite.exit) process.exit((rootSuite.errors.length || !rootSuite.passed) ? 1 : 0)
62 | }
63 |
64 | // Result:
65 | // ```
66 | //
67 | // ✢ suite level 1-1
68 | // ✓ test level 2-1
69 | // ✓ test level 2-2
70 | // ✢ suite level 2-1
71 | // ✓ test level 3-1 (106ms)
72 | // ✓ test level 3-2
73 | // ✢ suite level 2-2
74 | // ✓ test level 3-1 (105ms)
75 | // ✓ test level 3-2
76 | // ✢ suite level 3-1
77 | // ‒ test level 4-1
78 | // ‒ test level 4-2
79 | // ✢ suite level 3-2
80 | // ✓ test level 4-1 (100ms)
81 | // ✓ test level 4-2
82 | // ‒ test level 4-3
83 | // ✓ test level 4-4
84 | // ✓ test level 1-1 (100ms)
85 | // ✗ test level 1-2 (1)
86 | // ✓ test level 1-3
87 | //
88 | // Test failed: 11 passed; 1 failed; 3 ignored. (606ms)
89 | //
90 | // 1) /test level 1-2:
91 | // AssertionError: 22 === 21
92 | // at Test.fn (/Users/zensh/git/js/thunkjs/tman/example/nested.js:116:10)
93 | // at Test. (/Users/zensh/git/js/thunkjs/tman/lib/core.js:557:37)
94 | //
95 | // ```
96 |
--------------------------------------------------------------------------------
/test/browser/test-async.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 | /* global tman */
6 |
7 | var count = 0
8 | var assert = {
9 | strictEqual: function (a, b) {
10 | if (a !== b) throw new Error(String(a) + ' not equal ' + String(b))
11 | }
12 | }
13 |
14 | function delay (n) {
15 | return new Promise((resolve, reject) => setTimeout(resolve, n))
16 | }
17 |
18 | tman.before(function () {
19 | assert.strictEqual(count++, 0)
20 | console.log('Start practical tests')
21 | })
22 |
23 | tman.after(function () {
24 | assert.strictEqual(count++, 24)
25 | console.log('End practical tests')
26 | })
27 |
28 | tman.suite('suite level 1-1', function () {
29 | tman.beforeEach(function * () {
30 | count++
31 | yield delay(10)
32 | })
33 |
34 | tman.it('test level 2-1', function () {
35 | assert.strictEqual(count++, 2)
36 | })
37 |
38 | tman.it('test level 2-2', function () {
39 | assert.strictEqual(count++, 4)
40 | })
41 |
42 | tman.suite('suite level 2-1', function () {
43 | tman.beforeEach(async function () {
44 | count++
45 | await delay(20)
46 | })
47 |
48 | tman.it('test level 3-1', async () => {
49 | assert.strictEqual(count++, 7)
50 | await delay(100)
51 | })
52 |
53 | tman.it('test level 3-2', function () {
54 | assert.strictEqual(count++, 9)
55 | })
56 | })
57 |
58 | tman.suite('suite level 2-2', function () {
59 | tman.afterEach(async () => {
60 | count++
61 | await delay(20)
62 | })
63 |
64 | tman.it('test level 3-1', async function () {
65 | assert.strictEqual(count++, 11)
66 | await delay(100)
67 | })
68 |
69 | tman.it('test level 3-2', function () {
70 | assert.strictEqual(count++, 13)
71 | })
72 |
73 | tman.suite.skip('suite level 3-1', function () {
74 | tman.afterEach(async function () {
75 | assert.strictEqual('skip', false)
76 | })
77 |
78 | tman.it('test level 4-1', async function () {
79 | assert.strictEqual('skip', false)
80 | })
81 |
82 | tman.it('test level 4-2', function () {
83 | assert.strictEqual('skip', false)
84 | })
85 | })
86 |
87 | tman.suite('suite level 3-2', function () {
88 | tman.before(function () {
89 | assert.strictEqual(count++, 15)
90 | })
91 |
92 | tman.after(function () {
93 | assert.strictEqual(count++, 19)
94 | })
95 |
96 | tman.it('test level 4-1', async function () {
97 | assert.strictEqual(count++, 16)
98 | await delay(100)
99 | })
100 |
101 | tman.it('test level 4-2', function () {
102 | assert.strictEqual(count++, 17)
103 | })
104 |
105 | tman.it.skip('test level 4-3', function () {
106 | assert.strictEqual('skip', false)
107 | })
108 |
109 | tman.it('test level 4-4', function () {
110 | assert.strictEqual(count++, 18)
111 | })
112 | })
113 | })
114 | })
115 |
116 | tman.it('test level 1-1', async function () {
117 | assert.strictEqual(count++, 21)
118 | await delay(100)
119 | })
120 |
121 | tman.it('test level 1-2', function () {
122 | assert.strictEqual(count++, 22)
123 | })
124 |
125 | tman.it('test level 1-3', function () {
126 | assert.strictEqual(count++, 23)
127 | })
128 |
129 | tman.run()
130 |
--------------------------------------------------------------------------------
/test/cli/test-in-src.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | // `bin/tman test/cli/test-in-src`
7 | // `TEST=* node test/cli/test-in-src`
8 | // `node test/cli/test-in-src --test`
9 |
10 | const assert = require('assert')
11 | const thunk = require('thunks')()
12 | const tman = require('../..')
13 |
14 | var count = 0
15 |
16 | module.exports = atomicCount
17 | function atomicCount () {
18 | return count++
19 | }
20 |
21 | tman(function () {
22 | tman.before(function () {
23 | assert.strictEqual(atomicCount(), 0)
24 | })
25 |
26 | tman.after(function () {
27 | assert.strictEqual(atomicCount(), 24)
28 | })
29 |
30 | tman.suite('suite level 1-1', function () {
31 | tman.beforeEach(function * () {
32 | atomicCount()
33 | yield thunk.delay(10)
34 | })
35 |
36 | tman.it('test level 2-1', function () {
37 | assert.strictEqual(atomicCount(), 2)
38 | })
39 |
40 | tman.it('test level 2-2', function () {
41 | assert.strictEqual(atomicCount(), 4)
42 | })
43 |
44 | tman.suite('suite level 2-1', function () {
45 | tman.beforeEach(function * () {
46 | atomicCount()
47 | yield thunk.delay(20)
48 | })
49 |
50 | tman.it('test level 3-1', function * () {
51 | assert.strictEqual(atomicCount(), 7)
52 | yield thunk.delay(100)
53 | })
54 |
55 | tman.it('test level 3-2', function () {
56 | assert.strictEqual(atomicCount(), 9)
57 | })
58 | })
59 |
60 | tman.suite('suite level 2-2', function () {
61 | tman.afterEach(function * () {
62 | atomicCount()
63 | yield thunk.delay(20)
64 | })
65 |
66 | tman.it('test level 3-1', function * () {
67 | assert.strictEqual(atomicCount(), 11)
68 | yield thunk.delay(100)
69 | })
70 |
71 | tman.it('test level 3-2', function () {
72 | assert.strictEqual(atomicCount(), 13)
73 | })
74 |
75 | tman.suite.skip('suite level 3-1', function () {
76 | tman.afterEach(function * () {
77 | assert.strictEqual('skip', false)
78 | })
79 |
80 | tman.it('test level 4-1', function * () {
81 | assert.strictEqual('skip', false)
82 | })
83 |
84 | tman.it('test level 4-2', function () {
85 | assert.strictEqual('skip', false)
86 | })
87 | })
88 |
89 | tman.suite('suite level 3-2', function () {
90 | tman.before(function () {
91 | assert.strictEqual(atomicCount(), 15)
92 | })
93 |
94 | tman.after(function () {
95 | assert.strictEqual(atomicCount(), 19)
96 | })
97 |
98 | tman.it('test level 4-1', function * () {
99 | assert.strictEqual(atomicCount(), 16)
100 | yield thunk.delay(100)
101 | })
102 |
103 | tman.it('test level 4-2', function () {
104 | assert.strictEqual(atomicCount(), 17)
105 | })
106 |
107 | tman.it.skip('test level 4-3', function () {
108 | assert.strictEqual('skip', false)
109 | })
110 |
111 | tman.it('test level 4-4', function () {
112 | assert.strictEqual(atomicCount(), 18)
113 | })
114 | })
115 | })
116 | })
117 |
118 | tman.it('test level 1-1', function * () {
119 | assert.strictEqual(atomicCount(), 21)
120 | yield thunk.delay(100)
121 | })
122 |
123 | tman.it('test level 1-2', function () {
124 | assert.strictEqual(atomicCount(), 22)
125 | })
126 |
127 | tman.it('test level 1-3', function () {
128 | assert.strictEqual(atomicCount(), 23)
129 | })
130 | })
131 |
--------------------------------------------------------------------------------
/lib/tman.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | const fs = require('fs')
7 | const path = require('path')
8 | const glob = require('glob')
9 | const core = require('./core')
10 | const format = require('./format')
11 | const info = require('../package.json')
12 | const Reporter = require('./reporters/base')
13 | require('./reporters/spec') // mount "spec" as default reporter
14 |
15 | const env = {}
16 | const tm = module.exports = tmanFactroy()
17 | tm.NAME = info.name
18 | tm.VERSION = info.version
19 | tm.Test = core.Test
20 | tm.Suite = core.Suite
21 | tm.Reporter = Reporter
22 | tm.format = format
23 | tm.createTman = tmanFactroy
24 | tm.tman = tm
25 | tm.env = env
26 | tm.env.TEST = getProcessEnv()
27 | tm.baseDir = ''
28 | tm.setBaseDir = function (filePath) {
29 | if (!tm.baseDir) tm.baseDir = path.dirname(filePath)
30 | else {
31 | for (let i = 0; i < tm.baseDir.length; i++) {
32 | if (tm.baseDir[i] === filePath[i]) continue
33 | tm.baseDir = tm.baseDir.slice(0, i)
34 | return
35 | }
36 | }
37 | }
38 | tm.loadFiles = function (files, sort) {
39 | if (!Array.isArray(files)) files = [files]
40 | if (tm.baseDir && require.cache) {
41 | // clear test files require cache
42 | Object.keys(require.cache).forEach((id) => {
43 | if (id.indexOf(tm.baseDir) === 0) delete require.cache[id]
44 | })
45 | }
46 | files = resolveFiles(files)
47 | if (sort !== false) sortFiles(files)
48 | files.forEach((filePath) => {
49 | filePath = path.resolve(filePath)
50 | tm.setBaseDir(filePath)
51 | require(filePath)
52 | })
53 | }
54 | tm.globals = function (globals) {
55 | globals.forEach((name) => {
56 | if (global[name]) throw new Error('"' + name + '" exists on global')
57 | if (!tm[name]) throw new Error('"' + name + '" not exists on tman')
58 | global[name] = tm[name]
59 | })
60 | }
61 | tm.useColors = function (useColors) {
62 | format.useColors(useColors)
63 | }
64 | tm.loadReporter = function (reporter) {
65 | const reporterPath = path.join(__dirname, 'reporters', reporter)
66 | try {
67 | const Reporter = require(reporterPath)
68 | tm.setReporter(Reporter)
69 | } catch (err) {
70 | throw new Error('reporter "' + reporter + '" does not exist in ' + reporterPath)
71 | }
72 | }
73 |
74 | function tmanFactroy () {
75 | const tman = core.Tman(env)
76 | tman.setReporter(Reporter.defaultReporter)
77 | return tman
78 | }
79 |
80 | function getProcessEnv () {
81 | let envTest = tm.env.TEST || process.env.TEST
82 | if (envTest) return envTest
83 | for (let i = 2; i < process.argv.length; i++) {
84 | if (process.argv[i].indexOf('--test') === 0) {
85 | envTest = process.argv[i].slice(7)
86 | break
87 | }
88 | }
89 | return envTest == null ? '' : (envTest || 'root')
90 | }
91 |
92 | function resolveFiles (args) {
93 | const files = []
94 | args.forEach((arg) => {
95 | const result = []
96 | if (fsStat(arg) === 1) {
97 | files.push(arg)
98 | return
99 | }
100 | const filenames = glob.sync(arg)
101 | if (!filenames.length) filenames.push(arg + '.js')
102 | filenames.forEach((filename) => {
103 | const stat = fsStat(filename)
104 | if (stat === 1) result.push(filename)
105 | else if (stat === 2) {
106 | result.push.apply(result, glob.sync(path.join(filename, '*.{js,ts,es,coffee}')))
107 | }
108 | })
109 | files.push.apply(files, result)
110 | })
111 | return files
112 | }
113 |
114 | function sortFiles (files) {
115 | files.sort((a, b) => (a.split(path.sep).length - b.split(path.sep).length) || Number(a > b) || -Number(a < b))
116 | }
117 |
118 | function fsStat (filePath) {
119 | try {
120 | const stat = fs.statSync(filePath)
121 | if (stat.isFile()) return 1
122 | else if (stat.isDirectory()) return 2
123 | else return 0
124 | } catch (e) {}
125 | return 0
126 | }
127 |
--------------------------------------------------------------------------------
/lib/reporters/browser.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | const Reporter = require('./base')
7 |
8 | module.exports = Browser
9 | Reporter.defaultReporter = Browser
10 |
11 | function Browser (ctx) {
12 | Reporter.call(this, ctx)
13 | }
14 | inherits(Browser, Reporter)
15 |
16 | Browser.prototype.onStart = function (suite) {
17 | let rootElement = document.getElementById('tman')
18 | if (!rootElement) {
19 | rootElement = createElement('div', 'tman')
20 | rootElement.setAttribute('id', 'tman')
21 | document.body.appendChild(rootElement)
22 | }
23 | rootElement.appendChild(createElement('h2', 'tman-header', 'T-man'))
24 | this.ctx.$element = rootElement
25 | }
26 |
27 | Browser.prototype.onSuiteStart = function (suite) {
28 | if (this.ctx === suite.ctx) return // It is rootSuite
29 | const title = '✢ ' + suite.title
30 | const $element = suite.ctx.$element = createElement('div', 'tman-suite')
31 | $element.appendChild(createElement('h3', '', indent(suite.depth) + title))
32 | suite.ctx.parent.$element.appendChild($element)
33 | }
34 |
35 | Browser.prototype.onSuiteFinish = function (suite) {
36 | if (suite.state instanceof Error) {
37 | suite.ctx.$element.setAttribute('class', 'tman-test error')
38 | const $element = createElement('span', 'more-info',
39 | indent(suite.depth + 1) + suite.state.title + ' ✗ (' + suite.state.order + ')')
40 | suite.ctx.$element.appendChild($element)
41 | }
42 | }
43 |
44 | Browser.prototype.onTestStart = function (test) {
45 | test.ctx.$element = createElement('div', 'tman-test', indent(test.depth) + test.title)
46 | test.ctx.parent.$element.appendChild(test.ctx.$element)
47 | }
48 |
49 | Browser.prototype.onTestFinish = function (test) {
50 | let message = ''
51 | let className = 'tman-test '
52 | if (test.state === null) {
53 | message += ' ‒'
54 | className += 'ignored'
55 | } else if (test.state === true) {
56 | message += ' ✓'
57 | className += 'success'
58 | const time = test.endTime - test.startTime
59 | if (time > 50) message += ' (' + time + 'ms)'
60 | } else {
61 | message += ' ✗ (' + test.state.order + ')'
62 | className += 'error'
63 | }
64 | test.ctx.$element.setAttribute('class', className)
65 | if (message) {
66 | test.ctx.$element.appendChild(createElement('span', 'more-info', message))
67 | }
68 | }
69 |
70 | Browser.prototype.onFinish = function (rootSuite) {
71 | const resultElement = createElement('div', 'tman-footer')
72 | this.ctx.$element.appendChild(resultElement)
73 |
74 | const statElement = createElement('div', 'tman-statistics')
75 | statElement.appendChild(createElement('span',
76 | 'info', 'Test ' + (rootSuite.errors.length ? 'failed: ' : 'finished: ')))
77 | statElement.appendChild(createElement('span',
78 | rootSuite.passed && 'success', rootSuite.passed + ' passed;'))
79 | statElement.appendChild(createElement('span',
80 | rootSuite.errors.length && 'error', rootSuite.errors.length + ' failed;'))
81 | statElement.appendChild(createElement('span',
82 | rootSuite.errors && 'ignored', rootSuite.ignored + ' ignored.'))
83 | statElement.appendChild(createElement('span',
84 | 'info', '(' + (rootSuite.endTime - rootSuite.startTime) + 'ms)'))
85 |
86 | resultElement.appendChild(statElement)
87 | /* istanbul ignore next */
88 | rootSuite.errors.forEach((err) => {
89 | const errElement = createElement('div', 'tman-error')
90 | errElement.appendChild(createElement('h4', 'error', err.order + ') ' + err.title + ':'))
91 | let message = err.stack ? err.stack : String(err)
92 | message = message.replace(/^/gm, '
').replace(/ /g, ' ').slice(5)
93 | errElement.appendChild(createElement('p', 'error-stack', message))
94 | resultElement.appendChild(errElement)
95 | })
96 | }
97 |
98 | function indent (len) {
99 | let ch = ' '
100 | let pad = ''
101 |
102 | while (len > 0) {
103 | if (len & 1) pad += ch
104 | if ((len >>= 1)) ch = ch + ch // avoid "standard" lint
105 | }
106 | return pad
107 | }
108 |
109 | function createElement (tag, className, content) {
110 | const el = document.createElement(tag)
111 | if (className) el.setAttribute('class', className)
112 | if (content) el.innerHTML = content
113 | return el
114 | }
115 |
116 | function inherits (Child, Parent) {
117 | function Ctor () {
118 | this.constructor = Child
119 | }
120 |
121 | Ctor.prototype = Parent.prototype
122 | Child.prototype = new Ctor()
123 | return Child
124 | }
125 |
--------------------------------------------------------------------------------
/lib/reporters/diff.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | const util = require('util')
7 | const diff = require('diff')
8 | const Reporter = require('./base')
9 | const format = require('../format')
10 | const objToString = Object.prototype.toString
11 |
12 | module.exports = Diff
13 | Reporter.defaultReporter = Diff
14 |
15 | function Diff (ctx) {
16 | Reporter.call(this, ctx)
17 | }
18 |
19 | util.inherits(Diff, Reporter)
20 |
21 | Diff.prototype.onFinish = function (rootSuite) {
22 | let message = '\nTest ' + (rootSuite.errors.length ? 'failed: ' : 'finished: ')
23 | message += rootSuite.passed + ' passed; '
24 | message += rootSuite.errors.length + ' failed; '
25 | message += rootSuite.ignored + ' ignored.'
26 | message += ' (' + (rootSuite.endTime - rootSuite.startTime) + 'ms)\n'
27 | this.log(message)
28 | this.logError(rootSuite)
29 | if (rootSuite.exit && process.exit) process.exit((rootSuite.errors.length || !rootSuite.passed) ? 1 : 0)
30 | }
31 |
32 | Diff.prototype.logError = function (rootSuite) {
33 | rootSuite.errors.forEach((err, i) => {
34 | // msg
35 | let msg
36 | let message
37 | if (err.message && typeof err.message.toString === 'function') {
38 | message = err.message + ''
39 | } else if (typeof err.inspect === 'function') {
40 | message = err.inspect() + ''
41 | } else {
42 | message = ''
43 | }
44 | let stack = err.stack || message
45 | let index = message ? stack.indexOf(message) : -1
46 | let actual = err.actual
47 | let expected = err.expected
48 |
49 | if (index === -1) {
50 | msg = message
51 | } else {
52 | index += message.length
53 | msg = stack.slice(0, index)
54 | // remove msg from stack
55 | stack = stack.slice(index + 1)
56 | }
57 |
58 | // uncaught
59 | if (err.uncaught) {
60 | msg = 'Uncaught ' + msg
61 | }
62 | // explicitly show diff
63 | const isShowDiff = err.showDiff !== false && sameType(actual, expected) && expected !== undefined
64 | if (isShowDiff) {
65 | if (!(typeof actual === 'string' && typeof expected === 'string')) {
66 | err._actual = err.actual
67 | err._expected = err.expected
68 | err.actual = actual = stringify(actual)
69 | err.expected = expected = stringify(expected)
70 | }
71 |
72 | const match = message.match(/^([^:]+): expected/)
73 | msg = '\n ' + format.gray(match ? match[1] : msg)
74 |
75 | msg += unifiedDiff(err)
76 | }
77 |
78 | // indent stack trace
79 | stack = stack.replace(/^/gm, ' ')
80 | const result = errMessageFormat(isShowDiff, (i + 1), err.title, msg, stack)
81 | this.log(result)
82 | })
83 | }
84 |
85 | /**
86 | * Return formated error message
87 | * @private
88 | * @param{boolean} is diff message
89 | * @param{number} index of message in Error queue
90 | * @param{string} test suite title
91 | * @param{string} error message
92 | * @param{string} error stack
93 | */
94 | function errMessageFormat (showDiff, pos, title, msg, stack) {
95 | if (showDiff) {
96 | return format.red(' ' + pos + ') ' + title + ':\n' + msg) + format.gray('\n' + stack + '\n')
97 | }
98 | return format.red(' ' + pos + ') ' + title + ':\n') +
99 | format.white(' ' + msg) +
100 | format.white('\n' + stack + '\n')
101 | }
102 |
103 | /**
104 | * Returns a unified diff between two strings.
105 | * @private
106 | * @param {Error} err with actual/expected
107 | * @return {string} The diff.
108 | */
109 | function unifiedDiff (err) {
110 | const indent = ' '
111 | function cleanUp (line) {
112 | if (line[0] === '+') {
113 | return indent + format.colorLines('green', line)
114 | }
115 | if (line[0] === '-') {
116 | return indent + format.colorLines('red', line)
117 | }
118 | if (line.match(/@@/)) {
119 | return null
120 | }
121 | if (line.match(/\\ No newline/)) {
122 | return null
123 | }
124 | if (line.trim().length) {
125 | line = format.colorLines('white', line)
126 | }
127 | return indent + line
128 | }
129 | function notBlank (line) {
130 | return typeof line !== 'undefined' && line !== null
131 | }
132 | let msg = diff.createPatch('string', err.actual, err.expected)
133 | let lines = msg.split('\n').splice(4)
134 | let diffResult = lines.map(cleanUp).filter(notBlank).join('\n')
135 | if (!diffResult.trim().length) {
136 | msg = diff.createPatch(
137 | 'string',
138 | stringify(Object.keys(err._actual || err.actual).sort()),
139 | stringify(Object.keys(err._expected || err.expected).sort())
140 | )
141 | lines = msg.split('\n').splice(4)
142 | diffResult = format.red(' object keys not match: \n') + lines.map(cleanUp).filter(notBlank).join('\n')
143 | }
144 | return '\n ' +
145 | format.colorLines('green', '+ expected') + ' ' +
146 | format.colorLines('red', '- actual') +
147 | '\n\n' +
148 | diffResult
149 | }
150 |
151 | /**
152 | * Check that a / b have the same type.
153 | *
154 | * @private
155 | * @param {Object} a
156 | * @param {Object} b
157 | * @return {boolean}
158 | */
159 | function sameType (a, b) {
160 | return objToString.call(a) === objToString.call(b)
161 | }
162 |
163 | let CIRCULAR_ERROR_MESSAGE
164 |
165 | function stringify (obj) {
166 | try {
167 | if (obj && typeof obj.toJSON === 'function') {
168 | obj = obj.toJSON()
169 | }
170 | return typeof obj === 'string'
171 | ? obj : JSON.stringify(obj, Object.keys(obj).sort(), 2).replace(/,(\n|$)/g, '$1')
172 | } catch (err) {
173 | // Populate the circular error message lazily
174 | if (!CIRCULAR_ERROR_MESSAGE) {
175 | try {
176 | const a = {}; a.a = a; JSON.stringify(a)
177 | } catch (err) {
178 | CIRCULAR_ERROR_MESSAGE = err.message
179 | }
180 | }
181 | if (err.name === 'TypeError' && err.message === CIRCULAR_ERROR_MESSAGE) {
182 | return '[Circular]'
183 | }
184 | }
185 | return '[object Object]'
186 | }
187 |
--------------------------------------------------------------------------------
/bin/_tman:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict'
3 |
4 | const fs = require('fs')
5 | const path = require('path')
6 | const program = require('commander')
7 | const getOptions = require('./options')
8 | const packageInfo = require('../package.json')
9 | const cwd = process.cwd()
10 |
11 | // Prefer the local installation of T-man
12 | const tman = localTman(path.join(cwd, 'node_modules', 'tman')) || localTman(cwd) || require('..')
13 | if (packageInfo.version !== tman.VERSION) {
14 | console.warn(tman.format.red('\nWarning: T-man version mismatch:', true))
15 | console.warn(tman.format.red(
16 | ' Global: v' + packageInfo.version + ', update: npm i -g tman', true))
17 | console.warn(tman.format.red(
18 | ' Local: v' + tman.VERSION + ', update: npm i tman@latest\n', true))
19 | }
20 |
21 | // options
22 | program._name = tman.NAME
23 | program
24 | .version('v' + tman.VERSION)
25 | .usage('[debug] [options] [files]')
26 | .option('-c, --colors', 'force enabling of colors')
27 | .option('-C, --no-colors', 'force disabling of colors')
28 | .option('-d, --debug', "enable node's debugger, synonym for node --debug")
29 | .option('-e, --exclude ', 'exclude tests matching ')
30 | .option('-g, --grep ', 'run tests matching ')
31 | .option('-gc, --expose-gc', 'expose gc extension')
32 | .option('-r, --require ', 'require the given module')
33 | .option('-R, --reporter ', 'specify the reporter to use [spec]')
34 | .option('-t, --timeout ', 'set test-case timeout in milliseconds [2000]')
35 | .option('--debug-brk', "enable node's debugger breaking on the first line")
36 | .option('--inspect', "enable node's debugger breaking on the first line")
37 | .option('--inspect-brk', "enable node's debugger breaking on the first line")
38 | .option('--es_staging', 'enable all staged features')
39 | .option('--globals ', 'allow the given comma-delimited global [names]')
40 | .option('--harmony<_classes,_generators,...>', 'all node --harmony* flags are available')
41 | .option('--icu-data-dir', 'include ICU data')
42 | .option('--mocha', 'mocha compatible mode')
43 | .option('--no-sort', 'don\'t sort test files')
44 | .option('--no-timeout', 'disables timeouts, given implicitly with --debug')
45 | .option('--no-exit',
46 | 'require a clean shutdown of the event loop: T-man will not call process.exit')
47 | .option('--opts ', 'specify opts path', 'test/tman.opts')
48 | .option('--perf-basic-prof', 'enable perf linux profiler (basic support)')
49 | .option('--preserve-symlinks', 'Instructs the module loader to preserve symbolic links when resolving and caching modules')
50 | .option('--reporters', 'display available reporters')
51 | .option('--throw-deprecation', 'throw an exception anytime a deprecated function is used')
52 | .option('--trace', 'trace function calls')
53 | .option('--trace-deprecation', 'show stack traces on deprecations')
54 | .option('--use_strict', 'enforce strict mode')
55 |
56 | module.paths.push(cwd, path.join(cwd, 'node_modules'))
57 | // -r, --require
58 | const requires = []
59 | program.on('option:require', (name) => {
60 | let stat = fsStat(name + '.js') || fsStat(name)
61 | if (stat) name = path.resolve(name)
62 | requires.push(name)
63 | })
64 | // --globals
65 | const globals = []
66 | program.on('option:globals', (val) => {
67 | globals.push.apply(globals, parseList(val))
68 | })
69 | program.on('option:reporters', () => {
70 | console.log()
71 | console.log(' dot - dot matrix')
72 | console.log(' spec - hierarchical spec list')
73 | console.log(' base - spec-style listing with TAB')
74 | console.log()
75 | process.exit()
76 | })
77 |
78 | // If not already done, load mocha.opts
79 | if (!process.env.LOADED_TMAN_OPTS) getOptions()
80 | // parse args
81 | program.parse(process.argv)
82 |
83 | // --no-colors | --colors
84 | if (~process.argv.indexOf('--no-colors') || ~process.argv.indexOf('-C')) tman.useColors(false)
85 | else if (~process.argv.indexOf('--colors') || ~process.argv.indexOf('-c')) tman.useColors(true)
86 | // --exclude
87 | if (program.exclude) tman.exclude(program.exclude)
88 | // --grep
89 | if (program.grep) tman.grep(program.grep)
90 | // --mocha
91 | if (program.mocha) tman.mocha()
92 | // --no-exit
93 | tman.setExit(program.exit)
94 | // --timeout
95 | const timeout = program.timeout === false ? -1 : parseInt(program.timeout, 10)
96 | if (timeout) tman.timeout(timeout)
97 |
98 | // reporter
99 | if (program.reporter) tman.loadReporter(program.reporter)
100 |
101 | // requires
102 | requires.forEach((mod) => require(mod))
103 |
104 | // register to global object
105 | const defaultGlobals = ['tman', 'describe', 'suite', 'test', 'it', 'before', 'after', 'beforeEach', 'afterEach']
106 | tman.globals(globals.length ? globals : defaultGlobals)
107 |
108 | if (!tman.env.TEST) tman.env.TEST = 'root'
109 | if (!process.env.npm_execpath) {
110 | // can't exit when runing with npm. https://github.com/npm/npm/issues/4603
111 | process.once('SIGINT', () => {
112 | tman.abort()
113 | // force to exit in 3 seconds.
114 | setTimeout(() => tman.exit(1), 3000)
115 | })
116 | }
117 |
118 | // // load test files.
119 | const files = program.args
120 | // default files to `test/*.{js,ts,es,coffee}`
121 | if (!files.length) files.push(path.join('test', '*.{js,ts,es,coffee}'))
122 | tman.loadFiles(files, program.sort !== false)
123 | tman.tryRun()
124 |
125 | function localTman (dirname) {
126 | let tmanId = path.sep + path.join('lib', 'tman.js')
127 | let file = path.join(dirname, 'lib', 'tman.js')
128 | if (file.slice(tmanId.length * -1) !== tmanId) return null
129 | if (fsStat(file) !== 1 || fsStat(path.join(dirname, 'bin', 'tman')) !== 1) return null
130 | return require(file)
131 | }
132 |
133 | // 0: unknown, 1: file, 2: directory
134 | function fsStat (filePath) {
135 | try {
136 | let stat = fs.statSync(filePath)
137 | if (stat.isFile()) return 1
138 | else if (stat.isDirectory()) return 2
139 | else return 0
140 | } catch (e) {}
141 | return 0
142 | }
143 |
144 | // Parse list.
145 | function parseList (str) {
146 | return str.replace(/\W/g, ' ').trim().split(/ +/)
147 | }
148 |
--------------------------------------------------------------------------------
/test/typings.test.ts:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | // `bin/tman -r ts-node/register test/typings.test.ts`
4 |
5 | ///
6 |
7 | import { thunk, thunks, Scope } from 'thunks'
8 | import * as assert from 'assert'
9 | import * as tman from '../'
10 | import { tman as tman1, Suite, Test, Reporter, suite, it } from '../'
11 |
12 | tman(function () {}) // should ok
13 | tman(function (done) {}) // should error
14 | tman('test', function () {}) // should ok
15 |
16 | tman.suite('tman typings', () => {
17 | tman.it('tman', function () {
18 | assert.ok(tman.suite instanceof Function)
19 | assert.ok(tman.it instanceof Function)
20 | assert.ok(tman.before instanceof Function)
21 | assert.ok(tman.after instanceof Function)
22 | assert.ok(tman.beforeEach instanceof Function)
23 | assert.ok(tman.afterEach instanceof Function)
24 | assert.ok(tman.only instanceof Function)
25 | assert.ok(tman.skip instanceof Function)
26 |
27 | assert.ok(tman.Suite instanceof Function)
28 | assert.ok(tman.Test instanceof Function)
29 | assert.ok(tman.setBaseDir instanceof Function)
30 | assert.ok(tman.grep instanceof Function)
31 | assert.ok(tman.exclude instanceof Function)
32 | assert.ok(tman.mocha instanceof Function)
33 | assert.ok(tman.reset instanceof Function)
34 | assert.ok(tman.setExit instanceof Function)
35 | assert.ok(tman.tryRun instanceof Function)
36 | assert.ok(tman.run instanceof Function)
37 | assert.ok(tman.createTman instanceof Function)
38 | assert.ok(tman.loadFiles instanceof Function)
39 | assert.ok(tman.loadReporter instanceof Function)
40 | assert.ok(tman.useColors instanceof Function)
41 | assert.ok(tman.globals instanceof Function)
42 | assert.ok(tman.rootSuite instanceof Suite)
43 | assert.ok(tman.rootSuite.reporter instanceof Reporter)
44 |
45 | assert.ok(tman.Reporter.prototype.log instanceof Function)
46 | assert.ok(tman.Reporter.prototype.onSuiteStart instanceof Function)
47 | assert.ok(tman.Reporter.prototype.onSuiteFinish instanceof Function)
48 | assert.ok(tman.Reporter.prototype.onTestStart instanceof Function)
49 | assert.ok(tman.Reporter.prototype.onTestFinish instanceof Function)
50 | assert.ok(tman.Reporter.prototype.onStart instanceof Function)
51 | assert.ok(tman.Reporter.prototype.onFinish instanceof Function)
52 |
53 | assert.strictEqual(tman, tman1)
54 | assert.strictEqual(tman.Suite, Suite)
55 | assert.strictEqual(tman.Test, Test)
56 | assert.strictEqual(tman.it, it)
57 | assert.strictEqual(tman.it, tman.test)
58 | assert.strictEqual(tman.suite, suite)
59 | assert.strictEqual(tman.suite, tman.describe)
60 | })
61 |
62 | tman.it('tman(suite)', function () {
63 | let tm = tman.createTman()
64 | assert.ok(tm(function () {}) instanceof tman.Suite)
65 | assert.ok(tm('test', function () {}) instanceof tman.Suite)
66 | tm.setExit(false)
67 | return tm.run(function () {})
68 | })
69 | })
70 |
71 | tman.suite('run with typings', () => {
72 | let count = 0
73 |
74 | tman.before(() => {
75 | assert.strictEqual(count++, 0)
76 | })
77 |
78 | tman.after((done) => {
79 | assert.strictEqual(count++, 24)
80 | done()
81 | })
82 |
83 | tman.suite('suite level 1-1', () => {
84 | tman.beforeEach(function () {
85 | count++
86 | return thunk.delay(10)
87 | })
88 |
89 | tman.it('test level 2-1', function () {
90 | assert.strictEqual(count++, 2)
91 | return Promise.resolve()
92 | })
93 |
94 | tman.it('test level 2-2', function * () {
95 | yield thunk.delay(10)
96 | assert.strictEqual(count++, 4)
97 | })
98 |
99 | tman.suite('suite level 2-1', () => {
100 | tman.beforeEach(function () {
101 | count++
102 | return {
103 | then: function (resolve, reject) {
104 | return Promise.resolve(resolve())
105 | }
106 | }
107 | })
108 |
109 | tman.it('test level 3-1', function () {
110 | assert.strictEqual(count++, 7)
111 | return {
112 | toThunk: function () {
113 | return function (done) { setTimeout(done, 10)}
114 | }
115 | }
116 | })
117 |
118 | tman.it('test level 3-2', () => {
119 | assert.strictEqual(count++, 9)
120 |
121 | return {
122 | toPromise: function () {
123 | return Promise.resolve()
124 | }
125 | }
126 | })
127 | })
128 |
129 | tman.suite('suite level 2-2', () => {
130 | tman.afterEach(function () {
131 | count++
132 | return (function *() { yield thunk.delay(20) })()
133 | })
134 |
135 | tman.it('test level 3-1', function () {
136 | assert.strictEqual(count++, 11)
137 | return thunks(new Scope())(1)
138 | })
139 |
140 | tman.it('test level 3-2', () => {
141 | assert.strictEqual(count++, 13)
142 | })
143 |
144 | tman.suite.skip('suite level 3-1', () => {
145 | tman.afterEach(function () {
146 | assert.strictEqual('skip', false)
147 | })
148 |
149 | tman.it('test level 4-1', function () {
150 | assert.strictEqual('skip', false)
151 | })
152 |
153 | tman.it('test level 4-2', () => {
154 | assert.strictEqual('skip', false)
155 | })
156 | })
157 |
158 | tman.suite('suite level 3-2', function () {
159 | tman.before(function () {
160 | assert.strictEqual(count++, 15)
161 | })
162 |
163 | tman.after(function () {
164 | assert.strictEqual(count++, 19)
165 | })
166 |
167 | tman.it('test level 4-1', function () {
168 | assert.strictEqual(count++, 16)
169 | return thunk.delay(100)
170 | })
171 |
172 | tman.it('test level 4-2', function () {
173 | assert.strictEqual(count++, 17)
174 | })
175 |
176 | tman.it.skip('test level 4-3', function () {
177 | assert.strictEqual('skip', false)
178 | })
179 |
180 | tman.it('test level 4-4', function () {
181 | assert.strictEqual(count++, 18)
182 | })
183 | })
184 | })
185 | })
186 |
187 | tman.it('test level 1-1', function () {
188 | this.timeout(1000)
189 | assert.strictEqual(count++, 21)
190 | return thunk.delay(100)
191 | })
192 |
193 | tman.it('test level 1-2', function () {
194 | assert.strictEqual(count++, 22)
195 | })
196 |
197 | tman.it('test level 1-3', function () {
198 | assert.strictEqual(count++, 23)
199 | })
200 | })
201 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for tman
2 | // Project: https://github.com/thunks/tman
3 | // Definitions by: zensh
4 |
5 | // Import: `import * as tman from 'tman'`
6 | // Import: `import { suite, it, before, after, beforeEach, afterEach } from 'tman'`
7 |
8 | interface Callback {
9 | (err?: Error): void;
10 | }
11 |
12 | interface ThunkLikeFunction {
13 | (fn: Callback): void;
14 | }
15 |
16 | interface ThunkFunction {
17 | (fn?: Callback): ThunkFunction;
18 | }
19 |
20 | interface AsyncFunction extends Function {
21 | (): PromiseLike;
22 | }
23 |
24 | interface AsyncFunctionConstructor {
25 | new (...args: string[]): AsyncFunction;
26 | (...args: string[]): AsyncFunction;
27 | prototype: AsyncFunction;
28 | }
29 |
30 | interface PromiseLike {
31 | then(onfulfilled?: (value: any) => any, onrejected?: (reason: Error) => any): PromiseLike;
32 | }
33 |
34 | interface ToThunk {
35 | toThunk(): ThunkLikeFunction;
36 | }
37 |
38 | interface ToPromise {
39 | toPromise(): PromiseLike;
40 | }
41 |
42 | interface SuiteAction {
43 | (done?: SuitDone): void;
44 | }
45 |
46 | type SuitDone = (error?: any) => any;
47 |
48 | type TestAction = (done: SuitDone) => any | PromiseLike;
49 |
50 | interface SuiteFn {
51 | (title: string, fn: SuiteAction): tman.Suite;
52 | only(title: string, fn: SuiteAction): tman.Suite;
53 | skip(title: string, fn: SuiteAction): tman.Suite;
54 | }
55 |
56 | interface TestFn {
57 | (title: string, fn: TestAction): tman.Test;
58 | only(title: string, fn: TestAction): tman.Test;
59 | skip(title: string, fn: TestAction): tman.Test;
60 | }
61 |
62 | interface SuiteResult {
63 | ctx: tman.Suite;
64 | title: string;
65 | fullTitle: string;
66 | depth: number;
67 | startTime: number;
68 | endTime: number;
69 | state: Error | boolean;
70 | mode: 'skip' | 'only' | 'hasOnly';
71 | }
72 |
73 | interface RootSuiteResult extends SuiteResult {
74 | ctx: RootSuite;
75 | abort: boolean;
76 | passed: number;
77 | ignored: number;
78 | errors: Array;
79 | }
80 |
81 | interface TestResult {
82 | ctx: tman.Test;
83 | title: string;
84 | fullTitle: string;
85 | depth: number;
86 | startTime: number;
87 | endTime: number;
88 | state: Error | boolean;
89 | mode: 'skip' | 'only';
90 | }
91 |
92 | interface RootSuite extends tman.Suite {
93 | abort: boolean;
94 | passed: number;
95 | ignored: number;
96 | errors: Array;
97 | reporter: tman.Reporter;
98 | }
99 |
100 | interface Tman {
101 | (suite: SuiteAction): tman.Suite;
102 | (title: string, suite: SuiteAction): tman.Suite;
103 | rootSuite: RootSuite;
104 | suite: SuiteFn;
105 | describe: SuiteFn;
106 | test: TestFn;
107 | it: TestFn;
108 | only(suite: SuiteAction): tman.Suite;
109 | skip(suite: SuiteAction): tman.Suite;
110 | only(title: string, fn: SuiteAction): tman.Suite;
111 | skip(title: string, fn: SuiteAction): tman.Suite;
112 | before(test: TestAction): void;
113 | after(test: TestAction): void;
114 | beforeEach(test: TestAction): void;
115 | afterEach(test: TestAction): void;
116 | grep(pattern: string): void;
117 | exclude(pattern: string): void;
118 | mocha(): void;
119 | reset(): void;
120 | setExit(shouldExit: boolean): void;
121 | setReporter(reporter: tman.Reporter, options?: any): void;
122 | timeout(duration: number): void;
123 | tryRun(delay?: number): ThunkFunction;
124 | run(callback?: Callback): ThunkFunction;
125 | }
126 |
127 | declare function tman (suite: SuiteAction): tman.Suite;
128 | declare function tman (title: string, suite: SuiteAction): tman.Suite;
129 | declare namespace tman {
130 | export const NAME: string;
131 | export const VERSION: string;
132 | export const TEST: string;
133 | export var baseDir: string;
134 | // method in Tman interface
135 | export const suite: SuiteFn;
136 | export const describe: SuiteFn;
137 | export const test: TestFn;
138 | export const it: TestFn;
139 | export const rootSuite: RootSuite;
140 |
141 | export function tman (suite: SuiteAction): tman.Suite;
142 | export function tman (title: string, suite: SuiteAction): tman.Suite;
143 | export function only(suite: SuiteAction): Suite;
144 | export function skip(suite: SuiteAction): Suite;
145 | export function only(title: string, fn: SuiteAction): Suite;
146 | export function skip(title: string, fn: SuiteAction): Suite;
147 | export function before(test: TestAction): void;
148 | export function after(test: TestAction): void;
149 | export function beforeEach(test: TestAction): void;
150 | export function afterEach(test: TestAction): void;
151 | export function grep(pattern: string): void;
152 | export function exclude(pattern: string): void;
153 | export function mocha(): void;
154 | export function reset(): void;
155 | export function setExit(shouldExit: boolean): void;
156 | export function timeout(duration: number): void;
157 | export function tryRun(delay?: number): ThunkFunction;
158 | export function run(callback?: Callback): ThunkFunction;
159 |
160 | // extra method
161 | export function createTman (): Tman;
162 | export function setBaseDir(path: string): void;
163 | export function globals(args: Array): void;
164 | export function useColors(args: boolean): void;
165 | export function loadReporter(reporter: string): void;
166 | export function loadFiles(files: string | Array, sort?: boolean): void;
167 |
168 | export class Test {
169 | title: string;
170 | parent: Suite;
171 | root: Suite;
172 | startTime: number;
173 | endTime: number;
174 | state: boolean | Error | void;
175 | depth: number;
176 | mode: 'skip' | 'only';
177 | constructor(title: string, parent: Suite, mode: 'only' | 'skip' | '');
178 | onStart(): void;
179 | onFinish(): void;
180 | fullTitle(): string;
181 | timeout(duration: number): void;
182 | toJSON(): TestResult;
183 | toThunk(): ThunkLikeFunction;
184 | }
185 |
186 | export class Suite {
187 | title: string;
188 | parent: Suite;
189 | root: Suite;
190 | startTime: number;
191 | endTime: number;
192 | state: boolean | Error | void;
193 | depth: number;
194 | children: Array;
195 | mode: 'skip' | 'only' | 'hasOnly';
196 | constructor(title: string, parent: Suite, fn: TestAction, mode: 'only' | 'skip' | '');
197 | reset(): Suite;
198 | onStart(): void;
199 | onFinish(): void;
200 | fullTitle(): string;
201 | timeout(duration: number): void;
202 | toJSON(): SuiteResult;
203 | toThunk(): ThunkLikeFunction;
204 | log(...args: any[]): void;
205 | }
206 |
207 | export class Reporter {
208 | ctx: Suite;
209 | constructor(ctx: Suite, options?: any);
210 | log(...args: any[]): void;
211 | onStart(): void;
212 | onSuiteStart(suiteResult: SuiteResult): void;
213 | onSuiteFinish(suiteResult: SuiteResult): void;
214 | onTestStart(suiteResult: TestResult): void;
215 | onTestFinish(suiteResult: TestResult): void;
216 | onFinish(rootSuiteResult: RootSuiteResult): void;
217 | }
218 | }
219 |
220 | export = tman;
221 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | var path = require('path')
7 | var util = require('util')
8 | var assert = require('assert')
9 | var slice = Array.prototype.slice
10 |
11 | var tman = require('..')
12 | var format = tman.format
13 | var supportES2015 = false
14 |
15 | try { // 检测是否支持 generator,是则加载 generator 测试
16 | supportES2015 = new Function('return function* (){}') // eslint-disable-line
17 | } catch (e) {}
18 |
19 | assert.strictEqual(tman.baseDir, path.join(process.cwd(), 'test'))
20 |
21 | function CustomReporter (ctx, childCtx) {
22 | tman.Reporter.defaultReporter.call(this, ctx)
23 | this.childCtx = childCtx
24 | }
25 | util.inherits(CustomReporter, tman.Reporter.defaultReporter)
26 | CustomReporter.prototype.onFinish = function (res) {
27 | tman.rootSuite.passed += res.passed + res.errors.length + res.ignored
28 | }
29 | CustomReporter.prototype.log = function () {
30 | var args = slice.call(arguments)
31 | args[0] = format.indent(this.childCtx.depth) + args[0]
32 | tman.rootSuite.reporter.log.apply(null, args)
33 | }
34 |
35 | tman.afterEach(function () {
36 | tman.rootSuite.reporter.log('')
37 | })
38 |
39 | tman.suite('Suites and tests', function () {
40 | tman.it('synchronous and asynchronous test', function () {
41 | var ctx = this
42 | var count = 0
43 | // new child instance for test
44 | var t = tman.createTman()
45 | t.setReporter(CustomReporter, this)
46 |
47 | t.before(function () {
48 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
49 | assert.strictEqual(count++, 0)
50 | })
51 |
52 | t.after(function () {
53 | assert.strictEqual(count++, 5)
54 | })
55 |
56 | t.it('synchronous test', function () {
57 | assert.strictEqual(count++, 1)
58 | })
59 |
60 | t.it('callback style asynchronous test', function (done) {
61 | assert.strictEqual(count++, 2)
62 | setTimeout(done, 10)
63 | })
64 |
65 | t.it('thunk style asynchronous test', function () {
66 | assert.strictEqual(count++, 3)
67 | return function (done) {
68 | assert.strictEqual(count++, 4)
69 | setTimeout(done, 10)
70 | }
71 | })
72 |
73 | if (supportES2015) require('./es2015/async-test')(t)
74 | return t.run()
75 | })
76 |
77 | tman.it('nested suites and tests', function () {
78 | var ctx = this
79 | var count = 0
80 | // new child instance for test
81 | var t = tman.createTman()
82 | t.setReporter(CustomReporter, this)
83 |
84 | t.before(function () {
85 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
86 | assert.strictEqual(count++, 0)
87 | })
88 |
89 | t.after(function () {
90 | assert.strictEqual(count++, 26)
91 | })
92 |
93 | t.suite('suite 1-1', function () {
94 | t.beforeEach(function () {
95 | count++
96 | })
97 |
98 | t.it('test 2-1', function () {
99 | assert.strictEqual(count++, 2)
100 | })
101 |
102 | t.it('test 2-2', function () {
103 | assert.strictEqual(count++, 4)
104 | })
105 |
106 | t.suite('suite 2-1', function () {
107 | t.beforeEach(function () {
108 | count++
109 | })
110 |
111 | t.it('test 3-1', function () {
112 | assert.strictEqual(count++, 7)
113 | })
114 |
115 | t.it('test 3-2', function () {
116 | assert.strictEqual(count++, 9)
117 | })
118 | })
119 |
120 | t.suite('suite 2-2', function () {
121 | t.afterEach(function () {
122 | count++
123 | })
124 |
125 | t.it('test 3-1', function () {
126 | assert.strictEqual(count++, 11)
127 | })
128 |
129 | t.it('test 3-2', function () {
130 | assert.strictEqual(count++, 13)
131 | })
132 |
133 | t.suite('suite 3-1', function () {
134 | t.before(function () {
135 | assert.strictEqual(count++, 15)
136 | })
137 |
138 | t.after(function () {
139 | assert.strictEqual(count++, 19)
140 | })
141 |
142 | t.it('test 4-1', function () {
143 | assert.strictEqual(count++, 16)
144 | })
145 |
146 | t.it('test 4-2', function () {
147 | assert.strictEqual(count++, 17)
148 | })
149 |
150 | t.it('test 4-3', function () {
151 | assert.strictEqual(count++, 18)
152 | })
153 | })
154 |
155 | t.it('test 3-3', function () {
156 | assert.strictEqual(count++, 21)
157 | })
158 | })
159 | })
160 |
161 | t.it('test 1-1', function () {
162 | assert.strictEqual(count++, 23)
163 | })
164 |
165 | t.it('test 1-2', function () {
166 | assert.strictEqual(count++, 24)
167 | })
168 |
169 | t.it('test 1-3', function () {
170 | assert.strictEqual(count++, 25)
171 | })
172 |
173 | return t.run()
174 | })
175 |
176 | tman.it('invalid suite and test', function () {
177 | var t = tman.createTman()
178 |
179 | assert.throws(function () {
180 | t.suite(function () {})
181 | }, /invalid string/)
182 |
183 | assert.throws(function () {
184 | t.suite(123, function () {})
185 | }, /invalid string/)
186 |
187 | assert.throws(function () {
188 | t.it(null, function () {})
189 | }, /invalid string/)
190 |
191 | assert.throws(function () {
192 | t.it([], function () {})
193 | }, /invalid string/)
194 |
195 | assert.throws(function () {
196 | t.suite('test')
197 | }, /not function/)
198 |
199 | assert.throws(function () {
200 | t.suite('test', 123)
201 | }, /not function/)
202 |
203 | assert.throws(function () {
204 | t.it('test', {})
205 | }, /not function/)
206 | })
207 | })
208 |
209 | tman.suite('Hooks', function () {
210 | tman.it('work for suites and tests', function () {
211 | var ctx = this
212 | var count = 0
213 | // new child instance for test
214 | var t = tman.createTman()
215 | t.setReporter(CustomReporter, this)
216 |
217 | t.before(function () {
218 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
219 | assert.strictEqual(count++, 0)
220 | })
221 |
222 | t.after(function () {
223 | assert.strictEqual(count++, 11)
224 | })
225 |
226 | t.after(function (done) {
227 | assert.strictEqual(count++, 12)
228 | done()
229 | })
230 |
231 | t.beforeEach(function () {
232 | count++
233 | })
234 |
235 | t.afterEach(function () {
236 | count++
237 | })
238 |
239 | t.it('test 1-1', function () {
240 | assert.strictEqual(count++, 2)
241 | })
242 |
243 | t.suite('suite 1-1', function () {
244 | t.it('test 2-1', function () {
245 | assert.strictEqual(count++, 5)
246 | })
247 |
248 | t.it('test 2-2', function () {
249 | assert.strictEqual(count++, 6)
250 | })
251 | })
252 |
253 | t.it('test 1-2', function () {
254 | assert.strictEqual(count++, 9)
255 | })
256 |
257 | return t.run()
258 | })
259 |
260 | tman.it('work for nested suites and tests', function () {
261 | var ctx = this
262 | var count = 0
263 | // new child instance for test
264 | var t = tman.createTman()
265 | t.setReporter(CustomReporter, this)
266 |
267 | t.before(function () {
268 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
269 | assert.strictEqual(count++, 0)
270 | assert.strictEqual(this, t.rootSuite)
271 | })
272 |
273 | t.after(function () {
274 | assert.strictEqual(count++, 18)
275 | assert.strictEqual(this, t.rootSuite)
276 | })
277 |
278 | t.it('test 1-1', function () {
279 | assert.strictEqual(count++, 1)
280 | })
281 |
282 | t.suite('suite 1-1', function () {
283 | var suite = this
284 |
285 | t.before(function () {
286 | assert.strictEqual(count++, 2)
287 | assert.strictEqual(this, suite)
288 | })
289 |
290 | t.after(function () {
291 | assert.strictEqual(count++, 16)
292 | assert.strictEqual(this, suite)
293 | })
294 |
295 | t.beforeEach(function () {
296 | count++
297 | assert.strictEqual(this, suite)
298 | })
299 |
300 | t.beforeEach(function (done) {
301 | count++
302 | assert.strictEqual(this, suite)
303 | done()
304 | })
305 |
306 | t.afterEach(function () {
307 | count++
308 | assert.strictEqual(this, suite)
309 | })
310 |
311 | t.it('test 2-1', function () {
312 | assert.strictEqual(count++, 5)
313 | })
314 |
315 | t.it('test 2-2', function () {
316 | assert.strictEqual(count++, 9)
317 | })
318 |
319 | t.suite('suite 2-1', function () {
320 | t.it('test 3-1', function () {
321 | assert.strictEqual(count++, 13)
322 | })
323 |
324 | t.it('test 3-2', function () {
325 | assert.strictEqual(count++, 14)
326 | })
327 | })
328 | })
329 |
330 | t.it('test 1-2', function () {
331 | assert.strictEqual(count++, 17)
332 | })
333 |
334 | return t.run()
335 | })
336 |
337 | tman.it('invalid hooks', function () {
338 | var t = tman.createTman()
339 |
340 | assert.throws(function () {
341 | t.before('test')
342 | }, /not function/)
343 |
344 | assert.throws(function () {
345 | t.after()
346 | }, /not function/)
347 |
348 | assert.throws(function () {
349 | t.beforeEach([])
350 | }, /not function/)
351 |
352 | assert.throws(function () {
353 | t.afterEach(new Date())
354 | }, /not function/)
355 | })
356 |
357 | tman.it('work with ES2015', function () {
358 | var ctx = this
359 | // new child instance for test
360 | var t = tman.createTman()
361 | t.setReporter(CustomReporter, this)
362 | t.before(function () {
363 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
364 | })
365 |
366 | if (supportES2015) require('./es2015/async-hook')(t)
367 |
368 | return t.run()
369 | })
370 | })
371 |
--------------------------------------------------------------------------------
/lib/core.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | const path = require('path')
7 | const thunks = require('thunks')
8 | const thunk = thunks()
9 | // Save timer references to avoid other module (Sinon) interfering.
10 | const $setTimeout = setTimeout
11 | const $clearTimeout = clearTimeout
12 |
13 | function Suite (title, parent, mode) {
14 | this.title = title
15 | this.parent = parent
16 | this.root = parent ? parent.root : this
17 |
18 | this.mode = mode // 'skip', 'only', 'hasOnly'
19 | this.duration = -1
20 | this.startTime = 0
21 | this.endTime = 0
22 | this.children = []
23 | this.ctxMachine = this
24 | this.state = null // skip: null, passed: true, failed: error
25 | this.cleanHandle = null
26 | this.depth = parent ? (parent.depth + 1) : 0
27 | this.before = new Hooks('before', this)
28 | this.after = new Hooks('after', this)
29 | this.beforeEach = new Hooks('beforeEach', this)
30 | this.afterEach = new Hooks('afterEach', this)
31 | }
32 |
33 | Suite.prototype.reset = function () {
34 | this.startTime = 0
35 | this.endTime = 0
36 | this.children.length = 0
37 | this.ctxMachine = this
38 | this.state = null
39 | this.cleanHandle = null
40 | this.before.hooks.length = 0
41 | this.after.hooks.length = 0
42 | this.beforeEach.hooks.length = 0
43 | this.afterEach.hooks.length = 0
44 | return this
45 | }
46 |
47 | /* istanbul ignore next */
48 | Suite.prototype.inspect = function () {
49 | return {
50 | title: this.title,
51 | mode: this.mode,
52 | depth: this.depth,
53 | startTime: this.startTime,
54 | endTime: this.endTime,
55 | before: this.before.inspect(),
56 | after: this.after.inspect(),
57 | beforeEach: this.beforeEach.inspect(),
58 | afterEach: this.afterEach.inspect(),
59 | duration: this.getDuration(),
60 | parent: this.parent && '',
61 | children: this.children.map((test) => '<' + test.constructor.name + ': ' + test.title + '>')
62 | }
63 | }
64 |
65 | Suite.prototype.toJSON = function () {
66 | return {
67 | ctx: this,
68 | title: this.title,
69 | fullTitle: this.fullTitle(),
70 | mode: this.mode, // 'skip', 'only', 'hasOnly'
71 | depth: this.depth,
72 | startTime: this.startTime,
73 | endTime: this.endTime,
74 | state: this.state // skip: null, passed: true, failed: error
75 | }
76 | }
77 |
78 | Suite.prototype.addSuite = function (title, fn, mode) {
79 | const ctx = this.ctxMachine
80 | assertStr(title, ctx)
81 | assertFn(fn, ctx)
82 | const suite = new Suite(title, ctx, mode)
83 | if (mode === 'only' && !ctx.isSkip()) ctx.setOnly()
84 | ctx.children.push(suite)
85 | this.ctxMachine = suite
86 | fn.call(suite)
87 | this.ctxMachine = ctx
88 | return suite
89 | }
90 |
91 | Suite.prototype.addTest = function (title, fn, mode) {
92 | const ctx = this.ctxMachine
93 | assertStr(title, ctx)
94 | assertFn(fn, ctx)
95 | const test = new Test(title, ctx, fn, mode)
96 | if (mode === 'only' && !ctx.isSkip()) ctx.setOnly()
97 | ctx.children.push(test)
98 | return test
99 | }
100 |
101 | Suite.prototype.addBefore = function (fn) {
102 | const ctx = this.ctxMachine
103 | assertFn(fn, ctx)
104 | ctx.before.add(fn)
105 | }
106 |
107 | Suite.prototype.addAfter = function (fn) {
108 | const ctx = this.ctxMachine
109 | assertFn(fn, ctx)
110 | ctx.after.add(fn)
111 | }
112 |
113 | Suite.prototype.addBeforeEach = function (fn) {
114 | const ctx = this.ctxMachine
115 | assertFn(fn, ctx)
116 | ctx.beforeEach.add(fn)
117 | }
118 |
119 | Suite.prototype.addAfterEach = function (fn) {
120 | const ctx = this.ctxMachine
121 | assertFn(fn, ctx)
122 | ctx.afterEach.add(fn)
123 | }
124 |
125 | Suite.prototype.setOnly = function () {
126 | this.mode = 'hasOnly'
127 | if (this.parent) this.parent.setOnly()
128 | }
129 |
130 | Suite.prototype.hasOnly = function () {
131 | if (this.mode === 'hasOnly') return true
132 | return this.parent ? this.parent.hasOnly() : false
133 | }
134 |
135 | Suite.prototype.isOnly = function () {
136 | if (this.mode === 'only') return true
137 | return this.parent ? this.parent.isOnly() : false
138 | }
139 |
140 | Suite.prototype.isSkip = function () {
141 | if (this.mode === 'skip') return true
142 | return this.parent ? this.parent.isSkip() : false
143 | }
144 |
145 | Suite.prototype.timeout = function (duration) {
146 | this.duration = duration >= 0 ? +duration : -1
147 | }
148 |
149 | Suite.prototype.getDuration = function () {
150 | if (this.duration >= 0) return this.duration
151 | return this.parent ? this.parent.getDuration() : 0
152 | }
153 |
154 | Suite.prototype.fullTitle = function () {
155 | return this.parent ? path.join(this.parent.fullTitle(), this.title) : path.sep
156 | }
157 |
158 | Suite.prototype.toThunk = function () {
159 | const ctx = this
160 | const hasOnly = this.hasOnly()
161 |
162 | return function (done) {
163 | /* istanbul ignore next */
164 | if (ctx.root.abort) return done()
165 | if (hasOnly && ctx.mode !== 'hasOnly' && !ctx.isOnly()) return done()
166 |
167 | ctx.root.reporter.onSuiteStart(ctx.toJSON())
168 | if (ctx.mode === 'skip') {
169 | return thunk.seq(ctx.children.map((test) => {
170 | test.mode = 'skip'
171 | return test
172 | }))(function () {
173 | ctx.root.reporter.onSuiteFinish(ctx.toJSON())
174 | })(done)
175 | }
176 |
177 | ctx.cleanHandle = clearSuite
178 | function clearSuite (err) {
179 | if (clearSuite.called) return
180 | clearSuite.called = true
181 | ctx.root.runnerMachine = null
182 | if (err == null) ctx.state = true
183 | else {
184 | ctx.state = err
185 | ctx.root.errors.push(err)
186 | err.order = ctx.root.errors.length
187 | err.title = ctx.fullTitle() + ' ' + (err.title || clearSuite.hookTitle || '')
188 | }
189 | ctx.endTime = Date.now()
190 | ctx.root.reporter.onSuiteFinish(ctx.toJSON())
191 | done()
192 | }
193 |
194 | const tasks = []
195 | tasks.push(ctx.before)
196 | ctx.children.forEach((test) => {
197 | if (test instanceof Test) {
198 | const fullTitle = test.fullTitle()
199 | if (ctx.root.exclude.test(fullTitle) || !ctx.root.grep.test(fullTitle)) return
200 | }
201 | if (hasOnly && test.mode !== 'hasOnly' && !test.isOnly()) return
202 | if (test.mode === 'skip') tasks.push(test)
203 | // Mocha compatible mode
204 | else if (ctx.root.mocha && test instanceof Suite) tasks.push(thunk.delay(), test)
205 | else tasks.push(thunk.delay(), ctx.beforeEach, test, ctx.afterEach)
206 | })
207 | tasks.push(ctx.after)
208 | ctx.startTime = Date.now()
209 | thunk.seq(tasks)(clearSuite)
210 | }
211 | }
212 |
213 | function Hooks (title, parent) {
214 | this.title = title
215 | this.parent = parent
216 | this.hooks = []
217 | }
218 |
219 | Hooks.prototype.add = function (fn) {
220 | this.hooks.push(fn)
221 | }
222 |
223 | /* istanbul ignore next */
224 | Hooks.prototype.inspect = function () {
225 | return {
226 | title: this.title,
227 | hooks: this.hooks.map((hook) => '<' + hook.constructor.name + '>')
228 | }
229 | }
230 |
231 | // Mocha compatible mode
232 | Hooks.prototype.getParentHooks = function () {
233 | const suite = this.parent
234 | if (suite.parent && (this.title === 'beforeEach' || this.title === 'afterEach')) {
235 | return suite.parent[this.title]
236 | }
237 | return null
238 | }
239 |
240 | Hooks.prototype.toThunk = function () {
241 | const ctx = this
242 | const suite = ctx.parent
243 |
244 | return function (done) {
245 | const hooks = ctx.hooks.map((hook) => toThunkableFn(hook, suite))
246 | // Mocha compatible mode
247 | if (suite.root.mocha) {
248 | const parentHooks = ctx.getParentHooks()
249 | if (parentHooks) hooks.unshift(parentHooks)
250 | }
251 |
252 | if (!hooks.length) return done()
253 | const title = '"' + ctx.title + '" Hook'
254 | if (!suite.cleanHandle.called) {
255 | suite.cleanHandle.hookTitle = title
256 | suite.root.runnerMachine = suite.cleanHandle
257 | }
258 |
259 | thunk.seq.call(suite, hooks)(function (err) {
260 | if (err != null) {
261 | err.title = title
262 | throw err
263 | }
264 | })(done)
265 | }
266 | }
267 |
268 | function Test (title, parent, fn, mode) {
269 | this.title = title
270 | this.parent = parent
271 | this.root = parent.root
272 |
273 | this.fn = fn
274 | this.mode = mode // 'skip', 'only'
275 | this.duration = -1
276 | this.startTime = 0
277 | this.endTime = 0
278 | this.timer = null
279 | this.state = null // skip: null, passed: true, failed: error
280 | this.cleanHandle = null
281 | this.depth = parent.depth + 1
282 | }
283 |
284 | /* istanbul ignore next */
285 | Test.prototype.inspect = function () {
286 | return {
287 | title: this.title,
288 | mode: this.mode,
289 | depth: this.depth,
290 | startTime: this.startTime,
291 | endTime: this.endTime,
292 | state: this.state,
293 | duration: this.getDuration(),
294 | fn: this.fn && '',
295 | parent: this.parent && ''
296 | }
297 | }
298 |
299 | Test.prototype.toJSON = function () {
300 | return {
301 | ctx: this,
302 | title: this.title,
303 | fullTitle: this.fullTitle(),
304 | mode: this.mode, // 'skip', 'only'
305 | depth: this.depth,
306 | startTime: this.startTime,
307 | endTime: this.endTime,
308 | state: this.state // skip: null, passed: true, failed: error
309 | }
310 | }
311 |
312 | Test.prototype.isOnly = function () {
313 | return this.mode === 'only' || this.parent.isOnly()
314 | }
315 |
316 | Test.prototype.timeout = function (duration) {
317 | this.duration = duration >= 0 ? +duration : -1
318 | }
319 |
320 | Test.prototype.getDuration = function () {
321 | return this.duration >= 0 ? this.duration : this.parent.getDuration()
322 | }
323 |
324 | Test.prototype.fullTitle = function () {
325 | return path.join(this.parent.fullTitle(), this.title)
326 | }
327 |
328 | Test.prototype.toThunk = function () {
329 | const ctx = this
330 |
331 | return function (done) {
332 | /* istanbul ignore next */
333 | if (ctx.root.abort) return done()
334 | if (ctx.parent.hasOnly() && !ctx.isOnly()) return done()
335 | ctx.root.reporter.onTestStart(ctx.toJSON())
336 | if (ctx.mode === 'skip') {
337 | ctx.root.ignored++
338 | ctx.root.reporter.onTestFinish(ctx.toJSON())
339 | return done()
340 | }
341 |
342 | ctx.cleanHandle = clearTest
343 | function clearTest (err) {
344 | if (clearTest.called) return
345 | clearTest.called = true
346 | $clearTimeout(ctx.timer)
347 | ctx.root.runnerMachine = null
348 | if (err == null) {
349 | ctx.state = true
350 | ctx.root.passed++
351 | } else {
352 | ctx.state = err
353 | ctx.root.errors.push(err)
354 | err.order = ctx.root.errors.length
355 | err.title = ctx.fullTitle()
356 | }
357 | ctx.endTime = Date.now()
358 | ctx.root.reporter.onTestFinish(ctx.toJSON())
359 | done()
360 | }
361 |
362 | ctx.startTime = Date.now()
363 | ctx.root.runnerMachine = clearTest
364 | thunk.race.call(ctx, [
365 | toThunkableFn(ctx.fn, ctx),
366 | function (callback) {
367 | thunk.delay()(function () {
368 | const duration = ctx.getDuration()
369 | if (ctx.endTime || !duration) return
370 | ctx.timer = $setTimeout(function () {
371 | callback(new Error('timeout of ' + duration + 'ms exceeded.'))
372 | }, duration)
373 | })
374 | }
375 | ])(clearTest)
376 | }
377 | }
378 |
379 | exports.Suite = Suite
380 | exports.Test = Test
381 | exports.Tman = function (env) {
382 | const tm = _tman('')
383 | const rootSuite = tm.rootSuite = new Suite('root', null, '')
384 | rootSuite.exit = true
385 | rootSuite.grep = /.*/
386 | rootSuite.exclude = /.{-1}/
387 | rootSuite.timeout(2000)
388 |
389 | tm.only = _tman('only')
390 | tm.skip = _tman('skip')
391 | function _tman (mode) {
392 | return function tman (title, fn) {
393 | if (!env.TEST) return
394 | if (typeof title === 'function') {
395 | fn = title
396 | title = 'T-man'
397 | }
398 | const suite = rootSuite.addSuite(title, fn, mode)
399 | tm.tryRun(10)
400 | return suite
401 | }
402 | }
403 |
404 | tm.describe = tm.suite = function (title, fn) {
405 | return rootSuite.addSuite(title, fn, '')
406 | }
407 | tm.suite.only = function (title, fn) {
408 | return rootSuite.addSuite(title, fn, 'only')
409 | }
410 | tm.suite.skip = function (title, fn) {
411 | return rootSuite.addSuite(title, fn, 'skip')
412 | }
413 |
414 | tm.it = tm.test = function (title, fn) {
415 | return rootSuite.addTest(title, fn, '')
416 | }
417 | tm.test.only = function (title, fn) {
418 | return rootSuite.addTest(title, fn, 'only')
419 | }
420 | tm.test.skip = function (title, fn) {
421 | return rootSuite.addTest(title, fn, 'skip')
422 | }
423 |
424 | tm.before = function (fn) {
425 | rootSuite.addBefore(fn)
426 | }
427 |
428 | tm.after = function (fn) {
429 | rootSuite.addAfter(fn)
430 | }
431 |
432 | tm.beforeEach = function (fn) {
433 | rootSuite.addBeforeEach(fn)
434 | }
435 |
436 | tm.afterEach = function (fn) {
437 | rootSuite.addAfterEach(fn)
438 | }
439 |
440 | tm.grep = function (str) {
441 | rootSuite.grep = parseRegExp(str)
442 | }
443 |
444 | tm.exclude = function (str) {
445 | rootSuite.exclude = parseRegExp(str)
446 | }
447 |
448 | tm.mocha = function () {
449 | rootSuite.mocha = true
450 | }
451 |
452 | tm.reset = function () {
453 | rootSuite.reset()
454 | }
455 |
456 | tm.abort = function () {
457 | rootSuite.abort = true
458 | }
459 |
460 | tm.setExit = function (exit) {
461 | rootSuite.exit = !!exit
462 | }
463 |
464 | tm.setReporter = function (CustomReporter, options) {
465 | rootSuite.reporter = new CustomReporter(rootSuite, options)
466 | }
467 |
468 | tm.timeout = function (duration) {
469 | rootSuite.timeout(duration)
470 | }
471 |
472 | var timer = null
473 | var running = false
474 | tm.tryRun = function (delay) {
475 | if (timer) $clearTimeout(timer)
476 | return thunk(function (done) {
477 | timer = $setTimeout(function () {
478 | if (!running) tm.run()(done)
479 | }, delay > 0 ? delay : 0)
480 | })(function (err, res) {
481 | if (err) throw err
482 | return res
483 | })
484 | }
485 |
486 | tm.run = function (hook) {
487 | /* istanbul ignore next */
488 | if (running) throw new Error('T-man is running!')
489 |
490 | function endTest (err) {
491 | running = false
492 | process.removeListener('uncaughtException', uncaught)
493 | endTest.called = true
494 | let suite
495 | if (err == null) {
496 | suite = rootSuite.toJSON()
497 | suite.exit = rootSuite.exit
498 | suite.abort = rootSuite.abort
499 | suite.passed = rootSuite.passed
500 | suite.ignored = rootSuite.ignored
501 | suite.errors = rootSuite.errors.slice()
502 | }
503 |
504 | return thunk.call(tm, hook && hook.call(tm, err, suite))(function (error) {
505 | err = err || error
506 | if (err || !suite) throw err
507 | rootSuite.reporter.onFinish(suite)
508 | return suite
509 | })
510 | }
511 |
512 | tm.uncaught = uncaught
513 | process.on('uncaughtException', uncaught)
514 | function uncaught (err) {
515 | const uncaughtHandle = rootSuite.runnerMachine || endTest
516 | err = err || new Error('uncaught exception')
517 | err.uncaught = true
518 |
519 | const stack = err.stack
520 | err.stack = stack
521 | if (uncaughtHandle.called) rootSuite.reporter.log(String(err))
522 | else uncaughtHandle(err)
523 | }
524 |
525 | running = true
526 | rootSuite.abort = false
527 | rootSuite.passed = 0
528 | rootSuite.ignored = 0
529 | rootSuite.errors = []
530 | rootSuite.runnerMachine = null
531 | rootSuite.reporter.onStart()
532 | return thunk.delay.call(tm)(function () {
533 | return rootSuite
534 | })(endTest)
535 | }
536 |
537 | return tm
538 | }
539 |
540 | function assertFn (fn, ctx) {
541 | if (typeof fn !== 'function') {
542 | throw new Error(String(fn) + ' is not function in "' + ctx.fullTitle() + '"')
543 | }
544 | }
545 |
546 | function assertStr (str, ctx) {
547 | if (!str || typeof str !== 'string') {
548 | throw new Error(String(str) + ' is invalid string in "' + ctx.fullTitle() + '"')
549 | }
550 | }
551 |
552 | function toThunkableFn (fn, ctx) {
553 | if (thunks.isThunkableFn(fn)) return fn
554 | return function (done) { thunk(fn.call(ctx))(done) }
555 | }
556 |
557 | // extract args if it's regex-like, i.e: [string, pattern, flag]
558 | function parseRegExp (str) {
559 | if (str instanceof RegExp) return str
560 | const arg = String(str).match(/^\/(.*)\/(g|i|)$|.*/)
561 | return new RegExp(arg[1] || arg[0], arg[2])
562 | }
563 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | T-man
2 | ====
3 | Super test manager for JavaScript.
4 |
5 | [![NPM version][npm-image]][npm-url]
6 | [![Build Status][travis-image]][travis-url]
7 | [![Coverage Status][coveralls-image]][coveralls-url]
8 | [![Downloads][downloads-image]][downloads-url]
9 |
10 | T-man is a refactor version of [mocha](http://mochajs.org/), but more lightweight, more flexible. In most case, you can use `tman` replace of `mocha` directly.
11 |
12 | Summary
13 | -------
14 | - [T-man](#t-man)
15 | - [Summary](#summary)
16 | - [Examples](#examples)
17 | - [Simple tests](#simple-tests)
18 | - [Mocha style tests](#mocha-style-tests)
19 | - [Es-next tests with babel](#es-next-tests-with-babel)
20 | - [Tests in source code](#tests-in-source-code)
21 | - [Practical tests](#practical-tests)
22 | - [Complex tests](#complex-tests)
23 | - [Usage](#usage)
24 | - [Use as CLI](#use-as-cli)
25 | - [Use with npm package.json](#use-with-npm-packagejson)
26 | - [Assertions](#assertions)
27 | - [Suites and tests](#suites-and-tests)
28 | - [tman.suite(title, fn), tman.describe(title, fn)](#tmansuitetitle-fn-tmandescribetitle-fn)
29 | - [tman.test(title, fn), tman.it(title, fn)](#tmantesttitle-fn-tmanittitle-fn)
30 | - [Hooks](#hooks)
31 | - [tman.before(fn)](#tmanbeforefn)
32 | - [tman.after(fn)](#tmanafterfn)
33 | - [tman.beforeEach(fn)](#tmanbeforeeachfn)
34 | - [tman.afterEach(fn)](#tmanaftereachfn)
35 | - [Exclusive or inclusive tests](#exclusive-or-inclusive-tests)
36 | - [tman.suite.only(title, fn)](#tmansuiteonlytitle-fn)
37 | - [tman.it.only(title, fn)](#tmanitonlytitle-fn)
38 | - [tman.suite.skip(title, fn)](#tmansuiteskiptitle-fn)
39 | - [tman.it.skip(title, fn)](#tmanitskiptitle-fn)
40 | - [tman.grep(pattern)](#tmangreppattern)
41 | - [tman.exclude(pattern)](#tmanexcludepattern)
42 | - [Timeouts](#timeouts)
43 | - [Write tests in source code](#write-tests-in-source-code)
44 | - [tman(title, fn)](#tmantitle-fn)
45 | - [tman.only(title, fn)](#tmanonlytitle-fn)
46 | - [tman.skip(title, fn)](#tmanskiptitle-fn)
47 | - [Run tests](#run-tests)
48 | - [tman.run([callback])](#tmanruncallback)
49 | - [tman.mocha()](#tmanmocha)
50 | - [tman.reset()](#tmanreset)
51 | - [tman.loadFiles(filePath, sort)](#tmanloadfilesfilepath-sort)
52 | - [tman.globals(globals)](#tmanglobalsglobals)
53 | - [T-man CLI](#t-man-cli)
54 | - [T-man test mode](#t-man-test-mode)
55 | - [TypeScript Typings](#typescript-typings)
56 | - [Reporters](#reporters)
57 | - [spec](#spec)
58 | - [dot](#dot)
59 | - [base](#base)
60 | - [FAQ](#faq)
61 | - [How to run CoffeeScript (or TypeScript) tests?](#how-to-run-coffeescript-or-typescript-tests)
62 | - [License](#license)
63 |
64 | ## Examples
65 |
66 | ### [Simple tests](https://github.com/thunks/tman/tree/master/example/simple.js)
67 | It define test cases in top level, and no suites.
68 |
69 | ```js
70 | const assert = require('assert')
71 | const tman = require('tman')
72 | const Rx = require('rxjs')
73 |
74 | var count = 0
75 |
76 | tman.it('synchronous test', function () {
77 | assert.strictEqual(count++, 0)
78 | })
79 |
80 | tman.it('callback style asynchronous test', function (done) {
81 | assert.strictEqual(count++, 1)
82 | setTimeout(done, 100)
83 | })
84 |
85 | tman.it('promise style asynchronous test', function () {
86 | assert.strictEqual(count++, 2)
87 | return new Promise(function (resolve) {
88 | assert.strictEqual(count++, 3)
89 | setTimeout(resolve, 100)
90 | })
91 | })
92 |
93 | tman.it('thunk style asynchronous test', function () {
94 | assert.strictEqual(count++, 4)
95 | return function (done) {
96 | assert.strictEqual(count++, 5)
97 | setTimeout(done, 100)
98 | }
99 | })
100 |
101 | tman.it('generator style asynchronous test', function * () {
102 | assert.strictEqual(count++, 6)
103 | yield function (done) { setTimeout(done, 50) }
104 | yield new Promise(function (resolve) { setTimeout(resolve, 50) })
105 | assert.strictEqual(count++, 7)
106 | })
107 |
108 | tman.it('Rx.Observable asynchronous test', function () {
109 | assert.strictEqual(count++, 8)
110 | return Rx.Observable.fromPromise(new Promise(function (resolve) {
111 | assert.strictEqual(count++, 9)
112 | setTimeout(resolve, 100)
113 | }))
114 | })
115 |
116 | // Node.js v8
117 | tman.it('async/await style asynchronous test', async function () {
118 | assert.strictEqual(count++, 10)
119 | await new Promise(function (resolve) { setTimeout(resolve, 50) })
120 | assert.strictEqual(count++, 11)
121 | })
122 | ```
123 |
124 | Run by T-man CLI (need `npm i tman -g`):
125 | ```sh
126 | tman example/simple
127 | ```
128 |
129 | ### [Mocha style tests](https://github.com/thunks/tman/tree/master/example/mocha.js)
130 | It is a mocha style tests. It only can be run by T-man CLI: `tman example/mocha`.
131 | Through T-man CLI, some method are registered to node global object.
132 | And you can use generator as well, it is equal to `mocha` + `thunk-mocha`.
133 |
134 | ```js
135 | const assert = require('assert')
136 |
137 | var count = 0
138 |
139 | describe('mocha style', function () {
140 | before(function () {
141 | assert.strictEqual(count++, 0)
142 | })
143 |
144 | after(function () {
145 | assert.strictEqual(count++, 9)
146 | })
147 |
148 | it('synchronous test', function () {
149 | assert.strictEqual(count++, 1)
150 | })
151 |
152 | it('callback style asynchronous test', function (done) {
153 | assert.strictEqual(count++, 2)
154 | setTimeout(done, 100)
155 | })
156 |
157 | it('promise style asynchronous test', function () {
158 | assert.strictEqual(count++, 3)
159 | return new Promise(function (resolve) {
160 | assert.strictEqual(count++, 4)
161 | setTimeout(resolve, 100)
162 | })
163 | })
164 |
165 | it('thunk style asynchronous test', function () {
166 | assert.strictEqual(count++, 5)
167 | return function (done) {
168 | assert.strictEqual(count++, 6)
169 | setTimeout(done, 100)
170 | }
171 | })
172 |
173 | it('generator style asynchronous test', function * () {
174 | assert.strictEqual(count++, 7)
175 | yield function (done) { setTimeout(done, 100) }
176 | assert.strictEqual(count++, 8)
177 | })
178 | })
179 | ```
180 |
181 | ### [Es-next tests with babel](https://github.com/thunks/tman/tree/master/example/es-next.es)
182 | `tman -r babel-register -r babel-polyfill example/es-next.es`:
183 | ```js
184 | import assert from 'assert'
185 | import tman from 'tman'
186 |
187 | var count = 0
188 | // async "after hook"
189 | tman.after(async () => {
190 | assert.strictEqual(await Promise.resolve(count++), 4)
191 | })
192 |
193 | tman.it('async/await asynchronous test', async function () {
194 | assert.strictEqual(await Promise.resolve(count++), 0)
195 | assert.strictEqual(await new Promise((resolve, reject) => {
196 | setTimeout(() => {
197 | resolve(count++)
198 | }, 100)
199 | }), 1)
200 | })
201 |
202 | tman.it('generator asynchronous test', function * () {
203 | // yield Promise
204 | assert.strictEqual(yield Promise.resolve(count++), 2)
205 | // yield thunk function
206 | assert.strictEqual(yield (done) => {
207 | setTimeout(() => {
208 | done(null, count++)
209 | }, 100)
210 | }, 3)
211 | })
212 | ```
213 |
214 | ### [Tests in source code](https://github.com/thunks/tman/tree/master/example/tests-in-source-code.js)
215 | It shows writing tests in source code. The tests will run in [test mode](#t-man-test-mode).
216 |
217 | ### [Practical tests](https://github.com/thunks/tman/tree/master/example/nested.js)
218 | It includes nested suites and tests, just simulate practical use case.
219 |
220 | ### [Complex tests](https://github.com/thunks/tman/tree/master/test/index.js)
221 | It is the test of `tman`, not only nested suites and tests, but also several `tman` instance compose!
222 |
223 | ## Usage
224 |
225 | ### Use as CLI
226 | T-man is easiest to use when installed with [npm](https://www.npmjs.com/package/tman):
227 | ```sh
228 | npm install tman -g
229 | ```
230 | Run test in `myproject_dir`:
231 | ```sh
232 | cd myproject_dir && tman
233 | ```
234 | T-man will try to load `myproject_dir/test/*.{js,ts,es,coffee}` and run it.
235 |
236 | ### Use with npm package.json
237 | npm script in `package.json`(, also with `istanbul`):
238 | ```json
239 | "scripts": {
240 | "test": "tman",
241 | "test-cov": "istanbul cover _tman"
242 | }
243 | ```
244 |
245 | Then run:
246 | ```sh
247 | npm test
248 | ```
249 | or
250 | ```sh
251 | npm run test-cov
252 | ```
253 |
254 | The `tman` will try to load tests with glob `test/*.js` and run them.
255 |
256 | You may also run tests with your own globs: `tman test/index.js test/service/*.js test/api/*.js`.
257 |
258 | ### Assertions
259 | T-man has no built-in assertion method, but allows you to use any assertion library you want, if it throws an error, it will work! You can utilize libraries such as:
260 |
261 | - [assert](https://nodejs.org/api/assert.html) Node.js built-in assertion module
262 | - [should.js](https://github.com/shouldjs/should.js) BDD style shown throughout these docs
263 | - [expect.js](https://github.com/LearnBoost/expect.js) expect() style assertions
264 | - [chai](http://chaijs.com/) expect(), assert() and should style assertions
265 |
266 | ### Suites and tests
267 |
268 | #### tman.suite(title, fn), tman.describe(title, fn)
269 | You may use `suite` to organize huge scale tests. `describe` is an alias of `suite`. You can define any level of nested suites and test cases.
270 |
271 | ```js
272 | tman.suite('User', function () {
273 | tman.suite('#save()', function () {
274 | tman.it('should save without error', function * () {
275 | yield new User('Tman').save()
276 | })
277 | })
278 | })
279 | ```
280 |
281 | #### tman.test(title, fn), tman.it(title, fn)
282 | Define test logic, support synchronous or asynchronous test. `it` is an alias of `test`.
283 |
284 | ```js
285 | tman.it('synchronous test', function () {
286 | // test body
287 | })
288 |
289 | tman.it('callback style asynchronous test', function (done) {
290 | // test body
291 | setTimeout(done, 100)
292 | })
293 |
294 | tman.it('promise style asynchronous test', function () {
295 | // test body
296 | return new Promise(function (resolve) {
297 | // test body
298 | setTimeout(resolve, 100)
299 | })
300 | })
301 |
302 | tman.it('thunk style asynchronous test', function () {
303 | // test body
304 | return function (done) {
305 | // test body
306 | setTimeout(done, 100)
307 | }
308 | })
309 |
310 | tman.it('generator style asynchronous test', function * () {
311 | // test body
312 | yield thunk.delay(100)
313 | // test body
314 | })
315 | ```
316 |
317 | ### Hooks
318 | This hooks can be used to set up preconditions and clean up after your tests. All of them support synchronous or asynchronous function, just like `tman.it`. You can define any level hooks for `suite` or `test`.
319 |
320 | #### tman.before(fn)
321 | #### tman.after(fn)
322 | #### tman.beforeEach(fn)
323 | #### tman.afterEach(fn)
324 |
325 | ```js
326 | tman.suite('hooks', function () {
327 |
328 | tman.before(function () {
329 | // runs before all tests in this block
330 | })
331 |
332 | tman.after(function () {
333 | // runs after all tests in this block
334 | })
335 |
336 | tman.beforeEach(function () {
337 | // runs before each test in this block
338 | })
339 |
340 | tman.afterEach(function () {
341 | // runs after each test in this block
342 | })
343 |
344 | // test cases
345 | tman.it('test', function () {
346 | // ...
347 | })
348 | })
349 | ```
350 |
351 | ### Exclusive or inclusive tests
352 | `only` and `skip` will work as your expectation. If you have more than one `only` in your tests or suites, only the first `only` will take effect, all other will not be read.
353 |
354 | #### tman.suite.only(title, fn)
355 | #### tman.it.only(title, fn)
356 | #### tman.suite.skip(title, fn)
357 | #### tman.it.skip(title, fn)
358 |
359 | ```js
360 | tman.suite('Array', function () {
361 | tman.suite('#indexOf()', function () {
362 | tman.it.only('should return -1 unless present', function () {
363 | // ...
364 | })
365 |
366 | tman.it('should return the index when present', function () {
367 | // ...
368 | })
369 | })
370 | })
371 | ```
372 |
373 | #### tman.grep(pattern)
374 | Sets grep pattern and run tests matching pattern, same as `--grep ` CLI option.
375 |
376 | #### tman.exclude(pattern)
377 | Sets exclude pattern and exclude tests matching pattern, same as `--exclude ` CLI option.
378 |
379 | ### Timeouts
380 | Default timeout is `2000ms`.
381 |
382 | Suite-level timeouts may be applied to entire test "suites", or disabled via this.timeout(0). This will be inherited by all nested suites and test-cases that do not override the value.
383 |
384 | ```js
385 | tman.suite('a suite of tests', function () {
386 | this.timeout(500)
387 |
388 | tman.it('should take less than 500ms', function (done) {
389 | setTimeout(done, 300)
390 | })
391 |
392 | tman.it('should take less than 500ms as well', function (done) {
393 | setTimeout(done, 200)
394 | })
395 | })
396 | ```
397 |
398 | Test-specific timeouts may also be applied, or the use of this.timeout(0) to disable timeouts all together.
399 |
400 | ```js
401 | tman.it('should take less than 500ms', function (done) {
402 | this.timeout(500)
403 | setTimeout(done, 300)
404 | });
405 | ```
406 |
407 | ### Write tests in source code
408 |
409 | #### tman(title, fn)
410 | #### tman.only(title, fn)
411 | #### tman.skip(title, fn)
412 | You can write tests in your source code:
413 |
414 | ```js
415 | exports.stringify = function (val) {
416 | return val == null ? '' : String(val)
417 | }
418 |
419 | tman('test in source code', function () {
420 | const assert = require('assert')
421 |
422 | tman.it('stringify', function () {
423 | assert.strictEqual(exports.stringify(), '')
424 | assert.strictEqual(exports.stringify(null), '')
425 | assert.strictEqual(exports.stringify(0), '0')
426 | assert.strictEqual(exports.stringify(false), 'false')
427 | assert.strictEqual(exports.stringify(NaN), 'NaN')
428 | })
429 | })
430 | ```
431 |
432 | The tests will only run in `test mode`.
433 |
434 | ### Run tests
435 |
436 | #### tman.run([callback])
437 | You can run the tests programmatically:
438 |
439 | ```js
440 | // Run: `node example.js`
441 | tman.suite('User', function () {
442 | tman.suite('#save()', function () {
443 | tman.it('should save without error', function * () {
444 | yield new User('Tman').save()
445 | })
446 | })
447 | // others
448 | })
449 |
450 | tman.run()
451 | ```
452 |
453 | **If you run tests with CLI, you will not need to use `tman.run`,** the `tman` command will run tests automatically.
454 |
455 | #### tman.mocha()
456 | Enable mocha compatible mode, same as `--mocha` CLI option.
457 |
458 | #### tman.reset()
459 | Clear all tests of tman instance.
460 |
461 | #### tman.loadFiles(filePath, sort)
462 | Load test files to tman, it will clear previous tests file that in `require.cache`.
463 |
464 | #### tman.globals(globals)
465 | Set the given globals.
466 |
467 | #### T-man CLI
468 |
469 | ```sh
470 | $ tman --help
471 |
472 | Usage: tman [debug] [options] [files]
473 |
474 | Options:
475 |
476 | -h, --help output usage information
477 | -V, --version output the version number
478 | -c, --colors force enabling of colors
479 | -C, --no-colors force disabling of colors
480 | -d, --debug enable node\'s debugger, synonym for node --debug
481 | -e, --exclude exclude tests matching
482 | -g, --grep run tests matching
483 | -gc, --expose-gc expose gc extension
484 | -r, --require require the given module
485 | -R, --reporter specify the reporter to use [spec]
486 | -t, --timeout set test-case timeout in milliseconds [2000]
487 | --debug-brk enable node\'s debugger breaking on the first line
488 | --es_staging enable all staged features
489 | --globals allow the given comma-delimited global [names]
490 | --harmony<_classes,_generators,...> all node --harmony* flags are available
491 | --icu-data-dir include ICU data
492 | --mocha Mocha compatible mode
493 | --no-sort don\'t sort test files
494 | --no-timeout disables timeouts, given implicitly with --debug
495 | --no-exit require a clean shutdown of the event loop: T-man will not call process.exit
496 | --opts specify opts path
497 | --perf-basic-prof enable perf linux profiler (basic support)
498 | --preserve-symlinks Instructs the module loader to preserve symbolic links when resolving and caching modules
499 | --reporters display available reporters
500 | --throw-deprecation throw an exception anytime a deprecated function is used
501 | --trace trace function calls
502 | --trace-deprecation show stack traces on deprecations
503 | --use_strict enforce strict mode
504 | ```
505 |
506 | #### T-man test mode
507 | There are 3 ways to run with `test mode`:
508 |
509 | 1. `tman example/test_in_source_code.js`
510 | 2. `node example/test_in_source_code.js --test`
511 | 3. `TEST=* node example/test_in_source_code.js`
512 |
513 | ### TypeScript Typings
514 |
515 | ```typescript
516 | import * as tman from 'tman'
517 | import { tman, suite, it, before, after, beforeEach, afterEach } from 'tman'
518 | ```
519 |
520 | ### Reporters
521 |
522 | #### spec
523 |
524 | 
525 |
526 | #### dot
527 |
528 | 
529 |
530 | #### base
531 |
532 | 
533 |
534 | ### FAQ
535 |
536 | ### How to run CoffeeScript (or TypeScript) tests?
537 | Use `--require` option:
538 |
539 | 1. `tman -r coffee-script/register test/*.coffee`
540 | 2. `tman -r ts-node/register test/*.ts`
541 |
542 | [Here](https://github.com/thunks/tman/tree/master/example/simple.coffee) is a simple example. You can require one more modules.
543 |
544 | ### License
545 | T-man is licensed under the [MIT](https://github.com/thunks/tman/blob/master/LICENSE) license.
546 | Copyright © 2016-2020 thunks.
547 |
548 | [npm-url]: https://npmjs.org/package/tman
549 | [npm-image]: http://img.shields.io/npm/v/tman.svg
550 |
551 | [travis-url]: https://travis-ci.org/thunks/tman
552 | [travis-image]: http://img.shields.io/travis/thunks/tman.svg
553 |
554 | [coveralls-url]: https://coveralls.io/github/thunks/tman?branch=master
555 | [coveralls-image]: https://coveralls.io/repos/github/thunks/tman/badge.svg?branch=master
556 |
557 | [downloads-url]: https://npmjs.org/package/tman
558 | [downloads-image]: http://img.shields.io/npm/dm/tman.svg?style=flat-square
559 |
--------------------------------------------------------------------------------
/test/others.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // **Github:** https://github.com/thunks/tman
3 | //
4 | // **License:** MIT
5 |
6 | var path = require('path')
7 | var util = require('util')
8 | var assert = require('assert')
9 | var thunk = require('thunks')()
10 | var slice = Array.prototype.slice
11 |
12 | var tman = require('..')
13 | var format = tman.format
14 |
15 | assert.strictEqual(tman.baseDir, path.join(process.cwd(), 'test'))
16 |
17 | function CustomReporter (ctx, childCtx) {
18 | tman.Reporter.defaultReporter.call(this, ctx)
19 | this.childCtx = childCtx
20 | }
21 | util.inherits(CustomReporter, tman.Reporter.defaultReporter)
22 | CustomReporter.prototype.onFinish = function (res) {
23 | tman.rootSuite.passed += res.passed + res.errors.length + res.ignored
24 | this.logError(res)
25 | }
26 | CustomReporter.prototype.log = function () {
27 | var args = slice.call(arguments)
28 | Array.prototype.push.apply(this.childCtx.messages, args)
29 | args[0] = format.indent(this.childCtx.depth) + args[0]
30 | tman.rootSuite.reporter.log.apply(null, args)
31 | }
32 |
33 | tman.suite('Exclusive or inclusive tests', function () {
34 | tman.it('"skip" test', function () {
35 | var ctx = this
36 | var count = 0
37 | // new child instance for test
38 | var t = tman.createTman()
39 | this.messages = []
40 | t.setReporter(CustomReporter, this)
41 |
42 | t.before(function () {
43 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
44 | assert.strictEqual(count++, 0)
45 | })
46 |
47 | t.after(function () {
48 | assert.strictEqual(count++, 4)
49 | })
50 |
51 | t.it('test 1-1', function () {
52 | assert.strictEqual(count++, 1)
53 | })
54 |
55 | t.it.skip('test 1-2', function (done) {
56 | assert.strictEqual(true, false)
57 | done()
58 | })
59 |
60 | t.suite('suite 1-1', function () {
61 | t.it.skip('test 2-1', function () {
62 | assert.strictEqual(true, false)
63 | })
64 |
65 | t.suite.skip('suite 2-1', function () {
66 | t.it('test 3-1', function () {
67 | assert.strictEqual(true, false)
68 | })
69 |
70 | t.it('test 3-2', function () {
71 | assert.strictEqual(true, false)
72 | })
73 | })
74 |
75 | t.it('test 2-2', function () {
76 | assert.strictEqual(count++, 2)
77 | })
78 |
79 | t.it('test 2-3', function () {
80 | assert.deepStrictEqual({
81 | a: 1,
82 | b: 2,
83 | d: 5
84 | }, {
85 | a: 4,
86 | b: 2,
87 | c: 3
88 | })
89 | })
90 |
91 | t.it('test 2-4', function () {
92 | assert.deepStrictEqual({
93 | a: undefined,
94 | b: 2,
95 | c: 3
96 | }, {
97 | b: 2,
98 | c: 3
99 | })
100 | })
101 |
102 | t.it('test 2-5', function () {
103 | assert.deepStrictEqual({
104 | toJSON: function () {
105 | return {
106 | a: 5
107 | }
108 | }
109 | }, {
110 | a: 5
111 | })
112 | })
113 | })
114 |
115 | t.it('test 1-3', function () {
116 | assert.strictEqual(count++, 3)
117 | })
118 |
119 | return t.run(function (err, res) {
120 | if (err) throw err
121 | assert.strictEqual(res.passed, 3)
122 | assert.strictEqual(res.ignored, 4)
123 |
124 | var messages = ctx.messages.join('')
125 | assert.ok(messages.indexOf('test 1-2') > 0)
126 | assert.ok(messages.indexOf('test 2-1') > 0)
127 | assert.ok(messages.indexOf('suite 2-1') > 0)
128 | assert.ok(messages.indexOf('test 3-1') > 0)
129 | assert.ok(messages.indexOf('test 3-2') > 0)
130 | })
131 | })
132 |
133 | tman.it('"only" test', function () {
134 | var ctx = this
135 | var count = 0
136 | // new child instance for test
137 | var t = tman.createTman()
138 | this.messages = []
139 | t.setReporter(CustomReporter, this)
140 |
141 | t.before(function () {
142 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
143 | assert.strictEqual(count++, 0)
144 | })
145 |
146 | t.after(function () {
147 | assert.strictEqual(count++, 2)
148 | })
149 |
150 | t.it.only('test 1-1', function () {
151 | assert.strictEqual(count++, 1)
152 | })
153 |
154 | t.it('test 1-2', function () {
155 | assert.strictEqual(true, false)
156 | })
157 |
158 | t.it('test 1-3', function () {
159 | assert.strictEqual(true, false)
160 | })
161 |
162 | return t.run(function (err, res) {
163 | if (err) throw err
164 | assert.strictEqual(res.passed, 1)
165 | assert.strictEqual(res.ignored, 0)
166 |
167 | var messages = ctx.messages.join('')
168 | assert.ok(messages.indexOf('test 1-1') > 0)
169 | assert.ok(messages.indexOf('test 1-2') === -1)
170 | assert.ok(messages.indexOf('test 1-3') === -1)
171 | })
172 | })
173 |
174 | tman.it('"only" suite and "skip" test', function () {
175 | var ctx = this
176 | var count = 0
177 | // new child instance for test
178 | var t = tman.createTman()
179 | this.messages = []
180 | t.setReporter(CustomReporter, this)
181 |
182 | t.before(function () {
183 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
184 | assert.strictEqual(count++, 0)
185 | })
186 |
187 | t.after(function () {
188 | assert.strictEqual(count++, 4)
189 | })
190 |
191 | t.suite('suite 1-1', function () {
192 | t.it('test 2-1', function () {
193 | assert.strictEqual(true, false)
194 | })
195 |
196 | t.it('test 2-2', function () {
197 | assert.strictEqual(true, false)
198 | })
199 | })
200 |
201 | t.suite.only('suite 1-2', function () {
202 | t.it('test 2-1', function () {
203 | assert.strictEqual(count++, 1)
204 | })
205 |
206 | t.it('test 2-2', function () {
207 | assert.strictEqual(count++, 2)
208 | })
209 |
210 | t.suite('suite 2-1', function () {
211 | t.it('test 3-1', function () {
212 | assert.strictEqual(count++, 3)
213 | })
214 |
215 | t.it.skip('test 3-2', function () {
216 | assert.strictEqual(true, false)
217 | })
218 | })
219 | })
220 |
221 | t.it('test 1-1', function () {
222 | assert.strictEqual(true, false)
223 | })
224 |
225 | return t.run(function (err, res) {
226 | if (err) throw err
227 | assert.strictEqual(res.passed, 3)
228 | assert.strictEqual(res.ignored, 1)
229 |
230 | var messages = ctx.messages.join('')
231 | assert.ok(messages.indexOf('suite 1-1') === -1)
232 | assert.ok(messages.indexOf('suite 1-2') > 0)
233 | assert.ok(messages.indexOf('test 2-1') > 0)
234 | assert.ok(messages.indexOf('test 2-2') > 0)
235 | assert.ok(messages.indexOf('suite 2-1') > 0)
236 | assert.ok(messages.indexOf('test 3-1') > 0)
237 | assert.ok(messages.indexOf('test 3-2') > 0)
238 | assert.ok(messages.indexOf('test 1-1') === -1)
239 | })
240 | })
241 |
242 | tman.it('muilt "only"', function () {
243 | var ctx = this
244 | var count = 0
245 | // new child instance for test
246 | var t = tman.createTman()
247 | this.messages = []
248 | t.setReporter(CustomReporter, this)
249 |
250 | t.before(function () {
251 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
252 | assert.strictEqual(count++, 0)
253 | })
254 |
255 | t.after(function () {
256 | assert.strictEqual(count++, 7)
257 | })
258 |
259 | t.suite('suite 1-1', function () {
260 | t.it('test 1-2-1', function () {
261 | assert.strictEqual(true, false)
262 | })
263 |
264 | t.it('test 1-2-2', function () {
265 | assert.strictEqual(true, false)
266 | })
267 | })
268 |
269 | t.it.only('test 1-1', function () {
270 | assert.strictEqual(count++, 1)
271 | })
272 |
273 | t.it('test 1-2', function () {
274 | assert.strictEqual(true, false)
275 | })
276 |
277 | t.suite.only('suite 1-2', function () {
278 | t.it('test 2-2-1', function () {
279 | assert.strictEqual(count++, 2)
280 | })
281 |
282 | t.it('test 2-2-2', function () {
283 | assert.strictEqual(count++, 3)
284 | })
285 |
286 | t.it.skip('test 2-2-3', function () {
287 | assert.strictEqual(true, false)
288 | })
289 |
290 | t.it('test 2-2-4', function () {
291 | assert.notStrictEqual('same string', 'same string')
292 | })
293 | })
294 |
295 | t.suite.only('suite 1-3', function () {
296 | t.it('test 3-2-1', function () {
297 | assert.strictEqual(true, false)
298 | })
299 |
300 | t.it.only('test 3-2-2', function () {
301 | assert.strictEqual(count++, 4)
302 | })
303 |
304 | t.it.only('test 3-2-3', function () {
305 | assert.strictEqual(count++, 5)
306 | })
307 | })
308 |
309 | t.it.only('test 1-3', function () {
310 | assert.strictEqual(count++, 6)
311 | })
312 |
313 | t.it('test 1-4', function () {
314 | assert.strictEqual(true, false)
315 | })
316 |
317 | return t.run(function (err, res) {
318 | if (err) throw err
319 | assert.strictEqual(res.passed, 6)
320 | assert.strictEqual(res.ignored, 1)
321 |
322 | var messages = ctx.messages.join('')
323 | assert.ok(messages.indexOf('suite 1-1') === -1)
324 | assert.ok(messages.indexOf('test 1-1') > 0)
325 | assert.ok(messages.indexOf('test 1-2') === -1)
326 | assert.ok(messages.indexOf('suite 1-2') > 0)
327 | assert.ok(messages.indexOf('test 2-2-1') > 0)
328 | assert.ok(messages.indexOf('test 2-2-2') > 0)
329 | assert.ok(messages.indexOf('test 2-2-3') > 0)
330 | assert.ok(messages.indexOf('suite 1-3') > 0)
331 | assert.ok(messages.indexOf('test 3-2-1') === -1)
332 | assert.ok(messages.indexOf('test 3-2-2') > 0)
333 | assert.ok(messages.indexOf('test 3-2-3') > 0)
334 | assert.ok(messages.indexOf('test 1-3') > 0)
335 | assert.ok(messages.indexOf('test 1-4') === -1)
336 | })
337 | })
338 |
339 | tman.it('"only" in "skip" mode should not take effect', function () {
340 | var ctx = this
341 | var count = 0
342 | // new child instance for test
343 | var t = tman.createTman()
344 | this.messages = []
345 | t.setReporter(CustomReporter, this)
346 |
347 | t.before(function () {
348 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
349 | assert.strictEqual(count++, 0)
350 | })
351 |
352 | t.after(function () {
353 | assert.strictEqual(count++, 4)
354 | })
355 |
356 | t.it('test 1-1', function () {
357 | assert.strictEqual(count++, 1)
358 | })
359 |
360 | t.it('test 1-2', function () {
361 | assert.strictEqual(count++, 2)
362 | })
363 |
364 | t.suite.skip('suite 1-1', function () {
365 | t.it.only('test 2-1', function () {
366 | assert.strictEqual(true, false)
367 | })
368 |
369 | t.suite.only('suite 2-1', function () {
370 | t.it('test 3-1', function () {
371 | assert.strictEqual(true, false)
372 | })
373 |
374 | t.it('test 3-2', function () {
375 | assert.strictEqual(true, false)
376 | })
377 | })
378 | })
379 |
380 | t.it('test 1-3', function () {
381 | assert.strictEqual(count++, 3)
382 | })
383 |
384 | return t.run(function (err, res) {
385 | if (err) throw err
386 | assert.strictEqual(res.passed, 3)
387 | assert.strictEqual(res.ignored, 3)
388 |
389 | var messages = ctx.messages.join('')
390 | assert.ok(messages.indexOf('test 1-1') > 0)
391 | assert.ok(messages.indexOf('test 1-2') > 0)
392 | assert.ok(messages.indexOf('suite 1-1') > 0)
393 | assert.ok(messages.indexOf('test 2-1') > 0)
394 | assert.ok(messages.indexOf('suite 2-1') > 0)
395 | assert.ok(messages.indexOf('test 3-1') > 0)
396 | assert.ok(messages.indexOf('test 3-2') > 0)
397 | assert.ok(messages.indexOf('test 1-3') > 0)
398 | })
399 | })
400 | })
401 |
402 | tman.suite('grep and exclude', function () {
403 | tman.it('grep', function () {
404 | // new child instance for test
405 | var t = tman.createTman()
406 | assert.ok(t.rootSuite.grep.test(''))
407 | assert.ok(t.rootSuite.grep.test('*'))
408 | assert.ok(t.rootSuite.grep.test('abc, 123'))
409 |
410 | t.grep('api')
411 | assert.ok(t.rootSuite.grep.test('api'))
412 | assert.ok(t.rootSuite.grep.test('/api/user'))
413 | assert.ok(t.rootSuite.grep.test('#api, /user'))
414 | assert.ok(!t.rootSuite.grep.test(''))
415 | assert.ok(!t.rootSuite.grep.test('apji'))
416 |
417 | t.grep('/aa|BB/')
418 | assert.ok(!t.rootSuite.grep.test(''))
419 | assert.ok(!t.rootSuite.grep.test('abc'))
420 | assert.ok(!t.rootSuite.grep.test('bb'))
421 | assert.ok(t.rootSuite.grep.test('aa'))
422 | assert.ok(t.rootSuite.grep.test('BB'))
423 | assert.ok(t.rootSuite.grep.test('aaBB'))
424 |
425 | t.grep('/aa|BB/i')
426 | assert.ok(t.rootSuite.grep.test('bb'))
427 | })
428 |
429 | tman.it('exclude', function () {
430 | // new child instance for test
431 | var t = tman.createTman()
432 | assert.ok(!t.rootSuite.exclude.test(''))
433 | assert.ok(!t.rootSuite.exclude.test('*'))
434 | assert.ok(!t.rootSuite.exclude.test('abc, 123'))
435 |
436 | t.exclude('api')
437 | assert.ok(t.rootSuite.exclude.test('api'))
438 | assert.ok(t.rootSuite.exclude.test('/api/user'))
439 | assert.ok(t.rootSuite.exclude.test('#api, /user'))
440 | assert.ok(!t.rootSuite.exclude.test(''))
441 | assert.ok(!t.rootSuite.exclude.test('apji'))
442 |
443 | t.exclude('/aa|BB/')
444 | assert.ok(!t.rootSuite.exclude.test(''))
445 | assert.ok(!t.rootSuite.exclude.test('abc'))
446 | assert.ok(!t.rootSuite.exclude.test('bb'))
447 | assert.ok(t.rootSuite.exclude.test('aa'))
448 | assert.ok(t.rootSuite.exclude.test('BB'))
449 | assert.ok(t.rootSuite.exclude.test('aaBB'))
450 |
451 | t.exclude('/aa|BB/i')
452 | assert.ok(t.rootSuite.exclude.test('bb'))
453 | })
454 |
455 | tman.it('grep and exclude in tests', function () {
456 | var ctx = this
457 | var count = 0
458 | // new child instance for test
459 | var t = tman.createTman()
460 | this.messages = []
461 | t.setReporter(CustomReporter, this)
462 |
463 | t.grep('api')
464 | t.before(function () {
465 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
466 | assert.strictEqual(count++, 0)
467 | })
468 |
469 | t.after(function () {
470 | assert.strictEqual(count++, 4)
471 | })
472 |
473 | t.it('should not run', function () {
474 | assert.strictEqual(true, false)
475 | })
476 |
477 | t.it('api test', function () {
478 | assert.strictEqual(count++, 1)
479 | })
480 |
481 | t.it('api should ignore', function () {
482 | assert.strictEqual(true, false)
483 | })
484 |
485 | t.suite('suite', function () {
486 | t.it('test not run', function () {
487 | assert.strictEqual(true, false)
488 | })
489 |
490 | t.it('api 1', function () {
491 | assert.strictEqual(count++, 2)
492 | })
493 |
494 | t.it('ignore 1', function () {
495 | assert.strictEqual(true, false)
496 | })
497 | })
498 |
499 | t.suite('suite api', function () {
500 | t.it('test 1', function () {
501 | assert.strictEqual(count++, 3)
502 | })
503 |
504 | t.it('ignore', function () {
505 | assert.strictEqual(true, false)
506 | })
507 |
508 | t.it('api ignore', function () {
509 | assert.strictEqual(true, false)
510 | })
511 | })
512 |
513 | t.suite('ignore suite', function () {
514 | t.it('test 2', function () {
515 | assert.strictEqual(true, false)
516 | })
517 |
518 | t.it('api 2', function () {
519 | assert.strictEqual(true, false)
520 | })
521 | })
522 |
523 | t.it.skip('skip api', function () {
524 | assert.strictEqual(true, false)
525 | })
526 |
527 | t.exclude('ignore')
528 | return t.run(function (err, res) {
529 | if (err) throw err
530 | assert.strictEqual(res.passed, 3)
531 | assert.strictEqual(res.ignored, 1)
532 |
533 | var messages = ctx.messages.join('')
534 | assert.ok(messages.indexOf('should not run') < 0)
535 | assert.ok(messages.indexOf('api test') > 0)
536 | assert.ok(messages.indexOf('api should ignore') < 0)
537 | assert.ok(messages.indexOf('test not run') < 0)
538 | assert.ok(messages.indexOf('api 1') > 0)
539 | assert.ok(messages.indexOf('ignore 1') < 0)
540 | assert.ok(messages.indexOf('test 1') > 0)
541 | assert.ok(messages.indexOf('api ignore') < 0)
542 | assert.ok(messages.indexOf('test 2') < 0)
543 | assert.ok(messages.indexOf('api 2') < 0)
544 | assert.ok(messages.indexOf('skip api') > 0)
545 | })
546 | })
547 | })
548 |
549 | tman.suite('Timeouts and errors', function () {
550 | tman.it('suite timeouts and test timeouts', function () {
551 | var ctx = this
552 | var count = 0
553 | // new child instance for test
554 | var t = tman.createTman()
555 | this.messages = []
556 | t.setReporter(CustomReporter, this)
557 |
558 | t.before(function () {
559 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
560 | assert.strictEqual(count++, 0)
561 | })
562 |
563 | t.after(function () {
564 | assert.strictEqual(count++, 6)
565 | })
566 |
567 | t.it('test 1-1', function (done) {
568 | assert.strictEqual(count++, 1)
569 | setTimeout(done, 100)
570 | })
571 |
572 | t.it('test 1-2, timeout', function (done) {
573 | this.timeout(50)
574 | assert.strictEqual(count++, 2)
575 | setTimeout(done, 100)
576 | })
577 |
578 | t.suite('suite 1-1, timeout', function () {
579 | this.timeout(90)
580 |
581 | t.it('test 2-1', function (done) {
582 | this.timeout(110)
583 | assert.strictEqual(count++, 3)
584 | setTimeout(done, 100)
585 | })
586 |
587 | t.it('test 2-2, timeout', function (done) {
588 | assert.strictEqual(count++, 4)
589 | setTimeout(done, 100)
590 | })
591 |
592 | t.it('test 2-2, no-timeout', function (done) {
593 | this.timeout(0)
594 | assert.strictEqual(count++, 5)
595 | setTimeout(done, 100)
596 | })
597 | })
598 |
599 | return t.run(function (err, res) {
600 | if (err) throw err
601 | assert.strictEqual(res.passed, 3)
602 | assert.strictEqual(res.ignored, 0)
603 |
604 | var messages = ctx.messages.join('')
605 | assert.ok(messages.indexOf('test 1-1') > 0)
606 | assert.ok(messages.indexOf('test 1-2, timeout') > 0)
607 | assert.ok(messages.indexOf('suite 1-1, timeout') > 0)
608 | assert.ok(messages.indexOf('test 2-1') > 0)
609 | assert.ok(messages.indexOf('test 2-2, timeout') > 0)
610 |
611 | assert.ok(res.errors[0] instanceof Error)
612 | assert.ok(res.errors[0].message.indexOf('50ms') > 0)
613 | assert.strictEqual(res.errors[0].order, 1)
614 | assert.strictEqual(res.errors[0].title, '/test 1-2, timeout')
615 |
616 | assert.ok(res.errors[1] instanceof Error)
617 | assert.ok(res.errors[1].message.indexOf('90ms') > 0)
618 | assert.strictEqual(res.errors[1].order, 2)
619 | assert.strictEqual(res.errors[1].title, '/suite 1-1, timeout/test 2-2, timeout')
620 | })
621 | })
622 |
623 | tman.it('record errors', function () {
624 | var ctx = this
625 | var count = 0
626 | // new child instance for test
627 | var t = tman.createTman()
628 | this.messages = []
629 | t.setReporter(CustomReporter, this)
630 |
631 | t.before(function () {
632 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
633 | assert.strictEqual(count++, 0)
634 | })
635 |
636 | t.after(function () {
637 | assert.strictEqual(count++, 5)
638 | })
639 |
640 | t.it('test 1-1', function (done) {
641 | assert.strictEqual(count++, 1)
642 | throw new Error('error')
643 | })
644 |
645 | t.it('test 1-2', function () {
646 | assert.strictEqual(count++, 2)
647 | return thunk(function (done) {
648 | throw new Error('error from thunk')
649 | })
650 | })
651 |
652 | t.it.skip('test 1-3', function (done) {
653 | assert.strictEqual(true, false)
654 | throw new Error('error')
655 | })
656 |
657 | t.suite('suite 1-1', function () {
658 | t.it('test 2-1', function (done) {
659 | assert.strictEqual(count++, 3)
660 | setTimeout(function () {
661 | done(new Error('error'))
662 | }, 100)
663 | })
664 |
665 | t.it('test 2-2', function (done) {
666 | assert.strictEqual(count++, 4)
667 | setTimeout(done, 100)
668 | })
669 | })
670 |
671 | return t.run(function (err, res) {
672 | if (err) throw err
673 | assert.strictEqual(res.passed, 1)
674 | assert.strictEqual(res.ignored, 1)
675 |
676 | var messages = ctx.messages.join('')
677 | assert.ok(messages.indexOf('test 1-1 (1)') > 0)
678 | assert.ok(messages.indexOf('test 1-2 (2)') > 0)
679 | assert.ok(messages.indexOf('test 1-3') > 0)
680 | assert.ok(messages.indexOf('suite 1-1') > 0)
681 | assert.ok(messages.indexOf('test 2-1 (3)') > 0)
682 | assert.ok(messages.indexOf('test 2-2') > 0)
683 |
684 | assert.ok(res.errors[0] instanceof Error)
685 | assert.strictEqual(res.errors[0].order, 1)
686 | assert.strictEqual(res.errors[0].title, '/test 1-1')
687 |
688 | assert.ok(res.errors[1] instanceof Error)
689 | assert.strictEqual(res.errors[1].order, 2)
690 | assert.strictEqual(res.errors[1].title, '/test 1-2')
691 |
692 | assert.ok(res.errors[2] instanceof Error)
693 | assert.strictEqual(res.errors[2].order, 3)
694 | assert.strictEqual(res.errors[2].title, '/suite 1-1/test 2-1')
695 | })
696 | })
697 |
698 | tman.it('hook errors', function () {
699 | var ctx = this
700 | var count = 0
701 | // new child instance for test
702 | var t = tman.createTman()
703 | this.messages = []
704 | t.setReporter(CustomReporter, this)
705 |
706 | t.before(function () {
707 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
708 | assert.strictEqual(count++, 0)
709 | })
710 |
711 | t.after(function () {
712 | assert.strictEqual(count++, 5)
713 | })
714 |
715 | t.it('test 1-1 with error', function (done) {
716 | assert.strictEqual(count++, 1)
717 | throw new Error('error')
718 | })
719 |
720 | t.it('test 1-2', function () {
721 | assert.strictEqual(count++, 2)
722 | })
723 |
724 | t.suite('suite 1-1', function () {
725 | t.before(function () {
726 | throw new Error('before hook error')
727 | })
728 |
729 | t.it('test 2-1 not run', function () {
730 | assert.strictEqual(count++, 0)
731 | })
732 | })
733 |
734 | t.suite('suite 1-2', function () {
735 | t.afterEach(function () {
736 | throw new Error('afterEach hook error')
737 | })
738 |
739 | t.it('test 2-1 run', function () {
740 | assert.strictEqual(count++, 3)
741 | })
742 |
743 | t.it('test 2-2 not run', function () {
744 | assert.strictEqual(count++, 0)
745 | })
746 | })
747 |
748 | t.it('test 1-3', function () {
749 | assert.strictEqual(count++, 4)
750 | })
751 |
752 | return t.run(function (err, res) {
753 | if (err) throw err
754 | assert.strictEqual(res.passed, 3)
755 | assert.strictEqual(res.ignored, 0)
756 |
757 | var messages = ctx.messages.join('')
758 | assert.ok(messages.indexOf('test 1-1 with error (1)') > 0)
759 | assert.ok(messages.indexOf('/suite 1-1 "before" Hook (2)') > 0)
760 | assert.ok(messages.indexOf('/suite 1-2 "afterEach" Hook (3)') > 0)
761 |
762 | assert.ok(res.errors[0] instanceof Error)
763 | assert.strictEqual(res.errors[0].order, 1)
764 | assert.strictEqual(res.errors[0].title, '/test 1-1 with error')
765 |
766 | assert.ok(res.errors[1] instanceof Error)
767 | assert.strictEqual(res.errors[1].order, 2)
768 | assert.strictEqual(res.errors[1].title, '/suite 1-1 "before" Hook')
769 |
770 | assert.ok(res.errors[2] instanceof Error)
771 | assert.strictEqual(res.errors[2].order, 3)
772 | assert.strictEqual(res.errors[2].title, '/suite 1-2 "afterEach" Hook')
773 | })
774 | })
775 |
776 | tman.it('uncaughtException errors', function () {
777 | var ctx = this
778 | var count = 0
779 | // new child instance for test
780 | var t = tman.createTman()
781 | this.messages = []
782 | t.setReporter(CustomReporter, this)
783 | // remove parent uncaughtException handle
784 | process.removeListener('uncaughtException', tman.uncaught)
785 |
786 | t.before(function () {
787 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
788 | assert.strictEqual(count++, 0)
789 | })
790 |
791 | t.after(function () {
792 | assert.strictEqual(count++, 5)
793 | // add parent uncaughtException handle
794 | process.on('uncaughtException', tman.uncaught)
795 | })
796 |
797 | t.it('test 1-1 with error', function (done) {
798 | assert.strictEqual(count++, 1)
799 | setTimeout(function () {
800 | throw new Error('error')
801 | })
802 | })
803 |
804 | t.it('test 1-2', function () {
805 | assert.strictEqual(count++, 2)
806 | })
807 |
808 | t.suite('suite 1-1', function () {
809 | t.before(function (done) {
810 | setTimeout(function () {
811 | throw new Error('before hook error')
812 | })
813 | })
814 |
815 | t.it('test 2-1 not run', function () {
816 | assert.strictEqual(count++, 0)
817 | })
818 | })
819 |
820 | t.suite('suite 1-2', function () {
821 | t.afterEach(function (done) {
822 | setTimeout(function () {
823 | throw new Error('afterEach hook error')
824 | })
825 | })
826 |
827 | t.it('test 2-1 run', function () {
828 | assert.strictEqual(count++, 3)
829 | })
830 |
831 | t.it('test 2-2 not run', function () {
832 | assert.strictEqual(count++, 0)
833 | })
834 | })
835 |
836 | t.it('test 1-3', function () {
837 | assert.strictEqual(count++, 4)
838 | })
839 |
840 | return t.run(function (err, res) {
841 | if (err) throw err
842 | assert.strictEqual(res.passed, 3)
843 | assert.strictEqual(res.ignored, 0)
844 |
845 | var messages = ctx.messages.join('')
846 | assert.ok(messages.indexOf('test 1-1 with error (1)') > 0)
847 | assert.ok(messages.indexOf('/suite 1-1 "before" Hook (2)') > 0)
848 | assert.ok(messages.indexOf('/suite 1-2 "afterEach" Hook (3)') > 0)
849 |
850 | assert.ok(res.errors[0] instanceof Error)
851 | assert.strictEqual(res.errors[0].order, 1)
852 | assert.strictEqual(res.errors[0].title, '/test 1-1 with error')
853 |
854 | assert.ok(res.errors[1] instanceof Error)
855 | assert.strictEqual(res.errors[1].order, 2)
856 | assert.strictEqual(res.errors[1].title, '/suite 1-1 "before" Hook')
857 |
858 | assert.ok(res.errors[2] instanceof Error)
859 | assert.strictEqual(res.errors[2].order, 3)
860 | assert.strictEqual(res.errors[2].title, '/suite 1-2 "afterEach" Hook')
861 | })
862 | })
863 | })
864 |
865 | tman.suite('mocha compatible mode', function () {
866 | tman.it('enable', function () {
867 | var ctx = this
868 | var count = 0
869 | // new child instance for test
870 | var t = tman.createTman()
871 | this.messages = []
872 | t.setReporter(CustomReporter, this)
873 |
874 | t.mocha()
875 | t.before(function () {
876 | t.rootSuite.reporter.log(format.yellow('↓ ' + ctx.title + ':', true))
877 | assert.strictEqual(count++, 0)
878 | })
879 |
880 | t.after(function () {
881 | assert.strictEqual(count++, 37)
882 | })
883 |
884 | t.beforeEach(function () {
885 | count++
886 | })
887 |
888 | t.afterEach(function () {
889 | count++
890 | })
891 |
892 | t.it('test 1-1', function () {
893 | assert.strictEqual(count++, 2)
894 | })
895 |
896 | t.it('test 1-2', function () {
897 | assert.strictEqual(count++, 5)
898 | })
899 |
900 | t.suite('suite 1-1', function () {
901 | t.beforeEach(function () {
902 | count++
903 | })
904 |
905 | t.it('test 2-1', function () {
906 | assert.strictEqual(count++, 9)
907 | })
908 |
909 | t.it('test 2-2', function () {
910 | assert.strictEqual(count++, 13)
911 | })
912 |
913 | t.it('test 2-3', function () {
914 | assert.strictEqual(count++, 17)
915 | })
916 | })
917 |
918 | t.suite('suite 1-2', function () {
919 | t.it('test 2-1', function () {
920 | assert.strictEqual(count++, 20)
921 | })
922 | })
923 |
924 | t.suite('suite 1-3', function () {
925 | t.afterEach(function () {
926 | count++
927 | })
928 |
929 | t.it('test 2-1', function () {
930 | assert.strictEqual(count++, 23)
931 | })
932 |
933 | t.it('test 2-2', function () {
934 | assert.strictEqual(count++, 27)
935 | })
936 |
937 | t.suite('suite 1-3-1', function () {
938 | t.it('test 3-1', function () {
939 | assert.strictEqual(count++, 31)
940 | })
941 | })
942 | })
943 |
944 | t.it.skip('test 1-3', function () {
945 | assert.strictEqual(true, false)
946 | })
947 |
948 | t.it('test 1-4', function () {
949 | assert.strictEqual(count++, 35)
950 | })
951 |
952 | return t.run(function (err, res) {
953 | if (err) throw err
954 | assert.strictEqual(res.passed, 10)
955 | assert.strictEqual(res.ignored, 1)
956 | })
957 | })
958 | })
959 |
960 | tman.suite('reset', function () {
961 | tman.it('suite.reset', function () {
962 | var count = 0
963 | var t = tman.createTman()
964 | this.messages = []
965 | t.setReporter(CustomReporter, this)
966 |
967 | t.before(function () {
968 | assert.strictEqual(count++, 0)
969 | })
970 |
971 | t.after(function () {
972 | assert.strictEqual(count++, 2)
973 | })
974 |
975 | var suite = t.suite('suite', function () {
976 | t.before(function () {
977 | assert.strictEqual(true, false)
978 | })
979 |
980 | t.it('test 1', function () {
981 | assert.strictEqual(true, false)
982 | })
983 |
984 | t.it('test 2', function () {
985 | assert.strictEqual(true, false)
986 | })
987 | })
988 |
989 | t.it('test', function () {
990 | assert.strictEqual(count++, 1)
991 | })
992 |
993 | assert.strictEqual(t.rootSuite.children[0], suite)
994 | assert.strictEqual(suite.before.hooks.length, 1)
995 | assert.strictEqual(suite.after.hooks.length, 0)
996 | assert.strictEqual(suite.beforeEach.hooks.length, 0)
997 | assert.strictEqual(suite.afterEach.hooks.length, 0)
998 | assert.strictEqual(suite.children.length, 2)
999 |
1000 | suite.reset()
1001 | assert.strictEqual(suite.before.hooks.length, 0)
1002 | assert.strictEqual(suite.children.length, 0)
1003 |
1004 | return t.run(function (err, res) {
1005 | if (err) throw err
1006 | assert.strictEqual(res.passed, 1)
1007 | assert.strictEqual(res.ignored, 0)
1008 | })
1009 | })
1010 |
1011 | tman.it('tman.reset', function () {
1012 | var t = tman.createTman()
1013 | this.messages = []
1014 | t.setReporter(CustomReporter, this)
1015 |
1016 | t.before(function () {
1017 | assert.strictEqual(true, false)
1018 | })
1019 |
1020 | t.after(function () {
1021 | assert.strictEqual(true, false)
1022 | })
1023 |
1024 | t.suite('suite', function () {
1025 | t.before(function () {
1026 | assert.strictEqual(true, false)
1027 | })
1028 |
1029 | t.it('test 1', function () {
1030 | assert.strictEqual(true, false)
1031 | })
1032 |
1033 | t.it('test 2', function () {
1034 | assert.strictEqual(true, false)
1035 | })
1036 | })
1037 |
1038 | t.it('test', function () {
1039 | assert.strictEqual(true, false)
1040 | })
1041 |
1042 | t.reset()
1043 |
1044 | return t.run(function (err, res) {
1045 | if (err) throw err
1046 | assert.strictEqual(res.passed, 0)
1047 | assert.strictEqual(res.ignored, 0)
1048 |
1049 | t.it('test', function () {
1050 | assert.strictEqual(true, true)
1051 | })
1052 |
1053 | return t.run(function (err, res) {
1054 | if (err) throw err
1055 | assert.strictEqual(res.passed, 1)
1056 | assert.strictEqual(res.ignored, 0)
1057 | })
1058 | })
1059 | })
1060 | })
1061 |
1062 | tman.suite('tman.tryRun', function () {
1063 | tman.it('should clear previous tryRun', function () {
1064 | var time = Date.now()
1065 | var t = tman.createTman()
1066 | t.setExit(false)
1067 | this.messages = []
1068 | t.setReporter(CustomReporter, this)
1069 |
1070 | t.it('test tryRun', function () {
1071 | assert.strictEqual(true, true)
1072 | })
1073 |
1074 | t.tryRun(100)(function () {
1075 | assert.strictEqual('will be cleared', false)
1076 | })
1077 |
1078 | return thunk.delay(50)(function () {
1079 | return t.tryRun(50)(function (err, res) {
1080 | assert.strictEqual(err, null)
1081 | assert.strictEqual(res.passed, 1)
1082 | assert.strictEqual(res.ignored, 0)
1083 | assert.ok(Date.now() - time >= 100)
1084 | })
1085 | })
1086 | })
1087 |
1088 | tman.it('should not run if running', function () {
1089 | var time = Date.now()
1090 | var t = tman.createTman()
1091 | t.setExit(false)
1092 | this.messages = []
1093 | t.setReporter(CustomReporter, this)
1094 |
1095 | t.it('test tryRun', function () {
1096 | return thunk.delay(100)(function () {
1097 | assert.strictEqual(true, true)
1098 | })
1099 | })
1100 |
1101 | t.tryRun(50)(function () {
1102 | assert.strictEqual('should not run', false)
1103 | })
1104 | return t.tryRun(10)(function (err, res) {
1105 | assert.strictEqual(err, null)
1106 | assert.strictEqual(res.passed, 1)
1107 | assert.strictEqual(res.ignored, 0)
1108 | assert.ok(Date.now() - time > 100)
1109 | })
1110 | })
1111 | })
1112 |
--------------------------------------------------------------------------------