this repo has no description
at main 5.4 kB view raw
1import { beforeEach, describe, expect, it } from "vitest"; 2import { fireEvent, render, screen, waitFor } from "@testing-library/svelte"; 3import Dashboard from "../routes/Dashboard.svelte"; 4import { 5 clearMocks, 6 jsonResponse, 7 mockData, 8 mockEndpoint, 9 setupAuthenticatedUser, 10 setupFetchMock, 11 setupUnauthenticatedUser, 12} from "./mocks"; 13const STORAGE_KEY = "tranquil_pds_session"; 14describe("Dashboard", () => { 15 beforeEach(() => { 16 clearMocks(); 17 setupFetchMock(); 18 }); 19 describe("authentication guard", () => { 20 it("redirects to login when not authenticated", async () => { 21 setupUnauthenticatedUser(); 22 render(Dashboard); 23 await waitFor(() => { 24 expect(globalThis.location.pathname).toBe("/app/login"); 25 }); 26 }); 27 it("shows loading state while checking auth", () => { 28 const { container } = render(Dashboard); 29 expect(container.querySelector(".skeleton-section")).toBeInTheDocument(); 30 expect(container.querySelectorAll(".skeleton-card").length).toBeGreaterThan(0); 31 }); 32 }); 33 describe("authenticated view", () => { 34 beforeEach(() => { 35 setupAuthenticatedUser(); 36 }); 37 it("displays user account info and page structure", async () => { 38 render(Dashboard); 39 await waitFor(() => { 40 expect(screen.getByRole("heading", { name: /dashboard/i })) 41 .toBeInTheDocument(); 42 expect(screen.getByRole("heading", { name: /account overview/i })) 43 .toBeInTheDocument(); 44 expect(screen.getAllByText(/@testuser\.test\.tranquil\.dev/).length) 45 .toBeGreaterThan(0); 46 expect(screen.getByText(/did:web:test\.tranquil\.dev:u:testuser/)) 47 .toBeInTheDocument(); 48 expect(screen.getByText("test@example.com")).toBeInTheDocument(); 49 expect(screen.getByText("Verified")).toBeInTheDocument(); 50 expect(screen.getByText("Verified")).toHaveClass("badge", "success"); 51 }); 52 }); 53 it("displays unverified badge when email not confirmed", async () => { 54 setupAuthenticatedUser({ emailConfirmed: false }); 55 render(Dashboard); 56 await waitFor(() => { 57 expect(screen.getByText("Unverified")).toBeInTheDocument(); 58 expect(screen.getByText("Unverified")).toHaveClass("badge", "warning"); 59 }); 60 }); 61 it("displays all navigation cards", async () => { 62 render(Dashboard); 63 await waitFor(() => { 64 const navCards = [ 65 { name: /app passwords/i, href: "/app/app-passwords" }, 66 { name: /account settings/i, href: "/app/settings" }, 67 { name: /communication preferences/i, href: "/app/comms" }, 68 { name: /repository explorer/i, href: "/app/repo" }, 69 ]; 70 for (const { name, href } of navCards) { 71 const card = screen.getByRole("link", { name }); 72 expect(card).toBeInTheDocument(); 73 expect(card).toHaveAttribute("href", href); 74 } 75 }); 76 }); 77 it("displays invite codes card when invites are required and user is admin", async () => { 78 setupAuthenticatedUser({ isAdmin: true }); 79 mockEndpoint( 80 "com.atproto.server.describeServer", 81 () => 82 jsonResponse(mockData.describeServer({ inviteCodeRequired: true })), 83 ); 84 render(Dashboard); 85 await waitFor(() => { 86 const inviteCard = screen.getByRole("link", { name: /invite codes/i }); 87 expect(inviteCard).toBeInTheDocument(); 88 expect(inviteCard).toHaveAttribute("href", "/app/invite-codes"); 89 }); 90 }); 91 }); 92 describe("logout functionality", () => { 93 beforeEach(() => { 94 setupAuthenticatedUser(); 95 localStorage.setItem(STORAGE_KEY, JSON.stringify(mockData.session())); 96 mockEndpoint("/oauth/revoke", () => jsonResponse({})); 97 }); 98 it("calls oauth revoke and navigates to login on logout", async () => { 99 let revokeCalled = false; 100 mockEndpoint("/oauth/revoke", () => { 101 revokeCalled = true; 102 return jsonResponse({}); 103 }); 104 render(Dashboard); 105 await waitFor(() => { 106 expect(screen.getByRole("button", { name: /@testuser/i })) 107 .toBeInTheDocument(); 108 }); 109 await fireEvent.click(screen.getByRole("button", { name: /@testuser/i })); 110 await waitFor(() => { 111 expect(screen.getByRole("button", { name: /sign out/i })) 112 .toBeInTheDocument(); 113 }); 114 await fireEvent.click(screen.getByRole("button", { name: /sign out/i })); 115 await waitFor(() => { 116 expect(revokeCalled).toBe(true); 117 expect(globalThis.location.pathname).toBe("/app/login"); 118 }); 119 }); 120 it("clears session from localStorage after logout", async () => { 121 const storedSession = localStorage.getItem(STORAGE_KEY); 122 expect(storedSession).not.toBeNull(); 123 render(Dashboard); 124 await waitFor(() => { 125 expect(screen.getByRole("button", { name: /@testuser/i })) 126 .toBeInTheDocument(); 127 }); 128 await fireEvent.click(screen.getByRole("button", { name: /@testuser/i })); 129 await waitFor(() => { 130 expect(screen.getByRole("button", { name: /sign out/i })) 131 .toBeInTheDocument(); 132 }); 133 await fireEvent.click(screen.getByRole("button", { name: /sign out/i })); 134 await waitFor(() => { 135 expect(localStorage.getItem(STORAGE_KEY)).toBeNull(); 136 }); 137 }); 138 }); 139});