├── .babelrc ├── .eaterrc ├── .eslintrc.json ├── .gitignore ├── .travis.yml ├── README.md ├── bin ├── eater.js └── opts.js ├── images ├── eater.png ├── powerassert.png └── screenshot.png ├── index.js ├── lib ├── abortPromiseException.js ├── arraysToArgs.js ├── eater.js ├── forkTest.js ├── listupFiles.js ├── ordinalize.js ├── reporter │ └── Reporter.js └── runner.js ├── package-lock.json ├── package.json ├── renovate.json ├── runner.js └── test ├── babel ├── use-eater-with-babel-power-assert.js └── use-eater-with-babel.js ├── core ├── bin │ ├── eater │ │ ├── error.js │ │ ├── execRequires.js │ │ ├── glob.js │ │ ├── help.js │ │ ├── procs.js │ │ ├── repoter.js │ │ ├── requires.js │ │ ├── settingFromPackageJson.js │ │ ├── tap.js │ │ ├── targets.js │ │ └── version.js │ └── opts │ │ ├── .eaterrc │ │ ├── eaterrc.js │ │ ├── eaterrcNormal │ │ └── package.json ├── index.js ├── lib │ ├── eater │ │ ├── arraysToArgs.js │ │ ├── hasAnyError.js │ │ ├── nextTest.js │ │ ├── nextTestWithMock.js │ │ ├── noExtension.js │ │ ├── onEaterFinish.js │ │ ├── procs.js │ │ ├── receiveAllSuccessMessage.js │ │ ├── receiveFailedMessage.js │ │ ├── receiveLegacyDoneMessage.js │ │ ├── receiveLegacyFailedMessage.js │ │ ├── receiveMessage.js │ │ ├── receiveWithFailedMessage.js │ │ ├── reportFailure.js │ │ └── reportSuccess.js │ ├── listupFiles.js │ ├── oridinalize.js │ ├── reporter │ │ └── Reporter.js │ ├── runner.js │ └── runner │ │ ├── asScript.js │ │ ├── duplicateTestName.js │ │ ├── testFirst.js │ │ ├── testSecond.js │ │ ├── tester.js │ │ └── testseq.js └── promises │ ├── testPromiseRejectionHandled.js │ └── testPromiseUnhandledRejection.js ├── enable-babel.js ├── enable-power-assert.js ├── env └── test_process_env.js ├── fixture ├── __test__ │ └── b.js ├── babel │ ├── assert.js │ ├── babel.js │ └── failed.js ├── error.js ├── failedRunner.js ├── legacyDoneRunner.js ├── legacyFailedRunner.js ├── runner.js ├── runnerAllSuccess.js ├── runnerWithFailed.js ├── success.js └── test │ ├── a.js │ └── aaa │ └── bbb │ ├── c.js │ ├── c.test.js │ └── ccc │ └── b.js ├── only ├── only.js └── test.js ├── reporter ├── DotReporter.js └── EsModuleReporter.js └── runner ├── context.js └── tdd.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | ] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.eaterrc: -------------------------------------------------------------------------------- 1 | { 2 | "require":[ 3 | "./test/enable-power-assert.js", 4 | "./test/runner/context.js", 5 | ], 6 | "ext": 'js' 7 | } 8 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true, 4 | "commonjs": true, 5 | "es6": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "rules": { 9 | "accessor-pairs": "error", 10 | "array-bracket-spacing": "error", 11 | "array-callback-return": "error", 12 | "arrow-body-style": "error", 13 | "arrow-parens": [ 14 | "error", 15 | "always" 16 | ], 17 | "arrow-spacing": [ 18 | "error", 19 | { 20 | "after": true, 21 | "before": true 22 | } 23 | ], 24 | "block-scoped-var": "error", 25 | "block-spacing": "error", 26 | "brace-style": [ 27 | "error", 28 | "1tbs" 29 | ], 30 | "callback-return": "error", 31 | "camelcase": "error", 32 | "comma-dangle": "error", 33 | "comma-spacing": [ 34 | "error", 35 | { 36 | "after": true, 37 | "before": false 38 | } 39 | ], 40 | "comma-style": "error", 41 | "complexity": "error", 42 | "computed-property-spacing": [ 43 | "error", 44 | "never" 45 | ], 46 | "consistent-return": "error", 47 | "consistent-this": "error", 48 | "curly": "error", 49 | "default-case": "error", 50 | "dot-location": "error", 51 | "dot-notation": [ 52 | "error", 53 | { 54 | "allowKeywords": true 55 | } 56 | ], 57 | "eol-last": "error", 58 | "eqeqeq": "error", 59 | "func-names": [ 60 | "error", 61 | "always" 62 | ], 63 | "func-style": [ 64 | "error", 65 | "declaration" 66 | ], 67 | "generator-star-spacing": "error", 68 | "global-require": "error", 69 | "guard-for-in": "error", 70 | "handle-callback-err": "error", 71 | "id-blacklist": "error", 72 | "id-length": "off", 73 | "id-match": "error", 74 | "indent": ["error", 2], 75 | "init-declarations": "error", 76 | "jsx-quotes": "error", 77 | "key-spacing": "error", 78 | "keyword-spacing": [ 79 | "error", 80 | { 81 | "after": true, 82 | "before": true 83 | } 84 | ], 85 | "linebreak-style": [ 86 | "error", 87 | "unix" 88 | ], 89 | "lines-around-comment": "error", 90 | "max-depth": "error", 91 | "max-len": ["error", 120], 92 | "max-lines": "error", 93 | "max-nested-callbacks": "error", 94 | "max-params": "off", 95 | "max-statements": "off", 96 | "max-statements-per-line": "error", 97 | "new-cap": "error", 98 | "new-parens": "error", 99 | "newline-after-var": "off", 100 | "newline-before-return": "off", 101 | "newline-per-chained-call": "error", 102 | "no-alert": "error", 103 | "no-array-constructor": "error", 104 | "no-bitwise": "error", 105 | "no-caller": "error", 106 | "no-catch-shadow": "error", 107 | "no-confusing-arrow": "error", 108 | "no-continue": "error", 109 | "no-console": "off", 110 | "no-div-regex": "error", 111 | "no-duplicate-imports": "error", 112 | "no-else-return": "error", 113 | "no-empty-function": "off", 114 | "no-eq-null": "error", 115 | "no-eval": "error", 116 | "no-extend-native": "error", 117 | "no-extra-bind": "error", 118 | "no-extra-label": "error", 119 | "no-extra-parens": "off", 120 | "no-floating-decimal": "error", 121 | "no-implicit-globals": "error", 122 | "no-implied-eval": "error", 123 | "no-inline-comments": "error", 124 | "no-invalid-this": "error", 125 | "no-iterator": "error", 126 | "no-label-var": "error", 127 | "no-labels": "error", 128 | "no-lone-blocks": "error", 129 | "no-lonely-if": "error", 130 | "no-loop-func": "error", 131 | "no-magic-numbers": "off", 132 | "no-mixed-operators": "error", 133 | "no-mixed-requires": "error", 134 | "no-multi-spaces": "off", 135 | "no-multi-str": "error", 136 | "no-multiple-empty-lines": "error", 137 | "no-negated-condition": "error", 138 | "no-nested-ternary": "error", 139 | "no-new": "error", 140 | "no-new-func": "error", 141 | "no-new-object": "error", 142 | "no-new-require": "error", 143 | "no-new-wrappers": "error", 144 | "no-octal-escape": "error", 145 | "no-param-reassign": "error", 146 | "no-path-concat": "error", 147 | "no-plusplus": "off", 148 | "no-process-env": "off", 149 | "no-process-exit": "off", 150 | "no-proto": "error", 151 | "no-prototype-builtins": "error", 152 | "no-restricted-globals": "error", 153 | "no-restricted-imports": "error", 154 | "no-restricted-modules": "error", 155 | "no-restricted-syntax": "error", 156 | "no-return-assign": "error", 157 | "no-script-url": "error", 158 | "no-self-compare": "error", 159 | "no-sequences": "error", 160 | "no-shadow": "error", 161 | "no-shadow-restricted-names": "error", 162 | "no-spaced-func": "error", 163 | "no-sync": "off", 164 | "no-ternary": "off", 165 | "no-throw-literal": "error", 166 | "no-trailing-spaces": "error", 167 | "no-undef-init": "error", 168 | "no-undefined": "error", 169 | "no-underscore-dangle": "error", 170 | "no-unmodified-loop-condition": "error", 171 | "no-unneeded-ternary": "error", 172 | "no-unused-expressions": "error", 173 | "no-use-before-define": "error", 174 | "no-useless-call": "error", 175 | "no-useless-computed-key": "error", 176 | "no-useless-concat": "error", 177 | "no-useless-constructor": "error", 178 | "no-useless-escape": "error", 179 | "no-useless-rename": "error", 180 | "no-var": "error", 181 | "no-void": "error", 182 | "no-warning-comments": "error", 183 | "no-whitespace-before-property": "error", 184 | "no-with": "error", 185 | "object-curly-newline": "error", 186 | "object-curly-spacing": "error", 187 | "object-property-newline": [ 188 | "error", 189 | { 190 | "allowMultiplePropertiesPerLine": true 191 | } 192 | ], 193 | "object-shorthand": "error", 194 | "one-var": "off", 195 | "one-var-declaration-per-line": "error", 196 | "operator-assignment": [ 197 | "error", 198 | "always" 199 | ], 200 | "operator-linebreak": "error", 201 | "padded-blocks": "error", 202 | "prefer-arrow-callback": "error", 203 | "prefer-const": "error", 204 | "prefer-reflect": "error", 205 | "prefer-rest-params": "error", 206 | "prefer-spread": "error", 207 | "prefer-template": "off", 208 | "quote-props": "off", 209 | "quotes": [ 210 | "error", 211 | "single" 212 | ], 213 | "radix": [ 214 | "error", 215 | "as-needed" 216 | ], 217 | "require-jsdoc": "off", 218 | "rest-spread-spacing": "error", 219 | "semi": "error", 220 | "semi-spacing": "error", 221 | "sort-imports": "error", 222 | "sort-vars": "error", 223 | "space-before-blocks": "error", 224 | "space-before-function-paren": "off", 225 | "space-in-parens": [ 226 | "error", 227 | "never" 228 | ], 229 | "space-infix-ops": "error", 230 | "space-unary-ops": "error", 231 | "spaced-comment": "error", 232 | "strict": "error", 233 | "template-curly-spacing": [ 234 | "error", 235 | "never" 236 | ], 237 | "unicode-bom": [ 238 | "error", 239 | "never" 240 | ], 241 | "valid-jsdoc": "error", 242 | "vars-on-top": "error", 243 | "wrap-iife": "error", 244 | "wrap-regex": "error", 245 | "yield-star-spacing": "error", 246 | "yoda": [ 247 | "error", 248 | "never" 249 | ] 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | node_modules 4 | .nyc_output 5 | npm-debug.log 6 | coverage 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | - "10" 5 | - "12" 6 | script: npm run coveralls 7 | sudo: false 8 | cache: 9 | directories: 10 | - node_modules 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Eater 2 | =============== 3 | [![npm version](https://badge.fury.io/js/eater.svg)](https://badge.fury.io/js/eater) 4 | [![Build Status](https://travis-ci.org/yosuke-furukawa/eater.svg?branch=master)](https://travis-ci.org/yosuke-furukawa/eater) 5 | [![Coverage Status](https://coveralls.io/repos/github/yosuke-furukawa/eater/badge.svg?branch=master)](https://coveralls.io/github/yosuke-furukawa/eater?branch=master) 6 | 7 | ![logo](https://github.com/yosuke-furukawa/eater/raw/master/images/eater.png) 8 | 9 | Eater is **Ea** sy **t** est runn **er** . 10 | Eater has one simple rule. 11 | 12 | ``` 13 | If test file outputs `stderr` message, the test failed. 14 | ``` 15 | 16 | #Features 17 | 18 | - Multi-process: All eater test files run as separate processes and eater does not launch too many processes more than CPU-core number. 19 | - Easy mock: An eater test does not affect the other tests, but mock object sometimes kills your test. 20 | - Happy async: eater aims is here to handle async test well. Each eater files will run in `Node.js` child_process, so the tests always should be async first. If your tests mix sync and async tests, you will have a headache to maintain the tests. 21 | 22 | # [Demo](https://github.com/yosuke-furukawa/eater-demo) 23 | 24 | 25 | ![demo](https://github.com/yosuke-furukawa/eater-demo/raw/master/images/eater-demo.gif) 26 | 27 | # How to use 28 | 29 | ## 1. Install 30 | 31 | ``` 32 | $ npm install eater -g 33 | ``` 34 | 35 | ## 2. Write some tests 36 | 37 | ```js 38 | // test/sometest.js 39 | const assert = require('assert'); 40 | assert(1 === 2); // always failure 41 | ``` 42 | 43 | ## Run 44 | 45 | ``` 46 | $ eater 47 | ``` 48 | 49 | ![image](https://github.com/yosuke-furukawa/eater/raw/master/images/screenshot.png) 50 | 51 | ## eater `--dir` and `--ext` and `--glob` 52 | 53 | eater searches JavaScript files under `process.cwd()/test` dir by default. If you want to change the dir, use `--dir` option. 54 | 55 | ``` 56 | $ eater --dir spec/ 57 | ``` 58 | 59 | And if you changed test file extension, like `.jsx/.es6/.test.js`, you use `--ext` option. 60 | 61 | ``` 62 | $ eater --ext jsx 63 | ``` 64 | 65 | eater can find test files using glob pattern match. you use `--glob` option. 66 | 67 | ``` 68 | $ eater --glob **/__test/**/*.js 69 | ``` 70 | 71 | ### file 72 | 73 | ``` 74 | $ eater test/sometest.js test/foo.js test/bar.jd 75 | ``` 76 | 77 | ## If you are [power-assert](https://github.com/power-assert-js/power-assert) user 78 | 79 | ### 1. install `power-assert` and `espower-loader` 80 | 81 | ``` 82 | $ npm install eater -D 83 | $ npm install power-assert espower-loader -D 84 | ``` 85 | 86 | ### 2. enable `power-assert` 87 | 88 | ```js 89 | // script/enable-power-assert.js 90 | require('espower-loader')({ 91 | cwd: process.cwd(), 92 | pattern: 'test/**/*.js' 93 | }); 94 | ``` 95 | 96 | ### 3. run tests with `--require` 97 | 98 | ``` 99 | $ eater --require ./script/enable-power-assert.js 100 | ``` 101 | 102 | ![power-assert](https://github.com/yosuke-furukawa/eater/raw/master/images/powerassert.png) 103 | 104 | ## If you are babel(JSX) user 105 | 106 | ### 1. install `babel-register` or `active-cache-babel-register` 107 | 108 | ``` 109 | $ npm install eater -D 110 | $ npm install babel-register -D 111 | ``` 112 | 113 | or 114 | 115 | ``` 116 | $ npm install eater -D 117 | $ npm install active-cache-babel-register -D 118 | ``` 119 | 120 | Note: [active-cache-babel-register](https://github.com/yosuke-furukawa/active-cache-babel-register) improves babel transpilation performance. 121 | 122 | ### 2. enable `babel` 123 | 124 | ```js 125 | // script/enable-babel.js 126 | require('babel-register')({ // or to use require('active-cache-babel-register') 127 | ignore: (file) => { 128 | if (file.match(/node_modules/)) return true; 129 | return false; 130 | } 131 | }); 132 | ``` 133 | 134 | ### 3. run tests with `--require` 135 | 136 | ``` 137 | $ eater --require ./script/enable-babel.js 138 | ``` 139 | 140 | ## if you are power-assert and babel user: 141 | 142 | ### 1. install babel-preset-power-assert 143 | 144 | ``` 145 | $ npm install babel-preset-power-assert -D 146 | ``` 147 | 148 | ### 2. write your .babelrc 149 | 150 | ``` 151 | { 152 | "presets": ["es2015", "babel-preset-power-assert"] 153 | } 154 | ``` 155 | 156 | ### 3. run tests with `--require` 157 | 158 | ``` 159 | $ eater --require ./script/enable-babel.js 160 | ``` 161 | 162 | ## Coverage 163 | 164 | ### 1. install nyc instead of istanbul 165 | 166 | ``` 167 | $ npm install nyc -D 168 | ``` 169 | 170 | ### 2. run test with nyc 171 | 172 | ``` 173 | $ nyc eater 174 | ``` 175 | 176 | ## eater runner settings 177 | 178 | eater reads the arguments from settings. 179 | 180 | - package.json 181 | - .eaterrc 182 | 183 | ### package.json 184 | 185 | ```js 186 | { 187 | "name": "eaterDemo", 188 | "version": "1.0.0", 189 | "scripts": { 190 | "test": "eater" 191 | }, 192 | "eater": { 193 | "dir": "test/core", 194 | "require": [ 195 | "./enable-power-assert.js", 196 | "./enable-jsx.js" 197 | ] 198 | } 199 | } 200 | ``` 201 | 202 | ### .eaterrc 203 | 204 | .eaterrc is JSON5 format so you can write comment and trailing commas. 205 | 206 | ```js 207 | { 208 | dir: "test/core", 209 | require: [ 210 | "./enable-power-assert.js", 211 | "./enable-jsx.js", 212 | ], 213 | } 214 | ``` 215 | 216 | ### runner 217 | 218 | If you would like to use test runner, eater has `test` function. 219 | 220 | ```js 221 | const calc = require('../foo/bar/calc'); 222 | const test = require('eater/runner').test; 223 | const assert = require('assert'); 224 | 225 | test('give 2 arguments return sum', () => { 226 | const result = calc.sum(1, 2); 227 | assert(result === 3); 228 | }); 229 | 230 | test('give 2 arguments return sum on async', () => { 231 | const result = calc.sumAsync(1, 2); 232 | result.then((value) => { 233 | assert(value === 3) 234 | }); 235 | }); 236 | ``` 237 | 238 | Note that each subtests also run as separated processes, 239 | you don't have to care about sync/async stuff. 240 | 241 | # Use custom reporter 242 | 243 | ``` 244 | $ npm install eater-pacman-reporter 245 | $ eater --reporter eater-pacman-reporter 246 | ``` 247 | 248 | ![pacman](https://raw.githubusercontent.com/yosuke-furukawa/eater-pacman-reporter/master/images/pacman.gif) 249 | 250 | ## Custom Reporters 251 | 252 | - [eater-tap-reporter](https://npmjs.com/package/eater-tap-reporter) 253 | - [eater-pacman-reporter](https://npmjs.com/package/eater-pacman-reporter) 254 | - [eater-b-reporter](https://npmjs.com/package/eater-b-reporter) 255 | 256 | # Exclusive feature 257 | 258 | The exclusivity feature allows you to run `only` the specified test code by adding `// eater:only` comment on top of your test code. Here's an example. 259 | 260 | ```javascript 261 | // eater:only 262 | const test = require('eater/lib/runner').test; 263 | const mustCall = require('must-call'); 264 | const assert = require('power-assert'); 265 | 266 | test('only is executed', () => { 267 | assert(true); 268 | }); 269 | ``` 270 | 271 | And if you need to exclude your test case, `only` function is helpful. 272 | 273 | 274 | ```javascript 275 | // eater:only 276 | const only = require('eater/lib/runner').only; 277 | const test = require('eater/lib/runner').test; 278 | const mustCall = require('must-call'); 279 | const assert = require('power-assert'); 280 | 281 | test('this test should not execute', (_, fail) =>{ 282 | fail('should not be executed'); 283 | }); 284 | 285 | only('only is executed', () => { 286 | assert(true); 287 | }); 288 | ``` 289 | -------------------------------------------------------------------------------- /bin/eater.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const minimist = require('minimist'); 4 | const execArgv = minimist(process.execArgv); 5 | const argv = minimist(process.argv.slice(2)); 6 | const existsSync = require('exists-sync'); 7 | const path = require('path'); 8 | const opts = require('./opts')(argv, execArgv, process.cwd()); 9 | 10 | function showHelp() { 11 | console.log(` 12 | eater [--dir test directroy default 'test/'] [--ext test file extension default '.js'] [--glob find test files using glob pattern match like 'test/**/*.js'] [--reporter fooreporter] [--procs max process number default cpu core num] [--require prerequire modules] 13 | eater --dir test/lib 14 | eater --dir spec --ext .js 15 | eater --dir test/lib --ext .test.js 16 | eater --dir test/lib --ext .test.js --reporter SomeCustomReporter 17 | eater --dir test/lib --ext .test.js --procs 10 18 | eater --glob **/__test__/**/*.js 19 | eater --require foo/bar 20 | eater --eaterrc example/dir/.eaterrc 21 | eater test/foo.js test/bar.js test/buz.js 22 | `); 23 | process.exit(0); 24 | } 25 | 26 | if (opts.help) { 27 | showHelp(); 28 | } 29 | 30 | if (opts.version) { 31 | const pack = require('../package.json'); 32 | console.log(pack.version); 33 | process.exit(0); 34 | } 35 | 36 | var requires = opts.requires; 37 | 38 | requires = requires.map((r, i) => { 39 | const isLocalFile = existsSync(r) || existsSync(r + '.js'); 40 | const file = isLocalFile ? path.resolve(r) : r; 41 | require(file); 42 | return file; 43 | }); 44 | 45 | const Eater = require('../lib/eater'); 46 | const eater = new Eater({ 47 | reporter: new opts.Reporter(), 48 | dir: opts.dir, 49 | ext: opts.ext, 50 | glob: opts.glob, 51 | procs: opts.procs, 52 | requires: requires, 53 | targets: opts.targets, 54 | }); 55 | eater.eat(); 56 | 57 | eater.on('err', () => { 58 | process.exit(1); 59 | }); 60 | -------------------------------------------------------------------------------- /bin/opts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const existsSync = require('exists-sync'); 3 | const path = require('path'); 4 | const colo = require('colo'); 5 | const fs = require('fs'); 6 | const JSON5 = require('json5'); 7 | 8 | const opts = (argv, execArgv, cwd) => { 9 | const eaterrcFile = argv.eaterrc || path.join(cwd, '.eaterrc'); 10 | var eaterrc = {}; 11 | if (existsSync(eaterrcFile)) { 12 | eaterrc = JSON5.parse(fs.readFileSync(eaterrcFile).toString()); 13 | } 14 | if (existsSync(`${cwd}/package.json`)) { 15 | const eaterPackage = require(`${cwd}/package.json`).eater || {}; 16 | eaterrc = Object.assign(eaterrc, eaterPackage); 17 | } 18 | var reporter = argv.reporter || eaterrc.reporter; 19 | var dir = argv.dir || eaterrc.dir || 'test/'; 20 | var ext = argv.ext || eaterrc.ext || '.js'; 21 | var glob = argv.glob || eaterrc.glob; 22 | var procs = Number(argv.procs) || Number(eaterrc.procs) || 0; 23 | var requires = argv.require || eaterrc.require || []; 24 | var execRequires = execArgv.require || []; 25 | var help = argv.help || argv.h; 26 | var version = argv.version || argv.v; 27 | var targets = argv._; 28 | 29 | var Reporter = require('../lib/reporter/Reporter'); 30 | 31 | if (reporter) { 32 | try { 33 | const obj = require(reporter); 34 | Reporter = obj && obj.__esModule ? obj['default'] : obj; 35 | } catch(e) { 36 | console.error(colo.red.bold(e.toString())); 37 | process.exit(1); 38 | } 39 | } 40 | 41 | if (!Array.isArray(requires)) { 42 | requires = [requires]; 43 | } 44 | if (!Array.isArray(execRequires)) { 45 | execRequires = [execRequires]; 46 | } 47 | 48 | Array.prototype.push.apply(requires, execRequires); 49 | 50 | return { 51 | dir: dir, 52 | ext: ext, 53 | glob: glob, 54 | procs: procs, 55 | help: help, 56 | version: version, 57 | Reporter: Reporter, 58 | requires: requires, 59 | targets: targets, 60 | }; 61 | }; 62 | 63 | module.exports = opts; 64 | -------------------------------------------------------------------------------- /images/eater.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yosuke-furukawa/eater/59b327ede95dd5daa0d207d3a53e0f5c86b00921/images/eater.png -------------------------------------------------------------------------------- /images/powerassert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yosuke-furukawa/eater/59b327ede95dd5daa0d207d3a53e0f5c86b00921/images/powerassert.png -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yosuke-furukawa/eater/59b327ede95dd5daa0d207d3a53e0f5c86b00921/images/screenshot.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const Eater = require('./lib/eater'); 2 | const Reporter = require('./lib/reporter/Reporter'); 3 | 4 | module.exports.Eater = Eater; 5 | module.exports.Reporter = Reporter; 6 | -------------------------------------------------------------------------------- /lib/abortPromiseException.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | process.on('unhandledRejection', (e) => { 3 | 4 | throw e; 5 | 6 | }); 7 | -------------------------------------------------------------------------------- /lib/arraysToArgs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = (arrays, key) => { 3 | 4 | const results = []; 5 | arrays.forEach((item) => { 6 | 7 | results.push(`--${key}`); 8 | results.push(item); 9 | 10 | }); 11 | return results; 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /lib/eater.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const path = require('path'); 3 | const listupFiles = require('./listupFiles'); 4 | const arraysToArgs = require('./arraysToArgs'); 5 | const forkTest = require('./forkTest'); 6 | const EventEmitter = require('events').EventEmitter; 7 | const DEFAULT_MAXPROCS = require('os').cpus().length; 8 | 9 | class Eater extends EventEmitter { 10 | 11 | constructor(options) { 12 | 13 | super(); 14 | this.reporter = options.reporter; 15 | this.dir = options.dir; 16 | this.extension = options.ext || '.js'; 17 | this.glob = options.glob; 18 | this.procs = options.procs || DEFAULT_MAXPROCS; 19 | this.targets = options.targets || []; 20 | if (this.targets.length === 0) { 21 | 22 | this.files = listupFiles(this.dir, this.extension, this.glob); 23 | 24 | } else { 25 | 26 | this.files = this.targets; 27 | 28 | } 29 | this.fileNum = this.files.length; 30 | this.requires = options.requires || []; 31 | this.finishedFiles = []; 32 | this.errors = {}; 33 | this.hasAnyError = false; 34 | 35 | } 36 | 37 | eat() { 38 | 39 | this.reporter.reportFileNumber(this.fileNum); 40 | const currentFiles = this.files.splice(0, this.procs); 41 | this.on('next', this.nextTest); 42 | this.on('finish', (hasAnyError) => process.emit('eater:finish', hasAnyError)); 43 | currentFiles.forEach((file) => this.emit('next', file)); 44 | 45 | } 46 | 47 | nextTest(file) { 48 | 49 | this.reporter.reportTestName(file); 50 | const args = arraysToArgs(this.requires, 'require'); 51 | args.unshift('--require', path.join(__dirname, 'abortPromiseException')); 52 | const child = forkTest(file, {silent: true, execArgv: args}); 53 | this.reporter.setChildProc(child); 54 | child.on('message', (m) => { 55 | 56 | if (m.type === 'failure') { 57 | 58 | this.reporter.reportSubFailure(m.testName, file, m.out, m.error); 59 | this.errors[`${file} - ${m.testName}`] = m.error; 60 | 61 | } else if (m.type === 'success') { 62 | 63 | this.reporter.reportSubSuccess(m.testName, file, m.out); 64 | 65 | } else if (m.type === 'testname') { 66 | 67 | this.reporter.reportSubTestName(m.testName, file); 68 | 69 | } 70 | 71 | }); 72 | child.on('success', (out) => { 73 | 74 | this.reporter.reportSuccess(file, out); 75 | 76 | }); 77 | child.on('failure', (out, error) => { 78 | 79 | this.reporter.reportFailure(file, out, error); 80 | this.hasAnyError = true; 81 | this.errors[file] = error; 82 | 83 | }); 84 | child.on('close', () => { 85 | 86 | this.finishedFiles.push(file); 87 | if (this.files.length > 0) { 88 | 89 | this.emit('next', this.files.shift()); 90 | 91 | } else if (this.finishedFiles.length === this.fileNum) { 92 | 93 | this.reporter.reportFinish(this.hasAnyError, this.errors); 94 | this.emit('finish', this.hasAnyError); 95 | 96 | if (this.hasAnyError) { 97 | 98 | this.emit('err', this.hasAnyError, this.errors); 99 | 100 | } 101 | 102 | } 103 | 104 | } 105 | ); 106 | 107 | } 108 | 109 | } 110 | 111 | module.exports = Eater; 112 | -------------------------------------------------------------------------------- /lib/forkTest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const cp = require('child_process'); 3 | 4 | function forkTest(file, opts) { 5 | 6 | let hasErr = false; 7 | 8 | const child = cp.fork(file, opts); 9 | 10 | let out = ''; 11 | child.stdout.setEncoding('utf8'); 12 | child.stdout.on('data', (data) => { 13 | 14 | out += data; 15 | 16 | }); 17 | 18 | let error = ''; 19 | child.stderr.setEncoding('utf8'); 20 | child.stderr.on('data', (data) => { 21 | 22 | hasErr = true; 23 | error += data; 24 | 25 | }); 26 | child.on('close', () => { 27 | 28 | if (hasErr) { 29 | 30 | child.emit('failure', out, error); 31 | 32 | } else { 33 | 34 | child.emit('success', out); 35 | 36 | } 37 | 38 | }); 39 | 40 | return child; 41 | 42 | } 43 | 44 | module.exports = forkTest; 45 | -------------------------------------------------------------------------------- /lib/listupFiles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const glob = require('glob'); 5 | const EATER_ONLY = 'eater:only'; 6 | 7 | module.exports = function listupFiles(dir, extention, globPattern) { 8 | 9 | if (typeof dir !== 'string') { 10 | 11 | throw new Error('dir should be string'); 12 | 13 | } 14 | 15 | if (typeof extention !== 'string') { 16 | 17 | throw new Error('extension should be string'); 18 | 19 | } 20 | 21 | if (globPattern && !glob.hasMagic(globPattern)) { 22 | 23 | throw new Error('glob pattern should have magic glob chars like *, ?'); 24 | 25 | } 26 | 27 | let files = []; 28 | 29 | if (globPattern) { 30 | 31 | files = glob.sync(globPattern); 32 | 33 | } else { 34 | 35 | const testDir = fs.readdirSync(dir); 36 | testDir.forEach((f) => { 37 | 38 | const file = path.join(dir, f); 39 | if (fs.statSync(file).isDirectory()) { 40 | 41 | files = files.concat(listupFiles(file, extention)); 42 | 43 | } else { 44 | 45 | if (!file.endsWith(extention)) { 46 | 47 | return; 48 | 49 | } 50 | files.push(file); 51 | 52 | } 53 | 54 | }); 55 | 56 | } 57 | 58 | let onlyTest = null; 59 | files.forEach((file) => { 60 | 61 | const content = fs.readFileSync(file, 'utf-8'); 62 | if (content.indexOf(EATER_ONLY) >= 0) { 63 | 64 | onlyTest = file; 65 | 66 | } 67 | 68 | }); 69 | 70 | if (onlyTest) { 71 | 72 | files = [onlyTest]; 73 | 74 | } 75 | 76 | return files; 77 | 78 | }; 79 | -------------------------------------------------------------------------------- /lib/ordinalize.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = function ordinalize(num) { 3 | 4 | const n = parseInt(num); 5 | const twoDigits = n % 100; 6 | const num11to13 = twoDigits >= 11 && twoDigits <= 13; 7 | if (num11to13) { 8 | 9 | return n + 'th'; 10 | 11 | } 12 | 13 | const oneDigits = n % 10; 14 | if (oneDigits === 1) { 15 | 16 | return n + 'st'; 17 | 18 | } 19 | if (oneDigits === 2) { 20 | 21 | return n + 'nd'; 22 | 23 | } 24 | if (oneDigits === 3) { 25 | 26 | return n + 'rd'; 27 | 28 | } 29 | 30 | return n + 'th'; 31 | 32 | }; 33 | -------------------------------------------------------------------------------- /lib/reporter/Reporter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const colo = require('colo'); 3 | const ordinalize = require('../ordinalize'); 4 | const TOTAL = Symbol('eater.total'); 5 | 6 | class Reporter { 7 | 8 | constructor() { 9 | 10 | this.exectimeMap = new Map(); 11 | this.successCount = 0; 12 | this.subSuccessCount = 0; 13 | this.failureCount = 0; 14 | this.subFailureCount = 0; 15 | 16 | } 17 | reportFileNumber(num) { 18 | 19 | console.log(colo.cyan.bold(`Test File Num : ${num}`)); 20 | this.exectimeMap.set(TOTAL, {start: Date.now()}); 21 | 22 | } 23 | reportTestName(name) { 24 | 25 | console.log(colo.grey.bold(`Testing... : ${name}`)); 26 | this.exectimeMap.set(name, {start: Date.now()}); 27 | 28 | } 29 | reportSubTestName(name, parent) { 30 | 31 | const key = `${name} - ${parent}`; 32 | const value = this.exectimeMap.get(key); 33 | const num = (value && ordinalize(value.num + 1)) || ''; 34 | console.log(colo.grey(` Test Name : ${name} in ${parent} ${num}`)); 35 | this.exectimeMap.set(key, {start: Date.now(), num: value ? value.num + 1 : 1}); 36 | 37 | } 38 | setChildProc(child) { // eslint-disable-line no-unused-vars 39 | } 40 | reportSubFailure(name, parent, out, error) { 41 | 42 | const key = `${name} - ${parent}`; 43 | const value = this.exectimeMap.get(key); 44 | const message = (out ? out + '\n' : '') + (error || ''); 45 | const start = (value && value.start) || Date.now(); 46 | const num = (value && value.num > 1 && ordinalize(value.num)) || ''; 47 | console.log(`${colo.red(' ✗ failure: ')}${num} ${name} - ${parent} ${Date.now() - start} ms\n${message}`); 48 | this.subFailureCount++; 49 | 50 | } 51 | reportSubSuccess(name, parent, out) { 52 | 53 | const key = `${name} - ${parent}`; 54 | const value = this.exectimeMap.get(key); 55 | const message = (out ? out + '\n' : ''); 56 | const start = (value && value.start) || Date.now(); 57 | const num = (value && value.num > 1 && ordinalize(value.num)) || ''; 58 | console.log(`${colo.green(' ✓ success: ')}${num} ${name} - ${parent} ${Date.now() - start} ms\n${message}`); 59 | this.subSuccessCount++; 60 | 61 | } 62 | reportFailure(name, out, error) { 63 | 64 | const message = (out ? out + '\n' : '') + (error || ''); 65 | const value = this.exectimeMap.get(name); 66 | const start = (value && value.start) || Date.now(); 67 | console.log(`${colo.red.bold('✗ failure: ')} ${name} ${Date.now() - start} ms\n${message}`); 68 | this.failureCount++; 69 | 70 | } 71 | reportSuccess(name, out) { 72 | 73 | const message = (out ? out + '\n' : ''); 74 | const value = this.exectimeMap.get(name); 75 | const start = (value && value.start) || Date.now(); 76 | console.log(`${colo.green.bold('✓ success: ')} ${name} ${Date.now() - start} ms\n${message}`); 77 | this.successCount++; 78 | 79 | } 80 | reportFinish(hasAnyError, errors) { 81 | 82 | const start = this.exectimeMap.get(TOTAL).start; 83 | const keys = Object.keys(errors); 84 | if (keys.length) { 85 | 86 | console.log(`\n\n${colo.red.bold('ALL FAILURES:')}`); 87 | keys.forEach((key) => { 88 | 89 | console.log(`${colo.bold(key)}\n${errors[key]}`); 90 | 91 | }); 92 | 93 | } 94 | console.log( 95 | `${colo.green.bold('✓ Total success count: ' + this.successCount)}\n` + 96 | `${this.subSuccessCount ? colo.green(' ✓ Total sub success count: ' + this.subSuccessCount) + '\n' : ''}` + 97 | `${this.failureCount ? colo.red.bold('✗ Total failure count: ' + this.failureCount) + '\n' : ''}` + 98 | `${this.subFailureCount ? colo.red(' ✗ Total sub failure count: ' + this.subFailureCount) + '\n' : ''}` + 99 | `Total duration time: ${colo.cyan.bold((Date.now() - start) + 'ms')}` 100 | ); 101 | 102 | } 103 | 104 | } 105 | 106 | module.exports = Reporter; 107 | -------------------------------------------------------------------------------- /lib/runner.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const EventEmitter = require('events').EventEmitter; 3 | const colo = require('colo'); 4 | const forkTest = require('./forkTest'); 5 | 6 | const runEmitter = new EventEmitter(); 7 | 8 | class Runner { 9 | 10 | static test(message, check) { 11 | 12 | Runner.tasks.push({message, check}); 13 | if (!Runner.eaten) { 14 | 15 | process.nextTick(Runner.eat); 16 | Runner.eaten = true; 17 | 18 | } 19 | 20 | } 21 | 22 | static only(message, check) { 23 | 24 | Runner.onlyTask = {message, check}; 25 | if (!Runner.eaten) { 26 | 27 | process.nextTick(Runner.eat); 28 | Runner.eaten = true; 29 | 30 | } 31 | 32 | } 33 | 34 | 35 | static runTest(task) { 36 | 37 | const checkPromise = new Promise(task.check); 38 | checkPromise.then(() => { 39 | 40 | process.exit(0); 41 | 42 | }).catch((e) => { 43 | 44 | if (e && e.stack) { 45 | 46 | console.error(`${e.stack}`); 47 | 48 | } else { 49 | 50 | console.error(`${colo.red.bold('Subtest failed message: ')}${e}`); 51 | 52 | } 53 | 54 | }); 55 | 56 | } 57 | 58 | static nextTest(next) { 59 | 60 | const task = Runner.tasks[next]; 61 | Runner.report({type: 'testname', testName: task.message}); 62 | const child = forkTest( 63 | process.argv[1], { 64 | silent: true, 65 | env: Object.assign(process.env, {EATER_SUBTEST: '' + next}) 66 | }); 67 | child.on('success', (out) => { 68 | 69 | Runner.report({type: 'success', testName: task.message, out}); 70 | 71 | }); 72 | child.on('failure', (out, error) => { 73 | 74 | Runner.report({type: 'failure', testName: task.message, out, error}); 75 | ++Runner.errorTasks; 76 | 77 | }); 78 | child.on('close', () => { 79 | 80 | if (next + 1 < Runner.taskCount) { 81 | 82 | runEmitter.emit('next', next + 1); 83 | 84 | } else if (Runner.errorTasks) { 85 | 86 | console.error(colo.red.bold(`${Runner.errorTasks} Subtest(s) failed`)); 87 | 88 | } 89 | 90 | }); 91 | 92 | } 93 | 94 | static report(message) { 95 | 96 | if (process.send) { 97 | 98 | process.send(message); 99 | 100 | } else { 101 | 102 | console.log(`${message.type}: ${message.testName}`); 103 | 104 | } 105 | 106 | } 107 | 108 | static eat() { 109 | 110 | if (Runner.onlyTask) { 111 | 112 | Runner.tasks = [Runner.onlyTask]; 113 | 114 | } 115 | Runner.taskCount = Runner.tasks.length; 116 | runEmitter.on('run', Runner.runTest); 117 | runEmitter.on('next', Runner.nextTest); 118 | 119 | if (process.env.EATER_SUBTEST) { 120 | 121 | const next = +(process.env.EATER_SUBTEST) || 0; 122 | runEmitter.emit('run', Runner.tasks[next]); 123 | 124 | } else { 125 | 126 | runEmitter.emit('next', 0); 127 | 128 | } 129 | 130 | } 131 | 132 | } 133 | 134 | Runner.eaten = false; 135 | Runner.tasks = []; 136 | Runner.onlyTask = null; 137 | Runner.taskCount = 0; 138 | Runner.errorTasks = 0; 139 | 140 | module.exports = Runner; 141 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eater", 3 | "version": "4.0.4", 4 | "description": "eater is EAsy Test runnER", 5 | "main": "index.js", 6 | "bin": "./bin/eater.js", 7 | "scripts": { 8 | "test": "npm-run-all test:* lint", 9 | "test:core": "node bin/eater.js --dir test/core", 10 | "test:runner": "node bin/eater.js --dir test/runner", 11 | "test:env": "NODE_ENV=test node bin/eater.js --dir test/env", 12 | "test:babel": "node bin/eater.js --dir test/babel", 13 | "test:only": "node bin/eater.js --dir test/only", 14 | "cov": "nyc npm-run-all test:core test:runner test:only", 15 | "report": "nyc report --reporter=text-lcov", 16 | "coveralls": "npm-run-all cov report | coveralls", 17 | "lint": "eslint lib/ --fix" 18 | }, 19 | "keywords": [ 20 | "test", 21 | "assert" 22 | ], 23 | "author": "yosuke-furukawa", 24 | "license": "MIT", 25 | "dependencies": { 26 | "colo": "^1.0.0", 27 | "exists-sync": "0.1.0", 28 | "glob": "^7.1.6", 29 | "json5": "^2.1.2", 30 | "minimist": "^1.2.5" 31 | }, 32 | "devDependencies": { 33 | "@babel/core": "7.14.0", 34 | "@babel/preset-env": "7.14.1", 35 | "@babel/register": "7.13.16", 36 | "core-js": "3.15.2", 37 | "coveralls": "3.1.0", 38 | "eater-tap-reporter": "0.1.0", 39 | "eslint": "7.27.0", 40 | "espower-loader": "1.2.2", 41 | "mock-require": "3.0.3", 42 | "must-call": "1.0.0", 43 | "npm-run-all": "4.1.5", 44 | "nyc": "15.1.0", 45 | "power-assert": "1.6.1" 46 | }, 47 | "repository": { 48 | "type": "git", 49 | "url": "https://github.com/yosuke-furukawa/eater" 50 | }, 51 | "bugs": { 52 | "url": "https://github.com/yosuke-furukawa/eater/issues" 53 | }, 54 | "homepage": "https://github.com/yosuke-furukawa/eater" 55 | } 56 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /runner.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/runner'); 2 | -------------------------------------------------------------------------------- /test/babel/use-eater-with-babel-power-assert.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | 4 | const resultRequireBabel = cp.spawnSync('node', [`${process.cwd()}/bin/eater.js`, '--require', './test/enable-babel.js', 'test/fixture/babel/failed.js' ]); 5 | 6 | console.log(resultRequireBabel.stdout.toString()) 7 | 8 | assert(resultRequireBabel.stdout.toString().match(/false == true/)); 9 | -------------------------------------------------------------------------------- /test/babel/use-eater-with-babel.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | 4 | const resultRequireBabel = cp.execSync(` 5 | node ${process.cwd()}/bin/eater.js --require ./test/enable-babel.js --dir test/fixture/babel --ext assert.js --reporter eater-tap-reporter 6 | `.trim()).toString(); 7 | 8 | assert(resultRequireBabel.match(/1\.\.1/)); 9 | assert(resultRequireBabel.match(/ok 1 test[/\\]fixture[/\\]babel[/\\]assert\.js/)); 10 | -------------------------------------------------------------------------------- /test/core/bin/eater/error.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | 4 | const result = cp.spawnSync("node", [`${process.cwd()}/bin/eater.js`, "--dir", "test/fixture/", "--ext", "error.js"]); 5 | console.log() 6 | assert(result.stdout.toString().indexOf('Error!!!!!') !== -1); 7 | assert(result.status === 1); 8 | -------------------------------------------------------------------------------- /test/core/bin/eater/execRequires.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | 4 | const result = cp.execSync(` 5 | node --require ./test/fixture/success.js ${process.cwd()}/bin/eater.js --dir test/fixture/ --ext success.js --procs 10 --reporter eater-tap-reporter 6 | `.trim()).toString(); 7 | 8 | assert(result.match(/success!!/)); 9 | assert(result.match(/1\.\.1/)); 10 | assert(result.match(/ok 1 test[/\\]fixture[/\\]success\.js/)); 11 | -------------------------------------------------------------------------------- /test/core/bin/eater/glob.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | 4 | const result = cp.execSync(`node ${process.cwd()}/bin/eater.js --glob **/__test__/**/*.js`).toString(); 5 | assert(result.match(/test[\\/]fixture[\\/]__test__[\\/]b.js/)); 6 | -------------------------------------------------------------------------------- /test/core/bin/eater/help.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | 4 | const result = cp.execSync(`node ${process.cwd()}/bin/eater.js --help`).toString(); 5 | assert(result.indexOf(`eater [--dir test directroy default 'test/'] [--ext test file extension default '.js']`) !== -1); 6 | 7 | -------------------------------------------------------------------------------- /test/core/bin/eater/procs.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | 4 | const result = cp.execSync(`node ${process.cwd()}/bin/eater.js --reporter eater-tap-reporter --dir test/fixture/ --ext success.js --procs 10`).toString(); 5 | 6 | assert(result.match(/1\.\.1/)); 7 | assert(result.match(/ok 1 test[/\\]fixture[/\\]success\.js/)); 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/core/bin/eater/repoter.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | const colo = require('colo'); 4 | const Reporter = require(`${process.cwd()}`).Reporter; 5 | 6 | const result = cp.execSync(`node ${process.cwd()}/bin/eater.js --reporter ${process.cwd()}/test/reporter/DotReporter --dir test/fixture/ --ext success.js`).toString(); 7 | assert(result.trim() === '.'); 8 | 9 | const esModuleResult = cp.execSync(`node ${process.cwd()}/bin/eater.js --reporter ${process.cwd()}/test/reporter/EsModuleReporter --dir test/fixture/ --ext success.js`).toString(); 10 | assert(esModuleResult.trim() === 'o'); 11 | 12 | const errResult = cp.spawnSync("node", [`${process.cwd()}/bin/eater.js`, "--reporter", "NotFoundReporter", "--dir", "test/fixture/", "--ext", "js"]); 13 | assert(errResult.stderr.toString().trim().indexOf("Error: Cannot find module 'NotFoundReporter'") >= 0); 14 | -------------------------------------------------------------------------------- /test/core/bin/eater/requires.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | 4 | const result = cp.execSync(` 5 | node ${process.cwd()}/bin/eater.js --require test/fixture/success.js --dir test/fixture/ --ext success.js --procs 10 --reporter eater-tap-reporter 6 | `.trim()).toString(); 7 | 8 | assert(result.match(/success!!/)); 9 | assert(result.match(/1\.\.1/)); 10 | assert(result.match(/ok 1 test[/\\]fixture[/\\]success\.js/)); 11 | 12 | const hasDotResult = cp.execSync(` 13 | node ${process.cwd()}/bin/eater.js --require ./test/fixture/success.js --dir test/fixture/ --ext success.js --procs 10 --reporter eater-tap-reporter 14 | `.trim()).toString(); 15 | 16 | assert(hasDotResult.match(/success!!/)); 17 | assert(hasDotResult.match(/1\.\.1/)); 18 | assert(hasDotResult.match(/ok 1 test[/\\]fixture[/\\]success\.js/)); 19 | 20 | const withoutJSResult = cp.execSync(` 21 | node ${process.cwd()}/bin/eater.js --require test/fixture/success --dir test/fixture/ --ext success.js --procs 10 --reporter eater-tap-reporter 22 | `.trim()).toString(); 23 | 24 | assert(withoutJSResult.match(/success!!/)); 25 | assert(withoutJSResult.match(/1\.\.1/)); 26 | assert(withoutJSResult.match(/ok 1 test[/\\]fixture[/\\]success\.js/)); 27 | 28 | const coloResult = cp.execSync(` 29 | node ${process.cwd()}/bin/eater.js --require colo --dir test/fixture/ --ext success.js --procs 10 --reporter eater-tap-reporter 30 | `.trim()).toString(); 31 | 32 | assert(coloResult.match(/1\.\.1/)); 33 | assert(coloResult.match(/ok 1 test[/\\]fixture[/\\]success\.js/)); 34 | 35 | -------------------------------------------------------------------------------- /test/core/bin/eater/settingFromPackageJson.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | 4 | const result = cp.spawnSync('node',` 5 | --require ./test/package/mockPackageJson.js ${process.cwd()}/bin/eater.js --dir test/fixture/ --ext success.js 6 | `.trim().split(' ')); 7 | console.log(result.stdout.toString()); 8 | -------------------------------------------------------------------------------- /test/core/bin/eater/tap.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | 4 | const result = cp.execSync(`node ${process.cwd()}/bin/eater.js --reporter eater-tap-reporter --dir test/fixture/ --ext success.js`).toString(); 5 | 6 | assert(result.match(/1\.\.1/)); 7 | assert(result.match(/ok 1 test[/\\]fixture[/\\]success\.js/)); 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/core/bin/eater/targets.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | const colo = require('colo'); 4 | const Reporter = require(`${process.cwd()}`).Reporter; 5 | 6 | const result = cp.execSync(`node ${process.cwd()}/bin/eater.js test/fixture/success.js test/fixture/test/a.js`).toString(); 7 | 8 | assert(result.match(/success!!/)); 9 | assert(result.match(/test[/\\]fixture[/\\]success\.js/)); 10 | assert(result.match(/hogehoge/)); 11 | assert(result.match(/test[/\\]fixture[/\\]test[/\\]a\.js/)); 12 | -------------------------------------------------------------------------------- /test/core/bin/eater/version.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | const p = require(`${process.cwd()}/package.json`); 4 | 5 | const result = cp.execSync(`node ${process.cwd()}/bin/eater.js --version`).toString(); 6 | assert(result.trim() === p.version); 7 | -------------------------------------------------------------------------------- /test/core/bin/opts/.eaterrc: -------------------------------------------------------------------------------- 1 | { 2 | "reporter": "eater-tap-reporter" 3 | } 4 | 5 | -------------------------------------------------------------------------------- /test/core/bin/opts/eaterrc.js: -------------------------------------------------------------------------------- 1 | const opts = require(`${process.cwd()}/bin/opts`); 2 | const assert = require('power-assert'); 3 | const path = require('path'); 4 | 5 | const argv = { 6 | eaterrc: path.resolve(`${__dirname}/eaterrcNormal`), 7 | }; 8 | var result = opts(argv, {}, process.cwd()); 9 | assert.deepEqual(result.requires, ["test/fixture/success.js", "colo"]); 10 | 11 | result = opts({}, {}, __dirname); 12 | assert(result.Reporter); // eater-tap-reporter 13 | assert(result.dir === "test/core"); 14 | 15 | result = opts({}, {}, `${__dirname}/nopackage`); 16 | assert(result.Reporter); // default reporter `'../lib/reporter/Reporter'` 17 | assert(result.dir === 'test/'); 18 | -------------------------------------------------------------------------------- /test/core/bin/opts/eaterrcNormal: -------------------------------------------------------------------------------- 1 | { 2 | "require": [ 3 | "test/fixture/success.js", 4 | "colo", 5 | ], 6 | } 7 | -------------------------------------------------------------------------------- /test/core/bin/opts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eater", 3 | "version": "1.2.1", 4 | "description": "eater is EAsy Test runnER", 5 | "main": "index.js", 6 | "bin": "./bin/eater.js", 7 | "scripts": { 8 | "test": "npm run test:core && npm run test:runner", 9 | "test:core": "./bin/eater.js --require ./test/enable-power-assert.js --dir test/core --ext js", 10 | "test:runner": "./bin/eater.js --require ./test/enable-power-assert.js --require ./test/runner/context.js --dir test/runner --ext js", 11 | "test:babel": "./bin/eater.js --dir test/babel --ext js", 12 | "cov": "nyc npm test", 13 | "coveralls": "nyc npm test && nyc report --reporter=text-lcov | coveralls" 14 | }, 15 | "keywords": [ 16 | "test", 17 | "assert" 18 | ], 19 | "author": "yosuke-furukawa", 20 | "license": "MIT", 21 | "dependencies": { 22 | "colo": "^0.3.1", 23 | "exists-sync": "0.0.3", 24 | "json5": "^0.5.0", 25 | "minimist": "^1.2.0" 26 | }, 27 | "devDependencies": { 28 | "babel-preset-es2015": "^6.6.0", 29 | "coveralls": "^2.11.9", 30 | "espower-babel": "^4.0.3", 31 | "espower-loader": "^1.0.0", 32 | "mock-require": "^1.2.1", 33 | "nyc": "^6.4.0", 34 | "power-assert": "^1.3.1" 35 | }, 36 | "eater": { 37 | "dir": "test/core" 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /test/core/index.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | const eater = require(`${process.cwd()}`); 3 | const Eater = require(`${process.cwd()}/lib/eater`); 4 | const Reporter = require(`${process.cwd()}/lib/reporter/Reporter`); 5 | 6 | assert(eater.Eater === Eater); 7 | assert(eater.Reporter === Reporter); 8 | -------------------------------------------------------------------------------- /test/core/lib/eater/arraysToArgs.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | const arraysToArgs = require(`${process.cwd()}/lib/arraysToArgs`); 3 | const results = arraysToArgs([ 4 | 'foo', 5 | 'bar', 6 | 'buz', 7 | ], 'require'); 8 | 9 | assert.deepEqual( 10 | results, 11 | [ 12 | '--require', 13 | 'foo', 14 | '--require', 15 | 'bar', 16 | '--require', 17 | 'buz', 18 | ] 19 | ); 20 | 21 | const noArgs = arraysToArgs([ 22 | ], 'require'); 23 | 24 | assert.deepEqual( 25 | noArgs, 26 | [] 27 | ); 28 | -------------------------------------------------------------------------------- /test/core/lib/eater/hasAnyError.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('power-assert'); 4 | const Eater = require(`${process.cwd()}/lib/eater`); 5 | const mockReporter = { 6 | setChildProc: (child) => { 7 | // do nothing 8 | }, 9 | reportTestName: (name) => { 10 | // do nothing 11 | }, 12 | reportFileNumber: (num) => { 13 | assert(num === 1); 14 | }, 15 | reportFailure: (name) => { 16 | assert(name.match(/test[/\\]fixture[/\\]error\.js/)); 17 | }, 18 | reportFinish: (hasAnyError) => { 19 | assert(hasAnyError); 20 | } 21 | }; 22 | const eater = new Eater({ 23 | reporter: mockReporter, 24 | dir: 'test/fixture', 25 | ext: 'error.js', 26 | }); 27 | eater.eat(); 28 | eater.on('err', (hasAnyError) => { 29 | assert(hasAnyError === true); 30 | }); 31 | -------------------------------------------------------------------------------- /test/core/lib/eater/nextTest.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | const Eater = require(`${process.cwd()}/lib/eater`); 3 | const mockReporter = { 4 | setChildProc: (child) => { 5 | // do nothing 6 | }, 7 | reportTestName: (name) => { 8 | // do nothing 9 | }, 10 | reportSuccess: (name) => { 11 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]success\.js/)); 12 | }, 13 | reportFinish: (hasAnyError) => { 14 | assert(!hasAnyError); 15 | } 16 | }; 17 | const eater = new Eater({ 18 | reporter: mockReporter, 19 | dir: 'test/core', 20 | ext: '.nosuchfiles', 21 | }); 22 | eater.files = ['./test/fixture/success.js']; 23 | eater.nextTest('./test/fixture/success.js'); 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/core/lib/eater/nextTestWithMock.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const mustCall = require('must-call'); 3 | const assert = require('power-assert'); 4 | const Eater = require(`${process.cwd()}/lib/eater`); 5 | const mockFork = () => { 6 | return { 7 | stdout: { 8 | setEncoding() {}, 9 | on: () => { 10 | // do nothing 11 | } 12 | }, 13 | stderr: { 14 | setEncoding() {}, 15 | on: () => { 16 | // do nothing 17 | } 18 | }, 19 | on: (m, cb) => { 20 | if (m === 'message') { 21 | cb({ type: 'testname', testName: 'test' }); 22 | cb({ type: 'success', testName: 'test' }); 23 | cb({ type: 'failure', testName: 'test' }); 24 | cb({ type: 'nosuchtype', testName: 'test' }); 25 | } 26 | } 27 | }; 28 | }; 29 | cp.fork = mockFork; 30 | const mockReporter = { 31 | setChildProc: (child) => { 32 | // do nothing 33 | }, 34 | reportTestName: () => { 35 | // do nothing 36 | }, 37 | reportSubTestName: mustCall((name, parent) => { 38 | assert(name === 'test'); 39 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]success\.js/)); 40 | }), 41 | reportSubSuccess: mustCall((name, parent) => { 42 | assert(name === 'test'); 43 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]success\.js/)); 44 | }), 45 | reportSubFailure: mustCall((name, parent) => { 46 | assert(name === 'test'); 47 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]success\.js/)); 48 | }), 49 | }; 50 | const eater = new Eater({ 51 | reporter: mockReporter, 52 | dir: 'test/core', 53 | ext: '.nosuchfiles', 54 | }); 55 | eater.files = ['./test/fixture/success.js']; 56 | eater.nextTest('./test/fixture/success.js'); 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /test/core/lib/eater/noExtension.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | const Eater = require(`${process.cwd()}/lib/eater`); 3 | const mockReporter = { 4 | setChildProc: (child) => { 5 | // do nothing 6 | }, 7 | reportTestName: (name) => { 8 | // do nothing 9 | }, 10 | reportFileNumber: (num) => { 11 | // do nothing 12 | }, 13 | reportSuccess: (name) => { 14 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]success\.js/)); 15 | }, 16 | reportFinish: (hasAnyError) => { 17 | assert(!hasAnyError); 18 | } 19 | }; 20 | const eater = new Eater({ 21 | reporter: mockReporter, 22 | dir: 'test/core', 23 | }); 24 | eater.files = ['./test/fixture/success.js']; 25 | 26 | eater.eat(); 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/core/lib/eater/onEaterFinish.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | const Eater = require(`${process.cwd()}/lib/eater`); 5 | const mockReporter = { 6 | setChildProc: (child) => { 7 | // do nothing 8 | }, 9 | reportFileNumber: () => { 10 | // do nothing 11 | }, 12 | reportTestName: (name) => { 13 | // do nothing 14 | }, 15 | reportSubTestName: (name, parent) => { 16 | // do nothing 17 | }, 18 | reportSubSuccess: (name) => { 19 | // do nothing 20 | }, 21 | reportFinish: (name) => { 22 | // do nothing 23 | }, 24 | reportSuccess: (name) => { 25 | // do nothing 26 | }, 27 | }; 28 | const eater = new Eater({ 29 | reporter: mockReporter, 30 | dir: 'test/fixture', 31 | ext: 'success.js', 32 | }); 33 | eater.eat(); 34 | 35 | process.on('eater:finish', mustCall((hasAnyError) => { 36 | assert(!hasAnyError); 37 | })); 38 | 39 | -------------------------------------------------------------------------------- /test/core/lib/eater/procs.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | const Eater = require(`${process.cwd()}/lib/eater`); 3 | const mockReporter = { 4 | setChildProc: (child) => { 5 | // do nothing 6 | }, 7 | reportSuccess: (name) => { 8 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]success\.js/)); 9 | }, 10 | reportFinish: (hasAnyError) => { 11 | assert(!hasAnyError); 12 | }, 13 | }; 14 | const eater = new Eater({ 15 | reporter: mockReporter, 16 | dir: 'test/core', 17 | ext: '.nosuchfiles', 18 | procs: 10 19 | }); 20 | 21 | assert(eater.procs === 10); 22 | 23 | -------------------------------------------------------------------------------- /test/core/lib/eater/receiveAllSuccessMessage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | const Eater = require(`${process.cwd()}/lib/eater`); 5 | 6 | const subtestNames = ['sync', 'async']; 7 | let subtests = 0; 8 | 9 | const mockReporter = { 10 | setChildProc: mustCall((child) => { 11 | // do nothing 12 | }), 13 | reportTestName: mustCall((name) => { 14 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]runnerAllSuccess\.js/)); 15 | }), 16 | reportSubTestName: mustCall((name, parent) => { 17 | assert(name === subtestNames[subtests]); 18 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]runnerAllSuccess\.js/)); 19 | }, 2), 20 | reportSubSuccess: mustCall((name) => { 21 | assert(name === subtestNames[subtests]); 22 | ++subtests; 23 | }, 2), 24 | reportSuccess: mustCall((name) => { 25 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]runnerAllSuccess\.js/)); 26 | }), 27 | }; 28 | const eater = new Eater({ 29 | reporter: mockReporter, 30 | dir: 'test/core', 31 | ext: '.nosuchfiles', 32 | }); 33 | eater.nextTest('./test/fixture/runnerAllSuccess.js'); 34 | -------------------------------------------------------------------------------- /test/core/lib/eater/receiveFailedMessage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | const Eater = require(`${process.cwd()}/lib/eater`); 5 | const mockReporter = { 6 | setChildProc: mustCall((child) => { 7 | // do nothing 8 | }), 9 | reportTestName: mustCall((name) => { 10 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]failedRunner\.js/)); 11 | }), 12 | reportSubTestName: mustCall((name, parent) => { 13 | assert(name === 'assert falsy'); 14 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]failedRunner\.js/)); 15 | }), 16 | reportSubFailure: mustCall((name, parent) => { 17 | assert(name === 'assert falsy'); 18 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]failedRunner\.js/)); 19 | }), 20 | reportFailure: mustCall((name) => { 21 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]failedRunner\.js/)); 22 | }), 23 | }; 24 | const eater = new Eater({ 25 | reporter: mockReporter, 26 | dir: 'test/core', 27 | ext: '.nosuchfiles', 28 | }); 29 | eater.nextTest('./test/fixture/failedRunner.js'); 30 | 31 | -------------------------------------------------------------------------------- /test/core/lib/eater/receiveLegacyDoneMessage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | const Eater = require(`${process.cwd()}/lib/eater`); 5 | const mockReporter = { 6 | setChildProc: mustCall((child) => { 7 | // do nothing 8 | }), 9 | reportTestName: mustCall((name) => { 10 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]legacyDoneRunner\.js/)); 11 | }), 12 | reportSubTestName: mustCall((name, parent) => { 13 | assert(name === 'explicitly success'); 14 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]legacyDoneRunner\.js/)); 15 | }), 16 | reportSubSuccess: mustCall((name, parent) => { 17 | assert(name === 'explicitly success'); 18 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]legacyDoneRunner\.js/)); 19 | }), 20 | reportSuccess: mustCall((name) => { 21 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]legacyDoneRunner\.js/)); 22 | }), 23 | }; 24 | const eater = new Eater({ 25 | reporter: mockReporter, 26 | dir: 'test/core', 27 | ext: '.nosuchfiles', 28 | }); 29 | eater.nextTest('./test/fixture/legacyDoneRunner.js'); 30 | -------------------------------------------------------------------------------- /test/core/lib/eater/receiveLegacyFailedMessage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | const Eater = require(`${process.cwd()}/lib/eater`); 5 | const mockReporter = { 6 | setChildProc: mustCall((child) => { 7 | // do nothing 8 | }), 9 | reportTestName: mustCall((name) => { 10 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]legacyFailedRunner\.js/)); 11 | }), 12 | reportSubTestName: mustCall((name, parent) => { 13 | assert(name === 'explicitly fail'); 14 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]legacyFailedRunner\.js/)); 15 | }), 16 | reportSubFailure: mustCall((name, parent, out, error) => { 17 | assert(name === 'explicitly fail'); 18 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]legacyFailedRunner\.js/)); 19 | assert(error.match(/Subtest failed message/)); 20 | }), 21 | reportFailure: mustCall((name) => { 22 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]legacyFailedRunner\.js/)); 23 | }), 24 | }; 25 | const eater = new Eater({ 26 | reporter: mockReporter, 27 | dir: 'test/core', 28 | ext: '.nosuchfiles', 29 | }); 30 | eater.nextTest('./test/fixture/legacyFailedRunner.js'); 31 | 32 | -------------------------------------------------------------------------------- /test/core/lib/eater/receiveMessage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | const Eater = require(`${process.cwd()}/lib/eater`); 5 | const mockReporter = { 6 | setChildProc: mustCall((child) => { 7 | // do nothing 8 | }), 9 | reportTestName: mustCall((name) => { 10 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]runner\.js/)); 11 | }), 12 | reportSubTestName: mustCall((name, parent) => { 13 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]runner\.js/)); 14 | assert(name === 'assert truthy'); 15 | }), 16 | reportSubSuccess: mustCall((name) => { 17 | assert(name === 'assert truthy'); 18 | }), 19 | reportSuccess: mustCall((name) => { 20 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]runner\.js/)); 21 | }), 22 | }; 23 | const eater = new Eater({ 24 | reporter: mockReporter, 25 | dir: 'test/core', 26 | ext: '.nosuchfiles', 27 | }); 28 | eater.nextTest('./test/fixture/runner.js'); 29 | -------------------------------------------------------------------------------- /test/core/lib/eater/receiveWithFailedMessage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | const Eater = require(`${process.cwd()}/lib/eater`); 5 | 6 | const subtestNames = ['sync', 'async']; 7 | let subtests = 0; 8 | 9 | const mockReporter = { 10 | setChildProc: mustCall((child) => { 11 | // do nothing 12 | }), 13 | reportTestName: mustCall((name) => { 14 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]runnerWithFailed\.js/)); 15 | }), 16 | reportSubTestName: mustCall((name, parent) => { 17 | assert(name === subtestNames[subtests]); 18 | assert(parent.match(/.[/\\]test[/\\]fixture[/\\]runnerWithFailed\.js/)); 19 | }, 2), 20 | reportSubFailure: mustCall((name) => { 21 | assert(name === 'sync'); 22 | ++subtests; 23 | }), 24 | reportSubSuccess: mustCall((name) => { 25 | assert(name === 'async'); 26 | ++subtests; 27 | }), 28 | reportFailure: mustCall((name, out, error) => { 29 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]runnerWithFailed\.js/)); 30 | assert(error.match(/1 Subtest\(s\) failed/)); 31 | }), 32 | }; 33 | const eater = new Eater({ 34 | reporter: mockReporter, 35 | dir: 'test/core', 36 | ext: '.nosuchfiles', 37 | }); 38 | eater.nextTest('./test/fixture/runnerWithFailed.js'); 39 | -------------------------------------------------------------------------------- /test/core/lib/eater/reportFailure.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | const Eater = require(`${process.cwd()}/lib/eater`); 3 | const mockReporter = { 4 | setChildProc: (child) => { 5 | // do nothing 6 | }, 7 | reportTestName: (name) => { 8 | // do nothing 9 | }, 10 | reportFailure: (name) => { 11 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]error\.js/)); 12 | }, 13 | reportFinish: (hasAnyError) => { 14 | assert(hasAnyError); 15 | } 16 | }; 17 | const eater = new Eater({ 18 | reporter: mockReporter, 19 | dir: 'test/core', 20 | ext: '.nosuchfiles', 21 | }); 22 | eater.nextTest('./test/fixture/error.js'); 23 | -------------------------------------------------------------------------------- /test/core/lib/eater/reportSuccess.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | const Eater = require(`${process.cwd()}/lib/eater`); 3 | const mockReporter = { 4 | setChildProc: (child) => { 5 | // do nothing 6 | }, 7 | reportTestName: (name) => { 8 | // do nothing 9 | }, 10 | reportSuccess: (name) => { 11 | assert(name.match(/.[/\\]test[/\\]fixture[/\\]success\.js/)); 12 | }, 13 | reportFinish: (hasAnyError) => { 14 | assert(!hasAnyError); 15 | }, 16 | }; 17 | const eater = new Eater({ 18 | reporter: mockReporter, 19 | dir: 'test/core', 20 | ext: '.nosuchfiles', 21 | }); 22 | eater.nextTest('./test/fixture/success.js'); 23 | 24 | -------------------------------------------------------------------------------- /test/core/lib/listupFiles.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | const listupFiles = require(`${process.cwd()}/lib/listupFiles`); 3 | 4 | const lists = listupFiles('./test/fixture', '.js'); 5 | assert(lists.length > 0); 6 | assert(lists.some((file) => file.match(/test[/\\]fixture[/\\]test[/\\]a\.js/))); 7 | assert(lists.some((file) => file.match(/test[/\\]fixture[/\\]test[/\\]aaa[/\\]bbb[/\\]ccc[/\\]b\.js/))); 8 | assert(lists.some((file) => file.match(/test[/\\]fixture[/\\]test[/\\]aaa[/\\]bbb[/\\]c\.js/))); 9 | assert(lists.some((file) => file.match(/test[/\\]fixture[/\\]test[/\\]aaa[/\\]bbb[/\\]c.test\.js/))); 10 | 11 | const listTestJsFiles = listupFiles('test/fixture', '.test.js'); 12 | assert(listTestJsFiles.length === 1); 13 | assert(listTestJsFiles.some((file) => file.match(/test[/\\]fixture[/\\]test[/\\]aaa[/\\]bbb[/\\]c\.test.js/))); 14 | 15 | const listPatternMatchFiles = listupFiles('', '', '**/__test__/**/*.js'); 16 | assert(listPatternMatchFiles.length === 1); 17 | assert(listPatternMatchFiles.some((file) => file.match(/test[/\\]fixture[/\\]__test__[/\\]b.js/))); 18 | 19 | const listOnlyFiles = listupFiles('./test/only', '.js'); 20 | assert(listOnlyFiles.length === 1); 21 | assert(listOnlyFiles.some((file) => file.match(/test[/\\]only[/\\]only\.js/))); 22 | 23 | assert.throws(() => { 24 | listupFiles('./test/fixture'); 25 | }, /extension should be string/ ); 26 | 27 | assert.throws(() => { 28 | listupFiles(null, '.js'); 29 | }, /dir should be string/ ); 30 | 31 | assert.throws(() => { 32 | listupFiles('', '', 'test/foo/bar'); 33 | }, /glob pattern should have magic glob chars/ ); 34 | -------------------------------------------------------------------------------- /test/core/lib/oridinalize.js: -------------------------------------------------------------------------------- 1 | const ordinalize = require(`${process.cwd()}/lib/ordinalize`); 2 | const assert = require('power-assert'); 3 | 4 | assert(ordinalize(1) === '1st'); 5 | assert(ordinalize('1') === '1st'); 6 | 7 | assert(ordinalize(2) === '2nd'); 8 | assert(ordinalize('2') === '2nd'); 9 | 10 | assert(ordinalize(3) === '3rd'); 11 | assert(ordinalize('3') === '3rd'); 12 | 13 | assert(ordinalize(4) === '4th'); 14 | assert(ordinalize('4') === '4th'); 15 | 16 | assert(ordinalize(11) === '11th'); 17 | 18 | assert(ordinalize(12) === '12th'); 19 | 20 | assert(ordinalize(13) === '13th'); 21 | 22 | assert(ordinalize(21) === '21st'); 23 | assert(ordinalize(102) === '102nd'); 24 | assert(ordinalize(1012) === '1012th'); 25 | -------------------------------------------------------------------------------- /test/core/lib/reporter/Reporter.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | const Reporter = require(`${process.cwd()}/lib/reporter/Reporter`); 3 | const reporter = new Reporter(); 4 | 5 | console.log = (message) => { 6 | assert(message.indexOf('Test File Num : 123') !== -1); 7 | }; 8 | 9 | reporter.reportFileNumber(123); 10 | 11 | console.log = (message) => { 12 | assert(message.indexOf('Testing... : foobarbuz') !== -1); 13 | }; 14 | 15 | reporter.reportTestName('foobarbuz'); 16 | 17 | 18 | console.log = (message) => { 19 | assert(message.indexOf('Test Name : foobarbuz in parent') !== -1); 20 | }; 21 | 22 | reporter.reportSubTestName('foobarbuz', 'parent'); 23 | 24 | console.log = (message) => { 25 | assert(message.indexOf('Test Name : foobarbuz in parent 2nd') !== -1); 26 | }; 27 | 28 | reporter.reportSubTestName('foobarbuz', 'parent'); 29 | 30 | console.log = (message) => { 31 | assert(message.indexOf('failure') !== -1); 32 | assert(message.indexOf('foobarbuz') !== -1); 33 | }; 34 | 35 | reporter.reportFailure('foobarbuz'); 36 | 37 | console.log = (message) => { 38 | assert(message.indexOf('no-such-failure-test') !== -1); 39 | assert(message.indexOf('failure') !== -1); 40 | }; 41 | 42 | reporter.reportFailure('no-such-failure-test'); 43 | 44 | console.log = (message) => { 45 | assert(message.indexOf('failure') !== -1); 46 | assert(message.indexOf('foobarbuz') !== -1); 47 | assert(message.indexOf('out') !== -1); 48 | assert(message.indexOf('error') !== -1); 49 | }; 50 | 51 | reporter.reportFailure('foobarbuz', 'out', 'error'); 52 | 53 | console.log = (message) => { 54 | assert(message.indexOf('success') !== -1); 55 | assert(message.indexOf('hogefuga') !== -1); 56 | }; 57 | 58 | reporter.reportSuccess('hogefuga'); 59 | 60 | console.log = (message) => { 61 | assert(message.indexOf('failure') !== -1); 62 | assert(message.indexOf('foobarbuz') !== -1); 63 | assert(message.indexOf('parent') !== -1); 64 | assert(message.indexOf('out') !== -1); 65 | assert(message.indexOf('error') !== -1); 66 | }; 67 | 68 | reporter.reportSubFailure('foobarbuz', 'parent', 'out', 'error'); 69 | 70 | console.log = (message) => { 71 | assert(message.indexOf('failure') !== -1); 72 | assert(message.indexOf('foobarbuz') !== -1); 73 | assert(message.indexOf('parent') !== -1); 74 | }; 75 | 76 | reporter.reportSubFailure('foobarbuz', 'parent'); 77 | 78 | console.log = (message) => { 79 | assert(message.indexOf('failure') !== -1); 80 | assert(message.indexOf('foobarbuz2') !== -1); 81 | assert(message.indexOf('parent') !== -1); 82 | }; 83 | 84 | reporter.reportSubFailure('foobarbuz2', 'parent'); 85 | 86 | console.log = (message) => { 87 | assert(message.indexOf('success') !== -1); 88 | assert(message.indexOf('hogefuga') !== -1); 89 | }; 90 | 91 | reporter.reportSubSuccess('hogefuga'); 92 | 93 | const child = { 94 | stdout: { 95 | pipe: (obj) => { 96 | assert.deepEqual(obj, process.stdout); 97 | } 98 | }, 99 | stderr: { 100 | pipe: (obj) => { 101 | assert.deepEqual(obj, process.stderr); 102 | } 103 | }, 104 | }; 105 | reporter.setChildProc(child); 106 | 107 | console.log = (message) => { 108 | assert(message.indexOf('Total duration time:') !== -1); 109 | }; 110 | reporter.reportFinish(false, []); 111 | -------------------------------------------------------------------------------- /test/core/lib/runner.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | const originalProcessSend = process.send; 5 | const originalConsoleError = console.error; 6 | console.error = () => {}; 7 | 8 | process.send = mustCall((obj) => { 9 | assert(obj.type === 'testname'); 10 | assert(obj.testName === 'useCase truthy'); 11 | }); 12 | 13 | test('useCase truthy', (resolve, reject) => { 14 | assert(true); 15 | resolve(); 16 | }); 17 | 18 | process.send = mustCall((obj) => { 19 | assert(obj.type === 'testname'); 20 | assert(obj.testName === 'useCase falsy'); 21 | }); 22 | 23 | test('useCase falsy', (resolve, reject) => { 24 | assert(1 === 2); 25 | resolve(); 26 | }); 27 | 28 | process.send = mustCall((obj) => { 29 | assert(obj.testName === 'throw error'); 30 | }); 31 | 32 | test('throw error', (resolve, reject) => { 33 | throw new Error('e'); 34 | }); 35 | 36 | process.send = mustCall((obj) => { 37 | assert(obj.testName === 'must call'); 38 | }); 39 | 40 | test('must call', (resolve, reject) => { 41 | Promise.resolve(100).then(mustCall((value) => { 42 | assert(value !== 100); 43 | })) 44 | }); 45 | 46 | process.send = mustCall((obj) => { 47 | assert(obj.testName === 'throw null'); 48 | }, 3); 49 | 50 | test('throw null', (resolve, reject) => { 51 | reject(null); 52 | }); 53 | -------------------------------------------------------------------------------- /test/core/lib/runner/asScript.js: -------------------------------------------------------------------------------- 1 | const cp = require('child_process'); 2 | const assert = require('power-assert'); 3 | 4 | const runner = cp.spawnSync("node", [`${process.cwd()}/test/fixture/runner.js`]); 5 | assert(runner.stdout.toString().match(/success: assert truthy/)); 6 | 7 | const failedRunner = cp.spawnSync("node", [`${process.cwd()}/test/fixture/failedRunner.js`]); 8 | assert(failedRunner.stdout.toString().match(/failure: assert falsy/)); 9 | assert(failedRunner.stderr.toString().match(/1 Subtest\(s\) failed/)); 10 | -------------------------------------------------------------------------------- /test/core/lib/runner/duplicateTestName.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const ordinalize = require(`${process.cwd()}/lib/ordinalize`); 3 | const assert = require('power-assert'); 4 | 5 | test('test', () => { 6 | assert(true); 7 | }); 8 | 9 | test('test', () => { 10 | assert(true); 11 | }); 12 | 13 | test('test', () => { 14 | assert(true); 15 | }); 16 | -------------------------------------------------------------------------------- /test/core/lib/runner/testFirst.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | 5 | process.env.EATER_SUBTEST = '0'; 6 | 7 | test('first', mustCall(() => { 8 | assert(true); 9 | })); 10 | 11 | test('second', () => { 12 | assert(false); 13 | }); 14 | -------------------------------------------------------------------------------- /test/core/lib/runner/testSecond.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | 5 | process.env.EATER_SUBTEST = '1'; 6 | 7 | test('first', () => { 8 | assert(false); 9 | }); 10 | 11 | test('second', mustCall(() => { 12 | assert(true); 13 | })); 14 | -------------------------------------------------------------------------------- /test/core/lib/runner/tester.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const assert = require('power-assert'); 3 | 4 | test('assert truthy', () => { 5 | assert(true); 6 | }); 7 | 8 | -------------------------------------------------------------------------------- /test/core/lib/runner/testseq.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | 5 | test('assert truthy', () => { 6 | console.log('assert truthy'); 7 | assert(true); 8 | }); 9 | 10 | 11 | test('assert truthy async', () => { 12 | setTimeout(mustCall(() => { 13 | console.log('assert truthy async'); 14 | assert(true); 15 | }), 200); 16 | }); 17 | 18 | 19 | test('assert truthy async2', () => { 20 | setTimeout(mustCall(() => { 21 | console.log('assert truthy async2'); 22 | assert(true); 23 | }), 100); 24 | }); 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/core/promises/testPromiseRejectionHandled.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | 3 | function testRejectPromise() { 4 | return Promise.reject(new Error('Error Promise')); 5 | } 6 | const promise = testRejectPromise(); 7 | setTimeout(() => {promise.catch(); }, 100); 8 | process.on('uncaughtException', (e) => { 9 | assert(e.message === 'Error Promise'); 10 | }); 11 | 12 | process.on('rejectionHandled', (p) => { 13 | p.catch((e) => { 14 | assert(e.message === 'Error Promise'); 15 | }); 16 | }); 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/core/promises/testPromiseUnhandledRejection.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | 3 | function testRejectPromise() { 4 | return new Promise((resolve, reject) => { 5 | setTimeout(() => { 6 | reject(new Error('test')); 7 | }, 100); 8 | }); 9 | } 10 | 11 | testRejectPromise().then(() => { 12 | assert('test'); 13 | }).catch((e) => { 14 | // failure!!!!! 15 | // call unhandledRejection 16 | assert(e.message !== 'test'); 17 | }); 18 | 19 | process.on('uncaughtException', (e) => { 20 | assert.ok(e); 21 | assert(e.stack.match(/test[/\\]core[/\\]promises[/\\]testPromiseUnhandledRejection.js/)); 22 | }); 23 | 24 | -------------------------------------------------------------------------------- /test/enable-babel.js: -------------------------------------------------------------------------------- 1 | require('@babel/register')({ 2 | }); 3 | 4 | -------------------------------------------------------------------------------- /test/enable-power-assert.js: -------------------------------------------------------------------------------- 1 | require('espower-loader')({ 2 | // directory where match starts with 3 | cwd: process.cwd(), 4 | // glob pattern using minimatch module 5 | pattern: 'test/core/**/*.js' 6 | }); 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/env/test_process_env.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const assert = require('power-assert'); 3 | const mustCall = require('must-call'); 4 | const ENV = 'test'; 5 | 6 | assert(process.env.NODE_ENV === ENV) 7 | 8 | test('assert process.env.NODE_ENV is test', () => { 9 | assert(process.env.NODE_ENV === ENV) 10 | }); 11 | 12 | -------------------------------------------------------------------------------- /test/fixture/__test__/b.js: -------------------------------------------------------------------------------- 1 | var b = 1; 2 | -------------------------------------------------------------------------------- /test/fixture/babel/assert.js: -------------------------------------------------------------------------------- 1 | const assert = require('power-assert'); 2 | 3 | require('./babel'); 4 | 5 | assert('pass' == 'pass'); 6 | 7 | -------------------------------------------------------------------------------- /test/fixture/babel/babel.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | 3 | console.log('load fs'); 4 | -------------------------------------------------------------------------------- /test/fixture/babel/failed.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import assert from 'assert'; 3 | 4 | console.log('load fs'); 5 | assert('passs' == 'pass'); 6 | -------------------------------------------------------------------------------- /test/fixture/error.js: -------------------------------------------------------------------------------- 1 | console.error('Error!!!!!'); 2 | 3 | -------------------------------------------------------------------------------- /test/fixture/failedRunner.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const assert = require('power-assert'); 3 | 4 | test('assert falsy', () => { 5 | assert(false); 6 | }); 7 | -------------------------------------------------------------------------------- /test/fixture/legacyDoneRunner.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const assert = require('power-assert'); 3 | 4 | test('explicitly success', (done) => { 5 | done(); 6 | assert(false); // not affect 7 | }); 8 | 9 | -------------------------------------------------------------------------------- /test/fixture/legacyFailedRunner.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const assert = require('power-assert'); 3 | 4 | test('explicitly fail', (done, fail) => { 5 | fail(); 6 | }); 7 | -------------------------------------------------------------------------------- /test/fixture/runner.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const assert = require('power-assert'); 3 | 4 | test('assert truthy', () => { 5 | assert(true); 6 | }); 7 | 8 | -------------------------------------------------------------------------------- /test/fixture/runnerAllSuccess.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const mustCall = require('must-call'); 3 | const assert = require('power-assert'); 4 | 5 | test('sync', () => { 6 | assert(true); 7 | }); 8 | 9 | test('async', () =>{ 10 | setImmediate(mustCall(() => { 11 | assert(true); 12 | })); 13 | }); 14 | -------------------------------------------------------------------------------- /test/fixture/runnerWithFailed.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const mustCall = require('must-call'); 3 | const assert = require('power-assert'); 4 | 5 | test('sync', () => { 6 | assert(false); 7 | }); 8 | 9 | test('async', () =>{ 10 | setImmediate(mustCall(() => { 11 | assert(true); 12 | })); 13 | }); 14 | -------------------------------------------------------------------------------- /test/fixture/success.js: -------------------------------------------------------------------------------- 1 | console.log('success!!'); 2 | -------------------------------------------------------------------------------- /test/fixture/test/a.js: -------------------------------------------------------------------------------- 1 | console.log('hogehoge'); 2 | -------------------------------------------------------------------------------- /test/fixture/test/aaa/bbb/c.js: -------------------------------------------------------------------------------- 1 | console.log('boo'); 2 | -------------------------------------------------------------------------------- /test/fixture/test/aaa/bbb/c.test.js: -------------------------------------------------------------------------------- 1 | console.log('hogehoge'); 2 | -------------------------------------------------------------------------------- /test/fixture/test/aaa/bbb/ccc/b.js: -------------------------------------------------------------------------------- 1 | console.log('hogehoge'); 2 | -------------------------------------------------------------------------------- /test/only/only.js: -------------------------------------------------------------------------------- 1 | // __eater:only__ 2 | const only = require(`${process.cwd()}/lib/runner`).only; 3 | const test = require(`${process.cwd()}/lib/runner`).test; 4 | const mustCall = require('must-call'); 5 | const assert = require('power-assert'); 6 | 7 | only('only is executed', () => { 8 | assert(true); 9 | }); 10 | 11 | test('this test should not execute', (_, fail) =>{ 12 | fail('should not be executed'); 13 | }); 14 | -------------------------------------------------------------------------------- /test/only/test.js: -------------------------------------------------------------------------------- 1 | const test = require(`${process.cwd()}/lib/runner`).test; 2 | const assert = require('power-assert'); 3 | 4 | test('assert falsy', () => { 5 | assert(false); 6 | }); 7 | -------------------------------------------------------------------------------- /test/reporter/DotReporter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const Reporter = require('../../').Reporter; 3 | 4 | class DotReporter extends Reporter { 5 | reportFileNumber(num) { 6 | } 7 | reportTestName(name) { 8 | } 9 | setChildProc(child) { 10 | child.stdout.on('data', () => {process.stdout.emit('data', '')}); 11 | child.stderr.on('data', () => {process.stderr.emit('data', '')}); 12 | } 13 | reportFailure(name) { 14 | console.log('F'); 15 | } 16 | reportSuccess(name) { 17 | console.log('.'); 18 | } 19 | reportFinish(hasAnyError, errors) { 20 | } 21 | } 22 | 23 | module.exports = DotReporter; 24 | -------------------------------------------------------------------------------- /test/reporter/EsModuleReporter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const Reporter = require('../../').Reporter; 3 | 4 | class EsModuleReporter extends Reporter { 5 | reportFileNumber(num) { 6 | } 7 | reportTestName(name) { 8 | } 9 | setChildProc(child) { 10 | child.stdout.on('data', () => {process.stdout.emit('data', '')}); 11 | child.stderr.on('data', () => {process.stderr.emit('data', '')}); 12 | } 13 | reportFailure(name) { 14 | console.log('x'); 15 | } 16 | reportSuccess(name) { 17 | console.log('o'); 18 | } 19 | reportFinish(hasAnyError, errors) { 20 | } 21 | } 22 | 23 | Object.defineProperty(module.exports, "__esModule", { value: true }); 24 | module.exports.default = EsModuleReporter; 25 | -------------------------------------------------------------------------------- /test/runner/context.js: -------------------------------------------------------------------------------- 1 | const colo = require('colo'); 2 | 3 | global.done = () => { }; 4 | 5 | global.describe = (message, func) => { 6 | console.log(colo.grey(message)); 7 | func(global.done); 8 | }; 9 | 10 | global.beforeEach = (func) => { 11 | global.beforeEachFunc = func; 12 | }; 13 | 14 | global.afterEach = (func) => { 15 | global.afterEachFunc = func; 16 | }; 17 | 18 | global.it = (message, func) => { 19 | console.log(' ' + colo.grey(message)); 20 | global.beforeEachFunc && global.beforeEachFunc(global.done); 21 | func(global.done); 22 | global.afterEachFunc && global.afterEachFunc(global.done); 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /test/runner/tdd.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const assert = require('power-assert'); 3 | 4 | describe('hogehoge', () => { 5 | beforeEach(() => { 6 | console.log('beforeEach'); 7 | }); 8 | afterEach(() => { 9 | console.log('afterEach'); 10 | }); 11 | it('should be true', () => { 12 | assert(true); 13 | }); 14 | it('should be async', (done) => { 15 | setTimeout(() => { 16 | console.log('async!'); 17 | assert(true); 18 | done(); 19 | }, 1000); 20 | }); 21 | it('should be async2', (done) => { 22 | setTimeout(() => { 23 | console.log('async2!'); 24 | assert(true); 25 | done(); 26 | }, 1000); 27 | }); 28 | it('should be sync', () => { 29 | setTimeout(() => { 30 | console.log('sync!'); 31 | assert(true); 32 | }, 1000); 33 | assert(true); 34 | }); 35 | }); 36 | --------------------------------------------------------------------------------