Replace Jest with Vitest (#2929)

This commit is contained in:
Jon Koops 2022-07-07 07:23:54 +02:00 committed by GitHub
parent a7694b8945
commit 4eb4448878
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 4985 additions and 7848 deletions

View file

@ -1,18 +0,0 @@
import type { InitialOptionsTsJest } from "ts-jest";
const config: InitialOptionsTsJest = {
preset: "ts-jest",
globals: {
"ts-jest": {
tsconfig: "tsconfig.jest.json",
},
},
testMatch: ["<rootDir>/src/**/*.test.ts?(x)"],
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
moduleNameMapper: {
"\\.css$": "<rootDir>/mocks/fileMock.ts",
"lodash-es": "lodash",
},
};
export default config;

12669
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,7 @@
"lint": "eslint . --ext js,jsx,mjs,ts,tsx", "lint": "eslint . --ext js,jsx,mjs,ts,tsx",
"start": "snowpack dev", "start": "snowpack dev",
"start:rh-sso": "THEME_NAME=rh-sso snowpack dev", "start:rh-sso": "THEME_NAME=rh-sso snowpack dev",
"test": "jest", "test": "vitest",
"cy:open": "cypress open --e2e --browser chrome", "cy:open": "cypress open --e2e --browser chrome",
"cy:run": "cypress run --browser chrome", "cy:run": "cypress run --browser chrome",
"cy:check-types": "tsc --project cypress/tsconfig.json", "cy:check-types": "tsc --project cypress/tsconfig.json",
@ -71,6 +71,7 @@
"@types/tar-fs": "^2.0.1", "@types/tar-fs": "^2.0.1",
"@typescript-eslint/eslint-plugin": "^5.30.4", "@typescript-eslint/eslint-plugin": "^5.30.4",
"@typescript-eslint/parser": "^5.30.4", "@typescript-eslint/parser": "^5.30.4",
"@vitejs/plugin-react": "^1.3.2",
"cypress": "^10.3.0", "cypress": "^10.3.0",
"decompress": "^4.2.1", "decompress": "^4.2.1",
"del": "^6.1.1", "del": "^6.1.1",
@ -83,8 +84,6 @@
"gunzip-maybe": "^1.4.2", "gunzip-maybe": "^1.4.2",
"http2-proxy": "^5.0.53", "http2-proxy": "^5.0.53",
"husky": "^8.0.1", "husky": "^8.0.1",
"jest": "^28.1.2",
"jest-environment-jsdom": "^28.1.2",
"lint-staged": "^13.0.3", "lint-staged": "^13.0.3",
"node-fetch": "^3.2.6", "node-fetch": "^3.2.6",
"postcss": "^8.4.14", "postcss": "^8.4.14",
@ -94,9 +93,9 @@
"progress-promise": "^0.0.6", "progress-promise": "^0.0.6",
"snowpack": "^3.8.6", "snowpack": "^3.8.6",
"tar-fs": "^2.1.1", "tar-fs": "^2.1.1",
"ts-jest": "^28.0.5",
"ts-node": "^10.8.2", "ts-node": "^10.8.2",
"typescript": "^4.7.4" "typescript": "^4.7.4",
"vitest": "^0.17.0"
}, },
"lint-staged": { "lint-staged": {
"*.{js,jsx,mjs,ts,tsx}": "eslint --cache --fix" "*.{js,jsx,mjs,ts,tsx}": "eslint --cache --fix"

View file

@ -1,3 +1,4 @@
import { describe, expect, it } from "vitest";
import { ExecutionList, IndexChange, LevelChange } from "../execution-model"; import { ExecutionList, IndexChange, LevelChange } from "../execution-model";
describe("ExecutionList", () => { describe("ExecutionList", () => {

View file

@ -1,4 +1,5 @@
import type PasswordPolicyTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/passwordPolicyTypeRepresentation"; import type PasswordPolicyTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/passwordPolicyTypeRepresentation";
import { describe, expect, it } from "vitest";
import { parsePolicy, serializePolicy, SubmittedValues } from "./util"; import { parsePolicy, serializePolicy, SubmittedValues } from "./util";
describe("serializePolicy", () => { describe("serializePolicy", () => {

View file

@ -1,13 +1,14 @@
/** /**
* @jest-environment jsdom * @vitest-environment jsdom
*/ */
import { fireEvent, screen, render } from "@testing-library/react";
import React from "react"; import React from "react";
import { fireEvent, render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { useConfirmDialog } from "./ConfirmDialog"; import { useConfirmDialog } from "./ConfirmDialog";
describe("ConfirmDialog", () => { describe("ConfirmDialog", () => {
it("renders a simple confirm dialog", () => { it("renders a simple confirm dialog", () => {
const onConfirm = jest.fn(); const onConfirm = vi.fn();
const Test = () => { const Test = () => {
const [toggle, ConfirmDialog] = useConfirmDialog({ const [toggle, ConfirmDialog] = useConfirmDialog({
titleKey: "Delete app02?", titleKey: "Delete app02?",

View file

@ -1,11 +1,12 @@
/** /**
* @jest-environment jsdom * @vitest-environment jsdom
*/ */
import { render, waitFor } from "@testing-library/react"; import React, { FunctionComponent } from "react";
import type KeycloakAdminClient from "@keycloak/keycloak-admin-client"; import type KeycloakAdminClient from "@keycloak/keycloak-admin-client";
import type { ServerInfoRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/serverInfoRepesentation"; import type { ServerInfoRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/serverInfoRepesentation";
import React, { FunctionComponent } from "react"; import { render, waitFor } from "@testing-library/react";
import { HashRouter } from "react-router-dom"; import { HashRouter } from "react-router-dom";
import { describe, expect, it } from "vitest";
import { AccessContextProvider } from "../../context/access/Access"; import { AccessContextProvider } from "../../context/access/Access";
import { AdminClient } from "../../context/auth/AdminClient"; import { AdminClient } from "../../context/auth/AdminClient";
import { RealmContext } from "../../context/realm-context/RealmContext"; import { RealmContext } from "../../context/realm-context/RealmContext";

View file

@ -1,16 +1,17 @@
/** /**
* @jest-environment jsdom * @vitest-environment jsdom
*/ */
import React from "react";
import type WhoAmIRepresentation from "@keycloak/keycloak-admin-client/lib/defs/whoAmIRepresentation";
import { FormGroup, Switch } from "@patternfly/react-core"; import { FormGroup, Switch } from "@patternfly/react-core";
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
import type WhoAmIRepresentation from "@keycloak/keycloak-admin-client/lib/defs/whoAmIRepresentation";
import React from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { KeycloakTextInput } from "../keycloak-text-input/KeycloakTextInput"; import { describe, expect, it } from "vitest";
import { AccessContextProvider } from "../../context/access/Access"; import { AccessContextProvider } from "../../context/access/Access";
import { RealmContext } from "../../context/realm-context/RealmContext"; import { RealmContext } from "../../context/realm-context/RealmContext";
import { WhoAmI, WhoAmIContext } from "../../context/whoami/WhoAmI"; import { WhoAmI, WhoAmIContext } from "../../context/whoami/WhoAmI";
import whoami from "../../context/whoami/__tests__/mock-whoami.json"; import whoami from "../../context/whoami/__tests__/mock-whoami.json";
import { KeycloakTextInput } from "../keycloak-text-input/KeycloakTextInput";
import { FormAccess } from "./FormAccess"; import { FormAccess } from "./FormAccess";
describe("FormAccess", () => { describe("FormAccess", () => {

View file

@ -1,10 +1,11 @@
import { describe, expect, it, vi } from "vitest";
import { import {
arrayToKeyValue, arrayToKeyValue,
keyValueToArray, keyValueToArray,
KeyValueType, KeyValueType,
} from "./key-value-convert"; } from "./key-value-convert";
jest.mock("react"); vi.mock("react");
describe("Tests the convert functions for attribute input", () => { describe("Tests the convert functions for attribute input", () => {
it("converts empty array into form value", () => { it("converts empty array into form value", () => {

View file

@ -1,3 +1,4 @@
import { describe, expect, it } from "vitest";
import { getTimeUnit, toHumanFormat } from "./TimeSelector"; import { getTimeUnit, toHumanFormat } from "./TimeSelector";
describe("Time conversion functions", () => { describe("Time conversion functions", () => {

View file

@ -1,9 +1,10 @@
/** /**
* @jest-environment jsdom * @vitest-environment jsdom
*/ */
import whoamiMock from "./mock-whoami.json";
import { WhoAmI } from "../WhoAmI";
import type WhoAmIRepresentation from "@keycloak/keycloak-admin-client/lib/defs/whoAmIRepresentation"; import type WhoAmIRepresentation from "@keycloak/keycloak-admin-client/lib/defs/whoAmIRepresentation";
import { expect, test } from "vitest";
import { WhoAmI } from "../WhoAmI";
import whoamiMock from "./mock-whoami.json";
test("returns display name", () => { test("returns display name", () => {
const whoami = new WhoAmI(whoamiMock as WhoAmIRepresentation); const whoami = new WhoAmI(whoamiMock as WhoAmIRepresentation);

View file

@ -1,6 +1,7 @@
import { describe, expect, it, vi } from "vitest";
import { convertFormValuesToObject, convertToFormValues } from "./util"; import { convertFormValuesToObject, convertToFormValues } from "./util";
jest.mock("react"); vi.mock("react");
describe("Tests the form convert util functions", () => { describe("Tests the form convert util functions", () => {
it("convert to form values", () => { it("convert to form values", () => {
@ -116,7 +117,7 @@ describe("Tests the form convert util functions", () => {
const given = { const given = {
config: { group: ["one"], another: { nested: ["value"] } }, config: { group: ["one"], another: { nested: ["value"] } },
}; };
const setValue = jest.fn(); const setValue = vi.fn();
//when //when
convertToFormValues(given, setValue); convertToFormValues(given, setValue);

View file

@ -1,3 +1,4 @@
import { describe, expect, it } from "vitest";
import { isDefined } from "./isDefined"; import { isDefined } from "./isDefined";
describe("isDefined", () => { describe("isDefined", () => {

View file

@ -1,11 +1,11 @@
import type { Context } from "react"; import type { Context } from "react";
import { useContext } from "react"; import { useContext } from "react";
import { mocked } from "jest-mock"; import { beforeEach, describe, expect, it, vi } from "vitest";
import useRequiredContext from "./useRequiredContext"; import useRequiredContext from "./useRequiredContext";
jest.mock("react"); vi.mock("react");
const useContextMock = mocked(useContext); const useContextMock = vi.mocked(useContext);
describe("useRequiredContext", () => { describe("useRequiredContext", () => {
beforeEach(() => { beforeEach(() => {

View file

@ -1,19 +1,20 @@
/** /**
* @jest-environment jsdom * @vitest-environment jsdom
*/ */
import { renderHook } from "@testing-library/react-hooks"; import { renderHook } from "@testing-library/react-hooks";
import { describe, expect, it, vi } from "vitest";
import useSetTimeout from "./useSetTimeout"; import useSetTimeout from "./useSetTimeout";
jest.useFakeTimers(); vi.useFakeTimers();
describe("useSetTimeout", () => { describe("useSetTimeout", () => {
it("schedules timeouts and triggers the callbacks", () => { it("schedules timeouts and triggers the callbacks", () => {
const { result } = renderHook(() => useSetTimeout()); const { result } = renderHook(() => useSetTimeout());
const setTimeoutSpy = jest.spyOn(global, "setTimeout"); const setTimeoutSpy = vi.spyOn(global, "setTimeout");
// Schedule some timeouts... // Schedule some timeouts...
const callback1 = jest.fn(); const callback1 = vi.fn();
const callback2 = jest.fn(); const callback2 = vi.fn();
result.current(callback1, 1000); result.current(callback1, 1000);
result.current(callback2, 500); result.current(callback2, 500);
@ -24,10 +25,10 @@ describe("useSetTimeout", () => {
// Ensure callbacks are called after timers run. // Ensure callbacks are called after timers run.
expect(callback2).not.toBeCalled(); expect(callback2).not.toBeCalled();
jest.advanceTimersByTime(500); vi.advanceTimersByTime(500);
expect(callback1).not.toBeCalled(); expect(callback1).not.toBeCalled();
expect(callback2).toBeCalled(); expect(callback2).toBeCalled();
jest.advanceTimersByTime(500); vi.advanceTimersByTime(500);
expect(callback1).toBeCalled(); expect(callback1).toBeCalled();
setTimeoutSpy.mockRestore(); setTimeoutSpy.mockRestore();
@ -38,16 +39,16 @@ describe("useSetTimeout", () => {
unmount(); unmount();
expect(() => result.current(jest.fn(), 1000)).toThrowError( expect(() => result.current(vi.fn(), 1000)).toThrowError(
"Can't schedule a timeout on an unmounted component." "Can't schedule a timeout on an unmounted component."
); );
}); });
it("clears a timeout if the component unmounts", () => { it("clears a timeout if the component unmounts", () => {
const { result, unmount } = renderHook(() => useSetTimeout()); const { result, unmount } = renderHook(() => useSetTimeout());
const setTimeoutSpy = jest.spyOn(global, "setTimeout"); const setTimeoutSpy = vi.spyOn(global, "setTimeout");
const clearTimeoutSpy = jest.spyOn(global, "clearTimeout"); const clearTimeoutSpy = vi.spyOn(global, "clearTimeout");
const callback = jest.fn(); const callback = vi.fn();
result.current(callback, 1000); result.current(callback, 1000);
@ -56,7 +57,7 @@ describe("useSetTimeout", () => {
expect(clearTimeoutSpy).toBeCalled(); expect(clearTimeoutSpy).toBeCalled();
// And the callback should no longer be called. // And the callback should no longer be called.
jest.runOnlyPendingTimers(); vi.runOnlyPendingTimers();
expect(callback).not.toBeCalled(); expect(callback).not.toBeCalled();
setTimeoutSpy.mockRestore(); setTimeoutSpy.mockRestore();
@ -65,9 +66,9 @@ describe("useSetTimeout", () => {
it("clears a timeout when cancelled", () => { it("clears a timeout when cancelled", () => {
const { result } = renderHook(() => useSetTimeout()); const { result } = renderHook(() => useSetTimeout());
const setTimeoutSpy = jest.spyOn(global, "setTimeout"); const setTimeoutSpy = vi.spyOn(global, "setTimeout");
const clearTimeoutSpy = jest.spyOn(global, "clearTimeout"); const clearTimeoutSpy = vi.spyOn(global, "clearTimeout");
const callback = jest.fn(); const callback = vi.fn();
const cancel = result.current(callback, 1000); const cancel = result.current(callback, 1000);
// Timeout should be cleared when cancelling. // Timeout should be cleared when cancelling.
@ -75,7 +76,7 @@ describe("useSetTimeout", () => {
expect(clearTimeoutSpy).toBeCalled(); expect(clearTimeoutSpy).toBeCalled();
// And the callback should no longer be called. // And the callback should no longer be called.
jest.runOnlyPendingTimers(); vi.runOnlyPendingTimers();
expect(callback).not.toBeCalled(); expect(callback).not.toBeCalled();
setTimeoutSpy.mockRestore(); setTimeoutSpy.mockRestore();

View file

@ -1,7 +1,8 @@
/** /**
* @jest-environment jsdom * @vitest-environment jsdom
*/ */
import { act, renderHook } from "@testing-library/react-hooks"; import { act, renderHook } from "@testing-library/react-hooks";
import { describe, expect, it } from "vitest";
import useToggle from "./useToggle"; import useToggle from "./useToggle";
describe("useToggle", () => { describe("useToggle", () => {

View file

@ -1,13 +0,0 @@
{
"extends": "./tsconfig.json",
"include": [
"src",
"jest.setup.ts"
],
// overwrite exclude so test files are included.
"exclude": [],
"compilerOptions": {
"types": ["jest"],
"jsx": "react"
}
}

19
vite.config.ts Normal file
View file

@ -0,0 +1,19 @@
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
// Resolve the 'module' entrypoint at all times (not the default due to Node.js compatibility issues).
mainFields: ["module"],
},
plugins: [react({ jsxRuntime: "classic" })],
test: {
setupFiles: "vitest.setup.ts",
watch: false,
deps: {
// Ensure '.mjs' files are used for '@patternfly/react-styles'.
inline: [/@patternfly\/react-styles/],
},
},
});

View file

@ -1,6 +1,9 @@
import "@testing-library/jest-dom"; import matchers from "@testing-library/jest-dom/matchers";
import i18n from "i18next"; import i18n from "i18next";
import { initReactI18next } from "react-i18next"; import { initReactI18next } from "react-i18next";
import { expect } from "vitest";
expect.extend(matchers);
i18n.use(initReactI18next).init({ i18n.use(initReactI18next).init({
lng: "en", lng: "en",