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(window.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.getByText(/@testuser\.test\.tranquil\.dev/))
44 .toBeInTheDocument();
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: /invite codes/i, href: "#/invite-codes" },
66 { name: /account settings/i, href: "#/settings" },
67 { name: /communication preferences/i, href: "#/comms" },
68 { name: /repository explorer/i, href: "#/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 });
78 describe("logout functionality", () => {
79 beforeEach(() => {
80 setupAuthenticatedUser();
81 localStorage.setItem(STORAGE_KEY, JSON.stringify(mockData.session()));
82 mockEndpoint("com.atproto.server.deleteSession", () => jsonResponse({}));
83 });
84 it("calls deleteSession and navigates to login on logout", async () => {
85 let deleteSessionCalled = false;
86 mockEndpoint("com.atproto.server.deleteSession", () => {
87 deleteSessionCalled = true;
88 return jsonResponse({});
89 });
90 render(Dashboard);
91 await waitFor(() => {
92 expect(screen.getByRole("button", { name: /sign out/i }))
93 .toBeInTheDocument();
94 });
95 await fireEvent.click(screen.getByRole("button", { name: /sign out/i }));
96 await waitFor(() => {
97 expect(deleteSessionCalled).toBe(true);
98 expect(window.location.hash).toBe("#/login");
99 });
100 });
101 it("clears session from localStorage after logout", async () => {
102 const storedSession = localStorage.getItem(STORAGE_KEY);
103 expect(storedSession).not.toBeNull();
104 render(Dashboard);
105 await waitFor(() => {
106 expect(screen.getByRole("button", { name: /sign out/i }))
107 .toBeInTheDocument();
108 });
109 await fireEvent.click(screen.getByRole("button", { name: /sign out/i }));
110 await waitFor(() => {
111 expect(localStorage.getItem(STORAGE_KEY)).toBeNull();
112 });
113 });
114 });
115});