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.pathname).toBe("/app/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/app-passwords" },
65 { name: /account settings/i, href: "/app/settings" },
66 { name: /communication preferences/i, href: "/app/comms" },
67 { name: /repository explorer/i, href: "/app/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 () =>
81 jsonResponse(mockData.describeServer({ inviteCodeRequired: true })),
82 );
83 render(Dashboard);
84 await waitFor(() => {
85 const inviteCard = screen.getByRole("link", { name: /invite codes/i });
86 expect(inviteCard).toBeInTheDocument();
87 expect(inviteCard).toHaveAttribute("href", "/app/invite-codes");
88 });
89 });
90 });
91 describe("logout functionality", () => {
92 beforeEach(() => {
93 setupAuthenticatedUser();
94 localStorage.setItem(STORAGE_KEY, JSON.stringify(mockData.session()));
95 mockEndpoint("/oauth/revoke", () => jsonResponse({}));
96 });
97 it("calls oauth revoke and navigates to login on logout", async () => {
98 let revokeCalled = false;
99 mockEndpoint("/oauth/revoke", () => {
100 revokeCalled = true;
101 return jsonResponse({});
102 });
103 render(Dashboard);
104 await waitFor(() => {
105 expect(screen.getByRole("button", { name: /@testuser/i }))
106 .toBeInTheDocument();
107 });
108 await fireEvent.click(screen.getByRole("button", { name: /@testuser/i }));
109 await waitFor(() => {
110 expect(screen.getByRole("button", { name: /sign out/i }))
111 .toBeInTheDocument();
112 });
113 await fireEvent.click(screen.getByRole("button", { name: /sign out/i }));
114 await waitFor(() => {
115 expect(revokeCalled).toBe(true);
116 expect(globalThis.location.pathname).toBe("/app/login");
117 });
118 });
119 it("clears session from localStorage after logout", async () => {
120 const storedSession = localStorage.getItem(STORAGE_KEY);
121 expect(storedSession).not.toBeNull();
122 render(Dashboard);
123 await waitFor(() => {
124 expect(screen.getByRole("button", { name: /@testuser/i }))
125 .toBeInTheDocument();
126 });
127 await fireEvent.click(screen.getByRole("button", { name: /@testuser/i }));
128 await waitFor(() => {
129 expect(screen.getByRole("button", { name: /sign out/i }))
130 .toBeInTheDocument();
131 });
132 await fireEvent.click(screen.getByRole("button", { name: /sign out/i }));
133 await waitFor(() => {
134 expect(localStorage.getItem(STORAGE_KEY)).toBeNull();
135 });
136 });
137 });
138});