test: Split test utilities to improve test times (#2622)
This commit is contained in:
+12
-12
@@ -87,7 +87,7 @@ describe('media-source', () => {
|
||||
const instance = createBrowserMediaSource();
|
||||
|
||||
expect(instance?.isTypeSupported('video/mp4')).toBe(false);
|
||||
expect(FakeManagedMediaSource.isTypeSupported).toBeCalledWith('video/mp4');
|
||||
expect(FakeManagedMediaSource.isTypeSupported).toHaveBeenCalledWith('video/mp4');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -99,7 +99,7 @@ describe('media-source', () => {
|
||||
const video = document.createElement('video');
|
||||
instance?.attach(video);
|
||||
|
||||
expect(createObjectURL).toBeCalledTimes(1);
|
||||
expect(createObjectURL).toHaveBeenCalledTimes(1);
|
||||
expect(video.src).toContain('blob:fake-url');
|
||||
expect(video.srcObject).toBeNull();
|
||||
});
|
||||
@@ -111,15 +111,15 @@ describe('media-source', () => {
|
||||
const video = document.createElement('video');
|
||||
instance?.attach(video);
|
||||
|
||||
expect(revokeObjectURL).not.toBeCalled();
|
||||
expect(revokeObjectURL).not.toHaveBeenCalled();
|
||||
|
||||
FakeMediaSource.instances[0].dispatchEvent(new Event('sourceopen'));
|
||||
|
||||
expect(revokeObjectURL).toBeCalledWith('blob:fake-url');
|
||||
expect(revokeObjectURL).toHaveBeenCalledWith('blob:fake-url');
|
||||
|
||||
instance?.detach(video);
|
||||
|
||||
expect(revokeObjectURL).toBeCalledTimes(1);
|
||||
expect(revokeObjectURL).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should delegate isTypeSupported to MediaSource', () => {
|
||||
@@ -129,7 +129,7 @@ describe('media-source', () => {
|
||||
const instance = createBrowserMediaSource();
|
||||
|
||||
expect(instance?.isTypeSupported('video/mp4')).toBe(false);
|
||||
expect(FakeMediaSource.isTypeSupported).toBeCalledWith('video/mp4');
|
||||
expect(FakeMediaSource.isTypeSupported).toHaveBeenCalledWith('video/mp4');
|
||||
});
|
||||
|
||||
it('should detach by clearing src and revoking the object URL', () => {
|
||||
@@ -140,7 +140,7 @@ describe('media-source', () => {
|
||||
instance?.attach(video);
|
||||
instance?.detach(video);
|
||||
|
||||
expect(revokeObjectURL).toBeCalledWith('blob:fake-url');
|
||||
expect(revokeObjectURL).toHaveBeenCalledWith('blob:fake-url');
|
||||
expect(video.getAttribute('src')).toBe('');
|
||||
});
|
||||
|
||||
@@ -153,7 +153,7 @@ describe('media-source', () => {
|
||||
instance?.detach(video);
|
||||
instance?.detach(video);
|
||||
|
||||
expect(revokeObjectURL).toBeCalledTimes(1);
|
||||
expect(revokeObjectURL).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -170,12 +170,12 @@ describe('media-source', () => {
|
||||
const mediaSource = video.srcObject;
|
||||
assert(mediaSource instanceof FakeManagedMediaSource);
|
||||
mediaSource.dispatchEvent(new Event('sourceopen'));
|
||||
expect(callback).toBeCalledTimes(1);
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
|
||||
unsubscribe?.();
|
||||
|
||||
mediaSource.dispatchEvent(new Event('sourceopen'));
|
||||
expect(callback).toBeCalledTimes(1);
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should delegate addSourceBuffer', () => {
|
||||
@@ -188,7 +188,7 @@ describe('media-source', () => {
|
||||
|
||||
const mediaSource = video.srcObject;
|
||||
assert(mediaSource instanceof FakeManagedMediaSource);
|
||||
expect(mediaSource.addSourceBuffer).toBeCalledWith(
|
||||
expect(mediaSource.addSourceBuffer).toHaveBeenCalledWith(
|
||||
'video/mp4; codecs="avc1.640029"',
|
||||
);
|
||||
});
|
||||
@@ -203,7 +203,7 @@ describe('media-source', () => {
|
||||
|
||||
const mediaSource = video.srcObject;
|
||||
assert(mediaSource instanceof FakeManagedMediaSource);
|
||||
expect(mediaSource.setLiveSeekableRange).toBeCalledWith(10, 20);
|
||||
expect(mediaSource.setLiveSeekableRange).toHaveBeenCalledWith(10, 20);
|
||||
});
|
||||
|
||||
it('should report open only while the media source readyState is open', () => {
|
||||
|
||||
+16
-16
@@ -72,10 +72,10 @@ describe('ImageSurfaceController', () => {
|
||||
|
||||
await controller.showFrame(createFrame());
|
||||
|
||||
expect(decoder.decode).toBeCalledTimes(1);
|
||||
expect(URL.createObjectURL).toBeCalledTimes(1);
|
||||
expect(decoder.decode).toHaveBeenCalledTimes(1);
|
||||
expect(URL.createObjectURL).toHaveBeenCalledTimes(1);
|
||||
expect(image.getAttribute('src')).toBe(createdURLs()[0]);
|
||||
expect(URL.revokeObjectURL).not.toBeCalled();
|
||||
expect(URL.revokeObjectURL).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should revoke the previous frame when showing the next', async () => {
|
||||
@@ -85,8 +85,8 @@ describe('ImageSurfaceController', () => {
|
||||
await controller.showFrame(createFrame());
|
||||
|
||||
expect(image.getAttribute('src')).toBe(createdURLs()[1]);
|
||||
expect(URL.revokeObjectURL).toBeCalledTimes(1);
|
||||
expect(URL.revokeObjectURL).toBeCalledWith(createdURLs()[0]);
|
||||
expect(URL.revokeObjectURL).toHaveBeenCalledTimes(1);
|
||||
expect(URL.revokeObjectURL).toHaveBeenCalledWith(createdURLs()[0]);
|
||||
});
|
||||
|
||||
it('should keep showing the previous frame until the next has decoded', async () => {
|
||||
@@ -110,13 +110,13 @@ describe('ImageSurfaceController', () => {
|
||||
// The next frame is still decoding off-DOM, so the visible <img> is
|
||||
// untouched and the previous URL stays valid (revoking it would blank it).
|
||||
expect(image.getAttribute('src')).toBe(createdURLs()[0]);
|
||||
expect(URL.revokeObjectURL).not.toBeCalled();
|
||||
expect(URL.revokeObjectURL).not.toHaveBeenCalled();
|
||||
|
||||
releaseSecond();
|
||||
await flushPromises();
|
||||
|
||||
expect(image.getAttribute('src')).toBe(createdURLs()[1]);
|
||||
expect(URL.revokeObjectURL).toBeCalledWith(createdURLs()[0]);
|
||||
expect(URL.revokeObjectURL).toHaveBeenCalledWith(createdURLs()[0]);
|
||||
});
|
||||
|
||||
it('should present only the newest frame while a decode is in flight', async () => {
|
||||
@@ -130,13 +130,13 @@ describe('ImageSurfaceController', () => {
|
||||
await flushPromises();
|
||||
|
||||
// Only the first frame's decode has started; the rest wait behind it.
|
||||
expect(URL.createObjectURL).toBeCalledTimes(1);
|
||||
expect(URL.createObjectURL).toHaveBeenCalledTimes(1);
|
||||
|
||||
releaseDecode();
|
||||
await flushPromises();
|
||||
|
||||
// The middle frame was superseded, so only the newest is presented next.
|
||||
expect(URL.createObjectURL).toBeCalledTimes(2);
|
||||
expect(URL.createObjectURL).toHaveBeenCalledTimes(2);
|
||||
expect(image.getAttribute('src')).toBe(createdURLs()[1]);
|
||||
});
|
||||
|
||||
@@ -148,7 +148,7 @@ describe('ImageSurfaceController', () => {
|
||||
await controller.showFrame(createFrame());
|
||||
|
||||
expect(image.hasAttribute('src')).toBe(false);
|
||||
expect(URL.revokeObjectURL).toBeCalledWith(createdURLs()[0]);
|
||||
expect(URL.revokeObjectURL).toHaveBeenCalledWith(createdURLs()[0]);
|
||||
});
|
||||
|
||||
it('should not paint a frame that decoded after the surface detached', async () => {
|
||||
@@ -165,7 +165,7 @@ describe('ImageSurfaceController', () => {
|
||||
await flushPromises();
|
||||
|
||||
expect(image.hasAttribute('src')).toBe(false);
|
||||
expect(URL.revokeObjectURL).toBeCalledWith(createdURLs()[0]);
|
||||
expect(URL.revokeObjectURL).toHaveBeenCalledWith(createdURLs()[0]);
|
||||
});
|
||||
|
||||
it('should do nothing without an image element', async () => {
|
||||
@@ -173,7 +173,7 @@ describe('ImageSurfaceController', () => {
|
||||
|
||||
await controller.showFrame(createFrame());
|
||||
|
||||
expect(URL.createObjectURL).not.toBeCalled();
|
||||
expect(URL.createObjectURL).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not paint onto a detached element', async () => {
|
||||
@@ -181,7 +181,7 @@ describe('ImageSurfaceController', () => {
|
||||
|
||||
await controller.showFrame(createFrame());
|
||||
|
||||
expect(URL.createObjectURL).not.toBeCalled();
|
||||
expect(URL.createObjectURL).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -192,7 +192,7 @@ describe('ImageSurfaceController', () => {
|
||||
|
||||
controller.reset();
|
||||
|
||||
expect(URL.revokeObjectURL).toBeCalledWith(createdURLs()[0]);
|
||||
expect(URL.revokeObjectURL).toHaveBeenCalledWith(createdURLs()[0]);
|
||||
expect(image.hasAttribute('src')).toBe(false);
|
||||
});
|
||||
|
||||
@@ -201,7 +201,7 @@ describe('ImageSurfaceController', () => {
|
||||
|
||||
controller.reset();
|
||||
|
||||
expect(URL.revokeObjectURL).not.toBeCalled();
|
||||
expect(URL.revokeObjectURL).not.toHaveBeenCalled();
|
||||
expect(image.hasAttribute('src')).toBe(false);
|
||||
});
|
||||
|
||||
@@ -226,7 +226,7 @@ describe('ImageSurfaceController', () => {
|
||||
const controller = new ImageSurfaceController(createLitElement(), () => null);
|
||||
|
||||
expect(() => controller.reset()).not.toThrow();
|
||||
expect(URL.revokeObjectURL).not.toBeCalled();
|
||||
expect(URL.revokeObjectURL).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('OffscreenImage', () => {
|
||||
const offscreen = new OffscreenImage(create);
|
||||
|
||||
expect(offscreen.get()).toBe(offscreen.get());
|
||||
expect(create).toBeCalledTimes(1);
|
||||
expect(create).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should create an image with the default factory when none is injected', () => {
|
||||
@@ -43,7 +43,7 @@ describe('OffscreenImage', () => {
|
||||
offscreen.clear();
|
||||
offscreen.get();
|
||||
|
||||
expect(create).toBeCalledTimes(2);
|
||||
expect(create).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should tolerate clear when no image is held', () => {
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('OffscreenVideo', () => {
|
||||
const offscreen = new OffscreenVideo(create);
|
||||
|
||||
expect(offscreen.get()).toBe(offscreen.get());
|
||||
expect(create).toBeCalledTimes(1);
|
||||
expect(create).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should create a video with the default factory when none is injected', () => {
|
||||
@@ -48,7 +48,7 @@ describe('OffscreenVideo', () => {
|
||||
offscreen.clear();
|
||||
offscreen.get();
|
||||
|
||||
expect(create).toBeCalledTimes(2);
|
||||
expect(create).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should tolerate clear when no video is held', () => {
|
||||
|
||||
+84
-84
@@ -238,7 +238,7 @@ describe('Go2RTCSessionController', () => {
|
||||
const { session, surfaces, createWebSocket } = setup();
|
||||
session.connect('https://host/api/ws?src=camera', surfaces, ['mse']);
|
||||
|
||||
expect(createWebSocket).toBeCalledWith('wss://host/api/ws?src=camera');
|
||||
expect(createWebSocket).toHaveBeenCalledWith('wss://host/api/ws?src=camera');
|
||||
});
|
||||
|
||||
it('should be idempotent for an unchanged target', () => {
|
||||
@@ -246,7 +246,7 @@ describe('Go2RTCSessionController', () => {
|
||||
session.connect('http://host/api/ws?src=camera', surfaces, ['mse']);
|
||||
session.connect('http://host/api/ws?src=camera', surfaces, ['mse']);
|
||||
|
||||
expect(createWebSocket).toBeCalledTimes(1);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should reconnect when the URL changes', () => {
|
||||
@@ -254,8 +254,8 @@ describe('Go2RTCSessionController', () => {
|
||||
session.connect('http://host/api/ws?src=camera', surfaces, ['mse']);
|
||||
session.connect('http://host/api/ws?src=other', surfaces, ['mse']);
|
||||
|
||||
expect(websockets[0].close).toBeCalled();
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(websockets[0].close).toHaveBeenCalled();
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should reconnect when the modes change', () => {
|
||||
@@ -263,8 +263,8 @@ describe('Go2RTCSessionController', () => {
|
||||
session.connect('http://host/api/ws?src=camera', surfaces, ['mse']);
|
||||
session.connect('http://host/api/ws?src=camera', surfaces, ['webrtc']);
|
||||
|
||||
expect(websockets[0].close).toBeCalled();
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(websockets[0].close).toHaveBeenCalled();
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should be idempotent when omitted modes match the default', () => {
|
||||
@@ -272,7 +272,7 @@ describe('Go2RTCSessionController', () => {
|
||||
session.connect('http://host/api/ws?src=camera', surfaces);
|
||||
session.connect('http://host/api/ws?src=camera', surfaces, [...GO2RTC_MODES]);
|
||||
|
||||
expect(createWebSocket).toBeCalledTimes(1);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should construct real collaborators by default', () => {
|
||||
@@ -293,8 +293,8 @@ describe('Go2RTCSessionController', () => {
|
||||
session.connect('http://host/api/ws?src=camera', surfaces);
|
||||
websockets[0].fireOpen();
|
||||
|
||||
expect(createBinarySource).toBeCalledTimes(1);
|
||||
expect(createWebRTCSource).toBeCalledTimes(1);
|
||||
expect(createBinarySource).toHaveBeenCalledTimes(1);
|
||||
expect(createWebRTCSource).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should keep the channel open when the binary lane drains synchronously while WebRTC is configured', () => {
|
||||
@@ -309,11 +309,11 @@ describe('Go2RTCSessionController', () => {
|
||||
session.connect('http://host/api/ws?src=camera', surfaces, ['mse', 'webrtc']);
|
||||
websockets[0].fireOpen();
|
||||
|
||||
expect(createWebRTCSource).toBeCalledTimes(1);
|
||||
expect(websockets[0].close).not.toBeCalled();
|
||||
expect(createWebRTCSource).toHaveBeenCalledTimes(1);
|
||||
expect(websockets[0].close).not.toHaveBeenCalled();
|
||||
|
||||
vi.advanceTimersByTime(2 * 1000);
|
||||
expect(createWebSocket).toBeCalledTimes(1);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -324,9 +324,9 @@ describe('Go2RTCSessionController', () => {
|
||||
session.connect('http://host/api/ws?src=camera', surfaces, ['mse']);
|
||||
websockets[0].fireOpen();
|
||||
|
||||
expect(createBinarySource).toBeCalledTimes(1);
|
||||
expect(createBinarySource).toHaveBeenCalledTimes(1);
|
||||
expect(createBinarySource.mock.calls[0][0]).toBe('mse');
|
||||
expect(binarySources[0].start).toBeCalled();
|
||||
expect(binarySources[0].start).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should report loaded media from the binary source', () => {
|
||||
@@ -336,7 +336,7 @@ describe('Go2RTCSessionController', () => {
|
||||
websockets[0].fireOpen();
|
||||
binaryContexts[0].callbacks.loadedCallback();
|
||||
|
||||
expect(mediaLoadedCallback).toBeCalledWith(
|
||||
expect(mediaLoadedCallback).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ technology: ['mse'] }),
|
||||
);
|
||||
});
|
||||
@@ -354,11 +354,11 @@ describe('Go2RTCSessionController', () => {
|
||||
websockets[0].fireOpen();
|
||||
binaryContexts[0].callbacks.failedCallback('media_error');
|
||||
|
||||
expect(binarySources[0].stop).toBeCalled();
|
||||
expect(websockets[0].close).toBeCalled();
|
||||
expect(binarySources[0].stop).toHaveBeenCalled();
|
||||
expect(websockets[0].close).toHaveBeenCalled();
|
||||
|
||||
vi.advanceTimersByTime(2 * 1000);
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should fall back through the binary modes in order', () => {
|
||||
@@ -385,9 +385,9 @@ describe('Go2RTCSessionController', () => {
|
||||
|
||||
// The last binary mode failing reconnects.
|
||||
binaryContexts[2].callbacks.failedCallback('media_error');
|
||||
expect(websockets[0].close).toBeCalled();
|
||||
expect(websockets[0].close).toHaveBeenCalled();
|
||||
vi.advanceTimersByTime(2 * 1000);
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should reconnect when the factory declines the mode', () => {
|
||||
@@ -397,9 +397,9 @@ describe('Go2RTCSessionController', () => {
|
||||
session.connect('http://host/api/ws?src=camera', surfaces, ['mse']);
|
||||
websockets[0].fireOpen();
|
||||
|
||||
expect(websockets[0].close).toBeCalled();
|
||||
expect(websockets[0].close).toHaveBeenCalled();
|
||||
vi.advanceTimersByTime(2 * 1000);
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should report loaded media with the video surface controller for MSE', () => {
|
||||
@@ -415,7 +415,7 @@ describe('Go2RTCSessionController', () => {
|
||||
expect(
|
||||
setupResult.mediaLoadedCallback.mock.calls[0][0].mediaPlayerController,
|
||||
).toBe(setupResult.videoController);
|
||||
expect(setupResult.surfaceCommittedCallback).toBeCalledWith('video');
|
||||
expect(setupResult.surfaceCommittedCallback).toHaveBeenCalledWith('video');
|
||||
});
|
||||
|
||||
it('should report loaded media with the image surface controller for MJPEG', () => {
|
||||
@@ -431,7 +431,7 @@ describe('Go2RTCSessionController', () => {
|
||||
expect(
|
||||
setupResult.mediaLoadedCallback.mock.calls[0][0].mediaPlayerController,
|
||||
).toBe(setupResult.imageController);
|
||||
expect(setupResult.surfaceCommittedCallback).toBeCalledWith('image');
|
||||
expect(setupResult.surfaceCommittedCallback).toHaveBeenCalledWith('image');
|
||||
});
|
||||
|
||||
it('should hide controls temporarily on load', () => {
|
||||
@@ -471,7 +471,7 @@ describe('Go2RTCSessionController', () => {
|
||||
binaryContexts[0].callbacks.loadedCallback();
|
||||
|
||||
// Committed once, but the reload refreshed the reported dimensions.
|
||||
expect(surfaceCommittedCallback).toBeCalledTimes(1);
|
||||
expect(surfaceCommittedCallback).toHaveBeenCalledTimes(1);
|
||||
expect(mediaLoadedCallback.mock.calls[0][0]).toEqual(
|
||||
expect.objectContaining({ width: 640, height: 480 }),
|
||||
);
|
||||
@@ -494,7 +494,7 @@ describe('Go2RTCSessionController', () => {
|
||||
session.connect('http://host/api/ws?src=camera', surfaces, ['webrtc']);
|
||||
websockets[0].fireOpen();
|
||||
|
||||
expect(createVideoElement).not.toBeCalled();
|
||||
expect(createVideoElement).not.toHaveBeenCalled();
|
||||
expect(webRTCContexts[0].target.video).toBe(video);
|
||||
});
|
||||
|
||||
@@ -505,10 +505,10 @@ describe('Go2RTCSessionController', () => {
|
||||
websockets[0].fireOpen();
|
||||
webRTCContexts[0].callbacks.loadedCallback();
|
||||
|
||||
expect(mediaLoadedCallback).toBeCalledWith(
|
||||
expect(mediaLoadedCallback).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ technology: ['webrtc'] }),
|
||||
);
|
||||
expect(websockets[0].close).toBeCalled();
|
||||
expect(websockets[0].close).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reconnect when the committed WebRTC stream fails', () => {
|
||||
@@ -521,7 +521,7 @@ describe('Go2RTCSessionController', () => {
|
||||
|
||||
expect(video.srcObject).toBeNull();
|
||||
vi.advanceTimersByTime(2 * 1000);
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should pre-arm the WebRTC source with the current microphone stream', () => {
|
||||
@@ -552,7 +552,7 @@ describe('Go2RTCSessionController', () => {
|
||||
|
||||
audioTransceiver.receiver.track.setMuted(true);
|
||||
|
||||
expect(mediaLoadedCallback).toBeCalledTimes(1);
|
||||
expect(mediaLoadedCallback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -561,8 +561,8 @@ describe('Go2RTCSessionController', () => {
|
||||
const setupResult = setup();
|
||||
startSourceRace(setupResult);
|
||||
|
||||
expect(setupResult.createBinarySource).toBeCalledTimes(1);
|
||||
expect(setupResult.createVideoElement).toBeCalledTimes(1);
|
||||
expect(setupResult.createBinarySource).toHaveBeenCalledTimes(1);
|
||||
expect(setupResult.createVideoElement).toHaveBeenCalledTimes(1);
|
||||
expect(setupResult.webRTCContexts[0].target.video).toBe(
|
||||
setupResult.offscreenVideos[0],
|
||||
);
|
||||
@@ -579,9 +579,9 @@ describe('Go2RTCSessionController', () => {
|
||||
setupResult.webRTCContexts[0].callbacks.loadedCallback();
|
||||
|
||||
expect(setupResult.video.srcObject).toBe(setupResult.webRTCStream.asMediaStream());
|
||||
expect(setupResult.binarySources[0].stop).toBeCalled();
|
||||
expect(setupResult.websockets[0].close).toBeCalled();
|
||||
expect(setupResult.mediaLoadedCallback).toBeCalledWith(
|
||||
expect(setupResult.binarySources[0].stop).toHaveBeenCalled();
|
||||
expect(setupResult.websockets[0].close).toHaveBeenCalled();
|
||||
expect(setupResult.mediaLoadedCallback).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ technology: ['webrtc'] }),
|
||||
);
|
||||
});
|
||||
@@ -595,9 +595,9 @@ describe('Go2RTCSessionController', () => {
|
||||
setupResult.binaryContexts[0].callbacks.loadedCallback();
|
||||
setupResult.webRTCContexts[0].callbacks.loadedCallback();
|
||||
|
||||
expect(setupResult.webRTCSources[0].stop).toBeCalled();
|
||||
expect(setupResult.binarySources[0].stop).not.toBeCalled();
|
||||
expect(setupResult.websockets[0].close).not.toBeCalled();
|
||||
expect(setupResult.webRTCSources[0].stop).toHaveBeenCalled();
|
||||
expect(setupResult.binarySources[0].stop).not.toHaveBeenCalled();
|
||||
expect(setupResult.websockets[0].close).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should adopt WebRTC that wins before the binary source loads', () => {
|
||||
@@ -606,7 +606,7 @@ describe('Go2RTCSessionController', () => {
|
||||
setupResult.webRTCContexts[0].callbacks.loadedCallback();
|
||||
|
||||
expect(setupResult.video.srcObject).toBe(setupResult.webRTCStream.asMediaStream());
|
||||
expect(setupResult.binarySources[0].stop).toBeCalled();
|
||||
expect(setupResult.binarySources[0].stop).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not reconnect when a racing binary fails while WebRTC continues', () => {
|
||||
@@ -614,7 +614,7 @@ describe('Go2RTCSessionController', () => {
|
||||
startSourceRace(setupResult);
|
||||
setupResult.binaryContexts[0].callbacks.failedCallback('media_error');
|
||||
|
||||
expect(setupResult.websockets[0].close).not.toBeCalled();
|
||||
expect(setupResult.websockets[0].close).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not reconnect when a racing WebRTC fails while binary continues', () => {
|
||||
@@ -622,8 +622,8 @@ describe('Go2RTCSessionController', () => {
|
||||
startSourceRace(setupResult);
|
||||
setupResult.webRTCContexts[0].callbacks.failedCallback('connect_timeout');
|
||||
|
||||
expect(setupResult.webRTCSources[0].stop).toBeCalled();
|
||||
expect(setupResult.websockets[0].close).not.toBeCalled();
|
||||
expect(setupResult.webRTCSources[0].stop).toHaveBeenCalled();
|
||||
expect(setupResult.websockets[0].close).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reconnect when both racing lanes fail', () => {
|
||||
@@ -632,9 +632,9 @@ describe('Go2RTCSessionController', () => {
|
||||
setupResult.binaryContexts[0].callbacks.failedCallback('media_error');
|
||||
setupResult.webRTCContexts[0].callbacks.failedCallback('connect_timeout');
|
||||
|
||||
expect(setupResult.websockets[0].close).toBeCalled();
|
||||
expect(setupResult.websockets[0].close).toHaveBeenCalled();
|
||||
vi.advanceTimersByTime(2 * 1000);
|
||||
expect(setupResult.createWebSocket).toBeCalledTimes(2);
|
||||
expect(setupResult.createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should ignore a duplicate loaded callback from a lost WebRTC lane', () => {
|
||||
@@ -648,7 +648,7 @@ describe('Go2RTCSessionController', () => {
|
||||
// WebRTC lost and stopped; a late duplicate callback is ignored.
|
||||
setupResult.webRTCContexts[0].callbacks.loadedCallback();
|
||||
|
||||
expect(setupResult.webRTCSources[0].stop).toBeCalledTimes(1);
|
||||
expect(setupResult.webRTCSources[0].stop).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -665,7 +665,7 @@ describe('Go2RTCSessionController', () => {
|
||||
|
||||
setupResult.binaryContexts[0].targets.image.showFrame(frame);
|
||||
|
||||
expect(setupResult.showFrame).toBeCalledWith(frame);
|
||||
expect(setupResult.showFrame).toHaveBeenCalledWith(frame);
|
||||
});
|
||||
|
||||
it('should reset the outgoing video surface when falling back to an image mode', () => {
|
||||
@@ -682,7 +682,7 @@ describe('Go2RTCSessionController', () => {
|
||||
|
||||
expect(video.srcObject).toBeNull();
|
||||
// The image surface, being committed to, is not reset.
|
||||
expect(reset).not.toBeCalled();
|
||||
expect(reset).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reset the outgoing image surface when WebRTC wins over an image mode', () => {
|
||||
@@ -700,7 +700,7 @@ describe('Go2RTCSessionController', () => {
|
||||
setupResult.binaryContexts[0].callbacks.loadedCallback();
|
||||
setupResult.webRTCContexts[0].callbacks.loadedCallback();
|
||||
|
||||
expect(setupResult.reset).toBeCalled();
|
||||
expect(setupResult.reset).toHaveBeenCalled();
|
||||
expect(setupResult.surfaceCommittedCallback).toHaveBeenLastCalledWith('video');
|
||||
});
|
||||
|
||||
@@ -715,7 +715,7 @@ describe('Go2RTCSessionController', () => {
|
||||
websockets[0].fireOpen();
|
||||
binaryContexts[0].callbacks.loadedCallback();
|
||||
|
||||
expect(mediaLoadedCallback).not.toBeCalled();
|
||||
expect(mediaLoadedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reconnect when handed a new surfaces object for the same target', () => {
|
||||
@@ -728,8 +728,8 @@ describe('Go2RTCSessionController', () => {
|
||||
'mse',
|
||||
]);
|
||||
|
||||
expect(websockets[0].close).toBeCalled();
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(websockets[0].close).toHaveBeenCalled();
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should abandon the binary lane when the video element is detached at open', () => {
|
||||
@@ -739,7 +739,7 @@ describe('Go2RTCSessionController', () => {
|
||||
setVideoElement(null);
|
||||
websockets[0].fireOpen();
|
||||
|
||||
expect(createBinarySource).not.toBeCalled();
|
||||
expect(createBinarySource).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should abandon a WebRTC-only lane when the video element is detached at open', () => {
|
||||
@@ -749,7 +749,7 @@ describe('Go2RTCSessionController', () => {
|
||||
setVideoElement(null);
|
||||
websockets[0].fireOpen();
|
||||
|
||||
expect(createWebRTCSource).not.toBeCalled();
|
||||
expect(createWebRTCSource).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should still commit a WebRTC win when the video element is detached', () => {
|
||||
@@ -762,8 +762,8 @@ describe('Go2RTCSessionController', () => {
|
||||
// No element to attach the stream to, but the win still tears down the
|
||||
// binary lane and reports loaded media (dimensions come from the
|
||||
// off-screen element).
|
||||
expect(setupResult.binarySources[0].stop).toBeCalled();
|
||||
expect(setupResult.mediaLoadedCallback).toBeCalledWith(
|
||||
expect(setupResult.binarySources[0].stop).toHaveBeenCalled();
|
||||
expect(setupResult.mediaLoadedCallback).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ technology: ['webrtc'] }),
|
||||
);
|
||||
});
|
||||
@@ -782,7 +782,7 @@ describe('Go2RTCSessionController', () => {
|
||||
setVideoElement(null);
|
||||
|
||||
expect(() => binaryContexts[0].callbacks.loadedCallback()).not.toThrow();
|
||||
expect(mediaLoadedCallback).not.toBeCalled();
|
||||
expect(mediaLoadedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should skip resetting a detached video surface on a switch to image', () => {
|
||||
@@ -826,7 +826,7 @@ describe('Go2RTCSessionController', () => {
|
||||
// Re-attached in time for the retry, which then reconnects normally.
|
||||
setVideoElement(video);
|
||||
vi.advanceTimersByTime(2 * 1000);
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -840,7 +840,7 @@ describe('Go2RTCSessionController', () => {
|
||||
]).asMediaStream();
|
||||
session.setMicrophoneStream(micStream);
|
||||
|
||||
expect(webRTCSources[0].setMicrophoneStream).toBeCalledWith(micStream);
|
||||
expect(webRTCSources[0].setMicrophoneStream).toHaveBeenCalledWith(micStream);
|
||||
});
|
||||
|
||||
it('should tolerate a microphone change with no WebRTC source', () => {
|
||||
@@ -857,9 +857,9 @@ describe('Go2RTCSessionController', () => {
|
||||
websockets[0].fireOpen();
|
||||
websockets[0].fireClose();
|
||||
|
||||
expect(binarySources[0].stop).toBeCalled();
|
||||
expect(binarySources[0].stop).toHaveBeenCalled();
|
||||
vi.advanceTimersByTime(2 * 1000);
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should escalate via the error callback after exhausting reconnect attempts', () => {
|
||||
@@ -877,13 +877,13 @@ describe('Go2RTCSessionController', () => {
|
||||
websockets[3].fireOpen();
|
||||
websockets[3].fireClose();
|
||||
|
||||
expect(createWebSocket).toBeCalledTimes(4);
|
||||
expect(errorCallback).toBeCalledTimes(1);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(4);
|
||||
expect(errorCallback).toHaveBeenCalledTimes(1);
|
||||
|
||||
// The socket dropped with no source reporting a cause.
|
||||
expect(errorCallback).toBeCalledWith(null);
|
||||
expect(errorCallback).toHaveBeenCalledWith(null);
|
||||
vi.advanceTimersByTime(2 * 1000);
|
||||
expect(createWebSocket).toBeCalledTimes(4);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
|
||||
it('should escalate with the most recent source failure reason', () => {
|
||||
@@ -901,7 +901,7 @@ describe('Go2RTCSessionController', () => {
|
||||
websockets[3].fireOpen();
|
||||
binaryContexts[3].callbacks.failedCallback('unsupported');
|
||||
|
||||
expect(errorCallback).toBeCalledWith('unsupported');
|
||||
expect(errorCallback).toHaveBeenCalledWith('unsupported');
|
||||
});
|
||||
|
||||
it('should reset the reconnect budget after a successful media load', () => {
|
||||
@@ -933,8 +933,8 @@ describe('Go2RTCSessionController', () => {
|
||||
websockets[attempt + 1].fireOpen();
|
||||
}
|
||||
|
||||
expect(errorCallback).not.toBeCalled();
|
||||
expect(createWebSocket).toBeCalledTimes(6);
|
||||
expect(errorCallback).not.toHaveBeenCalled();
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(6);
|
||||
});
|
||||
|
||||
it('should tear down all lanes and clear the video on reset', () => {
|
||||
@@ -942,9 +942,9 @@ describe('Go2RTCSessionController', () => {
|
||||
startSourceRace(setupResult);
|
||||
setupResult.session.reset();
|
||||
|
||||
expect(setupResult.binarySources[0].stop).toBeCalled();
|
||||
expect(setupResult.webRTCSources[0].stop).toBeCalled();
|
||||
expect(setupResult.websockets[0].close).toBeCalled();
|
||||
expect(setupResult.binarySources[0].stop).toHaveBeenCalled();
|
||||
expect(setupResult.webRTCSources[0].stop).toHaveBeenCalled();
|
||||
expect(setupResult.websockets[0].close).toHaveBeenCalled();
|
||||
expect(setupResult.video.srcObject).toBeNull();
|
||||
});
|
||||
|
||||
@@ -956,7 +956,7 @@ describe('Go2RTCSessionController', () => {
|
||||
session.reset();
|
||||
vi.advanceTimersByTime(2 * 1000);
|
||||
|
||||
expect(createWebSocket).toBeCalledTimes(1);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should allow connecting to the same target after reset', () => {
|
||||
@@ -965,7 +965,7 @@ describe('Go2RTCSessionController', () => {
|
||||
session.reset();
|
||||
session.connect('http://host/api/ws?src=camera', surfaces, ['mse']);
|
||||
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -978,7 +978,7 @@ describe('Go2RTCSessionController', () => {
|
||||
binaryContexts[0].callbacks.failedCallback('media_error');
|
||||
|
||||
vi.advanceTimersByTime(2 * 1000);
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should ignore a loaded callback from a retired binary source', () => {
|
||||
@@ -990,7 +990,7 @@ describe('Go2RTCSessionController', () => {
|
||||
setupResult.mediaLoadedCallback.mockClear();
|
||||
setupResult.binaryContexts[0].callbacks.loadedCallback();
|
||||
|
||||
expect(setupResult.mediaLoadedCallback).not.toBeCalled();
|
||||
expect(setupResult.mediaLoadedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore a failed callback from a retired binary source', () => {
|
||||
@@ -1000,7 +1000,7 @@ describe('Go2RTCSessionController', () => {
|
||||
setupResult.binarySources[0].stop.mockClear();
|
||||
setupResult.binaryContexts[0].callbacks.failedCallback('media_error');
|
||||
|
||||
expect(setupResult.binarySources[0].stop).not.toBeCalled();
|
||||
expect(setupResult.binarySources[0].stop).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore a failed callback from a retired WebRTC source', () => {
|
||||
@@ -1012,7 +1012,7 @@ describe('Go2RTCSessionController', () => {
|
||||
webRTCSources[0].stop.mockClear();
|
||||
webRTCContexts[0].callbacks.failedCallback('media_error');
|
||||
|
||||
expect(webRTCSources[0].stop).not.toBeCalled();
|
||||
expect(webRTCSources[0].stop).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should adopt WebRTC when the racing binary already failed', () => {
|
||||
@@ -1031,7 +1031,7 @@ describe('Go2RTCSessionController', () => {
|
||||
setupResult.webRTCContexts[0].callbacks.loadedCallback();
|
||||
|
||||
expect(setupResult.video.srcObject).toBeFalsy();
|
||||
expect(setupResult.binarySources[0].stop).toBeCalled();
|
||||
expect(setupResult.binarySources[0].stop).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not report media that cannot be described', () => {
|
||||
@@ -1045,7 +1045,7 @@ describe('Go2RTCSessionController', () => {
|
||||
websockets[0].fireOpen();
|
||||
binaryContexts[0].callbacks.loadedCallback();
|
||||
|
||||
expect(mediaLoadedCallback).not.toBeCalled();
|
||||
expect(mediaLoadedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should swallow a rejected microphone update', async () => {
|
||||
@@ -1090,7 +1090,7 @@ describe('Go2RTCSessionController', () => {
|
||||
]);
|
||||
websockets[0].fireOpen();
|
||||
|
||||
expect(mediaLoadedCallback).not.toBeCalled();
|
||||
expect(mediaLoadedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore callbacks fired while a WebRTC source is constructed', () => {
|
||||
@@ -1124,7 +1124,7 @@ describe('Go2RTCSessionController', () => {
|
||||
]);
|
||||
websockets[0].fireOpen();
|
||||
|
||||
expect(mediaLoadedCallback).not.toBeCalled();
|
||||
expect(mediaLoadedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use the default binary source factory when none is injected', () => {
|
||||
@@ -1153,7 +1153,7 @@ describe('Go2RTCSessionController', () => {
|
||||
// closes and retries; the point is that the default factory was used.
|
||||
websockets[0].fireOpen();
|
||||
|
||||
expect(websockets[0].close).toBeCalled();
|
||||
expect(websockets[0].close).toHaveBeenCalled();
|
||||
session.reset();
|
||||
});
|
||||
|
||||
@@ -1236,7 +1236,7 @@ describe('Go2RTCSessionController', () => {
|
||||
|
||||
binaryContexts[0].callbacks.failedCallback('media_error');
|
||||
|
||||
expect(consoleSpy).toBeCalledWith('go2rtc-experimental source failed', {
|
||||
expect(consoleSpy).toHaveBeenCalledWith('go2rtc-experimental source failed', {
|
||||
lane: 'binary',
|
||||
mode: 'mse',
|
||||
reason: 'media_error',
|
||||
@@ -1253,7 +1253,7 @@ describe('Go2RTCSessionController', () => {
|
||||
|
||||
webRTCContexts[0].callbacks.failedCallback('connect_timeout');
|
||||
|
||||
expect(consoleSpy).toBeCalledWith('go2rtc-experimental source failed', {
|
||||
expect(consoleSpy).toHaveBeenCalledWith('go2rtc-experimental source failed', {
|
||||
lane: 'webrtc',
|
||||
reason: 'connect_timeout',
|
||||
});
|
||||
@@ -1267,7 +1267,7 @@ describe('Go2RTCSessionController', () => {
|
||||
|
||||
binaryContexts[0].callbacks.failedCallback('media_error');
|
||||
|
||||
expect(consoleSpy).not.toBeCalled();
|
||||
expect(consoleSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -29,7 +29,7 @@ describe('SignalingChannel', () => {
|
||||
const { channel, createWebSocket, websockets } = setup();
|
||||
channel.connect();
|
||||
|
||||
expect(createWebSocket).toBeCalledWith('ws://host/api/ws?src=camera');
|
||||
expect(createWebSocket).toHaveBeenCalledWith('ws://host/api/ws?src=camera');
|
||||
expect(websockets[0].binaryType).toBe('arraybuffer');
|
||||
});
|
||||
|
||||
@@ -38,7 +38,7 @@ describe('SignalingChannel', () => {
|
||||
channel.connect();
|
||||
channel.connect();
|
||||
|
||||
expect(createWebSocket).toBeCalledTimes(1);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should report open state and call the open callback', () => {
|
||||
@@ -51,7 +51,7 @@ describe('SignalingChannel', () => {
|
||||
websockets[0].fireOpen();
|
||||
|
||||
expect(channel.isOpen()).toBe(true);
|
||||
expect(openCallback).toBeCalled();
|
||||
expect(openCallback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should tolerate an absent open callback', () => {
|
||||
@@ -66,7 +66,7 @@ describe('SignalingChannel', () => {
|
||||
channel.connect();
|
||||
channel.send({ type: 'mse', value: 'codecs' });
|
||||
|
||||
expect(websockets[0].send).not.toBeCalled();
|
||||
expect(websockets[0].send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should send JSON once open', () => {
|
||||
@@ -86,7 +86,7 @@ describe('SignalingChannel', () => {
|
||||
channel.connect();
|
||||
websockets[0].fireMessage('{"type":"mse","value":"video/mp4"}');
|
||||
|
||||
expect(callback).toBeCalledWith({ type: 'mse', value: 'video/mp4' });
|
||||
expect(callback).toHaveBeenCalledWith({ type: 'mse', value: 'video/mp4' });
|
||||
});
|
||||
|
||||
it('should stop dispatching after unsubscribe', () => {
|
||||
@@ -97,7 +97,7 @@ describe('SignalingChannel', () => {
|
||||
unsubscribe();
|
||||
websockets[0].fireMessage('{"type":"mse"}');
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should dispatch to remaining subscribers when one unsubscribes during dispatch', () => {
|
||||
@@ -111,8 +111,8 @@ describe('SignalingChannel', () => {
|
||||
channel.connect();
|
||||
websockets[0].fireMessage('{"type":"mse"}');
|
||||
|
||||
expect(unsubscribeDuringDispatch).toBeCalledTimes(1);
|
||||
expect(secondCallback).toBeCalledTimes(1);
|
||||
expect(unsubscribeDuringDispatch).toHaveBeenCalledTimes(1);
|
||||
expect(secondCallback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should ignore invalid JSON', () => {
|
||||
@@ -122,7 +122,7 @@ describe('SignalingChannel', () => {
|
||||
channel.connect();
|
||||
websockets[0].fireMessage('NOT JSON');
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore malformed messages', () => {
|
||||
@@ -132,7 +132,7 @@ describe('SignalingChannel', () => {
|
||||
channel.connect();
|
||||
websockets[0].fireMessage('{"type":6}');
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore unexpected data types', () => {
|
||||
@@ -142,7 +142,7 @@ describe('SignalingChannel', () => {
|
||||
channel.connect();
|
||||
websockets[0].fireMessage(42);
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should route binary data to the binary callback', () => {
|
||||
@@ -153,7 +153,7 @@ describe('SignalingChannel', () => {
|
||||
const data = new ArrayBuffer(8);
|
||||
websockets[0].fireMessage(data);
|
||||
|
||||
expect(binaryCallback).toBeCalledWith(data);
|
||||
expect(binaryCallback).toHaveBeenCalledWith(data);
|
||||
});
|
||||
|
||||
it('should drop binary data without a binary callback', () => {
|
||||
@@ -171,7 +171,7 @@ describe('SignalingChannel', () => {
|
||||
channel.connect();
|
||||
websockets[0].fireMessage(new ArrayBuffer(8));
|
||||
|
||||
expect(binaryCallback).not.toBeCalled();
|
||||
expect(binaryCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should close the underlying websocket without firing the disconnect callback', () => {
|
||||
@@ -181,9 +181,9 @@ describe('SignalingChannel', () => {
|
||||
websockets[0].fireOpen();
|
||||
channel.close();
|
||||
|
||||
expect(websockets[0].close).toBeCalled();
|
||||
expect(websockets[0].close).toHaveBeenCalled();
|
||||
expect(channel.isOpen()).toBe(false);
|
||||
expect(disconnectCallback).not.toBeCalled();
|
||||
expect(disconnectCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should tolerate closing when never connected', () => {
|
||||
@@ -205,9 +205,9 @@ describe('SignalingChannel', () => {
|
||||
websockets[0].fireMessage('{"type":"mse"}');
|
||||
websockets[0].fireClose();
|
||||
|
||||
expect(openCallback).not.toBeCalled();
|
||||
expect(messageCallback).not.toBeCalled();
|
||||
expect(disconnectCallback).not.toBeCalled();
|
||||
expect(openCallback).not.toHaveBeenCalled();
|
||||
expect(messageCallback).not.toHaveBeenCalled();
|
||||
expect(disconnectCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fire the disconnect callback on unexpected closure', () => {
|
||||
@@ -217,7 +217,7 @@ describe('SignalingChannel', () => {
|
||||
websockets[0].fireOpen();
|
||||
websockets[0].fireClose();
|
||||
|
||||
expect(disconnectCallback).toBeCalledTimes(1);
|
||||
expect(disconnectCallback).toHaveBeenCalledTimes(1);
|
||||
expect(channel.isOpen()).toBe(false);
|
||||
});
|
||||
|
||||
@@ -234,7 +234,7 @@ describe('SignalingChannel', () => {
|
||||
websockets[0].fireClose();
|
||||
channel.connect();
|
||||
|
||||
expect(createWebSocket).toBeCalledTimes(2);
|
||||
expect(createWebSocket).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should construct a real websocket by default', () => {
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('MJPEGStreamSource', () => {
|
||||
source.start();
|
||||
channel.binaryCallback?.(frame());
|
||||
|
||||
expect(showFrame).toBeCalledTimes(1);
|
||||
expect(showFrame).toHaveBeenCalledTimes(1);
|
||||
const shown = showFrame.mock.calls[0][0] as Blob;
|
||||
expect(shown).toBeInstanceOf(Blob);
|
||||
expect(shown.type).toBe('image/jpeg');
|
||||
@@ -55,7 +55,7 @@ describe('MJPEGStreamSource', () => {
|
||||
channel.binaryCallback?.(frame());
|
||||
await flushPromises();
|
||||
|
||||
expect(loadedCallback).toBeCalledTimes(1);
|
||||
expect(loadedCallback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should not report loaded when stopped before the first frame decodes', async () => {
|
||||
@@ -75,7 +75,7 @@ describe('MJPEGStreamSource', () => {
|
||||
resolveDecode();
|
||||
await flushPromises();
|
||||
|
||||
expect(loadedCallback).not.toBeCalled();
|
||||
expect(loadedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail on a server error for mjpeg', () => {
|
||||
@@ -83,7 +83,7 @@ describe('MJPEGStreamSource', () => {
|
||||
source.start();
|
||||
channel.receiveMessage({ type: 'error', value: 'mjpeg: stream not found' });
|
||||
|
||||
expect(failedCallback).toBeCalledWith('server_error');
|
||||
expect(failedCallback).toHaveBeenCalledWith('server_error');
|
||||
});
|
||||
|
||||
it('should ignore a server error for another mode', () => {
|
||||
@@ -91,7 +91,7 @@ describe('MJPEGStreamSource', () => {
|
||||
source.start();
|
||||
channel.receiveMessage({ type: 'error', value: 'mse: stream not found' });
|
||||
|
||||
expect(failedCallback).not.toBeCalled();
|
||||
expect(failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should stop cleanly', () => {
|
||||
@@ -146,7 +146,7 @@ describe('MJPEGStreamSource', () => {
|
||||
source.start();
|
||||
vi.advanceTimersByTime(5 * 1000);
|
||||
|
||||
expect(failedCallback).toBeCalledWith('connect_timeout');
|
||||
expect(failedCallback).toHaveBeenCalledWith('connect_timeout');
|
||||
});
|
||||
|
||||
it('should not fail once a frame has arrived', () => {
|
||||
@@ -155,7 +155,7 @@ describe('MJPEGStreamSource', () => {
|
||||
channel.binaryCallback?.(frame());
|
||||
vi.advanceTimersByTime(5 * 1000);
|
||||
|
||||
expect(failedCallback).not.toBeCalled();
|
||||
expect(failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not fail after stop', () => {
|
||||
@@ -164,7 +164,7 @@ describe('MJPEGStreamSource', () => {
|
||||
source.stop();
|
||||
vi.advanceTimersByTime(5 * 1000);
|
||||
|
||||
expect(failedCallback).not.toBeCalled();
|
||||
expect(failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -93,7 +93,7 @@ describe('MP4StreamSource', () => {
|
||||
channel.binaryCallback?.(frame());
|
||||
|
||||
// Second frame reuses the same decoder rather than creating another.
|
||||
expect(createVideoElement).toBeCalledTimes(1);
|
||||
expect(createVideoElement).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should draw a decoded frame and show it as an image', async () => {
|
||||
@@ -103,12 +103,12 @@ describe('MP4StreamSource', () => {
|
||||
decoderVideo.dispatchEvent(new Event('loadeddata'));
|
||||
await flushPromises();
|
||||
|
||||
expect(canvas.context?.drawImage).toBeCalled();
|
||||
expect(showFrame).toBeCalledTimes(1);
|
||||
expect(canvas.context?.drawImage).toHaveBeenCalled();
|
||||
expect(showFrame).toHaveBeenCalledTimes(1);
|
||||
const shown = showFrame.mock.calls[0][0] as Blob;
|
||||
expect(shown).toBeInstanceOf(Blob);
|
||||
expect(shown.type).toBe('image/jpeg');
|
||||
expect(loadedCallback).toBeCalledTimes(1);
|
||||
expect(loadedCallback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should report loaded only on the first drawn frame', async () => {
|
||||
@@ -121,7 +121,7 @@ describe('MP4StreamSource', () => {
|
||||
decoderVideo.dispatchEvent(new Event('loadeddata'));
|
||||
await flushPromises();
|
||||
|
||||
expect(loadedCallback).toBeCalledTimes(1);
|
||||
expect(loadedCallback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should not show a frame when the canvas produces no blob', () => {
|
||||
@@ -131,7 +131,7 @@ describe('MP4StreamSource', () => {
|
||||
channel.binaryCallback?.(frame());
|
||||
decoderVideo.dispatchEvent(new Event('loadeddata'));
|
||||
|
||||
expect(showFrame).not.toBeCalled();
|
||||
expect(showFrame).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing when the canvas has no 2d context', () => {
|
||||
@@ -141,7 +141,7 @@ describe('MP4StreamSource', () => {
|
||||
channel.binaryCallback?.(frame());
|
||||
decoderVideo.dispatchEvent(new Event('loadeddata'));
|
||||
|
||||
expect(showFrame).not.toBeCalled();
|
||||
expect(showFrame).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail on a server error for mp4', () => {
|
||||
@@ -149,7 +149,7 @@ describe('MP4StreamSource', () => {
|
||||
source.start();
|
||||
channel.receiveMessage({ type: 'error', value: 'mp4: stream not found' });
|
||||
|
||||
expect(failedCallback).toBeCalledWith('server_error');
|
||||
expect(failedCallback).toHaveBeenCalledWith('server_error');
|
||||
});
|
||||
|
||||
it('should clear the decoder on stop', () => {
|
||||
@@ -172,7 +172,7 @@ describe('MP4StreamSource', () => {
|
||||
// surface.
|
||||
decoderVideo.dispatchEvent(new Event('loadeddata'));
|
||||
|
||||
expect(showFrame).not.toBeCalled();
|
||||
expect(showFrame).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('first-frame timeout', () => {
|
||||
@@ -181,7 +181,7 @@ describe('MP4StreamSource', () => {
|
||||
source.start();
|
||||
vi.advanceTimersByTime(5 * 1000);
|
||||
|
||||
expect(failedCallback).toBeCalledWith('connect_timeout');
|
||||
expect(failedCallback).toHaveBeenCalledWith('connect_timeout');
|
||||
});
|
||||
|
||||
it('should not fail once a frame has been drawn', () => {
|
||||
@@ -191,7 +191,7 @@ describe('MP4StreamSource', () => {
|
||||
decoderVideo.dispatchEvent(new Event('loadeddata'));
|
||||
vi.advanceTimersByTime(5 * 1000);
|
||||
|
||||
expect(failedCallback).not.toBeCalled();
|
||||
expect(failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not fail after stop', () => {
|
||||
@@ -200,7 +200,7 @@ describe('MP4StreamSource', () => {
|
||||
source.stop();
|
||||
vi.advanceTimersByTime(5 * 1000);
|
||||
|
||||
expect(failedCallback).not.toBeCalled();
|
||||
expect(failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -70,14 +70,14 @@ describe('MSEStreamSource', () => {
|
||||
const { source, failedCallback } = setup({ unsupported: true });
|
||||
source.start();
|
||||
|
||||
expect(failedCallback).toBeCalledWith('unsupported');
|
||||
expect(failedCallback).toHaveBeenCalledWith('unsupported');
|
||||
});
|
||||
|
||||
it('should attach the media source to the video on start', () => {
|
||||
const { source, instance, video } = setup();
|
||||
source.start();
|
||||
|
||||
expect(instance.attach).toBeCalledWith(video);
|
||||
expect(instance.attach).toHaveBeenCalledWith(video);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -121,7 +121,7 @@ describe('MSEStreamSource', () => {
|
||||
instance.fireSourceOpen();
|
||||
vi.advanceTimersByTime(5 * 1000);
|
||||
|
||||
expect(failedCallback).toBeCalledWith('negotiation_timeout');
|
||||
expect(failedCallback).toHaveBeenCalledWith('negotiation_timeout');
|
||||
});
|
||||
|
||||
it('should not time out after a successful negotiation', () => {
|
||||
@@ -129,14 +129,14 @@ describe('MSEStreamSource', () => {
|
||||
negotiate(setupResult);
|
||||
vi.advanceTimersByTime(5 * 1000);
|
||||
|
||||
expect(setupResult.failedCallback).not.toBeCalled();
|
||||
expect(setupResult.failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should create a source buffer in segments mode on negotiation', () => {
|
||||
const setupResult = setup();
|
||||
negotiate(setupResult);
|
||||
|
||||
expect(setupResult.instance.addSourceBuffer).toBeCalledWith(
|
||||
expect(setupResult.instance.addSourceBuffer).toHaveBeenCalledWith(
|
||||
'video/mp4; codecs="avc1.640029,mp4a.40.2"',
|
||||
);
|
||||
expect(setupResult.instance.sourceBuffer.mode).toBe('segments');
|
||||
@@ -148,7 +148,7 @@ describe('MSEStreamSource', () => {
|
||||
negotiate(setupResult);
|
||||
setupResult.channel.receiveMessage({ type: 'mse', value: 'video/mp4' });
|
||||
|
||||
expect(setupResult.instance.addSourceBuffer).toBeCalledTimes(1);
|
||||
expect(setupResult.instance.addSourceBuffer).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should ignore negotiation responses without a string value', () => {
|
||||
@@ -156,7 +156,7 @@ describe('MSEStreamSource', () => {
|
||||
setupResult.source.start();
|
||||
setupResult.channel.receiveMessage({ type: 'mse', value: 42 });
|
||||
|
||||
expect(setupResult.instance.addSourceBuffer).not.toBeCalled();
|
||||
expect(setupResult.instance.addSourceBuffer).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore unrelated messages', () => {
|
||||
@@ -164,8 +164,8 @@ describe('MSEStreamSource', () => {
|
||||
setupResult.source.start();
|
||||
setupResult.channel.receiveMessage({ type: 'webrtc/answer', value: 'sdp' });
|
||||
|
||||
expect(setupResult.instance.addSourceBuffer).not.toBeCalled();
|
||||
expect(setupResult.failedCallback).not.toBeCalled();
|
||||
expect(setupResult.instance.addSourceBuffer).not.toHaveBeenCalled();
|
||||
expect(setupResult.failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -176,12 +176,12 @@ describe('MSEStreamSource', () => {
|
||||
instance.fireSourceOpen();
|
||||
channel.receiveMessage({ type: 'error', value: 'mse: stream not found' });
|
||||
|
||||
expect(failedCallback).toBeCalledWith('server_error');
|
||||
expect(failedCallback).toHaveBeenCalledWith('server_error');
|
||||
|
||||
// The negotiation timer must have stopped.
|
||||
failedCallback.mockClear();
|
||||
vi.advanceTimersByTime(5 * 1000);
|
||||
expect(failedCallback).not.toBeCalled();
|
||||
expect(failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore server errors for other modes', () => {
|
||||
@@ -189,7 +189,7 @@ describe('MSEStreamSource', () => {
|
||||
source.start();
|
||||
channel.receiveMessage({ type: 'error', value: 'webrtc/offer: failed' });
|
||||
|
||||
expect(failedCallback).not.toBeCalled();
|
||||
expect(failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should ignore server errors without a string value', () => {
|
||||
@@ -197,7 +197,7 @@ describe('MSEStreamSource', () => {
|
||||
source.start();
|
||||
channel.receiveMessage({ type: 'error' });
|
||||
|
||||
expect(failedCallback).not.toBeCalled();
|
||||
expect(failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -211,7 +211,7 @@ describe('MSEStreamSource', () => {
|
||||
instance.fireSourceOpen();
|
||||
channel.receiveMessage({ type: 'mse', value: 'video/mp4' });
|
||||
|
||||
expect(failedCallback).toBeCalledWith('media_error');
|
||||
expect(failedCallback).toHaveBeenCalledWith('media_error');
|
||||
});
|
||||
|
||||
it('should append binary data directly when idle', () => {
|
||||
@@ -220,7 +220,7 @@ describe('MSEStreamSource', () => {
|
||||
const data = new ArrayBuffer(8);
|
||||
setupResult.channel.binaryCallback?.(data);
|
||||
|
||||
expect(setupResult.instance.sourceBuffer.appendBuffer).toBeCalledWith(data);
|
||||
expect(setupResult.instance.sourceBuffer.appendBuffer).toHaveBeenCalledWith(data);
|
||||
});
|
||||
|
||||
it('should swallow direct append failures', () => {
|
||||
@@ -233,7 +233,7 @@ describe('MSEStreamSource', () => {
|
||||
expect(() =>
|
||||
setupResult.channel.binaryCallback?.(new ArrayBuffer(8)),
|
||||
).not.toThrow();
|
||||
expect(setupResult.failedCallback).not.toBeCalled();
|
||||
expect(setupResult.failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should stage binary data while the source buffer updates', () => {
|
||||
@@ -243,12 +243,14 @@ describe('MSEStreamSource', () => {
|
||||
const staged = new ArrayBuffer(8);
|
||||
setupResult.channel.binaryCallback?.(staged);
|
||||
|
||||
expect(setupResult.instance.sourceBuffer.appendBuffer).not.toBeCalled();
|
||||
expect(setupResult.instance.sourceBuffer.appendBuffer).not.toHaveBeenCalled();
|
||||
|
||||
setupResult.instance.sourceBuffer.updating = false;
|
||||
setupResult.instance.sourceBuffer.fireUpdateEnd();
|
||||
|
||||
expect(setupResult.instance.sourceBuffer.appendBuffer).toBeCalledWith(staged);
|
||||
expect(setupResult.instance.sourceBuffer.appendBuffer).toHaveBeenCalledWith(
|
||||
staged,
|
||||
);
|
||||
});
|
||||
|
||||
it('should stage binary data behind earlier staged data', () => {
|
||||
@@ -263,7 +265,7 @@ describe('MSEStreamSource', () => {
|
||||
sourceBuffer.updating = false;
|
||||
setupResult.channel.binaryCallback?.(second);
|
||||
|
||||
expect(sourceBuffer.appendBuffer).not.toBeCalled();
|
||||
expect(sourceBuffer.appendBuffer).not.toHaveBeenCalled();
|
||||
|
||||
sourceBuffer.fireUpdateEnd();
|
||||
expect(sourceBuffer.appendBuffer).toHaveBeenNthCalledWith(1, first);
|
||||
@@ -279,10 +281,10 @@ describe('MSEStreamSource', () => {
|
||||
|
||||
sourceBuffer.updating = true;
|
||||
setupResult.channel.binaryCallback?.(new ArrayBuffer(2 * 1024 * 1024));
|
||||
expect(setupResult.failedCallback).not.toBeCalled();
|
||||
expect(setupResult.failedCallback).not.toHaveBeenCalled();
|
||||
|
||||
setupResult.channel.binaryCallback?.(new ArrayBuffer(1));
|
||||
expect(setupResult.failedCallback).toBeCalledWith('buffer_overflow');
|
||||
expect(setupResult.failedCallback).toHaveBeenCalledWith('buffer_overflow');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -295,7 +297,7 @@ describe('MSEStreamSource', () => {
|
||||
sourceBuffer.updating = true;
|
||||
sourceBuffer.fireUpdateEnd();
|
||||
|
||||
expect(sourceBuffer.remove).not.toBeCalled();
|
||||
expect(sourceBuffer.remove).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing on updateend without buffered content', () => {
|
||||
@@ -303,8 +305,8 @@ describe('MSEStreamSource', () => {
|
||||
negotiate(setupResult);
|
||||
setupResult.instance.sourceBuffer.fireUpdateEnd();
|
||||
|
||||
expect(setupResult.instance.sourceBuffer.remove).not.toBeCalled();
|
||||
expect(setupResult.instance.setLiveSeekableRange).not.toBeCalled();
|
||||
expect(setupResult.instance.sourceBuffer.remove).not.toHaveBeenCalled();
|
||||
expect(setupResult.instance.setLiveSeekableRange).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not trim after the media source has closed', () => {
|
||||
@@ -319,8 +321,8 @@ describe('MSEStreamSource', () => {
|
||||
setupResult.instance.isOpen.mockReturnValue(false);
|
||||
sourceBuffer.fireUpdateEnd();
|
||||
|
||||
expect(sourceBuffer.remove).not.toBeCalled();
|
||||
expect(setupResult.instance.setLiveSeekableRange).not.toBeCalled();
|
||||
expect(sourceBuffer.remove).not.toHaveBeenCalled();
|
||||
expect(setupResult.instance.setLiveSeekableRange).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should trim media behind the retained window', () => {
|
||||
@@ -332,8 +334,8 @@ describe('MSEStreamSource', () => {
|
||||
sourceBuffer.fireUpdateEnd();
|
||||
|
||||
// Retains the last 15s (end 20 -> retainedStart 5).
|
||||
expect(sourceBuffer.remove).toBeCalledWith(0, 5);
|
||||
expect(setupResult.instance.setLiveSeekableRange).toBeCalledWith(5, 20);
|
||||
expect(sourceBuffer.remove).toHaveBeenCalledWith(0, 5);
|
||||
expect(setupResult.instance.setLiveSeekableRange).toHaveBeenCalledWith(5, 20);
|
||||
});
|
||||
|
||||
it('should not trim when all media is within the retained window', () => {
|
||||
@@ -344,7 +346,7 @@ describe('MSEStreamSource', () => {
|
||||
setupResult.video.currentTime = 19;
|
||||
sourceBuffer.fireUpdateEnd();
|
||||
|
||||
expect(sourceBuffer.remove).not.toBeCalled();
|
||||
expect(sourceBuffer.remove).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not move the playhead when it falls behind the window', () => {
|
||||
@@ -464,7 +466,7 @@ describe('MSEStreamSource', () => {
|
||||
sourceBuffer.fireUpdateEnd();
|
||||
|
||||
// Trim still bounds memory, but the playhead and rate are left untouched.
|
||||
expect(sourceBuffer.remove).toBeCalled();
|
||||
expect(sourceBuffer.remove).toHaveBeenCalled();
|
||||
expect(setupResult.video.currentTime).toBe(2);
|
||||
expect(setupResult.video.playbackRate).toBe(1);
|
||||
});
|
||||
@@ -507,7 +509,7 @@ describe('MSEStreamSource', () => {
|
||||
negotiate(setupResult);
|
||||
setupResult.video.dispatchEvent(new Event('loadeddata'));
|
||||
|
||||
expect(setupResult.loadedCallback).toBeCalledTimes(1);
|
||||
expect(setupResult.loadedCallback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should fail on video element errors', () => {
|
||||
@@ -515,7 +517,7 @@ describe('MSEStreamSource', () => {
|
||||
setupResult.source.start();
|
||||
setupResult.video.dispatchEvent(new Event('error'));
|
||||
|
||||
expect(setupResult.failedCallback).toBeCalledWith('media_error');
|
||||
expect(setupResult.failedCallback).toHaveBeenCalledWith('media_error');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -525,19 +527,19 @@ describe('MSEStreamSource', () => {
|
||||
negotiate(setupResult);
|
||||
setupResult.source.stop();
|
||||
|
||||
expect(setupResult.instance.detach).toBeCalledWith(setupResult.video);
|
||||
expect(setupResult.instance.detach).toHaveBeenCalledWith(setupResult.video);
|
||||
expect(setupResult.channel.binaryCallback).toBeNull();
|
||||
expect(setupResult.channel.getMessageCallbackCount()).toBe(0);
|
||||
expect(setupResult.instance.getSourceOpenCallbackCount()).toBe(0);
|
||||
|
||||
setupResult.video.dispatchEvent(new Event('loadeddata'));
|
||||
setupResult.video.dispatchEvent(new Event('error'));
|
||||
expect(setupResult.loadedCallback).not.toBeCalled();
|
||||
expect(setupResult.failedCallback).not.toBeCalled();
|
||||
expect(setupResult.loadedCallback).not.toHaveBeenCalled();
|
||||
expect(setupResult.failedCallback).not.toHaveBeenCalled();
|
||||
|
||||
setupResult.instance.sourceBuffer.buffered = createTimeRanges([[0, 20]]);
|
||||
setupResult.instance.sourceBuffer.fireUpdateEnd();
|
||||
expect(setupResult.instance.sourceBuffer.remove).not.toBeCalled();
|
||||
expect(setupResult.instance.sourceBuffer.remove).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should stop the negotiation timer on stop', () => {
|
||||
@@ -547,7 +549,7 @@ describe('MSEStreamSource', () => {
|
||||
setupResult.source.stop();
|
||||
vi.advanceTimersByTime(5 * 1000);
|
||||
|
||||
expect(setupResult.failedCallback).not.toBeCalled();
|
||||
expect(setupResult.failedCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should tolerate stopping before starting', () => {
|
||||
|
||||
Reference in New Issue
Block a user