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