223 lines
6.4 KiB
TypeScript
223 lines
6.4 KiB
TypeScript
import type { ReactiveControllerHost } from 'lit';
|
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
import { mock } from 'vitest-mock-extended';
|
|
|
|
import { CachedValueController } from '../../src/components-lib/cached-value-controller';
|
|
|
|
// @vitest-environment jsdom
|
|
describe('CachedValueController', () => {
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
it('should not restart timer on hostUpdate if not connected', () => {
|
|
const host = mock<ReactiveControllerHost & HTMLElement>();
|
|
const callback = vi.fn().mockReturnValue(42);
|
|
let refreshSeconds: number | null = 10;
|
|
|
|
const controller = new CachedValueController(host, () => refreshSeconds, callback);
|
|
|
|
Object.defineProperty(host, 'isConnected', { get: () => false });
|
|
|
|
refreshSeconds = 20;
|
|
controller.hostUpdate();
|
|
expect(controller.hasTimer()).toBeFalsy();
|
|
});
|
|
|
|
it('should not restart timer if unchanged on hostUpdate', () => {
|
|
const host = mock<ReactiveControllerHost & HTMLElement>();
|
|
const callback = vi.fn().mockReturnValue(42);
|
|
const refreshSeconds: number | null = 10;
|
|
|
|
const controller = new CachedValueController(host, () => refreshSeconds, callback);
|
|
|
|
Object.defineProperty(host, 'isConnected', { get: () => true });
|
|
|
|
// This starts the timer as isConnected is true
|
|
controller.hostConnected();
|
|
|
|
const startTimerSpy = vi.spyOn(controller, 'startTimer');
|
|
|
|
controller.hostUpdate();
|
|
|
|
// Should not restart since refreshSeconds hasn't changed
|
|
expect(startTimerSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should construct', () => {
|
|
const host = mock<ReactiveControllerHost & HTMLElement>();
|
|
const callback = vi.fn();
|
|
const controller = new CachedValueController(host, () => 10, callback);
|
|
|
|
expect(controller).toBeTruthy();
|
|
});
|
|
|
|
it('should have timer', () => {
|
|
const host = mock<ReactiveControllerHost & HTMLElement>();
|
|
const callback = vi.fn();
|
|
const startCallback = vi.fn();
|
|
const stopCallback = vi.fn();
|
|
|
|
vi.useFakeTimers();
|
|
|
|
const controller = new CachedValueController(
|
|
host,
|
|
() => 10,
|
|
callback,
|
|
startCallback,
|
|
stopCallback,
|
|
);
|
|
|
|
controller.startTimer();
|
|
expect(startCallback).toHaveBeenCalled();
|
|
|
|
callback.mockReturnValue(3);
|
|
vi.runOnlyPendingTimers();
|
|
expect(callback).toHaveBeenCalled();
|
|
expect(host.requestUpdate).toHaveBeenCalled();
|
|
expect(controller.getValue()).toBe(3);
|
|
|
|
callback.mockReturnValue(4);
|
|
vi.runOnlyPendingTimers();
|
|
expect(callback).toHaveBeenCalled();
|
|
expect(host.requestUpdate).toHaveBeenCalled();
|
|
expect(controller.getValue()).toBe(4);
|
|
|
|
expect(controller.hasTimer()).toBeTruthy();
|
|
|
|
controller.stopTimer();
|
|
expect(stopCallback).toHaveBeenCalled();
|
|
|
|
callback.mockReset();
|
|
vi.runOnlyPendingTimers();
|
|
expect(callback).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should clear value', () => {
|
|
const host = mock<ReactiveControllerHost & HTMLElement>();
|
|
const callback = vi.fn().mockReturnValue(42);
|
|
|
|
vi.useFakeTimers();
|
|
|
|
const controller = new CachedValueController(host, () => 10, callback);
|
|
controller.startTimer();
|
|
|
|
vi.runOnlyPendingTimers();
|
|
expect(controller.getValue()).equal(42);
|
|
|
|
controller.clearValue();
|
|
expect(controller.getValue()).toBeNull();
|
|
});
|
|
|
|
it('should connect and disconnect host', () => {
|
|
const host = mock<ReactiveControllerHost & HTMLElement>();
|
|
const callback = vi.fn().mockReturnValue(43);
|
|
const startCallback = vi.fn();
|
|
const stopCallback = vi.fn();
|
|
|
|
const controller = new CachedValueController(
|
|
host,
|
|
() => 10,
|
|
callback,
|
|
startCallback,
|
|
stopCallback,
|
|
);
|
|
|
|
controller.hostConnected();
|
|
expect(controller.getValue()).equal(43);
|
|
expect(startCallback).toHaveBeenCalled();
|
|
expect(host.requestUpdate).toHaveBeenCalled();
|
|
|
|
controller.hostDisconnected();
|
|
expect(controller.getValue()).toBeNull();
|
|
expect(stopCallback).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call timer tick callback on each tick before updateValue', () => {
|
|
const host = mock<ReactiveControllerHost & HTMLElement>();
|
|
const callback = vi.fn().mockReturnValue('value');
|
|
const tickCallback = vi.fn();
|
|
|
|
vi.useFakeTimers();
|
|
|
|
const controller = new CachedValueController(
|
|
host,
|
|
() => 5,
|
|
callback,
|
|
undefined,
|
|
undefined,
|
|
tickCallback,
|
|
);
|
|
|
|
controller.startTimer();
|
|
|
|
vi.runOnlyPendingTimers();
|
|
expect(tickCallback).toHaveBeenCalledTimes(1);
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
|
|
vi.runOnlyPendingTimers();
|
|
expect(tickCallback).toHaveBeenCalledTimes(2);
|
|
expect(callback).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it('should not call timerTickCallback on manual updateValue', () => {
|
|
const host = mock<ReactiveControllerHost & HTMLElement>();
|
|
const callback = vi.fn().mockReturnValue('value');
|
|
const tickCallback = vi.fn();
|
|
|
|
const controller = new CachedValueController(
|
|
host,
|
|
() => 5,
|
|
callback,
|
|
undefined,
|
|
undefined,
|
|
tickCallback,
|
|
);
|
|
|
|
controller.updateValue();
|
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
expect(tickCallback).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should restart timer with new interval on hostUpdate', () => {
|
|
const host = mock<ReactiveControllerHost & HTMLElement>();
|
|
const callback = vi.fn().mockReturnValue(42);
|
|
let refreshSeconds: number | null = null;
|
|
|
|
const controller = new CachedValueController(host, () => refreshSeconds, callback);
|
|
|
|
vi.useFakeTimers();
|
|
Object.defineProperty(host, 'isConnected', { get: () => true });
|
|
controller.hostConnected();
|
|
expect(controller.hasTimer()).toBeFalsy();
|
|
|
|
refreshSeconds = 20;
|
|
controller.hostUpdate();
|
|
|
|
// Timer should have been restarted. Fast forward 15 seconds. If it didn't
|
|
// restart, it would fire at 10 seconds. Since it restarted at 20 seconds,
|
|
// it shouldn't fire at 15 seconds.
|
|
callback.mockClear();
|
|
vi.advanceTimersByTime(15 * 1000);
|
|
expect(callback).not.toHaveBeenCalled();
|
|
|
|
vi.advanceTimersByTime(5 * 1000);
|
|
expect(callback).toHaveBeenCalled();
|
|
|
|
// Now set it to null -> stops timer
|
|
refreshSeconds = null;
|
|
controller.hostUpdate();
|
|
expect(controller.hasTimer()).toBeFalsy();
|
|
|
|
// Now set it to 0 -> stops timer
|
|
refreshSeconds = 0;
|
|
controller.hostUpdate();
|
|
expect(controller.hasTimer()).toBeFalsy();
|
|
|
|
// Now set it to negative -> stops timer
|
|
refreshSeconds = -1;
|
|
controller.hostUpdate();
|
|
expect(controller.hasTimer()).toBeFalsy();
|
|
});
|
|
});
|