diff --git a/frontend/__tests__/components/test/LiveStats.jsdom-spec.tsx b/frontend/__tests__/components/test/LiveStats.jsdom-spec.tsx new file mode 100644 index 000000000000..4d477f574d57 --- /dev/null +++ b/frontend/__tests__/components/test/LiveStats.jsdom-spec.tsx @@ -0,0 +1,104 @@ +import { describe, vi, it, expect, beforeEach, Mock } from "vitest"; +import { createSignal } from "solid-js"; +import { render } from "@solidjs/testing-library"; +import { LiveStats } from "../../../src/ts/components/test/LiveStats"; + +import * as ConfigSignals from "../../../src/ts/signals/config"; +import * as TestSignals from "../../../src/ts/signals/test"; + +import { isFocused } from "../../../src/ts/test/focus"; + +describe("LiveStats", () => { + const [wpm] = createSignal("120"); + const [acc] = createSignal("98%"); + const [burst] = createSignal("140"); + + const liveSpeedStyleMock = vi.spyOn(ConfigSignals, "getLiveSpeedStyle"); + const liveAccStyleMock = vi.spyOn(ConfigSignals, "getLiveAccStyle"); + const liveBurstStyleMock = vi.spyOn(ConfigSignals, "getLiveBurstStyle"); + const statsVisibleMock = vi.spyOn(TestSignals, "statsVisible"); + + beforeEach(() => { + [ + isFocused as Mock, + liveSpeedStyleMock, + liveAccStyleMock, + liveBurstStyleMock, + statsVisibleMock, + ].forEach((it) => it.mockClear()); + + (isFocused as Mock).mockReturnValue(true); + liveSpeedStyleMock.mockReturnValue("text"); + liveBurstStyleMock.mockReturnValue("text"); + liveAccStyleMock.mockReturnValue("text"); + statsVisibleMock.mockReturnValue({ visible: true, animate: false }); + }); + + function renderElement(mode: "mini" | "text"): { + speed: HTMLElement; + acc: HTMLElement; + burst: HTMLElement; + } { + const { container } = render(() => ( + + )); + + return { + // oxlint-disable-next-line no-non-null-assertion + speed: container.querySelector(".speed")!, + // oxlint-disable-next-line no-non-null-assertion + acc: container.querySelector(".acc")!, + // oxlint-disable-next-line no-non-null-assertion + burst: container.querySelector(".burst")!, + }; + } + + it("does render if mode matches", () => { + //GIVEN + + //WHEN + const { speed, acc, burst } = renderElement("text"); + + //THEN + expect(speed).toHaveAttribute("data-visible", "true"); + expect(speed).toHaveTextContent("120"); + expect(acc).toHaveAttribute("data-visible", "true"); + expect(acc).toHaveTextContent("98%"); + expect(burst).toHaveAttribute("data-visible", "true"); + expect(burst).toHaveTextContent("140"); + }); + it("does not render if mode does not match", () => { + //WHEN + const { speed, acc, burst } = renderElement("mini"); + + //THEN + expect(speed).toHaveAttribute("data-visible", "false"); + expect(acc).toHaveAttribute("data-visible", "false"); + expect(burst).toHaveAttribute("data-visible", "false"); + }); + + it("does not render if not focussed", () => { + //GIVEN + (isFocused as Mock).mockReturnValue(false); + + //WHEN + const { speed, acc, burst } = renderElement("text"); + + //WHEN + expect(speed).toHaveAttribute("data-visible", "false"); + expect(acc).toHaveAttribute("data-visible", "false"); + expect(burst).toHaveAttribute("data-visible", "false"); + }); + it("does not render if statsVisible=false", () => { + //GIVEN + statsVisibleMock.mockReturnValue({ visible: false }); + + //WHEN + const { speed, acc, burst } = renderElement("text"); + + //WHEN + expect(speed).toHaveAttribute("data-visible", "false"); + expect(acc).toHaveAttribute("data-visible", "false"); + expect(burst).toHaveAttribute("data-visible", "false"); + }); +}); diff --git a/frontend/__tests__/root/config.spec.ts b/frontend/__tests__/root/config.spec.ts index 9021c5ea1b54..974bfe5106b9 100644 --- a/frontend/__tests__/root/config.spec.ts +++ b/frontend/__tests__/root/config.spec.ts @@ -53,7 +53,7 @@ describe("Config", () => { mocks.forEach((it) => it.mockClear()); vi.mock("../../src/ts/test/test-state", () => ({ - isActive: true, + isActive: () => true, })); isConfigValueValidMock.mockReturnValue(true); diff --git a/frontend/__tests__/setup-jsdom.ts b/frontend/__tests__/setup-jsdom.ts index ae671c34afdb..dd762f0824dc 100644 --- a/frontend/__tests__/setup-jsdom.ts +++ b/frontend/__tests__/setup-jsdom.ts @@ -1,6 +1,21 @@ import $ from "jquery"; +import { vi } from "vitest"; +import "@testing-library/jest-dom"; +import { getDefaultConfig } from "../src/ts/constants/default-config"; //@ts-expect-error add to global global["$"] = $; //@ts-expect-error add to global global["jQuery"] = $; + +vi.mock("../src/ts/config", () => { + return { + default: getDefaultConfig(), + }; +}); + +vi.mock("../src/ts/test/focus", () => { + return { + isFocused: vi.fn(), + }; +}); diff --git a/frontend/__tests__/tsconfig.json b/frontend/__tests__/tsconfig.json index 97e01a3900fa..b149e8c6930e 100644 --- a/frontend/__tests__/tsconfig.json +++ b/frontend/__tests__/tsconfig.json @@ -3,8 +3,15 @@ "compilerOptions": { "moduleResolution": "Bundler", "module": "ESNext", - "noEmit": true + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js" }, "files": ["vitest.d.ts"], - "include": ["./**/*.spec.ts", "./**/*.jsdom-spec.ts", "./setup-tests.ts"] + "include": [ + "./**/*.spec.ts", + "./**/*.jsdom-spec.ts", + "./**/*.jsdom-spec.tsx", + "./setup-tests.ts" + ] } diff --git a/frontend/__tests__/utils/dom.jsdom-spec.ts b/frontend/__tests__/utils/dom.jsdom-spec.ts index 8d38ebf56f40..25c5f424c4ed 100644 --- a/frontend/__tests__/utils/dom.jsdom-spec.ts +++ b/frontend/__tests__/utils/dom.jsdom-spec.ts @@ -27,7 +27,7 @@ describe("dom", () => { } beforeEach(() => { - handler.mockReset(); + handler.mockClear(); document.body.innerHTML = ""; const root = document.createElement("div"); @@ -151,7 +151,7 @@ describe("dom", () => { ); //WHEN click on mid1 handler is only called one time - handler.mockReset(); + handler.mockClear(); clickTarget = screen.getByTestId("mid1"); await userEvent.click(clickTarget); diff --git a/frontend/__tests__/vitest.d.ts b/frontend/__tests__/vitest.d.ts index d08189355996..2420f547252d 100644 --- a/frontend/__tests__/vitest.d.ts +++ b/frontend/__tests__/vitest.d.ts @@ -1,6 +1,9 @@ import type { Assertion, AsymmetricMatchersContaining } from "vitest"; import { TestActivityDay } from "../src/ts/elements/test-activity-calendar"; +/// +import "@testing-library/jest-dom"; + interface ActivityDayMatchers { toBeDate: (date: string) => ActivityDayMatchers; toHaveTests: (tests: number) => ActivityDayMatchers; diff --git a/frontend/package.json b/frontend/package.json index 09d7b37315ab..5d777190f338 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -61,7 +61,9 @@ "@fortawesome/fontawesome-free": "5.15.4", "@monkeytype/oxlint-config": "workspace:*", "@monkeytype/typescript-config": "workspace:*", + "@solidjs/testing-library": "0.8.10", "@testing-library/dom": "10.4.1", + "@testing-library/jest-dom": "6.9.1", "@testing-library/user-event": "14.6.1", "@types/canvas-confetti": "1.4.3", "@types/chartjs-plugin-trendline": "1.0.1", @@ -87,6 +89,7 @@ "oxlint-tsgolint": "0.10.1", "postcss": "8.4.31", "sass": "1.70.0", + "solid-js": "1.9.10", "subset-font": "2.3.0", "tsx": "4.16.2", "typescript": "5.9.3", @@ -98,6 +101,7 @@ "vite-plugin-inspect": "11.3.3", "vite-plugin-minify": "2.1.0", "vite-plugin-pwa": "1.1.0", + "vite-plugin-solid": "2.11.10", "vitest": "4.0.15" }, "lint-staged": { diff --git a/frontend/src/html/pages/test.html b/frontend/src/html/pages/test.html index a2cf8e5a2538..3067055f618e 100644 --- a/frontend/src/html/pages/test.html +++ b/frontend/src/html/pages/test.html @@ -124,17 +124,8 @@
Time left to memorise all words: 0s
Time left to memorise all words: 0s
-
-
- -
-
-
- - - - -
+
+