From e99dd90719a44c5e75c4791c68912ce9b98a5d2f Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Tue, 19 Jun 2018 18:44:36 -0400 Subject: [PATCH 01/13] Enable configurable retries for failed test cases --- .../jest_adapter_init.js | 2 +- packages/jest-circus/src/run.js | 19 +++++++++++++++---- packages/jest-cli/src/cli/args.js | 15 ++++++++++++++- packages/jest-config/src/defaults.js | 1 + packages/jest-config/src/index.js | 2 ++ packages/jest-config/src/normalize.js | 2 ++ packages/jest-config/src/valid_config.js | 1 + types/Argv.js | 1 + types/Config.js | 4 ++++ 9 files changed, 41 insertions(+), 6 deletions(-) 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 6a1e50f8614a..19b6a8895b2b 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 @@ -108,7 +108,7 @@ export const runAndTransformResultsToJestFormat = async ({ globalConfig: GlobalConfig, testPath: string, }): Promise => { - const runResult = await run(); + const runResult = await run(globalConfig.testRetries); let numFailingTests = 0; let numPassingTests = 0; diff --git a/packages/jest-circus/src/run.js b/packages/jest-circus/src/run.js index b929757c43de..812cd17df92e 100644 --- a/packages/jest-circus/src/run.js +++ b/packages/jest-circus/src/run.js @@ -28,10 +28,10 @@ import { const Promise = getOriginalPromise(); -const run = async (): Promise => { +const run = async (numRetries: number): Promise => { const {rootDescribeBlock} = getState(); dispatch({name: 'run_start'}); - await _runTestsForDescribeBlock(rootDescribeBlock); + await _runTestsForDescribeBlock(rootDescribeBlock, numRetries); dispatch({name: 'run_finish'}); return makeRunResult( getState().rootDescribeBlock, @@ -39,19 +39,30 @@ const run = async (): Promise => { ); }; -const _runTestsForDescribeBlock = async (describeBlock: DescribeBlock) => { +const _runTestsForDescribeBlock = async ( + describeBlock: DescribeBlock, + numRetries: number, +) => { dispatch({describeBlock, name: 'run_describe_start'}); const {beforeAll, afterAll} = getAllHooksForDescribe(describeBlock); for (const hook of beforeAll) { await _callHook({describeBlock, hook}); } + for (const test of describeBlock.tests) { + let numRetriesAvailable = numRetries; + await _runTest(test); + + while (numRetriesAvailable > 0 && test.errors.length > 0) { + await _runTest(test); + numRetriesAvailable--; + } } for (const child of describeBlock.children) { - await _runTestsForDescribeBlock(child); + await _runTestsForDescribeBlock(child, numRetries); } for (const hook of afterAll) { diff --git a/packages/jest-cli/src/cli/args.js b/packages/jest-cli/src/cli/args.js index 6ecb7597daa3..1ba0ddc722c6 100644 --- a/packages/jest-cli/src/cli/args.js +++ b/packages/jest-cli/src/cli/args.js @@ -51,6 +51,14 @@ export const check = (argv: Argv) => { ); } + const intRetries = parseInt(argv.testRetries, 10); + if (isNaN(intRetries) || intRetries < 0) { + throw new Error( + 'The --testRetries option requires a positive integer to be specified.\n' + + 'Example usage: jest --testRetries=3', + ); + } + if ( argv.config && !isJSONString(argv.config) && @@ -578,9 +586,14 @@ export const options = { description: 'Allows the use of a custom results processor. ' + 'This processor must be a node module that exports ' + - 'a function expecting as the first argument the result object', + 'a function expecting as the first argument the result object.', type: 'string', }, + testRetries: { + default: 0, + description: 'Allows failed tests to be retried n-times automatically.', + type: 'number', + }, testRunner: { description: 'Allows to specify a custom test runner. The default is ' + diff --git a/packages/jest-config/src/defaults.js b/packages/jest-config/src/defaults.js index 8fc32221d1ff..10b1f3f7dd30 100644 --- a/packages/jest-config/src/defaults.js +++ b/packages/jest-config/src/defaults.js @@ -70,6 +70,7 @@ export default ({ testPathIgnorePatterns: [NODE_MODULES_REGEXP], testRegex: '', testResultsProcessor: null, + testRetries: 0, testRunner: 'jasmine2', testURL: 'about:blank', timers: 'real', diff --git a/packages/jest-config/src/index.js b/packages/jest-config/src/index.js index e41f728a0d53..2d529ca631e2 100644 --- a/packages/jest-config/src/index.js +++ b/packages/jest-config/src/index.js @@ -142,6 +142,7 @@ const getConfigs = ( testNamePattern: options.testNamePattern, testPathPattern: options.testPathPattern, testResultsProcessor: options.testResultsProcessor, + testRetries: options.testRetries, updateSnapshot: options.updateSnapshot, useStderr: options.useStderr, verbose: options.verbose, @@ -191,6 +192,7 @@ const getConfigs = ( testMatch: options.testMatch, testPathIgnorePatterns: options.testPathIgnorePatterns, testRegex: options.testRegex, + testRetries: options.testRetries, testRunner: options.testRunner, testURL: options.testURL, timers: options.timers, diff --git a/packages/jest-config/src/normalize.js b/packages/jest-config/src/normalize.js index 56147c042584..ba1117874f31 100644 --- a/packages/jest-config/src/normalize.js +++ b/packages/jest-config/src/normalize.js @@ -552,6 +552,7 @@ export default function normalize(options: InitialOptions, argv: Argv) { case 'testFailureExitCode': case 'testLocationInResults': case 'testNamePattern': + case 'testRetries': case 'testURL': case 'timers': case 'useStderr': @@ -576,6 +577,7 @@ export default function normalize(options: InitialOptions, argv: Argv) { newOptions.json = argv.json; newOptions.testFailureExitCode = parseInt(newOptions.testFailureExitCode, 10); + newOptions.testRetries = parseInt(newOptions.testRetries, 10); for (const key of [ 'lastCommit', diff --git a/packages/jest-config/src/valid_config.js b/packages/jest-config/src/valid_config.js index 1c5372c05b0a..3454a9cd87e3 100644 --- a/packages/jest-config/src/valid_config.js +++ b/packages/jest-config/src/valid_config.js @@ -94,6 +94,7 @@ export default ({ testPathIgnorePatterns: [NODE_MODULES_REGEXP], testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$', testResultsProcessor: 'processor-node-module', + testRetries: 0, testRunner: 'jasmine2', testURL: 'about:blank', timers: 'real', diff --git a/types/Argv.js b/types/Argv.js index ef157f155dfd..0611a536ad83 100644 --- a/types/Argv.js +++ b/types/Argv.js @@ -83,6 +83,7 @@ export type Argv = {| testPathPattern: Array, testRegex: string, testResultsProcessor: ?string, + testRetries: ?string, testRunner: string, testURL: string, timers: 'real' | 'fake', diff --git a/types/Config.js b/types/Config.js index db18796f5ecc..d6ac89de54ff 100644 --- a/types/Config.js +++ b/types/Config.js @@ -74,6 +74,7 @@ export type DefaultOptions = {| testPathIgnorePatterns: Array, testRegex: string, testResultsProcessor: ?string, + testRetries: string | number, testRunner: ?string, testURL: string, timers: 'real' | 'fake', @@ -163,6 +164,7 @@ export type InitialOptions = { testPathIgnorePatterns?: Array, testRegex?: string, testResultsProcessor?: ?string, + testRetries?: string | number, testRunner?: string, testURL?: string, timers?: 'real' | 'fake', @@ -227,6 +229,7 @@ export type GlobalConfig = {| testNamePattern: string, testPathPattern: string, testResultsProcessor: ?string, + testRetries: number, updateSnapshot: SnapshotUpdateState, useStderr: boolean, verbose: ?boolean, @@ -277,6 +280,7 @@ export type ProjectConfig = {| testLocationInResults: boolean, testPathIgnorePatterns: Array, testRegex: string, + testRetries: ?string, testRunner: string, testURL: string, timers: 'real' | 'fake', From b265a8b00d628415a32e036b2a052958b9ff5373 Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Tue, 19 Jun 2018 19:09:08 -0400 Subject: [PATCH 02/13] Update tests --- TestUtils.js | 2 ++ e2e/__tests__/__snapshots__/show_config.test.js.snap | 2 ++ packages/jest-cli/src/cli/args.js | 5 ++++- types/Argv.js | 2 +- types/Config.js | 6 +++--- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/TestUtils.js b/TestUtils.js index c92b4ba9ae60..32e3011e65b2 100644 --- a/TestUtils.js +++ b/TestUtils.js @@ -56,6 +56,7 @@ const DEFAULT_GLOBAL_CONFIG: GlobalConfig = { testNamePattern: '', testPathPattern: '', testResultsProcessor: null, + testRetries: 0, updateSnapshot: 'none', useStderr: false, verbose: false, @@ -108,6 +109,7 @@ const DEFAULT_PROJECT_CONFIG: ProjectConfig = { testMatch: [], testPathIgnorePatterns: [], testRegex: '.test.js$', + testRetries: 0, testRunner: 'jest-jasmine2', testURL: '', timers: 'real', diff --git a/e2e/__tests__/__snapshots__/show_config.test.js.snap b/e2e/__tests__/__snapshots__/show_config.test.js.snap index 04b1d7f17d90..4fc4a627ba38 100644 --- a/e2e/__tests__/__snapshots__/show_config.test.js.snap +++ b/e2e/__tests__/__snapshots__/show_config.test.js.snap @@ -57,6 +57,7 @@ exports[`--showConfig outputs config info and exits 1`] = ` \\"/node_modules/\\" ], \\"testRegex\\": \\"\\", + \\"testRetries\\": 0, \\"testRunner\\": \\"<>/jest-jasmine2/build/index.js\\", \\"testURL\\": \\"about:blank\\", \\"timers\\": \\"real\\", @@ -106,6 +107,7 @@ exports[`--showConfig outputs config info and exits 1`] = ` \\"testFailureExitCode\\": 1, \\"testPathPattern\\": \\"\\", \\"testResultsProcessor\\": null, + \\"testRetries\\": 0, \\"updateSnapshot\\": \\"all\\", \\"useStderr\\": false, \\"verbose\\": null, diff --git a/packages/jest-cli/src/cli/args.js b/packages/jest-cli/src/cli/args.js index 1ba0ddc722c6..89ef120b012c 100644 --- a/packages/jest-cli/src/cli/args.js +++ b/packages/jest-cli/src/cli/args.js @@ -52,7 +52,10 @@ export const check = (argv: Argv) => { } const intRetries = parseInt(argv.testRetries, 10); - if (isNaN(intRetries) || intRetries < 0) { + if ( + (argv.hasOwnProperty('testRetries') && isNaN(intRetries)) || + intRetries < 0 + ) { throw new Error( 'The --testRetries option requires a positive integer to be specified.\n' + 'Example usage: jest --testRetries=3', diff --git a/types/Argv.js b/types/Argv.js index 0611a536ad83..f6254cc92cc5 100644 --- a/types/Argv.js +++ b/types/Argv.js @@ -83,7 +83,7 @@ export type Argv = {| testPathPattern: Array, testRegex: string, testResultsProcessor: ?string, - testRetries: ?string, + testRetries: number, testRunner: string, testURL: string, timers: 'real' | 'fake', diff --git a/types/Config.js b/types/Config.js index d6ac89de54ff..9ab07881a8d0 100644 --- a/types/Config.js +++ b/types/Config.js @@ -74,7 +74,7 @@ export type DefaultOptions = {| testPathIgnorePatterns: Array, testRegex: string, testResultsProcessor: ?string, - testRetries: string | number, + testRetries: ?number, testRunner: ?string, testURL: string, timers: 'real' | 'fake', @@ -164,7 +164,7 @@ export type InitialOptions = { testPathIgnorePatterns?: Array, testRegex?: string, testResultsProcessor?: ?string, - testRetries?: string | number, + testRetries?: ?number, testRunner?: string, testURL?: string, timers?: 'real' | 'fake', @@ -280,7 +280,7 @@ export type ProjectConfig = {| testLocationInResults: boolean, testPathIgnorePatterns: Array, testRegex: string, - testRetries: ?string, + testRetries: number, testRunner: string, testURL: string, timers: 'real' | 'fake', From ee92c9572dc64382e988a04dc2fdf15f073f1535 Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Thu, 21 Jun 2018 11:48:53 -0400 Subject: [PATCH 03/13] Remove testRetries CLI and config option. Add as jest.retryTimes with reporter integration. --- TestUtils.js | 2 - .../__snapshots__/show_config.test.js.snap | 2 - .../__snapshots__/snapshot.test.js.snap | 12 ++-- e2e/__tests__/snapshot.test.js | 2 +- e2e/__tests__/test_retries.test.js | 62 +++++++++++++++++++ .../__tests__/snapshot.test.js | 1 + e2e/test-retries/__tests__/noretry.test.js | 11 ++++ e2e/test-retries/__tests__/retry.test.js | 13 ++++ e2e/test-retries/package.json | 5 ++ e2e/test-retries/reporters/RetryReporter.js | 30 +++++++++ packages/jest-circus/src/event_handler.js | 1 + .../jest_adapter_init.js | 3 +- packages/jest-circus/src/run.js | 26 +++++--- packages/jest-circus/src/utils.js | 2 + packages/jest-cli/src/cli/args.js | 16 ----- packages/jest-config/src/defaults.js | 1 - packages/jest-config/src/index.js | 2 - packages/jest-config/src/normalize.js | 2 - packages/jest-config/src/valid_config.js | 1 - packages/jest-runtime/src/index.js | 6 ++ types/Argv.js | 1 - types/Circus.js | 1 + types/Config.js | 4 -- types/Jest.js | 1 + 24 files changed, 159 insertions(+), 48 deletions(-) create mode 100644 e2e/__tests__/test_retries.test.js create mode 100644 e2e/test-retries/__tests__/noretry.test.js create mode 100644 e2e/test-retries/__tests__/retry.test.js create mode 100644 e2e/test-retries/package.json create mode 100644 e2e/test-retries/reporters/RetryReporter.js diff --git a/TestUtils.js b/TestUtils.js index 32e3011e65b2..c92b4ba9ae60 100644 --- a/TestUtils.js +++ b/TestUtils.js @@ -56,7 +56,6 @@ const DEFAULT_GLOBAL_CONFIG: GlobalConfig = { testNamePattern: '', testPathPattern: '', testResultsProcessor: null, - testRetries: 0, updateSnapshot: 'none', useStderr: false, verbose: false, @@ -109,7 +108,6 @@ const DEFAULT_PROJECT_CONFIG: ProjectConfig = { testMatch: [], testPathIgnorePatterns: [], testRegex: '.test.js$', - testRetries: 0, testRunner: 'jest-jasmine2', testURL: '', timers: 'real', diff --git a/e2e/__tests__/__snapshots__/show_config.test.js.snap b/e2e/__tests__/__snapshots__/show_config.test.js.snap index 4fc4a627ba38..04b1d7f17d90 100644 --- a/e2e/__tests__/__snapshots__/show_config.test.js.snap +++ b/e2e/__tests__/__snapshots__/show_config.test.js.snap @@ -57,7 +57,6 @@ exports[`--showConfig outputs config info and exits 1`] = ` \\"/node_modules/\\" ], \\"testRegex\\": \\"\\", - \\"testRetries\\": 0, \\"testRunner\\": \\"<>/jest-jasmine2/build/index.js\\", \\"testURL\\": \\"about:blank\\", \\"timers\\": \\"real\\", @@ -107,7 +106,6 @@ exports[`--showConfig outputs config info and exits 1`] = ` \\"testFailureExitCode\\": 1, \\"testPathPattern\\": \\"\\", \\"testResultsProcessor\\": null, - \\"testRetries\\": 0, \\"updateSnapshot\\": \\"all\\", \\"useStderr\\": false, \\"verbose\\": null, diff --git a/e2e/__tests__/__snapshots__/snapshot.test.js.snap b/e2e/__tests__/__snapshots__/snapshot.test.js.snap index 7d07b4330396..c1ec5378d06e 100644 --- a/e2e/__tests__/__snapshots__/snapshot.test.js.snap +++ b/e2e/__tests__/__snapshots__/snapshot.test.js.snap @@ -83,24 +83,24 @@ Ran all test suites." exports[`Snapshot works with escaped characters 1`] = ` "Test Suites: 1 passed, 1 total -Tests: 1 passed, 1 total -Snapshots: 1 written, 1 total +Tests: 2 passed, 2 total +Snapshots: 2 written, 2 total Time: <> Ran all test suites matching /snapshot.test.js/i." `; exports[`Snapshot works with escaped characters 2`] = ` "Test Suites: 1 passed, 1 total -Tests: 2 passed, 2 total -Snapshots: 1 written, 1 passed, 2 total +Tests: 3 passed, 3 total +Snapshots: 1 written, 2 passed, 3 total Time: <> Ran all test suites matching /snapshot.test.js/i." `; exports[`Snapshot works with escaped characters 3`] = ` "Test Suites: 1 passed, 1 total -Tests: 2 passed, 2 total -Snapshots: 2 passed, 2 total +Tests: 3 passed, 3 total +Snapshots: 3 passed, 3 total Time: <> Ran all test suites matching /snapshot.test.js/i." `; diff --git a/e2e/__tests__/snapshot.test.js b/e2e/__tests__/snapshot.test.js index 4a63d2a3e94b..008d2865b245 100644 --- a/e2e/__tests__/snapshot.test.js +++ b/e2e/__tests__/snapshot.test.js @@ -128,7 +128,7 @@ describe('Snapshot', () => { ]); let stderr = result.stderr; - expect(stderr).toMatch('1 snapshot written'); + expect(stderr).toMatch('2 snapshots written'); expect(result.status).toBe(0); expect(extractSummary(stderr).summary).toMatchSnapshot(); diff --git a/e2e/__tests__/test_retries.test.js b/e2e/__tests__/test_retries.test.js new file mode 100644 index 000000000000..71bfe96f5c0d --- /dev/null +++ b/e2e/__tests__/test_retries.test.js @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2014-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 fs = require('fs'); +const path = require('path'); +const runJest = require('../runJest'); + +describe('Test Retries', () => { + const outputFileName = 'retries.result.json'; + const outputFilePath = path.join( + process.cwd(), + 'e2e/test-retries/', + outputFileName, + ); + + afterAll(() => { + fs.unlinkSync(outputFilePath); + }); + + it('retries failed tests if configured', () => { + let jsonResult; + + const reporterConfig = { + reporters: [ + ['/reporters/RetryReporter.js', {output: outputFilePath}], + ], + }; + + // Test retries only available via JEST_CIRCUS + // also testResults.invocations only available via JEST_CIRCUS + process.env.JEST_CIRCUS = '1'; + + runJest('test-retries', [ + '--config', + JSON.stringify(reporterConfig), + 'retry.test.js', + ]); + + const testOutput = fs.readFileSync(outputFilePath, 'utf8'); + + try { + jsonResult = JSON.parse(testOutput); + } catch (err) { + throw new Error( + `Can't parse the JSON result from ${outputFileName}, ${err.toString()}`, + ); + } + + expect(jsonResult.numPassedTests).toBe(0); + expect(jsonResult.numFailedTests).toBe(2); + expect(jsonResult.numPendingTests).toBe(0); + expect(jsonResult.testResults[0].testResults[0].invocations).toBe(4); + expect(jsonResult.testResults[1].testResults[0].invocations).toBe(1); + }); +}); diff --git a/e2e/snapshot-escape/__tests__/snapshot.test.js b/e2e/snapshot-escape/__tests__/snapshot.test.js index 4aa41bf14a73..f2141a8e9291 100644 --- a/e2e/snapshot-escape/__tests__/snapshot.test.js +++ b/e2e/snapshot-escape/__tests__/snapshot.test.js @@ -8,3 +8,4 @@ // prettier-ignore test('escape strings', () => expect('one: \\\'').toMatchSnapshot()); +test('escape strings two', () => expect('two: \'"').toMatchSnapshot()); \ No newline at end of file diff --git a/e2e/test-retries/__tests__/noretry.test.js b/e2e/test-retries/__tests__/noretry.test.js new file mode 100644 index 000000000000..6943fbdb844e --- /dev/null +++ b/e2e/test-retries/__tests__/noretry.test.js @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2014-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'; + +it('retryTimes not set', () => { + expect(true).toBeFalsy(); +}); diff --git a/e2e/test-retries/__tests__/retry.test.js b/e2e/test-retries/__tests__/retry.test.js new file mode 100644 index 000000000000..187ca0227723 --- /dev/null +++ b/e2e/test-retries/__tests__/retry.test.js @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2014-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'; + +jest.retryTimes(3); + +it('retryTimes set', () => { + expect(true).toBeFalsy(); +}); diff --git a/e2e/test-retries/package.json b/e2e/test-retries/package.json new file mode 100644 index 000000000000..148788b25446 --- /dev/null +++ b/e2e/test-retries/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "testEnvironment": "node" + } +} diff --git a/e2e/test-retries/reporters/RetryReporter.js b/e2e/test-retries/reporters/RetryReporter.js new file mode 100644 index 000000000000..d2bb466e9a2d --- /dev/null +++ b/e2e/test-retries/reporters/RetryReporter.js @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2014-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'; + +const fs = require('fs'); + +/** + * RetryReporter + * Reporter for testing output of onRunComplete + */ +class RetryReporter { + constructor(globalConfig, options) { + this._options = options; + } + + onRunComplete(contexts, results) { + if (this._options.output) { + fs.writeFileSync(this._options.output, JSON.stringify(results, null, 2), { + encoding: 'utf8', + }); + } + } +} + +module.exports = RetryReporter; diff --git a/packages/jest-circus/src/event_handler.js b/packages/jest-circus/src/event_handler.js index 23782bf028e5..c30537c14e77 100644 --- a/packages/jest-circus/src/event_handler.js +++ b/packages/jest-circus/src/event_handler.js @@ -114,6 +114,7 @@ const handler: EventHandler = (event, state): void => { case 'test_start': { state.currentlyRunningTest = event.test; event.test.startedAt = Date.now(); + event.test.invocations += 1; break; } case 'test_fn_failure': { 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 19b6a8895b2b..4fc29a28d48a 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 @@ -108,7 +108,7 @@ export const runAndTransformResultsToJestFormat = async ({ globalConfig: GlobalConfig, testPath: string, }): Promise => { - const runResult = await run(globalConfig.testRetries); + const runResult = await run(); let numFailingTests = 0; let numPassingTests = 0; @@ -137,6 +137,7 @@ export const runAndTransformResultsToJestFormat = async ({ duration: testResult.duration, failureMessages: testResult.errors, fullName: ancestorTitles.concat(title).join(' '), + invocations: testResult.invocations, location: testResult.location, numPassingAsserts: 0, status, diff --git a/packages/jest-circus/src/run.js b/packages/jest-circus/src/run.js index 812cd17df92e..2d0146e97493 100644 --- a/packages/jest-circus/src/run.js +++ b/packages/jest-circus/src/run.js @@ -28,10 +28,10 @@ import { const Promise = getOriginalPromise(); -const run = async (numRetries: number): Promise => { +const run = async (): Promise => { const {rootDescribeBlock} = getState(); dispatch({name: 'run_start'}); - await _runTestsForDescribeBlock(rootDescribeBlock, numRetries); + await _runTestsForDescribeBlock(rootDescribeBlock); dispatch({name: 'run_finish'}); return makeRunResult( getState().rootDescribeBlock, @@ -39,10 +39,7 @@ const run = async (numRetries: number): Promise => { ); }; -const _runTestsForDescribeBlock = async ( - describeBlock: DescribeBlock, - numRetries: number, -) => { +const _runTestsForDescribeBlock = async (describeBlock: DescribeBlock) => { dispatch({describeBlock, name: 'run_describe_start'}); const {beforeAll, afterAll} = getAllHooksForDescribe(describeBlock); @@ -50,11 +47,22 @@ const _runTestsForDescribeBlock = async ( await _callHook({describeBlock, hook}); } - for (const test of describeBlock.tests) { - let numRetriesAvailable = numRetries; + // Tests that fail and are retried we run after other tests + const retryTimes = parseInt(global.retryTimes, 10) || 0; + const deferredRetryTests = []; + for (const test of describeBlock.tests) { await _runTest(test); + if (retryTimes > 0 && test.errors.length > 0) { + deferredRetryTests.push(test); + } + } + + // Re-run failed tests n-times if configured + for (const test of deferredRetryTests) { + let numRetriesAvailable = retryTimes; + while (numRetriesAvailable > 0 && test.errors.length > 0) { await _runTest(test); numRetriesAvailable--; @@ -62,7 +70,7 @@ const _runTestsForDescribeBlock = async ( } for (const child of describeBlock.children) { - await _runTestsForDescribeBlock(child, numRetries); + await _runTestsForDescribeBlock(child); } for (const hook of afterAll) { diff --git a/packages/jest-circus/src/utils.js b/packages/jest-circus/src/utils.js index f2ecfcf4a708..eda159eb7d74 100644 --- a/packages/jest-circus/src/utils.js +++ b/packages/jest-circus/src/utils.js @@ -80,6 +80,7 @@ export const makeTest = ( duration: null, errors: [], fn, + invocations: 0, mode: _mode, name: convertDescriptorToString(name), parent, @@ -276,6 +277,7 @@ const makeTestResults = (describeBlock: DescribeBlock, config): TestResults => { testResults.push({ duration: test.duration, errors: test.errors.map(_formatError), + invocations: test.invocations, location, status, testPath, diff --git a/packages/jest-cli/src/cli/args.js b/packages/jest-cli/src/cli/args.js index 89ef120b012c..b12f0a6c84a2 100644 --- a/packages/jest-cli/src/cli/args.js +++ b/packages/jest-cli/src/cli/args.js @@ -51,17 +51,6 @@ export const check = (argv: Argv) => { ); } - const intRetries = parseInt(argv.testRetries, 10); - if ( - (argv.hasOwnProperty('testRetries') && isNaN(intRetries)) || - intRetries < 0 - ) { - throw new Error( - 'The --testRetries option requires a positive integer to be specified.\n' + - 'Example usage: jest --testRetries=3', - ); - } - if ( argv.config && !isJSONString(argv.config) && @@ -592,11 +581,6 @@ export const options = { 'a function expecting as the first argument the result object.', type: 'string', }, - testRetries: { - default: 0, - description: 'Allows failed tests to be retried n-times automatically.', - type: 'number', - }, testRunner: { description: 'Allows to specify a custom test runner. The default is ' + diff --git a/packages/jest-config/src/defaults.js b/packages/jest-config/src/defaults.js index 10b1f3f7dd30..8fc32221d1ff 100644 --- a/packages/jest-config/src/defaults.js +++ b/packages/jest-config/src/defaults.js @@ -70,7 +70,6 @@ export default ({ testPathIgnorePatterns: [NODE_MODULES_REGEXP], testRegex: '', testResultsProcessor: null, - testRetries: 0, testRunner: 'jasmine2', testURL: 'about:blank', timers: 'real', diff --git a/packages/jest-config/src/index.js b/packages/jest-config/src/index.js index 2d529ca631e2..e41f728a0d53 100644 --- a/packages/jest-config/src/index.js +++ b/packages/jest-config/src/index.js @@ -142,7 +142,6 @@ const getConfigs = ( testNamePattern: options.testNamePattern, testPathPattern: options.testPathPattern, testResultsProcessor: options.testResultsProcessor, - testRetries: options.testRetries, updateSnapshot: options.updateSnapshot, useStderr: options.useStderr, verbose: options.verbose, @@ -192,7 +191,6 @@ const getConfigs = ( testMatch: options.testMatch, testPathIgnorePatterns: options.testPathIgnorePatterns, testRegex: options.testRegex, - testRetries: options.testRetries, testRunner: options.testRunner, testURL: options.testURL, timers: options.timers, diff --git a/packages/jest-config/src/normalize.js b/packages/jest-config/src/normalize.js index ba1117874f31..56147c042584 100644 --- a/packages/jest-config/src/normalize.js +++ b/packages/jest-config/src/normalize.js @@ -552,7 +552,6 @@ export default function normalize(options: InitialOptions, argv: Argv) { case 'testFailureExitCode': case 'testLocationInResults': case 'testNamePattern': - case 'testRetries': case 'testURL': case 'timers': case 'useStderr': @@ -577,7 +576,6 @@ export default function normalize(options: InitialOptions, argv: Argv) { newOptions.json = argv.json; newOptions.testFailureExitCode = parseInt(newOptions.testFailureExitCode, 10); - newOptions.testRetries = parseInt(newOptions.testRetries, 10); for (const key of [ 'lastCommit', diff --git a/packages/jest-config/src/valid_config.js b/packages/jest-config/src/valid_config.js index 3454a9cd87e3..1c5372c05b0a 100644 --- a/packages/jest-config/src/valid_config.js +++ b/packages/jest-config/src/valid_config.js @@ -94,7 +94,6 @@ export default ({ testPathIgnorePatterns: [NODE_MODULES_REGEXP], testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$', testResultsProcessor: 'processor-node-module', - testRetries: 0, testRunner: 'jasmine2', testURL: 'about:blank', timers: 'real', diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index 8443d0301144..347463d0ecb3 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -830,6 +830,11 @@ class Runtime { return jestObject; }; + const retryTimes = (numTestRetries: number) => { + this._environment.global.retryTimes = numTestRetries; + return jestObject; + }; + const jestObject = { addMatchers: (matchers: Object) => this._environment.global.jasmine.addMatchers(matchers), @@ -855,6 +860,7 @@ class Runtime { resetModuleRegistry: resetModules, resetModules, restoreAllMocks, + retryTimes, runAllImmediates: () => this._environment.fakeTimers.runAllImmediates(), runAllTicks: () => this._environment.fakeTimers.runAllTicks(), runAllTimers: () => this._environment.fakeTimers.runAllTimers(), diff --git a/types/Argv.js b/types/Argv.js index f6254cc92cc5..ef157f155dfd 100644 --- a/types/Argv.js +++ b/types/Argv.js @@ -83,7 +83,6 @@ export type Argv = {| testPathPattern: Array, testRegex: string, testResultsProcessor: ?string, - testRetries: number, testRunner: string, testURL: string, timers: 'real' | 'fake', diff --git a/types/Circus.js b/types/Circus.js index 6dc18e37f2f7..6490cf24932f 100644 --- a/types/Circus.js +++ b/types/Circus.js @@ -194,6 +194,7 @@ export type TestEntry = {| asyncError: Exception, // Used if the test failure contains no usable stack trace errors: TestError, fn: ?TestFn, + invocations: number, mode: TestMode, name: TestName, parent: DescribeBlock, diff --git a/types/Config.js b/types/Config.js index 9ab07881a8d0..db18796f5ecc 100644 --- a/types/Config.js +++ b/types/Config.js @@ -74,7 +74,6 @@ export type DefaultOptions = {| testPathIgnorePatterns: Array, testRegex: string, testResultsProcessor: ?string, - testRetries: ?number, testRunner: ?string, testURL: string, timers: 'real' | 'fake', @@ -164,7 +163,6 @@ export type InitialOptions = { testPathIgnorePatterns?: Array, testRegex?: string, testResultsProcessor?: ?string, - testRetries?: ?number, testRunner?: string, testURL?: string, timers?: 'real' | 'fake', @@ -229,7 +227,6 @@ export type GlobalConfig = {| testNamePattern: string, testPathPattern: string, testResultsProcessor: ?string, - testRetries: number, updateSnapshot: SnapshotUpdateState, useStderr: boolean, verbose: ?boolean, @@ -280,7 +277,6 @@ export type ProjectConfig = {| testLocationInResults: boolean, testPathIgnorePatterns: Array, testRegex: string, - testRetries: number, testRunner: string, testURL: string, timers: 'real' | 'fake', diff --git a/types/Jest.js b/types/Jest.js index ec01cd6d54c9..27b1f5b7d35d 100644 --- a/types/Jest.js +++ b/types/Jest.js @@ -45,6 +45,7 @@ export type Jest = {| methodName: string, accessType?: 'get' | 'set', ): JestMockFn, + retryTimes(numRetries: number): Jest, unmock(moduleName: string): Jest, useFakeTimers(): Jest, useRealTimers(): Jest, From 7d6f27b1317a447e267f4d86d67bca0b3beb6a06 Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Thu, 21 Jun 2018 11:56:02 -0400 Subject: [PATCH 04/13] Add jest.retryTimes to CHANGELOG.md and JestObjectAPI.md --- CHANGELOG.md | 1 + docs/JestObjectAPI.md | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 865d3a5fca39..00fc6739c4fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - `[jest-each]` Add support for keyPaths in test titles ([#6457](https://github.com/facebook/jest/pull/6457)) - `[jest-cli]` Add `jest --init` option that generates a basic configuration file with a short description for each option ([#6442](https://github.com/facebook/jest/pull/6442)) +- `[jest.retryTimes]` Add `jest.retryTimes()` option that allows failed tests to be retried n-times when using jest-circus. ([#6498](https://github.com/facebook/jest/pull/6498)) ### Fixes diff --git a/docs/JestObjectAPI.md b/docs/JestObjectAPI.md index 31ed2e713d56..584b4f8da354 100644 --- a/docs/JestObjectAPI.md +++ b/docs/JestObjectAPI.md @@ -21,6 +21,7 @@ The `jest` object is automatically in scope within every test file. The methods - [`jest.resetAllMocks()`](#jestresetallmocks) - [`jest.restoreAllMocks()`](#jestrestoreallmocks) - [`jest.resetModules()`](#jestresetmodules) +- [`jest.retryTimes()`](#jestretrytimes) - [`jest.runAllTicks()`](#jestrunallticks) - [`jest.runAllTimers()`](#jestrunalltimers) - [`jest.advanceTimersByTime(msToRun)`](#jestadvancetimersbytimemstorun) @@ -312,6 +313,21 @@ test('works too', () => { Returns the `jest` object for chaining. +### `jest.retryTimes()` + +Runs failed tests n-times until they pass or until the max number of retries are exhausted. + +Example in a test: + +```js +jest.retryTimes(3); +test('will fail', () => { + expect(true).toBe(false); +}); +``` + +Returns the `jest` object for chaining. + ### `jest.runAllTicks()` Exhausts the **micro**-task queue (usually interfaced in node via `process.nextTick`). From 38ba329049d199c27eba6cd1d95a238c74641cd1 Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Thu, 21 Jun 2018 12:01:19 -0400 Subject: [PATCH 05/13] Prettier fix on snapshot test --- e2e/snapshot-escape/__tests__/snapshot.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/snapshot-escape/__tests__/snapshot.test.js b/e2e/snapshot-escape/__tests__/snapshot.test.js index f2141a8e9291..40c77186d3cb 100644 --- a/e2e/snapshot-escape/__tests__/snapshot.test.js +++ b/e2e/snapshot-escape/__tests__/snapshot.test.js @@ -8,4 +8,4 @@ // prettier-ignore test('escape strings', () => expect('one: \\\'').toMatchSnapshot()); -test('escape strings two', () => expect('two: \'"').toMatchSnapshot()); \ No newline at end of file +test('escape strings two', () => expect('two: \'"').toMatchSnapshot()); From 262e34d0b7d0565fda5f4092cca61ba5c5921f49 Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Thu, 21 Jun 2018 12:45:11 -0400 Subject: [PATCH 06/13] Update runJest to support jest-circus environment override --- e2e/__tests__/test_retries.test.js | 12 +++++------- e2e/runJest.js | 23 +++++++++++++++++++---- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/e2e/__tests__/test_retries.test.js b/e2e/__tests__/test_retries.test.js index 71bfe96f5c0d..c15e4dfe2c0e 100644 --- a/e2e/__tests__/test_retries.test.js +++ b/e2e/__tests__/test_retries.test.js @@ -35,13 +35,11 @@ describe('Test Retries', () => { // Test retries only available via JEST_CIRCUS // also testResults.invocations only available via JEST_CIRCUS - process.env.JEST_CIRCUS = '1'; - - runJest('test-retries', [ - '--config', - JSON.stringify(reporterConfig), - 'retry.test.js', - ]); + runJest( + 'test-retries', + ['--config', JSON.stringify(reporterConfig), 'retry.test.js'], + {useJestCircus: true}, + ); const testOutput = fs.readFileSync(outputFilePath, 'utf8'); diff --git a/e2e/runJest.js b/e2e/runJest.js index c4b859c0ee5c..c25b0b5d8b1f 100644 --- a/e2e/runJest.js +++ b/e2e/runJest.js @@ -21,6 +21,7 @@ const JEST_PATH = path.resolve(__dirname, '../packages/jest-cli/bin/jest.js'); type RunJestOptions = { nodePath?: string, skipPkgJsonCheck?: boolean, // don't complain if can't find package.json + useJestCircus?: boolean, }; // return the result of the spawned process: @@ -49,12 +50,26 @@ function runJest( ); } - const env = options.nodePath - ? Object.assign({}, process.env, { + const nodePathOverrides = options.nodePath + ? { FORCE_COLOR: 0, NODE_PATH: options.nodePath, - }) - : process.env; + } + : {}; + + const jestCircusOverrides = options.useJestCircus + ? { + JEST_CIRCUS: 1, + } + : {}; + + const env = Object.assign( + {}, + process.env, + nodePathOverrides, + jestCircusOverrides, + ); + const result = spawnSync(JEST_PATH, args || [], { cwd: dir, env, From e9762af6870017c8d2b76f2c67962c91fb6331c7 Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Thu, 21 Jun 2018 16:23:29 -0400 Subject: [PATCH 07/13] Update docs and use skipSuiteOnJasmine --- docs/JestObjectAPI.md | 8 +++++++- e2e/__tests__/test_retries.test.js | 14 +++++++++----- e2e/runJest.js | 13 +------------ 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/JestObjectAPI.md b/docs/JestObjectAPI.md index 584b4f8da354..de71880fdac3 100644 --- a/docs/JestObjectAPI.md +++ b/docs/JestObjectAPI.md @@ -315,7 +315,7 @@ Returns the `jest` object for chaining. ### `jest.retryTimes()` -Runs failed tests n-times until they pass or until the max number of retries are exhausted. +Runs failed tests n-times until they pass or until the max number of retries are exhausted. This only works with jest-circus! Example in a test: @@ -326,6 +326,12 @@ test('will fail', () => { }); ``` +To run with jest circus: + +``` +JEST_CIRCUS=1 jest +``` + Returns the `jest` object for chaining. ### `jest.runAllTicks()` diff --git a/e2e/__tests__/test_retries.test.js b/e2e/__tests__/test_retries.test.js index c15e4dfe2c0e..aa96c94d5572 100644 --- a/e2e/__tests__/test_retries.test.js +++ b/e2e/__tests__/test_retries.test.js @@ -12,6 +12,10 @@ const fs = require('fs'); const path = require('path'); const runJest = require('../runJest'); +const ConditionalTest = require('../../scripts/ConditionalTest'); + +ConditionalTest.skipSuiteOnJasmine(); + describe('Test Retries', () => { const outputFileName = 'retries.result.json'; const outputFilePath = path.join( @@ -35,11 +39,11 @@ describe('Test Retries', () => { // Test retries only available via JEST_CIRCUS // also testResults.invocations only available via JEST_CIRCUS - runJest( - 'test-retries', - ['--config', JSON.stringify(reporterConfig), 'retry.test.js'], - {useJestCircus: true}, - ); + runJest('test-retries', [ + '--config', + JSON.stringify(reporterConfig), + 'retry.test.js', + ]); const testOutput = fs.readFileSync(outputFilePath, 'utf8'); diff --git a/e2e/runJest.js b/e2e/runJest.js index c25b0b5d8b1f..085abee877b6 100644 --- a/e2e/runJest.js +++ b/e2e/runJest.js @@ -57,18 +57,7 @@ function runJest( } : {}; - const jestCircusOverrides = options.useJestCircus - ? { - JEST_CIRCUS: 1, - } - : {}; - - const env = Object.assign( - {}, - process.env, - nodePathOverrides, - jestCircusOverrides, - ); + const env = Object.assign({}, process.env, nodePathOverrides); const result = spawnSync(JEST_PATH, args || [], { cwd: dir, From d1edc3712a2208ce207660612498e37325195d9d Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Thu, 21 Jun 2018 20:47:42 -0400 Subject: [PATCH 08/13] Update retryTimes tests --- e2e/__tests__/test_retries.test.js | 36 +++++++++++++++++-- .../{noretry.test.js => control.test.js} | 0 2 files changed, 34 insertions(+), 2 deletions(-) rename e2e/test-retries/__tests__/{noretry.test.js => control.test.js} (100%) diff --git a/e2e/__tests__/test_retries.test.js b/e2e/__tests__/test_retries.test.js index aa96c94d5572..684e750b01cb 100644 --- a/e2e/__tests__/test_retries.test.js +++ b/e2e/__tests__/test_retries.test.js @@ -56,9 +56,41 @@ describe('Test Retries', () => { } expect(jsonResult.numPassedTests).toBe(0); - expect(jsonResult.numFailedTests).toBe(2); + expect(jsonResult.numFailedTests).toBe(1); expect(jsonResult.numPendingTests).toBe(0); expect(jsonResult.testResults[0].testResults[0].invocations).toBe(4); - expect(jsonResult.testResults[1].testResults[0].invocations).toBe(1); + }); + + it('does not retry by default', () => { + let jsonResult; + + const reporterConfig = { + reporters: [ + ['/reporters/RetryReporter.js', {output: outputFilePath}], + ], + }; + + // Test retries only available via JEST_CIRCUS + // also testResults.invocations only available via JEST_CIRCUS + runJest('test-retries', [ + '--config', + JSON.stringify(reporterConfig), + 'control.test.js', + ]); + + const testOutput = fs.readFileSync(outputFilePath, 'utf8'); + + try { + jsonResult = JSON.parse(testOutput); + } catch (err) { + throw new Error( + `Can't parse the JSON result from ${outputFileName}, ${err.toString()}`, + ); + } + + expect(jsonResult.numPassedTests).toBe(0); + expect(jsonResult.numFailedTests).toBe(1); + expect(jsonResult.numPendingTests).toBe(0); + expect(jsonResult.testResults[0].testResults[0].invocations).toBe(1); }); }); diff --git a/e2e/test-retries/__tests__/noretry.test.js b/e2e/test-retries/__tests__/control.test.js similarity index 100% rename from e2e/test-retries/__tests__/noretry.test.js rename to e2e/test-retries/__tests__/control.test.js From 09fb974e797fcdd102ac30931938efb800b6eb55 Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Thu, 21 Jun 2018 20:48:29 -0400 Subject: [PATCH 09/13] Remove useJestCircus boolean on runTest --- e2e/runJest.js | 1 - 1 file changed, 1 deletion(-) diff --git a/e2e/runJest.js b/e2e/runJest.js index 085abee877b6..5a35fd13c7c8 100644 --- a/e2e/runJest.js +++ b/e2e/runJest.js @@ -21,7 +21,6 @@ const JEST_PATH = path.resolve(__dirname, '../packages/jest-cli/bin/jest.js'); type RunJestOptions = { nodePath?: string, skipPkgJsonCheck?: boolean, // don't complain if can't find package.json - useJestCircus?: boolean, }; // return the result of the spawned process: From b346cc228dca4e1d281bfb6283bdf9d588ba74eb Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Fri, 22 Jun 2018 11:55:32 -0400 Subject: [PATCH 10/13] Remove outdated comment. Revert runJest environment override logic. --- e2e/__tests__/test_retries.test.js | 2 -- e2e/runJest.js | 10 ++++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/e2e/__tests__/test_retries.test.js b/e2e/__tests__/test_retries.test.js index 684e750b01cb..e9c64bc236a9 100644 --- a/e2e/__tests__/test_retries.test.js +++ b/e2e/__tests__/test_retries.test.js @@ -37,8 +37,6 @@ describe('Test Retries', () => { ], }; - // Test retries only available via JEST_CIRCUS - // also testResults.invocations only available via JEST_CIRCUS runJest('test-retries', [ '--config', JSON.stringify(reporterConfig), diff --git a/e2e/runJest.js b/e2e/runJest.js index 5a35fd13c7c8..d8d4a37cdcb1 100644 --- a/e2e/runJest.js +++ b/e2e/runJest.js @@ -49,14 +49,12 @@ function runJest( ); } - const nodePathOverrides = options.nodePath - ? { + const env = options.nodePath + ? Object.assign({}, process.env, { FORCE_COLOR: 0, NODE_PATH: options.nodePath, - } - : {}; - - const env = Object.assign({}, process.env, nodePathOverrides); + }) + : process.env; const result = spawnSync(JEST_PATH, args || [], { cwd: dir, From b9d65f8e08eda13d7c9d3898a93da1d532752c09 Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Fri, 22 Jun 2018 14:50:16 -0400 Subject: [PATCH 11/13] Removed outdated comment from test_retries test --- e2e/__tests__/test_retries.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/e2e/__tests__/test_retries.test.js b/e2e/__tests__/test_retries.test.js index e9c64bc236a9..4d20afe36425 100644 --- a/e2e/__tests__/test_retries.test.js +++ b/e2e/__tests__/test_retries.test.js @@ -68,8 +68,6 @@ describe('Test Retries', () => { ], }; - // Test retries only available via JEST_CIRCUS - // also testResults.invocations only available via JEST_CIRCUS runJest('test-retries', [ '--config', JSON.stringify(reporterConfig), From 20667aafbe10474e1de9f886bc9dd63291bbceea Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Fri, 22 Jun 2018 17:37:09 -0400 Subject: [PATCH 12/13] Update snapshot tests --- e2e/__tests__/__snapshots__/snapshot.test.js.snap | 12 ++++++------ e2e/__tests__/snapshot.test.js | 2 +- e2e/snapshot-escape/__tests__/snapshot.test.js | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/e2e/__tests__/__snapshots__/snapshot.test.js.snap b/e2e/__tests__/__snapshots__/snapshot.test.js.snap index c1ec5378d06e..7d07b4330396 100644 --- a/e2e/__tests__/__snapshots__/snapshot.test.js.snap +++ b/e2e/__tests__/__snapshots__/snapshot.test.js.snap @@ -83,24 +83,24 @@ Ran all test suites." exports[`Snapshot works with escaped characters 1`] = ` "Test Suites: 1 passed, 1 total -Tests: 2 passed, 2 total -Snapshots: 2 written, 2 total +Tests: 1 passed, 1 total +Snapshots: 1 written, 1 total Time: <> Ran all test suites matching /snapshot.test.js/i." `; exports[`Snapshot works with escaped characters 2`] = ` "Test Suites: 1 passed, 1 total -Tests: 3 passed, 3 total -Snapshots: 1 written, 2 passed, 3 total +Tests: 2 passed, 2 total +Snapshots: 1 written, 1 passed, 2 total Time: <> Ran all test suites matching /snapshot.test.js/i." `; exports[`Snapshot works with escaped characters 3`] = ` "Test Suites: 1 passed, 1 total -Tests: 3 passed, 3 total -Snapshots: 3 passed, 3 total +Tests: 2 passed, 2 total +Snapshots: 2 passed, 2 total Time: <> Ran all test suites matching /snapshot.test.js/i." `; diff --git a/e2e/__tests__/snapshot.test.js b/e2e/__tests__/snapshot.test.js index 008d2865b245..4a63d2a3e94b 100644 --- a/e2e/__tests__/snapshot.test.js +++ b/e2e/__tests__/snapshot.test.js @@ -128,7 +128,7 @@ describe('Snapshot', () => { ]); let stderr = result.stderr; - expect(stderr).toMatch('2 snapshots written'); + expect(stderr).toMatch('1 snapshot written'); expect(result.status).toBe(0); expect(extractSummary(stderr).summary).toMatchSnapshot(); diff --git a/e2e/snapshot-escape/__tests__/snapshot.test.js b/e2e/snapshot-escape/__tests__/snapshot.test.js index 40c77186d3cb..4aa41bf14a73 100644 --- a/e2e/snapshot-escape/__tests__/snapshot.test.js +++ b/e2e/snapshot-escape/__tests__/snapshot.test.js @@ -8,4 +8,3 @@ // prettier-ignore test('escape strings', () => expect('one: \\\'').toMatchSnapshot()); -test('escape strings two', () => expect('two: \'"').toMatchSnapshot()); From 19bf8a6983aec9a2fe390d9b9452fab4905f8a4a Mon Sep 17 00:00:00 2001 From: Jason Palmer Date: Mon, 25 Jun 2018 08:57:10 -0400 Subject: [PATCH 13/13] Update Jest Object docs for retryTimes. Use symbol for global lookup. --- docs/JestObjectAPI.md | 12 +++++++++++- packages/jest-circus/src/run.js | 2 +- packages/jest-runtime/src/index.js | 2 +- types/Jest.js | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/JestObjectAPI.md b/docs/JestObjectAPI.md index de71880fdac3..65b6338e800e 100644 --- a/docs/JestObjectAPI.md +++ b/docs/JestObjectAPI.md @@ -328,8 +328,18 @@ test('will fail', () => { To run with jest circus: +Install jest-circus + +``` +yarn add --dev jest-circus ``` -JEST_CIRCUS=1 jest + +Then set as the testRunner in your jest config: + +```js +module.exports = { + testRunner: 'jest-circus/runner', +}; ``` Returns the `jest` object for chaining. diff --git a/packages/jest-circus/src/run.js b/packages/jest-circus/src/run.js index 2d0146e97493..0853cb31f67e 100644 --- a/packages/jest-circus/src/run.js +++ b/packages/jest-circus/src/run.js @@ -48,7 +48,7 @@ const _runTestsForDescribeBlock = async (describeBlock: DescribeBlock) => { } // Tests that fail and are retried we run after other tests - const retryTimes = parseInt(global.retryTimes, 10) || 0; + const retryTimes = parseInt(global[Symbol.for('RETRY_TIMES')], 10) || 0; const deferredRetryTests = []; for (const test of describeBlock.tests) { diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index 347463d0ecb3..6c895b94e1db 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -831,7 +831,7 @@ class Runtime { }; const retryTimes = (numTestRetries: number) => { - this._environment.global.retryTimes = numTestRetries; + this._environment.global[Symbol.for('RETRY_TIMES')] = numTestRetries; return jestObject; }; diff --git a/types/Jest.js b/types/Jest.js index 27b1f5b7d35d..88966e299f2c 100644 --- a/types/Jest.js +++ b/types/Jest.js @@ -32,6 +32,7 @@ export type Jest = {| resetModuleRegistry(): Jest, resetModules(): Jest, restoreAllMocks(): Jest, + retryTimes(numRetries: number): Jest, runAllImmediates(): void, runAllTicks(): void, runAllTimers(): void, @@ -45,7 +46,6 @@ export type Jest = {| methodName: string, accessType?: 'get' | 'set', ): JestMockFn, - retryTimes(numRetries: number): Jest, unmock(moduleName: string): Jest, useFakeTimers(): Jest, useRealTimers(): Jest,