diff --git a/docs/api/QUnit/module.md b/docs/api/QUnit/module.md index 041659682..99eac0867 100644 --- a/docs/api/QUnit/module.md +++ b/docs/api/QUnit/module.md @@ -28,7 +28,12 @@ All tests inside a module will be grouped under that module. Tests can be added Modules can be nested inside other modules via a [module scope](#module-scope). In the output, tests are generally prefixed by the names of all parent modules. E.g. "Grandparent > Parent > Child > my test". -The `QUnit.module.only()`, `QUnit.module.skip()`, and `QUnit.module.todo()` methods are aliases for `QUnit.module()` that apply the behaviour of [`QUnit.test.only()`](./test.only.md), [`QUnit.test.skip()`](./test.skip.md) or [`QUnit.test.todo()`](./test.todo.md) to all a module's tests at once. +`QUnit.module.only( name, … )`
+`QUnit.module.todo( name, … )`
+`QUnit.module.skip( name, … )`
+`QUnit.module.if( name, condition, … )` + +These methods are aliases for `QUnit.module()` that apply the behaviour of [`QUnit.test.only()`](./test.only.md), [`QUnit.test.todo()`](./test.todo.md), [`QUnit.test.skip()`](./test.skip.md) or [`QUnit.test.if()`](./test.if.md) to all a module's tests at once. @@ -119,10 +124,11 @@ Example: [§ Hooks via module options](#hooks-via-module-options). ## Changelog -| [QUnit 2.4](https://github.com/qunitjs/qunit/releases/tag/2.4.0) | The `QUnit.module.only()`, `QUnit.module.skip()`, and `QUnit.module.todo()` aliases were introduced. -| [QUnit 2.0](https://github.com/qunitjs/qunit/releases/tag/2.0.0) | The `before` and `after` options were introduced. -| [QUnit 1.20](https://github.com/qunitjs/qunit/releases/tag/1.20.0) | The `scope` feature was introduced. -| [QUnit 1.16](https://github.com/qunitjs/qunit/releases/tag/1.16.0) | The `beforeEach` and `afterEach` options were introduced.
The `setup` and `teardown` options were deprecated in QUnit 1.16 and removed in QUnit 2.0. +| UNRELEASED | Added `QUnit.module.if()` alias. +| [QUnit 2.4](https://github.com/qunitjs/qunit/releases/tag/2.4.0) | Added `QUnit.module.only()`, `QUnit.module.skip()`, and `QUnit.module.todo()` aliases. +| [QUnit 2.0](https://github.com/qunitjs/qunit/releases/tag/2.0.0) | Added `before` and `after` options. +| [QUnit 1.20](https://github.com/qunitjs/qunit/releases/tag/1.20.0) | Introduce `scope` feature. +| [QUnit 1.16](https://github.com/qunitjs/qunit/releases/tag/1.16.0) | Added `beforeEach` and `afterEach` options.
The `setup` and `teardown` options were deprecated in QUnit 1.16 and removed in QUnit 2.0. ## Examples diff --git a/docs/api/QUnit/test.each.md b/docs/api/QUnit/test.each.md index 07821922b..e342cc057 100644 --- a/docs/api/QUnit/test.each.md +++ b/docs/api/QUnit/test.each.md @@ -11,8 +11,9 @@ version_added: "2.16.0" `QUnit.test.each( name, dataset, callback )`
`QUnit.test.only.each( name, dataset, callback )`
+`QUnit.test.todo.each( name, dataset, callback )`
`QUnit.test.skip.each( name, dataset, callback )`
-`QUnit.test.todo.each( name, dataset, callback )` +`QUnit.test.if.each( name, condition, dataset, callback )` Add tests using a data provider. @@ -35,7 +36,7 @@ Use this method to add multiple tests that are similar, but with different data Each test case is passed one value of your dataset. -The [`only`](./test.only.md), [`skip`](./test.skip.md), and [`todo`](./test.todo.md) variants are also available, as `QUnit.test.only.each`, `QUnit.test.skip.each`, and `QUnit.test.todo.each` respectively. +The [`only`](./test.only.md), [`todo`](./test.todo.md), [`skip`](./test.skip.md), and [`if`](./test.if.md) variants are also available, as `QUnit.test.only.each`, `QUnit.test.todo.each`, `QUnit.test.skip.each`, and `QUnit.test.if.each` respectively. ## Examples diff --git a/docs/api/QUnit/test.if.md b/docs/api/QUnit/test.if.md new file mode 100644 index 000000000..42cad5ce5 --- /dev/null +++ b/docs/api/QUnit/test.if.md @@ -0,0 +1,45 @@ +--- +layout: page-api +title: QUnit.test.if() +excerpt: Add a test that may be skipped. +groups: + - main +redirect_from: + - "/QUnit/test.if/" +version_added: "unreleased" +--- + +`QUnit.test.if( name, condition, callback )` + +Add a test that only runs if a condition is true. + +| parameter | description | +|-----------|-------------| +| `name` (string) | Title of unit being tested | +| `condition` (string) | Expression to decide if the test should be run | +| `callback` (function) | Function that performs the test | + +If the condition is true, this is equivalent to calling [`QUnit.test()`](./test.md). + +If the conditional is false, this is equivalent to calling [`QUnit.test.skip()`](./test.skip.md), and test will not run. Instead, it will be listed in the results as a "skipped" test. + +As a codebase becomes bigger, you may need to conditionally skip an entire group of tests. You can use [`QUnit.module.if()`](./module.md) to recursively skip all tests in a module based on a given condition. + +## Examples + +```js +QUnit.module('MyApp'); + +// Skip if executed without a DOM +QUnit.test.if('render', typeof document !== 'undefined', function (assert) { + assert.strictEqual(MyApp.render(), '

Hello world!

'); +}); +``` + +```js +QUnit.module.if('MyApp', typeof document !== 'undefined'); + +QUnit.test('render', function (assert) { + assert.strictEqual(MyApp.render(), '

Hello world!

'); +}); +``` diff --git a/docs/api/QUnit/test.skip.md b/docs/api/QUnit/test.skip.md index 61da001ab..a6ef9a1cc 100644 --- a/docs/api/QUnit/test.skip.md +++ b/docs/api/QUnit/test.skip.md @@ -27,6 +27,10 @@ This test will be listed in the results as a "skipped" test. The callback and th As a codebase becomes bigger, you may sometimes want to temporarily disable an entire group of tests at once. You can use [`QUnit.module.skip()`](./module.md) to recursively skip all tests in the same module. +## See also + +* [`QUnit.test.if( name, condition, callback )`](./test.if.md) + ## Changelog | [QUnit 2.12](https://github.com/qunitjs/qunit/releases/tag/2.12.0) | The `QUnit.skip()` method was renamed to `QUnit.test.skip()`.
Use of `QUnit.skip()` remains supported as an alias. diff --git a/src/module.js b/src/module.js index d197e5f01..e0fc1a22c 100644 --- a/src/module.js +++ b/src/module.js @@ -171,6 +171,14 @@ module.skip = function (name, options, scope) { processModule(name, options, scope, { skip: true }); }; +module.if = function (name, condition, options, scope) { + if (focused) { + return; + } + + processModule(name, options, scope, { skip: !condition }); +}; + module.todo = function (name, options, scope) { if (focused) { return; diff --git a/src/test.js b/src/test.js index dce4743e9..1ac006f1a 100644 --- a/src/test.js +++ b/src/test.js @@ -105,7 +105,7 @@ export default function Test (settings) { }); if (this.skip) { - // Skipped tests will fully ignore any sent callback + // Skipped tests will fully ignore (and dereference for garbage collect) any sent callback this.callback = function () {}; this.async = false; this.expected = 0; @@ -970,6 +970,9 @@ extend(test, { skip: function (testName) { addTest({ testName, skip: true }); }, + if: function (testName, condition, callback) { + addTest({ testName, callback, skip: !condition }); + }, only: function (testName, callback) { addOnlyTest({ testName, callback }); }, @@ -1007,7 +1010,18 @@ test.skip.each = function (testName, dataset) { }); }); }; - +test.if.each = function (testName, condition, dataset, callback) { + runEach(dataset, (data, testKey) => { + addTest({ + testName: makeEachTestName(testName, testKey), + callback, + withData: true, + stackOffset: 5, + skip: !condition, + data: condition ? data : undefined + }); + }); +}; test.only.each = function (testName, dataset, callback) { runEach(dataset, (data, testKey) => { addOnlyTest({ diff --git a/test/cli/fixtures/test-if.js b/test/cli/fixtures/test-if.js new file mode 100644 index 000000000..dad46a95a --- /dev/null +++ b/test/cli/fixtures/test-if.js @@ -0,0 +1,37 @@ +QUnit.test.if('skip me', false, function (assert) { + assert.true(false); +}); + +QUnit.test.if('keep me', true, function (assert) { + assert.true(true); +}); + +QUnit.test('regular', function (assert) { + assert.true(true); +}); + +QUnit.test.if.each('skip dataset', false, ['a', 'b'], function (assert, _data) { + assert.true(false); +}); + +QUnit.test.if.each('keep dataset', true, ['a', 'b'], function (assert, data) { + assert.true(true); + assert.equal(typeof data, 'string'); +}); + +QUnit.module.if('skip group', false, function () { + QUnit.test('skipper', function (assert) { + assert.true(false); + }); +}); + +QUnit.module.if('keep group', true, function (hooks) { + let list = []; + hooks.beforeEach(function () { + list.push('x'); + }); + QUnit.test('keeper', function (assert) { + assert.true(true); + assert.deepEqual(list, ['x']); + }); +}); diff --git a/test/cli/fixtures/test-if.tap.txt b/test/cli/fixtures/test-if.tap.txt new file mode 100644 index 000000000..fc4ead929 --- /dev/null +++ b/test/cli/fixtures/test-if.tap.txt @@ -0,0 +1,18 @@ +# name: no tests +# command: ["qunit", "test-if.js"] + +TAP version 13 +ok 1 # SKIP skip me +ok 2 keep me +ok 3 regular +ok 4 # SKIP skip dataset [0] +ok 5 # SKIP skip dataset [1] +ok 6 keep dataset [0] +ok 7 keep dataset [1] +ok 8 # SKIP skip group > skipper +ok 9 keep group > keeper +1..9 +# pass 5 +# skip 4 +# todo 0 +# fail 0 diff --git a/test/main/deepEqual.js b/test/main/deepEqual.js index 8b14a6385..5cf50451d 100644 --- a/test/main/deepEqual.js +++ b/test/main/deepEqual.js @@ -1825,7 +1825,7 @@ var hasES6Map = (function () { } }()); -QUnit[hasES6Set ? 'test' : 'skip']('Sets', function (assert) { +QUnit.test.if('Sets', hasES6Set, function (assert) { var s1, s2, s3, s4, o1, o2, o3, o4, m1, m2, m3; // Empty sets @@ -1898,7 +1898,7 @@ QUnit[hasES6Set ? 'test' : 'skip']('Sets', function (assert) { assert.equal(QUnit.equiv(s1, s2), true, 'Sets with different insertion orders'); }); -QUnit[hasES6Map ? 'test' : 'skip']('Maps', function (assert) { +QUnit.test.if('Maps', hasES6Map, function (assert) { var m1, m2, m3, m4, o1, o2, o3, o4, s1, s2, s3; // Empty maps @@ -2016,7 +2016,7 @@ var hasES6Symbol = (function () { return typeof Symbol === 'function'; }()); -QUnit[hasES6Symbol ? 'test' : 'skip']('Symbols', function (assert) { +QUnit.test.if('Symbols', hasES6Symbol, function (assert) { var a = Symbol(1); var b = Symbol(1); diff --git a/test/main/stacktrace.js b/test/main/stacktrace.js index 6767f29b7..b3b779cd9 100644 --- a/test/main/stacktrace.js +++ b/test/main/stacktrace.js @@ -1,5 +1,5 @@ // Skip in environments without Error#stack support -(QUnit.stack() ? QUnit.module : QUnit.module.skip)('stacktrace', function () { +QUnit.module.if('stacktrace', !!QUnit.stack(), function () { function fooCurrent () { return QUnit.stack(); } @@ -65,7 +65,7 @@ // We do that for failed assertions, but for passing tests we omit // source details in these older browsers. var supportsUnthrownStack = !!(new Error().stack); - (supportsUnthrownStack ? QUnit.module : QUnit.module.skip)('source details', function () { + QUnit.module.if('source details', supportsUnthrownStack, function () { QUnit.test('QUnit.test()', function (assert) { var stack = norm(QUnit.config.current.stack); var line = stack.split('\n')[0]; diff --git a/test/main/test.js b/test/main/test.js index 257e33788..e752378a6 100644 --- a/test/main/test.js +++ b/test/main/test.js @@ -8,7 +8,7 @@ QUnit.module('test', function () { assert.true(true); }); - (typeof document !== 'undefined' ? QUnit.module : QUnit.module.skip)('fixture management', function (hooks) { + QUnit.module.if('fixture management', typeof document !== 'undefined', function (hooks) { /* global document */ var failure = false; var values = [ diff --git a/test/reorderError1.js b/test/reorderError1.js index f9020d282..8d7e51e58 100644 --- a/test/reorderError1.js +++ b/test/reorderError1.js @@ -1,7 +1,8 @@ /* eslint-env browser */ QUnit.module('Test call count - first case'); -QUnit[window.sessionStorage ? 'test' : 'skip']( +QUnit.test.if( 'does not skip tests after reordering', + !!window.sessionStorage, function (assert) { assert.equal(window.totalCount, 3); } diff --git a/test/reorderError2.js b/test/reorderError2.js index d56a85c0c..953a6e6c6 100644 --- a/test/reorderError2.js +++ b/test/reorderError2.js @@ -1,7 +1,8 @@ /* eslint-env browser */ QUnit.module('Test call count - second case'); -QUnit[window.sessionStorage ? 'test' : 'skip']( +QUnit.test.if( 'does not skip tests after reordering', + !!window.sessionStorage, function (assert) { assert.equal(window.totalCount, 2); }