diff --git a/test/cli/cli-main.js b/test/cli/cli-main.js index 54e593633..66ac1407d 100644 --- a/test/cli/cli-main.js +++ b/test/cli/cli-main.js @@ -54,176 +54,6 @@ ok 3 config # exit code: 1`); }); - QUnit.test('callbacks', async assert => { - const expected = `CALLBACK: begin1 -CALLBACK: begin2 -CALLBACK: moduleStart1 -CALLBACK: moduleStart2 -CALLBACK: testStart1 -CALLBACK: testStart2 -CALLBACK: module1 > before -CALLBACK: module1 > beforeEach -TEST: module1 > test1 -CALLBACK: log1 -CALLBACK: log2 -CALLBACK: module1 > afterEach -CALLBACK: testDone1 -CALLBACK: testDone2 -CALLBACK: moduleStart1 -CALLBACK: moduleStart2 -CALLBACK: testStart1 -CALLBACK: testStart2 -CALLBACK: module2 > before -CALLBACK: module1 > beforeEach -CALLBACK: module2 > beforeEach -TEST: module2 > test1 -CALLBACK: log1 -CALLBACK: log2 -CALLBACK: module2 > afterEach -CALLBACK: module1 > afterEach -CALLBACK: module2 > after -CALLBACK: testDone1 -CALLBACK: testDone2 -CALLBACK: moduleDone1 -CALLBACK: moduleDone2 -CALLBACK: moduleStart1 -CALLBACK: moduleStart2 -CALLBACK: testStart1 -CALLBACK: testStart2 -CALLBACK: module3 > before -CALLBACK: module1 > beforeEach -CALLBACK: module3 > beforeEach -TEST: module3 > test1 -CALLBACK: log1 -CALLBACK: log2 -CALLBACK: module3 > afterEach -CALLBACK: module1 > afterEach -CALLBACK: module3 > after -CALLBACK: testDone1 -CALLBACK: testDone2 -CALLBACK: moduleDone1 -CALLBACK: moduleDone2 -CALLBACK: testStart1 -CALLBACK: testStart2 -CALLBACK: module1 > beforeEach -TEST: module1 > test2 -CALLBACK: log1 -CALLBACK: log2 -CALLBACK: module1 > afterEach -CALLBACK: testDone1 -CALLBACK: testDone2 -CALLBACK: moduleStart1 -CALLBACK: moduleStart2 -CALLBACK: testStart1 -CALLBACK: testStart2 -CALLBACK: module4 > before -CALLBACK: module1 > beforeEach -CALLBACK: module4 > beforeEach -TEST: module4 > test1 -CALLBACK: log1 -CALLBACK: log2 -CALLBACK: module4 > afterEach -CALLBACK: module1 > afterEach -CALLBACK: module4 > after -CALLBACK: module1 > after -CALLBACK: testDone1 -CALLBACK: testDone2 -CALLBACK: moduleDone1 -CALLBACK: moduleDone2 -CALLBACK: moduleDone1 -CALLBACK: moduleDone2 -CALLBACK: done1 -CALLBACK: done2`; - - const command = ['qunit', 'callbacks.js']; - const execution = await execute(command); - - assert.equal(execution.stderr, expected); - assert.equal(execution.code, 0); - }); - - QUnit.test('callbacks with promises', async assert => { - const expected = `CALLBACK: begin -CALLBACK: begin2 -CALLBACK: moduleStart -CALLBACK: moduleStart -CALLBACK: testStart - test1 -CALLBACK: testDone - test1 -CALLBACK: moduleDone - module1 > nestedModule1 -CALLBACK: testStart - test2 -CALLBACK: testDone - test2 -CALLBACK: moduleStart -CALLBACK: testStart - test3 -CALLBACK: testDone - test3 -CALLBACK: moduleDone - module1 > nestedModule2 -CALLBACK: moduleDone - module1 -CALLBACK: done`; - - const command = ['qunit', 'callbacks-promises.js']; - const execution = await execute(command); - - assert.equal(execution.stderr, expected); - assert.equal(execution.code, 0); - }); - - QUnit.test('global hooks order', async assert => { - const expected = ` -HOOK: A1 @ global beforeEach-1 -HOOK: A1 @ global beforeEach-2 -HOOK: A1 @ global afterEach-2 -HOOK: A1 @ global afterEach-1 -HOOK: B1 @ B before -HOOK: B1 @ global beforeEach-1 -HOOK: B1 @ global beforeEach-2 -HOOK: B1 @ B beforeEach -HOOK: B1 @ B afterEach -HOOK: B1 @ global afterEach-2 -HOOK: B1 @ global afterEach-1 -HOOK: B2 @ global beforeEach-1 -HOOK: B2 @ global beforeEach-2 -HOOK: B2 @ B beforeEach -HOOK: B2 @ B afterEach -HOOK: B2 @ global afterEach-2 -HOOK: B2 @ global afterEach-1 -HOOK: BC1 @ BC before -HOOK: BC1 @ global beforeEach-1 -HOOK: BC1 @ global beforeEach-2 -HOOK: BC1 @ B beforeEach -HOOK: BC1 @ BC beforeEach -HOOK: BC1 @ BC afterEach -HOOK: BC1 @ B afterEach -HOOK: BC1 @ global afterEach-2 -HOOK: BC1 @ global afterEach-1 -HOOK: BC2 @ global beforeEach-1 -HOOK: BC2 @ global beforeEach-2 -HOOK: BC2 @ B beforeEach -HOOK: BC2 @ BC beforeEach -HOOK: BC2 @ BC afterEach -HOOK: BC2 @ B afterEach -HOOK: BC2 @ global afterEach-2 -HOOK: BC2 @ global afterEach-1 -HOOK: BCD1 @ BCD before -HOOK: BCD1 @ global beforeEach-1 -HOOK: BCD1 @ global beforeEach-2 -HOOK: BCD1 @ B beforeEach -HOOK: BCD1 @ BC beforeEach -HOOK: BCD1 @ BCD beforeEach -HOOK: BCD1 @ BCD afterEach -HOOK: BCD1 @ BC afterEach -HOOK: BCD1 @ B afterEach -HOOK: BCD1 @ global afterEach-2 -HOOK: BCD1 @ global afterEach-1 -HOOK: BCD1 @ BCD after -HOOK: BCD1 @ BC after -HOOK: BCD1 @ B after`; - - const command = ['qunit', 'hooks-global-order.js']; - const execution = await execute(command); - - assert.equal(execution.stderr, expected.trim()); - assert.equal(execution.code, 0); - }); - // TODO: Move to /test/cli/fixtures/ QUnit.test('run ESM test suite with import statement', async assert => { const command = ['qunit', '../../es2018/esm.mjs']; diff --git a/test/cli/events.js b/test/cli/events.js deleted file mode 100644 index 74b283d1f..000000000 --- a/test/cli/events.js +++ /dev/null @@ -1,285 +0,0 @@ -/** - * This test file verifies the execution order and contents of events emitted - * by QUnit after the test run finishes. They are expected to adhere to the - * js-reporters standard. - */ -const invokedHooks = []; -const invokedHookDetails = {}; -const requireQUnit = require('../../src/cli/require-qunit'); -const myQUnit = requireQUnit(); - -function callback (name) { - invokedHookDetails[name] = []; - - return function (details) { - invokedHooks.push(name); - invokedHookDetails[name].push(details); - }; -} - -myQUnit.on('runStart', callback('runStart')); -myQUnit.on('suiteStart', callback('suiteStart')); -myQUnit.on('testStart', callback('testStart')); -myQUnit.on('assertion', callback('assertion1')); -myQUnit.on('assertion', callback('assertion2')); -myQUnit.on('testEnd', callback('testEnd')); -myQUnit.on('suiteEnd', callback('suiteEnd')); -myQUnit.on('runEnd', callback('runEnd')); - -myQUnit.module('Events', function () { - myQUnit.module('Nested', function () { - myQUnit.todo('test1', function (assert) { - assert.true(false, 'failing assertion'); - }); - }); - - myQUnit.test('test2', function (assert) { - assert.true(true, 'passing assertion'); - }); - - myQUnit.skip('test3'); -}); - -const myQunitRun = new Promise(resolve => { - myQUnit.on('runEnd', resolve); -}); -myQUnit.start(); - -var test1Start = { - name: 'test1', - fullName: ['Events', 'Nested', 'test1'], - suiteName: 'Nested' -}; - -var test2Start = { - name: 'test2', - fullName: ['Events', 'test2'], - suiteName: 'Events' -}; - -var test3Start = { - name: 'test3', - fullName: ['Events', 'test3'], - suiteName: 'Events' -}; - -var suite2Start = { - name: 'Nested', - fullName: ['Events', 'Nested'], - childSuites: [], - testCounts: { - total: 1 - }, - tests: [ - test1Start - ] -}; - -var suite1Start = { - name: 'Events', - fullName: ['Events'], - childSuites: [ - suite2Start - ], - testCounts: { - total: 3 - }, - tests: [ - test2Start, - test3Start - ] -}; - -var assertion1 = { - passed: false, - message: 'failing assertion', - todo: true -}; - -var assertion2 = { - passed: true, - message: 'passing assertion', - todo: false -}; - -var test1End = { - name: 'test1', - fullName: ['Events', 'Nested', 'test1'], - suiteName: 'Nested', - status: 'todo', - errors: [ - assertion1 - ], - assertions: [ - assertion1 - ] -}; - -var test2End = { - name: 'test2', - fullName: ['Events', 'test2'], - suiteName: 'Events', - status: 'passed', - errors: [], - assertions: [ - assertion2 - ] -}; - -var test3End = { - name: 'test3', - fullName: ['Events', 'test3'], - suiteName: 'Events', - status: 'skipped', - errors: [], - assertions: [] -}; - -var suite2End = { - name: 'Nested', - fullName: ['Events', 'Nested'], - status: 'todo', - childSuites: [], - testCounts: { - skipped: 0, - passed: 0, - failed: 0, - todo: 1, - total: 1 - }, - tests: [ - test1End - ] -}; - -var suite1End = { - name: 'Events', - fullName: ['Events'], - status: 'passed', - childSuites: [ - suite2End - ], - testCounts: { - skipped: 1, - passed: 1, - failed: 0, - todo: 1, - total: 3 - }, - tests: [ - test2End, - test3End - ] -}; - -function removeUnstableProperties (obj) { - if (typeof obj !== 'object') { - return obj; - } - - delete obj.runtime; - delete obj.stack; - - Object.keys(obj).forEach(function (key) { - if (Array.isArray(obj[key])) { - obj[key].forEach(removeUnstableProperties); - } else if (typeof obj[key] === 'object') { - removeUnstableProperties(obj[key]); - } - }); - - return obj; -} - -// After all the tests run, we verify the events were fired in the correct order -// with the correct data -QUnit.module('Events', function () { - QUnit.test('verify callback order and data at end of test', async assert => { - await myQunitRun; - - assert.deepEqual(invokedHooks, [ - 'runStart', - 'suiteStart', - 'suiteStart', - 'testStart', - 'assertion1', - 'assertion2', - 'testEnd', - 'suiteEnd', - 'testStart', - 'assertion1', - 'assertion2', - 'testEnd', - 'testStart', - 'testEnd', - 'suiteEnd', - 'runEnd' - ], 'event callbacks are called in correct order'); - - assert.deepEqual( - invokedHookDetails.suiteStart[0], - suite1Start, - 'start of suite with tests and child suites data is correct' - ); - assert.deepEqual( - invokedHookDetails.suiteStart[1], - suite2Start, - 'start of child suite with tests data is correct' - ); - - assert.deepEqual( - invokedHookDetails.testStart[0], - test1Start, - 'regular testStart data is correct' - ); - assert.deepEqual( - invokedHookDetails.testStart[1], - test2Start, - 'skipped testStart data is correct' - ); - assert.deepEqual( - invokedHookDetails.testStart[2], - test3Start, - 'todo testStart data is correct' - ); - - assert.deepEqual( - removeUnstableProperties(invokedHookDetails.assertion1[0]), - assertion1, - 'failing assertion data is correct' - ); - assert.deepEqual( - removeUnstableProperties(invokedHookDetails.assertion1[1]), - assertion2, - 'passing assertion data is correct' - ); - - // These are pushed in reverse order of the starts - assert.deepEqual( - removeUnstableProperties(invokedHookDetails.testEnd[0]), - test1End, - 'todo testEnd data is correct' - ); - assert.deepEqual( - removeUnstableProperties(invokedHookDetails.testEnd[1]), - test2End, - 'regular testEnd data is correct' - ); - assert.deepEqual( - removeUnstableProperties(invokedHookDetails.testEnd[2]), - test3End, - 'skipped testEnd data is correct' - ); - - assert.deepEqual( - removeUnstableProperties(invokedHookDetails.suiteEnd[0]), - suite2End, - 'end of child suite with tests data is correct' - ); - assert.deepEqual( - removeUnstableProperties(invokedHookDetails.suiteEnd[1]), - suite1End, - 'end of suite with tests and child suites data is correct' - ); - }); -}); diff --git a/test/cli/fixtures/callbacks-promises.tap.txt b/test/cli/fixtures/callbacks-promises.tap.txt new file mode 100644 index 000000000..146d83073 --- /dev/null +++ b/test/cli/fixtures/callbacks-promises.tap.txt @@ -0,0 +1,28 @@ +# command: ["qunit", "callbacks-promises.js"] + +TAP version 13 +ok 1 module1 > nestedModule1 > test1 +ok 2 module1 > test2 +ok 3 module1 > nestedModule2 > test3 +1..3 +# pass 3 +# skip 0 +# todo 0 +# fail 0 + +# stderr +CALLBACK: begin +CALLBACK: begin2 +CALLBACK: moduleStart +CALLBACK: moduleStart +CALLBACK: testStart - test1 +CALLBACK: testDone - test1 +CALLBACK: moduleDone - module1 > nestedModule1 +CALLBACK: testStart - test2 +CALLBACK: testDone - test2 +CALLBACK: moduleStart +CALLBACK: testStart - test3 +CALLBACK: testDone - test3 +CALLBACK: moduleDone - module1 > nestedModule2 +CALLBACK: moduleDone - module1 +CALLBACK: done diff --git a/test/cli/fixtures/callbacks.tap.txt b/test/cli/fixtures/callbacks.tap.txt new file mode 100644 index 000000000..b4e8cb14c --- /dev/null +++ b/test/cli/fixtures/callbacks.tap.txt @@ -0,0 +1,94 @@ +# command: ["qunit", "callbacks.js"] + +TAP version 13 +ok 1 module1 > test1 +ok 2 module1 > module2 > test1 +ok 3 module1 > module3 > test1 +ok 4 module1 > test2 +ok 5 module1 > module4 > test1 +1..5 +# pass 5 +# skip 0 +# todo 0 +# fail 0 + +# stderr +CALLBACK: begin1 +CALLBACK: begin2 +CALLBACK: moduleStart1 +CALLBACK: moduleStart2 +CALLBACK: testStart1 +CALLBACK: testStart2 +CALLBACK: module1 > before +CALLBACK: module1 > beforeEach +TEST: module1 > test1 +CALLBACK: log1 +CALLBACK: log2 +CALLBACK: module1 > afterEach +CALLBACK: testDone1 +CALLBACK: testDone2 +CALLBACK: moduleStart1 +CALLBACK: moduleStart2 +CALLBACK: testStart1 +CALLBACK: testStart2 +CALLBACK: module2 > before +CALLBACK: module1 > beforeEach +CALLBACK: module2 > beforeEach +TEST: module2 > test1 +CALLBACK: log1 +CALLBACK: log2 +CALLBACK: module2 > afterEach +CALLBACK: module1 > afterEach +CALLBACK: module2 > after +CALLBACK: testDone1 +CALLBACK: testDone2 +CALLBACK: moduleDone1 +CALLBACK: moduleDone2 +CALLBACK: moduleStart1 +CALLBACK: moduleStart2 +CALLBACK: testStart1 +CALLBACK: testStart2 +CALLBACK: module3 > before +CALLBACK: module1 > beforeEach +CALLBACK: module3 > beforeEach +TEST: module3 > test1 +CALLBACK: log1 +CALLBACK: log2 +CALLBACK: module3 > afterEach +CALLBACK: module1 > afterEach +CALLBACK: module3 > after +CALLBACK: testDone1 +CALLBACK: testDone2 +CALLBACK: moduleDone1 +CALLBACK: moduleDone2 +CALLBACK: testStart1 +CALLBACK: testStart2 +CALLBACK: module1 > beforeEach +TEST: module1 > test2 +CALLBACK: log1 +CALLBACK: log2 +CALLBACK: module1 > afterEach +CALLBACK: testDone1 +CALLBACK: testDone2 +CALLBACK: moduleStart1 +CALLBACK: moduleStart2 +CALLBACK: testStart1 +CALLBACK: testStart2 +CALLBACK: module4 > before +CALLBACK: module1 > beforeEach +CALLBACK: module4 > beforeEach +TEST: module4 > test1 +CALLBACK: log1 +CALLBACK: log2 +CALLBACK: module4 > afterEach +CALLBACK: module1 > afterEach +CALLBACK: module4 > after +CALLBACK: module1 > after +CALLBACK: testDone1 +CALLBACK: testDone2 +CALLBACK: moduleDone1 +CALLBACK: moduleDone2 +CALLBACK: moduleDone1 +CALLBACK: moduleDone2 +CALLBACK: done1 +CALLBACK: done2 diff --git a/test/cli/fixtures/events.js b/test/cli/fixtures/events.js new file mode 100644 index 000000000..d45310dfd --- /dev/null +++ b/test/cli/fixtures/events.js @@ -0,0 +1,53 @@ +/** + * This test file verifies the execution order and contents of events emitted + * by QUnit after the test run finishes. They are expected to adhere to the + * js-reporters standard. + */ + +function removeUnstableProperties (obj) { + if (typeof obj === 'object') { + if ('runtime' in obj) { + // Stub out non-deterministic property + obj.runtime = 0; + } + for (var key in obj) { + if (Array.isArray(obj[key])) { + obj[key].forEach(removeUnstableProperties); + } else if (typeof obj[key] === 'object') { + removeUnstableProperties(obj[key]); + } + } + } + return obj; +} + +function callback (name) { + return function (details) { + console.warn('EVENT: ' + name); + removeUnstableProperties(details); + console.warn(JSON.stringify(details, null, 2)); + }; +} + +QUnit.on('runStart', callback('runStart')); +QUnit.on('suiteStart', callback('suiteStart')); +QUnit.on('testStart', callback('testStart')); +QUnit.on('assertion', callback('assertion1')); +QUnit.on('assertion', callback('assertion2')); +QUnit.on('testEnd', callback('testEnd')); +QUnit.on('suiteEnd', callback('suiteEnd')); +QUnit.on('runEnd', callback('runEnd')); + +QUnit.module('Events', function () { + QUnit.module('Nested', function () { + QUnit.todo('test1', function (assert) { + assert.true(false, 'failing assertion'); + }); + }); + + QUnit.test('test2', function (assert) { + assert.true(true, 'passing assertion'); + }); + + QUnit.skip('test3'); +}); diff --git a/test/cli/fixtures/events.tap.txt b/test/cli/fixtures/events.tap.txt new file mode 100644 index 000000000..289536a0e --- /dev/null +++ b/test/cli/fixtures/events.tap.txt @@ -0,0 +1,539 @@ +# command: ["qunit", "events.js"] + +TAP version 13 +not ok 1 # TODO Events > Nested > test1 + --- + message: failing assertion + severity: todo + actual : false + expected: true + stack: | + at /qunit/test/cli/fixtures/events.js:44:18 + ... +ok 2 Events > test2 +ok 3 # SKIP Events > test3 +1..3 +# pass 1 +# skip 1 +# todo 1 +# fail 0 + +# stderr +EVENT: runStart +{ + "fullName": [], + "tests": [], + "childSuites": [ + { + "name": "Events", + "fullName": [ + "Events" + ], + "tests": [ + { + "name": "test2", + "suiteName": "Events", + "fullName": [ + "Events", + "test2" + ] + }, + { + "name": "test3", + "suiteName": "Events", + "fullName": [ + "Events", + "test3" + ] + } + ], + "childSuites": [ + { + "name": "Nested", + "fullName": [ + "Events", + "Nested" + ], + "tests": [ + { + "name": "test1", + "suiteName": "Nested", + "fullName": [ + "Events", + "Nested", + "test1" + ] + } + ], + "childSuites": [], + "testCounts": { + "total": 1 + } + } + ], + "testCounts": { + "total": 3 + } + } + ], + "testCounts": { + "total": 3 + } +} +EVENT: suiteStart +{ + "name": "Events", + "fullName": [ + "Events" + ], + "tests": [ + { + "name": "test2", + "suiteName": "Events", + "fullName": [ + "Events", + "test2" + ] + }, + { + "name": "test3", + "suiteName": "Events", + "fullName": [ + "Events", + "test3" + ] + } + ], + "childSuites": [ + { + "name": "Nested", + "fullName": [ + "Events", + "Nested" + ], + "tests": [ + { + "name": "test1", + "suiteName": "Nested", + "fullName": [ + "Events", + "Nested", + "test1" + ] + } + ], + "childSuites": [], + "testCounts": { + "total": 1 + } + } + ], + "testCounts": { + "total": 3 + } +} +EVENT: suiteStart +{ + "name": "Nested", + "fullName": [ + "Events", + "Nested" + ], + "tests": [ + { + "name": "test1", + "suiteName": "Nested", + "fullName": [ + "Events", + "Nested", + "test1" + ] + } + ], + "childSuites": [], + "testCounts": { + "total": 1 + } +} +EVENT: testStart +{ + "name": "test1", + "suiteName": "Nested", + "fullName": [ + "Events", + "Nested", + "test1" + ] +} +EVENT: assertion1 +{ + "passed": false, + "actual": false, + "expected": true, + "message": "failing assertion", + "stack": " at /qunit/test/cli/fixtures/events.js:44:18", + "todo": true +} +EVENT: assertion2 +{ + "passed": false, + "actual": false, + "expected": true, + "message": "failing assertion", + "stack": " at /qunit/test/cli/fixtures/events.js:44:18", + "todo": true +} +EVENT: testEnd +{ + "name": "test1", + "suiteName": "Nested", + "fullName": [ + "Events", + "Nested", + "test1" + ], + "runtime": 0, + "status": "todo", + "errors": [ + { + "passed": false, + "actual": false, + "expected": true, + "message": "failing assertion", + "stack": " at /qunit/test/cli/fixtures/events.js:44:18", + "todo": true + } + ], + "assertions": [ + { + "passed": false, + "actual": false, + "expected": true, + "message": "failing assertion", + "stack": " at /qunit/test/cli/fixtures/events.js:44:18", + "todo": true + } + ] +} +EVENT: suiteEnd +{ + "name": "Nested", + "fullName": [ + "Events", + "Nested" + ], + "tests": [ + { + "name": "test1", + "suiteName": "Nested", + "fullName": [ + "Events", + "Nested", + "test1" + ], + "runtime": 0, + "status": "todo", + "errors": [ + { + "passed": false, + "message": "failing assertion", + "stack": " at /qunit/test/cli/fixtures/events.js:44:18", + "todo": true + } + ], + "assertions": [ + { + "passed": false, + "message": "failing assertion", + "stack": " at /qunit/test/cli/fixtures/events.js:44:18", + "todo": true + } + ] + } + ], + "childSuites": [], + "testCounts": { + "passed": 0, + "failed": 0, + "skipped": 0, + "todo": 1, + "total": 1 + }, + "runtime": 0, + "status": "todo" +} +EVENT: testStart +{ + "name": "test2", + "suiteName": "Events", + "fullName": [ + "Events", + "test2" + ] +} +EVENT: assertion1 +{ + "passed": true, + "actual": true, + "expected": true, + "message": "passing assertion", + "todo": false +} +EVENT: assertion2 +{ + "passed": true, + "actual": true, + "expected": true, + "message": "passing assertion", + "todo": false +} +EVENT: testEnd +{ + "name": "test2", + "suiteName": "Events", + "fullName": [ + "Events", + "test2" + ], + "runtime": 0, + "status": "passed", + "errors": [], + "assertions": [ + { + "passed": true, + "actual": true, + "expected": true, + "message": "passing assertion", + "todo": false + } + ] +} +EVENT: testStart +{ + "name": "test3", + "suiteName": "Events", + "fullName": [ + "Events", + "test3" + ] +} +EVENT: testEnd +{ + "name": "test3", + "suiteName": "Events", + "fullName": [ + "Events", + "test3" + ], + "runtime": 0, + "status": "skipped", + "errors": [], + "assertions": [] +} +EVENT: suiteEnd +{ + "name": "Events", + "fullName": [ + "Events" + ], + "tests": [ + { + "name": "test2", + "suiteName": "Events", + "fullName": [ + "Events", + "test2" + ], + "runtime": 0, + "status": "passed", + "errors": [], + "assertions": [ + { + "passed": true, + "message": "passing assertion", + "todo": false + } + ] + }, + { + "name": "test3", + "suiteName": "Events", + "fullName": [ + "Events", + "test3" + ], + "runtime": 0, + "status": "skipped", + "errors": [], + "assertions": [] + } + ], + "childSuites": [ + { + "name": "Nested", + "fullName": [ + "Events", + "Nested" + ], + "tests": [ + { + "name": "test1", + "suiteName": "Nested", + "fullName": [ + "Events", + "Nested", + "test1" + ], + "runtime": 0, + "status": "todo", + "errors": [ + { + "passed": false, + "message": "failing assertion", + "stack": " at /qunit/test/cli/fixtures/events.js:44:18", + "todo": true + } + ], + "assertions": [ + { + "passed": false, + "message": "failing assertion", + "stack": " at /qunit/test/cli/fixtures/events.js:44:18", + "todo": true + } + ] + } + ], + "childSuites": [], + "testCounts": { + "passed": 0, + "failed": 0, + "skipped": 0, + "todo": 1, + "total": 1 + }, + "runtime": 0, + "status": "todo" + } + ], + "testCounts": { + "passed": 1, + "failed": 0, + "skipped": 1, + "todo": 1, + "total": 3 + }, + "runtime": 0, + "status": "passed" +} +EVENT: runEnd +{ + "fullName": [], + "tests": [], + "childSuites": [ + { + "name": "Events", + "fullName": [ + "Events" + ], + "tests": [ + { + "name": "test2", + "suiteName": "Events", + "fullName": [ + "Events", + "test2" + ], + "runtime": 0, + "status": "passed", + "errors": [], + "assertions": [ + { + "passed": true, + "message": "passing assertion", + "todo": false + } + ] + }, + { + "name": "test3", + "suiteName": "Events", + "fullName": [ + "Events", + "test3" + ], + "runtime": 0, + "status": "skipped", + "errors": [], + "assertions": [] + } + ], + "childSuites": [ + { + "name": "Nested", + "fullName": [ + "Events", + "Nested" + ], + "tests": [ + { + "name": "test1", + "suiteName": "Nested", + "fullName": [ + "Events", + "Nested", + "test1" + ], + "runtime": 0, + "status": "todo", + "errors": [ + { + "passed": false, + "message": "failing assertion", + "stack": " at /qunit/test/cli/fixtures/events.js:44:18", + "todo": true + } + ], + "assertions": [ + { + "passed": false, + "message": "failing assertion", + "stack": " at /qunit/test/cli/fixtures/events.js:44:18", + "todo": true + } + ] + } + ], + "childSuites": [], + "testCounts": { + "passed": 0, + "failed": 0, + "skipped": 0, + "todo": 1, + "total": 1 + }, + "runtime": 0, + "status": "todo" + } + ], + "testCounts": { + "passed": 1, + "failed": 0, + "skipped": 1, + "todo": 1, + "total": 3 + }, + "runtime": 0, + "status": "passed" + } + ], + "testCounts": { + "passed": 1, + "failed": 0, + "skipped": 1, + "todo": 1, + "total": 3 + }, + "runtime": 0, + "status": "passed" +} diff --git a/test/cli/fixtures/hooks-global-order.tap.txt b/test/cli/fixtures/hooks-global-order.tap.txt new file mode 100644 index 000000000..5c94a0eb6 --- /dev/null +++ b/test/cli/fixtures/hooks-global-order.tap.txt @@ -0,0 +1,64 @@ +# command: ["qunit", "hooks-global-order.js"] + +TAP version 13 +ok 1 A1 +ok 2 B > B1 +ok 3 B > B2 +ok 4 B > BC > BC1 +ok 5 B > BC > BC2 +ok 6 B > BC > BCD > BCD1 +1..6 +# pass 6 +# skip 0 +# todo 0 +# fail 0 + +# stderr +HOOK: A1 @ global beforeEach-1 +HOOK: A1 @ global beforeEach-2 +HOOK: A1 @ global afterEach-2 +HOOK: A1 @ global afterEach-1 +HOOK: B1 @ B before +HOOK: B1 @ global beforeEach-1 +HOOK: B1 @ global beforeEach-2 +HOOK: B1 @ B beforeEach +HOOK: B1 @ B afterEach +HOOK: B1 @ global afterEach-2 +HOOK: B1 @ global afterEach-1 +HOOK: B2 @ global beforeEach-1 +HOOK: B2 @ global beforeEach-2 +HOOK: B2 @ B beforeEach +HOOK: B2 @ B afterEach +HOOK: B2 @ global afterEach-2 +HOOK: B2 @ global afterEach-1 +HOOK: BC1 @ BC before +HOOK: BC1 @ global beforeEach-1 +HOOK: BC1 @ global beforeEach-2 +HOOK: BC1 @ B beforeEach +HOOK: BC1 @ BC beforeEach +HOOK: BC1 @ BC afterEach +HOOK: BC1 @ B afterEach +HOOK: BC1 @ global afterEach-2 +HOOK: BC1 @ global afterEach-1 +HOOK: BC2 @ global beforeEach-1 +HOOK: BC2 @ global beforeEach-2 +HOOK: BC2 @ B beforeEach +HOOK: BC2 @ BC beforeEach +HOOK: BC2 @ BC afterEach +HOOK: BC2 @ B afterEach +HOOK: BC2 @ global afterEach-2 +HOOK: BC2 @ global afterEach-1 +HOOK: BCD1 @ BCD before +HOOK: BCD1 @ global beforeEach-1 +HOOK: BCD1 @ global beforeEach-2 +HOOK: BCD1 @ B beforeEach +HOOK: BCD1 @ BC beforeEach +HOOK: BCD1 @ BCD beforeEach +HOOK: BCD1 @ BCD afterEach +HOOK: BCD1 @ BC afterEach +HOOK: BCD1 @ B afterEach +HOOK: BCD1 @ global afterEach-2 +HOOK: BCD1 @ global afterEach-1 +HOOK: BCD1 @ BCD after +HOOK: BCD1 @ BC after +HOOK: BCD1 @ B after diff --git a/test/cli/fixtures/inception.js b/test/cli/fixtures/inception.js new file mode 100644 index 000000000..125117fab --- /dev/null +++ b/test/cli/fixtures/inception.js @@ -0,0 +1,37 @@ +const outerQUnit = global.QUnit; +delete global.QUnit; +const myQUnit = require('../../../src/cli/require-qunit')(); +global.QUnit = outerQUnit; + +const data = []; +myQUnit.on('runStart', function () { + data.push('runStart'); +}); +myQUnit.on('testEnd', function () { + data.push('testEnd'); +}); +myQUnit.on('runEnd', function () { + data.push('runEnd'); +}); + +myQUnit.module('example', function () { + myQUnit.test('a', function (assert) { + assert.true(true, 'message'); + }); +}); + +const myQunitRun = new Promise(resolve => { + myQUnit.on('runEnd', resolve); +}); + +myQUnit.start(); + +QUnit.test('inception', async function (assert) { + await myQunitRun; + + assert.deepEqual(data, [ + 'runStart', + 'testEnd', + 'runEnd' + ]); +}); diff --git a/test/cli/fixtures/inception.tap.txt b/test/cli/fixtures/inception.tap.txt new file mode 100644 index 000000000..36771b19e --- /dev/null +++ b/test/cli/fixtures/inception.tap.txt @@ -0,0 +1,9 @@ +# command: ["qunit", "inception.js"] + +TAP version 13 +ok 1 inception +1..1 +# pass 1 +# skip 0 +# todo 0 +# fail 0 diff --git a/test/cli/helpers/execute.js b/test/cli/helpers/execute.js index bdf15797e..04fbafa64 100644 --- a/test/cli/helpers/execute.js +++ b/test/cli/helpers/execute.js @@ -12,11 +12,19 @@ const reEscape = /([\\{}()|.?*+\-^$[\]])/g; function normalize (actual) { const dir = path.join(__dirname, '..', '..', '..'); const reDir = new RegExp(dir.replace(reEscape, '\\$1'), 'g'); + // Replace JSON-escaped backslash in Windows paths (events.tap.txt) + const reDirWindows = new RegExp( + dir.replace('\\', '\\\\').replace(reEscape, '\\$1'), + 'g' + ); // Replace backslashes (\) in stack traces on Windows to POSIX // but leave quoted/escaped shell arguments like \"foo\" unchanged. const reSep = new RegExp(path.sep.replace(reEscape, '\\$1') + '(?!")', 'g'); return actual + // Replace JSON-escaped backslash in Windows paths (events.tap.txt) + .replace(reDirWindows, '/qunit') + .replace(/\\\\/g, '/') .replace(reDir, '/qunit') .replace(reSep, '/') // Convert "at processModule (/qunit/qunit/qunit.js:1:2)" to "at qunit.js"