diff --git a/.eslintrc.js b/.eslintrc.js index 227fccc759ce..6e1a4573c321 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -42,8 +42,6 @@ module.exports = { '@typescript-eslint/prefer-ts-expect-error': 'error', // TS verifies this 'consistent-return': 'off', - // Since we do `export =`. Remove for Jest 27 - 'import/default': 'off', 'no-dupe-class-members': 'off', 'no-unused-vars': 'off', }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 21094d7cee63..7e68a5b8bd72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- `[expect]` [**BREAKING**] Migrate to ESM ([#12344](https://github.com/facebook/jest/pull/12344)) - `[jest-environment-jsdom]` [**BREAKING**] Add default `browser` condition to `exportConditions` for `jsdom` environment ([#11924](https://github.com/facebook/jest/pull/11924)) - `[jest-environment-jsdom]` [**BREAKING**] Migrate to ESM ([#12340](https://github.com/facebook/jest/pull/12340)) - `[jest-environment-node]` [**BREAKING**] Add default `node` and `node-addon` conditions to `exportConditions` for `node` environment ([#11924](https://github.com/facebook/jest/pull/11924)) diff --git a/babel.config.js b/babel.config.js index b7ee1b4e02e6..989e2d2e9403 100644 --- a/babel.config.js +++ b/babel.config.js @@ -17,7 +17,6 @@ module.exports = { overrides: [ { plugins: [ - 'babel-plugin-replace-ts-export-assignment', require.resolve( './scripts/babel-plugin-jest-replace-ts-require-assignment.js', ), diff --git a/package.json b/package.json index 3c250f2bf109..e38781a2e746 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "@typescript-eslint/parser": "^4.1.0", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", - "babel-plugin-replace-ts-export-assignment": "^0.0.2", "camelcase": "^6.2.0", "chalk": "^4.0.0", "chokidar": "^3.3.0", diff --git a/packages/expect/src/__tests__/matchers.test.js b/packages/expect/src/__tests__/matchers.test.js index f6526cfa7374..a6cfe072cc74 100644 --- a/packages/expect/src/__tests__/matchers.test.js +++ b/packages/expect/src/__tests__/matchers.test.js @@ -9,7 +9,7 @@ const chalk = require('chalk'); const Immutable = require('immutable'); const {alignedAnsiStyleSerializer} = require('@jest/test-utils'); const {stringify} = require('jest-matcher-utils'); -const jestExpect = require('../'); +const {expect: jestExpect} = require('../'); const chalkEnabled = chalk.enabled; expect.addSnapshotSerializer(alignedAnsiStyleSerializer); diff --git a/packages/expect/src/index.ts b/packages/expect/src/index.ts index 8660b1f13df6..7edb89b4d54d 100644 --- a/packages/expect/src/index.ts +++ b/packages/expect/src/index.ts @@ -41,8 +41,7 @@ import type { AsyncExpectationResult, Expect, ExpectationResult, - MatcherState as JestMatcherState, - Matchers as MatcherInterface, + MatcherState, MatchersObject, PromiseMatcherFn, RawMatcherFn, @@ -50,7 +49,9 @@ import type { ThrowingMatcherFn, } from './types'; -class JestAssertionError extends Error { +export type {Expect, MatcherState, Matchers} from './types'; + +export class JestAssertionError extends Error { matcherResult?: Omit & {message: string}; } @@ -63,7 +64,7 @@ const createToThrowErrorMatchingSnapshotMatcher = function ( matcher: RawMatcherFn, ) { return function ( - this: JestMatcherState, + this: MatcherState, received: any, testNameOrInlineSnapshot?: string, ) { @@ -84,7 +85,7 @@ const getPromiseMatcher = (name: string, matcher: any) => { return null; }; -const expect: any = (actual: any, ...rest: Array) => { +export const expect: Expect = (actual: any, ...rest: Array) => { if (rest.length !== 0) { throw new Error('Expect takes at most one argument.'); } @@ -252,7 +253,7 @@ const makeThrowingMatcher = ( let throws = true; const utils = {...matcherUtils, iterableEquality, subsetEquality}; - const matcherContext: JestMatcherState = { + const matcherContext: MatcherState = { // When throws is disabled, the matcher will not throw errors during test // execution but instead add them to the global matcher state. If a // matcher throws, test execution is normally stopped immediately. The @@ -355,7 +356,7 @@ const makeThrowingMatcher = ( } }; -expect.extend = ( +expect.extend = ( matchers: MatchersObject, ): void => setMatchers(matchers, false, expect); @@ -394,7 +395,7 @@ const _validateResult = (result: any) => { } }; -function assertions(expected: number) { +function assertions(expected: number): void { const error = new Error(); if (Error.captureStackTrace) { Error.captureStackTrace(error, assertions); @@ -405,7 +406,7 @@ function assertions(expected: number) { expectedAssertionsNumberError: error, }); } -function hasAssertions(...args: Array) { +function hasAssertions(...args: Array): void { const error = new Error(); if (Error.captureStackTrace) { Error.captureStackTrace(error, hasAssertions); @@ -419,9 +420,9 @@ function hasAssertions(...args: Array) { } // add default jest matchers -setMatchers(matchers, true, expect as Expect); -setMatchers(spyMatchers, true, expect as Expect); -setMatchers(toThrowMatchers, true, expect as Expect); +setMatchers(matchers, true, expect); +setMatchers(spyMatchers, true, expect); +setMatchers(toThrowMatchers, true, expect); expect.addSnapshotSerializer = () => void 0; expect.assertions = assertions; @@ -430,11 +431,4 @@ expect.getState = getState; expect.setState = setState; expect.extractExpectedAssertionsErrors = extractExpectedAssertionsErrors; -const expectExport = expect as Expect; - -declare namespace expectExport { - export type MatcherState = JestMatcherState; - export interface Matchers extends MatcherInterface {} -} - -export = expectExport; +export default expect; diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 6a41045dc70d..6e4e01f7da2c 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -15,7 +15,7 @@ import { createEmptyTestResult, } from '@jest/test-result'; import type {Circus, Config, Global} from '@jest/types'; -import {extractExpectedAssertionsErrors, getState, setState} from 'expect'; +import {Expect, expect} from 'expect'; import {bind} from 'jest-each'; import {formatExecError, formatResultsErrors} from 'jest-message-util'; import { @@ -33,7 +33,7 @@ import { } from '../state'; import testCaseReportHandler from '../testCaseReportHandler'; import {getTestID} from '../utils'; -import createExpect, {Expect} from './jestExpect'; +import createExpect from './jestExpect'; type Process = NodeJS.Process; @@ -162,7 +162,7 @@ export const initialize = async ({ updateSnapshot, }); // @ts-expect-error: snapshotState is a jest extension of `expect` - setState({snapshotState, testPath}); + expect.setState({snapshotState, testPath}); addEventHandler(handleSnapshotStateAfterRetry(snapshotState)); if (sendMessageToJest) { @@ -279,7 +279,7 @@ const handleSnapshotStateAfterRetry = const eventHandler = async (event: Circus.Event) => { switch (event.name) { case 'test_start': { - setState({currentTestName: getTestID(event.test)}); + expect.setState({currentTestName: getTestID(event.test)}); break; } case 'test_done': { @@ -291,7 +291,7 @@ const eventHandler = async (event: Circus.Event) => { }; const _addExpectedAssertionErrors = (test: Circus.TestEntry) => { - const failures = extractExpectedAssertionsErrors(); + const failures = expect.extractExpectedAssertionsErrors(); const errors = failures.map(failure => failure.error); test.errors = test.errors.concat(errors); }; @@ -300,8 +300,8 @@ const _addExpectedAssertionErrors = (test: Circus.TestEntry) => { // test execution and add them to the test result, potentially failing // a passing test. const _addSuppressedErrors = (test: Circus.TestEntry) => { - const {suppressedErrors} = getState(); - setState({suppressedErrors: []}); + const {suppressedErrors} = expect.getState(); + expect.setState({suppressedErrors: []}); if (suppressedErrors.length) { test.errors = test.errors.concat(suppressedErrors); } diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts index aacd1208b954..6f6332f72490 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts @@ -6,7 +6,7 @@ */ import type {Config} from '@jest/types'; -import expect = require('expect'); +import {Expect, expect} from 'expect'; import { addSerializer, toMatchInlineSnapshot, @@ -15,8 +15,6 @@ import { toThrowErrorMatchingSnapshot, } from 'jest-snapshot'; -export type Expect = typeof expect; - export default function jestExpect( config: Pick, ): Expect { diff --git a/packages/jest-circus/src/types.ts b/packages/jest-circus/src/types.ts index cb518790624a..92d47eb16983 100644 --- a/packages/jest-circus/src/types.ts +++ b/packages/jest-circus/src/types.ts @@ -5,9 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -// Used as type import type {Circus} from '@jest/types'; -import type expect = require('expect'); +import type {Expect} from 'expect'; export const STATE_SYM = Symbol( 'JEST_STATE_SYMBOL', @@ -26,7 +25,7 @@ declare global { STATE_SYM_SYMBOL: Circus.State; RETRY_TIMES_SYMBOL: string; TEST_TIMEOUT_SYMBOL: number; - expect: typeof expect; + expect: Expect; } } } diff --git a/packages/jest-globals/src/index.ts b/packages/jest-globals/src/index.ts index 6bebf8628f84..5d84d89125d1 100644 --- a/packages/jest-globals/src/index.ts +++ b/packages/jest-globals/src/index.ts @@ -7,11 +7,11 @@ import type {Jest} from '@jest/environment'; import type {Global} from '@jest/types'; -import type importedExpect = require('expect'); +import type {Expect} from 'expect'; export declare const jest: Jest; -export declare const expect: typeof importedExpect; +export declare const expect: Expect; export declare const it: Global.GlobalAdditions['it']; export declare const test: Global.GlobalAdditions['test']; diff --git a/packages/jest-jasmine2/src/jestExpect.ts b/packages/jest-jasmine2/src/jestExpect.ts index 30e32567f5f7..1c1d2a2e85c1 100644 --- a/packages/jest-jasmine2/src/jestExpect.ts +++ b/packages/jest-jasmine2/src/jestExpect.ts @@ -8,7 +8,7 @@ /* eslint-disable local/prefer-spread-eventually */ import type {Global} from '@jest/types'; -import expect = require('expect'); +import {MatcherState, expect} from 'expect'; import { addSerializer, toMatchInlineSnapshot, @@ -42,7 +42,7 @@ export default function jestExpect(config: {expand: boolean}): void { const jestMatchersObject = Object.create(null); Object.keys(jasmineMatchersObject).forEach(name => { jestMatchersObject[name] = function ( - this: expect.MatcherState, + this: MatcherState, ...args: Array ): RawMatcherFn { // use "expect.extend" if you need to use equality testers (via this.equal) diff --git a/packages/jest-jasmine2/src/setup_jest_globals.ts b/packages/jest-jasmine2/src/setup_jest_globals.ts index 72a713708fcc..85473e4bf2d3 100644 --- a/packages/jest-jasmine2/src/setup_jest_globals.ts +++ b/packages/jest-jasmine2/src/setup_jest_globals.ts @@ -6,7 +6,7 @@ */ import type {Config, Global} from '@jest/types'; -import {extractExpectedAssertionsErrors, getState, setState} from 'expect'; +import {expect} from 'expect'; import { SnapshotState, addSerializer, @@ -33,8 +33,8 @@ export type SetupOptions = { // test execution and add them to the test result, potentially failing // a passing test. const addSuppressedErrors = (result: SpecResult) => { - const {suppressedErrors} = getState(); - setState({suppressedErrors: []}); + const {suppressedErrors} = expect.getState(); + expect.setState({suppressedErrors: []}); if (suppressedErrors.length) { result.status = 'failed'; @@ -52,7 +52,7 @@ const addSuppressedErrors = (result: SpecResult) => { }; const addAssertionErrors = (result: SpecResult) => { - const assertionErrors = extractExpectedAssertionsErrors(); + const assertionErrors = expect.extractExpectedAssertionsErrors(); if (assertionErrors.length) { const jasmineErrors = assertionErrors.map(({actual, error, expected}) => ({ actual, @@ -77,7 +77,7 @@ const patchJasmine = () => { }; const onStart = attr.onStart; attr.onStart = (context: JasmineSpec) => { - setState({currentTestName: context.getFullName()}); + expect.setState({currentTestName: context.getFullName()}); onStart && onStart.call(attr, context); }; super(attr); @@ -115,7 +115,7 @@ export default async function setupJestGlobals({ updateSnapshot, }); // @ts-expect-error: snapshotState is a jest extension of `expect` - setState({snapshotState, testPath}); + expect.setState({snapshotState, testPath}); // Return it back to the outer scope (test runner outside the VM). return snapshotState; } diff --git a/packages/jest-jasmine2/src/types.ts b/packages/jest-jasmine2/src/types.ts index 4efe3220864f..0266dcc0502c 100644 --- a/packages/jest-jasmine2/src/types.ts +++ b/packages/jest-jasmine2/src/types.ts @@ -7,7 +7,7 @@ import type {AssertionError} from 'assert'; import type {Config} from '@jest/types'; -import type expect = require('expect'); +import type {Expect} from 'expect'; import type CallTracker from './jasmine/CallTracker'; import type Env from './jasmine/Env'; import type JsApiReporter from './jasmine/JsApiReporter'; @@ -89,13 +89,13 @@ export type Jasmine = { version: string; testPath: Config.Path; addMatchers: (matchers: JasmineMatchersObject) => void; -} & typeof expect & +} & Expect & typeof globalThis; declare global { namespace NodeJS { interface Global { - expect: typeof expect; + expect: Expect; } } } diff --git a/yarn.lock b/yarn.lock index f2ee5a5189bd..ae8000d76583 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2621,7 +2621,6 @@ __metadata: "@typescript-eslint/parser": ^4.1.0 ansi-regex: ^5.0.1 ansi-styles: ^5.0.0 - babel-plugin-replace-ts-export-assignment: ^0.0.2 camelcase: ^6.2.0 chalk: ^4.0.0 chokidar: ^3.3.0 @@ -6502,13 +6501,6 @@ __metadata: languageName: node linkType: hard -"babel-plugin-replace-ts-export-assignment@npm:^0.0.2": - version: 0.0.2 - resolution: "babel-plugin-replace-ts-export-assignment@npm:0.0.2" - checksum: da749130fe0479cd9da73f8b3aafc62e05885b12732ce0e25976a7138dad1688a03366791b12633afdd8a702e2018ec01764c4ddb0ed0dbc3783b7e75b1b148a - languageName: node - linkType: hard - "babel-plugin-syntax-trailing-function-commas@npm:^7.0.0-beta.0": version: 7.0.0-beta.0 resolution: "babel-plugin-syntax-trailing-function-commas@npm:7.0.0-beta.0"