Barazo default frontend
barazo.forum
1/**
2 * Tests for API client auth functions.
3 * Verifies the contract between client functions and the API response shape.
4 */
5
6import { describe, it, expect } from 'vitest'
7import { http, HttpResponse } from 'msw'
8import { server } from '@/mocks/server'
9import { initiateLogin, refreshSession, initiateCrossPostAuth } from '@/lib/api/client'
10
11const API_URL = ''
12
13describe('initiateLogin', () => {
14 it('returns the redirect URL from the API', async () => {
15 const expectedUrl = 'https://bsky.social/oauth/authorize?client_id=test&request_uri=urn:test'
16
17 server.use(
18 http.get(`${API_URL}/api/auth/login`, ({ request }) => {
19 const url = new URL(request.url)
20 expect(url.searchParams.get('handle')).toBe('jay.bsky.team')
21 return HttpResponse.json({ url: expectedUrl })
22 })
23 )
24
25 const result = await initiateLogin('jay.bsky.team')
26 expect(result).toEqual({ url: expectedUrl })
27 expect(result.url).toBe(expectedUrl)
28 })
29
30 it('passes handle as query parameter', async () => {
31 let receivedHandle: string | null = null
32
33 server.use(
34 http.get(`${API_URL}/api/auth/login`, ({ request }) => {
35 const url = new URL(request.url)
36 receivedHandle = url.searchParams.get('handle')
37 return HttpResponse.json({ url: 'https://example.com/oauth' })
38 })
39 )
40
41 await initiateLogin('gui.do')
42 expect(receivedHandle).toBe('gui.do')
43 })
44
45 it('throws on API error', async () => {
46 server.use(
47 http.get(`${API_URL}/api/auth/login`, () => {
48 return HttpResponse.json({ error: 'Failed to initiate login' }, { status: 502 })
49 })
50 )
51
52 await expect(initiateLogin('bad.handle')).rejects.toThrow('Failed to initiate login')
53 })
54
55 it('throws on invalid handle', async () => {
56 server.use(
57 http.get(`${API_URL}/api/auth/login`, () => {
58 return HttpResponse.json({ error: 'Invalid handle' }, { status: 400 })
59 })
60 )
61
62 await expect(initiateLogin('')).rejects.toThrow('Invalid handle')
63 })
64})
65
66describe('refreshSession', () => {
67 it('returns session data on success', async () => {
68 const result = await refreshSession()
69 expect(result).toHaveProperty('accessToken')
70 expect(result).toHaveProperty('did')
71 expect(result).toHaveProperty('handle')
72 })
73
74 it('throws on expired session', async () => {
75 server.use(
76 http.post(`${API_URL}/api/auth/refresh`, () => {
77 return HttpResponse.json({ error: 'No refresh token' }, { status: 401 })
78 })
79 )
80
81 await expect(refreshSession()).rejects.toThrow('No refresh token')
82 })
83})
84
85describe('initiateCrossPostAuth', () => {
86 it('returns the redirect URL with auth header', async () => {
87 const expectedUrl = 'https://bsky.social/oauth/authorize?scope=crosspost'
88
89 server.use(
90 http.get(`${API_URL}/api/auth/crosspost-authorize`, ({ request }) => {
91 const auth = request.headers.get('Authorization')
92 expect(auth).toBe('Bearer test-token-123')
93 return HttpResponse.json({ url: expectedUrl })
94 })
95 )
96
97 const result = await initiateCrossPostAuth('test-token-123')
98 expect(result).toEqual({ url: expectedUrl })
99 expect(result.url).toBe(expectedUrl)
100 })
101})