From 657f967d7218090a309b57b661781ab8269af940 Mon Sep 17 00:00:00 2001 From: Dmitrii Abramov Date: Tue, 23 May 2017 14:32:36 -0400 Subject: [PATCH] [WIP] jest-framework [WIP] jest-framework [WIP] jest-framework [WIP] Integrating with Jest [WIP] jest-framework [WIP] jest-framework [WIP] jest-framework --- packages/jest-framework/package.json | 16 ++ packages/jest-framework/src/eventHandler.js | 90 +++++++ packages/jest-framework/src/index.js | 58 +++++ .../jest-adapter-init.js | 174 ++++++++++++++ .../legacy_code_todo_rewrite/jest-adapter.js | 97 ++++++++ .../legacy_code_todo_rewrite/jest-expect.js | 34 +++ packages/jest-framework/src/run.js | 93 +++++++ packages/jest-framework/src/state.js | 52 ++++ packages/jest-framework/src/utils.js | 218 +++++++++++++++++ packages/jest-framework/types.js | 130 ++++++++++ .../jasmine-uses-jests-extend-api-test.js | 56 ----- .../__snapshots__/spyMatchers-test.js.snap | 227 +++--------------- .../src/__tests__/spyMatchers-test.js | 66 ++--- .../src/__tests__/toThrowMatchers-test.js | 20 -- packages/jest-runtime/src/index.js | 6 +- testSetupFile.js | 2 +- types/TestResult.js | 2 +- 17 files changed, 1024 insertions(+), 317 deletions(-) create mode 100644 packages/jest-framework/package.json create mode 100644 packages/jest-framework/src/eventHandler.js create mode 100644 packages/jest-framework/src/index.js create mode 100644 packages/jest-framework/src/legacy_code_todo_rewrite/jest-adapter-init.js create mode 100644 packages/jest-framework/src/legacy_code_todo_rewrite/jest-adapter.js create mode 100644 packages/jest-framework/src/legacy_code_todo_rewrite/jest-expect.js create mode 100644 packages/jest-framework/src/run.js create mode 100644 packages/jest-framework/src/state.js create mode 100644 packages/jest-framework/src/utils.js create mode 100644 packages/jest-framework/types.js delete mode 100644 packages/jest-jasmine2/src/__tests__/jasmine-uses-jests-extend-api-test.js diff --git a/packages/jest-framework/package.json b/packages/jest-framework/package.json new file mode 100644 index 000000000000..6f2589adad2a --- /dev/null +++ b/packages/jest-framework/package.json @@ -0,0 +1,16 @@ +{ + "name": "jest-framework", + "version": "20.0.3", + "repository": { + "type": "git", + "url": "https://github.com/facebook/jest.git" + }, + "license": "BSD-3-Clause", + "main": "build/index.js", + "dependencies": { + "jest-snapshot": "^20.0.3" + }, + "devDependencies": { + "jest-runtime": "^20.0.3" + } +} diff --git a/packages/jest-framework/src/eventHandler.js b/packages/jest-framework/src/eventHandler.js new file mode 100644 index 000000000000..eb8336aee0ae --- /dev/null +++ b/packages/jest-framework/src/eventHandler.js @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +import type {EventHandler} from '../types'; + +const { + makeDescribe, + getTestDuration, + makeTest, + isSharedHook, +} = require('./utils'); + +// To pass this value from Runtime object to state we need to use global[sym] +const TEST_TIMEOUT_SYMBOL = Symbol.for('TEST_TIMEOUT_SYMBOL'); + +const handler: EventHandler = (event, state): void => { + switch (event.name) { + case 'start_describe_definition': { + const {blockName, mode} = event; + const {currentDescribeBlock} = state; + const describeBlock = makeDescribe(blockName, currentDescribeBlock, mode); + currentDescribeBlock.children.push(describeBlock); + state.currentDescribeBlock = describeBlock; + break; + } + case 'finish_describe_definition': { + const {currentDescribeBlock} = state; + if (!currentDescribeBlock) { + throw new Error( + `currentDescribeBlock has to be there since we're finishing its definition`, + ); + } + if (currentDescribeBlock.parent) { + state.currentDescribeBlock = currentDescribeBlock.parent; + } + break; + } + case 'add_hook': { + const {currentDescribeBlock} = state; + const {fn, hookType: type} = event; + currentDescribeBlock.hooks.push({fn, type}); + break; + } + case 'add_test': { + const {currentDescribeBlock} = state; + const {fn, mode, testName: name} = event; + const test = makeTest(fn, mode, name, currentDescribeBlock); + test.mode === 'only' && (state.hasFocusedTests = true); + currentDescribeBlock.tests.push(test); + break; + } + case 'hook_start': { + isSharedHook(event.hook) && + state.sharedHooksThatHaveBeenExecuted.add(event.hook); + break; + } + case 'test_start': { + event.test.startedAt = Date.now(); + break; + } + case 'test_skip': { + event.test.status = 'skip'; + break; + } + case 'test_failure': { + event.test.status = 'fail'; + event.test.duration = getTestDuration(event.test); + event.test.errors.push(event.error); + break; + } + case 'test_success': { + event.test.status = 'pass'; + event.test.duration = getTestDuration(event.test); + break; + } + case 'run_start': { + state.testTimeout = global[TEST_TIMEOUT_SYMBOL] || state.testTimeout; + break; + } + } +}; + +module.exports = handler; diff --git a/packages/jest-framework/src/index.js b/packages/jest-framework/src/index.js new file mode 100644 index 000000000000..d26d37ec6ac2 --- /dev/null +++ b/packages/jest-framework/src/index.js @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +import type { + BlockFn, + HookFn, + HookType, + TestFn, + BlockMode, + BlockName, + TestName, +} from '../types'; +const {dispatch} = require('./state'); + +const describe = (blockName: BlockName, blockFn: BlockFn) => + _dispatchDescribe(blockFn, blockName); +describe.only = (blockName: BlockName, blockFn: BlockFn) => + _dispatchDescribe(blockFn, blockName, 'only'); +describe.skip = (blockName: BlockName, blockFn: BlockFn) => + _dispatchDescribe(blockFn, blockName, 'skip'); + +const _dispatchDescribe = (blockFn, blockName, mode?: BlockMode) => { + dispatch({blockName, mode, name: 'start_describe_definition'}); + blockFn(); + dispatch({name: 'finish_describe_definition'}); +}; + +const _addHook = (fn: HookFn, hookType: HookType) => + dispatch({fn, hookType, name: 'add_hook'}); +const beforeEach = (fn: HookFn) => _addHook(fn, 'beforeEach'); +const beforeAll = (fn: HookFn) => _addHook(fn, 'beforeAll'); +const afterEach = (fn: HookFn) => _addHook(fn, 'afterEach'); +const afterAll = (fn: HookFn) => _addHook(fn, 'afterAll'); + +const test = (testName: TestName, fn?: TestFn) => + dispatch({fn, name: 'add_test', testName}); +const it = test; +test.skip = (testName: TestName, fn?: TestFn) => + dispatch({fn, mode: 'skip', name: 'add_test', testName}); +test.only = (testName: TestName, fn: TestFn) => + dispatch({fn, mode: 'only', name: 'add_test', testName}); + +module.exports = { + afterAll, + afterEach, + beforeAll, + beforeEach, + describe, + it, + test, +}; diff --git a/packages/jest-framework/src/legacy_code_todo_rewrite/jest-adapter-init.js b/packages/jest-framework/src/legacy_code_todo_rewrite/jest-adapter-init.js new file mode 100644 index 000000000000..38025c015ef4 --- /dev/null +++ b/packages/jest-framework/src/legacy_code_todo_rewrite/jest-adapter-init.js @@ -0,0 +1,174 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +import type {TestResult, Status} from 'types/TestResult'; +import type {GlobalConfig, Path, ProjectConfig} from 'types/Config'; +import type {Event, Test} from '../../types'; + +const {getState, setState} = require('jest-matchers'); +const {formatResultsErrors} = require('jest-message-util'); +const {SnapshotState, addSerializer} = require('jest-snapshot'); +const {addEventHandler, TOP_DESCRIBE_BLOCK_NAME} = require('../state'); +const {getTestID} = require('../utils'); +const run = require('../run'); +const globals = require('../index'); + +const initialize = ({ + config, + globalConfig, + localRequire, + testPath, +}: { + config: ProjectConfig, + globalConfig: GlobalConfig, + localRequire: Path => any, + testPath: Path, +}) => { + Object.assign(global, globals); + + addEventHandler(eventHandler); + + // Jest tests snapshotSerializers in order preceding built-in serializers. + // Therefore, add in reverse because the last added is the first tested. + config.snapshotSerializers.concat().reverse().forEach(path => { + addSerializer(localRequire(path)); + }); + + const {expand, updateSnapshot} = globalConfig; + const snapshotState = new SnapshotState(testPath, {expand, updateSnapshot}); + setState({snapshotState, testPath}); + + // Return it back to the outer scope (test runner outside the VM). + return {globals, snapshotState}; +}; + +const runAndTransformResultsToJestFormat = async ({ + config, + globalConfig, + testPath, +}: { + config: ProjectConfig, + globalConfig: GlobalConfig, + testPath: string, +}): Promise => { + const result = await run(); + + let numFailingTests = 0; + let numPassingTests = 0; + let numPendingTests = 0; + + for (const testResult of result) { + switch (testResult.status) { + case 'fail': + numFailingTests += 1; + break; + case 'pass': + numPassingTests += 1; + break; + case 'skip': + numPendingTests += 1; + break; + } + } + + const assertionResults = result.map(testResult => { + let status: Status; + switch (testResult.status) { + case 'fail': + status = 'failed'; + break; + case 'pass': + status = 'passed'; + break; + case 'skip': + status = 'skipped'; + break; + } + + const ancestorTitles = testResult.testPath.filter( + name => name !== TOP_DESCRIBE_BLOCK_NAME, + ); + const title = ancestorTitles.pop(); + + // $FlowFixMe Types are slightly incompatible and need to be refactored + return { + ancestorTitles, + duration: testResult.duration, + failureMessages: testResult.errors, + fullName: ancestorTitles.concat(title).join(' '), + numPassingAsserts: 0, + status, + title: testResult.testPath[testResult.testPath.length - 1], + }; + }); + + const failureMessage = formatResultsErrors( + assertionResults, + config, + globalConfig, + testPath, + ); + + return { + console: null, + failureMessage, + numFailingTests, + numPassingTests, + numPendingTests, + perfStats: { + // populated outside + end: 0, + start: 0, + }, + skipped: false, + snapshot: { + added: 0, + fileDeleted: false, + matched: 0, + unchecked: 0, + unmatched: 0, + updated: 0, + }, + sourceMaps: {}, + testFilePath: testPath, + testResults: assertionResults, + }; +}; + +const eventHandler = (event: Event) => { + switch (event.name) { + case 'test_start': { + setState({currentTestName: getTestID(event.test)}); + break; + } + case 'test_success': + case 'test_failure': { + _addSuppressedErrors(event.test); + break; + } + } +}; + +// Get suppressed errors from ``jest-matchers`` that weren't throw during +// test execution and add them to the test result, potentially failing +// a passing test. +const _addSuppressedErrors = (test: Test) => { + const {suppressedErrors} = getState(); + setState({suppressedErrors: []}); + if (suppressedErrors.length) { + test.status = 'fail'; + test.errors = test.errors.concat(suppressedErrors); + } +}; + +module.exports = { + initialize, + runAndTransformResultsToJestFormat, +}; diff --git a/packages/jest-framework/src/legacy_code_todo_rewrite/jest-adapter.js b/packages/jest-framework/src/legacy_code_todo_rewrite/jest-adapter.js new file mode 100644 index 000000000000..2fb29c19ecf4 --- /dev/null +++ b/packages/jest-framework/src/legacy_code_todo_rewrite/jest-adapter.js @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +import type {Environment} from 'types/Environment'; +import type {GlobalConfig, ProjectConfig} from 'types/Config'; +import type {TestResult} from 'types/TestResult'; +import type Runtime from 'jest-runtime'; + +const FRAMEWORK_INITIALIZER = require.resolve('./jest-adapter-init'); +const path = require('path'); + +const jestAdapter = async ( + globalConfig: GlobalConfig, + config: ProjectConfig, + environment: Environment, + runtime: Runtime, + testPath: string, +): Promise => { + const { + initialize, + runAndTransformResultsToJestFormat, + } = runtime.requireInternalModule(FRAMEWORK_INITIALIZER); + + runtime.requireInternalModule(path.resolve(__dirname, './jest-expect.js'))({ + expand: globalConfig.expand, + }); + + const {globals, snapshotState} = initialize({ + config, + globalConfig, + localRequire: runtime.requireModule.bind(runtime), + testPath, + }); + + globals.beforeEach(() => { + if (config.resetModules) { + runtime.resetModules(); + } + + if (config.clearMocks) { + runtime.clearAllMocks(); + } + + if (config.resetMocks) { + runtime.resetAllMocks(); + } + + if (config.timers === 'fake') { + environment.fakeTimers.useFakeTimers(); + } + }); + + if (config.setupTestFrameworkScriptFile) { + runtime.requireModule(config.setupTestFrameworkScriptFile); + } + + runtime.requireModule(testPath); + const results = await runAndTransformResultsToJestFormat({ + config, + globalConfig, + testPath, + }); + return _addSnapshotData(results, snapshotState); +}; + +const _addSnapshotData = (results: TestResult, snapshotState) => { + results.testResults.forEach(({fullName, status}) => { + if (status === 'pending' || status === 'failed') { + // if test is skipped or failed, we don't want to mark + // its snapshots as obsolete. + snapshotState.markSnapshotsAsCheckedForTest(fullName); + } + }); + + const uncheckedCount = snapshotState.getUncheckedCount(); + if (uncheckedCount) { + snapshotState.removeUncheckedKeys(); + } + + const status = snapshotState.save(); + results.snapshot.fileDeleted = status.deleted; + results.snapshot.added = snapshotState.added; + results.snapshot.matched = snapshotState.matched; + results.snapshot.unmatched = snapshotState.unmatched; + results.snapshot.updated = snapshotState.updated; + results.snapshot.unchecked = !status.deleted ? uncheckedCount : 0; + return results; +}; + +module.exports = jestAdapter; diff --git a/packages/jest-framework/src/legacy_code_todo_rewrite/jest-expect.js b/packages/jest-framework/src/legacy_code_todo_rewrite/jest-expect.js new file mode 100644 index 000000000000..40a16e3e5823 --- /dev/null +++ b/packages/jest-framework/src/legacy_code_todo_rewrite/jest-expect.js @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +import type {RawMatcherFn} from 'types/Matchers'; + +const expect = require('jest-matchers'); + +const { + addSerializer, + toMatchSnapshot, + toThrowErrorMatchingSnapshot, +} = require('jest-snapshot'); + +type JasmineMatcher = { + (): JasmineMatcher, + compare: () => RawMatcherFn, + negativeCompare: () => RawMatcherFn, +}; + +module.exports = (config: {expand: boolean}) => { + global.expect = expect; + expect.setState({ + expand: config.expand, + }); + expect.extend({toMatchSnapshot, toThrowErrorMatchingSnapshot}); + (expect: Object).addSnapshotSerializer = addSerializer; +}; diff --git a/packages/jest-framework/src/run.js b/packages/jest-framework/src/run.js new file mode 100644 index 000000000000..8156707a8c29 --- /dev/null +++ b/packages/jest-framework/src/run.js @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +import type { + Test, + TestResults, + TestContext, + Hook, + DescribeBlock, +} from '../types'; + +const {getState, dispatch} = require('./state'); +const { + callAsyncFn, + getAllHooks, + isSharedHook, + makeTestResults, +} = require('./utils'); + +const run = async (): Promise => { + const {topDescribeBlock} = getState(); + dispatch({name: 'run_start'}); + await _runTestsForDescribeBlock(topDescribeBlock); + dispatch({name: 'run_finish'}); + return makeTestResults(getState().topDescribeBlock); +}; + +const _runTestsForDescribeBlock = async (describeBlock: DescribeBlock) => { + dispatch({describeBlock, name: 'run_describe_start'}); + for (const test of describeBlock.tests) { + await _runTest(test); + } + for (const child of describeBlock.children) { + await _runTestsForDescribeBlock(child); + } + dispatch({describeBlock, name: 'run_describe_finish'}); +}; + +const _runTest = async (test: Test): Promise => { + const testContext = Object.create(null); + const {afterHooks, beforeHooks} = getAllHooks(test); + + for (const hook of beforeHooks) { + await callHook(hook, testContext); + } + + await callTest(test, testContext); + + for (const hook of afterHooks) { + await callHook(hook, testContext); + } +}; + +const callHook = (hook: Hook, testContext: TestContext): Promise => { + const {sharedHooksThatHaveBeenExecuted} = getState(); + if (isSharedHook(hook) && sharedHooksThatHaveBeenExecuted.has(hook)) { + return Promise.resolve(); + } + + dispatch({hook, name: 'hook_start'}); + return callAsyncFn(hook.fn, testContext, {isHook: true}) + .then(() => dispatch({hook, name: 'hook_success'})) + .catch(error => dispatch({error, hook, name: 'hook_failure'})); +}; + +const callTest = (test: Test, testContext: TestContext): Promise => { + const isSkipped = + test.mode === 'skip' || + (getState().hasFocusedTests && test.mode !== 'only'); + + if (isSkipped) { + dispatch({name: 'test_skip', test}); + return Promise.resolve(); + } + + dispatch({name: 'test_start', test}); + if (!test.fn) { + throw Error(`Tests with no 'fn' should have 'mode' set to 'skipped'`); + } + + return callAsyncFn(test.fn, testContext) + .then(() => dispatch({name: 'test_success', test})) + .catch(error => dispatch({error, name: 'test_failure', test})); +}; + +module.exports = run; diff --git a/packages/jest-framework/src/state.js b/packages/jest-framework/src/state.js new file mode 100644 index 000000000000..48a7cfedc58f --- /dev/null +++ b/packages/jest-framework/src/state.js @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +import type {Event, State, EventHandler} from '../types'; + +const TOP_DESCRIBE_BLOCK_NAME = 'JEST_TOP_DESCRIBE_BLOCK'; + +const {makeDescribe} = require('./utils'); +const eventHandler = require('./eventHandler'); + +const eventHandlers: Array = [eventHandler]; + +const STATE_SYM = Symbol('JEST_STATE_SYMBOL'); + +const TOP_DESCRIBE_BLOCK = makeDescribe(TOP_DESCRIBE_BLOCK_NAME); +const INITIAL_STATE: State = { + currentDescribeBlock: TOP_DESCRIBE_BLOCK, + hasFocusedTests: false, + sharedHooksThatHaveBeenExecuted: new Set(), + testTimeout: 5000, + topDescribeBlock: TOP_DESCRIBE_BLOCK, +}; + +global[STATE_SYM] = INITIAL_STATE; + +const getState = (): State => global[STATE_SYM]; +const setState = (state: State): State => (global[STATE_SYM] = state); + +const dispatch = (event: Event): void => { + for (const handler of eventHandlers) { + handler(event, getState()); + } +}; + +const addEventHandler = (handler: EventHandler): void => { + eventHandlers.push(handler); +}; + +module.exports = { + TOP_DESCRIBE_BLOCK_NAME, + addEventHandler, + dispatch, + getState, + setState, +}; diff --git a/packages/jest-framework/src/utils.js b/packages/jest-framework/src/utils.js new file mode 100644 index 000000000000..160b0e578bc1 --- /dev/null +++ b/packages/jest-framework/src/utils.js @@ -0,0 +1,218 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +import type { + AsyncFn, + BlockMode, + BlockName, + DescribeBlock, + Exception, + Hook, + SharedHookType, + Test, + TestContext, + TestFn, + TestMode, + TestName, + TestResults, +} from '../types'; + +const makeDescribe = ( + name: BlockName, + parent: ?DescribeBlock, + mode?: BlockMode, +): DescribeBlock => { + if (parent && !mode) { + // If not set explicitly, inherit from the parent describe. + mode = parent.mode; + } + + return { + children: [], + hooks: [], + mode, + name, + parent, + tests: [], + }; +}; + +const makeTest = ( + fn: ?TestFn, + mode: TestMode, + name: TestName, + parent: DescribeBlock, +): Test => { + if (!fn) { + mode = 'skip'; // skip test if no fn passed + } else if (!mode) { + // if not set explicitly, inherit from its parent describe + mode = parent.mode; + } + + return { + duration: null, + errors: [], + fn, + mode, + name, + parent, + startedAt: null, + status: null, + }; +}; + +const getAllHooks = ( + test: Test, +): {[key: 'beforeHooks' | 'afterHooks']: Array} => { + const result = {afterHooks: [], beforeHooks: []}; + let {parent: block} = test; + + do { + for (const hook of block.hooks) { + switch (hook.type) { + case 'beforeEach': + case 'beforeAll': + result.beforeHooks.push(hook); + break; + case 'afterEach': + case 'afterAll': + result.afterHooks.push(hook); + break; + default: + throw new Error(`unexpected hook type: ${hook.type}`); + } + } + } while ((block = block.parent)); + // Before hooks are executed from top to bottom, the opposite of the way + // we traversed it. + result.beforeHooks.reverse(); + return result; +}; + +const SHARED_HOOK_TYPES: Set = new Set([ + 'beforeAll', + 'afterAll', +]); +// $FlowFixMe flow thinks that Set.has() can only accept the values of enum. +const isSharedHook = (hook: Hook): boolean => SHARED_HOOK_TYPES.has(hook.type); + +const callAsyncFn = ( + fn: AsyncFn, + testContext: TestContext, + {isHook}: {isHook?: boolean} = {isHook: false}, +): Promise => { + // If this fn accepts `done` callback we return a promise that fullfills as + // soon as `done` called. + if (fn.length) { + return new Promise((resolve, reject) => { + const done = (reason?: Error | string): void => + reason ? reject(reason) : resolve(); + + fn.call(testContext, done); + }); + } + + let returnedValue; + try { + returnedValue = fn.call(testContext); + } catch (error) { + return Promise.reject(error); + } + + // If it's a Promise, return it. + if (returnedValue instanceof Promise) { + return returnedValue; + } + + if (!isHook && returnedValue !== void 0) { + throw new Error( + ` + test functions can only return Promise or undefined. + Returned value: ${String(returnedValue)} + `, + ); + } + + // Otherwise this test is synchronous, and if it didn't throw it means + // it passed. + return Promise.resolve(); +}; + +const getTestDuration = (test: Test): ?number => { + const {startedAt} = test; + return startedAt ? Date.now() - startedAt : null; +}; + +const makeTestResults = (describeBlock: DescribeBlock): TestResults => { + let testResults = []; + for (const test of describeBlock.tests) { + const testPath = []; + let parent = test; + do { + testPath.unshift(parent.name); + } while ((parent = parent.parent)); + + const {status} = test; + + if (!status) { + console.log(test); + throw new Error('status should be present after tests are run'); + } + testResults.push({ + duration: test.duration, + errors: test.errors.map(_formatError), + status, + testPath, + }); + } + + for (const child of describeBlock.children) { + testResults = testResults.concat(makeTestResults(child)); + } + + return testResults; +}; + +// Return a string that identifies the test (concat of parent describe block +// names + test title) +const getTestID = (test: Test) => { + const titles = []; + let parent = test; + do { + titles.unshift(parent.name); + } while ((parent = parent.parent)); + + titles.shift(); // remove TOP_DESCRIBE_BLOCK_NAME + return titles.join(' '); +}; + +const _formatError = (error: ?Exception): string => { + if (!error) { + return 'NO ERROR MESSAGE OR STACK TRACE SPECIFIED'; + } else if (error.stack) { + return error.stack; + } else if (error.message) { + return error.message; + } else { + return String(error); + } +}; + +module.exports = { + callAsyncFn, + getAllHooks, + getTestDuration, + getTestID, + isSharedHook, + makeDescribe, + makeTest, + makeTestResults, +}; diff --git a/packages/jest-framework/types.js b/packages/jest-framework/types.js new file mode 100644 index 000000000000..7c1c1f56f481 --- /dev/null +++ b/packages/jest-framework/types.js @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +export type DoneFn = (reason?: string | Error) => void; +export type BlockFn = () => void; +export type BlockName = string; +export type BlockMode = void | 'skip' | 'only'; +export type TestName = string; +export type TestFn = (done?: DoneFn) => ?Promise; +export type HookFn = (done?: DoneFn) => ?Promise; +export type AsyncFn = TestFn | HookFn; +export type SharedHookType = 'afterAll' | 'beforeAll'; +export type HookType = SharedHookType | 'afterEach' | 'beforeEach'; +export type Hook = {fn: HookFn, type: HookType}; +export type TestContext = Object; +export type TestMode = void | 'skip' | 'only'; +export type Exception = any; // Since in JS anything can be thrown as an error. +export type FormattedError = string; // String representation of error. + +export type EventHandler = (event: Event, state: State) => void; + +export type Event = + | {| + mode: BlockMode, + name: 'start_describe_definition', + blockName: BlockName, + |} + | {| + name: 'finish_describe_definition', + |} + | {| + name: 'add_hook', + hookType: HookType, + fn: HookFn, + |} + | {| + name: 'add_test', + testName: TestName, + fn?: TestFn, + mode?: TestMode, + |} + | {| + name: 'hook_start', + hook: Hook, + |} + | {| + name: 'hook_success', + hook: Hook, + |} + | {| + name: 'hook_failure', + error: string | Exception, + hook: Hook, + |} + | {| + name: 'test_start', + test: Test, + |} + | {| + name: 'test_success', + test: Test, + |} + | {| + name: 'test_failure', + error: Exception, + test: Test, + |} + | {| + name: 'test_skip', + test: Test, + |} + | {| + name: 'run_describe_start', + describeBlock: DescribeBlock, + |} + | {| + name: 'run_describe_finish', + describeBlock: DescribeBlock, + |} + | {| + name: 'run_start', + |} + | {| + name: 'run_finish', + |}; + +export type TestStatus = 'pass' | 'fail' | 'skip'; +export type TestResult = {| + duration: ?number, + errors: Array, + status: TestStatus, + testPath: Array, +|}; + +export type TestResults = Array; + +export type State = {| + currentDescribeBlock: DescribeBlock, + hasFocusedTests: boolean, // that are defined using test.only + sharedHooksThatHaveBeenExecuted: Set, + topDescribeBlock: DescribeBlock, + testTimeout: number, +|}; + +export type DescribeBlock = {| + children: Array, + hooks: Array, + mode: BlockMode, + name: BlockName, + parent: ?DescribeBlock, + tests: Array, +|}; + +export type Test = {| + errors: Array, + fn: ?TestFn, + mode: TestMode, + name: TestName, + parent: DescribeBlock, + startedAt: ?number, + duration: ?number, + status: ?TestStatus, +|}; diff --git a/packages/jest-jasmine2/src/__tests__/jasmine-uses-jests-extend-api-test.js b/packages/jest-jasmine2/src/__tests__/jasmine-uses-jests-extend-api-test.js deleted file mode 100644 index d017747ddb19..000000000000 --- a/packages/jest-jasmine2/src/__tests__/jasmine-uses-jests-extend-api-test.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ -'use strict'; - -describe('addMatcher Adapter', () => { - const originalExtend = expect.extend; - - beforeEach(() => { - jasmine.addMatchers({ - _toBeValue(util, customEqualityTesters) { - return { - compare(actual, expected) { - const pass = actual == expected; - - return { - message: `Expected ${pass} to be same value as ${expected}`, - pass, - }; - }, - }; - }, - }); - - expect.extend({ - __specialExtend() { - return { - message: '', - pass: true, - }; - }, - }); - }); - - afterAll(() => { - expect.extend = originalExtend; - }); - - it('jasmine.addMatcher calls `expect.extend`', () => { - expect.extend = jest.genMockFunction(); - - jasmine.addMatchers({}); - - expect(expect.extend).toBeCalled(); - }); - - it('properly aliases to the Jest API', () => { - expect(1)._toBeValue(1); - expect(1).not._toBeValue(2); - }); -}); diff --git a/packages/jest-matchers/src/__tests__/__snapshots__/spyMatchers-test.js.snap b/packages/jest-matchers/src/__tests__/__snapshots__/spyMatchers-test.js.snap index 4a246ee70a63..3359d0eba015 100644 --- a/packages/jest-matchers/src/__tests__/__snapshots__/spyMatchers-test.js.snap +++ b/packages/jest-matchers/src/__tests__/__snapshots__/spyMatchers-test.js.snap @@ -8,7 +8,15 @@ Received: function: [Function fn]" `; -exports[`lastCalledWith works with jest.fn and arguments that don't match 1`] = ` +exports[`lastCalledWith works when not called 1`] = ` +"expect(jest.fn()).lastCalledWith(expected) + +Expected mock function to have been last called with: + [\\"foo\\", \\"bar\\"] +But it was not called." +`; + +exports[`lastCalledWith works with arguments that don't match 1`] = ` "expect(jest.fn()).lastCalledWith(expected) Expected mock function to have been last called with: @@ -17,21 +25,21 @@ But it was last called with: [\\"foo\\", \\"bar1\\"]" `; -exports[`lastCalledWith works with jest.fn and arguments that match 1`] = ` +exports[`lastCalledWith works with arguments that match 1`] = ` "expect(jest.fn()).not.lastCalledWith(expected) Expected mock function to not have been last called with: [\\"foo\\", \\"bar\\"]" `; -exports[`lastCalledWith works with jest.fn and many arguments 1`] = ` +exports[`lastCalledWith works with many arguments 1`] = ` "expect(jest.fn()).not.lastCalledWith(expected) Expected mock function to not have been last called with: [\\"foo\\", \\"bar\\"]" `; -exports[`lastCalledWith works with jest.fn and many arguments that don't match 1`] = ` +exports[`lastCalledWith works with many arguments that don't match 1`] = ` "expect(jest.fn()).lastCalledWith(expected) Expected mock function to have been last called with: @@ -41,14 +49,6 @@ But it was last called with: and two more calls." `; -exports[`lastCalledWith works with jest.fn when not called 1`] = ` -"expect(jest.fn()).lastCalledWith(expected) - -Expected mock function to have been last called with: - [\\"foo\\", \\"bar\\"] -But it was not called." -`; - exports[`toBeCalled works only on spies or jest.fn 1`] = ` "expect(jest.fn())[.not].toBeCalled() @@ -57,27 +57,6 @@ Received: function: [Function fn]" `; -exports[`toBeCalled works with jasmine.createSpy 1`] = ` -"expect(spy).toBeCalled() - -Expected spy to have been called." -`; - -exports[`toBeCalled works with jasmine.createSpy 2`] = ` -"expect(spy).not.toBeCalled() - -Expected spy not to be called but it was called with: - Array []" -`; - -exports[`toBeCalled works with jasmine.createSpy 3`] = ` -"expect(received)[.not].toBeCalled() - -Matcher does not accept any arguments. -Got: - number: 555" -`; - exports[`toBeCalled works with jest.fn 1`] = ` "expect(jest.fn()).toBeCalled() @@ -107,46 +86,6 @@ Received: function: [Function fn]" `; -exports[`toBeCalledWith works with jest.fn and arguments that don't match 1`] = ` -"expect(jest.fn()).toBeCalledWith(expected) - -Expected mock function to have been called with: - [\\"foo\\", \\"bar\\"] -But it was called with: - [\\"foo\\", \\"bar1\\"]" -`; - -exports[`toBeCalledWith works with jest.fn and arguments that match 1`] = ` -"expect(jest.fn()).not.toBeCalledWith(expected) - -Expected mock function not to have been called with: - [\\"foo\\", \\"bar\\"]" -`; - -exports[`toBeCalledWith works with jest.fn and many arguments 1`] = ` -"expect(jest.fn()).not.toBeCalledWith(expected) - -Expected mock function not to have been called with: - [\\"foo\\", \\"bar\\"]" -`; - -exports[`toBeCalledWith works with jest.fn and many arguments that don't match 1`] = ` -"expect(jest.fn()).toBeCalledWith(expected) - -Expected mock function to have been called with: - [\\"foo\\", \\"bar\\"] -But it was called with: - [\\"foo\\", \\"bar3\\"], [\\"foo\\", \\"bar2\\"], [\\"foo\\", \\"bar1\\"]" -`; - -exports[`toBeCalledWith works with jest.fn when not called 1`] = ` -"expect(jest.fn()).toBeCalledWith(expected) - -Expected mock function to have been called with: - [\\"foo\\", \\"bar\\"] -But it was not called." -`; - exports[`toHaveBeenCalled works only on spies or jest.fn 1`] = ` "expect(jest.fn())[.not].toHaveBeenCalled() @@ -155,27 +94,6 @@ Received: function: [Function fn]" `; -exports[`toHaveBeenCalled works with jasmine.createSpy 1`] = ` -"expect(spy).toHaveBeenCalled() - -Expected spy to have been called." -`; - -exports[`toHaveBeenCalled works with jasmine.createSpy 2`] = ` -"expect(spy).not.toHaveBeenCalled() - -Expected spy not to be called but it was called with: - Array []" -`; - -exports[`toHaveBeenCalled works with jasmine.createSpy 3`] = ` -"expect(received)[.not].toHaveBeenCalled() - -Matcher does not accept any arguments. -Got: - number: 555" -`; - exports[`toHaveBeenCalled works with jest.fn 1`] = ` "expect(jest.fn()).toHaveBeenCalled() @@ -246,21 +164,21 @@ Got: `; exports[`toHaveBeenCalledTimes fails if function called less than expected times 1`] = ` -"expect(spy).toHaveBeenCalledTimes(2) +"expect(jest.fn()).toHaveBeenCalledTimes(2) -Expected spy to have been called two times, but it was called one time." +Expected mock function to have been called two times, but it was called one time." `; exports[`toHaveBeenCalledTimes fails if function called more than expected times 1`] = ` -"expect(spy).toHaveBeenCalledTimes(2) +"expect(jest.fn()).toHaveBeenCalledTimes(2) -Expected spy to have been called two times, but it was called three times." +Expected mock function to have been called two times, but it was called three times." `; exports[`toHaveBeenCalledTimes passes if function called equal to expected times 1`] = ` -"expect(spy).not.toHaveBeenCalledTimes(2) +"expect(jest.fn()).not.toHaveBeenCalledTimes(2) -Expected spy not to be called two times, but it was called exactly two times." +Expected mock function not to be called two times, but it was called exactly two times." `; exports[`toHaveBeenCalledTimes verifies that actual is a Spy 1`] = ` @@ -279,47 +197,15 @@ Received: function: [Function fn]" `; -exports[`toHaveBeenCalledWith works with jasmine.createSpy and arguments that don't match 1`] = ` -"expect(spy).toHaveBeenCalledWith(expected) - -Expected spy to have been called with: - [\\"foo\\", \\"bar\\"] -But it was called with: - [\\"foo\\", \\"bar1\\"]" -`; - -exports[`toHaveBeenCalledWith works with jasmine.createSpy and arguments that match 1`] = ` -"expect(spy).not.toHaveBeenCalledWith(expected) - -Expected spy not to have been called with: - [\\"foo\\", \\"bar\\"]" -`; - -exports[`toHaveBeenCalledWith works with jasmine.createSpy and many arguments 1`] = ` -"expect(spy).not.toHaveBeenCalledWith(expected) - -Expected spy not to have been called with: - [\\"foo\\", \\"bar\\"]" -`; - -exports[`toHaveBeenCalledWith works with jasmine.createSpy and many arguments that don't match 1`] = ` -"expect(spy).toHaveBeenCalledWith(expected) - -Expected spy to have been called with: - [\\"foo\\", \\"bar\\"] -But it was called with: - [\\"foo\\", \\"bar3\\"], [\\"foo\\", \\"bar2\\"], [\\"foo\\", \\"bar1\\"]" -`; - -exports[`toHaveBeenCalledWith works with jasmine.createSpy when not called 1`] = ` -"expect(spy).toHaveBeenCalledWith(expected) +exports[`toHaveBeenCalledWith works when not called 1`] = ` +"expect(jest.fn()).toHaveBeenCalledWith(expected) -Expected spy to have been called with: +Expected mock function to have been called with: [\\"foo\\", \\"bar\\"] But it was not called." `; -exports[`toHaveBeenCalledWith works with jest.fn and arguments that don't match 1`] = ` +exports[`toHaveBeenCalledWith works with arguments that don't match 1`] = ` "expect(jest.fn()).toHaveBeenCalledWith(expected) Expected mock function to have been called with: @@ -328,21 +214,21 @@ But it was called with: [\\"foo\\", \\"bar1\\"]" `; -exports[`toHaveBeenCalledWith works with jest.fn and arguments that match 1`] = ` +exports[`toHaveBeenCalledWith works with arguments that match 1`] = ` "expect(jest.fn()).not.toHaveBeenCalledWith(expected) Expected mock function not to have been called with: [\\"foo\\", \\"bar\\"]" `; -exports[`toHaveBeenCalledWith works with jest.fn and many arguments 1`] = ` +exports[`toHaveBeenCalledWith works with many arguments 1`] = ` "expect(jest.fn()).not.toHaveBeenCalledWith(expected) Expected mock function not to have been called with: [\\"foo\\", \\"bar\\"]" `; -exports[`toHaveBeenCalledWith works with jest.fn and many arguments that don't match 1`] = ` +exports[`toHaveBeenCalledWith works with many arguments that don't match 1`] = ` "expect(jest.fn()).toHaveBeenCalledWith(expected) Expected mock function to have been called with: @@ -351,14 +237,6 @@ But it was called with: [\\"foo\\", \\"bar3\\"], [\\"foo\\", \\"bar2\\"], [\\"foo\\", \\"bar1\\"]" `; -exports[`toHaveBeenCalledWith works with jest.fn when not called 1`] = ` -"expect(jest.fn()).toHaveBeenCalledWith(expected) - -Expected mock function to have been called with: - [\\"foo\\", \\"bar\\"] -But it was not called." -`; - exports[`toHaveBeenLastCalledWith works only on spies or jest.fn 1`] = ` "expect(jest.fn())[.not].toHaveBeenLastCalledWith() @@ -367,48 +245,15 @@ Received: function: [Function fn]" `; -exports[`toHaveBeenLastCalledWith works with jasmine.createSpy and arguments that don't match 1`] = ` -"expect(spy).toHaveBeenLastCalledWith(expected) - -Expected spy to have been last called with: - [\\"foo\\", \\"bar\\"] -But it was last called with: - [\\"foo\\", \\"bar1\\"]" -`; - -exports[`toHaveBeenLastCalledWith works with jasmine.createSpy and arguments that match 1`] = ` -"expect(spy).not.toHaveBeenLastCalledWith(expected) - -Expected spy to not have been last called with: - [\\"foo\\", \\"bar\\"]" -`; - -exports[`toHaveBeenLastCalledWith works with jasmine.createSpy and many arguments 1`] = ` -"expect(spy).not.toHaveBeenLastCalledWith(expected) - -Expected spy to not have been last called with: - [\\"foo\\", \\"bar\\"]" -`; - -exports[`toHaveBeenLastCalledWith works with jasmine.createSpy and many arguments that don't match 1`] = ` -"expect(spy).toHaveBeenLastCalledWith(expected) - -Expected spy to have been last called with: - [\\"foo\\", \\"bar\\"] -But it was last called with: - [\\"foo\\", \\"bar3\\"] -and two more calls." -`; - -exports[`toHaveBeenLastCalledWith works with jasmine.createSpy when not called 1`] = ` -"expect(spy).toHaveBeenLastCalledWith(expected) +exports[`toHaveBeenLastCalledWith works when not called 1`] = ` +"expect(jest.fn()).toHaveBeenLastCalledWith(expected) -Expected spy to have been last called with: +Expected mock function to have been last called with: [\\"foo\\", \\"bar\\"] But it was not called." `; -exports[`toHaveBeenLastCalledWith works with jest.fn and arguments that don't match 1`] = ` +exports[`toHaveBeenLastCalledWith works with arguments that don't match 1`] = ` "expect(jest.fn()).toHaveBeenLastCalledWith(expected) Expected mock function to have been last called with: @@ -417,21 +262,21 @@ But it was last called with: [\\"foo\\", \\"bar1\\"]" `; -exports[`toHaveBeenLastCalledWith works with jest.fn and arguments that match 1`] = ` +exports[`toHaveBeenLastCalledWith works with arguments that match 1`] = ` "expect(jest.fn()).not.toHaveBeenLastCalledWith(expected) Expected mock function to not have been last called with: [\\"foo\\", \\"bar\\"]" `; -exports[`toHaveBeenLastCalledWith works with jest.fn and many arguments 1`] = ` +exports[`toHaveBeenLastCalledWith works with many arguments 1`] = ` "expect(jest.fn()).not.toHaveBeenLastCalledWith(expected) Expected mock function to not have been last called with: [\\"foo\\", \\"bar\\"]" `; -exports[`toHaveBeenLastCalledWith works with jest.fn and many arguments that don't match 1`] = ` +exports[`toHaveBeenLastCalledWith works with many arguments that don't match 1`] = ` "expect(jest.fn()).toHaveBeenLastCalledWith(expected) Expected mock function to have been last called with: @@ -440,11 +285,3 @@ But it was last called with: [\\"foo\\", \\"bar3\\"] and two more calls." `; - -exports[`toHaveBeenLastCalledWith works with jest.fn when not called 1`] = ` -"expect(jest.fn()).toHaveBeenLastCalledWith(expected) - -Expected mock function to have been last called with: - [\\"foo\\", \\"bar\\"] -But it was not called." -`; diff --git a/packages/jest-matchers/src/__tests__/spyMatchers-test.js b/packages/jest-matchers/src/__tests__/spyMatchers-test.js index 1f39ae5abd48..8dd5da1ab50f 100644 --- a/packages/jest-matchers/src/__tests__/spyMatchers-test.js +++ b/packages/jest-matchers/src/__tests__/spyMatchers-test.js @@ -10,14 +10,9 @@ const jestExpect = require('../'); -[ - ['toHaveBeenCalled', 'jasmine.createSpy'], - ['toHaveBeenCalled', 'jest.fn'], - ['toBeCalled', 'jasmine.createSpy'], - ['toBeCalled', 'jest.fn'], -].forEach(([called, mockName]) => { - test(`${called} works with ${mockName}`, () => { - const fn = mockName === 'jest.fn' ? jest.fn() : jasmine.createSpy('fn'); +['toHaveBeenCalled', 'toBeCalled'].forEach(called => { + test(`${called} works with jest.fn`, () => { + const fn = jest.fn(); jestExpect(fn).not[called](); expect(() => jestExpect(fn)[called]()).toThrowErrorMatchingSnapshot(); @@ -32,7 +27,7 @@ const jestExpect = require('../'); describe('toHaveBeenCalledTimes', () => { it('accepts only numbers', () => { - const fn = jasmine.createSpy('fn'); + const fn = jest.fn(); fn(); jestExpect(fn).toHaveBeenCalledTimes(1); @@ -51,16 +46,8 @@ describe('toHaveBeenCalledTimes', () => { ).toThrowErrorMatchingSnapshot(); }); - it('works both for Mock functions and Spies', () => { - [jasmine.createSpy('fn'), jest.fn()].forEach(fn => { - fn(); - fn(); - jestExpect(fn).toHaveBeenCalledTimes(2); - }); - }); - it('passes if function called equal to expected times', () => { - const fn = jasmine.createSpy('fn'); + const fn = jest.fn(); fn(); fn(); @@ -72,7 +59,7 @@ describe('toHaveBeenCalledTimes', () => { }); it('fails if function called more than expected times', () => { - const fn = jasmine.createSpy('fn'); + const fn = jest.fn(); fn(); fn(); fn(); @@ -86,7 +73,7 @@ describe('toHaveBeenCalledTimes', () => { }); it('fails if function called less than expected times', () => { - const fn = jasmine.createSpy('fn'); + const fn = jest.fn(); fn(); jestExpect(fn).toHaveBeenCalledTimes(1); @@ -114,19 +101,12 @@ describe('toHaveBeenCalledTimes', () => { }); [ - ['lastCalledWith', 'jest.fn'], - ['toBeCalledWith', 'jest.fn'], - ['toHaveBeenCalledWith', 'jasmine.createSpy'], - ['toHaveBeenCalledWith', 'jest.fn'], - ['toHaveBeenLastCalledWith', 'jasmine.createSpy'], - ['toHaveBeenLastCalledWith', 'jest.fn'], -].forEach(([calledWith, mockName]) => { - const getFunction = () => { - return mockName === 'jest.fn' ? jest.fn() : jasmine.createSpy('fn'); - }; - - test(`${calledWith} works with ${mockName} when not called`, () => { - const fn = getFunction(); + 'lastCalledWith', + 'toHaveBeenCalledWith', + 'toHaveBeenLastCalledWith', +].forEach(calledWith => { + test(`${calledWith} works when not called`, () => { + const fn = jest.fn(); jestExpect(fn).not[calledWith]('foo', 'bar'); expect(() => @@ -134,14 +114,14 @@ describe('toHaveBeenCalledTimes', () => { ).toThrowErrorMatchingSnapshot(); }); - test(`${calledWith} works with ${mockName} and no arguments`, () => { - const fn = getFunction(); + test(`${calledWith} works with no arguments`, () => { + const fn = jest.fn(); fn(); jestExpect(fn)[calledWith](); }); - test(`${calledWith} works with ${mockName} and arguments that don't match`, () => { - const fn = getFunction(); + test(`${calledWith} works with arguments that don't match`, () => { + const fn = jest.fn(); fn('foo', 'bar1'); jestExpect(fn).not[calledWith]('foo', 'bar'); @@ -151,8 +131,8 @@ describe('toHaveBeenCalledTimes', () => { ).toThrowErrorMatchingSnapshot(); }); - test(`${calledWith} works with ${mockName} and arguments that match`, () => { - const fn = getFunction(); + test(`${calledWith} works with arguments that match`, () => { + const fn = jest.fn(); fn('foo', 'bar'); jestExpect(fn)[calledWith]('foo', 'bar'); @@ -162,8 +142,8 @@ describe('toHaveBeenCalledTimes', () => { ).toThrowErrorMatchingSnapshot(); }); - test(`${calledWith} works with ${mockName} and many arguments that don't match`, () => { - const fn = getFunction(); + test(`${calledWith} works with many arguments that don't match`, () => { + const fn = jest.fn(); fn('foo', 'bar1'); fn('foo', 'bar2'); fn('foo', 'bar3'); @@ -175,8 +155,8 @@ describe('toHaveBeenCalledTimes', () => { ).toThrowErrorMatchingSnapshot(); }); - test(`${calledWith} works with ${mockName} and many arguments`, () => { - const fn = getFunction(); + test(`${calledWith} works with many arguments`, () => { + const fn = jest.fn(); fn('foo1', 'bar'); fn('foo', 'bar1'); fn('foo', 'bar'); diff --git a/packages/jest-matchers/src/__tests__/toThrowMatchers-test.js b/packages/jest-matchers/src/__tests__/toThrowMatchers-test.js index d9c48e8b2fe4..a8f413f517e8 100644 --- a/packages/jest-matchers/src/__tests__/toThrowMatchers-test.js +++ b/packages/jest-matchers/src/__tests__/toThrowMatchers-test.js @@ -110,26 +110,6 @@ class Error { }); }); - describe('errors', () => { - it('works', () => { - it('passes', () => { - jestExpect(() => { - throw new Err(); - })[toThrow](new Err()); - jestExpect(() => { - throw new Err('Message'); - })[toThrow](new Err('Message')); - jestExpect(() => { - throw new Err(); - })[toThrow](new Error()); - jestExpect(() => { - throw new Err(); - }).not[toThrow](new Err2()); - jestExpect(() => {}).not[toThrow](new Err()); - }); - }); - }); - describe('error class', () => { it('passes', () => { jestExpect(() => { diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index 79b69814948a..5a853a641b96 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -716,7 +716,11 @@ class Runtime { const spyOn = this._moduleMocker.spyOn.bind(this._moduleMocker); const setTestTimeout = (timeout: number) => { - this._environment.global.jasmine.DEFAULT_TIMEOUT_INTERVAL = timeout; + this._environment.global.jasmine + ? (this._environment.global.jasmine.DEFAULT_TIMEOUT_INTERVAL = timeout) + : (this._environment.global[ + Symbol.for('TEST_TIMEOUT_SYMBOL') + ] = timeout); }; const runtime = { diff --git a/testSetupFile.js b/testSetupFile.js index 2cc60baf4fb8..625e60464432 100644 --- a/testSetupFile.js +++ b/testSetupFile.js @@ -12,7 +12,7 @@ const jasmineReporters = require('jasmine-reporters'); // timeouts on travis jest.setTestTimeout(70000); -if (process.env.APPVEYOR_API_URL) { +if (global.jasmine && process.env.APPVEYOR_API_URL) { // Running on AppVeyor, add the custom reporter. jasmine.getEnv().addReporter(new jasmineReporters.AppVeyorReporter()); } diff --git a/types/TestResult.js b/types/TestResult.js index 3d97fc3a0111..2b5ee9b34578 100644 --- a/types/TestResult.js +++ b/types/TestResult.js @@ -84,7 +84,7 @@ export type Milliseconds = number; export type AssertionResult = {| ancestorTitles: Array, - duration?: Milliseconds, + duration?: ?Milliseconds, failureMessages: Array, fullName: string, numPassingAsserts: number,