This commit is contained in:
Michael Zhang 2023-06-15 20:18:38 -05:00
parent 0edff29b8c
commit 51d635c452
14 changed files with 3168 additions and 811 deletions

2
.gitignore vendored
View file

@ -26,3 +26,5 @@ dist-ssr
houhou.db
src/data/kanadata.json
.direnv
/coverage

10
jest.config.js Normal file
View file

@ -0,0 +1,10 @@
export default {
preset: "vite-jest",
setupFilesAfterEnv: ["<rootDir>/src/setupTests.js"],
testMatch: [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}",
],
testEnvironment: "jest-environment-jsdom",
};

3889
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"test": "vitest",
"tauri": "tauri"
},
"dependencies": {
@ -29,23 +30,27 @@
},
"devDependencies": {
"@eslint/js": "^8.42.0",
"@swc/core": "^1.3.64",
"@tauri-apps/cli": "^1.4.0",
"@testing-library/react": "^14.0.0",
"@types/lodash-es": "^4.17.7",
"@types/node": "^18.7.10",
"@types/node": "^20.3.1",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"@types/react-timeago": "^4.1.3",
"@typescript-eslint/eslint-plugin": "^5.59.11",
"@typescript-eslint/parser": "^5.59.11",
"@vitejs/plugin-react": "^3.0.0",
"@vitejs/plugin-react": "^4.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"@vitest/coverage-v8": "^0.32.0",
"autoprefixer": "^10.4.14",
"eslint": "^8.42.0",
"eslint-plugin-react": "^7.32.2",
"postcss": "^8.4.24",
"prettier": "^2.8.8",
"sass": "^1.62.1",
"typescript": "^4.9.5",
"vite": "^4.2.1"
"typescript": "^5.1.3",
"vite": "^4.2.1",
"vitest": "^0.32.0"
}
}

View file

@ -5,11 +5,11 @@ import { createBrowserRouter } from "react-router-dom";
import { Outlet, Route, createRoutesFromElements, matchPath, useLocation } from "react-router";
import { StrictMode } from "react";
import { Component as KanjiPane } from "./panes/KanjiPane";
import { Component as SettingsPane } from "./panes/SettingsPane";
import { Component as SrsPane } from "./panes/SrsPane";
import { Component as SrsReviewPane } from "./panes/SrsReviewPane";
import { Component as VocabPane } from "./panes/VocabPane";
import KanjiPane from "./panes/KanjiPane";
import SettingsPane from "./panes/SettingsPane";
import SrsPane from "./panes/SrsPane";
import SrsReviewPane from "./panes/SrsReviewPane";
import VocabPane from "./panes/VocabPane";
import styles from "./App.module.scss";

View file

@ -21,6 +21,7 @@ export default function DashboardItemStats({ srsStats }: DashboardItemStatsProps
{srsLevels.groups.map((group) => {
const groupLevels = srsLevelsByGroups.get(group);
if (!groupLevels) return null;
groupLevels.sort((a, b) => (a.delay == null || b.delay == null ? 0 : a.delay - b.delay));
const groupCount = groupLevels
.map((level) => grades.get(level.value) ?? 0)

View file

@ -16,7 +16,7 @@ export interface GetKanjiResult {
kanji: Kanji[];
}
export function Component() {
export default function KanjiPane() {
const { selectedKanji } = useParams();
const [searchQuery, setSearchQuery] = useState("");
@ -85,5 +85,3 @@ export function Component() {
</Flex>
);
}
Component.displayName = "KanjiPane";

View file

@ -11,7 +11,7 @@ interface ApplicationInfo {
srs_db_path: string;
}
export function Component() {
export default function SettingsPane() {
const { data: info } = useSWR("application_info", () =>
invoke<ApplicationInfo>("application_info"),
);
@ -55,5 +55,3 @@ export function Component() {
</main>
);
}
Component.displayName = "SettingsPane";

View file

@ -19,7 +19,7 @@ export interface SrsStats {
num_failure: number;
}
export function Component() {
export default function SrsPane() {
const { data: srsStats, error } = useSWR(["get_srs_stats"], ([command]) =>
invoke<SrsStats>(command),
);
@ -38,5 +38,3 @@ export function Component() {
</main>
);
}
Component.displayName = "SrsPane";

View file

@ -0,0 +1,15 @@
import SrsReviewPane from "./SrsReviewPane";
import { wrappedRender } from "../test/setup";
import { vi, Mock } from "vitest";
describe("SrsReviewPane", () => {
beforeEach(() => {});
afterEach(() => {
vi.restoreAllMocks();
});
test("renders without exploding", () => {
wrappedRender(<SrsReviewPane />);
});
});

View file

@ -18,7 +18,7 @@ import {
import InputBox from "../components/srsReview/InputBox";
import SelectOnClick from "../components/utils/SelectOnClick";
export function Component() {
export default function SrsReviewPane() {
// null = has not started, (.length == 0) = finished
const [reviewQueue, setReviewQueue] = useState<ReviewItem[] | null>(null);
const [completedQueue, setCompletedQueue] = useState<ReviewItem[]>([]);
@ -147,7 +147,9 @@ export function Component() {
/>
)}
<h1 className={styles.testWord}>{nextItem.challenge}</h1>
<h1 className={styles.testWord} data-testid="testWord">
{nextItem.challenge}
</h1>
<InputBox
submit={formSubmit}
@ -196,5 +198,3 @@ export function Component() {
</main>
);
}
Component.displayName = "SrsReviewPane";

View file

@ -1,12 +1,10 @@
import VocabList from "../components/VocabList";
import styles from "./VocabPane.module.scss";
export function Component() {
export default function VocabPane() {
return (
<main className={styles.main}>
<VocabList />
</main>
);
}
Component.displayName = "VocabPane";

7
src/test/setup.ts Normal file
View file

@ -0,0 +1,7 @@
import { render } from "@testing-library/react";
import { ReactElement } from "react";
import { BrowserRouter } from "react-router-dom";
export function wrappedRender(ui: ReactElement) {
return render(ui, { wrapper: BrowserRouter });
}

8
vitest.config.ts Normal file
View file

@ -0,0 +1,8 @@
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "jsdom",
},
});