50 lines
2.8 KiB
JavaScript
50 lines
2.8 KiB
JavaScript
const { test } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const { progressiveSource, needsAlignment, create } = require('./audio-continuity');
|
|
test('iPhone progressive audio uses saved/EQ sources before remote fallbacks', () => {
|
|
assert.equal(progressiveSource({ localUrl: 'blob:saved', audioUrl: 'remote' }, 'mux'), 'blob:saved');
|
|
assert.equal(progressiveSource({ eqAudioUrl: 'blob:eq', localUrl: 'blob:saved' }), 'blob:eq');
|
|
assert.equal(progressiveSource({ audioUrl: 'audio' }, 'mux'), 'audio');
|
|
assert.equal(progressiveSource({}, 'mux'), 'mux');
|
|
});
|
|
test('small drift and invalid clocks do not trigger an audible seek', () => {
|
|
assert.equal(needsAlignment(50.05, 50), false);
|
|
assert.equal(needsAlignment(49, 50), true);
|
|
assert.equal(needsAlignment(NaN, 50), false);
|
|
});
|
|
test('simultaneous play, visibility and watchdog resumes share one pending play', async () => {
|
|
let finish, calls = 0, seeks = 0;
|
|
const audio = { paused: true, get currentTime() { return 10; }, set currentTime(value) { seeks++; }, play() { calls++; return new Promise(resolve => { finish = resolve; }); } };
|
|
const controller = create();
|
|
controller.resume(audio, { currentTime: 10.05 });
|
|
controller.resume(audio, { currentTime: 12 });
|
|
const pending = controller.play(audio);
|
|
assert.equal(calls, 1); assert.equal(seeks, 0);
|
|
finish(); await pending;
|
|
controller.resume(audio, audio); // never seek an element to itself
|
|
assert.equal(seeks, 0); assert.equal(calls, 2); finish();
|
|
});
|
|
test('rejected autoplay can retry and only paused, misaligned secondaries seek', async () => {
|
|
const controller = create(); let calls = 0;
|
|
const audio = { paused: true, currentTime: 0, play() { calls++; return Promise.reject(new Error('OS suspension')); } };
|
|
await controller.play(audio); await controller.resume(audio, { currentTime: 4 });
|
|
assert.equal(calls, 2); assert.equal(audio.currentTime, 4);
|
|
audio.paused = false; controller.resume(audio, { currentTime: 10 });
|
|
assert.equal(audio.currentTime, 4); assert.equal(calls, 2);
|
|
});
|
|
test('a new play after pause/source reset is not blocked by a stale promise', async () => {
|
|
const controller = create(), finishes = []; let calls = 0;
|
|
const audio = { paused: true, play() { calls++; return new Promise(resolve => finishes.push(resolve)); } };
|
|
const old = controller.play(audio); controller.reset(audio);
|
|
const fresh = controller.play(audio); assert.equal(calls, 2);
|
|
finishes[0](); await old;
|
|
assert.equal(controller.play(audio), fresh); // old completion cannot discard the new request
|
|
finishes[1](); await fresh;
|
|
});
|
|
test('an ended element is never resumed (last song must not restart from 0)', () => {
|
|
let calls = 0;
|
|
const audio = { paused: true, ended: true, currentTime: 200, play() { calls++; return Promise.resolve(); } };
|
|
create().resume(audio, { currentTime: 200 });
|
|
assert.equal(calls, 0);
|
|
});
|