aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/client/components/SyncStatusIndicator.test.tsx
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-01-04 17:43:59 +0900
committernsfisis <nsfisis@gmail.com>2026-01-04 19:09:58 +0900
commitf8e4be9b36a16969ac53bd9ce12ce8064be10196 (patch)
treeb2cf350d2e2e52803ff809311effb40da767d859 /src/client/components/SyncStatusIndicator.test.tsx
parente1c9e5e89bb91bca2586470c786510c3e1c03826 (diff)
downloadkioku-f8e4be9b36a16969ac53bd9ce12ce8064be10196.tar.gz
kioku-f8e4be9b36a16969ac53bd9ce12ce8064be10196.tar.zst
kioku-f8e4be9b36a16969ac53bd9ce12ce8064be10196.zip
refactor(client): migrate state management from React Context to Jotai
Replace AuthProvider and SyncProvider with Jotai atoms for more granular state management and better performance. This migration: - Creates atoms for auth, sync, decks, cards, noteTypes, and study state - Uses atomFamily for parameterized state (e.g., cards by deckId) - Introduces StoreInitializer component for subscription initialization - Updates all components and pages to use useAtomValue/useSetAtom - Updates all tests to use Jotai Provider with createStore pattern 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/client/components/SyncStatusIndicator.test.tsx')
-rw-r--r--src/client/components/SyncStatusIndicator.test.tsx97
1 files changed, 47 insertions, 50 deletions
diff --git a/src/client/components/SyncStatusIndicator.test.tsx b/src/client/components/SyncStatusIndicator.test.tsx
index a607e11..b56161d 100644
--- a/src/client/components/SyncStatusIndicator.test.tsx
+++ b/src/client/components/SyncStatusIndicator.test.tsx
@@ -3,23 +3,38 @@
*/
import "fake-indexeddb/auto";
import { cleanup, render, screen } from "@testing-library/react";
+import { createStore, Provider } from "jotai";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+import {
+ isOnlineAtom,
+ isSyncingAtom,
+ lastErrorAtom,
+ pendingCountAtom,
+ syncStatusAtom,
+} from "../atoms";
+import { SyncStatus } from "../sync";
import { SyncStatusIndicator } from "./SyncStatusIndicator";
-// Mock the useSync hook
-const mockUseSync = vi.fn();
-vi.mock("../stores", () => ({
- useSync: () => mockUseSync(),
-}));
-
-// Mock the SyncStatus constant
-vi.mock("../sync", () => ({
- SyncStatus: {
- Idle: "idle",
- Syncing: "syncing",
- Error: "error",
- },
-}));
+function renderWithStore(atomValues: {
+ isOnline: boolean;
+ isSyncing: boolean;
+ pendingCount: number;
+ lastError: string | null;
+ status: (typeof SyncStatus)[keyof typeof SyncStatus];
+}) {
+ const store = createStore();
+ store.set(isOnlineAtom, atomValues.isOnline);
+ store.set(isSyncingAtom, atomValues.isSyncing);
+ store.set(pendingCountAtom, atomValues.pendingCount);
+ store.set(lastErrorAtom, atomValues.lastError);
+ store.set(syncStatusAtom, atomValues.status);
+
+ return render(
+ <Provider store={store}>
+ <SyncStatusIndicator />
+ </Provider>,
+ );
+}
describe("SyncStatusIndicator", () => {
beforeEach(() => {
@@ -31,130 +46,112 @@ describe("SyncStatusIndicator", () => {
});
it("displays 'Synced' when online with no pending changes", () => {
- mockUseSync.mockReturnValue({
+ renderWithStore({
isOnline: true,
isSyncing: false,
pendingCount: 0,
lastError: null,
- status: "idle",
+ status: SyncStatus.Idle,
});
- render(<SyncStatusIndicator />);
-
expect(screen.getByText("Synced")).toBeDefined();
expect(screen.getByTestId("sync-status-indicator")).toBeDefined();
});
it("displays 'Offline' when not online", () => {
- mockUseSync.mockReturnValue({
+ renderWithStore({
isOnline: false,
isSyncing: false,
pendingCount: 0,
lastError: null,
- status: "idle",
+ status: SyncStatus.Idle,
});
- render(<SyncStatusIndicator />);
-
expect(screen.getByText("Offline")).toBeDefined();
});
it("displays 'Syncing...' when syncing", () => {
- mockUseSync.mockReturnValue({
+ renderWithStore({
isOnline: true,
isSyncing: true,
pendingCount: 0,
lastError: null,
- status: "syncing",
+ status: SyncStatus.Syncing,
});
- render(<SyncStatusIndicator />);
-
expect(screen.getByText("Syncing...")).toBeDefined();
});
it("displays pending count when there are pending changes", () => {
- mockUseSync.mockReturnValue({
+ renderWithStore({
isOnline: true,
isSyncing: false,
pendingCount: 5,
lastError: null,
- status: "idle",
+ status: SyncStatus.Idle,
});
- render(<SyncStatusIndicator />);
-
expect(screen.getByText("5 pending")).toBeDefined();
});
it("displays 'Sync error' when there is an error", () => {
- mockUseSync.mockReturnValue({
+ renderWithStore({
isOnline: true,
isSyncing: false,
pendingCount: 0,
lastError: "Network error",
- status: "error",
+ status: SyncStatus.Error,
});
- render(<SyncStatusIndicator />);
-
expect(screen.getByText("Sync error")).toBeDefined();
});
it("shows error message in title when there is an error", () => {
- mockUseSync.mockReturnValue({
+ renderWithStore({
isOnline: true,
isSyncing: false,
pendingCount: 0,
lastError: "Network error",
- status: "error",
+ status: SyncStatus.Error,
});
- render(<SyncStatusIndicator />);
-
const indicator = screen.getByTestId("sync-status-indicator");
expect(indicator.getAttribute("title")).toBe("Network error");
});
it("prioritizes offline status over other states", () => {
- mockUseSync.mockReturnValue({
+ renderWithStore({
isOnline: false,
isSyncing: true,
pendingCount: 5,
lastError: "Error",
- status: "error",
+ status: SyncStatus.Error,
});
- render(<SyncStatusIndicator />);
-
expect(screen.getByText("Offline")).toBeDefined();
});
it("prioritizes syncing status over pending and error", () => {
- mockUseSync.mockReturnValue({
+ renderWithStore({
isOnline: true,
isSyncing: true,
pendingCount: 5,
lastError: null,
- status: "syncing",
+ status: SyncStatus.Syncing,
});
- render(<SyncStatusIndicator />);
-
expect(screen.getByText("Syncing...")).toBeDefined();
});
it("prioritizes error status over pending", () => {
- mockUseSync.mockReturnValue({
+ renderWithStore({
isOnline: true,
isSyncing: false,
pendingCount: 5,
lastError: "Network error",
- status: "error",
+ status: SyncStatus.Error,
});
- render(<SyncStatusIndicator />);
-
expect(screen.getByText("Sync error")).toBeDefined();
});
});