diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-01-01 23:44:50 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-01-01 23:47:21 +0900 |
| commit | 2fb6471a685bec1433be3335f377a1a2313e4820 (patch) | |
| tree | 328ddaeec0c591b06bf005d48b0242345c1336be /src/client/components/DeleteNoteModal.test.tsx | |
| parent | f30566e1c7126db4c6242ab38d07a9478f79d3db (diff) | |
| download | kioku-2fb6471a685bec1433be3335f377a1a2313e4820.tar.gz kioku-2fb6471a685bec1433be3335f377a1a2313e4820.tar.zst kioku-2fb6471a685bec1433be3335f377a1a2313e4820.zip | |
refactor(client): migrate API calls to typed RPC client
Replace raw fetch() calls with apiClient.rpc typed client across all
modal and page components. This provides better type safety and
eliminates manual auth header handling.
- Make handleResponse public for component usage
- Update all component tests to mock RPC methods instead of fetch
- Change POSTGRES_HOST default to kioku-db for Docker compatibility
🤖 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/DeleteNoteModal.test.tsx')
| -rw-r--r-- | src/client/components/DeleteNoteModal.test.tsx | 73 |
1 files changed, 28 insertions, 45 deletions
diff --git a/src/client/components/DeleteNoteModal.test.tsx b/src/client/components/DeleteNoteModal.test.tsx index a17323a..7130176 100644 --- a/src/client/components/DeleteNoteModal.test.tsx +++ b/src/client/components/DeleteNoteModal.test.tsx @@ -4,12 +4,26 @@ import { cleanup, render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { apiClient } from "../api/client"; -import { DeleteNoteModal } from "./DeleteNoteModal"; + +const mockDelete = vi.fn(); +const mockHandleResponse = vi.fn(); vi.mock("../api/client", () => ({ apiClient: { - getAuthHeader: vi.fn(), + rpc: { + api: { + decks: { + ":deckId": { + notes: { + ":noteId": { + $delete: (args: unknown) => mockDelete(args), + }, + }, + }, + }, + }, + }, + handleResponse: (res: unknown) => mockHandleResponse(res), }, ApiClientError: class ApiClientError extends Error { constructor( @@ -23,8 +37,8 @@ vi.mock("../api/client", () => ({ }, })); -const mockFetch = vi.fn(); -global.fetch = mockFetch; +import { ApiClientError } from "../api/client"; +import { DeleteNoteModal } from "./DeleteNoteModal"; describe("DeleteNoteModal", () => { const defaultProps = { @@ -37,9 +51,8 @@ describe("DeleteNoteModal", () => { beforeEach(() => { vi.clearAllMocks(); - vi.mocked(apiClient.getAuthHeader).mockReturnValue({ - Authorization: "Bearer access-token", - }); + mockDelete.mockResolvedValue({ ok: true }); + mockHandleResponse.mockResolvedValue({}); }); afterEach(() => { @@ -125,11 +138,6 @@ describe("DeleteNoteModal", () => { const onClose = vi.fn(); const onNoteDeleted = vi.fn(); - mockFetch.mockResolvedValueOnce({ - ok: true, - json: async () => ({ success: true }), - }); - render( <DeleteNoteModal {...defaultProps} @@ -141,9 +149,8 @@ describe("DeleteNoteModal", () => { await user.click(screen.getByRole("button", { name: "Delete" })); await waitFor(() => { - expect(mockFetch).toHaveBeenCalledWith("/api/decks/deck-1/notes/note-1", { - method: "DELETE", - headers: { Authorization: "Bearer access-token" }, + expect(mockDelete).toHaveBeenCalledWith({ + param: { deckId: "deck-1", noteId: "note-1" }, }); }); @@ -154,11 +161,9 @@ describe("DeleteNoteModal", () => { it("displays error message when delete fails", async () => { const user = userEvent.setup(); - mockFetch.mockResolvedValueOnce({ - ok: false, - status: 500, - json: async () => ({ error: "Failed to delete note" }), - }); + mockHandleResponse.mockRejectedValue( + new ApiClientError("Failed to delete note", 500), + ); render(<DeleteNoteModal {...defaultProps} />); @@ -175,12 +180,7 @@ describe("DeleteNoteModal", () => { const user = userEvent.setup(); // Create a promise that we can control - let resolveDelete: ((value: unknown) => void) | undefined; - const deletePromise = new Promise((resolve) => { - resolveDelete = resolve; - }); - - mockFetch.mockReturnValueOnce(deletePromise); + mockDelete.mockImplementation(() => new Promise(() => {})); // Never resolves render(<DeleteNoteModal {...defaultProps} />); @@ -188,24 +188,13 @@ describe("DeleteNoteModal", () => { // Should show "Deleting..." while request is in progress expect(screen.getByText("Deleting...")).toBeDefined(); - - // Resolve the delete request to cleanup - resolveDelete?.({ - ok: true, - json: async () => ({ success: true }), - }); }); it("disables buttons while deleting", async () => { const user = userEvent.setup(); // Create a promise that we can control - let resolveDelete: ((value: unknown) => void) | undefined; - const deletePromise = new Promise((resolve) => { - resolveDelete = resolve; - }); - - mockFetch.mockReturnValueOnce(deletePromise); + mockDelete.mockImplementation(() => new Promise(() => {})); // Never resolves render(<DeleteNoteModal {...defaultProps} />); @@ -220,11 +209,5 @@ describe("DeleteNoteModal", () => { "disabled", true, ); - - // Resolve the delete request to cleanup - resolveDelete?.({ - ok: true, - json: async () => ({ success: true }), - }); }); }); |
