diff --git a/CHANGELOG.md b/CHANGELOG.md index c0d7fbd43a29..6332c3821f3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- `[jest-jasmine2/jest-circus/jest-cli]` Add test.todo ([#6996](https://github.com/facebook/jest/pull/6996)) - `[pretty-format]` Option to not escape strings in diff messages ([#5661](https://github.com/facebook/jest/pull/5661)) ### Fixes diff --git a/docs/GlobalAPI.md b/docs/GlobalAPI.md index 1cfdfc642b56..0eb4f2be26d2 100644 --- a/docs/GlobalAPI.md +++ b/docs/GlobalAPI.md @@ -655,3 +655,21 @@ test('will be ran', () => { expect(1 / 0).toBe(Infinity); }); ``` + +### `test.todo(name)` + +Use `test.todo` when you are planning on writing tests. These tests will be highlighted in the summary output at the end so you know how many tests you still need todo. + +_Note_: If you supply a test callback function then the `test.todo` will throw an error. If you have already implemented the test and it is broken and you do not want it to run, then use `test.skip` instead. + +#### API + +- `name`: `String` the title of the test plan. + +Example: + +```js +const add = (a, b) => a + b; + +test.todo('add should be associative'); +``` diff --git a/e2e/__tests__/__snapshots__/globals.test.js.snap b/e2e/__tests__/__snapshots__/globals.test.js.snap index 4e61b01522ec..bb31e4b13844 100644 --- a/e2e/__tests__/__snapshots__/globals.test.js.snap +++ b/e2e/__tests__/__snapshots__/globals.test.js.snap @@ -23,7 +23,7 @@ exports[`cannot test with no implementation 1`] = ` "FAIL __tests__/only-constructs.test.js ● Test suite failed to run - Missing second argument. It must be a callback function. + Missing second argument. It must be a callback function. Perhaps you want to use \`test.todo\` for a test placeholder. 1 | 2 | it('it', () => {}); @@ -50,7 +50,7 @@ exports[`cannot test with no implementation with expand arg 1`] = ` "FAIL __tests__/only-constructs.test.js ● Test suite failed to run - Missing second argument. It must be a callback function. + Missing second argument. It must be a callback function. Perhaps you want to use \`test.todo\` for a test placeholder. 1 | 2 | it('it', () => {}); diff --git a/e2e/__tests__/__snapshots__/test-todo.test.js.snap b/e2e/__tests__/__snapshots__/test-todo.test.js.snap new file mode 100644 index 000000000000..bd51088a7639 --- /dev/null +++ b/e2e/__tests__/__snapshots__/test-todo.test.js.snap @@ -0,0 +1,79 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`shows error messages when called with invalid argument 1`] = ` +"FAIL __tests__/todo_non_string.test.js + ● Test suite failed to run + + Todo must be called with only a description. + + 6 | */ + 7 | + > 8 | it.todo(() => {}); + | ^ + 9 | + + at __tests__/todo_non_string.test.js:8:4 + +" +`; + +exports[`shows error messages when called with multiple arguments 1`] = ` +"FAIL __tests__/todo_multiple_args.test.js + ● Test suite failed to run + + Todo must be called with only a description. + + 6 | */ + 7 | + > 8 | it.todo('todo later', () => {}); + | ^ + 9 | + + at __tests__/todo_multiple_args.test.js:8:4 + +" +`; + +exports[`shows error messages when called with no arguments 1`] = ` +"FAIL __tests__/todo_no_args.test.js + ● Test suite failed to run + + Todo must be called with only a description. + + 6 | */ + 7 | + > 8 | it.todo(); + | ^ + 9 | + + at __tests__/todo_no_args.test.js:8:4 + +" +`; + +exports[`works with all statuses 1`] = ` +"FAIL __tests__/statuses.test.js + ✓ passes + ✕ fails + ○ skipped 1 test + ✎ todo 1 test + + ● fails + + expect(received).toBe(expected) // Object.is equality + + Expected: 101 + Received: 10 + + 11 | + 12 | it('fails', () => { + > 13 | expect(10).toBe(101); + | ^ + 14 | }); + 15 | + 16 | it.skip('skips', () => { + + at __tests__/statuses.test.js:13:14 + +" +`; diff --git a/e2e/__tests__/test-todo.test.js b/e2e/__tests__/test-todo.test.js new file mode 100644 index 000000000000..c430731a8f62 --- /dev/null +++ b/e2e/__tests__/test-todo.test.js @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2018-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +'use strict'; + +const path = require('path'); +const runJest = require('../runJest'); +const {extractSummary} = require('../Utils'); +const dir = path.resolve(__dirname, '../test-todo'); + +test('works with all statuses', () => { + const result = runJest(dir, ['statuses.test.js']); + expect(result.status).toBe(1); + const {rest} = extractSummary(result.stderr); + expect(rest).toMatchSnapshot(); +}); + +test('shows error messages when called with no arguments', () => { + const result = runJest(dir, ['todo_no_args.test.js']); + expect(result.status).toBe(1); + const {rest} = extractSummary(result.stderr); + expect(rest).toMatchSnapshot(); +}); + +test('shows error messages when called with multiple arguments', () => { + const result = runJest(dir, ['todo_multiple_args.test.js']); + expect(result.status).toBe(1); + const {rest} = extractSummary(result.stderr); + expect(rest).toMatchSnapshot(); +}); + +test('shows error messages when called with invalid argument', () => { + const result = runJest(dir, ['todo_non_string.test.js']); + expect(result.status).toBe(1); + const {rest} = extractSummary(result.stderr); + expect(rest).toMatchSnapshot(); +}); diff --git a/e2e/test-todo/__tests__/statuses.test.js b/e2e/test-todo/__tests__/statuses.test.js new file mode 100644 index 000000000000..4d9034ee7080 --- /dev/null +++ b/e2e/test-todo/__tests__/statuses.test.js @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2018-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +it('passes', () => { + expect(10).toBe(10); +}); + +it('fails', () => { + expect(10).toBe(101); +}); + +it.skip('skips', () => { + expect(10).toBe(101); +}); + +it.todo('todo'); diff --git a/e2e/test-todo/__tests__/todo_multiple_args.test.js b/e2e/test-todo/__tests__/todo_multiple_args.test.js new file mode 100644 index 000000000000..e0b852c31d88 --- /dev/null +++ b/e2e/test-todo/__tests__/todo_multiple_args.test.js @@ -0,0 +1,8 @@ +/** + * Copyright (c) 2018-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +it.todo('todo later', () => {}); diff --git a/e2e/test-todo/__tests__/todo_no_args.test.js b/e2e/test-todo/__tests__/todo_no_args.test.js new file mode 100644 index 000000000000..d82b8e902c53 --- /dev/null +++ b/e2e/test-todo/__tests__/todo_no_args.test.js @@ -0,0 +1,8 @@ +/** + * Copyright (c) 2018-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +it.todo(); diff --git a/e2e/test-todo/__tests__/todo_non_string.test.js b/e2e/test-todo/__tests__/todo_non_string.test.js new file mode 100644 index 000000000000..5c3c9d766a9d --- /dev/null +++ b/e2e/test-todo/__tests__/todo_non_string.test.js @@ -0,0 +1,8 @@ +/** + * Copyright (c) 2018-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +it.todo(() => {}); diff --git a/e2e/test-todo/package.json b/e2e/test-todo/package.json new file mode 100644 index 000000000000..148788b25446 --- /dev/null +++ b/e2e/test-todo/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "testEnvironment": "node" + } +} diff --git a/packages/jest-circus/src/__tests__/circus_it_test_error.test.js b/packages/jest-circus/src/__tests__/circus_it_test_error.test.js index 4fd4e2d99f27..4af5597c40a1 100644 --- a/packages/jest-circus/src/__tests__/circus_it_test_error.test.js +++ b/packages/jest-circus/src/__tests__/circus_it_test_error.test.js @@ -37,7 +37,9 @@ describe('test/it error throwing', () => { expect(() => { // $FlowFixMe: Easy, we're testing runitme errors here circusIt('test2'); - }).toThrowError('Missing second argument. It must be a callback function.'); + }).toThrowError( + 'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.', + ); }); it(`it throws an error when first argument isn't a string`, () => { expect(() => { @@ -62,7 +64,9 @@ describe('test/it error throwing', () => { expect(() => { // $FlowFixMe: Easy, we're testing runitme errors here circusTest('test6'); - }).toThrowError('Missing second argument. It must be a callback function.'); + }).toThrowError( + 'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.', + ); }); it(`test throws an error when first argument isn't a string`, () => { expect(() => { diff --git a/packages/jest-circus/src/__tests__/circus_todo_test_error.test.js b/packages/jest-circus/src/__tests__/circus_todo_test_error.test.js new file mode 100644 index 000000000000..1564ce029559 --- /dev/null +++ b/packages/jest-circus/src/__tests__/circus_todo_test_error.test.js @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + */ + +'use strict'; + +let circusIt; + +// using jest-jasmine2's 'it' to test jest-circus's 'it'. Had to differentiate +// the two with this alias. + +const aliasCircusIt = () => { + const {it} = require('../index.js'); + circusIt = it; +}; + +aliasCircusIt(); + +describe('test/it.todo error throwing', () => { + it('todo throws error when given no arguments', () => { + expect(() => { + // $FlowFixMe: Testing runitme errors here + circusIt.todo(); + }).toThrowError('Todo must be called with only a description.'); + }); + it('todo throws error when given more than one argument', () => { + expect(() => { + circusIt.todo('test1', () => {}); + }).toThrowError('Todo must be called with only a description.'); + }); + it('todo throws error when given none string description', () => { + expect(() => { + // $FlowFixMe: Testing runitme errors here + circusIt.todo(() => {}); + }).toThrowError('Todo must be called with only a description.'); + }); +}); diff --git a/packages/jest-circus/src/event_handler.js b/packages/jest-circus/src/event_handler.js index e50e1f56548d..fb5af141b802 100644 --- a/packages/jest-circus/src/event_handler.js +++ b/packages/jest-circus/src/event_handler.js @@ -105,6 +105,10 @@ const handler: EventHandler = (event, state): void => { event.test.status = 'skip'; break; } + case 'test_todo': { + event.test.status = 'todo'; + break; + } case 'test_done': { event.test.duration = getTestDuration(event.test); event.test.status = 'done'; diff --git a/packages/jest-circus/src/index.js b/packages/jest-circus/src/index.js index 790987a43349..c6463ce0cc1e 100644 --- a/packages/jest-circus/src/index.js +++ b/packages/jest-circus/src/index.js @@ -68,7 +68,9 @@ const test = (testName: TestName, fn: TestFn, timeout?: number) => { ); } if (fn === undefined) { - throw new Error('Missing second argument. It must be a callback function.'); + throw new Error( + 'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.', + ); } if (typeof fn !== 'function') { throw new Error( @@ -121,6 +123,32 @@ test.only = (testName: TestName, fn: TestFn, timeout?: number) => { }); }; +test.todo = (testName: TestName, ...rest: Array) => { + if (rest.length > 0 || typeof testName !== 'string') { + const e = new Error('Todo must be called with only a description.'); + + if (Error.captureStackTrace) { + Error.captureStackTrace(e, test.todo); + } + + throw e; + } + + const asyncError = new Error(); + if (Error.captureStackTrace) { + Error.captureStackTrace(asyncError, test); + } + + return dispatch({ + asyncError, + fn: () => {}, + mode: 'todo', + name: 'add_test', + testName, + timeout: undefined, + }); +}; + test.each = bindEach(test); test.only.each = bindEach(test.only); test.skip.each = bindEach(test.skip); diff --git a/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js b/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js index 47df43f83778..7f076478e948 100644 --- a/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js +++ b/packages/jest-circus/src/legacy_code_todo_rewrite/jest_adapter_init.js @@ -122,12 +122,16 @@ export const runAndTransformResultsToJestFormat = async ({ let numFailingTests = 0; let numPassingTests = 0; let numPendingTests = 0; + let numTodoTests = 0; const assertionResults = runResult.testResults.map(testResult => { let status: Status; if (testResult.status === 'skip') { status = 'pending'; numPendingTests += 1; + } else if (testResult.status === 'todo') { + status = 'todo'; + numTodoTests += 1; } else if (testResult.errors.length) { status = 'failed'; numFailingTests += 1; @@ -184,6 +188,7 @@ export const runAndTransformResultsToJestFormat = async ({ numFailingTests, numPassingTests, numPendingTests, + numTodoTests, openHandles: [], perfStats: { // populated outside diff --git a/packages/jest-circus/src/run.js b/packages/jest-circus/src/run.js index bf6bae4f2683..37fcfc8d1616 100644 --- a/packages/jest-circus/src/run.js +++ b/packages/jest-circus/src/run.js @@ -97,6 +97,11 @@ const _runTest = async (test: TestEntry): Promise => { return; } + if (test.mode === 'todo') { + dispatch({name: 'test_todo', test}); + return; + } + const {afterEach, beforeEach} = getEachHooksForTest(test); for (const hook of beforeEach) { diff --git a/packages/jest-cli/src/constants.js b/packages/jest-cli/src/constants.js index 67418d211d72..fec5f008415e 100644 --- a/packages/jest-cli/src/constants.js +++ b/packages/jest-cli/src/constants.js @@ -15,6 +15,7 @@ export const ICONS = { failed: isWindows ? '\u00D7' : '\u2715', pending: '\u25CB', success: isWindows ? '\u221A' : '\u2713', + todo: '\u270E', }; export const PACKAGE_JSON = 'package.json'; export const JEST_CONFIG = 'jest.config.js'; diff --git a/packages/jest-cli/src/reporters/utils.js b/packages/jest-cli/src/reporters/utils.js index bdea97306ef9..7f519991892d 100644 --- a/packages/jest-cli/src/reporters/utils.js +++ b/packages/jest-cli/src/reporters/utils.js @@ -122,6 +122,7 @@ export const getSummary = ( const testsFailed = aggregatedResults.numFailedTests; const testsPassed = aggregatedResults.numPassedTests; const testsPending = aggregatedResults.numPendingTests; + const testsTodo = aggregatedResults.numTodoTests; const testsTotal = aggregatedResults.numTotalTests; const width = (options && options.width) || 0; @@ -141,6 +142,7 @@ export const getSummary = ( chalk.bold('Tests: ') + (testsFailed ? chalk.bold.red(`${testsFailed} failed`) + ', ' : '') + (testsPending ? chalk.bold.yellow(`${testsPending} skipped`) + ', ' : '') + + (testsTodo ? chalk.bold.magenta(`${testsTodo} todo`) + ', ' : '') + (testsPassed ? chalk.bold.green(`${testsPassed} passed`) + ', ' : '') + `${testsTotal} total`; diff --git a/packages/jest-cli/src/reporters/verbose_reporter.js b/packages/jest-cli/src/reporters/verbose_reporter.js index 1e86c88b1516..9883c1844049 100644 --- a/packages/jest-cli/src/reporters/verbose_reporter.js +++ b/packages/jest-cli/src/reporters/verbose_reporter.js @@ -97,6 +97,8 @@ export default class VerboseReporter extends DefaultReporter { return chalk.red(ICONS.failed); } else if (status === 'pending') { return chalk.yellow(ICONS.pending); + } else if (status === 'todo') { + return chalk.magenta(ICONS.todo); } else { return chalk.green(ICONS.success); } @@ -112,26 +114,48 @@ export default class VerboseReporter extends DefaultReporter { if (this._globalConfig.expand) { tests.forEach(test => this._logTest(test, indentLevel)); } else { - const skippedCount = tests.reduce((result, test) => { - if (test.status === 'pending') { - result += 1; - } else { - this._logTest(test, indentLevel); - } + const summedTests = tests.reduce( + (result, test) => { + if (test.status === 'pending') { + result.pending += 1; + } else if (test.status === 'todo') { + result.todo += 1; + } else { + this._logTest(test, indentLevel); + } + + return result; + }, + {pending: 0, todo: 0}, + ); - return result; - }, 0); + if (summedTests.pending > 0) { + this._logSummedTests( + 'skipped', + this._getIcon('pending'), + summedTests.pending, + indentLevel, + ); + } - if (skippedCount > 0) { - this._logSkippedTests(skippedCount, indentLevel); + if (summedTests.todo > 0) { + this._logSummedTests( + 'todo', + this._getIcon('todo'), + summedTests.todo, + indentLevel, + ); } } } - _logSkippedTests(count: number, indentLevel: number) { - const icon = this._getIcon('pending'); - const text = chalk.dim(`skipped ${count} test${count === 1 ? '' : 's'}`); - + _logSummedTests( + prefix: string, + icon: string, + count: number, + indentLevel: number, + ) { + const text = chalk.dim(`${prefix} ${count} test${count === 1 ? '' : 's'}`); this._logLine(`${icon} ${text}`, indentLevel); } diff --git a/packages/jest-cli/src/testResultHelpers.js b/packages/jest-cli/src/testResultHelpers.js index ad2c8c0fed47..8c3a97ce07c0 100644 --- a/packages/jest-cli/src/testResultHelpers.js +++ b/packages/jest-cli/src/testResultHelpers.js @@ -21,6 +21,7 @@ export const makeEmptyAggregatedTestResult = (): AggregatedResult => ({ numPendingTestSuites: 0, numPendingTests: 0, numRuntimeErrorTestSuites: 0, + numTodoTests: 0, numTotalTestSuites: 0, numTotalTests: 0, openHandles: [], @@ -57,6 +58,7 @@ export const buildFailureTestResult = ( numFailingTests: 0, numPassingTests: 0, numPendingTests: 0, + numTodoTests: 0, openHandles: [], perfStats: { end: 0, @@ -87,10 +89,12 @@ export const addResult = ( aggregatedResults.numTotalTests += testResult.numPassingTests + testResult.numFailingTests + - testResult.numPendingTests; + testResult.numPendingTests + + testResult.numTodoTests; aggregatedResults.numFailedTests += testResult.numFailingTests; aggregatedResults.numPassedTests += testResult.numPassingTests; aggregatedResults.numPendingTests += testResult.numPendingTests; + aggregatedResults.numTodoTests += testResult.numTodoTests; if (testResult.testExecError) { aggregatedResults.numRuntimeErrorTestSuites++; diff --git a/packages/jest-jasmine2/src/__tests__/it_test_error.test.js b/packages/jest-jasmine2/src/__tests__/it_test_error.test.js index 9f1727645ffd..54189045b767 100644 --- a/packages/jest-jasmine2/src/__tests__/it_test_error.test.js +++ b/packages/jest-jasmine2/src/__tests__/it_test_error.test.js @@ -12,7 +12,9 @@ describe('test/it error throwing', () => { it(`it throws error with missing callback function`, () => { expect(() => { it('test1'); - }).toThrowError('Missing second argument. It must be a callback function.'); + }).toThrowError( + 'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.', + ); }); it(`it throws an error when first argument isn't a string`, () => { expect(() => { @@ -29,7 +31,9 @@ describe('test/it error throwing', () => { test(`test throws error with missing callback function`, () => { expect(() => { test('test4'); - }).toThrowError('Missing second argument. It must be a callback function.'); + }).toThrowError( + 'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.', + ); }); test(`test throws an error when first argument isn't a string`, () => { expect(() => { diff --git a/packages/jest-jasmine2/src/__tests__/todo_error.test.js b/packages/jest-jasmine2/src/__tests__/todo_error.test.js new file mode 100644 index 000000000000..7d195e75f4a7 --- /dev/null +++ b/packages/jest-jasmine2/src/__tests__/todo_error.test.js @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +'use strict'; + +describe('test/it.todo error throwing', () => { + it('it throws error when given no arguments', () => { + expect(() => { + it.todo(); + }).toThrowError('Todo must be called with only a description.'); + }); + it('it throws error when given more than one argument', () => { + expect(() => { + it.todo('test1', () => {}); + }).toThrowError('Todo must be called with only a description.'); + }); + it('it throws error when given none string description', () => { + expect(() => { + it.todo(() => {}); + }).toThrowError('Todo must be called with only a description.'); + }); +}); diff --git a/packages/jest-jasmine2/src/index.js b/packages/jest-jasmine2/src/index.js index ca4e8f824b6b..b93eab79d10c 100644 --- a/packages/jest-jasmine2/src/index.js +++ b/packages/jest-jasmine2/src/index.js @@ -62,6 +62,7 @@ async function jasmine2( environment.global.test = environment.global.it; environment.global.it.only = environment.global.fit; + environment.global.it.todo = env.todo; environment.global.it.skip = environment.global.xit; environment.global.xtest = environment.global.xit; environment.global.describe.skip = environment.global.xdescribe; diff --git a/packages/jest-jasmine2/src/jasmine/Env.js b/packages/jest-jasmine2/src/jasmine/Env.js index d547c0a8f271..e464f0713669 100644 --- a/packages/jest-jasmine2/src/jasmine/Env.js +++ b/packages/jest-jasmine2/src/jasmine/Env.js @@ -328,6 +328,9 @@ export default function(j$) { if (currentDeclarationSuite.markedPending) { suite.pend(); } + if (currentDeclarationSuite.markedTodo) { + suite.todo(); + } addSpecsToSuite(suite, specDefinitions); return suite; }; @@ -450,7 +453,7 @@ export default function(j$) { } if (fn === undefined) { throw new Error( - 'Missing second argument. It must be a callback function.', + 'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.', ); } if (typeof fn !== 'function') { @@ -489,6 +492,24 @@ export default function(j$) { return spec; }; + this.todo = function() { + const description = arguments[0]; + if (arguments.length !== 1 || typeof description !== 'string') { + const e = new Error('Todo must be called with only a description.'); + + if (Error.captureStackTrace) { + Error.captureStackTrace(e, test.todo); + } + + throw e; + } + + const spec = specFactory(description, () => {}, currentDeclarationSuite); + spec.todo(); + currentDeclarationSuite.addChild(spec); + return spec; + }; + this.fit = function(description, fn, timeout) { const spec = specFactory( description, diff --git a/packages/jest-jasmine2/src/jasmine/Spec.js b/packages/jest-jasmine2/src/jasmine/Spec.js index 807c3c168f75..c7ab00dfe70e 100644 --- a/packages/jest-jasmine2/src/jasmine/Spec.js +++ b/packages/jest-jasmine2/src/jasmine/Spec.js @@ -103,7 +103,12 @@ Spec.prototype.execute = function(onComplete, enabled) { this.onStart(this); - if (!this.isExecutable() || this.markedPending || enabled === false) { + if ( + !this.isExecutable() || + this.markedPending || + this.markedTodo || + enabled === false + ) { complete(enabled); return; } @@ -175,6 +180,10 @@ Spec.prototype.pend = function(message) { } }; +Spec.prototype.todo = function() { + this.markedTodo = true; +}; + Spec.prototype.getResult = function() { this.result.status = this.status(); return this.result; @@ -185,6 +194,10 @@ Spec.prototype.status = function(enabled) { return 'disabled'; } + if (this.markedTodo) { + return 'todo'; + } + if (this.markedPending) { return 'pending'; } diff --git a/packages/jest-jasmine2/src/reporter.js b/packages/jest-jasmine2/src/reporter.js index ac1e37c67976..2a867736f29a 100644 --- a/packages/jest-jasmine2/src/reporter.js +++ b/packages/jest-jasmine2/src/reporter.js @@ -85,12 +85,15 @@ export default class Jasmine2Reporter { let numFailingTests = 0; let numPassingTests = 0; let numPendingTests = 0; + let numTodoTests = 0; const testResults = this._testResults; testResults.forEach(testResult => { if (testResult.status === 'failed') { numFailingTests++; } else if (testResult.status === 'pending') { numPendingTests++; + } else if (testResult.status === 'todo') { + numTodoTests++; } else { numPassingTests++; } @@ -107,6 +110,7 @@ export default class Jasmine2Reporter { numFailingTests, numPassingTests, numPendingTests, + numTodoTests, perfStats: { end: 0, start: 0, diff --git a/packages/jest-runner/src/run_test.js b/packages/jest-runner/src/run_test.js index 64ed00bb9261..d511c31c52c6 100644 --- a/packages/jest-runner/src/run_test.js +++ b/packages/jest-runner/src/run_test.js @@ -195,7 +195,10 @@ async function runTestInternal( } const testCount = - result.numPassingTests + result.numFailingTests + result.numPendingTests; + result.numPassingTests + + result.numFailingTests + + result.numPendingTests + + result.numTodoTests; result.perfStats = {end: Date.now(), start}; result.testFilePath = path; diff --git a/types/Circus.js b/types/Circus.js index 484afbde9656..7a95671f9460 100644 --- a/types/Circus.js +++ b/types/Circus.js @@ -10,7 +10,7 @@ export type DoneFn = (reason?: string | Error) => void; export type BlockFn = () => void; export type BlockName = string | Function; -export type BlockMode = void | 'skip' | 'only'; +export type BlockMode = void | 'skip' | 'only' | 'todo'; export type TestMode = BlockMode; export type TestName = string; export type TestFn = (done?: DoneFn) => ?Promise; @@ -105,6 +105,10 @@ export type Event = name: 'test_skip', test: TestEntry, |} + | {| + name: 'test_todo', + test: TestEntry, + |} | {| // test failure is defined by presence of errors in `test.errors`, // `test_done` indicates that the test and all its hooks were run, @@ -145,7 +149,7 @@ export type Event = name: 'teardown', |}; -export type TestStatus = 'skip' | 'done'; +export type TestStatus = 'skip' | 'done' | 'todo'; export type TestResult = {| duration: ?number, errors: Array, diff --git a/types/TestResult.js b/types/TestResult.js index b32bd15e9590..928dc0d280e8 100644 --- a/types/TestResult.js +++ b/types/TestResult.js @@ -83,7 +83,7 @@ export type AssertionLocation = {| path: string, |}; -export type Status = 'passed' | 'failed' | 'skipped' | 'pending'; +export type Status = 'passed' | 'failed' | 'skipped' | 'pending' | 'todo'; export type Bytes = number; export type Milliseconds = number; @@ -118,6 +118,7 @@ export type AggregatedResultWithoutCoverage = { numPassedTests: number, numPassedTestSuites: number, numPendingTests: number, + numTodoTests: number, numPendingTestSuites: number, numRuntimeErrorTestSuites: number, numTotalTests: number, @@ -150,6 +151,7 @@ export type TestResult = {| numFailingTests: number, numPassingTests: number, numPendingTests: number, + numTodoTests: number, openHandles: Array, perfStats: {| end: Milliseconds,