diff --git a/CHANGELOG.md b/CHANGELOG.md index 462b3dc2222b..064d6eab7e30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features * `[jest-watch]` create new package `jest-watch` to ease custom watch plugin development ([#6318](https://github.com/facebook/jest/pull/6318)) +* Add a config/CLI option `errorOnDeprecated` which makes calling deprecated APIs throw hepful error messages. ### Fixes diff --git a/TestUtils.js b/TestUtils.js index 2faf446dde4a..c92b4ba9ae60 100644 --- a/TestUtils.js +++ b/TestUtils.js @@ -24,6 +24,7 @@ const DEFAULT_GLOBAL_CONFIG: GlobalConfig = { detectLeaks: false, detectOpenHandles: false, enabledTestsMap: null, + errorOnDeprecated: false, expand: false, filter: null, findRelatedTests: false, @@ -75,6 +76,7 @@ const DEFAULT_PROJECT_CONFIG: ProjectConfig = { detectLeaks: false, detectOpenHandles: false, displayName: undefined, + errorOnDeprecated: false, filter: null, forceCoverageMatch: [], globals: {}, diff --git a/docs/CLI.md b/docs/CLI.md index ee8f89e1613d..631074ba59d7 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -149,6 +149,10 @@ Attempt to collect and print open handles preventing Jest from exiting cleanly. The test environment used for all tests. This can point to any file or node module. Examples: `jsdom`, `node` or `path/to/my-environment.js`. +### `--errorOnDeprecated` + +Make calling deprecated APIs throw helpful error messages. Useful for easing the upgrade process. + ### `--expand` Alias: `-e`. Use this flag to show full diffs and errors instead of a patch. diff --git a/docs/Configuration.md b/docs/Configuration.md index 4c36920f45fa..697804822bdc 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -664,6 +664,12 @@ Pretty foo: Object { To make a dependency explicit instead of implicit, you can call [`expect.addSnapshotSerializer`](ExpectAPI.md#expectaddsnapshotserializerserializer) to add a module for an individual test file instead of adding its path to `snapshotSerializers` in Jest configuration. +### `errorOnDeprecated` [boolean] + +Default: `false` + +Make calling deprecated APIs throw helpful error messages. Useful for easing the upgrade process. + ### `testEnvironment` [string] Default: `"jsdom"` diff --git a/e2e/__tests__/__snapshots__/error-on-deprecated.test.js.snap b/e2e/__tests__/__snapshots__/error-on-deprecated.test.js.snap new file mode 100644 index 000000000000..c5542e8b0c26 --- /dev/null +++ b/e2e/__tests__/__snapshots__/error-on-deprecated.test.js.snap @@ -0,0 +1,226 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`fail.test.js errors in errorOnDeprecated mode 1`] = ` +"FAIL __tests__/fail.test.js + ✕ fail + + ● fail + + Illegal usage of global \`fail\`, prefer throwing an error, or the \`done.fail\` callback. + + 11 | test('fail', () => { + 12 | if (true) { + > 13 | fail('The truth hurts!'); + | ^ + 14 | } + 15 | }); + 16 | + + at __tests__/fail.test.js:13:5 + +" +`; + +exports[`jasmine.addMatchers.test.js errors in errorOnDeprecated mode 1`] = ` +"FAIL __tests__/jasmine.addMatchers.test.js + ● Test suite failed to run + + Illegal usage of \`jasmine.addMatchers\`, prefer \`expect.extends\`. + + 7 | 'use strict'; + 8 | + > 9 | jasmine.addMatchers({ + | ^ + 10 | theSpanishInquisition: () => ({ + 11 | compare: (actual, expected) => ({ + 12 | message: 'Nobdy expects the Spanish Inquisition!', + + at __tests__/jasmine.addMatchers.test.js:9:9 + +" +`; + +exports[`jasmine.any.test.js errors in errorOnDeprecated mode 1`] = ` +"FAIL __tests__/jasmine.any.test.js + ✕ jasmine.any + + ● jasmine.any + + Illegal usage of \`jasmine.any\`, prefer \`expect.any\`. + + 8 | + 9 | test('jasmine.any', () => { + > 10 | expect({name: 'Jessie'}).toEqual({name: jasmine.any(String)}); + | ^ + 11 | }); + 12 | + + at __tests__/jasmine.any.test.js:10:51 + +" +`; + +exports[`jasmine.anything.test.js errors in errorOnDeprecated mode 1`] = ` +"FAIL __tests__/jasmine.anything.test.js + ✕ jasmine.anything + + ● jasmine.anything + + Illegal usage of \`jasmine.anything\`, prefer \`expect.anything\`. + + 8 | + 9 | test('jasmine.anything', () => { + > 10 | expect({input: ['some', 'stuff']}).toEqual({input: jasmine.anything()}); + | ^ + 11 | }); + 12 | + + at __tests__/jasmine.anything.test.js:10:62 + +" +`; + +exports[`jasmine.arrayContaining.test.js errors in errorOnDeprecated mode 1`] = ` +"FAIL __tests__/jasmine.arrayContaining.test.js + ✕ jasmine.arrayContaining + + ● jasmine.arrayContaining + + Illegal usage of \`jasmine.arrayContaining\`, prefer \`expect.arrayContaining\`. + + 8 | + 9 | test('jasmine.arrayContaining', () => { + > 10 | expect(['some', 'stuff']).toEqual(jasmine.arrayContaining(['stuff'])); + | ^ + 11 | }); + 12 | + + at __tests__/jasmine.arrayContaining.test.js:10:45 + +" +`; + +exports[`jasmine.createSpy.test.js errors in errorOnDeprecated mode 1`] = ` +"FAIL __tests__/jasmine.createSpy.test.js + ✕ jasmine.createSpy + + ● jasmine.createSpy + + Illegal usage of \`jasmine.createSpy\`, prefer \`jest.fn\`. + + 8 | + 9 | test('jasmine.createSpy', () => { + > 10 | const mySpy = jasmine.createSpy(); + | ^ + 11 | mySpy('hello?'); + 12 | expect(mySpy).toHaveBeenCalledWith('hello?'); + 13 | }); + + at __tests__/jasmine.createSpy.test.js:10:25 + +" +`; + +exports[`jasmine.objectContaining.test.js errors in errorOnDeprecated mode 1`] = ` +"FAIL __tests__/jasmine.objectContaining.test.js + ✕ jasmine.objectContaining + + ● jasmine.objectContaining + + Illegal usage of \`jasmine.objectContaining\`, prefer \`expect.objectContaining\`. + + 9 | test('jasmine.objectContaining', () => { + 10 | expect({input: 'trash', output: 'trash'}).toEqual( + > 11 | jasmine.objectContaining({output: 'trash'}) + | ^ + 12 | ); + 13 | }); + 14 | + + at __tests__/jasmine.objectContaining.test.js:11:13 + +" +`; + +exports[`jasmine.stringMatching.test.js errors in errorOnDeprecated mode 1`] = ` +"FAIL __tests__/jasmine.stringMatching.test.js + ✕ jasmine.stringMatching + + ● jasmine.stringMatching + + Illegal usage of \`jasmine.stringMatching\`, prefer \`expect.stringMatching\`. + + 8 | + 9 | test('jasmine.stringMatching', () => { + > 10 | expect('Greetings Earthling!').toEqual(jasmine.stringMatching(/^Greetings/)); + | ^ + 11 | }); + 12 | + + at __tests__/jasmine.stringMatching.test.js:10:50 + +" +`; + +exports[`pending.test.js errors in errorOnDeprecated mode 1`] = ` +"FAIL __tests__/pending.test.js + ✕ pending + + ● pending + + Illegal usage of global \`pending\`, prefer explicitly skipping a test using \`test.skip\` + + 9 | test('pending', () => { + 10 | if (true) { + > 11 | pending('This test is pending.'); + | ^ + 12 | } + 13 | expect(false).toBe(true); + 14 | }); + + at __tests__/pending.test.js:11:5 + +" +`; + +exports[`spyOn.test.js errors in errorOnDeprecated mode 1`] = ` +"FAIL __tests__/spyOn.test.js + ✕ spyOn + + ● spyOn + + Illegal usage of global \`spyOn\`, prefer \`jest.spyOn\`. + + 15 | + 16 | test('spyOn', () => { + > 17 | spyOn(subject, 'func').and.returnValue('bar'); + | ^ + 18 | expect(subject.func()).toBe('bar'); + 19 | }); + 20 | + + at __tests__/spyOn.test.js:17:3 + +" +`; + +exports[`spyOnProperty.test.js errors in errorOnDeprecated mode 1`] = ` +"FAIL __tests__/spyOnProperty.test.js + ✕ spyOnProperty + + ● spyOnProperty + + Illegal usage of global \`spyOnProperty\`, prefer \`jest.spyOn\`. + + 22 | }; + 23 | + > 24 | const spy = spyOnProperty(obj, 'method', 'get'); + | ^ + 25 | + 26 | obj.method(); + 27 | + + at __tests__/spyOnProperty.test.js:24:15 + +" +`; diff --git a/e2e/__tests__/__snapshots__/show_config.test.js.snap b/e2e/__tests__/__snapshots__/show_config.test.js.snap index 4a12324818a5..452102922c3b 100644 --- a/e2e/__tests__/__snapshots__/show_config.test.js.snap +++ b/e2e/__tests__/__snapshots__/show_config.test.js.snap @@ -14,6 +14,7 @@ exports[`--showConfig outputs config info and exits 1`] = ` ], \\"detectLeaks\\": false, \\"detectOpenHandles\\": false, + \\"errorOnDeprecated\\": false, \\"filter\\": null, \\"forceCoverageMatch\\": [], \\"globals\\": {}, @@ -81,6 +82,7 @@ exports[`--showConfig outputs config info and exits 1`] = ` ], \\"detectLeaks\\": false, \\"detectOpenHandles\\": false, + \\"errorOnDeprecated\\": false, \\"expand\\": false, \\"filter\\": null, \\"globalSetup\\": null, diff --git a/e2e/__tests__/error-on-deprecated.test.js b/e2e/__tests__/error-on-deprecated.test.js new file mode 100644 index 000000000000..46e33ea3cc6b --- /dev/null +++ b/e2e/__tests__/error-on-deprecated.test.js @@ -0,0 +1,58 @@ +/** + * 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 runJest = require('../runJest'); +const {extractSummary} = require('../Utils'); +const ConditionalTest = require('../../scripts/ConditionalTest'); + +ConditionalTest.skipSuiteOnJestCircus(); + +const testFiles = [ + 'fail.test.js', + 'jasmine.addMatchers.test.js', + 'jasmine.any.test.js', + 'jasmine.anything.test.js', + 'jasmine.arrayContaining.test.js', + 'jasmine.createSpy.test.js', + 'jasmine.objectContaining.test.js', + 'jasmine.stringMatching.test.js', + 'pending.test.js', + 'spyOn.test.js', + 'spyOnProperty.test.js', +]; + +const SHOULD_NOT_PASS_IN_JEST = new Set([ + 'fail.test.js', + 'spyOnProperty.test.js', +]); + +testFiles.forEach(testFile => { + test(`${testFile} errors in errorOnDeprecated mode`, () => { + const result = runJest('error-on-deprecated', [ + testFile, + '--errorOnDeprecated', + ]); + expect(result.status).toBe(1); + const {rest} = extractSummary(result.stderr); + expect(rest).toMatchSnapshot(); + }); +}); + +testFiles.forEach(testFile => { + const shouldPass = SHOULD_NOT_PASS_IN_JEST.has(testFile); + + const expectation = `${testFile} ${shouldPass ? 'errors' : 'passes'}`; + const testName = `${expectation} when not in errorOnDeprecated mode`; + + test(testName, () => { + const result = runJest('error-on-deprecated', [testFile]); + expect(result.status).toBe(shouldPass ? 1 : 0); + }); +}); diff --git a/e2e/error-on-deprecated/__tests__/fail.test.js b/e2e/error-on-deprecated/__tests__/fail.test.js new file mode 100644 index 000000000000..05f74ba03c33 --- /dev/null +++ b/e2e/error-on-deprecated/__tests__/fail.test.js @@ -0,0 +1,15 @@ +/** + * 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'; + +/* globals fail */ + +test('fail', () => { + if (true) { + fail('The truth hurts!'); + } +}); diff --git a/e2e/error-on-deprecated/__tests__/jasmine.addMatchers.test.js b/e2e/error-on-deprecated/__tests__/jasmine.addMatchers.test.js new file mode 100644 index 000000000000..cc2b27482cf5 --- /dev/null +++ b/e2e/error-on-deprecated/__tests__/jasmine.addMatchers.test.js @@ -0,0 +1,20 @@ +/** + * 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'; + +jasmine.addMatchers({ + theSpanishInquisition: () => ({ + compare: (actual, expected) => ({ + message: 'Nobdy expects the Spanish Inquisition!', + pass: false, + }), + }), +}); + +test('jasmine.addMatchers', () => { + expect('Anybody').not.theSpanishInquisition(); +}); diff --git a/e2e/error-on-deprecated/__tests__/jasmine.any.test.js b/e2e/error-on-deprecated/__tests__/jasmine.any.test.js new file mode 100644 index 000000000000..269090614be2 --- /dev/null +++ b/e2e/error-on-deprecated/__tests__/jasmine.any.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'; + +test('jasmine.any', () => { + expect({name: 'Jessie'}).toEqual({name: jasmine.any(String)}); +}); diff --git a/e2e/error-on-deprecated/__tests__/jasmine.anything.test.js b/e2e/error-on-deprecated/__tests__/jasmine.anything.test.js new file mode 100644 index 000000000000..b4a9c01c227f --- /dev/null +++ b/e2e/error-on-deprecated/__tests__/jasmine.anything.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'; + +test('jasmine.anything', () => { + expect({input: ['some', 'stuff']}).toEqual({input: jasmine.anything()}); +}); diff --git a/e2e/error-on-deprecated/__tests__/jasmine.arrayContaining.test.js b/e2e/error-on-deprecated/__tests__/jasmine.arrayContaining.test.js new file mode 100644 index 000000000000..32156d058e6f --- /dev/null +++ b/e2e/error-on-deprecated/__tests__/jasmine.arrayContaining.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'; + +test('jasmine.arrayContaining', () => { + expect(['some', 'stuff']).toEqual(jasmine.arrayContaining(['stuff'])); +}); diff --git a/e2e/error-on-deprecated/__tests__/jasmine.createSpy.test.js b/e2e/error-on-deprecated/__tests__/jasmine.createSpy.test.js new file mode 100644 index 000000000000..1887b5495d91 --- /dev/null +++ b/e2e/error-on-deprecated/__tests__/jasmine.createSpy.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'; + +test('jasmine.createSpy', () => { + const mySpy = jasmine.createSpy(); + mySpy('hello?'); + expect(mySpy).toHaveBeenCalledWith('hello?'); +}); diff --git a/e2e/error-on-deprecated/__tests__/jasmine.objectContaining.test.js b/e2e/error-on-deprecated/__tests__/jasmine.objectContaining.test.js new file mode 100644 index 000000000000..d3cc7f174018 --- /dev/null +++ b/e2e/error-on-deprecated/__tests__/jasmine.objectContaining.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'; + +test('jasmine.objectContaining', () => { + expect({input: 'trash', output: 'trash'}).toEqual( + jasmine.objectContaining({output: 'trash'}) + ); +}); diff --git a/e2e/error-on-deprecated/__tests__/jasmine.stringMatching.test.js b/e2e/error-on-deprecated/__tests__/jasmine.stringMatching.test.js new file mode 100644 index 000000000000..e469bb90938b --- /dev/null +++ b/e2e/error-on-deprecated/__tests__/jasmine.stringMatching.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'; + +test('jasmine.stringMatching', () => { + expect('Greetings Earthling!').toEqual(jasmine.stringMatching(/^Greetings/)); +}); diff --git a/e2e/error-on-deprecated/__tests__/pending.test.js b/e2e/error-on-deprecated/__tests__/pending.test.js new file mode 100644 index 000000000000..5a49ef6fcb70 --- /dev/null +++ b/e2e/error-on-deprecated/__tests__/pending.test.js @@ -0,0 +1,14 @@ +/** + * 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'; + +test('pending', () => { + if (true) { + pending('This test is pending.'); + } + expect(false).toBe(true); +}); diff --git a/e2e/error-on-deprecated/__tests__/spyOn.test.js b/e2e/error-on-deprecated/__tests__/spyOn.test.js new file mode 100644 index 000000000000..7d6c932228f1 --- /dev/null +++ b/e2e/error-on-deprecated/__tests__/spyOn.test.js @@ -0,0 +1,19 @@ +/** + * 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'; + +/* globals spyOn */ +const subject = { + func: () => { + return 'foo'; + }, +}; + +test('spyOn', () => { + spyOn(subject, 'func').and.returnValue('bar'); + expect(subject.func()).toBe('bar'); +}); diff --git a/e2e/error-on-deprecated/__tests__/spyOnProperty.test.js b/e2e/error-on-deprecated/__tests__/spyOnProperty.test.js new file mode 100644 index 000000000000..fb81697c6481 --- /dev/null +++ b/e2e/error-on-deprecated/__tests__/spyOnProperty.test.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'; + +/* globals spyOnProperty */ + +const myObject = {}; +Object.defineProperties(myObject, { + name: () => 'Jordan', +}); + +test('spyOnProperty', () => { + let isOriginalCalled = false; + const obj = { + get method() { + return () => (isOriginalCalled = true); + }, + }; + + const spy = spyOnProperty(obj, 'method', 'get'); + + obj.method(); + + expect(isOriginalCalled).toBe(true); + expect(spy).toHaveBeenCalled(); +}); diff --git a/e2e/error-on-deprecated/package.json b/e2e/error-on-deprecated/package.json new file mode 100644 index 000000000000..148788b25446 --- /dev/null +++ b/e2e/error-on-deprecated/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "testEnvironment": "node" + } +} diff --git a/packages/jest-cli/src/cli/args.js b/packages/jest-cli/src/cli/args.js index 6acf3ae16985..edc17bda56a3 100644 --- a/packages/jest-cli/src/cli/args.js +++ b/packages/jest-cli/src/cli/args.js @@ -239,6 +239,11 @@ export const options = { '`path/to/my-environment.js`', type: 'string', }, + errorOnDeprecated: { + default: false, + description: 'Make calling deprecated APIs throw helpful error messages.', + type: 'boolean', + }, expand: { alias: 'e', default: undefined, diff --git a/packages/jest-config/src/defaults.js b/packages/jest-config/src/defaults.js index 4aab986b64d9..6fdf7fb55c70 100644 --- a/packages/jest-config/src/defaults.js +++ b/packages/jest-config/src/defaults.js @@ -39,6 +39,7 @@ export default ({ coverageReporters: ['json', 'text', 'lcov', 'clover'], detectLeaks: false, detectOpenHandles: false, + errorOnDeprecated: false, expand: false, filter: null, forceCoverageMatch: [], diff --git a/packages/jest-config/src/index.js b/packages/jest-config/src/index.js index 8b3074957c52..b5392bb2b97e 100644 --- a/packages/jest-config/src/index.js +++ b/packages/jest-config/src/index.js @@ -110,6 +110,7 @@ const getConfigs = ( detectLeaks: options.detectLeaks, detectOpenHandles: options.detectOpenHandles, enabledTestsMap: options.enabledTestsMap, + errorOnDeprecated: options.errorOnDeprecated, expand: options.expand, filter: options.filter, findRelatedTests: options.findRelatedTests, @@ -160,6 +161,7 @@ const getConfigs = ( detectLeaks: options.detectLeaks, detectOpenHandles: options.detectOpenHandles, displayName: options.displayName, + errorOnDeprecated: options.errorOnDeprecated, filter: options.filter, forceCoverageMatch: options.forceCoverageMatch, globals: options.globals, diff --git a/packages/jest-config/src/normalize.js b/packages/jest-config/src/normalize.js index 9efc83d073c3..72e3543ae42f 100644 --- a/packages/jest-config/src/normalize.js +++ b/packages/jest-config/src/normalize.js @@ -520,6 +520,7 @@ export default function normalize(options: InitialOptions, argv: Argv) { case 'detectLeaks': case 'detectOpenHandles': case 'displayName': + case 'errorOnDeprecated': case 'expand': case 'globals': case 'findRelatedTests': diff --git a/packages/jest-config/src/valid_config.js b/packages/jest-config/src/valid_config.js index 75e30f6365e9..1c5372c05b0a 100644 --- a/packages/jest-config/src/valid_config.js +++ b/packages/jest-config/src/valid_config.js @@ -37,6 +37,7 @@ export default ({ }, }, displayName: 'project-name', + errorOnDeprecated: false, expand: false, filter: '/filter.js', forceCoverageMatch: ['**/*.t.js'], diff --git a/packages/jest-jasmine2/src/error_on_private.js b/packages/jest-jasmine2/src/error_on_private.js new file mode 100644 index 000000000000..5b3469a5a8b6 --- /dev/null +++ b/packages/jest-jasmine2/src/error_on_private.js @@ -0,0 +1,52 @@ +/** + * 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 + */ + +import type {Global} from '../../../types/Global'; + +// prettier-ignore +const disabledGlobals = { + fail: 'Illegal usage of global `fail`, prefer throwing an error, or the `done.fail` callback.', + pending: 'Illegal usage of global `pending`, prefer explicitly skipping a test using `test.skip`', + spyOn: 'Illegal usage of global `spyOn`, prefer `jest.spyOn`.', + spyOnProperty: 'Illegal usage of global `spyOnProperty`, prefer `jest.spyOn`.', +}; + +// prettier-ignore +const disabledJasmineMethods = { + addMatchers: 'Illegal usage of `jasmine.addMatchers`, prefer `expect.extends`.', + any: 'Illegal usage of `jasmine.any`, prefer `expect.any`.', + anything: 'Illegal usage of `jasmine.anything`, prefer `expect.anything`.', + arrayContaining: 'Illegal usage of `jasmine.arrayContaining`, prefer `expect.arrayContaining`.', + createSpy: 'Illegal usage of `jasmine.createSpy`, prefer `jest.fn`.', + objectContaining: 'Illegal usage of `jasmine.objectContaining`, prefer `expect.objectContaining`.', + stringMatching: 'Illegal usage of `jasmine.stringMatching`, prefer `expect.stringMatching`.', +}; + +export function installErrorOnPrivate(global: Global): void { + const {jasmine} = global; + Object.keys(disabledGlobals).forEach(functionName => { + global[functionName] = () => { + throwAtFunction(disabledGlobals[functionName], global[functionName]); + }; + }); + + Object.keys(disabledJasmineMethods).forEach(methodName => { + jasmine[methodName] = () => { + throwAtFunction(disabledJasmineMethods[methodName], jasmine[methodName]); + }; + }); +} + +function throwAtFunction(message, fn) { + const e = new Error(message); + if (Error.captureStackTrace) { + Error.captureStackTrace(e, fn); + } + throw e; +} diff --git a/packages/jest-jasmine2/src/index.js b/packages/jest-jasmine2/src/index.js index 7876a93e084f..5f13c1f92154 100644 --- a/packages/jest-jasmine2/src/index.js +++ b/packages/jest-jasmine2/src/index.js @@ -16,6 +16,7 @@ import type Runtime from 'jest-runtime'; import path from 'path'; import installEach from './each'; +import {installErrorOnPrivate} from './error_on_private'; import {getCallsite} from 'jest-util'; import JasmineReporter from './reporter'; import {install as jasmineAsyncInstall} from './jasmine_async'; @@ -100,6 +101,10 @@ async function jasmine2( expand: globalConfig.expand, }); + if (globalConfig.errorOnDeprecated) { + installErrorOnPrivate(environment.global); + } + const snapshotState: SnapshotState = runtime .requireInternalModule(path.resolve(__dirname, './setup_jest_globals.js')) .default({ diff --git a/types/Config.js b/types/Config.js index dfafaef93e16..89aa7afbce57 100644 --- a/types/Config.js +++ b/types/Config.js @@ -31,6 +31,7 @@ export type DefaultOptions = {| clearMocks: boolean, coveragePathIgnorePatterns: Array, coverageReporters: Array, + errorOnDeprecated: boolean, expand: boolean, filter: ?Path, forceCoverageMatch: Array, @@ -139,6 +140,7 @@ export type InitialOptions = { skipFilter?: boolean, skipNodeResolution?: boolean, snapshotSerializers?: Array, + errorOnDeprecated?: boolean, testEnvironment?: string, testEnvironmentOptions?: Object, testFailureExitCode?: string | number, @@ -207,6 +209,7 @@ export type GlobalConfig = {| rootDir: Path, silent: boolean, skipFilter: boolean, + errorOnDeprecated: boolean, testFailureExitCode: number, testNamePattern: string, testPathPattern: string, @@ -231,6 +234,7 @@ export type ProjectConfig = {| detectLeaks: boolean, detectOpenHandles: boolean, displayName: ?string, + errorOnDeprecated: boolean, filter: ?Path, forceCoverageMatch: Array, globals: ConfigGlobals,