ci / api / api (push) Canceled after 0s
ci / module boundaries / boundaries (push) Canceled after 0s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Canceled after 11m29s
ci / db / db (push) Canceled after 11m22s
ci / mobile / mobile (Metro-бандл Android) (push) Canceled after 6m43s
ci / recommender / recommender (push) Canceled after 6m47s
ci / ts / ts (packages + web) (push) Canceled after 1s
33 lines
2.5 KiB
TypeScript
33 lines
2.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { ActivityPublisher } from './activity';
|
|
|
|
const track = { id: '00000000-0000-4000-8000-000000000001' };
|
|
const device = '00000000-0000-4000-8000-000000000002';
|
|
describe('listening activity leases', () => {
|
|
it('publishes actual playback, throttles progress, and clears on pause', async () => {
|
|
let now = 1000; const sent: unknown[] = [];
|
|
const publisher = new ActivityPublisher(async value => { sent.push(value); }, device, () => now);
|
|
publisher.update({ track, playing: false, context: null }); await publisher.idle(); expect(sent).toEqual([]);
|
|
publisher.update({ track, playing: true, context: { type: 'wave' }, positionMs: 123 }); await publisher.idle();
|
|
expect(sent[0]).toMatchObject({ context: 'wave', track_id: track.id, sequence: 1, position_ms: 123 });
|
|
publisher.update({ track, playing: true, context: { type: 'wave' }, positionMs: 900 }); await publisher.idle(); expect(sent).toHaveLength(1);
|
|
now += 20_001; publisher.update({ track, playing: true, context: { type: 'wave' }, positionMs: 20123 }); await publisher.idle(); expect(sent).toHaveLength(2);
|
|
publisher.update({ track, playing: false, context: null }); await publisher.idle(); expect(sent.at(-1)).toMatchObject({ playing: false, sequence: 3 });
|
|
publisher.dispose(); await publisher.idle();
|
|
});
|
|
it('serializes an in-flight play and a final stop without replaying intermediate tracks', async () => {
|
|
let release!: () => void; const waiting = new Promise<void>(r => { release = r; }); const sent: { playing: boolean; sequence: number }[] = [];
|
|
const publisher = new ActivityPublisher(async value => { sent.push(value); if (sent.length === 1) await waiting; }, device);
|
|
publisher.update({ track, playing: true, context: null });
|
|
publisher.update({ track: { id: device }, playing: true, context: null });
|
|
publisher.dispose(); release(); await publisher.idle();
|
|
expect(sent.map(v => [v.playing, v.sequence])).toEqual([[true, 1], [false, 2]]);
|
|
});
|
|
it('only treats UUID collection contexts as playlists', async () => {
|
|
const sent: { context: string }[] = []; const publisher = new ActivityPublisher(async v => { sent.push(v); }, device);
|
|
publisher.update({ track, playing: true, context: { type: 'collection', id: 'likes' } }); await publisher.idle(); expect(sent[0]?.context).toBe('other');
|
|
publisher.update({ track, playing: true, context: { type: 'collection', id: device } }); await publisher.idle(); expect(sent[1]?.context).toBe('playlist');
|
|
publisher.dispose(); await publisher.idle();
|
|
});
|
|
});
|