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 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});