From 9d66f512f4e7c4339a3f21dbf8777d789f4c2ef7 Mon Sep 17 00:00:00 2001 From: Michael Manzinger Date: Wed, 16 Aug 2023 15:29:34 +0200 Subject: [PATCH 1/6] fix: matchers type is making the global expect unsafe --- types/matchers.d.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/types/matchers.d.ts b/types/matchers.d.ts index af43570d..0552aa16 100755 --- a/types/matchers.d.ts +++ b/types/matchers.d.ts @@ -1,5 +1,7 @@ +/// + declare namespace matchers { - interface TestingLibraryMatchers extends Record { + interface TestingLibraryMatchers { /** * @deprecated * since v1.9.0 @@ -660,7 +662,13 @@ declare namespace matchers { */ toHaveErrorMessage(text?: string | RegExp | E): R } + + // Needs to extend Record to be accepted by expect.extend() + // as it requires a string index signature. + interface TestingLibraryMatchersExport + extends Record, + TestingLibraryMatchers {} } -declare const matchers: matchers.TestingLibraryMatchers +declare const matchers: matchers.TestingLibraryMatchersExport export = matchers From 254582bb247a21e19901c978f46cb5572907674d Mon Sep 17 00:00:00 2001 From: Michael Manzinger Date: Wed, 16 Aug 2023 15:30:32 +0200 Subject: [PATCH 2/6] Add test file for TypeScript typings --- tsconfig.json | 2 +- types-test.ts | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 types-test.ts diff --git a/tsconfig.json b/tsconfig.json index 9a426aba..ef9b2d9b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,5 +3,5 @@ "strict": true, "skipLibCheck": true }, - "include": ["*.d.ts", "types"] + "include": ["*.d.ts", "types", "types-test.ts"] } diff --git a/types-test.ts b/types-test.ts new file mode 100644 index 00000000..536ebb2b --- /dev/null +++ b/types-test.ts @@ -0,0 +1,186 @@ +/** + * File that tests whether the TypeScript typings work as expected. + */ + +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-floating-promises */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ + +import matchers = require('./types/matchers'); + +expect.extend(matchers); + +const element: HTMLElement = document.body; + +expect(element).toBeInTheDOM(); +expect(element).toBeInTheDOM(document.body); +expect(element).toBeInTheDocument(); +expect(element).toBeVisible(); +expect(element).toBeEmpty(); +expect(element).toBeDisabled(); +expect(element).toBeEnabled(); +expect(element).toBeInvalid(); +expect(element).toBeRequired(); +expect(element).toBeValid(); +expect(element).toContainElement(document.body); +expect(element).toContainElement(null); +expect(element).toContainHTML('body'); +expect(element).toHaveAttribute('attr'); +expect(element).toHaveAttribute('attr', true); +expect(element).toHaveAttribute('attr', 'yes'); +expect(element).toHaveClass(); +expect(element).toHaveClass('cls1'); +expect(element).toHaveClass('cls1', 'cls2', 'cls3', 'cls4'); +expect(element).toHaveClass('cls1', { exact: true }); +expect(element).toHaveDisplayValue('str'); +expect(element).toHaveDisplayValue(['str1', 'str2']); +expect(element).toHaveDisplayValue(/str/); +expect(element).toHaveDisplayValue([/str1/, 'str2']); +expect(element).toHaveFocus(); +expect(element).toHaveFormValues({ foo: 'bar', baz: 1 }); +expect(element).toHaveStyle('display: block'); +expect(element).toHaveStyle({ display: 'block', width: 100 }); +expect(element).toHaveTextContent('Text'); +expect(element).toHaveTextContent(/Text/); +expect(element).toHaveTextContent('Text', { normalizeWhitespace: true }); +expect(element).toHaveTextContent(/Text/, { normalizeWhitespace: true }); +expect(element).toHaveValue(); +expect(element).toHaveValue('str'); +expect(element).toHaveValue(['str1', 'str2']); +expect(element).toHaveValue(1); +expect(element).toHaveValue(null); +expect(element).toBeChecked(); +expect(element).toHaveDescription('some description'); +expect(element).toHaveDescription(/some description/); +expect(element).toHaveDescription(expect.stringContaining('partial')); +expect(element).toHaveDescription(); +expect(element).toHaveAccessibleDescription('some description'); +expect(element).toHaveAccessibleDescription(/some description/); +expect(element).toHaveAccessibleDescription(expect.stringContaining('partial')); +expect(element).toHaveAccessibleDescription(); +expect(element).toHaveAccessibleName('a label'); +expect(element).toHaveAccessibleName(/a label/); +expect(element).toHaveAccessibleName(expect.stringContaining('partial label')); +expect(element).toHaveAccessibleName(); +expect(element).toHaveErrorMessage('Invalid time: the time must be between 9:00 AM and 5:00 PM'); +expect(element).toHaveErrorMessage(/invalid time/i); +expect(element).toHaveErrorMessage(expect.stringContaining('Invalid time')); + +expect(element).not.toBeInTheDOM(); +expect(element).not.toBeInTheDOM(document.body); +expect(element).not.toBeInTheDocument(); +expect(element).not.toBeVisible(); +expect(element).not.toBeEmpty(); +expect(element).not.toBeEmptyDOMElement(); +expect(element).not.toBeDisabled(); +expect(element).not.toBeEnabled(); +expect(element).not.toBeInvalid(); +expect(element).not.toBeRequired(); +expect(element).not.toBeValid(); +expect(element).not.toContainElement(document.body); +expect(element).not.toContainElement(null); +expect(element).not.toContainHTML('body'); +expect(element).not.toHaveAttribute('attr'); +expect(element).not.toHaveAttribute('attr', true); +expect(element).not.toHaveAttribute('attr', 'yes'); +expect(element).not.toHaveClass(); +expect(element).not.toHaveClass('cls1'); +expect(element).not.toHaveClass('cls1', 'cls2', 'cls3', 'cls4'); +expect(element).not.toHaveClass('cls1', { exact: true }); +expect(element).not.toHaveDisplayValue('str'); +expect(element).not.toHaveDisplayValue(['str1', 'str2']); +expect(element).not.toHaveDisplayValue(/str/); +expect(element).not.toHaveDisplayValue([/str1/, 'str2']); +expect(element).not.toHaveFocus(); +expect(element).not.toHaveFormValues({ foo: 'bar', baz: 1 }); +expect(element).not.toHaveStyle('display: block'); +expect(element).not.toHaveTextContent('Text'); +expect(element).not.toHaveTextContent(/Text/); +expect(element).not.toHaveTextContent('Text', { normalizeWhitespace: true }); +expect(element).not.toHaveTextContent(/Text/, { normalizeWhitespace: true }); +expect(element).not.toHaveValue(); +expect(element).not.toHaveValue('str'); +expect(element).not.toHaveValue(['str1', 'str2']); +expect(element).not.toHaveValue(1); +expect(element).not.toBeChecked(); +expect(element).not.toHaveDescription('some description'); +expect(element).not.toHaveDescription(); +expect(element).not.toHaveAccessibleDescription('some description'); +expect(element).not.toHaveAccessibleDescription(); +expect(element).not.toHaveAccessibleName('a label'); +expect(element).not.toHaveAccessibleName(); +expect(element).not.toBePartiallyChecked(); +expect(element).not.toHaveErrorMessage(); +expect(element).not.toHaveErrorMessage('Pikachu!'); + +// @ts-expect-error The types accidentally allowed any property by falling back to "any" +expect(element).nonExistentProperty(); + +function customExpect( + _actual: HTMLElement, +): matchers.TestingLibraryMatchers | matchers.TestingLibraryMatchers> { + throw new Error('Method not implemented.'); +} + +customExpect(element).toBeInTheDOM(); +customExpect(element).toBeInTheDOM(document.body); +customExpect(element).toBeInTheDocument(); +customExpect(element).toBeVisible(); +customExpect(element).toBeEmpty(); +customExpect(element).toBeDisabled(); +customExpect(element).toBeEnabled(); +customExpect(element).toBeInvalid(); +customExpect(element).toBeRequired(); +customExpect(element).toBeValid(); +customExpect(element).toContainElement(document.body); +customExpect(element).toContainElement(null); +customExpect(element).toContainHTML('body'); +customExpect(element).toHaveAttribute('attr'); +customExpect(element).toHaveAttribute('attr', true); +customExpect(element).toHaveAttribute('attr', 'yes'); +customExpect(element).toHaveClass(); +customExpect(element).toHaveClass('cls1'); +customExpect(element).toHaveClass('cls1', 'cls2', 'cls3', 'cls4'); +customExpect(element).toHaveClass('cls1', { exact: true }); +customExpect(element).toHaveDisplayValue('str'); +customExpect(element).toHaveDisplayValue(['str1', 'str2']); +customExpect(element).toHaveDisplayValue(/str/); +customExpect(element).toHaveDisplayValue([/str1/, 'str2']); +customExpect(element).toHaveFocus(); +customExpect(element).toHaveFormValues({ foo: 'bar', baz: 1 }); +customExpect(element).toHaveStyle('display: block'); +customExpect(element).toHaveStyle({ display: 'block', width: 100 }); +customExpect(element).toHaveTextContent('Text'); +customExpect(element).toHaveTextContent(/Text/); +customExpect(element).toHaveTextContent('Text', { normalizeWhitespace: true }); +customExpect(element).toHaveTextContent(/Text/, { normalizeWhitespace: true }); +customExpect(element).toHaveValue(); +customExpect(element).toHaveValue('str'); +customExpect(element).toHaveValue(['str1', 'str2']); +customExpect(element).toHaveValue(1); +customExpect(element).toHaveValue(null); +customExpect(element).toBeChecked(); +customExpect(element).toHaveDescription('some description'); +customExpect(element).toHaveDescription(/some description/); +customExpect(element).toHaveDescription(expect.stringContaining('partial')); +customExpect(element).toHaveDescription(); +customExpect(element).toHaveAccessibleDescription('some description'); +customExpect(element).toHaveAccessibleDescription(/some description/); +customExpect(element).toHaveAccessibleDescription(expect.stringContaining('partial')); +customExpect(element).toHaveAccessibleDescription(); + +customExpect(element).toHaveAccessibleErrorMessage(); +customExpect(element).toHaveAccessibleErrorMessage('Invalid time: the time must be between 9:00 AM and 5:00 PM'); +customExpect(element).toHaveAccessibleErrorMessage(/invalid time/i); +customExpect(element).toHaveAccessibleErrorMessage(expect.stringContaining('Invalid time')); + +customExpect(element).toHaveAccessibleName('a label'); +customExpect(element).toHaveAccessibleName(/a label/); +customExpect(element).toHaveAccessibleName(expect.stringContaining('partial label')); +customExpect(element).toHaveAccessibleName(); +customExpect(element).toHaveErrorMessage('Invalid time: the time must be between 9:00 AM and 5:00 PM'); +customExpect(element).toHaveErrorMessage(/invalid time/i); +customExpect(element).toHaveErrorMessage(expect.stringContaining('Invalid time')); + +// @ts-expect-error The types accidentally allowed any property by falling back to "any" +customExpect(element).nonExistentProperty(); From 118f0abf1fcc6bcc77316e598bc2dfb70490f832 Mon Sep 17 00:00:00 2001 From: John Gozde Date: Thu, 17 Aug 2023 10:44:20 -0600 Subject: [PATCH 3/6] Remove jest specifics from matchers.d.ts --- types/matchers.d.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/types/matchers.d.ts b/types/matchers.d.ts index 0552aa16..ff9b8401 100755 --- a/types/matchers.d.ts +++ b/types/matchers.d.ts @@ -1,5 +1,3 @@ -/// - declare namespace matchers { interface TestingLibraryMatchers { /** @@ -662,13 +660,10 @@ declare namespace matchers { */ toHaveErrorMessage(text?: string | RegExp | E): R } - - // Needs to extend Record to be accepted by expect.extend() - // as it requires a string index signature. - interface TestingLibraryMatchersExport - extends Record, - TestingLibraryMatchers {} } -declare const matchers: matchers.TestingLibraryMatchersExport +// Needs to extend Record to be accepted by expect.extend() +// as it requires a string index signature. +declare const matchers: matchers.TestingLibraryMatchers & + Record export = matchers From 05331532cb19e15bc31569969b94a38a02354883 Mon Sep 17 00:00:00 2001 From: John Gozde Date: Thu, 17 Aug 2023 10:57:15 -0600 Subject: [PATCH 4/6] Type tests for all test environments --- package.json | 3 +- tsconfig.json | 4 +- types-test.ts | 186 ------------------ .../jest-globals-custom-expect-types.test.ts | 97 +++++++++ .../jest-globals/jest-globals-types.test.ts | 118 +++++++++++ types/__tests__/jest-globals/tsconfig.json | 9 + .../jest/jest-custom-expect-types.test.ts | 96 +++++++++ types/__tests__/jest/jest-types.test.ts | 117 +++++++++++ types/__tests__/jest/tsconfig.json | 9 + types/__tests__/vitest/tsconfig.json | 9 + .../vitest/vitest-custom-expect-types.test.ts | 97 +++++++++ types/__tests__/vitest/vitest-types.test.ts | 118 +++++++++++ 12 files changed, 675 insertions(+), 188 deletions(-) delete mode 100644 types-test.ts create mode 100644 types/__tests__/jest-globals/jest-globals-custom-expect-types.test.ts create mode 100644 types/__tests__/jest-globals/jest-globals-types.test.ts create mode 100644 types/__tests__/jest-globals/tsconfig.json create mode 100644 types/__tests__/jest/jest-custom-expect-types.test.ts create mode 100644 types/__tests__/jest/jest-types.test.ts create mode 100644 types/__tests__/jest/tsconfig.json create mode 100644 types/__tests__/vitest/tsconfig.json create mode 100644 types/__tests__/vitest/vitest-custom-expect-types.test.ts create mode 100644 types/__tests__/vitest/vitest-types.test.ts diff --git a/package.json b/package.json index f8346ee5..5abb86bd 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "setup": "npm install && npm run validate -s", "test": "kcd-scripts test", "test:update": "npm test -- --updateSnapshot --coverage", - "validate": "kcd-scripts validate" + "test:types": "tsc -p types/__tests__/jest && tsc -p types/__tests__/jest-globals && tsc -p types/__tests__/vitest", + "validate": "kcd-scripts validate && npm run test:types" }, "files": [ "dist", diff --git a/tsconfig.json b/tsconfig.json index ef9b2d9b..dec023f5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,9 @@ { "compilerOptions": { + "noEmit": true, "strict": true, "skipLibCheck": true }, - "include": ["*.d.ts", "types", "types-test.ts"] + "include": ["*.d.ts", "types"], + "exclude": ["types/__tests__"] } diff --git a/types-test.ts b/types-test.ts deleted file mode 100644 index 536ebb2b..00000000 --- a/types-test.ts +++ /dev/null @@ -1,186 +0,0 @@ -/** - * File that tests whether the TypeScript typings work as expected. - */ - -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-floating-promises */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ - -import matchers = require('./types/matchers'); - -expect.extend(matchers); - -const element: HTMLElement = document.body; - -expect(element).toBeInTheDOM(); -expect(element).toBeInTheDOM(document.body); -expect(element).toBeInTheDocument(); -expect(element).toBeVisible(); -expect(element).toBeEmpty(); -expect(element).toBeDisabled(); -expect(element).toBeEnabled(); -expect(element).toBeInvalid(); -expect(element).toBeRequired(); -expect(element).toBeValid(); -expect(element).toContainElement(document.body); -expect(element).toContainElement(null); -expect(element).toContainHTML('body'); -expect(element).toHaveAttribute('attr'); -expect(element).toHaveAttribute('attr', true); -expect(element).toHaveAttribute('attr', 'yes'); -expect(element).toHaveClass(); -expect(element).toHaveClass('cls1'); -expect(element).toHaveClass('cls1', 'cls2', 'cls3', 'cls4'); -expect(element).toHaveClass('cls1', { exact: true }); -expect(element).toHaveDisplayValue('str'); -expect(element).toHaveDisplayValue(['str1', 'str2']); -expect(element).toHaveDisplayValue(/str/); -expect(element).toHaveDisplayValue([/str1/, 'str2']); -expect(element).toHaveFocus(); -expect(element).toHaveFormValues({ foo: 'bar', baz: 1 }); -expect(element).toHaveStyle('display: block'); -expect(element).toHaveStyle({ display: 'block', width: 100 }); -expect(element).toHaveTextContent('Text'); -expect(element).toHaveTextContent(/Text/); -expect(element).toHaveTextContent('Text', { normalizeWhitespace: true }); -expect(element).toHaveTextContent(/Text/, { normalizeWhitespace: true }); -expect(element).toHaveValue(); -expect(element).toHaveValue('str'); -expect(element).toHaveValue(['str1', 'str2']); -expect(element).toHaveValue(1); -expect(element).toHaveValue(null); -expect(element).toBeChecked(); -expect(element).toHaveDescription('some description'); -expect(element).toHaveDescription(/some description/); -expect(element).toHaveDescription(expect.stringContaining('partial')); -expect(element).toHaveDescription(); -expect(element).toHaveAccessibleDescription('some description'); -expect(element).toHaveAccessibleDescription(/some description/); -expect(element).toHaveAccessibleDescription(expect.stringContaining('partial')); -expect(element).toHaveAccessibleDescription(); -expect(element).toHaveAccessibleName('a label'); -expect(element).toHaveAccessibleName(/a label/); -expect(element).toHaveAccessibleName(expect.stringContaining('partial label')); -expect(element).toHaveAccessibleName(); -expect(element).toHaveErrorMessage('Invalid time: the time must be between 9:00 AM and 5:00 PM'); -expect(element).toHaveErrorMessage(/invalid time/i); -expect(element).toHaveErrorMessage(expect.stringContaining('Invalid time')); - -expect(element).not.toBeInTheDOM(); -expect(element).not.toBeInTheDOM(document.body); -expect(element).not.toBeInTheDocument(); -expect(element).not.toBeVisible(); -expect(element).not.toBeEmpty(); -expect(element).not.toBeEmptyDOMElement(); -expect(element).not.toBeDisabled(); -expect(element).not.toBeEnabled(); -expect(element).not.toBeInvalid(); -expect(element).not.toBeRequired(); -expect(element).not.toBeValid(); -expect(element).not.toContainElement(document.body); -expect(element).not.toContainElement(null); -expect(element).not.toContainHTML('body'); -expect(element).not.toHaveAttribute('attr'); -expect(element).not.toHaveAttribute('attr', true); -expect(element).not.toHaveAttribute('attr', 'yes'); -expect(element).not.toHaveClass(); -expect(element).not.toHaveClass('cls1'); -expect(element).not.toHaveClass('cls1', 'cls2', 'cls3', 'cls4'); -expect(element).not.toHaveClass('cls1', { exact: true }); -expect(element).not.toHaveDisplayValue('str'); -expect(element).not.toHaveDisplayValue(['str1', 'str2']); -expect(element).not.toHaveDisplayValue(/str/); -expect(element).not.toHaveDisplayValue([/str1/, 'str2']); -expect(element).not.toHaveFocus(); -expect(element).not.toHaveFormValues({ foo: 'bar', baz: 1 }); -expect(element).not.toHaveStyle('display: block'); -expect(element).not.toHaveTextContent('Text'); -expect(element).not.toHaveTextContent(/Text/); -expect(element).not.toHaveTextContent('Text', { normalizeWhitespace: true }); -expect(element).not.toHaveTextContent(/Text/, { normalizeWhitespace: true }); -expect(element).not.toHaveValue(); -expect(element).not.toHaveValue('str'); -expect(element).not.toHaveValue(['str1', 'str2']); -expect(element).not.toHaveValue(1); -expect(element).not.toBeChecked(); -expect(element).not.toHaveDescription('some description'); -expect(element).not.toHaveDescription(); -expect(element).not.toHaveAccessibleDescription('some description'); -expect(element).not.toHaveAccessibleDescription(); -expect(element).not.toHaveAccessibleName('a label'); -expect(element).not.toHaveAccessibleName(); -expect(element).not.toBePartiallyChecked(); -expect(element).not.toHaveErrorMessage(); -expect(element).not.toHaveErrorMessage('Pikachu!'); - -// @ts-expect-error The types accidentally allowed any property by falling back to "any" -expect(element).nonExistentProperty(); - -function customExpect( - _actual: HTMLElement, -): matchers.TestingLibraryMatchers | matchers.TestingLibraryMatchers> { - throw new Error('Method not implemented.'); -} - -customExpect(element).toBeInTheDOM(); -customExpect(element).toBeInTheDOM(document.body); -customExpect(element).toBeInTheDocument(); -customExpect(element).toBeVisible(); -customExpect(element).toBeEmpty(); -customExpect(element).toBeDisabled(); -customExpect(element).toBeEnabled(); -customExpect(element).toBeInvalid(); -customExpect(element).toBeRequired(); -customExpect(element).toBeValid(); -customExpect(element).toContainElement(document.body); -customExpect(element).toContainElement(null); -customExpect(element).toContainHTML('body'); -customExpect(element).toHaveAttribute('attr'); -customExpect(element).toHaveAttribute('attr', true); -customExpect(element).toHaveAttribute('attr', 'yes'); -customExpect(element).toHaveClass(); -customExpect(element).toHaveClass('cls1'); -customExpect(element).toHaveClass('cls1', 'cls2', 'cls3', 'cls4'); -customExpect(element).toHaveClass('cls1', { exact: true }); -customExpect(element).toHaveDisplayValue('str'); -customExpect(element).toHaveDisplayValue(['str1', 'str2']); -customExpect(element).toHaveDisplayValue(/str/); -customExpect(element).toHaveDisplayValue([/str1/, 'str2']); -customExpect(element).toHaveFocus(); -customExpect(element).toHaveFormValues({ foo: 'bar', baz: 1 }); -customExpect(element).toHaveStyle('display: block'); -customExpect(element).toHaveStyle({ display: 'block', width: 100 }); -customExpect(element).toHaveTextContent('Text'); -customExpect(element).toHaveTextContent(/Text/); -customExpect(element).toHaveTextContent('Text', { normalizeWhitespace: true }); -customExpect(element).toHaveTextContent(/Text/, { normalizeWhitespace: true }); -customExpect(element).toHaveValue(); -customExpect(element).toHaveValue('str'); -customExpect(element).toHaveValue(['str1', 'str2']); -customExpect(element).toHaveValue(1); -customExpect(element).toHaveValue(null); -customExpect(element).toBeChecked(); -customExpect(element).toHaveDescription('some description'); -customExpect(element).toHaveDescription(/some description/); -customExpect(element).toHaveDescription(expect.stringContaining('partial')); -customExpect(element).toHaveDescription(); -customExpect(element).toHaveAccessibleDescription('some description'); -customExpect(element).toHaveAccessibleDescription(/some description/); -customExpect(element).toHaveAccessibleDescription(expect.stringContaining('partial')); -customExpect(element).toHaveAccessibleDescription(); - -customExpect(element).toHaveAccessibleErrorMessage(); -customExpect(element).toHaveAccessibleErrorMessage('Invalid time: the time must be between 9:00 AM and 5:00 PM'); -customExpect(element).toHaveAccessibleErrorMessage(/invalid time/i); -customExpect(element).toHaveAccessibleErrorMessage(expect.stringContaining('Invalid time')); - -customExpect(element).toHaveAccessibleName('a label'); -customExpect(element).toHaveAccessibleName(/a label/); -customExpect(element).toHaveAccessibleName(expect.stringContaining('partial label')); -customExpect(element).toHaveAccessibleName(); -customExpect(element).toHaveErrorMessage('Invalid time: the time must be between 9:00 AM and 5:00 PM'); -customExpect(element).toHaveErrorMessage(/invalid time/i); -customExpect(element).toHaveErrorMessage(expect.stringContaining('Invalid time')); - -// @ts-expect-error The types accidentally allowed any property by falling back to "any" -customExpect(element).nonExistentProperty(); diff --git a/types/__tests__/jest-globals/jest-globals-custom-expect-types.test.ts b/types/__tests__/jest-globals/jest-globals-custom-expect-types.test.ts new file mode 100644 index 00000000..96034dc1 --- /dev/null +++ b/types/__tests__/jest-globals/jest-globals-custom-expect-types.test.ts @@ -0,0 +1,97 @@ +/** + * File that tests whether the TypeScript typings work as expected. + */ + +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-floating-promises */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ + +import {expect} from '@jest/globals' +import * as matchers from '../../matchers' + +expect.extend(matchers) + +const element: HTMLElement = document.body + +function customExpect( + _actual: HTMLElement, +): + | matchers.TestingLibraryMatchers + | matchers.TestingLibraryMatchers> { + throw new Error('Method not implemented.') +} + +customExpect(element).toBeInTheDOM() +customExpect(element).toBeInTheDOM(document.body) +customExpect(element).toBeInTheDocument() +customExpect(element).toBeVisible() +customExpect(element).toBeEmpty() +customExpect(element).toBeDisabled() +customExpect(element).toBeEnabled() +customExpect(element).toBeInvalid() +customExpect(element).toBeRequired() +customExpect(element).toBeValid() +customExpect(element).toContainElement(document.body) +customExpect(element).toContainElement(null) +customExpect(element).toContainHTML('body') +customExpect(element).toHaveAttribute('attr') +customExpect(element).toHaveAttribute('attr', true) +customExpect(element).toHaveAttribute('attr', 'yes') +customExpect(element).toHaveClass() +customExpect(element).toHaveClass('cls1') +customExpect(element).toHaveClass('cls1', 'cls2', 'cls3', 'cls4') +customExpect(element).toHaveClass('cls1', {exact: true}) +customExpect(element).toHaveDisplayValue('str') +customExpect(element).toHaveDisplayValue(['str1', 'str2']) +customExpect(element).toHaveDisplayValue(/str/) +customExpect(element).toHaveDisplayValue([/str1/, 'str2']) +customExpect(element).toHaveFocus() +customExpect(element).toHaveFormValues({foo: 'bar', baz: 1}) +customExpect(element).toHaveStyle('display: block') +customExpect(element).toHaveStyle({display: 'block', width: 100}) +customExpect(element).toHaveTextContent('Text') +customExpect(element).toHaveTextContent(/Text/) +customExpect(element).toHaveTextContent('Text', {normalizeWhitespace: true}) +customExpect(element).toHaveTextContent(/Text/, {normalizeWhitespace: true}) +customExpect(element).toHaveValue() +customExpect(element).toHaveValue('str') +customExpect(element).toHaveValue(['str1', 'str2']) +customExpect(element).toHaveValue(1) +customExpect(element).toHaveValue(null) +customExpect(element).toBeChecked() +customExpect(element).toHaveDescription('some description') +customExpect(element).toHaveDescription(/some description/) +customExpect(element).toHaveDescription(expect.stringContaining('partial')) +customExpect(element).toHaveDescription() +customExpect(element).toHaveAccessibleDescription('some description') +customExpect(element).toHaveAccessibleDescription(/some description/) +customExpect(element).toHaveAccessibleDescription( + expect.stringContaining('partial'), +) +customExpect(element).toHaveAccessibleDescription() + +customExpect(element).toHaveAccessibleErrorMessage() +customExpect(element).toHaveAccessibleErrorMessage( + 'Invalid time: the time must be between 9:00 AM and 5:00 PM', +) +customExpect(element).toHaveAccessibleErrorMessage(/invalid time/i) +customExpect(element).toHaveAccessibleErrorMessage( + expect.stringContaining('Invalid time'), +) + +customExpect(element).toHaveAccessibleName('a label') +customExpect(element).toHaveAccessibleName(/a label/) +customExpect(element).toHaveAccessibleName( + expect.stringContaining('partial label'), +) +customExpect(element).toHaveAccessibleName() +customExpect(element).toHaveErrorMessage( + 'Invalid time: the time must be between 9:00 AM and 5:00 PM', +) +customExpect(element).toHaveErrorMessage(/invalid time/i) +customExpect(element).toHaveErrorMessage( + expect.stringContaining('Invalid time'), +) + +// @ts-expect-error The types accidentally allowed any property by falling back to "any" +customExpect(element).nonExistentProperty() diff --git a/types/__tests__/jest-globals/jest-globals-types.test.ts b/types/__tests__/jest-globals/jest-globals-types.test.ts new file mode 100644 index 00000000..645f44ec --- /dev/null +++ b/types/__tests__/jest-globals/jest-globals-types.test.ts @@ -0,0 +1,118 @@ +/** + * File that tests whether the TypeScript typings for @types/jest work as expected. + */ + +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-floating-promises */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ + +import {expect} from '@jest/globals' +import '../../jest-globals' + +const element: HTMLElement = document.body + +expect(element).toBeInTheDOM() +expect(element).toBeInTheDOM(document.body) +expect(element).toBeInTheDocument() +expect(element).toBeVisible() +expect(element).toBeEmpty() +expect(element).toBeDisabled() +expect(element).toBeEnabled() +expect(element).toBeInvalid() +expect(element).toBeRequired() +expect(element).toBeValid() +expect(element).toContainElement(document.body) +expect(element).toContainElement(null) +expect(element).toContainHTML('body') +expect(element).toHaveAttribute('attr') +expect(element).toHaveAttribute('attr', true) +expect(element).toHaveAttribute('attr', 'yes') +expect(element).toHaveClass() +expect(element).toHaveClass('cls1') +expect(element).toHaveClass('cls1', 'cls2', 'cls3', 'cls4') +expect(element).toHaveClass('cls1', {exact: true}) +expect(element).toHaveDisplayValue('str') +expect(element).toHaveDisplayValue(['str1', 'str2']) +expect(element).toHaveDisplayValue(/str/) +expect(element).toHaveDisplayValue([/str1/, 'str2']) +expect(element).toHaveFocus() +expect(element).toHaveFormValues({foo: 'bar', baz: 1}) +expect(element).toHaveStyle('display: block') +expect(element).toHaveStyle({display: 'block', width: 100}) +expect(element).toHaveTextContent('Text') +expect(element).toHaveTextContent(/Text/) +expect(element).toHaveTextContent('Text', {normalizeWhitespace: true}) +expect(element).toHaveTextContent(/Text/, {normalizeWhitespace: true}) +expect(element).toHaveValue() +expect(element).toHaveValue('str') +expect(element).toHaveValue(['str1', 'str2']) +expect(element).toHaveValue(1) +expect(element).toHaveValue(null) +expect(element).toBeChecked() +expect(element).toHaveDescription('some description') +expect(element).toHaveDescription(/some description/) +expect(element).toHaveDescription(expect.stringContaining('partial')) +expect(element).toHaveDescription() +expect(element).toHaveAccessibleDescription('some description') +expect(element).toHaveAccessibleDescription(/some description/) +expect(element).toHaveAccessibleDescription(expect.stringContaining('partial')) +expect(element).toHaveAccessibleDescription() +expect(element).toHaveAccessibleName('a label') +expect(element).toHaveAccessibleName(/a label/) +expect(element).toHaveAccessibleName(expect.stringContaining('partial label')) +expect(element).toHaveAccessibleName() +expect(element).toHaveErrorMessage( + 'Invalid time: the time must be between 9:00 AM and 5:00 PM', +) +expect(element).toHaveErrorMessage(/invalid time/i) +expect(element).toHaveErrorMessage(expect.stringContaining('Invalid time')) + +expect(element).not.toBeInTheDOM() +expect(element).not.toBeInTheDOM(document.body) +expect(element).not.toBeInTheDocument() +expect(element).not.toBeVisible() +expect(element).not.toBeEmpty() +expect(element).not.toBeEmptyDOMElement() +expect(element).not.toBeDisabled() +expect(element).not.toBeEnabled() +expect(element).not.toBeInvalid() +expect(element).not.toBeRequired() +expect(element).not.toBeValid() +expect(element).not.toContainElement(document.body) +expect(element).not.toContainElement(null) +expect(element).not.toContainHTML('body') +expect(element).not.toHaveAttribute('attr') +expect(element).not.toHaveAttribute('attr', true) +expect(element).not.toHaveAttribute('attr', 'yes') +expect(element).not.toHaveClass() +expect(element).not.toHaveClass('cls1') +expect(element).not.toHaveClass('cls1', 'cls2', 'cls3', 'cls4') +expect(element).not.toHaveClass('cls1', {exact: true}) +expect(element).not.toHaveDisplayValue('str') +expect(element).not.toHaveDisplayValue(['str1', 'str2']) +expect(element).not.toHaveDisplayValue(/str/) +expect(element).not.toHaveDisplayValue([/str1/, 'str2']) +expect(element).not.toHaveFocus() +expect(element).not.toHaveFormValues({foo: 'bar', baz: 1}) +expect(element).not.toHaveStyle('display: block') +expect(element).not.toHaveTextContent('Text') +expect(element).not.toHaveTextContent(/Text/) +expect(element).not.toHaveTextContent('Text', {normalizeWhitespace: true}) +expect(element).not.toHaveTextContent(/Text/, {normalizeWhitespace: true}) +expect(element).not.toHaveValue() +expect(element).not.toHaveValue('str') +expect(element).not.toHaveValue(['str1', 'str2']) +expect(element).not.toHaveValue(1) +expect(element).not.toBeChecked() +expect(element).not.toHaveDescription('some description') +expect(element).not.toHaveDescription() +expect(element).not.toHaveAccessibleDescription('some description') +expect(element).not.toHaveAccessibleDescription() +expect(element).not.toHaveAccessibleName('a label') +expect(element).not.toHaveAccessibleName() +expect(element).not.toBePartiallyChecked() +expect(element).not.toHaveErrorMessage() +expect(element).not.toHaveErrorMessage('Pikachu!') + +// @ts-expect-error The types accidentally allowed any property by falling back to "any" +expect(element).nonExistentProperty() diff --git a/types/__tests__/jest-globals/tsconfig.json b/types/__tests__/jest-globals/tsconfig.json new file mode 100644 index 00000000..25a9cf27 --- /dev/null +++ b/types/__tests__/jest-globals/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "noEmit": true, + "strict": true, + "skipLibCheck": true, + "types": [] + }, + "include": ["*.ts"] +} diff --git a/types/__tests__/jest/jest-custom-expect-types.test.ts b/types/__tests__/jest/jest-custom-expect-types.test.ts new file mode 100644 index 00000000..c3ac5a7d --- /dev/null +++ b/types/__tests__/jest/jest-custom-expect-types.test.ts @@ -0,0 +1,96 @@ +/** + * File that tests whether the TypeScript typings work as expected. + */ + +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-floating-promises */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ + +import * as matchers from '../../matchers' + +expect.extend(matchers) + +const element: HTMLElement = document.body + +function customExpect( + _actual: HTMLElement, +): + | matchers.TestingLibraryMatchers + | matchers.TestingLibraryMatchers> { + throw new Error('Method not implemented.') +} + +customExpect(element).toBeInTheDOM() +customExpect(element).toBeInTheDOM(document.body) +customExpect(element).toBeInTheDocument() +customExpect(element).toBeVisible() +customExpect(element).toBeEmpty() +customExpect(element).toBeDisabled() +customExpect(element).toBeEnabled() +customExpect(element).toBeInvalid() +customExpect(element).toBeRequired() +customExpect(element).toBeValid() +customExpect(element).toContainElement(document.body) +customExpect(element).toContainElement(null) +customExpect(element).toContainHTML('body') +customExpect(element).toHaveAttribute('attr') +customExpect(element).toHaveAttribute('attr', true) +customExpect(element).toHaveAttribute('attr', 'yes') +customExpect(element).toHaveClass() +customExpect(element).toHaveClass('cls1') +customExpect(element).toHaveClass('cls1', 'cls2', 'cls3', 'cls4') +customExpect(element).toHaveClass('cls1', {exact: true}) +customExpect(element).toHaveDisplayValue('str') +customExpect(element).toHaveDisplayValue(['str1', 'str2']) +customExpect(element).toHaveDisplayValue(/str/) +customExpect(element).toHaveDisplayValue([/str1/, 'str2']) +customExpect(element).toHaveFocus() +customExpect(element).toHaveFormValues({foo: 'bar', baz: 1}) +customExpect(element).toHaveStyle('display: block') +customExpect(element).toHaveStyle({display: 'block', width: 100}) +customExpect(element).toHaveTextContent('Text') +customExpect(element).toHaveTextContent(/Text/) +customExpect(element).toHaveTextContent('Text', {normalizeWhitespace: true}) +customExpect(element).toHaveTextContent(/Text/, {normalizeWhitespace: true}) +customExpect(element).toHaveValue() +customExpect(element).toHaveValue('str') +customExpect(element).toHaveValue(['str1', 'str2']) +customExpect(element).toHaveValue(1) +customExpect(element).toHaveValue(null) +customExpect(element).toBeChecked() +customExpect(element).toHaveDescription('some description') +customExpect(element).toHaveDescription(/some description/) +customExpect(element).toHaveDescription(expect.stringContaining('partial')) +customExpect(element).toHaveDescription() +customExpect(element).toHaveAccessibleDescription('some description') +customExpect(element).toHaveAccessibleDescription(/some description/) +customExpect(element).toHaveAccessibleDescription( + expect.stringContaining('partial'), +) +customExpect(element).toHaveAccessibleDescription() + +customExpect(element).toHaveAccessibleErrorMessage() +customExpect(element).toHaveAccessibleErrorMessage( + 'Invalid time: the time must be between 9:00 AM and 5:00 PM', +) +customExpect(element).toHaveAccessibleErrorMessage(/invalid time/i) +customExpect(element).toHaveAccessibleErrorMessage( + expect.stringContaining('Invalid time'), +) + +customExpect(element).toHaveAccessibleName('a label') +customExpect(element).toHaveAccessibleName(/a label/) +customExpect(element).toHaveAccessibleName( + expect.stringContaining('partial label'), +) +customExpect(element).toHaveAccessibleName() +customExpect(element).toHaveErrorMessage( + 'Invalid time: the time must be between 9:00 AM and 5:00 PM', +) +customExpect(element).toHaveErrorMessage(/invalid time/i) +customExpect(element).toHaveErrorMessage( + expect.stringContaining('Invalid time'), +) + +// @ts-expect-error The types accidentally allowed any property by falling back to "any" +customExpect(element).nonExistentProperty() diff --git a/types/__tests__/jest/jest-types.test.ts b/types/__tests__/jest/jest-types.test.ts new file mode 100644 index 00000000..404b9881 --- /dev/null +++ b/types/__tests__/jest/jest-types.test.ts @@ -0,0 +1,117 @@ +/** + * File that tests whether the TypeScript typings for @types/jest work as expected. + */ + +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-floating-promises */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ + +import '../../jest' + +const element: HTMLElement = document.body + +expect(element).toBeInTheDOM() +expect(element).toBeInTheDOM(document.body) +expect(element).toBeInTheDocument() +expect(element).toBeVisible() +expect(element).toBeEmpty() +expect(element).toBeDisabled() +expect(element).toBeEnabled() +expect(element).toBeInvalid() +expect(element).toBeRequired() +expect(element).toBeValid() +expect(element).toContainElement(document.body) +expect(element).toContainElement(null) +expect(element).toContainHTML('body') +expect(element).toHaveAttribute('attr') +expect(element).toHaveAttribute('attr', true) +expect(element).toHaveAttribute('attr', 'yes') +expect(element).toHaveClass() +expect(element).toHaveClass('cls1') +expect(element).toHaveClass('cls1', 'cls2', 'cls3', 'cls4') +expect(element).toHaveClass('cls1', {exact: true}) +expect(element).toHaveDisplayValue('str') +expect(element).toHaveDisplayValue(['str1', 'str2']) +expect(element).toHaveDisplayValue(/str/) +expect(element).toHaveDisplayValue([/str1/, 'str2']) +expect(element).toHaveFocus() +expect(element).toHaveFormValues({foo: 'bar', baz: 1}) +expect(element).toHaveStyle('display: block') +expect(element).toHaveStyle({display: 'block', width: 100}) +expect(element).toHaveTextContent('Text') +expect(element).toHaveTextContent(/Text/) +expect(element).toHaveTextContent('Text', {normalizeWhitespace: true}) +expect(element).toHaveTextContent(/Text/, {normalizeWhitespace: true}) +expect(element).toHaveValue() +expect(element).toHaveValue('str') +expect(element).toHaveValue(['str1', 'str2']) +expect(element).toHaveValue(1) +expect(element).toHaveValue(null) +expect(element).toBeChecked() +expect(element).toHaveDescription('some description') +expect(element).toHaveDescription(/some description/) +expect(element).toHaveDescription(expect.stringContaining('partial')) +expect(element).toHaveDescription() +expect(element).toHaveAccessibleDescription('some description') +expect(element).toHaveAccessibleDescription(/some description/) +expect(element).toHaveAccessibleDescription(expect.stringContaining('partial')) +expect(element).toHaveAccessibleDescription() +expect(element).toHaveAccessibleName('a label') +expect(element).toHaveAccessibleName(/a label/) +expect(element).toHaveAccessibleName(expect.stringContaining('partial label')) +expect(element).toHaveAccessibleName() +expect(element).toHaveErrorMessage( + 'Invalid time: the time must be between 9:00 AM and 5:00 PM', +) +expect(element).toHaveErrorMessage(/invalid time/i) +expect(element).toHaveErrorMessage(expect.stringContaining('Invalid time')) + +expect(element).not.toBeInTheDOM() +expect(element).not.toBeInTheDOM(document.body) +expect(element).not.toBeInTheDocument() +expect(element).not.toBeVisible() +expect(element).not.toBeEmpty() +expect(element).not.toBeEmptyDOMElement() +expect(element).not.toBeDisabled() +expect(element).not.toBeEnabled() +expect(element).not.toBeInvalid() +expect(element).not.toBeRequired() +expect(element).not.toBeValid() +expect(element).not.toContainElement(document.body) +expect(element).not.toContainElement(null) +expect(element).not.toContainHTML('body') +expect(element).not.toHaveAttribute('attr') +expect(element).not.toHaveAttribute('attr', true) +expect(element).not.toHaveAttribute('attr', 'yes') +expect(element).not.toHaveClass() +expect(element).not.toHaveClass('cls1') +expect(element).not.toHaveClass('cls1', 'cls2', 'cls3', 'cls4') +expect(element).not.toHaveClass('cls1', {exact: true}) +expect(element).not.toHaveDisplayValue('str') +expect(element).not.toHaveDisplayValue(['str1', 'str2']) +expect(element).not.toHaveDisplayValue(/str/) +expect(element).not.toHaveDisplayValue([/str1/, 'str2']) +expect(element).not.toHaveFocus() +expect(element).not.toHaveFormValues({foo: 'bar', baz: 1}) +expect(element).not.toHaveStyle('display: block') +expect(element).not.toHaveTextContent('Text') +expect(element).not.toHaveTextContent(/Text/) +expect(element).not.toHaveTextContent('Text', {normalizeWhitespace: true}) +expect(element).not.toHaveTextContent(/Text/, {normalizeWhitespace: true}) +expect(element).not.toHaveValue() +expect(element).not.toHaveValue('str') +expect(element).not.toHaveValue(['str1', 'str2']) +expect(element).not.toHaveValue(1) +expect(element).not.toBeChecked() +expect(element).not.toHaveDescription('some description') +expect(element).not.toHaveDescription() +expect(element).not.toHaveAccessibleDescription('some description') +expect(element).not.toHaveAccessibleDescription() +expect(element).not.toHaveAccessibleName('a label') +expect(element).not.toHaveAccessibleName() +expect(element).not.toBePartiallyChecked() +expect(element).not.toHaveErrorMessage() +expect(element).not.toHaveErrorMessage('Pikachu!') + +// @ts-expect-error The types accidentally allowed any property by falling back to "any" +expect(element).nonExistentProperty() diff --git a/types/__tests__/jest/tsconfig.json b/types/__tests__/jest/tsconfig.json new file mode 100644 index 00000000..52ecd5d4 --- /dev/null +++ b/types/__tests__/jest/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "noEmit": true, + "strict": true, + "skipLibCheck": true, + "types": ["jest"] + }, + "include": ["*.ts"] +} diff --git a/types/__tests__/vitest/tsconfig.json b/types/__tests__/vitest/tsconfig.json new file mode 100644 index 00000000..25a9cf27 --- /dev/null +++ b/types/__tests__/vitest/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "noEmit": true, + "strict": true, + "skipLibCheck": true, + "types": [] + }, + "include": ["*.ts"] +} diff --git a/types/__tests__/vitest/vitest-custom-expect-types.test.ts b/types/__tests__/vitest/vitest-custom-expect-types.test.ts new file mode 100644 index 00000000..e9008966 --- /dev/null +++ b/types/__tests__/vitest/vitest-custom-expect-types.test.ts @@ -0,0 +1,97 @@ +/** + * File that tests whether the TypeScript typings work as expected. + */ + +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-floating-promises */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ + +import {expect} from 'vitest' +import * as matchers from '../../matchers' + +expect.extend(matchers) + +const element: HTMLElement = document.body + +function customExpect( + _actual: HTMLElement, +): + | matchers.TestingLibraryMatchers + | matchers.TestingLibraryMatchers> { + throw new Error('Method not implemented.') +} + +customExpect(element).toBeInTheDOM() +customExpect(element).toBeInTheDOM(document.body) +customExpect(element).toBeInTheDocument() +customExpect(element).toBeVisible() +customExpect(element).toBeEmpty() +customExpect(element).toBeDisabled() +customExpect(element).toBeEnabled() +customExpect(element).toBeInvalid() +customExpect(element).toBeRequired() +customExpect(element).toBeValid() +customExpect(element).toContainElement(document.body) +customExpect(element).toContainElement(null) +customExpect(element).toContainHTML('body') +customExpect(element).toHaveAttribute('attr') +customExpect(element).toHaveAttribute('attr', true) +customExpect(element).toHaveAttribute('attr', 'yes') +customExpect(element).toHaveClass() +customExpect(element).toHaveClass('cls1') +customExpect(element).toHaveClass('cls1', 'cls2', 'cls3', 'cls4') +customExpect(element).toHaveClass('cls1', {exact: true}) +customExpect(element).toHaveDisplayValue('str') +customExpect(element).toHaveDisplayValue(['str1', 'str2']) +customExpect(element).toHaveDisplayValue(/str/) +customExpect(element).toHaveDisplayValue([/str1/, 'str2']) +customExpect(element).toHaveFocus() +customExpect(element).toHaveFormValues({foo: 'bar', baz: 1}) +customExpect(element).toHaveStyle('display: block') +customExpect(element).toHaveStyle({display: 'block', width: 100}) +customExpect(element).toHaveTextContent('Text') +customExpect(element).toHaveTextContent(/Text/) +customExpect(element).toHaveTextContent('Text', {normalizeWhitespace: true}) +customExpect(element).toHaveTextContent(/Text/, {normalizeWhitespace: true}) +customExpect(element).toHaveValue() +customExpect(element).toHaveValue('str') +customExpect(element).toHaveValue(['str1', 'str2']) +customExpect(element).toHaveValue(1) +customExpect(element).toHaveValue(null) +customExpect(element).toBeChecked() +customExpect(element).toHaveDescription('some description') +customExpect(element).toHaveDescription(/some description/) +customExpect(element).toHaveDescription(expect.stringContaining('partial')) +customExpect(element).toHaveDescription() +customExpect(element).toHaveAccessibleDescription('some description') +customExpect(element).toHaveAccessibleDescription(/some description/) +customExpect(element).toHaveAccessibleDescription( + expect.stringContaining('partial'), +) +customExpect(element).toHaveAccessibleDescription() + +customExpect(element).toHaveAccessibleErrorMessage() +customExpect(element).toHaveAccessibleErrorMessage( + 'Invalid time: the time must be between 9:00 AM and 5:00 PM', +) +customExpect(element).toHaveAccessibleErrorMessage(/invalid time/i) +customExpect(element).toHaveAccessibleErrorMessage( + expect.stringContaining('Invalid time'), +) + +customExpect(element).toHaveAccessibleName('a label') +customExpect(element).toHaveAccessibleName(/a label/) +customExpect(element).toHaveAccessibleName( + expect.stringContaining('partial label'), +) +customExpect(element).toHaveAccessibleName() +customExpect(element).toHaveErrorMessage( + 'Invalid time: the time must be between 9:00 AM and 5:00 PM', +) +customExpect(element).toHaveErrorMessage(/invalid time/i) +customExpect(element).toHaveErrorMessage( + expect.stringContaining('Invalid time'), +) + +// @ts-expect-error The types accidentally allowed any property by falling back to "any" +customExpect(element).nonExistentProperty() diff --git a/types/__tests__/vitest/vitest-types.test.ts b/types/__tests__/vitest/vitest-types.test.ts new file mode 100644 index 00000000..69f1dbc5 --- /dev/null +++ b/types/__tests__/vitest/vitest-types.test.ts @@ -0,0 +1,118 @@ +/** + * File that tests whether the TypeScript typings for @types/jest work as expected. + */ + +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-floating-promises */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ + +import {expect} from 'vitest' +import '../../vitest' + +const element: HTMLElement = document.body + +expect(element).toBeInTheDOM() +expect(element).toBeInTheDOM(document.body) +expect(element).toBeInTheDocument() +expect(element).toBeVisible() +expect(element).toBeEmpty() +expect(element).toBeDisabled() +expect(element).toBeEnabled() +expect(element).toBeInvalid() +expect(element).toBeRequired() +expect(element).toBeValid() +expect(element).toContainElement(document.body) +expect(element).toContainElement(null) +expect(element).toContainHTML('body') +expect(element).toHaveAttribute('attr') +expect(element).toHaveAttribute('attr', true) +expect(element).toHaveAttribute('attr', 'yes') +expect(element).toHaveClass() +expect(element).toHaveClass('cls1') +expect(element).toHaveClass('cls1', 'cls2', 'cls3', 'cls4') +expect(element).toHaveClass('cls1', {exact: true}) +expect(element).toHaveDisplayValue('str') +expect(element).toHaveDisplayValue(['str1', 'str2']) +expect(element).toHaveDisplayValue(/str/) +expect(element).toHaveDisplayValue([/str1/, 'str2']) +expect(element).toHaveFocus() +expect(element).toHaveFormValues({foo: 'bar', baz: 1}) +expect(element).toHaveStyle('display: block') +expect(element).toHaveStyle({display: 'block', width: 100}) +expect(element).toHaveTextContent('Text') +expect(element).toHaveTextContent(/Text/) +expect(element).toHaveTextContent('Text', {normalizeWhitespace: true}) +expect(element).toHaveTextContent(/Text/, {normalizeWhitespace: true}) +expect(element).toHaveValue() +expect(element).toHaveValue('str') +expect(element).toHaveValue(['str1', 'str2']) +expect(element).toHaveValue(1) +expect(element).toHaveValue(null) +expect(element).toBeChecked() +expect(element).toHaveDescription('some description') +expect(element).toHaveDescription(/some description/) +expect(element).toHaveDescription(expect.stringContaining('partial')) +expect(element).toHaveDescription() +expect(element).toHaveAccessibleDescription('some description') +expect(element).toHaveAccessibleDescription(/some description/) +expect(element).toHaveAccessibleDescription(expect.stringContaining('partial')) +expect(element).toHaveAccessibleDescription() +expect(element).toHaveAccessibleName('a label') +expect(element).toHaveAccessibleName(/a label/) +expect(element).toHaveAccessibleName(expect.stringContaining('partial label')) +expect(element).toHaveAccessibleName() +expect(element).toHaveErrorMessage( + 'Invalid time: the time must be between 9:00 AM and 5:00 PM', +) +expect(element).toHaveErrorMessage(/invalid time/i) +expect(element).toHaveErrorMessage(expect.stringContaining('Invalid time')) + +expect(element).not.toBeInTheDOM() +expect(element).not.toBeInTheDOM(document.body) +expect(element).not.toBeInTheDocument() +expect(element).not.toBeVisible() +expect(element).not.toBeEmpty() +expect(element).not.toBeEmptyDOMElement() +expect(element).not.toBeDisabled() +expect(element).not.toBeEnabled() +expect(element).not.toBeInvalid() +expect(element).not.toBeRequired() +expect(element).not.toBeValid() +expect(element).not.toContainElement(document.body) +expect(element).not.toContainElement(null) +expect(element).not.toContainHTML('body') +expect(element).not.toHaveAttribute('attr') +expect(element).not.toHaveAttribute('attr', true) +expect(element).not.toHaveAttribute('attr', 'yes') +expect(element).not.toHaveClass() +expect(element).not.toHaveClass('cls1') +expect(element).not.toHaveClass('cls1', 'cls2', 'cls3', 'cls4') +expect(element).not.toHaveClass('cls1', {exact: true}) +expect(element).not.toHaveDisplayValue('str') +expect(element).not.toHaveDisplayValue(['str1', 'str2']) +expect(element).not.toHaveDisplayValue(/str/) +expect(element).not.toHaveDisplayValue([/str1/, 'str2']) +expect(element).not.toHaveFocus() +expect(element).not.toHaveFormValues({foo: 'bar', baz: 1}) +expect(element).not.toHaveStyle('display: block') +expect(element).not.toHaveTextContent('Text') +expect(element).not.toHaveTextContent(/Text/) +expect(element).not.toHaveTextContent('Text', {normalizeWhitespace: true}) +expect(element).not.toHaveTextContent(/Text/, {normalizeWhitespace: true}) +expect(element).not.toHaveValue() +expect(element).not.toHaveValue('str') +expect(element).not.toHaveValue(['str1', 'str2']) +expect(element).not.toHaveValue(1) +expect(element).not.toBeChecked() +expect(element).not.toHaveDescription('some description') +expect(element).not.toHaveDescription() +expect(element).not.toHaveAccessibleDescription('some description') +expect(element).not.toHaveAccessibleDescription() +expect(element).not.toHaveAccessibleName('a label') +expect(element).not.toHaveAccessibleName() +expect(element).not.toBePartiallyChecked() +expect(element).not.toHaveErrorMessage() +expect(element).not.toHaveErrorMessage('Pikachu!') + +// @ts-expect-error The types accidentally allowed any property by falling back to "any" +expect(element).nonExistentProperty() From d2b130d543f112e0118005ea573cd4a91d6d508d Mon Sep 17 00:00:00 2001 From: John Gozde Date: Thu, 17 Aug 2023 10:58:18 -0600 Subject: [PATCH 5/6] Fix all AsymmetricMatcher interfaces --- types/jest-globals.d.ts | 5 ++++- types/jest.d.ts | 5 ++++- types/vitest.d.ts | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/types/jest-globals.d.ts b/types/jest-globals.d.ts index f7de8014..a6819079 100644 --- a/types/jest-globals.d.ts +++ b/types/jest-globals.d.ts @@ -4,5 +4,8 @@ import {type TestingLibraryMatchers} from './matchers' export {} declare module '@jest/expect' { export interface Matchers> - extends TestingLibraryMatchers {} + extends TestingLibraryMatchers< + ReturnType, + R + > {} } diff --git a/types/jest.d.ts b/types/jest.d.ts index bca4339c..1daed629 100644 --- a/types/jest.d.ts +++ b/types/jest.d.ts @@ -5,6 +5,9 @@ import {type TestingLibraryMatchers} from './matchers' declare global { namespace jest { interface Matchers - extends TestingLibraryMatchers {} + extends TestingLibraryMatchers< + ReturnType, + R + > {} } } diff --git a/types/vitest.d.ts b/types/vitest.d.ts index 1eefb412..a19295be 100644 --- a/types/vitest.d.ts +++ b/types/vitest.d.ts @@ -4,5 +4,8 @@ import {type TestingLibraryMatchers} from './matchers' export {} declare module '@vitest/expect' { interface JestAssertion - extends TestingLibraryMatchers {} + extends TestingLibraryMatchers< + ReturnType, + T + > {} } From d581e7d2f7d94fafcd605d54c129296e0d3164c8 Mon Sep 17 00:00:00 2001 From: John Gozde Date: Thu, 17 Aug 2023 11:11:12 -0600 Subject: [PATCH 6/6] Ignore type tests from eslint --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5abb86bd..c329a7d3 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,8 @@ "eslintIgnore": [ "node_modules", "coverage", - "dist" + "dist", + "types/__tests__" ], "repository": { "type": "git",