88 lines
3.4 KiB
TypeScript
88 lines
3.4 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest';
|
|
import {
|
|
wireAccountChatEvents,
|
|
type AccountRuntimeEventReporter,
|
|
} from '../src/services/account-runtime-event-wiring.js';
|
|
import type {
|
|
MediaReceivedListener,
|
|
NewReplyListener,
|
|
SyncProgressListener,
|
|
} from '../src/services/chat/index.js';
|
|
|
|
function harness() {
|
|
let progressListener: SyncProgressListener | null = null;
|
|
let replyListener: NewReplyListener | null = null;
|
|
let mediaListener: MediaReceivedListener | null = null;
|
|
const chatService = {
|
|
setProgressListener: vi.fn((listener: SyncProgressListener | null) => { progressListener = listener; }),
|
|
setNewReplyListener: vi.fn((listener: NewReplyListener | null) => { replyListener = listener; }),
|
|
setMediaReceivedListener: vi.fn((listener: MediaReceivedListener | null) => { mediaListener = listener; }),
|
|
};
|
|
const events = {
|
|
conversation: vi.fn(),
|
|
reply: vi.fn(),
|
|
mediaReceived: vi.fn(),
|
|
sync: vi.fn(),
|
|
} satisfies AccountRuntimeEventReporter;
|
|
|
|
wireAccountChatEvents(chatService, events, '@t2_account:reddit.com');
|
|
return {
|
|
events,
|
|
progress: (value: Parameters<SyncProgressListener>[0], completion?: Parameters<SyncProgressListener>[1]) => {
|
|
if (!progressListener) throw new Error('Progress listener was not installed');
|
|
progressListener(value, completion);
|
|
},
|
|
reply: (value: Parameters<NewReplyListener>[0]) => {
|
|
if (!replyListener) throw new Error('Reply listener was not installed');
|
|
replyListener(value);
|
|
},
|
|
media: (value: Parameters<MediaReceivedListener>[0]) => {
|
|
if (!mediaListener) throw new Error('Media listener was not installed');
|
|
mediaListener(value);
|
|
},
|
|
};
|
|
}
|
|
|
|
describe('wireAccountChatEvents', () => {
|
|
it('publishes replies and media received by an account-owned chat service', () => {
|
|
const fixture = harness();
|
|
|
|
fixture.reply({
|
|
conversationId: '!room:reddit.com', replyId: 'event-1', username: 'alice', replySnippet: 'hello',
|
|
});
|
|
fixture.media({ conversationId: '!room:reddit.com', username: 'alice', count: 2 });
|
|
|
|
expect(fixture.events.conversation).toHaveBeenCalledWith({
|
|
id: '!room:reddit.com', state: 'replied', unread: 1,
|
|
});
|
|
expect(fixture.events.reply).toHaveBeenCalledWith({
|
|
conversationId: '!room:reddit.com', id: 'event-1', username: 'alice', body: 'hello',
|
|
});
|
|
expect(fixture.events.mediaReceived).toHaveBeenCalledWith({
|
|
conversationId: '!room:reddit.com', username: 'alice', count: 2,
|
|
});
|
|
});
|
|
|
|
it('publishes account-scoped sync progress and failures', () => {
|
|
const fixture = harness();
|
|
const progress = {
|
|
kind: 'delta', phase: 'starting', current: 0, total: 4, startedAt: 123,
|
|
} as const;
|
|
|
|
fixture.progress(progress);
|
|
fixture.progress({ ...progress, phase: 'listing-rooms', current: 2, label: 'Loading rooms' });
|
|
fixture.progress(null, { status: 'failed', error: 'Matrix unavailable' });
|
|
|
|
expect(fixture.events.sync).toHaveBeenNthCalledWith(1, {
|
|
phase: 'started', id: 'chat-@t2_account:reddit.com-123', kind: 'delta',
|
|
});
|
|
expect(fixture.events.sync).toHaveBeenNthCalledWith(2, {
|
|
phase: 'progress', id: 'chat-@t2_account:reddit.com-123', kind: 'delta',
|
|
current: 2, total: 4, label: 'Loading rooms',
|
|
});
|
|
expect(fixture.events.sync).toHaveBeenNthCalledWith(3, {
|
|
phase: 'failed', id: 'chat-@t2_account:reddit.com-123', kind: 'delta', error: 'Matrix unavailable',
|
|
});
|
|
});
|
|
});
|