| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,6 +9,7 @@ | |||
| 9 | 9 | import type { MockInstance } from '@vitest/spy' | |
| 10 | 10 | import type { Constructable } from '@vitest/utils' | |
| 11 | 11 | import type { Formatter } from 'tinyrainbow' | |
| 12 | + import type { AsymmetricMatcher } from './jest-asymmetric-matchers' | ||
| 12 | 13 | import type { diff, getMatcherUtils, stringify } from './jest-matcher-utils' | |
| 13 | 14 | ||
| 14 | 15 | export type ChaiPlugin = Chai.ChaiPlugin | |
@@ -99,8 +100,8 @@ export interface ExpectStatic | |||
| 99 | 100 | AsymmetricMatchersContaining { | |
| 100 | 101 | <T>(actual: T, message?: string): Assertion<T> | |
| 101 | 102 | extend: (expects: MatchersObject) => void | |
| 102 | - anything: () => any | ||
| 103 | - any: (constructor: unknown) => any | ||
| 103 | + anything: () => AsymmetricMatcher<unknown> | ||
| 104 | + any: (constructor: unknown) => AsymmetricMatcher<unknown> | ||
| 104 | 105 | getState: () => MatcherState | |
| 105 | 106 | setState: (state: Partial<MatcherState>) => void | |
| 106 | 107 | not: AsymmetricMatchersContaining | |
@@ -146,15 +147,15 @@ export interface AsymmetricMatchersContaining extends CustomMatcher { | |||
| 146 | 147 | * @example | |
| 147 | 148 | * expect({ a: '1', b: 2 }).toEqual(expect.objectContaining({ a: '1' })) | |
| 148 | 149 | */ | |
| 149 | - objectContaining: <T = any>(expected: T) => any | ||
| 150 | + objectContaining: <T = any>(expected: DeeplyAllowMatchers<T>) => any | ||
| 150 | 151 | ||
| 151 | 152 | /** | |
| 152 | 153 | * Matches if the received array contains all elements in the expected array. | |
| 153 | 154 | * | |
| 154 | 155 | * @example | |
| 155 | 156 | * expect(['a', 'b', 'c']).toEqual(expect.arrayContaining(['b', 'a'])); | |
| 156 | 157 | */ | |
| 157 | - arrayContaining: <T = unknown>(expected: Array<T>) => any | ||
| 158 | + arrayContaining: <T = unknown>(expected: Array<DeeplyAllowMatchers<T>>) => any | ||
| 158 | 159 | ||
| 159 | 160 | /** | |
| 160 | 161 | * Matches if the received string or regex matches the expected pattern. | |
@@ -177,6 +178,14 @@ export interface AsymmetricMatchersContaining extends CustomMatcher { | |||
| 177 | 178 | closeTo: (expected: number, precision?: number) => any | |
| 178 | 179 | } | |
| 179 | 180 | ||
| 181 | + export type DeeplyAllowMatchers<T> = T extends Array<infer Element> | ||
| 182 | + ? (DeeplyAllowMatchers<Element> | Element)[] | ||
| 183 | + : T extends object | ||
| 184 | + ? { | ||
| 185 | + [K in keyof T]: DeeplyAllowMatchers<T[K]> | AsymmetricMatcher<unknown> | ||
| 186 | + } | ||
| 187 | + : T | ||
| 188 | + | ||
| 180 | 189 | export interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher { | |
| 181 | 190 | /** | |
| 182 | 191 | * Used when you want to check that two objects have the same value. | |
@@ -185,15 +194,15 @@ export interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMa | |||
| 185 | 194 | * @example | |
| 186 | 195 | * expect(user).toEqual({ name: 'Alice', age: 30 }); | |
| 187 | 196 | */ | |
| 188 | - toEqual: <E>(expected: E) => void | ||
| 197 | + toEqual: <E>(expected: DeeplyAllowMatchers<E>) => void | ||
| 189 | 198 | ||
| 190 | 199 | /** | |
| 191 | 200 | * Use to test that objects have the same types as well as structure. | |
| 192 | 201 | * | |
| 193 | 202 | * @example | |
| 194 | 203 | * expect(user).toStrictEqual({ name: 'Alice', age: 30 }); | |
| 195 | 204 | */ | |
| 196 | - toStrictEqual: <E>(expected: E) => void | ||
| 205 | + toStrictEqual: <E>(expected: DeeplyAllowMatchers<E>) => void | ||
| 197 | 206 | ||
| 198 | 207 | /** | |
| 199 | 208 | * Checks that a value is what you expect. It calls `Object.is` to compare values. | |
@@ -223,7 +232,7 @@ export interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMa | |||
| 223 | 232 | * address: { city: 'Wonderland' } | |
| 224 | 233 | * }); | |
| 225 | 234 | */ | |
| 226 | - toMatchObject: <E extends object | any[]>(expected: E) => void | ||
| 235 | + toMatchObject: <E extends object | any[]>(expected: DeeplyAllowMatchers<E>) => void | ||
| 227 | 236 | ||
| 228 | 237 | /** | |
| 229 | 238 | * Used when you want to check that an item is in a list. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,114 @@ | |||
| 1 | + /* eslint-disable no-lone-blocks */ | ||
| 2 | + | ||
| 3 | + import { expect, test } from 'vitest' | ||
| 4 | + | ||
| 5 | + test('expect.* allows asymmetrict mattchers with different types', () => { | ||
| 6 | + // types.ts examples: stringContaining | ||
| 7 | + expect('I have an apple').toEqual(expect.stringContaining('apple')) | ||
| 8 | + expect('I have an apple').toEqual<string>(expect.stringContaining('apple')) | ||
| 9 | + | ||
| 10 | + expect({ a: 'test string' }).toEqual({ a: expect.stringContaining('test') }) | ||
| 11 | + expect({ a: 'test string' }).toEqual<{ a: string }>({ a: expect.stringContaining('test') }) | ||
| 12 | + | ||
| 13 | + // types.ts examples: objectContaining | ||
| 14 | + expect({ a: '1', b: 2 }).toEqual(expect.objectContaining({ a: '1' })) | ||
| 15 | + expect({ a: '1', b: 2 }).toEqual<{ a: string; b: string }>(expect.objectContaining({ a: '1' })) | ||
| 16 | + | ||
| 17 | + // types.ts examples: arrayContaining | ||
| 18 | + expect(['a', 'b', 'c']).toEqual(expect.arrayContaining(['b', 'a'])) | ||
| 19 | + expect(['a', 'b', 'c']).toEqual<string[]>(expect.arrayContaining(['b', 'a'])) | ||
| 20 | + | ||
| 21 | + // types.ts examples: stringMatching | ||
| 22 | + expect('hello world').toEqual(expect.stringMatching(/^hello/)) | ||
| 23 | + expect('hello world').toEqual<string>(expect.stringMatching(/^hello/)) | ||
| 24 | + | ||
| 25 | + expect('hello world').toEqual(expect.stringMatching('hello')) | ||
| 26 | + expect('hello world').toEqual<string>(expect.stringMatching('hello')) | ||
| 27 | + | ||
| 28 | + // types.ts examples: closeTo | ||
| 29 | + expect(10.45).toEqual(expect.closeTo(10.5, 1)) | ||
| 30 | + expect(10.45).toEqual<number>(expect.closeTo(10.5, 1)) | ||
| 31 | + | ||
| 32 | + expect(5.11).toEqual(expect.closeTo(5.12)) | ||
| 33 | + expect(5.11).toEqual<number>(expect.closeTo(5.12)) | ||
| 34 | + | ||
| 35 | + // expect.any(String) | ||
| 36 | + // https://github.com/vitest-dev/vitest/pull/7016#issuecomment-2517674066 | ||
| 37 | + { | ||
| 38 | + const obj = { | ||
| 39 | + id: '', | ||
| 40 | + name: '', | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + expect(obj).toEqual({ | ||
| 44 | + id: expect.any(String), | ||
| 45 | + name: 'Amelia', | ||
| 46 | + }) | ||
| 47 | + | ||
| 48 | + expect(obj).toEqual<{ | ||
| 49 | + id: string | ||
| 50 | + name: string | ||
| 51 | + }>({ | ||
| 52 | + id: expect.any(String), | ||
| 53 | + name: 'Amelia', | ||
| 54 | + }) | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + // expect.any(Date) | ||
| 58 | + // https://github.com/vitest-dev/vitest/issues/4543#issuecomment-1817960296 | ||
| 59 | + // https://github.com/vitest-dev/vitest/issues/4543#issuecomment-1817967628 | ||
| 60 | + // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/62831#issue-1418959169 | ||
| 61 | + { | ||
| 62 | + const actual = {} as { | ||
| 63 | + foo: string | ||
| 64 | + bar: string | ||
| 65 | + createdAt: Date | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + expect(actual).toEqual({ | ||
| 69 | + foo: 'foo', | ||
| 70 | + bar: 'bar', | ||
| 71 | + createdAt: expect.any(Date), | ||
| 72 | + }) | ||
| 73 | + | ||
| 74 | + expect(actual).toEqual<{ | ||
| 75 | + foo: string | ||
| 76 | + bar: string | ||
| 77 | + createdAt: Date | ||
| 78 | + }>({ | ||
| 79 | + foo: 'foo', | ||
| 80 | + bar: 'bar', | ||
| 81 | + createdAt: expect.any(Date), | ||
| 82 | + }) | ||
| 83 | + | ||
| 84 | + expect(actual).toEqual<{ | ||
| 85 | + foo: string | ||
| 86 | + bar: string | ||
| 87 | + createdAt: Date | ||
| 88 | + }[]>([ | ||
| 89 | + { | ||
| 90 | + foo: 'foo', | ||
| 91 | + bar: 'bar', | ||
| 92 | + createdAt: expect.any(Date), | ||
| 93 | + }, | ||
| 94 | + ]) | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + // expect.arrayContaining | ||
| 98 | + // https://github.com/jestjs/jest/issues/13812#issue-1555843276 | ||
| 99 | + { | ||
| 100 | + expect([1, 2, 3]).toEqual(expect.arrayContaining(['a'])) | ||
| 101 | + expect([1, 2, 3]).toEqual<number[]>(expect.arrayContaining(['a'])) | ||
| 102 | + | ||
| 103 | + expect([1, 2, 3]).toEqual(expect.arrayContaining([expect.any(Number)])) | ||
| 104 | + expect([1, 2, 3]).toEqual<number[]>(expect.arrayContaining([expect.any(Number)])) | ||
| 105 | + | ||
| 106 | + expect([1, 2, 3]).toEqual(expect.arrayContaining([expect.anything()])) | ||
| 107 | + expect([1, 2, 3]).toEqual<number[]>(expect.arrayContaining([expect.anything()])) | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + // expect.any(Array) | ||
| 111 | + // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/62831/files#diff-ff7b882e4a29e7fe0e348a6bdf8b11774d606eaa221009b166b01389576d921fR1237 | ||
| 112 | + expect({ list: [1, 2, 3] }).toMatchObject({ list: expect.any(Array) }) | ||
| 113 | + expect({ list: [1, 2, 3] }).toMatchObject<{ list: number[] }>({ list: expect.any(Array) }) | ||
| 114 | + }) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,4 @@ | |||
| 1 | + { | ||
| 2 | + "extends": "../../tsconfig.build.json", | ||
| 3 | + "include": ["./**/*.test-d.ts"] | ||
| 4 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -71,6 +71,10 @@ export default defineConfig({ | |||
| 71 | 71 | provider: 'istanbul', | |
| 72 | 72 | reporter: ['text', 'html'], | |
| 73 | 73 | }, | |
| 74 | + typecheck: { | ||
| 75 | + enabled: true, | ||
| 76 | + tsconfig: './tsconfig.typecheck.json', | ||
| 77 | + }, | ||
| 74 | 78 | environmentMatchGlobs: [ | |
| 75 | 79 | ['**/*.dom.test.ts', 'happy-dom'], | |
| 76 | 80 | ['test/env-glob-dom/**', 'jsdom'], | |
| Back | FazBrowse Home | New Git URL |
0 commit comments