);
};
@@ -40,7 +42,7 @@ describe("WonderBlocksData.adapter", () => {
await waitFor(() => expect(container).toContainHTML("INTERCEPTED!"));
});
- it("should render like we expect", () => {
+ it("should render like we expect", async () => {
// Snapshot test is handy to visualize what's going on and help debug
// test failures of the other cases. The other cases assert specifics.
// Arrange
@@ -50,7 +52,9 @@ describe("WonderBlocksData.adapter", () => {
return (
diff --git a/packages/wonder-blocks-testing/src/harness/adapters/__tests__/render-state.test.tsx b/packages/wonder-blocks-testing/src/harness/adapters/__tests__/render-state.test.tsx
index e4f668ed7..27904e27e 100644
--- a/packages/wonder-blocks-testing/src/harness/adapters/__tests__/render-state.test.tsx
+++ b/packages/wonder-blocks-testing/src/harness/adapters/__tests__/render-state.test.tsx
@@ -3,6 +3,7 @@ import {render, screen} from "@testing-library/react";
import * as WBCore from "@khanacademy/wonder-blocks-core";
import {makeTestHarness} from "@khanacademy/wonder-blocks-testing-core";
+import {useId} from "react";
import * as RenderState from "../render-state";
jest.mock("@khanacademy/wonder-stuff-core", () => {
@@ -48,8 +49,8 @@ describe("SSR.adapter", () => {
it("should enable harnessing of components that require RenderStateRoot", () => {
// Arrange
const ComponentNeedsSsr = (props: any) => {
- const idf = WBCore.useUniqueIdWithoutMock();
- return
{idf?.get("my-id")}
;
+ const id = useId();
+ return
{id}-my-id
;
};
const testHarness = makeTestHarness(
{
@@ -65,7 +66,7 @@ describe("SSR.adapter", () => {
const underTest = () => render();
// Assert
- expect(underTest).not.toThrowError();
+ expect(underTest).not.toThrow();
});
it.each`
diff --git a/packages/wonder-blocks-theming/CHANGELOG.md b/packages/wonder-blocks-theming/CHANGELOG.md
index 6d49059c8..8346e8a58 100644
--- a/packages/wonder-blocks-theming/CHANGELOG.md
+++ b/packages/wonder-blocks-theming/CHANGELOG.md
@@ -1,5 +1,11 @@
# @khanacademy/wonder-blocks-theming
+## 3.0.0
+
+### Major Changes
+
+- e6abdd17: Upgrade to React 18
+
## 2.0.4
### Patch Changes
diff --git a/packages/wonder-blocks-theming/package.json b/packages/wonder-blocks-theming/package.json
index e1d2d6cf5..789a6a633 100644
--- a/packages/wonder-blocks-theming/package.json
+++ b/packages/wonder-blocks-theming/package.json
@@ -1,6 +1,6 @@
{
"name": "@khanacademy/wonder-blocks-theming",
- "version": "2.0.4",
+ "version": "3.0.0",
"publishConfig": {
"access": "public"
},
@@ -14,11 +14,11 @@
"dependencies": {},
"peerDependencies": {
"aphrodite": "^1.2.5",
- "react": "16.14.0",
- "react-dom": "16.14.0"
+ "react": "18.2.0",
+ "react-dom": "18.2.0"
},
"devDependencies": {
- "@khanacademy/wb-dev-build-settings": "^1.0.1"
+ "@khanacademy/wb-dev-build-settings": "^2.0.0"
},
"author": "",
"license": "MIT"
diff --git a/packages/wonder-blocks-theming/src/hooks/__tests__/use-scoped-theme.test.tsx b/packages/wonder-blocks-theming/src/hooks/__tests__/use-scoped-theme.test.tsx
index ce819eaeb..d738e4fe3 100644
--- a/packages/wonder-blocks-theming/src/hooks/__tests__/use-scoped-theme.test.tsx
+++ b/packages/wonder-blocks-theming/src/hooks/__tests__/use-scoped-theme.test.tsx
@@ -1,5 +1,5 @@
import * as React from "react";
-import {renderHook} from "@testing-library/react-hooks";
+import {renderHook} from "@testing-library/react";
import {
createThemeContext,
diff --git a/packages/wonder-blocks-theming/src/hooks/__tests__/use-styles.test.ts b/packages/wonder-blocks-theming/src/hooks/__tests__/use-styles.test.ts
index 05081c6bc..8efe3f7e0 100644
--- a/packages/wonder-blocks-theming/src/hooks/__tests__/use-styles.test.ts
+++ b/packages/wonder-blocks-theming/src/hooks/__tests__/use-styles.test.ts
@@ -1,4 +1,4 @@
-import {renderHook} from "@testing-library/react-hooks";
+import {renderHook} from "@testing-library/react";
import {StyleSheet} from "aphrodite";
import {ThemedStylesFn} from "../../types";
diff --git a/packages/wonder-blocks-timing/CHANGELOG.md b/packages/wonder-blocks-timing/CHANGELOG.md
index aa82f84df..fcc600725 100644
--- a/packages/wonder-blocks-timing/CHANGELOG.md
+++ b/packages/wonder-blocks-timing/CHANGELOG.md
@@ -1,5 +1,11 @@
# @khanacademy/wonder-blocks-timing
+## 6.0.0
+
+### Major Changes
+
+- e6abdd17: Upgrade to React 18
+
## 5.0.2
### Patch Changes
diff --git a/packages/wonder-blocks-timing/package.json b/packages/wonder-blocks-timing/package.json
index 2c7977bd8..843b92df4 100644
--- a/packages/wonder-blocks-timing/package.json
+++ b/packages/wonder-blocks-timing/package.json
@@ -1,7 +1,7 @@
{
"name": "@khanacademy/wonder-blocks-timing",
"private": false,
- "version": "5.0.2",
+ "version": "6.0.0",
"design": "v1",
"publishConfig": {
"access": "public"
@@ -14,10 +14,11 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"peerDependencies": {
- "react": "16.14.0"
+ "react": "18.2.0"
},
"devDependencies": {
- "@khanacademy/wb-dev-build-settings": "^1.0.1"
+ "@khanacademy/wb-dev-build-settings": "^2.0.0",
+ "@khanacademy/wonder-blocks-testing-core": "^2.0.0"
},
"author": "",
"license": "MIT"
diff --git a/packages/wonder-blocks-timing/src/hooks/__tests__/use-interval.test.ts b/packages/wonder-blocks-timing/src/hooks/__tests__/use-interval.test.ts
index e399bfc8e..036976cc2 100644
--- a/packages/wonder-blocks-timing/src/hooks/__tests__/use-interval.test.ts
+++ b/packages/wonder-blocks-timing/src/hooks/__tests__/use-interval.test.ts
@@ -1,4 +1,5 @@
-import {renderHook, act} from "@testing-library/react-hooks";
+import {renderHook, act} from "@testing-library/react";
+import {hookHarness} from "@khanacademy/wonder-blocks-testing-core";
import {SchedulePolicy, ClearPolicy, ActionPolicy} from "../../util/policies";
import {useInterval} from "../use-interval";
@@ -14,22 +15,30 @@ describe("useInterval", () => {
it("throws if the action is not a function", () => {
// Arrange
+ const captureErrorFn = jest.fn();
// Act
- const {result} = renderHook(() => useInterval(null as any, 1000));
+ renderHook(() => useInterval(null as any, 1000), {
+ wrapper: hookHarness({boundary: captureErrorFn}),
+ });
+ const result = captureErrorFn.mock.calls[0][0];
// Assert
- expect(result.error).toEqual(Error("Action must be a function"));
+ expect(result).toEqual(Error("Action must be a function"));
});
it("throws if the period is less than 1", () => {
// Arrange
+ const captureErrorFn = jest.fn();
// Act
- const {result} = renderHook(() => useInterval(() => {}, 0));
+ renderHook(() => useInterval(() => {}, 0), {
+ wrapper: hookHarness({boundary: captureErrorFn}),
+ });
+ const result = captureErrorFn.mock.calls[0][0];
// Assert
- expect(result.error).toEqual(Error("Interval period must be >= 1"));
+ expect(result).toEqual(Error("Interval period must be >= 1"));
});
it("sets an interval when schedule policy is SchedulePolicy.Immediately", () => {
diff --git a/packages/wonder-blocks-timing/src/hooks/__tests__/use-timeout.test.ts b/packages/wonder-blocks-timing/src/hooks/__tests__/use-timeout.test.ts
index 7de73fa08..ce2644829 100644
--- a/packages/wonder-blocks-timing/src/hooks/__tests__/use-timeout.test.ts
+++ b/packages/wonder-blocks-timing/src/hooks/__tests__/use-timeout.test.ts
@@ -1,4 +1,5 @@
-import {renderHook, act} from "@testing-library/react-hooks";
+import {renderHook, act} from "@testing-library/react";
+import {hookHarness} from "@khanacademy/wonder-blocks-testing-core";
import {SchedulePolicy, ClearPolicy, ActionPolicy} from "../../util/policies";
import {useTimeout} from "../use-timeout";
@@ -14,22 +15,30 @@ describe("useTimeout", () => {
it("throws if the action is not a function", () => {
// Arrange
+ const captureErrorFn = jest.fn();
// Act
- const {result} = renderHook(() => useTimeout(null as any, 1000));
+ renderHook(() => useTimeout(null as any, 1000), {
+ wrapper: hookHarness({boundary: captureErrorFn}),
+ });
+ const result = captureErrorFn.mock.calls[0][0];
// Assert
- expect(result.error).toEqual(Error("Action must be a function"));
+ expect(result).toEqual(Error("Action must be a function"));
});
it("throws if the period is less than 0", () => {
// Arrange
+ const captureErrorFn = jest.fn();
// Act
- const {result} = renderHook(() => useTimeout(() => {}, -1));
+ renderHook(() => useTimeout(() => {}, -1), {
+ wrapper: hookHarness({boundary: captureErrorFn}),
+ });
+ const result = captureErrorFn.mock.calls[0][0];
// Assert
- expect(result.error).toEqual(Error("Timeout period must be >= 0"));
+ expect(result).toEqual(Error("Timeout period must be >= 0"));
});
it("should return an ITimeout", () => {
diff --git a/packages/wonder-blocks-timing/tsconfig-build.json b/packages/wonder-blocks-timing/tsconfig-build.json
index f24528d77..669f5d5f0 100644
--- a/packages/wonder-blocks-timing/tsconfig-build.json
+++ b/packages/wonder-blocks-timing/tsconfig-build.json
@@ -5,5 +5,7 @@
"outDir": "./dist",
"rootDir": "src"
},
- "references": []
+ "references": [
+ {"path": "../wonder-blocks-testing-core/tsconfig-build.json"},
+ ]
}
\ No newline at end of file
diff --git a/packages/wonder-blocks-tokens/CHANGELOG.md b/packages/wonder-blocks-tokens/CHANGELOG.md
index 5f2021fce..dc7b7fbeb 100644
--- a/packages/wonder-blocks-tokens/CHANGELOG.md
+++ b/packages/wonder-blocks-tokens/CHANGELOG.md
@@ -1,5 +1,11 @@
# @khanacademy/wonder-blocks-tokens
+## 3.0.0
+
+### Major Changes
+
+- e6abdd17: Upgrade to React 18
+
## 2.1.0
### Minor Changes
diff --git a/packages/wonder-blocks-tokens/package.json b/packages/wonder-blocks-tokens/package.json
index 57ac02463..d47b26100 100644
--- a/packages/wonder-blocks-tokens/package.json
+++ b/packages/wonder-blocks-tokens/package.json
@@ -1,6 +1,6 @@
{
"name": "@khanacademy/wonder-blocks-tokens",
- "version": "2.1.0",
+ "version": "3.0.0",
"description": "Core primitive design tokens for Web Wonder Blocks",
"main": "dist/index.js",
"module": "dist/es/index.js",
@@ -15,6 +15,6 @@
},
"dependencies": {},
"devDependencies": {
- "@khanacademy/wb-dev-build-settings": "^1.0.1"
+ "@khanacademy/wb-dev-build-settings": "^2.0.0"
}
}
\ No newline at end of file
diff --git a/packages/wonder-blocks-toolbar/CHANGELOG.md b/packages/wonder-blocks-toolbar/CHANGELOG.md
index 4d179064a..0b7bf24d4 100644
--- a/packages/wonder-blocks-toolbar/CHANGELOG.md
+++ b/packages/wonder-blocks-toolbar/CHANGELOG.md
@@ -1,5 +1,26 @@
# @khanacademy/wonder-blocks-toolbar
+## 5.0.1
+
+### Patch Changes
+
+- Updated dependencies [f4abd572]
+ - @khanacademy/wonder-blocks-core@9.0.0
+ - @khanacademy/wonder-blocks-typography@3.0.1
+
+## 5.0.0
+
+### Major Changes
+
+- e6abdd17: Upgrade to React 18
+
+### Patch Changes
+
+- Updated dependencies [e6abdd17]
+ - @khanacademy/wonder-blocks-core@8.0.0
+ - @khanacademy/wonder-blocks-tokens@3.0.0
+ - @khanacademy/wonder-blocks-typography@3.0.0
+
## 4.0.0
### Major Changes
diff --git a/packages/wonder-blocks-toolbar/package.json b/packages/wonder-blocks-toolbar/package.json
index 9416eb39f..172a7b84a 100644
--- a/packages/wonder-blocks-toolbar/package.json
+++ b/packages/wonder-blocks-toolbar/package.json
@@ -1,6 +1,6 @@
{
"name": "@khanacademy/wonder-blocks-toolbar",
- "version": "4.0.0",
+ "version": "5.0.1",
"design": "v1",
"publishConfig": {
"access": "public"
@@ -16,15 +16,15 @@
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.6",
- "@khanacademy/wonder-blocks-core": "^7.0.1",
- "@khanacademy/wonder-blocks-tokens": "^2.1.0",
- "@khanacademy/wonder-blocks-typography": "^2.1.16"
+ "@khanacademy/wonder-blocks-core": "^9.0.0",
+ "@khanacademy/wonder-blocks-tokens": "^3.0.0",
+ "@khanacademy/wonder-blocks-typography": "^3.0.1"
},
"peerDependencies": {
"aphrodite": "^1.2.5",
- "react": "16.14.0"
+ "react": "18.2.0"
},
"devDependencies": {
- "@khanacademy/wb-dev-build-settings": "^1.0.1"
+ "@khanacademy/wb-dev-build-settings": "^2.0.0"
}
}
\ No newline at end of file
diff --git a/packages/wonder-blocks-tooltip/CHANGELOG.md b/packages/wonder-blocks-tooltip/CHANGELOG.md
index e4a04ef11..635fb4100 100644
--- a/packages/wonder-blocks-tooltip/CHANGELOG.md
+++ b/packages/wonder-blocks-tooltip/CHANGELOG.md
@@ -1,5 +1,38 @@
# @khanacademy/wonder-blocks-tooltip
+## 3.0.1
+
+### Patch Changes
+
+- Updated dependencies [f4abd572]
+- Updated dependencies [0955be7e]
+ - @khanacademy/wonder-blocks-core@9.0.0
+ - @khanacademy/wonder-blocks-modal@6.0.1
+ - @khanacademy/wonder-blocks-layout@3.0.1
+ - @khanacademy/wonder-blocks-typography@3.0.1
+
+## 3.0.0
+
+### Major Changes
+
+- e6abdd17: Upgrade to React 18
+
+### Patch Changes
+
+- Updated dependencies [e6abdd17]
+ - @khanacademy/wonder-blocks-core@8.0.0
+ - @khanacademy/wonder-blocks-layout@3.0.0
+ - @khanacademy/wonder-blocks-modal@6.0.0
+ - @khanacademy/wonder-blocks-tokens@3.0.0
+ - @khanacademy/wonder-blocks-typography@3.0.0
+
+## 2.5.5
+
+### Patch Changes
+
+- Updated dependencies [b5cad0b1]
+ - @khanacademy/wonder-blocks-modal@5.1.17
+
## 2.5.4
### Patch Changes
diff --git a/packages/wonder-blocks-tooltip/package.json b/packages/wonder-blocks-tooltip/package.json
index 20b1cfade..f9f7114b4 100644
--- a/packages/wonder-blocks-tooltip/package.json
+++ b/packages/wonder-blocks-tooltip/package.json
@@ -1,6 +1,6 @@
{
"name": "@khanacademy/wonder-blocks-tooltip",
- "version": "2.5.4",
+ "version": "3.0.1",
"design": "v1",
"publishConfig": {
"access": "public"
@@ -16,20 +16,20 @@
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.6",
- "@khanacademy/wonder-blocks-core": "^7.0.1",
- "@khanacademy/wonder-blocks-layout": "^2.2.2",
- "@khanacademy/wonder-blocks-modal": "^5.1.16",
- "@khanacademy/wonder-blocks-tokens": "^2.1.0",
- "@khanacademy/wonder-blocks-typography": "^2.1.16"
+ "@khanacademy/wonder-blocks-core": "^9.0.0",
+ "@khanacademy/wonder-blocks-layout": "^3.0.1",
+ "@khanacademy/wonder-blocks-modal": "^6.0.1",
+ "@khanacademy/wonder-blocks-tokens": "^3.0.0",
+ "@khanacademy/wonder-blocks-typography": "^3.0.1"
},
"peerDependencies": {
"@popperjs/core": "^2.10.1",
"aphrodite": "^1.2.5",
- "react": "16.14.0",
- "react-dom": "16.14.0",
+ "react": "18.2.0",
+ "react-dom": "18.2.0",
"react-popper": "^2.0.0"
},
"devDependencies": {
- "@khanacademy/wb-dev-build-settings": "^1.0.1"
+ "@khanacademy/wb-dev-build-settings": "^2.0.0"
}
}
\ No newline at end of file
diff --git a/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip-anchor.test.tsx b/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip-anchor.test.tsx
index 6780ebefa..3d752700f 100644
--- a/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip-anchor.test.tsx
+++ b/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip-anchor.test.tsx
@@ -14,16 +14,8 @@ jest.mock("../../util/active-tracker");
describe("TooltipAnchor", () => {
beforeEach(async () => {
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'mockReset' does not exist on type '{ (type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | ... 1 more ... | undefined): void; }'.
- if (typeof document.addEventListener.mockReset === "function") {
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'mockRestore' does not exist on type '{ (type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | ... 1 more ... | undefined): void; }'.
- document.addEventListener.mockRestore();
- }
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'mockReset' does not exist on type '{ (type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | ... 1 more ... | undefined): void; }'.
- if (typeof document.removeEventListener.mockReset === "function") {
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'mockRestore' does not exist on type '{ (type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | ... 1 more ... | undefined): void; }'.
- document.removeEventListener.mockRestore();
- }
+ jest.spyOn(document, "addEventListener").mockRestore();
+ jest.spyOn(document, "removeEventListener").mockRestore();
jest.clearAllTimers();
jest.useFakeTimers();
@@ -322,7 +314,7 @@ describe("TooltipAnchor", () => {
test("active state was not stolen, active is set to false with delay", async () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
const timeoutSpy = jest.spyOn(global, "setTimeout");
let activeState = false;
@@ -363,7 +355,7 @@ describe("TooltipAnchor", () => {
test("active state was not stolen, gives up active state", async () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
const timeoutSpy = jest.spyOn(global, "setTimeout");
const {default: ActiveTracker} = await import(
@@ -409,7 +401,7 @@ describe("TooltipAnchor", () => {
test("active state was stolen, active is set to false immediately", async () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
const timeoutSpy = jest.spyOn(global, "setTimeout");
let activeState = false;
@@ -606,7 +598,7 @@ describe("TooltipAnchor", () => {
test("active state was not stolen, active is set to false with delay", async () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
const timeoutSpy = jest.spyOn(global, "setTimeout");
let activeState = false;
@@ -646,7 +638,7 @@ describe("TooltipAnchor", () => {
test("active state was not stolen, gives up active state", async () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
const timeoutSpy = jest.spyOn(global, "setTimeout");
const {default: ActiveTracker} = await import(
@@ -691,7 +683,7 @@ describe("TooltipAnchor", () => {
test("active state was stolen, active is set to false immediately", async () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
const timeoutSpy = jest.spyOn(global, "setTimeout");
let activeState = false;
diff --git a/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip.integration.test.tsx b/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip.integration.test.tsx
index f18885b74..ad85a84a2 100644
--- a/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip.integration.test.tsx
+++ b/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip.integration.test.tsx
@@ -1,6 +1,6 @@
import * as React from "react";
-import {render, screen, fireEvent} from "@testing-library/react";
+import {render, screen, fireEvent, waitFor} from "@testing-library/react";
import {userEvent} from "@testing-library/user-event";
import Tooltip from "../tooltip";
@@ -55,7 +55,7 @@ describe("tooltip integration tests", () => {
it("should close TooltipBubble on mouseleave on TooltipBubble", async () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
render(an anchor);
@@ -82,7 +82,9 @@ describe("tooltip integration tests", () => {
jest.runAllTimers();
// Assert
- expect(screen.queryByRole("tooltip")).not.toBeInTheDocument();
+ await waitFor(() =>
+ expect(screen.queryByRole("tooltip")).not.toBeInTheDocument(),
+ );
});
it("should have an opened tooltip when subsequent mouseenter, mouseleave, and mouseenter events occur", async () => {
@@ -92,7 +94,7 @@ describe("tooltip integration tests", () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
render(an anchor);
@@ -104,7 +106,7 @@ describe("tooltip integration tests", () => {
await jest.runAllTimers();
// We add `hidden: true` because the tooltip is initially hidden while
// it is re-positioned
- expect(screen.getByRole("tooltip", {hidden: true})).toBeInTheDocument();
+ await screen.findByRole("tooltip", {hidden: true});
// Trigger mouseleave and mouseenter event and run timers only after
// both have been triggered. This simulates the mouseenter event being
// triggered before the tooltip is closed from the mouseleave event
diff --git a/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip.test.tsx b/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip.test.tsx
index 5ffa92c0d..f4640454c 100644
--- a/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip.test.tsx
+++ b/packages/wonder-blocks-tooltip/src/components/__tests__/tooltip.test.tsx
@@ -1,29 +1,12 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
-import {render, screen} from "@testing-library/react";
+import {act, render, screen} from "@testing-library/react";
import {userEvent} from "@testing-library/user-event";
import {View} from "@khanacademy/wonder-blocks-core";
import Tooltip from "../tooltip";
-const mockIDENTIFIER = "mock-identifier";
-jest.mock("@khanacademy/wonder-blocks-core", () => {
- const Core = jest.requireActual("@khanacademy/wonder-blocks-core");
- // We want all of Core to be the regular thing except for UniqueIDProvider
- return {
- ...Core,
- UniqueIDProvider: (props: any) =>
- // NOTE(kevinb): We aren't actually access the DOM here. The logic
- // used by this lint rule to determine DOM access could be more
- // precise.
- // eslint-disable-next-line testing-library/no-node-access
- props.children({
- get: () => mockIDENTIFIER,
- }),
- };
-});
-
describe("Tooltip", () => {
beforeEach(() => {
jest.clearAllMocks();
@@ -52,7 +35,7 @@ describe("Tooltip", () => {
it("should show the tooltip on hover", async () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
render(
@@ -62,21 +45,19 @@ describe("Tooltip", () => {
,
);
+ // Act
const node = await screen.findByText("Anchor");
await ue.hover(node);
- jest.runOnlyPendingTimers();
-
- // Act
- const tooltip = await screen.findByRole("tooltip");
+ await act(() => jest.runOnlyPendingTimersAsync());
// Assert
- expect(tooltip).toBeInTheDocument();
+ await screen.findByRole("tooltip");
});
it("should hide the tooltip on unhover", async () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
render(
@@ -88,9 +69,9 @@ describe("Tooltip", () => {
const node = await screen.findByText("Anchor");
await ue.hover(node);
- jest.runOnlyPendingTimers();
+ await act(() => jest.runOnlyPendingTimersAsync());
await ue.unhover(node);
- jest.runOnlyPendingTimers();
+ await act(() => jest.runOnlyPendingTimersAsync());
// Act
const tooltip = screen.queryByRole("tooltip");
@@ -102,7 +83,7 @@ describe("Tooltip", () => {
it("should work when the anchor is text", async () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
render(
@@ -114,7 +95,7 @@ describe("Tooltip", () => {
const node = await screen.findByText("Anchor");
await ue.hover(node);
- jest.runOnlyPendingTimers();
+ await act(() => jest.runOnlyPendingTimersAsync());
// Act
const tooltip = await screen.findByRole("tooltip");
@@ -152,7 +133,7 @@ describe("Tooltip", () => {
});
describe("accessibility", () => {
- test("no id, sets identifier of TooltipBubble with UniqueIDProvider", async () => {
+ test("no id, sets identifier of TooltipBubble", async () => {
// Arrange
const ue = userEvent.setup({
advanceTimers: jest.advanceTimersByTime,
@@ -164,22 +145,21 @@ describe("Tooltip", () => {
,
);
- const node = await screen.findByText("Anchor");
- await ue.hover(node);
- jest.runOnlyPendingTimers();
// Act
- // eslint-disable-next-line testing-library/no-node-access
- const result = document.querySelector("#" + mockIDENTIFIER);
+ const node = await screen.findByText("Anchor");
+ await ue.hover(node);
+ await act(() => jest.runOnlyPendingTimersAsync());
+ const result = await screen.findByRole("tooltip");
// Assert
- expect(result).toBeInTheDocument();
+ expect(result).toHaveAttribute("id", expect.any(String));
});
- test("custom id, sets identifier of TooltipBubble", async () => {
+ it("custom id, sets identifier of TooltipBubble", async () => {
// Arrange
const ue = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
+ advanceTimers: jest.advanceTimersByTimeAsync,
});
render(
@@ -188,16 +168,15 @@ describe("Tooltip", () => {
,
);
- const node = await screen.findByText("Anchor");
- await ue.hover(node);
- jest.runOnlyPendingTimers();
// Act
- // eslint-disable-next-line testing-library/no-node-access
- const result = document.querySelector("#tooltip-1");
+ const node = await screen.findByText("Anchor");
+ await ue.hover(node);
+ await act(() => jest.runOnlyPendingTimersAsync());
+ const result = await screen.findByRole("tooltip");
// Assert
- expect(result).toBeInTheDocument();
+ expect(result).toHaveAttribute("id", "tooltip-1");
});
describe("text-only anchor", () => {
@@ -217,7 +196,7 @@ describe("Tooltip", () => {
expect(result.innerHTML).toBe("Anchor");
});
- test("id provided, does not attach aria-describedby", async () => {
+ test("id provided, attaches aria-describedby", async () => {
// Arrange
render(
@@ -226,13 +205,15 @@ describe("Tooltip", () => {
,
);
- const node = await screen.findByText("Anchor");
// Act
- const result = node.getAttribute("aria-describedby");
+ const result = await screen.findByText("Anchor");
// Assert
- expect(result).toBeNull();
+ expect(result).toHaveAttribute(
+ "aria-describedby",
+ "tooltip-2-anchor-aria-content",
+ );
});
test("no id provided, attaches aria-describedby", async () => {
@@ -249,7 +230,8 @@ describe("Tooltip", () => {
// Assert
expect(node).toHaveAttribute(
"aria-describedby",
- mockIDENTIFIER,
+ // We don't know what the generated portion would be,
+ expect.stringMatching(/.*-anchor-aria-content/),
);
});
});
@@ -283,13 +265,8 @@ describe("Tooltip", () => {
expect(result.children[0].innerHTML).toBe("Anchor");
});
- test("id provided, does not attach aria-describedby", async () => {
+ test("id provided, attaches aria-describedby", async () => {
// Arrange
- const anchor = (
-
- Anchor
-
- );
const ref = await new Promise((resolve: any) => {
render(
@@ -298,19 +275,23 @@ describe("Tooltip", () => {
ref={resolve}
content="Content"
>
- {anchor}
+
+ Anchor
+ ,
);
});
- // @ts-expect-error [FEI-5019] - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'ReactInstance | null | undefined'.
- const node = ReactDOM.findDOMNode(ref) as any;
// Act
- const result = node.getAttribute("aria-describedby");
+ // @ts-expect-error [FEI-5019] - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'ReactInstance | null | undefined'.
+ const result = ReactDOM.findDOMNode(ref) as any;
// Assert
- expect(result).toBeNull();
+ expect(result).toHaveAttribute(
+ "aria-describedby",
+ "tooltip-3-anchor-aria-content",
+ );
});
test("no id provided, attaches aria-describedby", async () => {
@@ -329,14 +310,16 @@ describe("Tooltip", () => {
,
);
});
- // @ts-expect-error [FEI-5019] - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'ReactInstance | null | undefined'.
- const node = ReactDOM.findDOMNode(ref) as any;
// Act
- const result = node.getAttribute("aria-describedby");
+ // @ts-expect-error [FEI-5019] - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'ReactInstance | null | undefined'.
+ const result = ReactDOM.findDOMNode(ref) as any;
// Assert
- expect(result).toBe(mockIDENTIFIER);
+ expect(result).toHaveAttribute(
+ "aria-describedby",
+ expect.stringMatching(/.*-anchor-aria-content/),
+ );
});
});
});
@@ -344,6 +327,8 @@ describe("Tooltip", () => {
describe("Controlled", () => {
test("can be opened programmatically", async () => {
// Arrange
+
+ // Act
render(
@@ -351,16 +336,16 @@ describe("Tooltip", () => {
,
);
-
- // Act
- jest.runOnlyPendingTimers();
+ await act(() => jest.runOnlyPendingTimersAsync());
// Assert
- expect(await screen.findByText("Content")).toBeInTheDocument();
+ await screen.findByText("Content");
});
test("can be closed programmatically", async () => {
// Arrange
+
+ // Act
render(
@@ -368,9 +353,7 @@ describe("Tooltip", () => {
,
);
-
- // Act
- jest.runOnlyPendingTimers();
+ await act(() => jest.runOnlyPendingTimersAsync());
// Assert
expect(screen.queryByText("Content")).not.toBeInTheDocument();
diff --git a/packages/wonder-blocks-tooltip/src/components/tooltip-anchor.tsx b/packages/wonder-blocks-tooltip/src/components/tooltip-anchor.tsx
index 47a598341..74bfedcd8 100644
--- a/packages/wonder-blocks-tooltip/src/components/tooltip-anchor.tsx
+++ b/packages/wonder-blocks-tooltip/src/components/tooltip-anchor.tsx
@@ -6,7 +6,6 @@ import * as React from "react";
import * as ReactDOM from "react-dom";
import {Text as WBText} from "@khanacademy/wonder-blocks-core";
-import type {IIdentifierFactory} from "@khanacademy/wonder-blocks-core";
import ActiveTracker from "../util/active-tracker";
import {
@@ -54,9 +53,9 @@ type Props = {
*/
onActiveChanged: (active: boolean) => unknown;
/**
- * Optional unique id factory.
+ * Optional unique id.
*/
- ids?: IIdentifierFactory;
+ id?: string | undefined;
};
type DefaultProps = {
@@ -320,11 +319,11 @@ export default class TooltipAnchor
);
}
- _renderAccessibleChildren(ids: IIdentifierFactory): React.ReactNode {
+ _renderAccessibleChildren(uniqueId: string): React.ReactNode {
const anchorableChildren = this._renderAnchorableChildren();
return React.cloneElement(anchorableChildren, {
- "aria-describedby": ids.get(TooltipAnchor.ariaContentId),
+ "aria-describedby": `${uniqueId}-${TooltipAnchor.ariaContentId}`,
});
}
@@ -333,8 +332,8 @@ export default class TooltipAnchor
// If the content is just a string, we wrap it in a Text element
// so as not to affect styling or layout but still have an element
// to anchor to.
- if (this.props.ids) {
- return this._renderAccessibleChildren(this.props.ids);
+ if (this.props.id) {
+ return this._renderAccessibleChildren(this.props.id);
}
return this._renderAnchorableChildren();
}
diff --git a/packages/wonder-blocks-tooltip/src/components/tooltip.tsx b/packages/wonder-blocks-tooltip/src/components/tooltip.tsx
index 4aba3a9c9..3e3583ebd 100644
--- a/packages/wonder-blocks-tooltip/src/components/tooltip.tsx
+++ b/packages/wonder-blocks-tooltip/src/components/tooltip.tsx
@@ -20,10 +20,7 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
-import {
- UniqueIDProvider,
- IIdentifierFactory,
-} from "@khanacademy/wonder-blocks-core";
+import {Id} from "@khanacademy/wonder-blocks-core";
import {maybeGetPortalMountedModalHostElement} from "@khanacademy/wonder-blocks-modal";
import type {Typography} from "@khanacademy/wonder-blocks-typography";
import type {AriaProps} from "@khanacademy/wonder-blocks-core";
@@ -192,7 +189,6 @@ export default class Tooltip extends React.Component {
active: false,
activeBubble: false,
};
- static ariaContentId = "aria-content";
_updateAnchorElement(ref?: Element | null) {
if (ref && ref !== this.state.anchorElement) {
@@ -221,14 +217,8 @@ export default class Tooltip extends React.Component {
}
}
- _renderPopper(ids?: IIdentifierFactory): React.ReactNode {
- const {id, backgroundColor} = this.props;
- const bubbleId = ids ? ids.get(Tooltip.ariaContentId) : id;
- if (!bubbleId) {
- throw new Error("Did not get an identifier factory nor a id prop");
- }
-
- const {placement} = this.props;
+ _renderPopper(bubbleId: string): React.ReactNode {
+ const {backgroundColor, placement} = this.props;
return (
{
);
}
- _renderTooltipAnchor(ids?: IIdentifierFactory): React.ReactNode {
+ _renderTooltipAnchor(uniqueId: string): React.ReactNode {
const {autoUpdate, children, forceAnchorFocusivity} = this.props;
const {active, activeBubble} = this.state;
@@ -286,28 +276,23 @@ export default class Tooltip extends React.Component {
forceAnchorFocusivity={forceAnchorFocusivity}
anchorRef={(r) => this._updateAnchorElement(r)}
onActiveChanged={(active) => this.setState({active})}
- ids={ids}
+ id={`${uniqueId}-anchor`}
>
{children}
{shouldBeVisible &&
- ReactDOM.createPortal(this._renderPopper(ids), popperHost)}
+ ReactDOM.createPortal(
+ this._renderPopper(uniqueId),
+ popperHost,
+ )}
);
}
render(): React.ReactNode {
const {id} = this.props;
- if (id) {
- // Let's bypass the extra weight of an id provider since we don't
- // need it.
- return this._renderTooltipAnchor();
- } else {
- return (
-
- {(ids) => this._renderTooltipAnchor(ids)}
-
- );
- }
+ return (
+ {(uniqueId) => this._renderTooltipAnchor(uniqueId)}
+ );
}
}
diff --git a/packages/wonder-blocks-typography/CHANGELOG.md b/packages/wonder-blocks-typography/CHANGELOG.md
index eb53f370b..604800142 100644
--- a/packages/wonder-blocks-typography/CHANGELOG.md
+++ b/packages/wonder-blocks-typography/CHANGELOG.md
@@ -1,5 +1,23 @@
# @khanacademy/wonder-blocks-typography
+## 3.0.1
+
+### Patch Changes
+
+- Updated dependencies [f4abd572]
+ - @khanacademy/wonder-blocks-core@9.0.0
+
+## 3.0.0
+
+### Major Changes
+
+- e6abdd17: Upgrade to React 18
+
+### Patch Changes
+
+- Updated dependencies [e6abdd17]
+ - @khanacademy/wonder-blocks-core@8.0.0
+
## 2.1.16
### Patch Changes
diff --git a/packages/wonder-blocks-typography/package.json b/packages/wonder-blocks-typography/package.json
index 556fe99a6..de6f6b88c 100644
--- a/packages/wonder-blocks-typography/package.json
+++ b/packages/wonder-blocks-typography/package.json
@@ -1,6 +1,6 @@
{
"name": "@khanacademy/wonder-blocks-typography",
- "version": "2.1.16",
+ "version": "3.0.1",
"design": "v2",
"publishConfig": {
"access": "public"
@@ -16,13 +16,13 @@
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.6",
- "@khanacademy/wonder-blocks-core": "^7.0.1"
+ "@khanacademy/wonder-blocks-core": "^9.0.0"
},
"peerDependencies": {
"aphrodite": "^1.2.5",
- "react": "16.14.0"
+ "react": "18.2.0"
},
"devDependencies": {
- "@khanacademy/wb-dev-build-settings": "^1.0.1"
+ "@khanacademy/wb-dev-build-settings": "^2.0.0"
}
}
\ No newline at end of file
diff --git a/tsconfig-build.json b/tsconfig-build.json
index 50d327c25..efc145fba 100644
--- a/tsconfig-build.json
+++ b/tsconfig-build.json
@@ -17,7 +17,6 @@
{"path": "./packages/wonder-blocks-dropdown/tsconfig-build.json"},
{"path": "./packages/wonder-blocks-form/tsconfig-build.json"},
{"path": "./packages/wonder-blocks-grid/tsconfig-build.json"},
- {"path": "./packages/wonder-blocks-i18n/tsconfig-build.json"},
{"path": "./packages/wonder-blocks-icon/tsconfig-build.json"},
{"path": "./packages/wonder-blocks-icon-button/tsconfig-build.json"},
{"path": "./packages/wonder-blocks-labeled-field/tsconfig-build.json"},
diff --git a/tsconfig.json b/tsconfig.json
index 15616e625..4bf295422 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -8,6 +8,6 @@
"paths": {
"@khanacademy/*": ["./packages/*/src"]
- },
+ }
}
}
diff --git a/types/jest-extended.d.ts b/types/jest-extended.d.ts
new file mode 100644
index 000000000..06bbf1a61
--- /dev/null
+++ b/types/jest-extended.d.ts
@@ -0,0 +1,930 @@
+/* eslint-disable @typescript-eslint/no-empty-interface */
+/* eslint-disable jsdoc/valid-types */
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
+/**
+We use matchers provided by third-party packages that extend the `Matchers`
+interface within the `jest` namespace. TypeScript won't pick these up unless
+they are imported in a TypeScript file. This can be done by:
+
+1. Installing `ts-node` and making the Jest config a TS file
+(see https://www.npmjs.com/package/@testing-library/jest-dom#with-typescript
+for example) then import from there and include the jest setup file in the
+TypeScript includes.
+2. Vendoring the type doc files like we're doing here.
+
+This is a copy of the type definition file from jest-extended, amended to make
+sure the matchers extend the jest-expect interface.
+ */
+
+interface CustomMatchers extends Record {
+ /**
+ * Note: Currently unimplemented
+ * Passing assertion
+ *
+ * @param {String} message
+ */
+ pass(message: string): R;
+
+ /**
+ * Note: Currently unimplemented
+ * Failing assertion
+ *
+ * @param {String} message
+ */
+ fail(message: string): R;
+
+ /**
+ * Use .toBeEmpty when checking if a String '', Array [] or Object {} is empty.
+ */
+ toBeEmpty(): R;
+
+ /**
+ * Use .toBeOneOf when checking if a value is a member of a given Array.
+ * @param {Array.<*>} members
+ */
+ toBeOneOf(members: readonly E[]): R;
+
+ /**
+ * Use `.toBeNil` when checking a value is `null` or `undefined`.
+ */
+ toBeNil(): R;
+
+ /**
+ * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`.
+ * @param {Function} predicate
+ */
+ toSatisfy(predicate: (x: E) => boolean): R;
+
+ /**
+ * Use `.toBeArray` when checking if a value is an `Array`.
+ */
+ toBeArray(): R;
+
+ /**
+ * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x.
+ * @param {Number} x
+ */
+ toBeArrayOfSize(x: number): R;
+
+ /**
+ * Use `.toBeAfter` when checking if a date occurs after `date`.
+ * @param {Date} date
+ */
+ toBeAfter(date: Date): R;
+
+ /**
+ * Use `.toBeBefore` when checking if a date occurs before `date`.
+ * @param {Date} date
+ */
+ toBeBefore(date: Date): R;
+
+ /**
+ * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set.
+ * @param {Array.<*>} members
+ */
+ toIncludeAllMembers(members: readonly E[]): R;
+
+ /**
+ * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set.
+ * @param {Array.<*>} members
+ */
+ toIncludeAnyMembers(members: readonly E[]): R;
+
+ /**
+ * Use `.toIncludeSameMembers` when checking if two arrays contain equal values, in any order.
+ * @param {Array.<*>} members
+ */
+ toIncludeSameMembers(members: readonly E[]): R;
+
+ /**
+ * Use `.toPartiallyContain` when checking if any array value matches the partial member.
+ * @param {*} member
+ */
+ toPartiallyContain(member: E): R;
+
+ /**
+ * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array.
+ * @param {Function} predicate
+ */
+ toSatisfyAll(predicate: (x: E) => boolean): R;
+
+ /**
+ * Use `.toSatisfyAny` when you want to use a custom matcher by supplying a predicate function that returns `true` for any matching value in an array.
+ * @param {Function} predicate
+ */
+ toSatisfyAny(predicate: (x: any) => boolean): R;
+
+ /**
+ * Use `.toBeBoolean` when checking if a value is a `Boolean`.
+ */
+ toBeBoolean(): R;
+
+ /**
+ * Use `.toBeTrue` when checking a value is equal (===) to `true`.
+ */
+ toBeTrue(): R;
+
+ /**
+ * Use `.toBeFalse` when checking a value is equal (===) to `false`.
+ */
+ toBeFalse(): R;
+
+ /**
+ * Use `.toBeDate` when checking if a value is a `Date`.
+ */
+ toBeDate(): R;
+
+ /**
+ * Use `.toBeValidDate` when checking if a value is a `valid Date`.
+ */
+ toBeValidDate(): R;
+
+ /**
+ * Use `.toBeFunction` when checking if a value is a `Function`.
+ */
+ toBeFunction(): R;
+
+ /**
+ * Use `.toBeDateString` when checking if a value is a valid date string.
+ */
+ toBeDateString(): R;
+
+ /**
+ * Use `.toBeHexadecimal` when checking if a value is a valid HTML hex color.
+ */
+ toBeHexadecimal(): R;
+
+ /**
+ * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`.
+ *
+ * Note: Required Jest version >=23
+ *
+ * @param {Mock} mock
+ * @param {boolean} [failIfNoSecondInvocation=true]
+ */
+ toHaveBeenCalledBefore(
+ mock: jest.MockInstance,
+ failIfNoSecondInvocation?: boolean,
+ ): R;
+
+ /**
+ * Use `.toHaveBeenCalledAfter` when checking if a `Mock` was called after another `Mock`.
+ *
+ * Note: Required Jest version >=23
+ *
+ * @param {Mock} mock
+ * @param {boolean} [failIfNoFirstInvocation=true]
+ */
+ toHaveBeenCalledAfter(
+ mock: jest.MockInstance,
+ failIfNoFirstInvocation?: boolean,
+ ): R;
+
+ /**
+ * Use `.toHaveBeenCalledOnce` to check if a `Mock` was called exactly one time.
+ */
+ toHaveBeenCalledOnce(): R;
+
+ /**
+ * Use `.toHaveBeenCalledExactlyOnceWith` to check if a `Mock` was called exactly one time with the expected value.
+ */
+ toHaveBeenCalledExactlyOnceWith(...args: unknown[]): R;
+
+ /**
+ * Use `.toBeNumber` when checking if a value is a `Number`.
+ */
+ toBeNumber(): R;
+
+ /**
+ * Use `.toBeNaN` when checking a value is `NaN`.
+ */
+ toBeNaN(): R;
+
+ /**
+ * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`.
+ */
+ toBeFinite(): R;
+
+ /**
+ * Use `.toBePositive` when checking if a value is a positive `Number`.
+ */
+ toBePositive(): R;
+
+ /**
+ * Use `.toBeNegative` when checking if a value is a negative `Number`.
+ */
+ toBeNegative(): R;
+
+ /**
+ * Use `.toBeEven` when checking if a value is an even `Number`.
+ */
+ toBeEven(): R;
+
+ /**
+ * Use `.toBeOdd` when checking if a value is an odd `Number`.
+ */
+ toBeOdd(): R;
+
+ /**
+ * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive).
+ *
+ * @param {Number} start
+ * @param {Number} end
+ */
+ toBeWithin(start: number, end: number): R;
+
+ /**
+ * Use `.toBeInRange` when checking if an array has elements in range min (inclusive) and max (inclusive).
+ *
+ * @param min
+ * @param max
+ */
+ toBeInRange(min: number, max: number): R;
+
+ /**
+ * Use `.toBeObject` when checking if a value is an `Object`.
+ */
+ toBeObject(): R;
+
+ /**
+ * Use `.toContainKey` when checking if an object contains the provided key.
+ *
+ * @param {String} key
+ */
+ toContainKey(key: string): R;
+
+ /**
+ * Use `.toContainKeys` when checking if an object has all of the provided keys.
+ *
+ * @param {Array.} keys
+ */
+ toContainKeys(keys: readonly (keyof E | string)[]): R;
+
+ /**
+ * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys.
+ *
+ * @param {Array.} keys
+ */
+ toContainAllKeys(keys: readonly (keyof E | string)[]): R;
+
+ /**
+ * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys.
+ *
+ * @param {Array.} keys
+ */
+ toContainAnyKeys(keys: readonly (keyof E | string)[]): R;
+
+ /**
+ * Use `.toContainValue` when checking if an object contains the provided value.
+ *
+ * @param {*} value
+ */
+ toContainValue(value: E): R;
+
+ /**
+ * Use `.toContainValues` when checking if an object contains all of the provided values.
+ *
+ * @param {Array.<*>} values
+ */
+ toContainValues(values: readonly E[]): R;
+
+ /**
+ * Use `.toContainAllValues` when checking if an object only contains all of the provided values.
+ *
+ * @param {Array.<*>} values
+ */
+ toContainAllValues(values: readonly E[]): R;
+
+ /**
+ * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values.
+ *
+ * @param {Array.<*>} values
+ */
+ toContainAnyValues(values: readonly E[]): R;
+
+ /**
+ * Use `.toContainEntry` when checking if an object contains the provided entry.
+ *
+ * @param {Array.<[keyof E, E[keyof E]>} entry
+ */
+ toContainEntry(entry: readonly [keyof E, E[keyof E]]): R;
+
+ /**
+ * Use `.toContainEntries` when checking if an object contains all of the provided entries.
+ *
+ * @param {Array.>} entries
+ */
+ toContainEntries(
+ entries: readonly (readonly [keyof E, E[keyof E]])[],
+ ): R;
+
+ /**
+ * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries.
+ *
+ * @param {Array.>} entries
+ */
+ toContainAllEntries(
+ entries: readonly (readonly [keyof E, E[keyof E]])[],
+ ): R;
+
+ /**
+ * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries.
+ *
+ * @param {Array.>} entries
+ */
+ toContainAnyEntries(
+ entries: readonly (readonly [keyof E, E[keyof E]])[],
+ ): R;
+
+ /**
+ * Use `.toBeExtensible` when checking if an object is extensible.
+ */
+ toBeExtensible(): R;
+
+ /**
+ * Use `.toBeFrozen` when checking if an object is frozen.
+ */
+ toBeFrozen(): R;
+
+ /**
+ * Use `.toBeSealed` when checking if an object is sealed.
+ */
+ toBeSealed(): R;
+
+ /**
+ * Use `.toResolve` when checking if a promise resolves.
+ */
+ toResolve(): R;
+
+ /**
+ * Use `.toReject` when checking if a promise rejects.
+ */
+ toReject(): R;
+
+ /**
+ * Use `.toBeString` when checking if a value is a `String`.
+ */
+ toBeString(): R;
+
+ /**
+ * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings.
+ *
+ * @param {String} string
+ */
+ toEqualCaseInsensitive(string: string): R;
+
+ /**
+ * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix.
+ *
+ * @param {String} prefix
+ */
+ toStartWith(prefix: string): R;
+
+ /**
+ * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix.
+ *
+ * @param {String} suffix
+ */
+ toEndWith(suffix: string): R;
+
+ /**
+ * Use `.toInclude` when checking if a `String` includes the given `String` substring.
+ *
+ * @param {String} substring
+ */
+ toInclude(substring: string): R;
+
+ /**
+ * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times.
+ *
+ * @param {String} substring
+ * @param {Number} times
+ */
+ toIncludeRepeated(substring: string, times: number): R;
+
+ /**
+ * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings.
+ *
+ * @param {Array.} substring
+ */
+ toIncludeMultiple(substring: readonly string[]): R;
+
+ /**
+ * Use `.toThrowWithMessage` when checking if a callback function throws an error of a given type with a given error message.
+ *
+ * @param {Function} type
+ * @param {String | RegExp} message
+ */
+ toThrowWithMessage(
+ type: (...args: any[]) => any,
+ message: string | RegExp,
+ ): R;
+
+ /**
+ * Use `.toBeEmptyObject` when checking if a value is an empty `Object`.
+ */
+ toBeEmptyObject(): R;
+
+ /**
+ * Use `.toBeSymbol` when checking if a value is a `Symbol`.
+ */
+ toBeSymbol(): R;
+
+ /**
+ * Use `.toBeBetween` when checking if a date occurs between `startDate` and `endDate`.
+ * @param {Date} startDate
+ * @param {Date} endDate
+ */
+ toBeBetween(startDate: Date, endDate: Date): R;
+
+ /**
+ * Use `.toBeBeforeOrEqualTo` when checking if a date equals to or occurs before `date`.
+ * @param {Date} date
+ */
+ toBeBeforeOrEqualTo(date: Date): R;
+
+ /**
+ * Use `.toBeAfterOrEqualTo` when checking if a date equals to or occurs after `date`.
+ * @param {Date} date
+ */
+ toBeAfterOrEqualTo(date: Date): R;
+
+ /**
+ * Use `.toEqualIgnoringWhitespace` when checking if a `String` is equal (===) to given `String` ignoring white-space.
+ *
+ * @param {String} string
+ */
+ toEqualIgnoringWhitespace(string: string): R;
+}
+
+declare namespace jest {
+ // noinspection JSUnusedGlobalSymbols
+ interface Matchers {
+ /**
+ * Note: Currently unimplemented
+ * Passing assertion
+ *
+ * @param {String} message
+ */
+ pass(message: string): R;
+
+ /**
+ * Note: Currently unimplemented
+ * Failing assertion
+ *
+ * @param {String} message
+ */
+ fail(message: string): never;
+
+ /**
+ * Use .toBeEmpty when checking if a String '', Array [], Object {} or Iterable (i.e. Map, Set) is empty.
+ */
+ toBeEmpty(): R;
+
+ /**
+ * Use .toBeOneOf when checking if a value is a member of a given Array.
+ * @param {Array.<*>} members
+ */
+ toBeOneOf(members: readonly E[]): R;
+
+ /**
+ * Use `.toBeNil` when checking a value is `null` or `undefined`.
+ */
+ toBeNil(): R;
+
+ /**
+ * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`.
+ * @param {Function} predicate
+ */
+ toSatisfy(predicate: (x: E) => boolean): R;
+
+ /**
+ * Use `.toBeArray` when checking if a value is an `Array`.
+ */
+ toBeArray(): R;
+
+ /**
+ * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x.
+ * @param {Number} x
+ */
+ toBeArrayOfSize(x: number): R;
+
+ /**
+ * Use `.toBeAfter` when checking if a date occurs after `date`.
+ * @param {Date} date
+ */
+ toBeAfter(date: Date): R;
+
+ /**
+ * Use `.toBeBefore` when checking if a date occurs before `date`.
+ * @param {Date} date
+ */
+ toBeBefore(date: Date): R;
+
+ /**
+ * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set.
+ * @param {Array.<*>} members
+ */
+ toIncludeAllMembers(members: readonly E[]): R;
+
+ /**
+ * Use `.toIncludeAllPartialMembers` when checking if an `Array` contains all of the same partial members of a given set.
+ * @param {Array.<*>} members
+ */
+ toIncludeAllPartialMembers(members: readonly E[]): R;
+
+ /**
+ * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set.
+ * @param {Array.<*>} members
+ */
+ toIncludeAnyMembers(members: readonly E[]): R;
+
+ /**
+ * Use `.toIncludeSameMembers` when checking if two arrays contain equal values, in any order.
+ * @param {Array.<*>} members
+ */
+ toIncludeSameMembers(members: readonly E[]): R;
+
+ /**
+ * Use `.toPartiallyContain` when checking if any array value matches the partial member.
+ * @param {*} member
+ */
+ toPartiallyContain(member: E): R;
+
+ /**
+ * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array.
+ * @param {Function} predicate
+ */
+ toSatisfyAll(predicate: (x: E) => boolean): R;
+
+ /**
+ * Use `.toSatisfyAny` when you want to use a custom matcher by supplying a predicate function that returns `true` for any matching value in an array.
+ * @param {Function} predicate
+ */
+ toSatisfyAny(predicate: (x: any) => boolean): R;
+
+ /**
+ * Use `.toBeBoolean` when checking if a value is a `Boolean`.
+ */
+ toBeBoolean(): R;
+
+ /**
+ * Use `.toBeTrue` when checking a value is equal (===) to `true`.
+ */
+ toBeTrue(): R;
+
+ /**
+ * Use `.toBeFalse` when checking a value is equal (===) to `false`.
+ */
+ toBeFalse(): R;
+
+ /**
+ * Use `.toBeDate` when checking if a value is a `Date`.
+ */
+ toBeDate(): R;
+
+ /**
+ * Use `.toBeValidDate` when checking if a value is a `valid Date`.
+ */
+ toBeValidDate(): R;
+
+ /**
+ * Use `.toBeFunction` when checking if a value is a `Function`.
+ */
+ toBeFunction(): R;
+
+ /**
+ * Use `.toBeDateString` when checking if a value is a valid date string.
+ */
+ toBeDateString(): R;
+
+ /**
+ * Use `.toBeHexadecimal` when checking if a value is a valid HTML hex color.
+ */
+ toBeHexadecimal(): R;
+
+ /**
+ * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`.
+ *
+ * Note: Required Jest version >=23
+ *
+ * @param {Mock} mock
+ * @param {boolean} [failIfNoSecondInvocation=true]
+ */
+ toHaveBeenCalledBefore(
+ mock: jest.MockInstance,
+ failIfNoSecondInvocation?: boolean,
+ ): R;
+
+ /**
+ * Use `.toHaveBeenCalledAfter` when checking if a `Mock` was called after another `Mock`.
+ *
+ * Note: Required Jest version >=23
+ *
+ * @param {Mock} mock
+ * @param {boolean} [failIfNoFirstInvocation=true]
+ */
+ toHaveBeenCalledAfter(
+ mock: jest.MockInstance,
+ failIfNoFirstInvocation?: boolean,
+ ): R;
+
+ /**
+ * Use `.toHaveBeenCalledOnce` to check if a `Mock` was called exactly one time.
+ */
+ toHaveBeenCalledOnce(): R;
+
+ /**
+ * Use `.toHaveBeenCalledExactlyOnceWith` to check if a `Mock` was called exactly one time with the expected value.
+ */
+ toHaveBeenCalledExactlyOnceWith(...args: unknown[]): R;
+
+ /**
+ * Use `.toBeNumber` when checking if a value is a `Number`.
+ */
+ toBeNumber(): R;
+
+ /**
+ * Use `.toBeNaN` when checking a value is `NaN`.
+ */
+ toBeNaN(): R;
+
+ /**
+ * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`.
+ */
+ toBeFinite(): R;
+
+ /**
+ * Use `.toBePositive` when checking if a value is a positive `Number`.
+ */
+ toBePositive(): R;
+
+ /**
+ * Use `.toBeNegative` when checking if a value is a negative `Number`.
+ */
+ toBeNegative(): R;
+
+ /**
+ * Use `.toBeEven` when checking if a value is an even `Number`.
+ */
+ toBeEven(): R;
+
+ /**
+ * Use `.toBeOdd` when checking if a value is an odd `Number`.
+ */
+ toBeOdd(): R;
+
+ /**
+ * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive).
+ *
+ * @param {Number} start
+ * @param {Number} end
+ */
+ toBeWithin(start: number, end: number): R;
+
+ /**
+ * Use `.toBeInRange` when checking if an array has elements in range min (inclusive) and max (inclusive).
+ *
+ * @param min
+ * @param max
+ */
+ toBeInRange(min: number, max: number): R;
+
+ /**
+ * Use `.toBeInteger` when checking if a value is an integer.
+ */
+ toBeInteger(): R;
+
+ /**
+ * Use `.toBeObject` when checking if a value is an `Object`.
+ */
+ toBeObject(): R;
+
+ /**
+ * Use `.toContainKey` when checking if an object contains the provided key.
+ *
+ * @param {String} key
+ */
+ toContainKey(key: keyof E | string): R;
+
+ /**
+ * Use `.toContainKeys` when checking if an object has all of the provided keys.
+ *
+ * @param {Array.} keys
+ */
+ toContainKeys(keys: readonly (keyof E | string)[]): R;
+
+ /**
+ * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys.
+ *
+ * @param {Array.} keys
+ */
+ toContainAllKeys(keys: readonly (keyof E | string)[]): R;
+
+ /**
+ * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys.
+ *
+ * @param {Array.} keys
+ */
+ toContainAnyKeys(keys: readonly (keyof E | string)[]): R;
+
+ /**
+ * Use `.toContainValue` when checking if an object contains the provided value.
+ *
+ * @param {*} value
+ */
+ toContainValue(value: E): R;
+
+ /**
+ * Use `.toContainValues` when checking if an object contains all of the provided values.
+ *
+ * @param {Array.<*>} values
+ */
+ toContainValues(values: readonly E[]): R;
+
+ /**
+ * Use `.toContainAllValues` when checking if an object only contains all of the provided values.
+ *
+ * @param {Array.<*>} values
+ */
+ toContainAllValues(values: readonly E[]): R;
+
+ /**
+ * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values.
+ *
+ * @param {Array.<*>} values
+ */
+ toContainAnyValues(values: readonly E[]): R;
+
+ /**
+ * Use `.toContainEntry` when checking if an object contains the provided entry.
+ *
+ * @param {Array.} entry
+ */
+ toContainEntry(entry: readonly [keyof E, E[keyof E]]): R;
+
+ /**
+ * Use `.toContainEntries` when checking if an object contains all of the provided entries.
+ *
+ * @param {Array.>} entries
+ */
+ toContainEntries(
+ entries: readonly (readonly [keyof E, E[keyof E]])[],
+ ): R;
+
+ /**
+ * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries.
+ *
+ * @param {Array.>} entries
+ */
+ toContainAllEntries(
+ entries: readonly (readonly [keyof E, E[keyof E]])[],
+ ): R;
+
+ /**
+ * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries.
+ *
+ * @param {Array.>} entries
+ */
+ toContainAnyEntries(
+ entries: readonly (readonly [keyof E, E[keyof E]])[],
+ ): R;
+
+ /**
+ * Use `.toBeExtensible` when checking if an object is extensible.
+ */
+ toBeExtensible(): R;
+
+ /**
+ * Use `.toBeFrozen` when checking if an object is frozen.
+ */
+ toBeFrozen(): R;
+
+ /**
+ * Use `.toBeSealed` when checking if an object is sealed.
+ */
+ toBeSealed(): R;
+
+ /**
+ * Use `.toResolve` when checking if a promise resolves.
+ */
+ toResolve(): Promise;
+
+ /**
+ * Use `.toReject` when checking if a promise rejects.
+ */
+ toReject(): Promise;
+
+ /**
+ * Use `.toBeString` when checking if a value is a `String`.
+ */
+ toBeString(): R;
+
+ /**
+ * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings.
+ *
+ * @param {String} string
+ */
+ toEqualCaseInsensitive(string: string): R;
+
+ /**
+ * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix.
+ *
+ * @param {String} prefix
+ */
+ toStartWith(prefix: string): R;
+
+ /**
+ * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix.
+ *
+ * @param {String} suffix
+ */
+ toEndWith(suffix: string): R;
+
+ /**
+ * Use `.toInclude` when checking if a `String` includes the given `String` substring.
+ *
+ * @param {String} substring
+ */
+ toInclude(substring: string): R;
+
+ /**
+ * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times.
+ *
+ * @param {String} substring
+ * @param {Number} times
+ */
+ toIncludeRepeated(substring: string, times: number): R;
+
+ /**
+ * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings.
+ *
+ * @param {Array.} substring
+ */
+ toIncludeMultiple(substring: readonly string[]): R;
+
+ /**
+ * Use `.toThrowWithMessage` when checking if a callback function throws an error of a given type with a given error message.
+ *
+ * @param {Function} type
+ * @param {String | RegExp} message
+ */
+ toThrowWithMessage(
+ type:
+ | (new (...args: any[]) => {message: string})
+ | (abstract new (...args: any[]) => {message: string})
+ | ((...args: any[]) => {message: string}),
+ message: string | RegExp,
+ ): R;
+
+ /**
+ * Use `.toBeEmptyObject` when checking if a value is an empty `Object`.
+ */
+ toBeEmptyObject(): R;
+
+ /**
+ * Use `.toBeSymbol` when checking if a value is a `Symbol`.
+ */
+ toBeSymbol(): R;
+
+ /**
+ * Use `.toBeBetween` when checking if a date occurs between `startDate` and `endDate`.
+ * @param {Date} startDate
+ * @param {Date} endDate
+ */
+ toBeBetween(startDate: Date, endDate: Date): R;
+
+ /**
+ * Use `.toBeBeforeOrEqualTo` when checking if a date equals to or occurs before `date`.
+ * @param {Date} date
+ */
+ toBeBeforeOrEqualTo(date: Date): R;
+
+ /**
+ * Use `.toBeAfterOrEqualTo` when checking if a date equals to or occurs after `date`.
+ * @param {Date} date
+ */
+ toBeAfterOrEqualTo(date: Date): R;
+
+ /**
+ * Use `.toEqualIgnoringWhitespace` when checking if a `String` is equal (===) to given `String` ignoring white-space.
+ *
+ * @param {String} string
+ */
+ toEqualIgnoringWhitespace(string: string): R;
+ }
+
+ // noinspection JSUnusedGlobalSymbols
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
+ interface Expect extends CustomMatchers {}
+
+ // noinspection JSUnusedGlobalSymbols
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
+ interface InverseAsymmetricMatchers extends Expect {}
+}
+
+declare module "jest-extended" {
+ const matchers: CustomMatchers;
+ export = matchers;
+}
diff --git a/types/matchers.d.ts b/types/matchers.d.ts
index 5ab113e08..7d00dc512 100644
--- a/types/matchers.d.ts
+++ b/types/matchers.d.ts
@@ -1,7 +1,6 @@
// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace jest {
interface Matchers {
- toBeFunction(): R;
/*
* From: config/jest/matchers/to-have-no-a11y-violations.ts
*/
diff --git a/types/testing-library_jest-dom.d.ts b/types/testing-library_jest-dom.d.ts
new file mode 100644
index 000000000..4062625a3
--- /dev/null
+++ b/types/testing-library_jest-dom.d.ts
@@ -0,0 +1,751 @@
+/* eslint-disable @typescript-eslint/ban-types, @typescript-eslint/no-empty-interface */
+
+/**
+We use matchers provided by third-party packages that extend the `Matchers`
+interface within the `jest` namespace. TypeScript won't pick these up unless
+they are imported in a TypeScript file. This can be done by:
+
+1. Installing `ts-node` and making the Jest config a TS file
+(see https://www.npmjs.com/package/@testing-library/jest-dom#with-typescript
+for example) then import from there and include the jest setup file in the
+TypeScript includes.
+2. Vendoring the type doc files like we're doing here.
+
+This is a copy of the type definitions from @testing-library/jest-dom,
+amended to make sure the matchers extend the jest-expect interface.
+ */
+
+import {type ARIARole} from "aria-query";
+
+///
+
+declare namespace matchers {
+ interface TestingLibraryMatchers {
+ /**
+ * @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(/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: Array): 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 ,