From 4b764b9f6a7b564d7f8ec0e9b0c6ba9cc875f2b8 Mon Sep 17 00:00:00 2001
From: John Gozde
Date: Sun, 13 Aug 2023 10:28:15 -0600
Subject: [PATCH 01/11] feat: local types, supporting jest, @jest/globals,
vitest (#511)
* feat!: local types, supporting jest, @jest/globals, vitest
Moves matcher types back into this package and adds support for
@jest/globals and vitest.
BREAKING CHANGE: Removes the extend-expect script. Users should use
the default import path or one of the new test platform-specific
paths to automatically extend the appropriate "expect" instance.
extend-expect was not documented in the Readme, so this change should
have minimal impact.
Users can now use the following import paths to automatically extend
"expect" for their chosen test platform:
- @testing-library/jest-dom - jest (@types/jest)
- @testing-library/jest-dom/jest-globals - @jest/globals
- @testing-library/jest-dom/vitest - vitest
For example:
import '@testing-library/jest-dom/jest-globals'
Importing from one of the above paths will augment the appropriate
matcher interface for the given test platform, assuming the import
is done in a .ts file that is included in the user's tsconfig.json.
It's also (still) possible to import the matchers directly without
side effects:
import * as matchers from '@testing-library/jest-dom/matchers'
* Update kcd-scripts
BREAKING CHANGE: Drop node < 14
---
.github/workflows/validate.yml | 2 +-
README.md | 48 +++
extend-expect.js | 2 -
jest-globals.d.ts | 1 +
jest-globals.js | 4 +
matchers.d.ts | 3 +
package.json | 57 ++-
src/extend-expect.js | 3 -
src/index.js | 4 +-
src/to-be-in-the-document.js | 2 +-
src/to-contain-element.js | 2 +-
src/to-contain-html.js | 2 +-
src/utils.js | 10 +-
tests/setup-env.js | 2 +-
tsconfig.json | 7 +
types/index.d.ts | 1 +
types/jest-globals.d.ts | 8 +
types/jest.d.ts | 10 +
types/matchers.d.ts | 666 +++++++++++++++++++++++++++++++++
types/vitest.d.ts | 8 +
vitest.d.ts | 1 +
vitest.js | 4 +
22 files changed, 824 insertions(+), 23 deletions(-)
delete mode 100644 extend-expect.js
create mode 100644 jest-globals.d.ts
create mode 100644 jest-globals.js
create mode 100644 matchers.d.ts
delete mode 100644 src/extend-expect.js
create mode 100644 tsconfig.json
create mode 100644 types/index.d.ts
create mode 100644 types/jest-globals.d.ts
create mode 100644 types/jest.d.ts
create mode 100755 types/matchers.d.ts
create mode 100644 types/vitest.d.ts
create mode 100644 vitest.d.ts
create mode 100644 vitest.js
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index e6b270ac..6a727c41 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -16,7 +16,7 @@ jobs:
if: ${{ !contains(github.head_ref, 'all-contributors') }}
strategy:
matrix:
- node: [10.14, 12, 14, 15, 16]
+ node: [14, 16, 18, 20]
runs-on: ubuntu-latest
steps:
- name: ⬇️ Checkout repo
diff --git a/README.md b/README.md
index 7c6d3c65..4f0961d9 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,10 @@ clear to read and to maintain.
- [Installation](#installation)
- [Usage](#usage)
+ - [With `@jest/globals`](#with-jestglobals)
+ - [With Vitest](#with-vitest)
- [With TypeScript](#with-typescript)
+ - [With another Jest-compatible `expect`](#with-another-jest-compatible-expect)
- [Custom matchers](#custom-matchers)
- [`toBeDisabled`](#tobedisabled)
- [`toBeEnabled`](#tobeenabled)
@@ -128,6 +131,39 @@ import '@testing-library/jest-dom'
setupFilesAfterEnv: ['/jest-setup.js']
```
+### With `@jest/globals`
+
+If you are using [`@jest/globals`][jest-globals announcement] with
+[`injectGlobals: false`][inject-globals docs], you will need to use a different
+import in your tests setup file:
+
+```javascript
+// In your own jest-setup.js (or any other name)
+import '@testing-library/jest-dom/jest-globals'
+```
+
+[jest-globals announcement]:
+ https://jestjs.io/blog/2020/05/05/jest-26#a-new-way-to-consume-jest---jestglobals
+[inject-globals docs]:
+ https://jestjs.io/docs/configuration#injectglobals-boolean
+
+### With Vitest
+
+If you are using [vitest][], this module will work as-is, but you will need to
+use a different import in your tests setup file. This file should be added to
+the [`setupFiles`][vitest setupfiles] property in your vitest config:
+
+```javascript
+// In your own vitest-setup.js (or any other name)
+import '@testing-library/jest-dom/vitest'
+
+// In vitest.config.js add (if you haven't already)
+setupFiles: ['./vitest-setup.js']
+```
+
+[vitest]: https://vitest.dev/
+[vitest setupfiles]: https://vitest.dev/config/#setupfiles
+
### With TypeScript
If you're using TypeScript, make sure your setup file is a `.ts` and not a `.js`
@@ -144,6 +180,18 @@ haven't already:
],
```
+### With another Jest-compatible `expect`
+
+If you are using a different test runner that is compatible with Jest's `expect`
+interface, it might be possible to use it with this library:
+
+```javascript
+import * as matchers from '@testing-library/jest-dom/matchers'
+import {expect} from 'my-test-runner/expect'
+
+expect.extend(matchers)
+```
+
## Custom matchers
`@testing-library/jest-dom` can work with any library or framework that returns
diff --git a/extend-expect.js b/extend-expect.js
deleted file mode 100644
index e7d19c10..00000000
--- a/extend-expect.js
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line
-require('./dist/extend-expect')
diff --git a/jest-globals.d.ts b/jest-globals.d.ts
new file mode 100644
index 00000000..6c8e0b60
--- /dev/null
+++ b/jest-globals.d.ts
@@ -0,0 +1 @@
+///
diff --git a/jest-globals.js b/jest-globals.js
new file mode 100644
index 00000000..eeaf6ac9
--- /dev/null
+++ b/jest-globals.js
@@ -0,0 +1,4 @@
+const globals = require('@jest/globals')
+const extensions = require('./dist/matchers')
+
+globals.expect.extend(extensions)
diff --git a/matchers.d.ts b/matchers.d.ts
new file mode 100644
index 00000000..c1ec8ce5
--- /dev/null
+++ b/matchers.d.ts
@@ -0,0 +1,3 @@
+import * as matchers from './types/matchers'
+
+export = matchers
diff --git a/package.json b/package.json
index 0304d2c1..f8346ee5 100644
--- a/package.json
+++ b/package.json
@@ -3,8 +3,9 @@
"version": "0.0.0-semantically-released",
"description": "Custom jest matchers to test the state of the DOM",
"main": "dist/index.js",
+ "types": "types/index.d.ts",
"engines": {
- "node": ">=8",
+ "node": ">=14",
"npm": ">=6",
"yarn": ">=1"
},
@@ -19,8 +20,11 @@
},
"files": [
"dist",
- "extend-expect.js",
- "matchers.js"
+ "types",
+ "*.d.ts",
+ "jest-globals.js",
+ "matchers.js",
+ "vitest.js"
],
"keywords": [
"testing",
@@ -32,7 +36,6 @@
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.9.2",
- "@types/testing-library__jest-dom": "^5.9.1",
"aria-query": "^5.0.0",
"chalk": "^3.0.0",
"@adobe/css-tools": "^4.0.1",
@@ -42,16 +45,44 @@
"redent": "^3.0.0"
},
"devDependencies": {
+ "@jest/globals": "^29.6.2",
+ "expect": "^29.6.2",
"jest-environment-jsdom-sixteen": "^1.0.3",
"jest-watch-select-projects": "^2.0.0",
"jsdom": "^16.2.1",
- "kcd-scripts": "^11.1.0",
- "pretty-format": "^25.1.0"
+ "kcd-scripts": "^14.0.0",
+ "pretty-format": "^25.1.0",
+ "vitest": "^0.34.1",
+ "typescript": "^5.1.6"
+ },
+ "peerDependencies": {
+ "@jest/globals": ">= 28",
+ "@types/jest": ">= 28",
+ "jest": ">= 28",
+ "vitest": ">= 0.32"
+ },
+ "peerDependenciesMeta": {
+ "@jest/globals": {
+ "optional": true
+ },
+ "@types/jest": {
+ "optional": true
+ },
+ "jest": {
+ "optional": true
+ },
+ "vitest": {
+ "optional": true
+ }
},
"eslintConfig": {
"extends": "./node_modules/kcd-scripts/eslint.js",
+ "parserOptions": {
+ "sourceType": "module",
+ "ecmaVersion": 2020
+ },
"rules": {
- "@babel/no-invalid-this": "off"
+ "no-invalid-this": "off"
},
"overrides": [
{
@@ -61,6 +92,18 @@
"rules": {
"max-lines-per-function": "off"
}
+ },
+ {
+ "files": [
+ "**/*.d.ts"
+ ],
+ "rules": {
+ "@typescript-eslint/no-empty-interface": "off",
+ "@typescript-eslint/no-explicit-any": "off",
+ "@typescript-eslint/no-invalid-void-type": "off",
+ "@typescript-eslint/no-unused-vars": "off",
+ "@typescript-eslint/triple-slash-reference": "off"
+ }
}
]
},
diff --git a/src/extend-expect.js b/src/extend-expect.js
deleted file mode 100644
index 3801a1d5..00000000
--- a/src/extend-expect.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import * as extensions from './matchers'
-
-expect.extend(extensions)
diff --git a/src/index.js b/src/index.js
index 8cecbe35..3801a1d5 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1 +1,3 @@
-import './extend-expect'
+import * as extensions from './matchers'
+
+expect.extend(extensions)
diff --git a/src/to-be-in-the-document.js b/src/to-be-in-the-document.js
index 8ccc451a..a7eda78e 100644
--- a/src/to-be-in-the-document.js
+++ b/src/to-be-in-the-document.js
@@ -29,7 +29,7 @@ export function toBeInTheDocument(element) {
'',
),
'',
- // eslint-disable-next-line @babel/new-cap
+ // eslint-disable-next-line new-cap
this.utils.RECEIVED_COLOR(this.isNot ? errorFound() : errorNotFound()),
].join('\n')
},
diff --git a/src/to-contain-element.js b/src/to-contain-element.js
index c94ddbf9..445a6120 100644
--- a/src/to-contain-element.js
+++ b/src/to-contain-element.js
@@ -17,7 +17,7 @@ export function toContainElement(container, element) {
'element',
),
'',
- // eslint-disable-next-line @babel/new-cap
+ // eslint-disable-next-line new-cap
this.utils.RECEIVED_COLOR(`${this.utils.stringify(
container.cloneNode(false),
)} ${
diff --git a/src/to-contain-html.js b/src/to-contain-html.js
index ccbff5f5..30158ee1 100644
--- a/src/to-contain-html.js
+++ b/src/to-contain-html.js
@@ -23,7 +23,7 @@ export function toContainHTML(container, htmlText) {
'',
),
'Expected:',
- // eslint-disable-next-line @babel/new-cap
+ // eslint-disable-next-line new-cap
` ${this.utils.EXPECTED_COLOR(htmlText)}`,
'Received:',
` ${this.utils.printReceived(container.cloneNode(true))}`,
diff --git a/src/utils.js b/src/utils.js
index cdbb1088..2b45be02 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -28,7 +28,7 @@ class GenericTypeError extends Error {
'',
),
'',
- // eslint-disable-next-line @babel/new-cap
+ // eslint-disable-next-line new-cap
`${context.utils.RECEIVED_COLOR(
'received',
)} value must ${expectedString}.`,
@@ -91,9 +91,9 @@ class InvalidCSSError extends Error {
this.message = [
received.message,
'',
- // eslint-disable-next-line @babel/new-cap
+ // eslint-disable-next-line new-cap
context.utils.RECEIVED_COLOR(`Failing css:`),
- // eslint-disable-next-line @babel/new-cap
+ // eslint-disable-next-line new-cap
context.utils.RECEIVED_COLOR(`${received.css}`),
].join('\n')
}
@@ -137,11 +137,11 @@ function getMessage(
) {
return [
`${matcher}\n`,
- // eslint-disable-next-line @babel/new-cap
+ // eslint-disable-next-line new-cap
`${expectedLabel}:\n${context.utils.EXPECTED_COLOR(
redent(display(context, expectedValue), 2),
)}`,
- // eslint-disable-next-line @babel/new-cap
+ // eslint-disable-next-line new-cap
`${receivedLabel}:\n${context.utils.RECEIVED_COLOR(
redent(display(context, receivedValue), 2),
)}`,
diff --git a/tests/setup-env.js b/tests/setup-env.js
index a9325d25..151f6e7b 100644
--- a/tests/setup-env.js
+++ b/tests/setup-env.js
@@ -1,4 +1,4 @@
import {plugins} from 'pretty-format'
-import '../src/extend-expect'
+import '../src/index'
expect.addSnapshotSerializer(plugins.ConvertAnsi)
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 00000000..9a426aba
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "compilerOptions": {
+ "strict": true,
+ "skipLibCheck": true
+ },
+ "include": ["*.d.ts", "types"]
+}
diff --git a/types/index.d.ts b/types/index.d.ts
new file mode 100644
index 00000000..cebdd1af
--- /dev/null
+++ b/types/index.d.ts
@@ -0,0 +1 @@
+///
diff --git a/types/jest-globals.d.ts b/types/jest-globals.d.ts
new file mode 100644
index 00000000..f7de8014
--- /dev/null
+++ b/types/jest-globals.d.ts
@@ -0,0 +1,8 @@
+import {type expect} from '@jest/globals'
+import {type TestingLibraryMatchers} from './matchers'
+
+export {}
+declare module '@jest/expect' {
+ export interface Matchers>
+ extends TestingLibraryMatchers {}
+}
diff --git a/types/jest.d.ts b/types/jest.d.ts
new file mode 100644
index 00000000..bca4339c
--- /dev/null
+++ b/types/jest.d.ts
@@ -0,0 +1,10 @@
+///
+
+import {type TestingLibraryMatchers} from './matchers'
+
+declare global {
+ namespace jest {
+ interface Matchers
+ extends TestingLibraryMatchers {}
+ }
+}
diff --git a/types/matchers.d.ts b/types/matchers.d.ts
new file mode 100755
index 00000000..af43570d
--- /dev/null
+++ b/types/matchers.d.ts
@@ -0,0 +1,666 @@
+declare namespace matchers {
+ interface TestingLibraryMatchers extends Record {
+ /**
+ * @deprecated
+ * since v1.9.0
+ * @description
+ * Assert whether a value is a DOM element, or not. Contrary to what its name implies, this matcher only checks
+ * that you passed to it a valid DOM element.
+ *
+ * It does not have a clear definition of what "the DOM" is. Therefore, it does not check whether that element
+ * is contained anywhere.
+ * @see
+ * [testing-library/jest-dom#toBeInTheDom](https://github.com/testing-library/jest-dom#toBeInTheDom)
+ */
+ toBeInTheDOM(container?: HTMLElement | SVGElement): R
+ /**
+ * @description
+ * Assert whether an element is present in the document or not.
+ * @example
+ *
+ *
+ * expect(queryByTestId('svg-element')).toBeInTheDocument()
+ * expect(queryByTestId('does-not-exist')).not.toBeInTheDocument()
+ * @see
+ * [testing-library/jest-dom#tobeinthedocument](https://github.com/testing-library/jest-dom#tobeinthedocument)
+ */
+ toBeInTheDocument(): R
+ /**
+ * @description
+ * This allows you to check if an element is currently visible to the user.
+ *
+ * An element is visible if **all** the following conditions are met:
+ * * it does not have its css property display set to none
+ * * it does not have its css property visibility set to either hidden or collapse
+ * * it does not have its css property opacity set to 0
+ * * its parent element is also visible (and so on up to the top of the DOM tree)
+ * * it does not have the hidden attribute
+ * * if `` it has the open attribute
+ * @example
+ *
+ * Zero Opacity
+ *
+ *
+ *
Visible Example
+ *
+ * expect(getByTestId('zero-opacity')).not.toBeVisible()
+ * expect(getByTestId('visible')).toBeVisible()
+ * @see
+ * [testing-library/jest-dom#tobevisible](https://github.com/testing-library/jest-dom#tobevisible)
+ */
+ toBeVisible(): R
+ /**
+ * @deprecated
+ * since v5.9.0
+ * @description
+ * Assert whether an element has content or not.
+ * @example
+ *
+ *
+ *
+ *
+ * expect(getByTestId('empty')).toBeEmpty()
+ * expect(getByTestId('not-empty')).not.toBeEmpty()
+ * @see
+ * [testing-library/jest-dom#tobeempty](https://github.com/testing-library/jest-dom#tobeempty)
+ */
+ toBeEmpty(): R
+ /**
+ * @description
+ * Assert whether an element has content or not.
+ * @example
+ *
+ *
+ *
+ *
+ * expect(getByTestId('empty')).toBeEmptyDOMElement()
+ * expect(getByTestId('not-empty')).not.toBeEmptyDOMElement()
+ * @see
+ * [testing-library/jest-dom#tobeemptydomelement](https://github.com/testing-library/jest-dom#tobeemptydomelement)
+ */
+ toBeEmptyDOMElement(): R
+ /**
+ * @description
+ * Allows you to check whether an element is disabled from the user's perspective.
+ *
+ * Matches if the element is a form control and the `disabled` attribute is specified on this element or the
+ * element is a descendant of a form element with a `disabled` attribute.
+ * @example
+ *
+ *
+ * expect(getByTestId('button')).toBeDisabled()
+ * @see
+ * [testing-library/jest-dom#tobedisabled](https://github.com/testing-library/jest-dom#tobedisabled)
+ */
+ toBeDisabled(): R
+ /**
+ * @description
+ * Allows you to check whether an element is not disabled from the user's perspective.
+ *
+ * Works like `not.toBeDisabled()`.
+ *
+ * Use this matcher to avoid double negation in your tests.
+ * @example
+ *
+ *
+ * expect(getByTestId('button')).toBeEnabled()
+ * @see
+ * [testing-library/jest-dom#tobeenabled](https://github.com/testing-library/jest-dom#tobeenabled)
+ */
+ toBeEnabled(): R
+ /**
+ * @description
+ * Check if a form element, or the entire `form`, is currently invalid.
+ *
+ * An `input`, `select`, `textarea`, or `form` element is invalid if it has an `aria-invalid` attribute with no
+ * value or a value of "true", or if the result of `checkValidity()` is false.
+ * @example
+ *
+ *
+ *
+ *
+ * expect(getByTestId('no-aria-invalid')).not.toBeInvalid()
+ * expect(getByTestId('invalid-form')).toBeInvalid()
+ * @see
+ * [testing-library/jest-dom#tobeinvalid](https://github.com/testing-library/jest-dom#tobeinvalid)
+ */
+ toBeInvalid(): R
+ /**
+ * @description
+ * This allows you to check if a form element is currently required.
+ *
+ * An element is required if it is having a `required` or `aria-required="true"` attribute.
+ * @example
+ *
+ *
+ *
+ * expect(getByTestId('required-input')).toBeRequired()
+ * expect(getByTestId('supported-role')).not.toBeRequired()
+ * @see
+ * [testing-library/jest-dom#toberequired](https://github.com/testing-library/jest-dom#toberequired)
+ */
+ toBeRequired(): R
+ /**
+ * @description
+ * Allows you to check if a form element is currently required.
+ *
+ * An `input`, `select`, `textarea`, or `form` element is invalid if it has an `aria-invalid` attribute with no
+ * value or a value of "false", or if the result of `checkValidity()` is true.
+ * @example
+ *
+ *
+ *
+ *
+ * expect(getByTestId('no-aria-invalid')).not.toBeValid()
+ * expect(getByTestId('invalid-form')).toBeInvalid()
+ * @see
+ * [testing-library/jest-dom#tobevalid](https://github.com/testing-library/jest-dom#tobevalid)
+ */
+ toBeValid(): R
+ /**
+ * @description
+ * Allows you to assert whether an element contains another element as a descendant or not.
+ * @example
+ *
+ *
+ *
+ *
+ * const ancestor = getByTestId('ancestor')
+ * const descendant = getByTestId('descendant')
+ * const nonExistantElement = getByTestId('does-not-exist')
+ * expect(ancestor).toContainElement(descendant)
+ * expect(descendant).not.toContainElement(ancestor)
+ * expect(ancestor).not.toContainElement(nonExistantElement)
+ * @see
+ * [testing-library/jest-dom#tocontainelement](https://github.com/testing-library/jest-dom#tocontainelement)
+ */
+ toContainElement(element: HTMLElement | SVGElement | null): R
+ /**
+ * @description
+ * Assert whether a string representing a HTML element is contained in another element.
+ * @example
+ *
+ *
+ * expect(getByTestId('parent')).toContainHTML('')
+ * @see
+ * [testing-library/jest-dom#tocontainhtml](https://github.com/testing-library/jest-dom#tocontainhtml)
+ */
+ toContainHTML(htmlText: string): R
+ /**
+ * @description
+ * Allows you to check if a given element has an attribute or not.
+ *
+ * You can also optionally check that the attribute has a specific expected value or partial match using
+ * [expect.stringContaining](https://jestjs.io/docs/en/expect.html#expectnotstringcontainingstring) or
+ * [expect.stringMatching](https://jestjs.io/docs/en/expect.html#expectstringmatchingstring-regexp).
+ * @example
+ *
+ *
+ * expect(button).toHaveAttribute('disabled')
+ * expect(button).toHaveAttribute('type', 'submit')
+ * expect(button).not.toHaveAttribute('type', 'button')
+ * @see
+ * [testing-library/jest-dom#tohaveattribute](https://github.com/testing-library/jest-dom#tohaveattribute)
+ */
+ toHaveAttribute(attr: string, value?: unknown): R
+ /**
+ * @description
+ * Check whether the given element has certain classes within its `class` attribute.
+ *
+ * You must provide at least one class, unless you are asserting that an element does not have any classes.
+ * @example
+ *
+ *
+ *
no classes
+ *
+ * const deleteButton = getByTestId('delete-button')
+ * const noClasses = getByTestId('no-classes')
+ * expect(deleteButton).toHaveClass('btn')
+ * expect(deleteButton).toHaveClass('btn-danger xs')
+ * expect(deleteButton).toHaveClass('btn xs btn-danger', {exact: true})
+ * expect(deleteButton).not.toHaveClass('btn xs btn-danger', {exact: true})
+ * expect(noClasses).not.toHaveClass()
+ * @see
+ * [testing-library/jest-dom#tohaveclass](https://github.com/testing-library/jest-dom#tohaveclass)
+ */
+ toHaveClass(...classNames: string[]): R
+ toHaveClass(classNames: string, options?: {exact: boolean}): R
+ /**
+ * @description
+ * This allows you to check whether the given form element has the specified displayed value (the one the
+ * end user will see). It accepts ,
+ *
+ *
+ *
+ * expect(getByTestId('img-alt')).toHaveAccessibleName('Test alt')
+ * expect(getByTestId('img-empty-alt')).not.toHaveAccessibleName()
+ * expect(getByTestId('svg-title')).toHaveAccessibleName('Test title')
+ * expect(getByTestId('button-img-alt')).toHaveAccessibleName()
+ * expect(getByTestId('img-paragraph')).not.toHaveAccessibleName()
+ * expect(getByTestId('svg-button')).toHaveAccessibleName()
+ * expect(getByTestId('svg-without-title')).not.toHaveAccessibleName()
+ * expect(getByTestId('input-title')).toHaveAccessibleName()
+ * @see
+ * [testing-library/jest-dom#tohaveaccessiblename](https://github.com/testing-library/jest-dom#tohaveaccessiblename)
+ */
+ toHaveAccessibleName(text?: string | RegExp | E): R
+ /**
+ * @description
+ * This allows you to check whether the given element is partially checked.
+ * It accepts an input of type checkbox and elements with a role of checkbox
+ * with a aria-checked="mixed", or input of type checkbox with indeterminate
+ * set to true
+ *
+ * @example
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * const ariaCheckboxMixed = getByTestId('aria-checkbox-mixed')
+ * const inputCheckboxChecked = getByTestId('input-checkbox-checked')
+ * const inputCheckboxUnchecked = getByTestId('input-checkbox-unchecked')
+ * const ariaCheckboxChecked = getByTestId('aria-checkbox-checked')
+ * const ariaCheckboxUnchecked = getByTestId('aria-checkbox-unchecked')
+ * const inputCheckboxIndeterminate = getByTestId('input-checkbox-indeterminate')
+ *
+ * expect(ariaCheckboxMixed).toBePartiallyChecked()
+ * expect(inputCheckboxChecked).not.toBePartiallyChecked()
+ * expect(inputCheckboxUnchecked).not.toBePartiallyChecked()
+ * expect(ariaCheckboxChecked).not.toBePartiallyChecked()
+ * expect(ariaCheckboxUnchecked).not.toBePartiallyChecked()
+ *
+ * inputCheckboxIndeterminate.indeterminate = true
+ * expect(inputCheckboxIndeterminate).toBePartiallyChecked()
+ * @see
+ * [testing-library/jest-dom#tobepartiallychecked](https://github.com/testing-library/jest-dom#tobepartiallychecked)
+ */
+ toBePartiallyChecked(): R
+ /**
+ * @deprecated
+ * since v5.17.0
+ *
+ * @description
+ * Check whether the given element has an [ARIA error message](https://www.w3.org/TR/wai-aria/#aria-errormessage) or not.
+ *
+ * Use the `aria-errormessage` attribute to reference another element that contains
+ * custom error message text. Multiple ids is **NOT** allowed. Authors MUST use
+ * `aria-invalid` in conjunction with `aria-errormessage`. Learn more from the
+ * [`aria-errormessage` spec](https://www.w3.org/TR/wai-aria/#aria-errormessage).
+ *
+ * Whitespace is normalized.
+ *
+ * When a `string` argument is passed through, it will perform a whole
+ * case-sensitive match to the error message text.
+ *
+ * To perform a case-insensitive match, you can use a `RegExp` with the `/i`
+ * modifier.
+ *
+ * To perform a partial match, you can pass a `RegExp` or use
+ * expect.stringContaining("partial string")`.
+ *
+ * @example
+ *
+ *
+ *
+ * Invalid time: the time must be between 9:00 AM and 5:00 PM"
+ *
+ *
+ *
+ * const timeInput = getByLabel('startTime')
+ *
+ * expect(timeInput).toHaveErrorMessage(
+ * 'Invalid time: the time must be between 9:00 AM and 5:00 PM',
+ * )
+ * expect(timeInput).toHaveErrorMessage(/invalid time/i) // to partially match
+ * expect(timeInput).toHaveErrorMessage(expect.stringContaining('Invalid time')) // to partially match
+ * expect(timeInput).not.toHaveErrorMessage('Pikachu!')
+ * @see
+ * [testing-library/jest-dom#tohaveerrormessage](https://github.com/testing-library/jest-dom#tohaveerrormessage)
+ */
+ toHaveErrorMessage(text?: string | RegExp | E): R
+ }
+}
+
+declare const matchers: matchers.TestingLibraryMatchers
+export = matchers
diff --git a/types/vitest.d.ts b/types/vitest.d.ts
new file mode 100644
index 00000000..1eefb412
--- /dev/null
+++ b/types/vitest.d.ts
@@ -0,0 +1,8 @@
+import {type expect} from 'vitest'
+import {type TestingLibraryMatchers} from './matchers'
+
+export {}
+declare module '@vitest/expect' {
+ interface JestAssertion
+ extends TestingLibraryMatchers {}
+}
diff --git a/vitest.d.ts b/vitest.d.ts
new file mode 100644
index 00000000..1b17a0d4
--- /dev/null
+++ b/vitest.d.ts
@@ -0,0 +1 @@
+///
diff --git a/vitest.js b/vitest.js
new file mode 100644
index 00000000..e1f318c5
--- /dev/null
+++ b/vitest.js
@@ -0,0 +1,4 @@
+import {expect} from 'vitest'
+import * as extensions from './dist/matchers'
+
+expect.extend(extensions)
From bdb34f12959578c77b18b0c0910d512768b20ab0 Mon Sep 17 00:00:00 2001
From: Michael Manzinger
Date: Fri, 18 Aug 2023 07:24:56 +0200
Subject: [PATCH 02/11] fix: matchers type is making the global expect unsafe
(#513)
* fix: matchers type is making the global expect unsafe
* Add test file for TypeScript typings
* Remove jest specifics from matchers.d.ts
* Type tests for all test environments
* Fix all AsymmetricMatcher interfaces
* Ignore type tests from eslint
---------
Co-authored-by: Michael Manzinger
Co-authored-by: John Gozde
---
package.json | 6 +-
tsconfig.json | 4 +-
.../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 ++++++++++++++++++
types/jest-globals.d.ts | 5 +-
types/jest.d.ts | 5 +-
types/matchers.d.ts | 7 +-
types/vitest.d.ts | 5 +-
15 files changed, 694 insertions(+), 8 deletions(-)
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..c329a7d3 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",
@@ -110,7 +111,8 @@
"eslintIgnore": [
"node_modules",
"coverage",
- "dist"
+ "dist",
+ "types/__tests__"
],
"repository": {
"type": "git",
diff --git a/tsconfig.json b/tsconfig.json
index 9a426aba..dec023f5 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,7 +1,9 @@
{
"compilerOptions": {
+ "noEmit": true,
"strict": true,
"skipLibCheck": true
},
- "include": ["*.d.ts", "types"]
+ "include": ["*.d.ts", "types"],
+ "exclude": ["types/__tests__"]
}
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()
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/matchers.d.ts b/types/matchers.d.ts
index af43570d..ff9b8401 100755
--- a/types/matchers.d.ts
+++ b/types/matchers.d.ts
@@ -1,5 +1,5 @@
declare namespace matchers {
- interface TestingLibraryMatchers extends Record {
+ interface TestingLibraryMatchers {
/**
* @deprecated
* since v1.9.0
@@ -662,5 +662,8 @@ declare namespace matchers {
}
}
-declare const matchers: matchers.TestingLibraryMatchers
+// 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
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 61d17bd15b7d2cecb2868a2befe563cb9d5e22cf Mon Sep 17 00:00:00 2001
From: Ian VanSchooten
Date: Tue, 22 Aug 2023 12:22:41 -0400
Subject: [PATCH 03/11] chore: Publish ESM and CJS (#519)
* Add rollup config
* Sort dependencies in package.json
* Clean output folder before build
* Use relative paths for entries
* Convert cjs to esm if needed
* Add extensions to lodash imports
To support node16 resolution
* Ignore coverage for vitest and jest-globals
---
package.json | 57 ++++++++++++++++++++++++++++++++++----
rollup.config.js | 32 +++++++++++++++++++++
src/jest-globals.js | 6 ++++
src/to-have-form-values.js | 4 +--
src/to-have-value.js | 2 +-
src/utils.js | 2 +-
src/vitest.js | 6 ++++
7 files changed, 100 insertions(+), 9 deletions(-)
create mode 100644 rollup.config.js
create mode 100644 src/jest-globals.js
create mode 100644 src/vitest.js
diff --git a/package.json b/package.json
index c329a7d3..4ef94b17 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,51 @@
"name": "@testing-library/jest-dom",
"version": "0.0.0-semantically-released",
"description": "Custom jest matchers to test the state of the DOM",
- "main": "dist/index.js",
+ "main": "dist/cjs/index.js",
+ "module": "dist/esm/index.js",
+ "exports": {
+ ".": {
+ "require": {
+ "types": "./types/index.d.ts",
+ "default": "./dist/index.js"
+ },
+ "import": {
+ "types": "./types/index.d.ts",
+ "default": "./dist/index.mjs"
+ }
+ },
+ "./jest-globals": {
+ "require": {
+ "types": "./types/jest-globals.d.ts",
+ "default": "./dist/jest-globals.js"
+ },
+ "import": {
+ "types": "./types/jest-globals.d.ts",
+ "default": "./dist/jest-globals.mjs"
+ }
+ },
+ "./matchers": {
+ "require": {
+ "types": "./types/matchers.d.ts",
+ "default": "./dist/matchers.js"
+ },
+ "import": {
+ "types": "./types/matchers.d.ts",
+ "default": "./dist/matchers.mjs"
+ }
+ },
+ "./vitest": {
+ "require": {
+ "types": "./types/vitest.d.ts",
+ "default": "./dist/vitest.js"
+ },
+ "import": {
+ "types": "./types/vitest.d.ts",
+ "default": "./dist/vitest.mjs"
+ }
+ },
+ "./package.json": "./package.json"
+ },
"types": "types/index.d.ts",
"engines": {
"node": ">=14",
@@ -10,7 +54,7 @@
"yarn": ">=1"
},
"scripts": {
- "build": "kcd-scripts build",
+ "build": "rollup -c",
"format": "kcd-scripts format",
"lint": "kcd-scripts lint",
"setup": "npm install && npm run validate -s",
@@ -36,10 +80,10 @@
"author": "Ernesto Garcia (http://gnapse.github.io)",
"license": "MIT",
"dependencies": {
+ "@adobe/css-tools": "^4.0.1",
"@babel/runtime": "^7.9.2",
"aria-query": "^5.0.0",
"chalk": "^3.0.0",
- "@adobe/css-tools": "^4.0.1",
"css.escape": "^1.5.1",
"dom-accessibility-api": "^0.5.6",
"lodash": "^4.17.15",
@@ -47,14 +91,17 @@
},
"devDependencies": {
"@jest/globals": "^29.6.2",
+ "@rollup/plugin-commonjs": "^25.0.4",
"expect": "^29.6.2",
"jest-environment-jsdom-sixteen": "^1.0.3",
"jest-watch-select-projects": "^2.0.0",
"jsdom": "^16.2.1",
"kcd-scripts": "^14.0.0",
"pretty-format": "^25.1.0",
- "vitest": "^0.34.1",
- "typescript": "^5.1.6"
+ "rollup": "^3.28.1",
+ "rollup-plugin-delete": "^2.0.0",
+ "typescript": "^5.1.6",
+ "vitest": "^0.34.1"
},
"peerDependencies": {
"@jest/globals": ">= 28",
diff --git a/rollup.config.js b/rollup.config.js
new file mode 100644
index 00000000..80afe641
--- /dev/null
+++ b/rollup.config.js
@@ -0,0 +1,32 @@
+const del = require('rollup-plugin-delete')
+const commonjs = require('@rollup/plugin-commonjs')
+
+const entries = [
+ './src/index.js',
+ './src/jest-globals.js',
+ './src/matchers.js',
+ './src/vitest.js',
+]
+
+module.exports = [
+ {
+ input: entries,
+ output: [
+ {
+ dir: 'dist',
+ entryFileNames: '[name].mjs',
+ chunkFileNames: '[name]-[hash].mjs',
+ format: 'esm',
+ },
+ {
+ dir: 'dist',
+ entryFileNames: '[name].js',
+ chunkFileNames: '[name]-[hash].js',
+ format: 'cjs',
+ },
+ ],
+ external: id =>
+ !id.startsWith('\0') && !id.startsWith('.') && !id.startsWith('/'),
+ plugins: [del({targets: 'dist/*'}), commonjs()],
+ },
+]
diff --git a/src/jest-globals.js b/src/jest-globals.js
new file mode 100644
index 00000000..e23def7d
--- /dev/null
+++ b/src/jest-globals.js
@@ -0,0 +1,6 @@
+/* istanbul ignore file */
+
+import globals from '@jest/globals'
+import * as extensions from './matchers'
+
+globals.expect.extend(extensions)
diff --git a/src/to-have-form-values.js b/src/to-have-form-values.js
index c3fddcc0..fe8c890a 100644
--- a/src/to-have-form-values.js
+++ b/src/to-have-form-values.js
@@ -1,5 +1,5 @@
-import isEqualWith from 'lodash/isEqualWith'
-import uniq from 'lodash/uniq'
+import isEqualWith from 'lodash/isEqualWith.js'
+import uniq from 'lodash/uniq.js'
import escape from 'css.escape'
import {
checkHtmlElement,
diff --git a/src/to-have-value.js b/src/to-have-value.js
index 0b24e165..da79e416 100644
--- a/src/to-have-value.js
+++ b/src/to-have-value.js
@@ -1,4 +1,4 @@
-import isEqualWith from 'lodash/isEqualWith'
+import isEqualWith from 'lodash/isEqualWith.js'
import {
checkHtmlElement,
compareArraysAsSet,
diff --git a/src/utils.js b/src/utils.js
index 2b45be02..903f24c0 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,5 +1,5 @@
import redent from 'redent'
-import isEqual from 'lodash/isEqual'
+import isEqual from 'lodash/isEqual.js'
import {parse} from '@adobe/css-tools'
class GenericTypeError extends Error {
diff --git a/src/vitest.js b/src/vitest.js
new file mode 100644
index 00000000..a6b56cef
--- /dev/null
+++ b/src/vitest.js
@@ -0,0 +1,6 @@
+/* istanbul ignore file */
+
+import {expect} from 'vitest'
+import * as extensions from './matchers'
+
+expect.extend(extensions)
From 3d834bbab9e5c43b1e94b3e0a1ca0fd13c00801e Mon Sep 17 00:00:00 2001
From: John Gozde
Date: Tue, 22 Aug 2023 22:27:11 -0600
Subject: [PATCH 04/11] feat: manually trigger release (#520)
From 853a3e51ba6757a34780e32953525b6142eadcf9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stephan=20K=C3=B6ninger?=
Date: Wed, 23 Aug 2023 17:15:22 +0200
Subject: [PATCH 05/11] fix(package.json): update main and module file paths
(#523)
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 4ef94b17..416bc476 100644
--- a/package.json
+++ b/package.json
@@ -2,8 +2,8 @@
"name": "@testing-library/jest-dom",
"version": "0.0.0-semantically-released",
"description": "Custom jest matchers to test the state of the DOM",
- "main": "dist/cjs/index.js",
- "module": "dist/esm/index.js",
+ "main": "dist/index.js",
+ "module": "dist/index.mjs",
"exports": {
".": {
"require": {
From b959a681386164bf5d64f5b2b9c8bf891301bc12 Mon Sep 17 00:00:00 2001
From: John Gozde
Date: Thu, 24 Aug 2023 02:06:42 -0600
Subject: [PATCH 06/11] fix: bump @adobe/css-tools for ESM support (#525)
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 416bc476..737e3105 100644
--- a/package.json
+++ b/package.json
@@ -80,7 +80,7 @@
"author": "Ernesto Garcia (http://gnapse.github.io)",
"license": "MIT",
"dependencies": {
- "@adobe/css-tools": "^4.0.1",
+ "@adobe/css-tools": "^4.3.0",
"@babel/runtime": "^7.9.2",
"aria-query": "^5.0.0",
"chalk": "^3.0.0",
From 5b492ace23d52b7cb7d3f91913ed0b5311905a26 Mon Sep 17 00:00:00 2001
From: John Gozde
Date: Tue, 5 Sep 2023 20:53:08 -0600
Subject: [PATCH 07/11] fix: proper @jest/globals import (#530)
---
src/jest-globals.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/jest-globals.js b/src/jest-globals.js
index e23def7d..ac36d474 100644
--- a/src/jest-globals.js
+++ b/src/jest-globals.js
@@ -1,6 +1,6 @@
/* istanbul ignore file */
-import globals from '@jest/globals'
+import {expect} from '@jest/globals'
import * as extensions from './matchers'
-globals.expect.extend(extensions)
+expect.extend(extensions)
From 6d659995665076d78b9f874bec75545bfc56e5ab Mon Sep 17 00:00:00 2001
From: Wojciech Maj
Date: Thu, 7 Sep 2023 17:03:14 +0200
Subject: [PATCH 08/11] chore: add jest/vitest version to bug report template
(#526)
---
.github/ISSUE_TEMPLATE/Bug_Report.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/ISSUE_TEMPLATE/Bug_Report.md b/.github/ISSUE_TEMPLATE/Bug_Report.md
index 42b68d23..d6c5c0d3 100644
--- a/.github/ISSUE_TEMPLATE/Bug_Report.md
+++ b/.github/ISSUE_TEMPLATE/Bug_Report.md
@@ -20,6 +20,7 @@ tutorial to learn how: http://kcd.im/pull-request
- `@testing-library/jest-dom` version:
- `node` version:
+- `jest` (or `vitest`) version:
- `npm` (or `yarn`) version: