( test: Circus.TestEntry, parentSkipped: boolean, )
| 195 | }; |
| 196 | |
| 197 | const _runTest = async ( |
| 198 | test: Circus.TestEntry, |
| 199 | parentSkipped: boolean, |
| 200 | ): Promise<void> => { |
| 201 | await dispatch({name: 'test_start', test}); |
| 202 | const testContext = Object.create(null); |
| 203 | const {hasFocusedTests, testNamePattern} = getState(); |
| 204 | |
| 205 | const isSkipped = |
| 206 | parentSkipped || |
| 207 | test.mode === 'skip' || |
| 208 | (hasFocusedTests && test.mode === undefined) || |
| 209 | (testNamePattern && !testNamePattern.test(getTestID(test))); |
| 210 | |
| 211 | if (isSkipped) { |
| 212 | await dispatch({name: 'test_skip', test}); |
| 213 | return; |
| 214 | } |
| 215 | |
| 216 | if (test.mode === 'todo') { |
| 217 | await dispatch({name: 'test_todo', test}); |
| 218 | return; |
| 219 | } |
| 220 | |
| 221 | await dispatch({name: 'test_started', test}); |
| 222 | |
| 223 | const {afterEach, beforeEach} = getEachHooksForTest(test); |
| 224 | |
| 225 | for (const hook of beforeEach) { |
| 226 | if (test.errors.length > 0) { |
| 227 | // If any of the before hooks failed already, we don't run any |
| 228 | // hooks after that. |
| 229 | break; |
| 230 | } |
| 231 | await _callCircusHook({hook, test, testContext}); |
| 232 | } |
| 233 | |
| 234 | await _callCircusTest(test, testContext); |
| 235 | |
| 236 | for (const hook of afterEach) { |
| 237 | await _callCircusHook({hook, test, testContext}); |
| 238 | } |
| 239 | |
| 240 | // `afterAll` hooks should not affect test status (pass or fail), because if |
| 241 | // we had a global `afterAll` hook it would block all existing tests until |
| 242 | // this hook is executed. So we dispatch `test_done` right away. |
| 243 | await dispatch({name: 'test_done', test}); |
| 244 | }; |
| 245 | |
| 246 | const _callCircusHook = async ({ |
| 247 | hook, |
no test coverage detected