mirror of https://github.com/facebook/jest.git
Add test.todo (#6996)
This commit is contained in:
parent
15b43d6a27
commit
49b238046f
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
### Features
|
### 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))
|
- `[pretty-format]` Option to not escape strings in diff messages ([#5661](https://github.com/facebook/jest/pull/5661))
|
||||||
- `[jest-haste-map]` Add `getFileIterator` to `HasteFS` for faster file iteration ([#7010](https://github.com/facebook/jest/pull/7010)).
|
- `[jest-haste-map]` Add `getFileIterator` to `HasteFS` for faster file iteration ([#7010](https://github.com/facebook/jest/pull/7010)).
|
||||||
- `[jest-worker]` [**BREAKING**] Add functionality to call a `setup` method in the worker before the first call and a `teardown` method when ending the farm ([#7014](https://github.com/facebook/jest/pull/7014)).
|
- `[jest-worker]` [**BREAKING**] Add functionality to call a `setup` method in the worker before the first call and a `teardown` method when ending the farm ([#7014](https://github.com/facebook/jest/pull/7014)).
|
||||||
|
|
|
@ -655,3 +655,21 @@ test('will be ran', () => {
|
||||||
expect(1 / 0).toBe(Infinity);
|
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');
|
||||||
|
```
|
||||||
|
|
|
@ -23,7 +23,7 @@ exports[`cannot test with no implementation 1`] = `
|
||||||
"FAIL __tests__/only-constructs.test.js
|
"FAIL __tests__/only-constructs.test.js
|
||||||
● Test suite failed to run
|
● 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 |
|
1 |
|
||||||
2 | it('it', () => {});
|
2 | it('it', () => {});
|
||||||
|
@ -50,7 +50,7 @@ exports[`cannot test with no implementation with expand arg 1`] = `
|
||||||
"FAIL __tests__/only-constructs.test.js
|
"FAIL __tests__/only-constructs.test.js
|
||||||
● Test suite failed to run
|
● 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 |
|
1 |
|
||||||
2 | it('it', () => {});
|
2 | it('it', () => {});
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
"
|
||||||
|
`;
|
|
@ -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();
|
||||||
|
});
|
|
@ -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');
|
|
@ -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', () => {});
|
|
@ -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();
|
|
@ -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(() => {});
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"jest": {
|
||||||
|
"testEnvironment": "node"
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,7 +37,9 @@ describe('test/it error throwing', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
// $FlowFixMe: Easy, we're testing runitme errors here
|
// $FlowFixMe: Easy, we're testing runitme errors here
|
||||||
circusIt('test2');
|
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`, () => {
|
it(`it throws an error when first argument isn't a string`, () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
|
@ -62,7 +64,9 @@ describe('test/it error throwing', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
// $FlowFixMe: Easy, we're testing runitme errors here
|
// $FlowFixMe: Easy, we're testing runitme errors here
|
||||||
circusTest('test6');
|
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`, () => {
|
it(`test throws an error when first argument isn't a string`, () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
|
|
|
@ -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.');
|
||||||
|
});
|
||||||
|
});
|
|
@ -105,6 +105,10 @@ const handler: EventHandler = (event, state): void => {
|
||||||
event.test.status = 'skip';
|
event.test.status = 'skip';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'test_todo': {
|
||||||
|
event.test.status = 'todo';
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'test_done': {
|
case 'test_done': {
|
||||||
event.test.duration = getTestDuration(event.test);
|
event.test.duration = getTestDuration(event.test);
|
||||||
event.test.status = 'done';
|
event.test.status = 'done';
|
||||||
|
|
|
@ -68,7 +68,9 @@ const test = (testName: TestName, fn: TestFn, timeout?: number) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (fn === undefined) {
|
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') {
|
if (typeof fn !== 'function') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -121,6 +123,32 @@ test.only = (testName: TestName, fn: TestFn, timeout?: number) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test.todo = (testName: TestName, ...rest: Array<mixed>) => {
|
||||||
|
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.each = bindEach(test);
|
||||||
test.only.each = bindEach(test.only);
|
test.only.each = bindEach(test.only);
|
||||||
test.skip.each = bindEach(test.skip);
|
test.skip.each = bindEach(test.skip);
|
||||||
|
|
|
@ -128,12 +128,16 @@ export const runAndTransformResultsToJestFormat = async ({
|
||||||
let numFailingTests = 0;
|
let numFailingTests = 0;
|
||||||
let numPassingTests = 0;
|
let numPassingTests = 0;
|
||||||
let numPendingTests = 0;
|
let numPendingTests = 0;
|
||||||
|
let numTodoTests = 0;
|
||||||
|
|
||||||
const assertionResults = runResult.testResults.map(testResult => {
|
const assertionResults = runResult.testResults.map(testResult => {
|
||||||
let status: Status;
|
let status: Status;
|
||||||
if (testResult.status === 'skip') {
|
if (testResult.status === 'skip') {
|
||||||
status = 'pending';
|
status = 'pending';
|
||||||
numPendingTests += 1;
|
numPendingTests += 1;
|
||||||
|
} else if (testResult.status === 'todo') {
|
||||||
|
status = 'todo';
|
||||||
|
numTodoTests += 1;
|
||||||
} else if (testResult.errors.length) {
|
} else if (testResult.errors.length) {
|
||||||
status = 'failed';
|
status = 'failed';
|
||||||
numFailingTests += 1;
|
numFailingTests += 1;
|
||||||
|
@ -190,6 +194,7 @@ export const runAndTransformResultsToJestFormat = async ({
|
||||||
numFailingTests,
|
numFailingTests,
|
||||||
numPassingTests,
|
numPassingTests,
|
||||||
numPendingTests,
|
numPendingTests,
|
||||||
|
numTodoTests,
|
||||||
openHandles: [],
|
openHandles: [],
|
||||||
perfStats: {
|
perfStats: {
|
||||||
// populated outside
|
// populated outside
|
||||||
|
|
|
@ -97,6 +97,11 @@ const _runTest = async (test: TestEntry): Promise<void> => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (test.mode === 'todo') {
|
||||||
|
dispatch({name: 'test_todo', test});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const {afterEach, beforeEach} = getEachHooksForTest(test);
|
const {afterEach, beforeEach} = getEachHooksForTest(test);
|
||||||
|
|
||||||
for (const hook of beforeEach) {
|
for (const hook of beforeEach) {
|
||||||
|
|
|
@ -15,6 +15,7 @@ export const ICONS = {
|
||||||
failed: isWindows ? '\u00D7' : '\u2715',
|
failed: isWindows ? '\u00D7' : '\u2715',
|
||||||
pending: '\u25CB',
|
pending: '\u25CB',
|
||||||
success: isWindows ? '\u221A' : '\u2713',
|
success: isWindows ? '\u221A' : '\u2713',
|
||||||
|
todo: '\u270E',
|
||||||
};
|
};
|
||||||
export const PACKAGE_JSON = 'package.json';
|
export const PACKAGE_JSON = 'package.json';
|
||||||
export const JEST_CONFIG = 'jest.config.js';
|
export const JEST_CONFIG = 'jest.config.js';
|
||||||
|
|
|
@ -122,6 +122,7 @@ export const getSummary = (
|
||||||
const testsFailed = aggregatedResults.numFailedTests;
|
const testsFailed = aggregatedResults.numFailedTests;
|
||||||
const testsPassed = aggregatedResults.numPassedTests;
|
const testsPassed = aggregatedResults.numPassedTests;
|
||||||
const testsPending = aggregatedResults.numPendingTests;
|
const testsPending = aggregatedResults.numPendingTests;
|
||||||
|
const testsTodo = aggregatedResults.numTodoTests;
|
||||||
const testsTotal = aggregatedResults.numTotalTests;
|
const testsTotal = aggregatedResults.numTotalTests;
|
||||||
const width = (options && options.width) || 0;
|
const width = (options && options.width) || 0;
|
||||||
|
|
||||||
|
@ -141,6 +142,7 @@ export const getSummary = (
|
||||||
chalk.bold('Tests: ') +
|
chalk.bold('Tests: ') +
|
||||||
(testsFailed ? chalk.bold.red(`${testsFailed} failed`) + ', ' : '') +
|
(testsFailed ? chalk.bold.red(`${testsFailed} failed`) + ', ' : '') +
|
||||||
(testsPending ? chalk.bold.yellow(`${testsPending} skipped`) + ', ' : '') +
|
(testsPending ? chalk.bold.yellow(`${testsPending} skipped`) + ', ' : '') +
|
||||||
|
(testsTodo ? chalk.bold.magenta(`${testsTodo} todo`) + ', ' : '') +
|
||||||
(testsPassed ? chalk.bold.green(`${testsPassed} passed`) + ', ' : '') +
|
(testsPassed ? chalk.bold.green(`${testsPassed} passed`) + ', ' : '') +
|
||||||
`${testsTotal} total`;
|
`${testsTotal} total`;
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,8 @@ export default class VerboseReporter extends DefaultReporter {
|
||||||
return chalk.red(ICONS.failed);
|
return chalk.red(ICONS.failed);
|
||||||
} else if (status === 'pending') {
|
} else if (status === 'pending') {
|
||||||
return chalk.yellow(ICONS.pending);
|
return chalk.yellow(ICONS.pending);
|
||||||
|
} else if (status === 'todo') {
|
||||||
|
return chalk.magenta(ICONS.todo);
|
||||||
} else {
|
} else {
|
||||||
return chalk.green(ICONS.success);
|
return chalk.green(ICONS.success);
|
||||||
}
|
}
|
||||||
|
@ -112,26 +114,48 @@ export default class VerboseReporter extends DefaultReporter {
|
||||||
if (this._globalConfig.expand) {
|
if (this._globalConfig.expand) {
|
||||||
tests.forEach(test => this._logTest(test, indentLevel));
|
tests.forEach(test => this._logTest(test, indentLevel));
|
||||||
} else {
|
} else {
|
||||||
const skippedCount = tests.reduce((result, test) => {
|
const summedTests = tests.reduce(
|
||||||
if (test.status === 'pending') {
|
(result, test) => {
|
||||||
result += 1;
|
if (test.status === 'pending') {
|
||||||
} else {
|
result.pending += 1;
|
||||||
this._logTest(test, indentLevel);
|
} else if (test.status === 'todo') {
|
||||||
}
|
result.todo += 1;
|
||||||
|
} else {
|
||||||
|
this._logTest(test, indentLevel);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}, 0);
|
},
|
||||||
|
{pending: 0, todo: 0},
|
||||||
|
);
|
||||||
|
|
||||||
if (skippedCount > 0) {
|
if (summedTests.pending > 0) {
|
||||||
this._logSkippedTests(skippedCount, indentLevel);
|
this._logSummedTests(
|
||||||
|
'skipped',
|
||||||
|
this._getIcon('pending'),
|
||||||
|
summedTests.pending,
|
||||||
|
indentLevel,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (summedTests.todo > 0) {
|
||||||
|
this._logSummedTests(
|
||||||
|
'todo',
|
||||||
|
this._getIcon('todo'),
|
||||||
|
summedTests.todo,
|
||||||
|
indentLevel,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_logSkippedTests(count: number, indentLevel: number) {
|
_logSummedTests(
|
||||||
const icon = this._getIcon('pending');
|
prefix: string,
|
||||||
const text = chalk.dim(`skipped ${count} test${count === 1 ? '' : 's'}`);
|
icon: string,
|
||||||
|
count: number,
|
||||||
|
indentLevel: number,
|
||||||
|
) {
|
||||||
|
const text = chalk.dim(`${prefix} ${count} test${count === 1 ? '' : 's'}`);
|
||||||
this._logLine(`${icon} ${text}`, indentLevel);
|
this._logLine(`${icon} ${text}`, indentLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ export const makeEmptyAggregatedTestResult = (): AggregatedResult => ({
|
||||||
numPendingTestSuites: 0,
|
numPendingTestSuites: 0,
|
||||||
numPendingTests: 0,
|
numPendingTests: 0,
|
||||||
numRuntimeErrorTestSuites: 0,
|
numRuntimeErrorTestSuites: 0,
|
||||||
|
numTodoTests: 0,
|
||||||
numTotalTestSuites: 0,
|
numTotalTestSuites: 0,
|
||||||
numTotalTests: 0,
|
numTotalTests: 0,
|
||||||
openHandles: [],
|
openHandles: [],
|
||||||
|
@ -57,6 +58,7 @@ export const buildFailureTestResult = (
|
||||||
numFailingTests: 0,
|
numFailingTests: 0,
|
||||||
numPassingTests: 0,
|
numPassingTests: 0,
|
||||||
numPendingTests: 0,
|
numPendingTests: 0,
|
||||||
|
numTodoTests: 0,
|
||||||
openHandles: [],
|
openHandles: [],
|
||||||
perfStats: {
|
perfStats: {
|
||||||
end: 0,
|
end: 0,
|
||||||
|
@ -87,10 +89,12 @@ export const addResult = (
|
||||||
aggregatedResults.numTotalTests +=
|
aggregatedResults.numTotalTests +=
|
||||||
testResult.numPassingTests +
|
testResult.numPassingTests +
|
||||||
testResult.numFailingTests +
|
testResult.numFailingTests +
|
||||||
testResult.numPendingTests;
|
testResult.numPendingTests +
|
||||||
|
testResult.numTodoTests;
|
||||||
aggregatedResults.numFailedTests += testResult.numFailingTests;
|
aggregatedResults.numFailedTests += testResult.numFailingTests;
|
||||||
aggregatedResults.numPassedTests += testResult.numPassingTests;
|
aggregatedResults.numPassedTests += testResult.numPassingTests;
|
||||||
aggregatedResults.numPendingTests += testResult.numPendingTests;
|
aggregatedResults.numPendingTests += testResult.numPendingTests;
|
||||||
|
aggregatedResults.numTodoTests += testResult.numTodoTests;
|
||||||
|
|
||||||
if (testResult.testExecError) {
|
if (testResult.testExecError) {
|
||||||
aggregatedResults.numRuntimeErrorTestSuites++;
|
aggregatedResults.numRuntimeErrorTestSuites++;
|
||||||
|
|
|
@ -12,7 +12,9 @@ describe('test/it error throwing', () => {
|
||||||
it(`it throws error with missing callback function`, () => {
|
it(`it throws error with missing callback function`, () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
it('test1');
|
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`, () => {
|
it(`it throws an error when first argument isn't a string`, () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
|
@ -29,7 +31,9 @@ describe('test/it error throwing', () => {
|
||||||
test(`test throws error with missing callback function`, () => {
|
test(`test throws error with missing callback function`, () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
test('test4');
|
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`, () => {
|
test(`test throws an error when first argument isn't a string`, () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
|
|
|
@ -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.');
|
||||||
|
});
|
||||||
|
});
|
|
@ -62,6 +62,7 @@ async function jasmine2(
|
||||||
|
|
||||||
environment.global.test = environment.global.it;
|
environment.global.test = environment.global.it;
|
||||||
environment.global.it.only = environment.global.fit;
|
environment.global.it.only = environment.global.fit;
|
||||||
|
environment.global.it.todo = env.todo;
|
||||||
environment.global.it.skip = environment.global.xit;
|
environment.global.it.skip = environment.global.xit;
|
||||||
environment.global.xtest = environment.global.xit;
|
environment.global.xtest = environment.global.xit;
|
||||||
environment.global.describe.skip = environment.global.xdescribe;
|
environment.global.describe.skip = environment.global.xdescribe;
|
||||||
|
|
|
@ -330,6 +330,9 @@ export default function(j$) {
|
||||||
if (currentDeclarationSuite.markedPending) {
|
if (currentDeclarationSuite.markedPending) {
|
||||||
suite.pend();
|
suite.pend();
|
||||||
}
|
}
|
||||||
|
if (currentDeclarationSuite.markedTodo) {
|
||||||
|
suite.todo();
|
||||||
|
}
|
||||||
addSpecsToSuite(suite, specDefinitions);
|
addSpecsToSuite(suite, specDefinitions);
|
||||||
return suite;
|
return suite;
|
||||||
};
|
};
|
||||||
|
@ -452,7 +455,7 @@ export default function(j$) {
|
||||||
}
|
}
|
||||||
if (fn === undefined) {
|
if (fn === undefined) {
|
||||||
throw new Error(
|
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') {
|
if (typeof fn !== 'function') {
|
||||||
|
@ -491,6 +494,24 @@ export default function(j$) {
|
||||||
return spec;
|
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) {
|
this.fit = function(description, fn, timeout) {
|
||||||
const spec = specFactory(
|
const spec = specFactory(
|
||||||
description,
|
description,
|
||||||
|
|
|
@ -103,7 +103,12 @@ Spec.prototype.execute = function(onComplete, enabled) {
|
||||||
|
|
||||||
this.onStart(this);
|
this.onStart(this);
|
||||||
|
|
||||||
if (!this.isExecutable() || this.markedPending || enabled === false) {
|
if (
|
||||||
|
!this.isExecutable() ||
|
||||||
|
this.markedPending ||
|
||||||
|
this.markedTodo ||
|
||||||
|
enabled === false
|
||||||
|
) {
|
||||||
complete(enabled);
|
complete(enabled);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -175,6 +180,10 @@ Spec.prototype.pend = function(message) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Spec.prototype.todo = function() {
|
||||||
|
this.markedTodo = true;
|
||||||
|
};
|
||||||
|
|
||||||
Spec.prototype.getResult = function() {
|
Spec.prototype.getResult = function() {
|
||||||
this.result.status = this.status();
|
this.result.status = this.status();
|
||||||
return this.result;
|
return this.result;
|
||||||
|
@ -185,6 +194,10 @@ Spec.prototype.status = function(enabled) {
|
||||||
return 'disabled';
|
return 'disabled';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.markedTodo) {
|
||||||
|
return 'todo';
|
||||||
|
}
|
||||||
|
|
||||||
if (this.markedPending) {
|
if (this.markedPending) {
|
||||||
return 'pending';
|
return 'pending';
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,12 +85,15 @@ export default class Jasmine2Reporter {
|
||||||
let numFailingTests = 0;
|
let numFailingTests = 0;
|
||||||
let numPassingTests = 0;
|
let numPassingTests = 0;
|
||||||
let numPendingTests = 0;
|
let numPendingTests = 0;
|
||||||
|
let numTodoTests = 0;
|
||||||
const testResults = this._testResults;
|
const testResults = this._testResults;
|
||||||
testResults.forEach(testResult => {
|
testResults.forEach(testResult => {
|
||||||
if (testResult.status === 'failed') {
|
if (testResult.status === 'failed') {
|
||||||
numFailingTests++;
|
numFailingTests++;
|
||||||
} else if (testResult.status === 'pending') {
|
} else if (testResult.status === 'pending') {
|
||||||
numPendingTests++;
|
numPendingTests++;
|
||||||
|
} else if (testResult.status === 'todo') {
|
||||||
|
numTodoTests++;
|
||||||
} else {
|
} else {
|
||||||
numPassingTests++;
|
numPassingTests++;
|
||||||
}
|
}
|
||||||
|
@ -107,6 +110,7 @@ export default class Jasmine2Reporter {
|
||||||
numFailingTests,
|
numFailingTests,
|
||||||
numPassingTests,
|
numPassingTests,
|
||||||
numPendingTests,
|
numPendingTests,
|
||||||
|
numTodoTests,
|
||||||
perfStats: {
|
perfStats: {
|
||||||
end: 0,
|
end: 0,
|
||||||
start: 0,
|
start: 0,
|
||||||
|
|
|
@ -195,7 +195,10 @@ async function runTestInternal(
|
||||||
}
|
}
|
||||||
|
|
||||||
const testCount =
|
const testCount =
|
||||||
result.numPassingTests + result.numFailingTests + result.numPendingTests;
|
result.numPassingTests +
|
||||||
|
result.numFailingTests +
|
||||||
|
result.numPendingTests +
|
||||||
|
result.numTodoTests;
|
||||||
|
|
||||||
result.perfStats = {end: Date.now(), start};
|
result.perfStats = {end: Date.now(), start};
|
||||||
result.testFilePath = path;
|
result.testFilePath = path;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
export type DoneFn = (reason?: string | Error) => void;
|
export type DoneFn = (reason?: string | Error) => void;
|
||||||
export type BlockFn = () => void;
|
export type BlockFn = () => void;
|
||||||
export type BlockName = string | Function;
|
export type BlockName = string | Function;
|
||||||
export type BlockMode = void | 'skip' | 'only';
|
export type BlockMode = void | 'skip' | 'only' | 'todo';
|
||||||
export type TestMode = BlockMode;
|
export type TestMode = BlockMode;
|
||||||
export type TestName = string;
|
export type TestName = string;
|
||||||
export type TestFn = (done?: DoneFn) => ?Promise<any>;
|
export type TestFn = (done?: DoneFn) => ?Promise<any>;
|
||||||
|
@ -105,6 +105,10 @@ export type Event =
|
||||||
name: 'test_skip',
|
name: 'test_skip',
|
||||||
test: TestEntry,
|
test: TestEntry,
|
||||||
|}
|
|}
|
||||||
|
| {|
|
||||||
|
name: 'test_todo',
|
||||||
|
test: TestEntry,
|
||||||
|
|}
|
||||||
| {|
|
| {|
|
||||||
// test failure is defined by presence of errors in `test.errors`,
|
// test failure is defined by presence of errors in `test.errors`,
|
||||||
// `test_done` indicates that the test and all its hooks were run,
|
// `test_done` indicates that the test and all its hooks were run,
|
||||||
|
@ -145,7 +149,7 @@ export type Event =
|
||||||
name: 'teardown',
|
name: 'teardown',
|
||||||
|};
|
|};
|
||||||
|
|
||||||
export type TestStatus = 'skip' | 'done';
|
export type TestStatus = 'skip' | 'done' | 'todo';
|
||||||
export type TestResult = {|
|
export type TestResult = {|
|
||||||
duration: ?number,
|
duration: ?number,
|
||||||
errors: Array<FormattedError>,
|
errors: Array<FormattedError>,
|
||||||
|
|
|
@ -83,7 +83,7 @@ export type AssertionLocation = {|
|
||||||
path: string,
|
path: string,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
export type Status = 'passed' | 'failed' | 'skipped' | 'pending';
|
export type Status = 'passed' | 'failed' | 'skipped' | 'pending' | 'todo';
|
||||||
|
|
||||||
export type Bytes = number;
|
export type Bytes = number;
|
||||||
export type Milliseconds = number;
|
export type Milliseconds = number;
|
||||||
|
@ -118,6 +118,7 @@ export type AggregatedResultWithoutCoverage = {
|
||||||
numPassedTests: number,
|
numPassedTests: number,
|
||||||
numPassedTestSuites: number,
|
numPassedTestSuites: number,
|
||||||
numPendingTests: number,
|
numPendingTests: number,
|
||||||
|
numTodoTests: number,
|
||||||
numPendingTestSuites: number,
|
numPendingTestSuites: number,
|
||||||
numRuntimeErrorTestSuites: number,
|
numRuntimeErrorTestSuites: number,
|
||||||
numTotalTests: number,
|
numTotalTests: number,
|
||||||
|
@ -150,6 +151,7 @@ export type TestResult = {|
|
||||||
numFailingTests: number,
|
numFailingTests: number,
|
||||||
numPassingTests: number,
|
numPassingTests: number,
|
||||||
numPendingTests: number,
|
numPendingTests: number,
|
||||||
|
numTodoTests: number,
|
||||||
openHandles: Array<Error>,
|
openHandles: Array<Error>,
|
||||||
perfStats: {|
|
perfStats: {|
|
||||||
end: Milliseconds,
|
end: Milliseconds,
|
||||||
|
|
Loading…
Reference in New Issue