From dfda0790a7eca6b4b36b4c2a5857dd9655d6b3be Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Thu, 6 Oct 2022 12:15:17 +0300 Subject: [PATCH] chore: clean up typechecks of `expect` test files (#13393) --- packages/expect/src/__tests__/extend.test.ts | 20 +- .../expect/src/__tests__/spyMatchers.test.ts | 12 +- .../src/__tests__/toThrowMatchers.test.ts | 811 +++++++++--------- packages/expect/src/__tests__/tsconfig.json | 6 +- 4 files changed, 419 insertions(+), 430 deletions(-) diff --git a/packages/expect/src/__tests__/extend.test.ts b/packages/expect/src/__tests__/extend.test.ts index 6af0c25f5331..91ddb9e22907 100644 --- a/packages/expect/src/__tests__/extend.test.ts +++ b/packages/expect/src/__tests__/extend.test.ts @@ -9,11 +9,11 @@ import {equals, iterableEquality, subsetEquality} from '@jest/expect-utils'; import {alignedAnsiStyleSerializer} from '@jest/test-utils'; import * as matcherUtils from 'jest-matcher-utils'; -import importedExpect from '../'; +import jestExpect from '../'; expect.addSnapshotSerializer(alignedAnsiStyleSerializer); -importedExpect.extend({ +jestExpect.extend({ toBeDivisibleBy(actual: number, expected: number) { const pass = actual % expected === 0; const message: () => string = pass @@ -52,6 +52,11 @@ importedExpect.extend({ }); declare module '../types' { + interface AsymmetricMatchers { + toBeDivisibleBy(expected: number): void; + toBeSymbol(expected: symbol): void; + toBeWithinRange(floor: number, ceiling: number): void; + } interface Matchers { toBeDivisibleBy(expected: number): R; toBeSymbol(expected: symbol): R; @@ -64,17 +69,6 @@ declare module '../types' { } } -const jestExpect = importedExpect as typeof importedExpect & { - not: { - toBeDivisibleBy(expected: number): void; - toBeWithinRange(floor: number, ceiling: number): void; - }; - - toBeDivisibleBy(expected: number): void; - toBeSymbol(expected: symbol): void; - toBeWithinRange(floor: number, ceiling: number): void; -}; - it('is available globally when matcher is unary', () => { jestExpect(15).toBeDivisibleBy(5); jestExpect(15).toBeDivisibleBy(3); diff --git a/packages/expect/src/__tests__/spyMatchers.test.ts b/packages/expect/src/__tests__/spyMatchers.test.ts index d936bf4e3f44..e350b5ca7b59 100644 --- a/packages/expect/src/__tests__/spyMatchers.test.ts +++ b/packages/expect/src/__tests__/spyMatchers.test.ts @@ -7,20 +7,22 @@ import * as Immutable from 'immutable'; import {alignedAnsiStyleSerializer} from '@jest/test-utils'; -import importedExpect from '../'; +import jestExpect from '../'; expect.addSnapshotSerializer(alignedAnsiStyleSerializer); -importedExpect.extend({ +jestExpect.extend({ optionalFn(fn?: unknown) { const pass = fn === undefined || typeof fn === 'function'; return {message: () => 'expect either a function or undefined', pass}; }, }); -const jestExpect = importedExpect as typeof importedExpect & { - optionalFn(fn?: unknown): void; -}; +declare module '../types' { + interface AsymmetricMatchers { + optionalFn(fn?: unknown): void; + } +} // Given a Jest mock function, return a minimal mock of a spy. const createSpy = (fn: jest.Mock) => { diff --git a/packages/expect/src/__tests__/toThrowMatchers.test.ts b/packages/expect/src/__tests__/toThrowMatchers.test.ts index ae4df6b638b4..ff0770008b93 100644 --- a/packages/expect/src/__tests__/toThrowMatchers.test.ts +++ b/packages/expect/src/__tests__/toThrowMatchers.test.ts @@ -22,230 +22,275 @@ class CustomError extends Error { } } -// `as const` needs newer babel which explodes on node 6 -const matchers: ['toThrowError', 'toThrow'] = ['toThrowError', 'toThrow']; - -matchers.forEach(toThrow => { - describe(toThrow, () => { - class Err extends CustomError {} - class Err2 extends CustomError {} +describe.each(['toThrowError', 'toThrow'] as const)('%s', toThrow => { + class Err extends CustomError {} + class Err2 extends CustomError {} + + test('to throw or not to throw', () => { + jestExpect(() => { + throw new CustomError('apple'); + })[toThrow](); + jestExpect(() => {}).not[toThrow](); + }); - test('to throw or not to throw', () => { + describe('substring', () => { + it('passes', () => { jestExpect(() => { throw new CustomError('apple'); - })[toThrow](); - jestExpect(() => {}).not[toThrow](); + })[toThrow]('apple'); + jestExpect(() => { + throw new CustomError('banana'); + }).not[toThrow]('apple'); + jestExpect(() => {}).not[toThrow]('apple'); + }); + + test('did not throw at all', () => { + expect(() => + jestExpect(() => {})[toThrow]('apple'), + ).toThrowErrorMatchingSnapshot(); }); - describe('substring', () => { - it('passes', () => { + test('threw, but message did not match (error)', () => { + expect(() => { jestExpect(() => { throw new CustomError('apple'); - })[toThrow]('apple'); - jestExpect(() => { - throw new CustomError('banana'); - }).not[toThrow]('apple'); - jestExpect(() => {}).not[toThrow]('apple'); - }); + })[toThrow]('banana'); + }).toThrowErrorMatchingSnapshot(); + }); - test('did not throw at all', () => { - expect(() => - jestExpect(() => {})[toThrow]('apple'), - ).toThrowErrorMatchingSnapshot(); - }); + test('threw, but message did not match (non-error falsey)', () => { + expect(() => { + jestExpect(() => { + // eslint-disable-next-line no-throw-literal + throw ''; + })[toThrow]('Server Error'); + }).toThrowErrorMatchingSnapshot(); + }); - test('threw, but message did not match (error)', () => { - expect(() => { - jestExpect(() => { - throw new CustomError('apple'); - })[toThrow]('banana'); - }).toThrowErrorMatchingSnapshot(); - }); + it('properly escapes strings when matching against errors', () => { + jestExpect(() => { + throw new TypeError('"this"? throws.'); + })[toThrow]('"this"? throws.'); + }); - test('threw, but message did not match (non-error falsey)', () => { - expect(() => { - jestExpect(() => { - // eslint-disable-next-line no-throw-literal - throw ''; - })[toThrow]('Server Error'); - }).toThrowErrorMatchingSnapshot(); - }); + test('threw, but message should not match (error)', () => { + expect(() => { + jestExpect(() => { + throw new CustomError('Invalid array length'); + }).not[toThrow]('array'); + }).toThrowErrorMatchingSnapshot(); + }); - it('properly escapes strings when matching against errors', () => { + test('threw, but message should not match (non-error truthy)', () => { + expect(() => { jestExpect(() => { - throw new TypeError('"this"? throws.'); - })[toThrow]('"this"? throws.'); - }); + // eslint-disable-next-line no-throw-literal + throw 'Internal Server Error'; + }).not[toThrow]('Server Error'); + }).toThrowErrorMatchingSnapshot(); + }); + }); - test('threw, but message should not match (error)', () => { - expect(() => { - jestExpect(() => { - throw new CustomError('Invalid array length'); - }).not[toThrow]('array'); - }).toThrowErrorMatchingSnapshot(); - }); + describe('regexp', () => { + it('passes', () => { + jestExpect(() => { + throw new CustomError('apple'); + })[toThrow](/apple/); + jestExpect(() => { + throw new CustomError('banana'); + }).not[toThrow](/apple/); + jestExpect(() => {}).not[toThrow](/apple/); + }); - test('threw, but message should not match (non-error truthy)', () => { - expect(() => { - jestExpect(() => { - // eslint-disable-next-line no-throw-literal - throw 'Internal Server Error'; - }).not[toThrow]('Server Error'); - }).toThrowErrorMatchingSnapshot(); - }); + test('did not throw at all', () => { + expect(() => + jestExpect(() => {})[toThrow](/apple/), + ).toThrowErrorMatchingSnapshot(); }); - describe('regexp', () => { - it('passes', () => { + test('threw, but message did not match (error)', () => { + expect(() => { jestExpect(() => { throw new CustomError('apple'); - })[toThrow](/apple/); + })[toThrow](/banana/); + }).toThrowErrorMatchingSnapshot(); + }); + + test('threw, but message did not match (non-error falsey)', () => { + expect(() => { jestExpect(() => { - throw new CustomError('banana'); - }).not[toThrow](/apple/); - jestExpect(() => {}).not[toThrow](/apple/); - }); + // eslint-disable-next-line no-throw-literal + throw 0; + })[toThrow](/^[123456789]\d*/); + }).toThrowErrorMatchingSnapshot(); + }); - test('did not throw at all', () => { - expect(() => - jestExpect(() => {})[toThrow](/apple/), - ).toThrowErrorMatchingSnapshot(); - }); + test('threw, but message should not match (error)', () => { + expect(() => { + jestExpect(() => { + throw new CustomError('Invalid array length'); + }).not[toThrow](/ array /); + }).toThrowErrorMatchingSnapshot(); + }); - test('threw, but message did not match (error)', () => { - expect(() => { - jestExpect(() => { - throw new CustomError('apple'); - })[toThrow](/banana/); - }).toThrowErrorMatchingSnapshot(); - }); + test('threw, but message should not match (non-error truthy)', () => { + expect(() => { + jestExpect(() => { + // eslint-disable-next-line no-throw-literal + throw 404; + }).not[toThrow](/^[123456789]\d*/); + }).toThrowErrorMatchingSnapshot(); + }); + }); - test('threw, but message did not match (non-error falsey)', () => { - expect(() => { - jestExpect(() => { - // eslint-disable-next-line no-throw-literal - throw 0; - })[toThrow](/^[123456789]\d*/); - }).toThrowErrorMatchingSnapshot(); - }); + describe('error class', () => { + class SubErr extends Err { + constructor(message?: string) { + super(message); + // In a carefully written error subclass, + // name property is equal to constructor name. + this.name = this.constructor.name; + } + } + + class SubSubErr extends SubErr { + constructor(message?: string) { + super(message); + // In a carefully written error subclass, + // name property is equal to constructor name. + this.name = this.constructor.name; + } + } - test('threw, but message should not match (error)', () => { - expect(() => { - jestExpect(() => { - throw new CustomError('Invalid array length'); - }).not[toThrow](/ array /); - }).toThrowErrorMatchingSnapshot(); - }); + it('passes', () => { + jestExpect(() => { + throw new Err(); + })[toThrow](Err); + jestExpect(() => { + throw new Err(); + })[toThrow](CustomError); + jestExpect(() => { + throw new Err(); + }).not[toThrow](Err2); + jestExpect(() => {}).not[toThrow](Err); + }); - test('threw, but message should not match (non-error truthy)', () => { - expect(() => { - jestExpect(() => { - // eslint-disable-next-line no-throw-literal - throw 404; - }).not[toThrow](/^[123456789]\d*/); - }).toThrowErrorMatchingSnapshot(); - }); + test('did not throw at all', () => { + expect(() => + expect(() => {})[toThrow](Err), + ).toThrowErrorMatchingSnapshot(); }); - describe('error class', () => { - class SubErr extends Err { - constructor(message?: string) { - super(message); - // In a carefully written error subclass, - // name property is equal to constructor name. - this.name = this.constructor.name; - } - } + test('threw, but class did not match (error)', () => { + expect(() => { + jestExpect(() => { + throw new Err('apple'); + })[toThrow](Err2); + }).toThrowErrorMatchingSnapshot(); + }); - class SubSubErr extends SubErr { - constructor(message?: string) { - super(message); - // In a carefully written error subclass, - // name property is equal to constructor name. - this.name = this.constructor.name; - } - } + test('threw, but class did not match (non-error falsey)', () => { + expect(() => { + jestExpect(() => { + // eslint-disable-next-line no-throw-literal + throw undefined; + })[toThrow](Err2); + }).toThrowErrorMatchingSnapshot(); + }); - it('passes', () => { + test('threw, but class should not match (error)', () => { + expect(() => { jestExpect(() => { - throw new Err(); - })[toThrow](Err); + throw new Err('apple'); + }).not[toThrow](Err); + }).toThrowErrorMatchingSnapshot(); + }); + + test('threw, but class should not match (error subclass)', () => { + expect(() => { jestExpect(() => { - throw new Err(); - })[toThrow](CustomError); + throw new SubErr('apple'); + }).not[toThrow](Err); + }).toThrowErrorMatchingSnapshot(); + }); + + test('threw, but class should not match (error subsubclass)', () => { + expect(() => { jestExpect(() => { - throw new Err(); - }).not[toThrow](Err2); - jestExpect(() => {}).not[toThrow](Err); - }); + throw new SubSubErr('apple'); + }).not[toThrow](Err); + }).toThrowErrorMatchingSnapshot(); + }); + }); - test('did not throw at all', () => { - expect(() => - expect(() => {})[toThrow](Err), - ).toThrowErrorMatchingSnapshot(); - }); + describe('error-message', () => { + // Received message in report if object has message property. + class ErrorMessage { + // not extending Error! + constructor(public message: string) {} + } + const expected = new ErrorMessage('apple'); - test('threw, but class did not match (error)', () => { - expect(() => { - jestExpect(() => { - throw new Err('apple'); - })[toThrow](Err2); - }).toThrowErrorMatchingSnapshot(); + describe('pass', () => { + test('isNot false', () => { + jestExpect(() => { + throw new ErrorMessage('apple'); + })[toThrow](expected); }); - test('threw, but class did not match (non-error falsey)', () => { - expect(() => { - jestExpect(() => { - // eslint-disable-next-line no-throw-literal - throw undefined; - })[toThrow](Err2); - }).toThrowErrorMatchingSnapshot(); + test('isNot true', () => { + jestExpect(() => { + throw new ErrorMessage('banana'); + }).not[toThrow](expected); }); + }); - test('threw, but class should not match (error)', () => { - expect(() => { + describe('fail', () => { + test('isNot false', () => { + expect(() => jestExpect(() => { - throw new Err('apple'); - }).not[toThrow](Err); - }).toThrowErrorMatchingSnapshot(); + throw new ErrorMessage('banana'); + })[toThrow](expected), + ).toThrowErrorMatchingSnapshot(); }); - test('threw, but class should not match (error subclass)', () => { - expect(() => { + test('isNot true', () => { + const message = 'Invalid array length'; + expect(() => jestExpect(() => { - throw new SubErr('apple'); - }).not[toThrow](Err); - }).toThrowErrorMatchingSnapshot(); + throw new ErrorMessage(message); + }).not[toThrow]({message}), + ).toThrowErrorMatchingSnapshot(); }); - test('threw, but class should not match (error subsubclass)', () => { - expect(() => { + test('multiline diff highlight incorrect expected space', () => { + // jest/issues/2673 + const a = + "There is no route defined for key Settings. \nMust be one of: 'Home'"; + const b = + "There is no route defined for key Settings.\nMust be one of: 'Home'"; + expect(() => jestExpect(() => { - throw new SubSubErr('apple'); - }).not[toThrow](Err); - }).toThrowErrorMatchingSnapshot(); + throw new ErrorMessage(b); + })[toThrow]({message: a}), + ).toThrowErrorMatchingSnapshot(); }); }); + }); - describe('error-message', () => { - // Received message in report if object has message property. - class ErrorMessage { - // not extending Error! - constructor(public message: string) {} - } - const expected = new ErrorMessage('apple'); - + describe('asymmetric', () => { + describe('any-Class', () => { describe('pass', () => { test('isNot false', () => { jestExpect(() => { - throw new ErrorMessage('apple'); - })[toThrow](expected); + throw new Err('apple'); + })[toThrow](expect.any(Err)); }); test('isNot true', () => { jestExpect(() => { - throw new ErrorMessage('banana'); - }).not[toThrow](expected); + throw new Err('apple'); + }).not[toThrow](expect.any(Err2)); }); }); @@ -253,296 +298,246 @@ matchers.forEach(toThrow => { test('isNot false', () => { expect(() => jestExpect(() => { - throw new ErrorMessage('banana'); - })[toThrow](expected), + throw new Err('apple'); + })[toThrow](expect.any(Err2)), ).toThrowErrorMatchingSnapshot(); }); test('isNot true', () => { - const message = 'Invalid array length'; - expect(() => - jestExpect(() => { - throw new ErrorMessage(message); - }).not[toThrow]({message}), - ).toThrowErrorMatchingSnapshot(); - }); - - test('multiline diff highlight incorrect expected space', () => { - // jest/issues/2673 - const a = - "There is no route defined for key Settings. \nMust be one of: 'Home'"; - const b = - "There is no route defined for key Settings.\nMust be one of: 'Home'"; expect(() => jestExpect(() => { - throw new ErrorMessage(b); - })[toThrow]({message: a}), + throw new Err('apple'); + }).not[toThrow](expect.any(Err)), ).toThrowErrorMatchingSnapshot(); }); }); }); - describe('asymmetric', () => { - describe('any-Class', () => { - describe('pass', () => { - test('isNot false', () => { - jestExpect(() => { - throw new Err('apple'); - })[toThrow](expect.any(Err)); - }); - - test('isNot true', () => { - jestExpect(() => { - throw new Err('apple'); - }).not[toThrow](expect.any(Err2)); - }); + describe('anything', () => { + describe('pass', () => { + test('isNot false', () => { + jestExpect(() => { + throw new CustomError('apple'); + })[toThrow](expect.anything()); }); - describe('fail', () => { - test('isNot false', () => { - expect(() => - jestExpect(() => { - throw new Err('apple'); - })[toThrow](expect.any(Err2)), - ).toThrowErrorMatchingSnapshot(); - }); - - test('isNot true', () => { - expect(() => - jestExpect(() => { - throw new Err('apple'); - }).not[toThrow](expect.any(Err)), - ).toThrowErrorMatchingSnapshot(); - }); + test('isNot true', () => { + jestExpect(() => {}).not[toThrow](expect.anything()); + jestExpect(() => { + // eslint-disable-next-line no-throw-literal + throw null; + }).not[toThrow](expect.anything()); }); }); - describe('anything', () => { - describe('pass', () => { - test('isNot false', () => { - jestExpect(() => { - throw new CustomError('apple'); - })[toThrow](expect.anything()); - }); - - test('isNot true', () => { - jestExpect(() => {}).not[toThrow](expect.anything()); + describe('fail', () => { + test('isNot false', () => { + expect(() => jestExpect(() => { // eslint-disable-next-line no-throw-literal throw null; - }).not[toThrow](expect.anything()); - }); + })[toThrow](expect.anything()), + ).toThrowErrorMatchingSnapshot(); + }); + + test('isNot true', () => { + expect(() => + jestExpect(() => { + throw new CustomError('apple'); + }).not[toThrow](expect.anything()), + ).toThrowErrorMatchingSnapshot(); + }); + }); + }); + + describe('no-symbol', () => { + // Test serialization of asymmetric matcher which has no property: + // this.$$typeof = Symbol.for('jest.asymmetricMatcher') + const matchError = { + asymmetricMatch(received: Error | null | undefined) { + return ( + received !== null && + received !== undefined && + received.name === 'Error' + ); + }, + }; + const matchNotError = { + asymmetricMatch(received: Error | null | undefined) { + return ( + received !== null && + received !== undefined && + received.name !== 'Error' + ); + }, + }; + + describe('pass', () => { + test('isNot false', () => { + jestExpect(() => { + throw new CustomError('apple'); + })[toThrow](matchError); }); - describe('fail', () => { - test('isNot false', () => { - expect(() => - jestExpect(() => { - // eslint-disable-next-line no-throw-literal - throw null; - })[toThrow](expect.anything()), - ).toThrowErrorMatchingSnapshot(); - }); - - test('isNot true', () => { - expect(() => - jestExpect(() => { - throw new CustomError('apple'); - }).not[toThrow](expect.anything()), - ).toThrowErrorMatchingSnapshot(); - }); + test('isNot true', () => { + jestExpect(() => { + throw new CustomError('apple'); + }).not[toThrow](matchNotError); }); }); - describe('no-symbol', () => { - // Test serialization of asymmetric matcher which has no property: - // this.$$typeof = Symbol.for('jest.asymmetricMatcher') - const matchError = { - asymmetricMatch(received: Error | null | undefined) { - return ( - received !== null && - received !== undefined && - received.name === 'Error' - ); - }, - }; - const matchNotError = { - asymmetricMatch(received: Error | null | undefined) { - return ( - received !== null && - received !== undefined && - received.name !== 'Error' - ); - }, - }; - - describe('pass', () => { - test('isNot false', () => { + describe('fail', () => { + test('isNot false', () => { + expect(() => jestExpect(() => { throw new CustomError('apple'); - })[toThrow](matchError); - }); + })[toThrow](matchNotError), + ).toThrowErrorMatchingSnapshot(); + }); - test('isNot true', () => { + test('isNot true', () => { + expect(() => jestExpect(() => { throw new CustomError('apple'); - }).not[toThrow](matchNotError); - }); + }).not[toThrow](matchError), + ).toThrowErrorMatchingSnapshot(); }); + }); + }); - describe('fail', () => { - test('isNot false', () => { - expect(() => - jestExpect(() => { - throw new CustomError('apple'); - })[toThrow](matchNotError), - ).toThrowErrorMatchingSnapshot(); - }); - - test('isNot true', () => { - expect(() => - jestExpect(() => { - throw new CustomError('apple'); - }).not[toThrow](matchError), - ).toThrowErrorMatchingSnapshot(); - }); - }); + describe('objectContaining', () => { + const matchError = expect.objectContaining({ + name: 'Error', + }); + const matchNotError = expect.objectContaining({ + name: 'NotError', }); - describe('objectContaining', () => { - const matchError = expect.objectContaining({ - name: 'Error', + describe('pass', () => { + test('isNot false', () => { + jestExpect(() => { + throw new CustomError('apple'); + })[toThrow](matchError); }); - const matchNotError = expect.objectContaining({ - name: 'NotError', + + test('isNot true', () => { + jestExpect(() => { + throw new CustomError('apple'); + }).not[toThrow](matchNotError); }); + }); - describe('pass', () => { - test('isNot false', () => { + describe('fail', () => { + test('isNot false', () => { + expect(() => jestExpect(() => { throw new CustomError('apple'); - })[toThrow](matchError); - }); + })[toThrow](matchNotError), + ).toThrowErrorMatchingSnapshot(); + }); - test('isNot true', () => { + test('isNot true', () => { + expect(() => jestExpect(() => { throw new CustomError('apple'); - }).not[toThrow](matchNotError); - }); - }); - - describe('fail', () => { - test('isNot false', () => { - expect(() => - jestExpect(() => { - throw new CustomError('apple'); - })[toThrow](matchNotError), - ).toThrowErrorMatchingSnapshot(); - }); - - test('isNot true', () => { - expect(() => - jestExpect(() => { - throw new CustomError('apple'); - }).not[toThrow](matchError), - ).toThrowErrorMatchingSnapshot(); - }); + }).not[toThrow](matchError), + ).toThrowErrorMatchingSnapshot(); }); }); }); + }); - describe('promise/async throws if Error-like object is returned', () => { - const asyncFn = async (shouldThrow?: boolean, resolve?: boolean) => { - let err; - if (shouldThrow) { - err = new Err('async apple'); - } - if (resolve) { - return Promise.resolve(err || 'apple'); - } else { - return Promise.reject(err || 'apple'); - } - }; - - test('passes', async () => { - expect.assertions(24); - await jestExpect(Promise.reject(new Error())).rejects[toThrow](); - - await jestExpect(asyncFn(true)).rejects[toThrow](); - await jestExpect(asyncFn(true)).rejects[toThrow](Err); - await jestExpect(asyncFn(true)).rejects[toThrow](Error); - await jestExpect(asyncFn(true)).rejects[toThrow]('apple'); - await jestExpect(asyncFn(true)).rejects[toThrow](/app/); - - await jestExpect(asyncFn(true)).rejects.not[toThrow](Err2); - await jestExpect(asyncFn(true)).rejects.not[toThrow]('banana'); - await jestExpect(asyncFn(true)).rejects.not[toThrow](/banana/); - - await jestExpect(asyncFn(true, true)).resolves[toThrow](); - - await jestExpect(asyncFn(false, true)).resolves.not[toThrow](); - await jestExpect(asyncFn(false, true)).resolves.not[toThrow](Error); - await jestExpect(asyncFn(false, true)).resolves.not[toThrow]('apple'); - await jestExpect(asyncFn(false, true)).resolves.not[toThrow](/apple/); - await jestExpect(asyncFn(false, true)).resolves.not[toThrow]('banana'); - await jestExpect(asyncFn(false, true)).resolves.not[toThrow](/banana/); - - await jestExpect(asyncFn()).rejects.not[toThrow](); - await jestExpect(asyncFn()).rejects.not[toThrow](Error); - await jestExpect(asyncFn()).rejects.not[toThrow]('apple'); - await jestExpect(asyncFn()).rejects.not[toThrow](/apple/); - await jestExpect(asyncFn()).rejects.not[toThrow]('banana'); - await jestExpect(asyncFn()).rejects.not[toThrow](/banana/); - - // Works with nested functions inside promises - await jestExpect( - Promise.reject(() => { - throw new Error(); - }), - ).rejects[toThrow](); - await jestExpect(Promise.reject(() => {})).rejects.not[toThrow](); - }); - - test('did not throw at all', async () => { - await expect( - jestExpect(asyncFn()).rejects[toThrow](), - ).rejects.toThrowErrorMatchingSnapshot(); - }); - - test('threw, but class did not match', async () => { - await expect( - jestExpect(asyncFn(true)).rejects[toThrow](Err2), - ).rejects.toThrowErrorMatchingSnapshot(); - }); + describe('promise/async throws if Error-like object is returned', () => { + const asyncFn = async (shouldThrow?: boolean, resolve?: boolean) => { + let err; + if (shouldThrow) { + err = new Err('async apple'); + } + if (resolve) { + return Promise.resolve(err || 'apple'); + } else { + return Promise.reject(err || 'apple'); + } + }; + + test('passes', async () => { + expect.assertions(24); + await jestExpect(Promise.reject(new Error())).rejects[toThrow](); + + await jestExpect(asyncFn(true)).rejects[toThrow](); + await jestExpect(asyncFn(true)).rejects[toThrow](Err); + await jestExpect(asyncFn(true)).rejects[toThrow](Error); + await jestExpect(asyncFn(true)).rejects[toThrow]('apple'); + await jestExpect(asyncFn(true)).rejects[toThrow](/app/); + + await jestExpect(asyncFn(true)).rejects.not[toThrow](Err2); + await jestExpect(asyncFn(true)).rejects.not[toThrow]('banana'); + await jestExpect(asyncFn(true)).rejects.not[toThrow](/banana/); + + await jestExpect(asyncFn(true, true)).resolves[toThrow](); + + await jestExpect(asyncFn(false, true)).resolves.not[toThrow](); + await jestExpect(asyncFn(false, true)).resolves.not[toThrow](Error); + await jestExpect(asyncFn(false, true)).resolves.not[toThrow]('apple'); + await jestExpect(asyncFn(false, true)).resolves.not[toThrow](/apple/); + await jestExpect(asyncFn(false, true)).resolves.not[toThrow]('banana'); + await jestExpect(asyncFn(false, true)).resolves.not[toThrow](/banana/); + + await jestExpect(asyncFn()).rejects.not[toThrow](); + await jestExpect(asyncFn()).rejects.not[toThrow](Error); + await jestExpect(asyncFn()).rejects.not[toThrow]('apple'); + await jestExpect(asyncFn()).rejects.not[toThrow](/apple/); + await jestExpect(asyncFn()).rejects.not[toThrow]('banana'); + await jestExpect(asyncFn()).rejects.not[toThrow](/banana/); + + // Works with nested functions inside promises + await jestExpect( + Promise.reject(() => { + throw new Error(); + }), + ).rejects[toThrow](); + await jestExpect(Promise.reject(() => {})).rejects.not[toThrow](); + }); - test('threw, but should not have', async () => { - await expect( - jestExpect(asyncFn(true)).rejects.not[toThrow](), - ).rejects.toThrowErrorMatchingSnapshot(); - }); + test('did not throw at all', async () => { + await expect( + jestExpect(asyncFn()).rejects[toThrow](), + ).rejects.toThrowErrorMatchingSnapshot(); }); - describe('expected is undefined', () => { - test('threw, but should not have (non-error falsey)', () => { - expect(() => { - jestExpect(() => { - // eslint-disable-next-line no-throw-literal - throw null; - }).not[toThrow](); - }).toThrowErrorMatchingSnapshot(); - }); + test('threw, but class did not match', async () => { + await expect( + jestExpect(asyncFn(true)).rejects[toThrow](Err2), + ).rejects.toThrowErrorMatchingSnapshot(); }); - test('invalid arguments', () => { - expect(() => - jestExpect(() => {}).not[toThrow](111), - ).toThrowErrorMatchingSnapshot(); + test('threw, but should not have', async () => { + await expect( + jestExpect(asyncFn(true)).rejects.not[toThrow](), + ).rejects.toThrowErrorMatchingSnapshot(); }); + }); - test('invalid actual', () => { - expect(() => - jestExpect('a string')[toThrow](), - ).toThrowErrorMatchingSnapshot(); + describe('expected is undefined', () => { + test('threw, but should not have (non-error falsey)', () => { + expect(() => { + jestExpect(() => { + // eslint-disable-next-line no-throw-literal + throw null; + }).not[toThrow](); + }).toThrowErrorMatchingSnapshot(); }); }); + + test('invalid arguments', () => { + expect(() => + jestExpect(() => {}).not[toThrow](111), + ).toThrowErrorMatchingSnapshot(); + }); + + test('invalid actual', () => { + expect(() => + jestExpect('a string')[toThrow](), + ).toThrowErrorMatchingSnapshot(); + }); }); diff --git a/packages/expect/src/__tests__/tsconfig.json b/packages/expect/src/__tests__/tsconfig.json index 8ccc3083ffb0..dd1bca103251 100644 --- a/packages/expect/src/__tests__/tsconfig.json +++ b/packages/expect/src/__tests__/tsconfig.json @@ -1,7 +1,5 @@ { "extends": "../../../../tsconfig.test.json", - "compilerOptions": { - "rootDir": "../" - }, - "include": ["../**/*"] + "include": ["./**/*"], + "references": [{"path": "../../"}] }