switch to vitest
This commit is contained in:
parent
24880a5c2d
commit
3911334fee
|
@ -7,7 +7,8 @@
|
|||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"rust-lang.rust-analyzer",
|
||||
"yzhang.markdown-all-in-one"
|
||||
"yzhang.markdown-all-in-one",
|
||||
"zixuanchen.vitest-explorer"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": [
|
||||
|
|
|
@ -35,11 +35,7 @@
|
|||
}
|
||||
],
|
||||
|
||||
// It seems like rust-analyzer is supposed to be able to format
|
||||
// Rust files, but with "matklad.rust-analyzer" here, VS Code says
|
||||
// "There is no formatter for 'rust' files installed."
|
||||
"editor.defaultFormatter": "matklad.rust-analyzer"
|
||||
//"editor.defaultFormatter": null
|
||||
"editor.defaultFormatter": "rust-lang.rust-analyzer"
|
||||
},
|
||||
"markdown.extension.list.indentationSize": "inherit",
|
||||
"markdown.extension.toc.unorderedList.marker": "*",
|
||||
|
@ -47,5 +43,7 @@
|
|||
// Specify the path to the workspace version of TypeScript. Note this only
|
||||
// takes effect when workspace version is selected in the UI.
|
||||
// https://code.visualstudio.com/docs/typescript/typescript-compiling#_using-the-workspace-version-of-typescript
|
||||
"typescript.tsdk": "./ui/node_modules/typescript/lib"
|
||||
"typescript.tsdk": "./ui/node_modules/typescript/lib",
|
||||
"cmake.configureOnOpen": false,
|
||||
"vitest.enable": true
|
||||
}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
// This file is part of Moonfire NVR, a security camera network video recorder.
|
||||
// Copyright (C) 2023 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
|
||||
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception
|
||||
|
||||
// Environment based on `jsdom` with some extra globals, inspired by
|
||||
// the following comment:
|
||||
// https://github.com/jsdom/jsdom/issues/1724#issuecomment-1446858041
|
||||
|
||||
import JSDOMEnvironment from "jest-environment-jsdom";
|
||||
|
||||
// https://github.com/facebook/jest/blob/v29.4.3/website/versioned_docs/version-29.4/Configuration.md#testenvironment-string
|
||||
export default class FixJSDOMEnvironment extends JSDOMEnvironment {
|
||||
constructor(...args: ConstructorParameters<typeof JSDOMEnvironment>) {
|
||||
super(...args);
|
||||
|
||||
// Tests use fetch calls with relative URLs + msw to intercept.
|
||||
this.global.fetch = (
|
||||
resource: RequestInfo | URL,
|
||||
options?: RequestInit
|
||||
) => {
|
||||
throw "must use msw to fetch: " + resource;
|
||||
};
|
||||
|
||||
class MyRequest extends Request {
|
||||
constructor(input: RequestInfo | URL, init?: RequestInit | undefined) {
|
||||
input = new URL(input as string, "http://localhost");
|
||||
super(input, init);
|
||||
}
|
||||
}
|
||||
|
||||
this.global.Headers = Headers;
|
||||
this.global.Request = MyRequest;
|
||||
this.global.Response = Response;
|
||||
|
||||
// `src/LiveCamera/parser.ts` uses TextDecoder.
|
||||
this.global.TextDecoder = TextDecoder;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
// This file is part of Moonfire NVR, a security camera network video recorder.
|
||||
// Copyright (C) 2023 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
|
||||
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception
|
||||
|
||||
import type { Config } from "jest";
|
||||
|
||||
const config: Config = {
|
||||
testEnvironment: "./FixJSDomEnvironment.ts",
|
||||
|
||||
transform: {
|
||||
// https://github.com/swc-project/jest
|
||||
"\\.[tj]sx?$": [
|
||||
"@swc/jest",
|
||||
{
|
||||
// https://swc.rs/docs/configuration/compilation
|
||||
// https://github.com/swc-project/jest/issues/167#issuecomment-1809868077
|
||||
jsc: {
|
||||
transform: {
|
||||
react: {
|
||||
runtime: "automatic",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
setupFilesAfterEnv: ["<rootDir>/src/setupTests.ts"],
|
||||
|
||||
// https://github.com/jaredLunde/react-hook/issues/300#issuecomment-1845227937
|
||||
moduleNameMapper: {
|
||||
"@react-hook/(.*)": "<rootDir>/node_modules/@react-hook/$1/dist/main",
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
File diff suppressed because it is too large
Load Diff
|
@ -27,12 +27,12 @@
|
|||
"format": "prettier --write --ignore-path .gitignore .",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview",
|
||||
"test": "jest"
|
||||
"test": "vitest"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:jest/recommended",
|
||||
"plugin:vitest/recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:react/jsx-runtime",
|
||||
"plugin:react-hooks/recommended"
|
||||
|
@ -54,7 +54,6 @@
|
|||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"jest/no-disabled-tests": "off",
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
|
@ -86,12 +85,10 @@
|
|||
"@babel/preset-react": "^7.23.3",
|
||||
"@babel/preset-typescript": "^7.23.3",
|
||||
"@swc/core": "^1.3.100",
|
||||
"@swc/jest": "^0.2.29",
|
||||
"@testing-library/dom": "^8.11.3",
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/node": "^18.8.1",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.10",
|
||||
|
@ -99,18 +96,17 @@
|
|||
"@typescript-eslint/parser": "^6.14.0",
|
||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-plugin-jest": "^27.6.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.5",
|
||||
"eslint-plugin-vitest": "^0.3.18",
|
||||
"http-proxy-middleware": "^2.0.4",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"msw": "^1.3.2",
|
||||
"prettier": "^2.6.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.1.0",
|
||||
"vite": "^5.0.8",
|
||||
"vite-plugin-compression": "^0.5.1"
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vitest": "^1.0.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import App from "./App";
|
|||
import { renderWithCtx } from "./testutil";
|
||||
import { rest } from "msw";
|
||||
import { setupServer } from "msw/node";
|
||||
import { beforeAll, afterAll, afterEach, expect, test } from "vitest";
|
||||
|
||||
const server = setupServer(
|
||||
rest.get("/api/", (req, res, ctx) => {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import ErrorBoundary from "./ErrorBoundary";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const ThrowsLiteralComponent = () => {
|
||||
throw "simple string error";
|
||||
|
|
|
@ -11,6 +11,7 @@ import { Recording, VideoSampleEntry } from "../api";
|
|||
import { renderWithCtx } from "../testutil";
|
||||
import { Camera, Stream } from "../types";
|
||||
import VideoList from "./VideoList";
|
||||
import { beforeAll, afterAll, afterEach, expect, test } from "vitest";
|
||||
|
||||
const TEST_CAMERA: Camera = {
|
||||
uuid: "c7278ba0-a001-420c-911e-fff4e33f6916",
|
||||
|
|
|
@ -8,6 +8,7 @@ import { rest } from "msw";
|
|||
import { setupServer } from "msw/node";
|
||||
import Login from "./Login";
|
||||
import { renderWithCtx } from "./testutil";
|
||||
import { beforeAll, afterEach, afterAll, test, vi, expect } from "vitest";
|
||||
|
||||
// Set up a fake API backend.
|
||||
const server = setupServer(
|
||||
|
@ -47,20 +48,20 @@ afterAll(() => server.close());
|
|||
// https://github.com/facebook/jest/issues/13018 ?
|
||||
//
|
||||
// Argh!
|
||||
// beforeEach(() => jest.useFakeTimers({
|
||||
// beforeEach(() => vi.useFakeTimers({
|
||||
// legacyFakeTimers: true,
|
||||
// }));
|
||||
// afterEach(() => {
|
||||
// act(() => {
|
||||
// jest.runOnlyPendingTimers();
|
||||
// jest.useRealTimers();
|
||||
// vi.runOnlyPendingTimers();
|
||||
// vi.useRealTimers();
|
||||
// });
|
||||
// });
|
||||
|
||||
test("success", async () => {
|
||||
const user = userEvent.setup();
|
||||
const handleClose = jest.fn().mockName("handleClose");
|
||||
const onSuccess = jest.fn().mockName("handleOpen");
|
||||
const handleClose = vi.fn().mockName("handleClose");
|
||||
const onSuccess = vi.fn().mockName("handleOpen");
|
||||
renderWithCtx(
|
||||
<Login open={true} onSuccess={onSuccess} handleClose={handleClose} />
|
||||
);
|
||||
|
@ -75,8 +76,8 @@ test("success", async () => {
|
|||
// so the delay("infinite") request just sticks around, even though the fetch
|
||||
// has been aborted. Maybe https://github.com/mswjs/msw/pull/585 will fix it.
|
||||
test.skip("close while pending", async () => {
|
||||
const handleClose = jest.fn().mockName("handleClose");
|
||||
const onSuccess = jest.fn().mockName("handleOpen");
|
||||
const handleClose = vi.fn().mockName("handleClose");
|
||||
const onSuccess = vi.fn().mockName("handleOpen");
|
||||
const { rerender } = renderWithCtx(
|
||||
<Login open={true} onSuccess={onSuccess} handleClose={handleClose} />
|
||||
);
|
||||
|
@ -96,8 +97,8 @@ test.skip("close while pending", async () => {
|
|||
// TODO: fix and re-enable this test.
|
||||
// It depends on the timers; see TODO above.
|
||||
test.skip("bad credentials", async () => {
|
||||
const handleClose = jest.fn().mockName("handleClose");
|
||||
const onSuccess = jest.fn().mockName("handleOpen");
|
||||
const handleClose = vi.fn().mockName("handleClose");
|
||||
const onSuccess = vi.fn().mockName("handleOpen");
|
||||
renderWithCtx(
|
||||
<Login open={true} onSuccess={onSuccess} handleClose={handleClose} />
|
||||
);
|
||||
|
@ -110,8 +111,8 @@ test.skip("bad credentials", async () => {
|
|||
// TODO: fix and re-enable this test.
|
||||
// It depends on the timers; see TODO above.
|
||||
test.skip("server error", async () => {
|
||||
const handleClose = jest.fn().mockName("handleClose");
|
||||
const onSuccess = jest.fn().mockName("handleOpen");
|
||||
const handleClose = vi.fn().mockName("handleClose");
|
||||
const onSuccess = vi.fn().mockName("handleOpen");
|
||||
renderWithCtx(
|
||||
<Login open={true} onSuccess={onSuccess} handleClose={handleClose} />
|
||||
);
|
||||
|
@ -127,8 +128,8 @@ test.skip("server error", async () => {
|
|||
// TODO: fix and re-enable this test.
|
||||
// It depends on the timers; see TODO above.
|
||||
test.skip("network error", async () => {
|
||||
const handleClose = jest.fn().mockName("handleClose");
|
||||
const onSuccess = jest.fn().mockName("handleOpen");
|
||||
const handleClose = vi.fn().mockName("handleClose");
|
||||
const onSuccess = vi.fn().mockName("handleOpen");
|
||||
renderWithCtx(
|
||||
<Login open={true} onSuccess={onSuccess} handleClose={handleClose} />
|
||||
);
|
||||
|
|
|
@ -40,7 +40,7 @@ async function myfetch(
|
|||
): Promise<FetchResult<Response>> {
|
||||
let response;
|
||||
try {
|
||||
response = await fetch(url, init);
|
||||
response = await fetch(window.location.origin + url, init);
|
||||
} catch (e) {
|
||||
if (!(e instanceof DOMException)) {
|
||||
throw e;
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
import { act, render, screen, waitFor } from "@testing-library/react";
|
||||
import { useEffect } from "react";
|
||||
import { SnackbarProvider, useSnackbars } from "./snackbars";
|
||||
import { beforeEach, afterEach, expect, test, vi } from "vitest";
|
||||
|
||||
// Mock out timers.
|
||||
beforeEach(() => jest.useFakeTimers());
|
||||
beforeEach(() => { vi.useFakeTimers(); });
|
||||
afterEach(() => {
|
||||
jest.runOnlyPendingTimers();
|
||||
jest.useRealTimers();
|
||||
vi.runOnlyPendingTimers();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
test("notifications that time out", async () => {
|
||||
|
@ -34,24 +35,24 @@ test("notifications that time out", async () => {
|
|||
expect(screen.queryByText(/message B/)).not.toBeInTheDocument();
|
||||
|
||||
// ...then start to close...
|
||||
act(() => jest.advanceTimersByTime(5000));
|
||||
act(() => vi.advanceTimersByTime(5000));
|
||||
expect(screen.getByText(/message A/)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/message B/)).not.toBeInTheDocument();
|
||||
|
||||
// ...then it should close and message B should open...
|
||||
act(() => jest.runOnlyPendingTimers());
|
||||
act(() => vi.runOnlyPendingTimers());
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByText(/message A/)).not.toBeInTheDocument()
|
||||
);
|
||||
expect(screen.getByText(/message B/)).toBeInTheDocument();
|
||||
|
||||
// ...then message B should start to close...
|
||||
act(() => jest.advanceTimersByTime(5000));
|
||||
act(() => vi.advanceTimersByTime(5000));
|
||||
expect(screen.queryByText(/message A/)).not.toBeInTheDocument();
|
||||
expect(screen.getByText(/message B/)).toBeInTheDocument();
|
||||
|
||||
// ...then message B should fully close.
|
||||
act(() => jest.runOnlyPendingTimers());
|
||||
act(() => vi.runOnlyPendingTimers());
|
||||
expect(screen.queryByText(/message A/)).not.toBeInTheDocument();
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByText(/message B/)).not.toBeInTheDocument()
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
// This file is part of Moonfire NVR, a security camera network video recorder.
|
||||
// Copyright (C) 2023 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
|
||||
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception
|
||||
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
environment: "jsdom",
|
||||
globals: true,
|
||||
setupFiles: ["./src/setupTests.ts"],
|
||||
},
|
||||
});
|
Loading…
Reference in New Issue