diff --git a/.eslintrc b/.eslintrc index 365f8bc0..97c0a033 100644 --- a/.eslintrc +++ b/.eslintrc @@ -14,15 +14,16 @@ "complexity": "off", "func-style": "warn", "indent": ["error", 4], - "max-lines": "warn", "max-lines-per-function": "warn", - "max-statements": "warn", + "max-lines": "warn", "max-statements-per-line": [2, { "max": 2 }], + "max-statements": "warn", "multiline-comment-style": "off", - "no-param-reassign": "warn", "no-negated-condition": "off", - "no-use-before-define": "warn", + "no-param-reassign": "warn", "no-underscore-dangle": "warn", + "no-use-before-define": "warn", + "object-curly-newline": "off", "operator-linebreak": ["error", "before"], "sort-keys": "warn", }, diff --git a/bin/tape b/bin/tape index fbd58152..84f0f0ec 100755 --- a/bin/tape +++ b/bin/tape @@ -7,9 +7,14 @@ var parseOpts = require('minimist'); var opts = parseOpts(process.argv.slice(2), { alias: { r: 'require', i: 'ignore' }, string: ['require', 'ignore'], - default: { r: [], i: null } + boolean: ['only'], + default: { r: [], i: null, only: null } }); +if (typeof opts.only === 'boolean') { + process.env.NODE_TAPE_NO_ONLY_TEST = !opts.only; +} + var cwd = process.cwd(); if (typeof opts.require === 'string') { diff --git a/index.js b/index.js index 7e402af3..6d32e99b 100644 --- a/index.js +++ b/index.js @@ -55,7 +55,8 @@ module.exports = (function () { function createExitHarness(conf) { var config = conf || {}; var harness = createHarness({ - autoclose: defined(config.autoclose, false) + autoclose: defined(config.autoclose, false), + noOnly: defined(conf.noOnly, defined(process.env.NODE_TAPE_NO_ONLY_TEST, false)) }); var stream = harness.createStream({ objectMode: conf.objectMode }); @@ -139,6 +140,7 @@ function createHarness(conf_) { var only = false; test.only = function () { if (only) { throw new Error('there can only be one only test'); } + if (conf_.noOnly) { throw new Error('`only` tests are prohibited'); } only = true; var t = test.apply(null, arguments); results.only(t); diff --git a/readme.markdown b/readme.markdown index c322bb50..03fe7e14 100644 --- a/readme.markdown +++ b/readme.markdown @@ -139,6 +139,41 @@ By default, uncaught exceptions in your tests will not be intercepted, and will - In-process reporting with https://github.com/DavidAnson/tape-player - Describe blocks with https://github.com/mattriley/tape-describe +# command-line flags + +While running tests, top-level configurations can be passed via the command line to specify desired behavior. + +Available configurations are listed below: + +## --require + +**Alias**: `-r` + +This is used to load modules before running tests and is explained extensively in the [preloading modules](#preloading-modules) section. + +## --ignore + +**Alias**: `-i` + +This flag is used when tests from certain folders and/or files are not intended to be run. It defaults to `.gitignore` file when passed with no argument. + +```sh +tape -i .ignore **/*.js +``` + +An error is thrown if the specified file passed as argument does not exist. + +## --no-only +This is particularly useful in a CI environment where an [only test](#testonlyname-opts-cb) is not supposed to go unnoticed. + +By passing the `--no-only` flag, any existing [only test](#testonlyname-opts-cb) causes tests to fail. + +```sh +tape --no-only **/*.js +``` + +Alternatively, the environment variable `NODE_TAPE_NO_ONLY_TEST` can be set to `true` to achieve the same behavior; the command-line flag takes precedence. + # methods The assertion methods in `tape` are heavily influenced or copied from the methods in [node-tap](https://github.com/isaacs/node-tap). @@ -347,6 +382,8 @@ By default the TAP output goes to `console.log()`. You can pipe the output to so Like `test([name], [opts], cb)` except if you use `.only` this is the only test case that will run for the entire process, all other test cases using `tape` will be ignored. +Check out how the usage of [the --no-only flag](#--no-only) could help ensure there is no `.only` test running in a specified environment. + ## var stream = test.createStream(opts) Create a stream of output, bypassing the default output stream that writes messages to `console.log()`. By default `stream` will be a text stream of TAP output, but you can get an object stream instead by setting `opts.objectMode` to `true`. diff --git a/test/no_only.js b/test/no_only.js new file mode 100644 index 00000000..693ab110 --- /dev/null +++ b/test/no_only.js @@ -0,0 +1,110 @@ +'use strict'; + +var tap = require('tap'); +var path = require('path'); +var exec = require('child_process').exec; + +var stripFullStack = require('./common').stripFullStack; + +var tapeBin = path.join(__dirname, '../bin/tape'); + +var expectedExitCodeFailure = (/^0\.10\.\d+$/).test(process.versions.node); +var expectedStackTraceBug = (/^3\.[012]\.\d+$/).test(process.versions.node); // https://github.com/nodejs/node/issues/2581 + +tap.test( + 'Should throw error when --no-only is passed via cli and there is a .only test', + { todo: expectedExitCodeFailure || expectedStackTraceBug ? 'Fails on these node versions' : false }, + function (tt) { + tt.plan(3); + + exec(tapeBin + ' --no-only "**/*.js"', { + cwd: path.join(__dirname, 'no_only') + }, function (err, stdout, stderr) { + tt.same(stdout.toString('utf8'), ''); + tt.match(stripFullStack(stderr.toString('utf8')).join('\n'), /Error: `only` tests are prohibited\n/); + tt.equal(err.code, 1); + }); + } +); + +tap.test( + 'Should throw error when NODE_TAPE_NO_ONLY_TEST is passed via envs and there is an .only test', + { todo: expectedExitCodeFailure || expectedStackTraceBug ? 'Fails on these node versions' : false }, + function (tt) { + tt.plan(3); + + exec(tapeBin + ' "**/*.js"', { + cwd: path.join(__dirname, 'no_only'), + env: { PATH: process.env.PATH, NODE_TAPE_NO_ONLY_TEST: 'true' } + }, function (err, stdout, stderr) { + tt.same(stdout.toString('utf8'), ''); + tt.match(stripFullStack(stderr.toString('utf8')).join('\n'), /Error: `only` tests are prohibited\n/); + tt.equal(err.code, 1); + }); + } +); + +tap.test( + 'Should override NODE_TAPE_NO_ONLY_TEST env if --no-only is passed from cli', + { todo: expectedExitCodeFailure || expectedStackTraceBug ? 'Fails on these node versions' : false }, + function (tt) { + tt.plan(3); + + exec(tapeBin + ' --no-only "**/*.js"', { + cwd: path.join(__dirname, 'no_only'), + env: { PATH: process.env.PATH, NODE_TAPE_NO_ONLY_TEST: 'false' } + }, function (err, stdout, stderr) { + tt.same(stdout.toString('utf8'), ''); + tt.match(stripFullStack(stderr.toString('utf8')).join('\n'), /Error: `only` tests are prohibited\n/); + tt.equal(err.code, 1); + }); + } +); + +tap.test('Should run successfully if there is no only test', function (tt) { + tt.plan(3); + + exec(tapeBin + ' --no-only "**/test-a.js"', { + cwd: path.join(__dirname, 'no_only') + }, function (err, stdout, stderr) { + tt.match(stderr.toString('utf8'), /^\s*(\(node:\d+\) ExperimentalWarning: The ESM module loader is experimental\.)?\s*$/); + tt.same(stripFullStack(stdout.toString('utf8')), [ + 'TAP version 13', + '# should pass', + 'ok 1 should be truthy', + '', + '1..1', + '# tests 1', + '# pass 1', + '', + '# ok', + '', + '' + ]); + tt.equal(err, null); // code 0 + }); +}); + +tap.test('Should run successfully if there is an only test and no --no-only flag', function (tt) { + tt.plan(3); + + exec(tapeBin + ' "**/test-b.js"', { + cwd: path.join(__dirname, 'no_only') + }, function (err, stdout, stderr) { + tt.same(stripFullStack(stdout.toString('utf8')), [ + 'TAP version 13', + '# should pass again', + 'ok 1 should be truthy', + '', + '1..1', + '# tests 1', + '# pass 1', + '', + '# ok', + '', + '' + ]); + tt.match(stderr.toString('utf8'), /^\s*(\(node:\d+\) ExperimentalWarning: The ESM module loader is experimental\.)?\s*$/); + tt.equal(err, null); // code 0 + }); +}); diff --git a/test/no_only/test-a.js b/test/no_only/test-a.js new file mode 100644 index 00000000..41107d38 --- /dev/null +++ b/test/no_only/test-a.js @@ -0,0 +1,8 @@ +'use strict'; + +var tape = require('../../'); + +tape.test('should pass', function (t) { + t.plan(1); + t.ok(1); +}); diff --git a/test/no_only/test-b.js b/test/no_only/test-b.js new file mode 100644 index 00000000..c6f6eb6e --- /dev/null +++ b/test/no_only/test-b.js @@ -0,0 +1,14 @@ +'use strict'; + +var tape = require('../../'); + +tape.test('should pass', function (t) { + t.plan(1); + t.ok(1); +}); + +tape.test.only('should pass again', function (t) { + t.plan(1); + t.ok(1); +}); +