learn and share notes on atproto (wip) 馃 malfestio.stormlightlabs.org/
readability solid axum atproto srs
at main 141 lines 4.4 kB view raw
1import { api } from "$lib/api"; 2import { cleanup, render, screen, waitFor } from "@solidjs/testing-library"; 3import { JSX } from "solid-js"; 4import { afterEach, describe, expect, it, vi } from "vitest"; 5import Search from "../Search"; 6 7vi.mock("$lib/api", () => ({ api: { search: vi.fn() } })); 8 9const { mockSearchParams } = vi.hoisted(() => ({ mockSearchParams: { q: "" } })); 10 11vi.mock( 12 "@solidjs/router", 13 () => ({ 14 useSearchParams: () => [mockSearchParams], 15 A: (props: { href: string; children: JSX.Element }) => <a href={props.href}>{props.children}</a>, 16 useNavigate: () => vi.fn(), 17 }), 18); 19 20describe("Search", () => { 21 afterEach(() => { 22 cleanup(); 23 vi.clearAllMocks(); 24 }); 25 26 const mockSearchResults = [{ 27 item_type: "deck", 28 item_id: "deck1", 29 creator_did: "did:test:1", 30 data: { 31 id: "deck1", 32 owner_did: "did:test:1", 33 title: "Test Deck", 34 description: "A test deck", 35 tags: ["test"], 36 visibility: { type: "Public" }, 37 }, 38 rank: 0.9, 39 }, { 40 item_type: "card", 41 item_id: "card1", 42 creator_did: "did:test:1", 43 data: { id: "card1", deck_id: "deck1", front: "Card Front", back: "Card Back", owner_did: "did:test:1" }, 44 rank: 0.8, 45 }, { 46 item_type: "note", 47 item_id: "note1", 48 creator_did: "did:test:1", 49 data: { id: "note1", title: "Test Note", owner_did: "did:test:1" }, 50 rank: 0.7, 51 }]; 52 53 it("renders search results correctly", async () => { 54 mockSearchParams.q = "test"; 55 vi.mocked(api.search).mockResolvedValue( 56 { ok: true, json: () => Promise.resolve(mockSearchResults) } as unknown as Response, 57 ); 58 59 render(() => <Search />); 60 61 // Verify loading state or results 62 await waitFor(() => expect(screen.getByText("Search Results")).toBeInTheDocument()); 63 64 // Verify Deck result 65 await waitFor(() => expect(screen.getByText("Test Deck")).toBeInTheDocument()); 66 expect(screen.getByText("A test deck")).toBeInTheDocument(); 67 68 // Verify Card result 69 expect(screen.getByText("Card Front")).toBeInTheDocument(); 70 expect(screen.getByText("Card Back")).toBeInTheDocument(); 71 72 // Verify Note result 73 expect(screen.getByText("Test Note")).toBeInTheDocument(); 74 }); 75 76 it("shows empty state when no results", async () => { 77 mockSearchParams.q = "nonexistent"; 78 vi.mocked(api.search).mockResolvedValue({ ok: true, json: () => Promise.resolve([]) } as unknown as Response); 79 80 render(() => <Search />); 81 82 await waitFor(() => expect(screen.getByText("No results found for \"nonexistent\"")).toBeInTheDocument()); 83 }); 84 85 it("handles loading state", async () => { 86 mockSearchParams.q = "loading"; 87 vi.mocked(api.search).mockReturnValue(new Promise(() => {})); 88 89 render(() => <Search />); 90 91 expect(api.search).toHaveBeenCalledWith("loading"); 92 }); 93 94 it("generates correct links for results", async () => { 95 mockSearchParams.q = "test"; 96 vi.mocked(api.search).mockResolvedValue( 97 { ok: true, json: () => Promise.resolve(mockSearchResults) } as unknown as Response, 98 ); 99 100 render(() => <Search />); 101 102 await waitFor(() => expect(screen.getByText("Test Deck")).toBeInTheDocument()); 103 104 const deckLink = screen.getByText("Test Deck").closest("a"); 105 expect(deckLink).toHaveAttribute("href", "/decks/deck1"); 106 107 const cardLink = screen.getByText("Card in Deck").closest("a"); 108 expect(cardLink).toHaveAttribute("href", "/decks/deck1"); 109 110 const noteLink = screen.getByText("Test Note").closest("a"); 111 expect(noteLink).toHaveAttribute("href", "/notes/note1"); 112 }); 113 114 it("shows remote indicator for remote results", async () => { 115 mockSearchParams.q = "remote"; 116 const remoteResult = { 117 item_type: "deck", 118 item_id: "remote-deck", 119 creator_did: "did:remote:user", 120 data: { 121 id: "remote-deck", 122 owner_did: "did:remote:user", 123 title: "Remote Deck", 124 description: "From afar", 125 tags: [], 126 visibility: { type: "Public" }, 127 }, 128 rank: 1.0, 129 source: "remote", 130 }; 131 132 vi.mocked(api.search).mockResolvedValue( 133 { ok: true, json: () => Promise.resolve([remoteResult]) } as unknown as Response, 134 ); 135 136 render(() => <Search />); 137 138 await waitFor(() => expect(screen.getByText("Remote Deck")).toBeInTheDocument()); 139 expect(screen.getByText("Remote")).toBeInTheDocument(); 140 }); 141});