mirror of
https://github.com/screenci/screenci.git
synced 2026-09-19 08:57:46 +08:00
013b497efa
- Branding config and asset refs with CLI support. - App session handling replaces the edit-token exchange; login command and sign-in banner. - Docs: branding, signing in, screenshots; login skill reference. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1yyJeUrHajm8whsiHqk4G
98 lines
3.1 KiB
TypeScript
98 lines
3.1 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
import type { DevListenConfig, DevListenDeps } from './src/devListen'
|
|
import {
|
|
DevAuthError,
|
|
deregisterDevListener,
|
|
registerDevListener,
|
|
reportDevSyncState,
|
|
} from './src/devListen'
|
|
|
|
const config: DevListenConfig = {
|
|
apiUrl: 'http://localhost:8787',
|
|
credential: { header: 'X-ScreenCI-Secret', value: 'org-secret' },
|
|
projectName: 'demo',
|
|
machineName: 'laptop',
|
|
}
|
|
|
|
function jsonResponse(body: unknown, status = 200): Response {
|
|
return new Response(JSON.stringify(body), {
|
|
status,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
})
|
|
}
|
|
|
|
function makeDeps(overrides: Partial<DevListenDeps> = {}): DevListenDeps & {
|
|
fetchMock: ReturnType<typeof vi.fn>
|
|
} {
|
|
const fetchMock = vi.fn(async () => jsonResponse({ ok: true }))
|
|
return {
|
|
fetchFn: fetchMock as unknown as typeof fetch,
|
|
fetchMock,
|
|
sleep: vi.fn(async () => {}),
|
|
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
...overrides,
|
|
}
|
|
}
|
|
|
|
describe('registerDevListener', () => {
|
|
it('sends the org credential and the machine name', async () => {
|
|
const deps = makeDeps()
|
|
deps.fetchMock.mockResolvedValueOnce(jsonResponse({ listenerId: 'lst_1' }))
|
|
|
|
const result = await registerDevListener(config, deps)
|
|
|
|
expect(result).toEqual({ listenerId: 'lst_1' })
|
|
const [url, init] = deps.fetchMock.mock.calls[0] as [string, RequestInit]
|
|
expect(url).toBe('http://localhost:8787/cli/dev/register')
|
|
const headers = init.headers as Record<string, string>
|
|
expect(headers['X-ScreenCI-Secret']).toBe('org-secret')
|
|
expect(JSON.parse(init.body as string)).toEqual({
|
|
projectName: 'demo',
|
|
machineName: 'laptop',
|
|
})
|
|
})
|
|
|
|
it('throws DevAuthError on a 401', async () => {
|
|
const deps = makeDeps()
|
|
deps.fetchMock.mockResolvedValueOnce(
|
|
jsonResponse({ error: 'Invalid editor token' }, 401)
|
|
)
|
|
|
|
await expect(registerDevListener(config, deps)).rejects.toBeInstanceOf(
|
|
DevAuthError
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('reportDevSyncState', () => {
|
|
it('reports the syncing video names for the listener', async () => {
|
|
const deps = makeDeps()
|
|
await reportDevSyncState(config, deps, 'lst_1', ['Intro video'])
|
|
const [url, init] = deps.fetchMock.mock.calls[0] as [string, RequestInit]
|
|
expect(url).toBe('http://localhost:8787/cli/dev/sync-state')
|
|
expect(JSON.parse(init.body as string)).toEqual({
|
|
projectName: 'demo',
|
|
listenerId: 'lst_1',
|
|
syncingVideoNames: ['Intro video'],
|
|
})
|
|
})
|
|
|
|
it('tolerates an empty 2xx body', async () => {
|
|
const deps = makeDeps()
|
|
deps.fetchMock.mockResolvedValueOnce(new Response('', { status: 200 }))
|
|
await expect(
|
|
reportDevSyncState(config, deps, 'lst_1', [])
|
|
).resolves.toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('deregisterDevListener', () => {
|
|
it('deregisters with the listener id', async () => {
|
|
const deps = makeDeps()
|
|
await deregisterDevListener(config, deps, 'lst_1')
|
|
const [url, init] = deps.fetchMock.mock.calls[0] as [string, RequestInit]
|
|
expect(url).toBe('http://localhost:8787/cli/dev/deregister')
|
|
expect(JSON.parse(init.body as string).listenerId).toBe('lst_1')
|
|
})
|
|
})
|