fix: Report media failures once per failure (#2666)
This commit is contained in:
@@ -214,11 +214,29 @@ describe('EntityAvailabilityDetector', () => {
|
||||
|
||||
// Re-point at the (now available) entity from a fresh state.
|
||||
setEntityState('streaming');
|
||||
detector.reset();
|
||||
detector.invalidate('stream-changed');
|
||||
|
||||
expect(detector.getVerdict()).toEqual({ state: 'unknown' });
|
||||
});
|
||||
|
||||
it('should keep the verdict when media loads', () => {
|
||||
const { detector, fireStateChange } = setup();
|
||||
detector.subscribe();
|
||||
fireStateChange('unavailable');
|
||||
vi.advanceTimersByTime(GRACE_MS);
|
||||
|
||||
// This detector watches the camera entity, so media loading tells it
|
||||
// nothing about the entity it is watching.
|
||||
detector.invalidate('media-loaded');
|
||||
|
||||
expect(detector.getVerdict()).toEqual({
|
||||
state: 'not_live',
|
||||
authority: 'indirect',
|
||||
renderPlaceholder: true,
|
||||
reason: 'entity_unavailable',
|
||||
});
|
||||
});
|
||||
|
||||
it('should re-check the entity when reset', () => {
|
||||
// always_error makes the re-check produce a verdict immediately rather than
|
||||
// waiting out the grace window.
|
||||
@@ -228,7 +246,7 @@ describe('EntityAvailabilityDetector', () => {
|
||||
// An entity that is already unavailable never fires a state change, so
|
||||
// resetting must read it rather than wait to be told.
|
||||
setEntityState('unavailable');
|
||||
detector.reset();
|
||||
detector.invalidate('stream-changed');
|
||||
|
||||
expect(detector.getVerdict()).toEqual(
|
||||
expect.objectContaining({ state: 'not_live', authority: 'hard' }),
|
||||
@@ -238,7 +256,7 @@ describe('EntityAvailabilityDetector', () => {
|
||||
it('should do nothing on reset before subscribe', () => {
|
||||
const { detector, stateWatcher } = setup();
|
||||
|
||||
detector.reset();
|
||||
detector.invalidate('stream-changed');
|
||||
|
||||
expect(stateWatcher.subscribe).not.toHaveBeenCalled();
|
||||
expect(detector.getVerdict()).toEqual({ state: 'unknown' });
|
||||
@@ -249,7 +267,7 @@ describe('EntityAvailabilityDetector', () => {
|
||||
detector.subscribe();
|
||||
|
||||
setCameraEntity(null);
|
||||
detector.reset();
|
||||
detector.invalidate('stream-changed');
|
||||
|
||||
expect(stateWatcher.unsubscribe).toHaveBeenCalled();
|
||||
expect(detector.getVerdict()).toEqual({ state: 'unknown' });
|
||||
|
||||
@@ -248,12 +248,34 @@ describe('MediaPlayerLivenessDetector', () => {
|
||||
await callIntersectionHandler(true);
|
||||
fireMediaPlayerLiveness(false);
|
||||
|
||||
detector.reset();
|
||||
detector.invalidate('stream-changed');
|
||||
|
||||
expect(detector.getVerdict()).toEqual({ state: 'unknown' });
|
||||
expect(unsubscribe).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should keep the verdict when media loads', async () => {
|
||||
const { detector, loadMedia } = setup();
|
||||
const { player, unsubscribe, fireMediaPlayerLiveness } = createPlayer();
|
||||
detector.subscribe();
|
||||
loadMedia(player);
|
||||
|
||||
await callIntersectionHandler(true);
|
||||
fireMediaPlayerLiveness(false);
|
||||
|
||||
// The media player reported that media it had already loaded stopped
|
||||
// delivering frames, which another load does not answer.
|
||||
detector.invalidate('media-loaded');
|
||||
|
||||
expect(detector.getVerdict()).toEqual({
|
||||
state: 'not_live',
|
||||
authority: 'direct',
|
||||
renderPlaceholder: true,
|
||||
reason: 'stalled',
|
||||
});
|
||||
expect(unsubscribe).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should tear down the watch and stop listening on unsubscribe', async () => {
|
||||
const { detector, loadMedia } = setup();
|
||||
const first = createPlayer();
|
||||
|
||||
@@ -13,7 +13,7 @@ const createHostInDocument = (): HTMLElement => {
|
||||
|
||||
// @vitest-environment jsdom
|
||||
describe('ProviderErrorDetector', () => {
|
||||
it('should not report a change when reset', () => {
|
||||
it('should not report a change when the stream changes', () => {
|
||||
const host = createHostInDocument();
|
||||
const onChange = vi.fn();
|
||||
const detector = new ProviderErrorDetector(host, onChange);
|
||||
@@ -21,7 +21,7 @@ describe('ProviderErrorDetector', () => {
|
||||
dispatchLiveErrorEvent(host);
|
||||
onChange.mockClear();
|
||||
|
||||
detector.reset();
|
||||
detector.invalidate('stream-changed');
|
||||
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -93,14 +93,14 @@ describe('ProviderErrorDetector', () => {
|
||||
document.body.removeEventListener(LIVE_ERROR_EVENT, parentListener);
|
||||
});
|
||||
|
||||
it('should discard the verdict on reset', () => {
|
||||
it('should discard the verdict when the stream changes', () => {
|
||||
const host = createHostInDocument();
|
||||
const detector = new ProviderErrorDetector(host, vi.fn());
|
||||
detector.subscribe();
|
||||
dispatchLiveErrorEvent(host);
|
||||
expect(detector.getVerdict().state).toBe('not_live');
|
||||
|
||||
detector.reset();
|
||||
detector.invalidate('stream-changed');
|
||||
|
||||
expect(detector.getVerdict()).toEqual({ state: 'unknown' });
|
||||
});
|
||||
@@ -117,4 +117,31 @@ describe('ProviderErrorDetector', () => {
|
||||
expect(detector.getVerdict().state).toBe('unknown');
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should clear the failure when media arrives', () => {
|
||||
const host = createHostInDocument();
|
||||
const detector = new ProviderErrorDetector(host, vi.fn());
|
||||
detector.subscribe();
|
||||
dispatchLiveErrorEvent(host);
|
||||
|
||||
// The provider said it could not deliver the media, and then delivered it.
|
||||
detector.invalidate('media-loaded');
|
||||
|
||||
expect(detector.getVerdict()).toEqual({ state: 'unknown' });
|
||||
});
|
||||
|
||||
it('should report a later error after media cleared the previous one', () => {
|
||||
const host = createHostInDocument();
|
||||
const onChange = vi.fn();
|
||||
const detector = new ProviderErrorDetector(host, onChange);
|
||||
detector.subscribe();
|
||||
dispatchLiveErrorEvent(host);
|
||||
detector.invalidate('media-loaded');
|
||||
onChange.mockClear();
|
||||
|
||||
dispatchLiveErrorEvent(host);
|
||||
|
||||
expect(detector.getVerdict().state).toBe('not_live');
|
||||
expect(onChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user