You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
5.3 KiB
236 lines
5.3 KiB
'use strict'; |
|
|
|
Object.defineProperty(exports, '__esModule', { |
|
value: true |
|
}); |
|
exports.default = void 0; |
|
|
|
var _state = require('./state'); |
|
|
|
var _types = require('./types'); |
|
|
|
var _utils = require('./utils'); |
|
|
|
/** |
|
* Copyright (c) Facebook, Inc. and its affiliates. 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. |
|
*/ |
|
const run = async () => { |
|
const {rootDescribeBlock} = (0, _state.getState)(); |
|
await (0, _state.dispatch)({ |
|
name: 'run_start' |
|
}); |
|
await _runTestsForDescribeBlock(rootDescribeBlock); |
|
await (0, _state.dispatch)({ |
|
name: 'run_finish' |
|
}); |
|
return (0, _utils.makeRunResult)( |
|
(0, _state.getState)().rootDescribeBlock, |
|
(0, _state.getState)().unhandledErrors |
|
); |
|
}; |
|
|
|
const _runTestsForDescribeBlock = async describeBlock => { |
|
await (0, _state.dispatch)({ |
|
describeBlock, |
|
name: 'run_describe_start' |
|
}); |
|
const {beforeAll, afterAll} = (0, _utils.getAllHooksForDescribe)( |
|
describeBlock |
|
); |
|
const isSkipped = describeBlock.mode === 'skip'; |
|
|
|
if (!isSkipped) { |
|
for (const hook of beforeAll) { |
|
await _callCircusHook({ |
|
describeBlock, |
|
hook |
|
}); |
|
} |
|
} // Tests that fail and are retried we run after other tests |
|
|
|
const retryTimes = parseInt(global[_types.RETRY_TIMES], 10) || 0; |
|
const deferredRetryTests = []; |
|
|
|
for (const child of describeBlock.children) { |
|
switch (child.type) { |
|
case 'describeBlock': { |
|
await _runTestsForDescribeBlock(child); |
|
break; |
|
} |
|
|
|
case 'test': { |
|
const hasErrorsBeforeTestRun = child.errors.length > 0; |
|
await _runTest(child, isSkipped); |
|
|
|
if ( |
|
hasErrorsBeforeTestRun === false && |
|
retryTimes > 0 && |
|
child.errors.length > 0 |
|
) { |
|
deferredRetryTests.push(child); |
|
} |
|
|
|
break; |
|
} |
|
} |
|
} // Re-run failed tests n-times if configured |
|
|
|
for (const test of deferredRetryTests) { |
|
let numRetriesAvailable = retryTimes; |
|
|
|
while (numRetriesAvailable > 0 && test.errors.length > 0) { |
|
// Clear errors so retries occur |
|
await (0, _state.dispatch)({ |
|
name: 'test_retry', |
|
test |
|
}); |
|
await _runTest(test, isSkipped); |
|
numRetriesAvailable--; |
|
} |
|
} |
|
|
|
if (!isSkipped) { |
|
for (const hook of afterAll) { |
|
await _callCircusHook({ |
|
describeBlock, |
|
hook |
|
}); |
|
} |
|
} |
|
|
|
await (0, _state.dispatch)({ |
|
describeBlock, |
|
name: 'run_describe_finish' |
|
}); |
|
}; |
|
|
|
const _runTest = async (test, parentSkipped) => { |
|
await (0, _state.dispatch)({ |
|
name: 'test_start', |
|
test |
|
}); |
|
const testContext = Object.create(null); |
|
const {hasFocusedTests, testNamePattern} = (0, _state.getState)(); |
|
const isSkipped = |
|
parentSkipped || |
|
test.mode === 'skip' || |
|
(hasFocusedTests && test.mode !== 'only') || |
|
(testNamePattern && !testNamePattern.test((0, _utils.getTestID)(test))); |
|
|
|
if (isSkipped) { |
|
await (0, _state.dispatch)({ |
|
name: 'test_skip', |
|
test |
|
}); |
|
return; |
|
} |
|
|
|
if (test.mode === 'todo') { |
|
await (0, _state.dispatch)({ |
|
name: 'test_todo', |
|
test |
|
}); |
|
return; |
|
} |
|
|
|
const {afterEach, beforeEach} = (0, _utils.getEachHooksForTest)(test); |
|
|
|
for (const hook of beforeEach) { |
|
if (test.errors.length) { |
|
// If any of the before hooks failed already, we don't run any |
|
// hooks after that. |
|
break; |
|
} |
|
|
|
await _callCircusHook({ |
|
hook, |
|
test, |
|
testContext |
|
}); |
|
} |
|
|
|
await _callCircusTest(test, testContext); |
|
|
|
for (const hook of afterEach) { |
|
await _callCircusHook({ |
|
hook, |
|
test, |
|
testContext |
|
}); |
|
} // `afterAll` hooks should not affect test status (pass or fail), because if |
|
// we had a global `afterAll` hook it would block all existing tests until |
|
// this hook is executed. So we dispatch `test_done` right away. |
|
|
|
await (0, _state.dispatch)({ |
|
name: 'test_done', |
|
test |
|
}); |
|
}; |
|
|
|
const _callCircusHook = async ({hook, test, describeBlock, testContext}) => { |
|
await (0, _state.dispatch)({ |
|
hook, |
|
name: 'hook_start' |
|
}); |
|
const timeout = hook.timeout || (0, _state.getState)().testTimeout; |
|
|
|
try { |
|
await (0, _utils.callAsyncCircusFn)(hook, testContext, { |
|
isHook: true, |
|
timeout |
|
}); |
|
await (0, _state.dispatch)({ |
|
describeBlock, |
|
hook, |
|
name: 'hook_success', |
|
test |
|
}); |
|
} catch (error) { |
|
await (0, _state.dispatch)({ |
|
describeBlock, |
|
error, |
|
hook, |
|
name: 'hook_failure', |
|
test |
|
}); |
|
} |
|
}; |
|
|
|
const _callCircusTest = async (test, testContext) => { |
|
await (0, _state.dispatch)({ |
|
name: 'test_fn_start', |
|
test |
|
}); |
|
const timeout = test.timeout || (0, _state.getState)().testTimeout; |
|
(0, _utils.invariant)( |
|
test.fn, |
|
"Tests with no 'fn' should have 'mode' set to 'skipped'" |
|
); |
|
|
|
if (test.errors.length) { |
|
return; // We don't run the test if there's already an error in before hooks. |
|
} |
|
|
|
try { |
|
await (0, _utils.callAsyncCircusFn)(test, testContext, { |
|
isHook: false, |
|
timeout |
|
}); |
|
await (0, _state.dispatch)({ |
|
name: 'test_fn_success', |
|
test |
|
}); |
|
} catch (error) { |
|
await (0, _state.dispatch)({ |
|
error, |
|
name: 'test_fn_failure', |
|
test |
|
}); |
|
} |
|
}; |
|
|
|
var _default = run; |
|
exports.default = _default;
|
|
|