chore: Enforce a few house rules via eslint (#2539)
This commit is contained in:
committed by
dermotduffy
parent
5572ec728e
commit
921d45e577
@@ -198,11 +198,11 @@ describe('IssueManager', () => {
|
||||
|
||||
const manager = new IssueManager(api);
|
||||
|
||||
// hasIssue returns true from the start — simulates trigger() having
|
||||
// already mutated state before detectDynamic snapshots. The
|
||||
// before/after check inside detectDynamic sees true→true (no
|
||||
// transition), but the presence comparison against ConditionState
|
||||
// must still detect the change.
|
||||
// hasIssue returns true from the start -- simulates trigger() having
|
||||
// already mutated state before detectDynamic snapshots. The before/after
|
||||
// check inside detectDynamic sees true→true (no transition), but the
|
||||
// presence comparison against ConditionState must still detect the
|
||||
// change.
|
||||
const description = createIssueDescription();
|
||||
const issue = createIssue('config_error', {
|
||||
hasIssue: vi.fn().mockReturnValue(true),
|
||||
@@ -219,7 +219,7 @@ describe('IssueManager', () => {
|
||||
expect(api.getCardElementManager().update).toBeCalled();
|
||||
});
|
||||
|
||||
it('should never auto-popup on trigger — non-full-card issues surface via the status-bar icon; user clicks to open', () => {
|
||||
it('should never auto-popup on trigger -- non-full-card issues surface via the status-bar icon; user clicks to open', () => {
|
||||
const api = createCardAPI();
|
||||
vi.mocked(api.getConditionStateManager().getState).mockReturnValue({});
|
||||
|
||||
@@ -250,8 +250,8 @@ describe('IssueManager', () => {
|
||||
|
||||
expect(issue.retry).toBeCalled();
|
||||
|
||||
// Timer should have been reset — advancing less than retrySeconds
|
||||
// should not fire it again.
|
||||
// Timer should have been reset -- advancing less than retrySeconds should
|
||||
// not fire it again.
|
||||
assert(issue.retry);
|
||||
vi.mocked(issue.retry).mockClear();
|
||||
vi.advanceTimersByTime(500);
|
||||
@@ -312,11 +312,11 @@ describe('IssueManager', () => {
|
||||
});
|
||||
|
||||
it('should call update when an active issue swaps sub-states without changing the key set', () => {
|
||||
// Simulates ConnectionIssue going from 'lost' to 'starting': the
|
||||
// presence key set ({connection}) is identical, but the description
|
||||
// value differs. Because IssuePresence is a Map<key, description>,
|
||||
// the condition state diff sees the value-level change and fires
|
||||
// listeners — the IssueManager's own listener calls update().
|
||||
// Simulates ConnectionIssue going from 'lost' to 'starting': the presence
|
||||
// key set ({connection}) is identical, but the description value differs.
|
||||
// Because IssuePresence is a Map<key, description>, the condition state
|
||||
// diff sees the value-level change and fires listeners -- the
|
||||
// IssueManager's own listener calls update().
|
||||
const api = createCardAPI();
|
||||
|
||||
// Real ConditionStateManager so its isEqual-based diff actually runs.
|
||||
@@ -638,7 +638,7 @@ describe('IssueManager', () => {
|
||||
const { manager, issue } = createRetriableSetup({ retrySeconds: 'auto' });
|
||||
manager.evaluate();
|
||||
|
||||
// Run two retries — second delay should be 2x the first.
|
||||
// Run two retries -- second delay should be 2x the first.
|
||||
vi.advanceTimersByTime(RETRY_EXPONENTIAL_BASE_SECONDS * 0.75 * 1000);
|
||||
vi.advanceTimersByTime(RETRY_EXPONENTIAL_BASE_SECONDS * 2 * 0.75 * 1000);
|
||||
expect(issue.retry).toBeCalledTimes(2);
|
||||
@@ -671,16 +671,16 @@ describe('IssueManager', () => {
|
||||
});
|
||||
manager.evaluate();
|
||||
|
||||
// Three gated firings — each at the base delay (22.5s with 0.75 jitter).
|
||||
// If the counter were incrementing on gated fires, the second would be
|
||||
// at 45s and we'd never reach it after only 22.5s.
|
||||
// Three gated firings -- each at the base delay (22.5s with 0.75 jitter).
|
||||
// If the counter were incrementing on gated fires, the second would be at
|
||||
// 45s and we'd never reach it after only 22.5s.
|
||||
vi.advanceTimersByTime(RETRY_EXPONENTIAL_BASE_SECONDS * 0.75 * 1000);
|
||||
vi.advanceTimersByTime(RETRY_EXPONENTIAL_BASE_SECONDS * 0.75 * 1000);
|
||||
vi.advanceTimersByTime(RETRY_EXPONENTIAL_BASE_SECONDS * 0.75 * 1000);
|
||||
expect(issue.retry).not.toBeCalled();
|
||||
|
||||
// Clear the interaction. The next firing — still at the base delay —
|
||||
// is now allowed and the retry runs.
|
||||
// Clear the interaction. The next firing -- still at the base delay -- is
|
||||
// now allowed and the retry runs.
|
||||
vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false);
|
||||
vi.advanceTimersByTime(RETRY_EXPONENTIAL_BASE_SECONDS * 0.75 * 1000);
|
||||
expect(issue.retry).toBeCalledTimes(1);
|
||||
@@ -854,7 +854,7 @@ describe('IssueManager', () => {
|
||||
vi.mocked(api.getConditionStateManager().getState).mockReturnValue({});
|
||||
|
||||
const manager = new IssueManager(api);
|
||||
// Plain Issue implementation — no optional methods installed.
|
||||
// Plain Issue implementation -- no optional methods installed.
|
||||
const issue: Issue = {
|
||||
key: 'config_error',
|
||||
hasIssue: () => false,
|
||||
|
||||
@@ -2,9 +2,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { MediaLoadIssue } from '../../../../src/card-controller/issues/issues/media-load';
|
||||
import { InternalCallbackActionConfig } from '../../../../src/config/schema/actions/custom/internal';
|
||||
import { IMAGE_VIEW_TARGET_ID_SENTINEL } from '../../../../src/view/target-id';
|
||||
import { View } from '../../../../src/view/view';
|
||||
import { createCardAPI, createMediaLoadedInfo } from '../../../test-utils';
|
||||
import { IMAGE_VIEW_TARGET_ID_SENTINEL } from '../../../../src/view/target-id';
|
||||
|
||||
const createAPI = () => createCardAPI();
|
||||
|
||||
@@ -133,7 +133,7 @@ describe('MediaLoadIssue', () => {
|
||||
vi.advanceTimersByTime(10000);
|
||||
expect(issue.hasIssue()).toBe(true);
|
||||
|
||||
// Same target, different media view — issue stays active.
|
||||
// Same target, different media view -- issue stays active.
|
||||
issue.detectDynamic({ targetID: 'camera-1', view: 'clip' });
|
||||
expect(issue.hasIssue()).toBe(true);
|
||||
});
|
||||
@@ -145,7 +145,7 @@ describe('MediaLoadIssue', () => {
|
||||
vi.advanceTimersByTime(10000);
|
||||
expect(issue.hasIssue()).toBe(true);
|
||||
|
||||
// Switch to camera-2 which has no error — should deactivate and start
|
||||
// Switch to camera-2 which has no error -- should deactivate and start
|
||||
// a fresh timer for the new target.
|
||||
issue.detectDynamic({ targetID: 'camera-2', view: 'live' });
|
||||
expect(issue.hasIssue()).toBe(false);
|
||||
@@ -164,7 +164,7 @@ describe('MediaLoadIssue', () => {
|
||||
issue.detectDynamic({ targetID: 'camera-1', view: 'live' });
|
||||
expect(issue.hasIssue()).toBe(true);
|
||||
|
||||
// Switch to camera-2 which also has an error — should stay active.
|
||||
// Switch to camera-2 which also has an error -- should stay active.
|
||||
issue.detectDynamic({ targetID: 'camera-2', view: 'live' });
|
||||
expect(issue.hasIssue()).toBe(true);
|
||||
});
|
||||
@@ -456,7 +456,7 @@ describe('MediaLoadIssue', () => {
|
||||
|
||||
issue.retry();
|
||||
|
||||
// Issue remains active — no new 10s grace period. The error stays
|
||||
// Issue remains active -- no new 10s grace period. The error stays
|
||||
// visible while the provider re-attempts loading underneath.
|
||||
expect(issue.hasIssue()).toBe(true);
|
||||
});
|
||||
@@ -542,9 +542,9 @@ describe('MediaLoadIssue', () => {
|
||||
|
||||
issue.retry();
|
||||
|
||||
// After retry, the issue stays active and the errored target is
|
||||
// preserved — no new 10s grace period. If media:loaded fires, the
|
||||
// existing _handleMediaLoaded path will clear everything.
|
||||
// After retry, the issue stays active and the errored target is preserved
|
||||
// -- no new 10s grace period. If media:loaded fires, the existing
|
||||
// _handleMediaLoaded path will clear everything.
|
||||
expect(issue.hasIssue()).toBe(true);
|
||||
issue.detectDynamic({ targetID: 'camera-1', view: 'live' });
|
||||
expect(issue.hasIssue()).toBe(true);
|
||||
@@ -579,8 +579,8 @@ describe('MediaLoadIssue', () => {
|
||||
// Card detaches: timer must stop.
|
||||
issue.suspend();
|
||||
|
||||
// Full 10s later (plus margin) the timer has NOT matured — the user
|
||||
// was offscreen and that time does not count against them.
|
||||
// Full 10s later (plus margin) the timer has NOT matured -- the user was
|
||||
// offscreen and that time does not count against them.
|
||||
vi.advanceTimersByTime(20000);
|
||||
expect(issue.hasIssue()).toBe(false);
|
||||
expect(onChange).not.toBeCalled();
|
||||
@@ -594,7 +594,7 @@ describe('MediaLoadIssue', () => {
|
||||
vi.advanceTimersByTime(10000);
|
||||
expect(issue.hasIssue()).toBe(true);
|
||||
|
||||
// Card detaches — issue must remain visible on reattach.
|
||||
// Card detaches -- issue must remain visible on reattach.
|
||||
issue.suspend();
|
||||
|
||||
expect(issue.hasIssue()).toBe(true);
|
||||
@@ -609,8 +609,8 @@ describe('MediaLoadIssue', () => {
|
||||
issue.suspend();
|
||||
|
||||
// Reattach: the manager's resume() triggers evaluate() → detectDynamic.
|
||||
// The target is still loading, so the timer arms with a fresh 10s
|
||||
// window — not whatever was left when we suspended.
|
||||
// The target is still loading, so the timer arms with a fresh 10s window
|
||||
// -- not whatever was left when we suspended.
|
||||
issue.detectDynamic({ targetID: 'camera-1', view: 'live' });
|
||||
|
||||
vi.advanceTimersByTime(9999);
|
||||
|
||||
@@ -68,6 +68,28 @@ describe('IssueStateManager', () => {
|
||||
expect(mockLegacyResource.detectStatic).toBeCalledWith(hass);
|
||||
expect(mockMediaLoad.detectStatic).toBeCalledWith(hass);
|
||||
});
|
||||
|
||||
it('should isolate a failing issue and continue detecting the rest', async () => {
|
||||
const spy = vi.spyOn(console, 'warn').mockReturnValue();
|
||||
assert(mockConfigUpgrade.detectStatic);
|
||||
assert(mockLegacyResource.detectStatic);
|
||||
assert(mockMediaLoad.detectStatic);
|
||||
|
||||
vi.mocked(mockConfigUpgrade.detectStatic).mockRejectedValue(new Error('boom'));
|
||||
|
||||
// A second failure, a non-Error rejection, is isolated and logged too.
|
||||
vi.mocked(mockLegacyResource.detectStatic).mockRejectedValue('bad');
|
||||
|
||||
const manager = createManager();
|
||||
const hass = createHASS();
|
||||
|
||||
await expect(manager.detectStatic(hass)).resolves.toBeUndefined();
|
||||
|
||||
// Detection continued to the final issue despite the two earlier failures.
|
||||
expect(mockMediaLoad.detectStatic).toBeCalledWith(hass);
|
||||
expect(spy).toBeCalledTimes(2);
|
||||
spy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('trigger', () => {
|
||||
|
||||
Reference in New Issue
Block a user