mirror of
https://git.shipoclu.com/moon/plspace.git
synced 2026-08-13 02:42:30 +00:00
75 lines
2.3 KiB
TypeScript
75 lines
2.3 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
import { ApiClient } from './client'
|
|
|
|
function response(body: unknown, status = 200, headers: Record<string, string> = {}): Response {
|
|
return new Response(JSON.stringify(body), {
|
|
status,
|
|
headers: { 'Content-Type': 'application/json', ...headers },
|
|
})
|
|
}
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals()
|
|
})
|
|
|
|
describe('ApiClient Egregoros compatibility', () => {
|
|
it('refreshes an expired bearer token once and retries the request', async () => {
|
|
const refreshToken = vi.fn().mockResolvedValue('fresh-token')
|
|
const fetchMock = vi
|
|
.fn()
|
|
.mockResolvedValueOnce(response({ error: 'Invalid or expired token' }, 401))
|
|
.mockResolvedValueOnce(response({ id: 'alice' }))
|
|
vi.stubGlobal('fetch', fetchMock)
|
|
const client = new ApiClient('egregoros.example', 'expired-token', refreshToken)
|
|
|
|
await expect(client.get('/api/v1/accounts/verify_credentials')).resolves.toEqual({
|
|
id: 'alice',
|
|
})
|
|
|
|
expect(refreshToken).toHaveBeenCalledOnce()
|
|
expect((fetchMock.mock.calls[0][1].headers as Headers).get('Authorization')).toBe(
|
|
'Bearer expired-token',
|
|
)
|
|
expect((fetchMock.mock.calls[1][1].headers as Headers).get('Authorization')).toBe(
|
|
'Bearer fresh-token',
|
|
)
|
|
})
|
|
|
|
it('does not invent a next page when the server supplied only a prev link', async () => {
|
|
vi.stubGlobal(
|
|
'fetch',
|
|
vi.fn().mockResolvedValue(
|
|
response(
|
|
[{ id: 'newest' }, { id: 'oldest' }],
|
|
200,
|
|
{
|
|
Link: '<https://egregoros.example/api/v1/timelines/public?since_id=newest>; rel="prev"',
|
|
},
|
|
),
|
|
),
|
|
)
|
|
|
|
const page = await new ApiClient('egregoros.example').page<{ id: string }>(
|
|
'/api/v1/timelines/public',
|
|
{ limit: 20 },
|
|
)
|
|
|
|
expect(page.links.sinceId).toBe('newest')
|
|
expect(page.links.maxId).toBeUndefined()
|
|
})
|
|
|
|
it('derives a next cursor only for a full page when Link was stripped entirely', async () => {
|
|
vi.stubGlobal(
|
|
'fetch',
|
|
vi.fn().mockResolvedValue(response([{ id: 'newest' }, { id: 'oldest' }])),
|
|
)
|
|
|
|
const page = await new ApiClient('egregoros.example').page<{ id: string }>(
|
|
'/api/v1/timelines/public',
|
|
{ limit: 2 },
|
|
)
|
|
|
|
expect(page.links.maxId).toBe('oldest')
|
|
})
|
|
})
|