this repo has no description
1import { beforeEach, describe, expect, it } from "vitest"; 2import { fireEvent, render, screen, waitFor } from "@testing-library/svelte"; 3import Login from "../routes/Login.svelte"; 4import { 5 clearMocks, 6 jsonResponse, 7 mockData, 8 mockEndpoint, 9 setupFetchMock, 10} from "./mocks"; 11import { _testSetState, type SavedAccount } from "../lib/auth.svelte"; 12 13describe("Login", () => { 14 beforeEach(() => { 15 clearMocks(); 16 setupFetchMock(); 17 globalThis.location.hash = ""; 18 mockEndpoint( 19 "/oauth/par", 20 () => jsonResponse({ request_uri: "urn:mock:request" }), 21 ); 22 }); 23 24 describe("initial render with no saved accounts", () => { 25 beforeEach(() => { 26 _testSetState({ 27 session: null, 28 loading: false, 29 error: null, 30 savedAccounts: [], 31 }); 32 }); 33 34 it("renders login page with title and OAuth button", async () => { 35 render(Login); 36 await waitFor(() => { 37 expect(screen.getByRole("heading", { name: /sign in/i })) 38 .toBeInTheDocument(); 39 expect(screen.getByRole("button", { name: /sign in/i })) 40 .toBeInTheDocument(); 41 }); 42 }); 43 44 it("shows create account link", async () => { 45 render(Login); 46 await waitFor(() => { 47 expect(screen.getByText(/don't have an account/i)).toBeInTheDocument(); 48 expect(screen.getByRole("link", { name: /create/i })).toHaveAttribute( 49 "href", 50 "#/register", 51 ); 52 }); 53 }); 54 55 it("shows forgot password and lost passkey links", async () => { 56 render(Login); 57 await waitFor(() => { 58 expect(screen.getByRole("link", { name: /forgot password/i })) 59 .toHaveAttribute("href", "#/reset-password"); 60 expect(screen.getByRole("link", { name: /lost passkey/i })) 61 .toHaveAttribute("href", "#/request-passkey-recovery"); 62 }); 63 }); 64 }); 65 66 describe("with saved accounts", () => { 67 const savedAccounts: SavedAccount[] = [ 68 { 69 did: "did:web:test.tranquil.dev:u:alice", 70 handle: "alice.test.tranquil.dev", 71 accessJwt: "mock-jwt-alice", 72 refreshJwt: "mock-refresh-alice", 73 }, 74 { 75 did: "did:web:test.tranquil.dev:u:bob", 76 handle: "bob.test.tranquil.dev", 77 accessJwt: "mock-jwt-bob", 78 refreshJwt: "mock-refresh-bob", 79 }, 80 ]; 81 82 beforeEach(() => { 83 _testSetState({ 84 session: null, 85 loading: false, 86 error: null, 87 savedAccounts, 88 }); 89 mockEndpoint( 90 "com.atproto.server.getSession", 91 () => 92 jsonResponse(mockData.session({ handle: "alice.test.tranquil.dev" })), 93 ); 94 }); 95 96 it("displays saved accounts list", async () => { 97 render(Login); 98 await waitFor(() => { 99 expect(screen.getByText(/@alice\.test\.tranquil\.dev/)) 100 .toBeInTheDocument(); 101 expect(screen.getByText(/@bob\.test\.tranquil\.dev/)) 102 .toBeInTheDocument(); 103 }); 104 }); 105 106 it("shows sign in to another account option", async () => { 107 render(Login); 108 await waitFor(() => { 109 expect(screen.getByText(/sign in to another/i)).toBeInTheDocument(); 110 }); 111 }); 112 113 it("can click on saved account to switch", async () => { 114 render(Login); 115 await waitFor(() => { 116 expect(screen.getByText(/@alice\.test\.tranquil\.dev/)) 117 .toBeInTheDocument(); 118 }); 119 const aliceAccount = screen.getByText(/@alice\.test\.tranquil\.dev/) 120 .closest("[role='button']"); 121 if (aliceAccount) { 122 await fireEvent.click(aliceAccount); 123 } 124 await waitFor(() => { 125 expect(globalThis.location.hash).toBe("#/dashboard"); 126 }); 127 }); 128 129 it("can remove saved account with forget button", async () => { 130 render(Login); 131 await waitFor(() => { 132 expect(screen.getByText(/@alice\.test\.tranquil\.dev/)) 133 .toBeInTheDocument(); 134 const forgetButtons = screen.getAllByTitle(/remove/i); 135 expect(forgetButtons.length).toBe(2); 136 }); 137 }); 138 }); 139 140 describe("error handling", () => { 141 it("displays error message when auth state has error", async () => { 142 _testSetState({ 143 session: null, 144 loading: false, 145 error: "OAuth login failed", 146 savedAccounts: [], 147 }); 148 render(Login); 149 await waitFor(() => { 150 expect(screen.getByText(/oauth login failed/i)).toBeInTheDocument(); 151 expect(screen.getByText(/oauth login failed/i)).toHaveClass("error"); 152 }); 153 }); 154 }); 155 156 describe("verification flow", () => { 157 beforeEach(() => { 158 _testSetState({ 159 session: null, 160 loading: false, 161 error: null, 162 savedAccounts: [], 163 }); 164 }); 165 166 it("shows verification form when pending verification exists", async () => { 167 render(Login); 168 }); 169 }); 170 171 describe("loading state", () => { 172 it("shows loading state while auth is initializing", async () => { 173 _testSetState({ 174 session: null, 175 loading: true, 176 error: null, 177 savedAccounts: [], 178 }); 179 render(Login); 180 }); 181 }); 182});