fix(spf): add emptied listener to track-current-time behavior (#1634)

This commit is contained in:
Santiago Puppo
2026-06-01 16:54:58 -03:00
committed by GitHub
parent 3741e8de12
commit efc7c23b7b
2 changed files with 32 additions and 0 deletions
@@ -182,6 +182,31 @@ describe('trackCurrentTime', () => {
cleanup();
});
it('resets currentTime on emptied event (src change reuses engine)', async () => {
const mediaElement = document.createElement('video');
let currentTime = 5.5;
Object.defineProperty(mediaElement, 'currentTime', {
get: () => currentTime,
set: (v: number) => {
currentTime = v;
},
configurable: true,
});
const { state, cleanup } = setupTrackCurrentTime({}, { mediaElement });
await vi.waitFor(() => expect(state.currentTime.get()).toBe(5.5));
// Simulate src change on the same element: the media element load
// algorithm resets currentTime to 0 and dispatches `emptied`.
currentTime = 0;
mediaElement.dispatchEvent(new Event('emptied'));
await vi.waitFor(() => expect(state.currentTime.get()).toBe(0));
cleanup();
});
it('updates currentTime on seeking events (seek while paused)', async () => {
const mediaElement = document.createElement('video');
Object.defineProperty(mediaElement, 'currentTime', { value: 0, writable: true });
@@ -211,6 +236,7 @@ describe('trackCurrentTime', () => {
(mediaElement as any).currentTime = 50.0;
mediaElement.dispatchEvent(new Event('timeupdate'));
mediaElement.dispatchEvent(new Event('seeking'));
mediaElement.dispatchEvent(new Event('emptied'));
await new Promise((resolve) => setTimeout(resolve, 30));
expect(state.currentTime.get()).toBe(0);
@@ -5,6 +5,10 @@
* at the new position when this event dispatches, so buffer management can
* react immediately rather than waiting for `timeupdate`, which does not
* fire while paused.
* - `emptied` — fires when the resource selection algorithm tears down the
* current media (e.g. a new `src` is set on the same element). Re-syncs so
* downstream state doesn't retain the stale playback position from the
* previous source when the engine is reused across src changes.
*
* Also syncs immediately when a media element becomes available.
*
@@ -54,9 +58,11 @@ function trackCurrentTimeSetup({
const sync = () => state.currentTime.set(mediaElement.currentTime);
sync();
const removeEmptied = listen(mediaElement, 'emptied', sync);
const removeTimeupdate = listen(mediaElement, 'timeupdate', sync);
const removeSeeking = listen(mediaElement, 'seeking', sync);
return () => {
removeEmptied();
removeTimeupdate();
removeSeeking();
};