102 lines
3.4 KiB
TypeScript
102 lines
3.4 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
import { HttpAPIClient } from '@renderer/api/httpClient';
|
|
|
|
class FakeEventSource {
|
|
onopen: (() => void) | null = null;
|
|
onerror: (() => void) | null = null;
|
|
addEventListener = vi.fn();
|
|
close = vi.fn();
|
|
}
|
|
|
|
describe('HttpAPIClient memberWorkSync', () => {
|
|
let fetchMock: ReturnType<typeof vi.fn>;
|
|
let eventSourceMock: ReturnType<typeof vi.fn>;
|
|
|
|
beforeEach(() => {
|
|
fetchMock = vi.fn(async () => jsonResponse({ ok: true }));
|
|
eventSourceMock = vi.fn(() => new FakeEventSource());
|
|
vi.stubGlobal('fetch', fetchMock);
|
|
vi.stubGlobal('EventSource', eventSourceMock);
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it('maps browser-mode member work sync calls to the HTTP routes', async () => {
|
|
const client = new HttpAPIClient('http://127.0.0.1:53123');
|
|
fetchMock
|
|
.mockResolvedValueOnce(jsonResponse({ state: 'needs_sync' }))
|
|
.mockResolvedValueOnce(jsonResponse({ state: 'still_working' }))
|
|
.mockResolvedValueOnce(jsonResponse({ memberCount: 1 }))
|
|
.mockResolvedValueOnce(jsonResponse({ accepted: true }));
|
|
|
|
await expect(
|
|
client.memberWorkSync.getStatus({ teamName: 'demo team', memberName: 'bob/qa' })
|
|
).resolves.toEqual({ state: 'needs_sync' });
|
|
await expect(
|
|
client.memberWorkSync.refreshStatus({ teamName: 'demo team', memberName: 'bob/qa' })
|
|
).resolves.toEqual({ state: 'still_working' });
|
|
await expect(client.memberWorkSync.getMetrics({ teamName: 'demo team' })).resolves.toEqual({
|
|
memberCount: 1,
|
|
});
|
|
await expect(
|
|
client.memberWorkSync.report({
|
|
teamName: 'demo team',
|
|
memberName: 'bob/qa',
|
|
state: 'still_working',
|
|
agendaFingerprint: 'agenda:v1:test',
|
|
taskIds: ['task-a'],
|
|
source: 'app',
|
|
})
|
|
).resolves.toEqual({ accepted: true });
|
|
|
|
expect(eventSourceMock).toHaveBeenCalledWith('http://127.0.0.1:53123/api/events');
|
|
expect(fetchMock).toHaveBeenNthCalledWith(
|
|
1,
|
|
'http://127.0.0.1:53123/api/teams/demo%20team/member-work-sync/bob%2Fqa',
|
|
expect.objectContaining({ signal: expect.any(AbortSignal) })
|
|
);
|
|
expect(fetchMock).toHaveBeenNthCalledWith(
|
|
2,
|
|
'http://127.0.0.1:53123/api/teams/demo%20team/member-work-sync/bob%2Fqa/refresh',
|
|
expect.objectContaining({
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({}),
|
|
signal: expect.any(AbortSignal),
|
|
})
|
|
);
|
|
expect(fetchMock).toHaveBeenNthCalledWith(
|
|
3,
|
|
'http://127.0.0.1:53123/api/teams/demo%20team/member-work-sync/metrics',
|
|
expect.objectContaining({ signal: expect.any(AbortSignal) })
|
|
);
|
|
expect(fetchMock).toHaveBeenNthCalledWith(
|
|
4,
|
|
'http://127.0.0.1:53123/api/teams/demo%20team/member-work-sync/report',
|
|
expect.objectContaining({
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
teamName: 'demo team',
|
|
memberName: 'bob/qa',
|
|
state: 'still_working',
|
|
agendaFingerprint: 'agenda:v1:test',
|
|
taskIds: ['task-a'],
|
|
source: 'app',
|
|
}),
|
|
signal: expect.any(AbortSignal),
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
function jsonResponse(body: unknown): Response {
|
|
return new Response(JSON.stringify(body), {
|
|
status: 200,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
});
|
|
}
|