Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement --no-only flag functionality #572

Merged
merged 1 commit into from
Jan 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@
"no-magic-numbers": "off",
"max-lines": "warn",
"max-lines-per-function": "warn",
"max-statements": "warn",
"max-statements-per-line": [2, { "max": 2 }],
"max-statements": "warn",
"multiline-comment-style": "off",
"no-negated-condition": "off",
"no-use-before-define": "warn",
"no-underscore-dangle": "warn",
"no-use-before-define": "warn",
"object-curly-newline": "off",
"sort-keys": "warn",
},
"ignorePatterns": ["syntax-error.*"],
Expand Down
7 changes: 6 additions & 1 deletion bin/tape
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ var objectKeys = require('object-keys');
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') {
Expand Down
4 changes: 3 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ module.exports = (function () {
function createExitHarness(conf, wait) {
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 running = false;
var ended = false;
Expand Down Expand Up @@ -163,6 +164,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);
Expand Down
37 changes: 37 additions & 0 deletions readme.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,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.
jocrah marked this conversation as resolved.
Show resolved Hide resolved

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.
jocrah marked this conversation as resolved.
Show resolved Hide resolved

```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).
Expand Down Expand Up @@ -362,6 +397,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`.
Expand Down
110 changes: 110 additions & 0 deletions test/no_only.js
Original file line number Diff line number Diff line change
@@ -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
});
});
8 changes: 8 additions & 0 deletions test/no_only/test-a.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict';

var tape = require('../../');

tape.test('should pass', function (t) {
t.plan(1);
t.ok(1);
});
14 changes: 14 additions & 0 deletions test/no_only/test-b.js
Original file line number Diff line number Diff line change
@@ -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);
});