Extract setOptionalInterval util from SessionController

pull/12295/head
Sage Abdullah 2024-08-23 11:38:33 +01:00 zatwierdzone przez LB (Ben Johnston)
rodzic 7b67723da9
commit a5b42936ec
3 zmienionych plików z 87 dodań i 6 usunięć

Wyświetl plik

@ -2,6 +2,7 @@ import { Controller } from '@hotwired/stimulus';
import { DialogController } from './DialogController';
import { SwapController } from './SwapController';
import { ActionController } from './ActionController';
import { setOptionalInterval } from '../utils/interval';
interface PingResponse {
session_id: string;
@ -73,7 +74,7 @@ export class SessionController extends Controller<HTMLElement> {
declare interceptValue: boolean;
/** The interval ID for the periodic pinging */
declare interval: number;
declare interval: number | null;
/** The last action button that triggered the event */
lastActionButton?: HTMLButtonElement;
@ -120,11 +121,7 @@ export class SessionController extends Controller<HTMLElement> {
*/
addInterval(): void {
this.clearInterval();
// Values outside this range will be ignored by window.setInterval,
// making it fire all the time.
if (this.intervalValue <= 0 || this.intervalValue >= 2 ** 31) return;
this.interval = window.setInterval(this.ping, this.intervalValue);
this.interval = setOptionalInterval(this.ping, this.intervalValue);
}
/**
@ -133,6 +130,7 @@ export class SessionController extends Controller<HTMLElement> {
clearInterval(): void {
if (this.interval) {
window.clearInterval(this.interval);
this.interval = null;
}
}

Wyświetl plik

@ -0,0 +1,59 @@
import { setOptionalInterval } from './interval';
jest.useFakeTimers();
jest.spyOn(global, 'setInterval');
describe('setOptionalInterval', () => {
afterEach(() => {
jest.clearAllMocks();
jest.clearAllTimers();
});
it('should be a pass-through for setInterval in normal cases', () => {
const callback = jest.fn();
const interval = setOptionalInterval(callback, 1);
expect(setInterval).toHaveBeenCalledWith(callback, 1);
expect(interval).toEqual(global.setInterval.mock.results[0].value);
expect(callback).not.toHaveBeenCalled();
jest.advanceTimersByTime(1);
expect(callback).toHaveBeenCalledTimes(1);
});
it('should not set the interval if the delay is unset', () => {
const callback = jest.fn();
const interval = setOptionalInterval(callback);
expect(setInterval).not.toHaveBeenCalled();
expect(interval).toBeNull();
expect(callback).not.toHaveBeenCalled();
jest.advanceTimersByTime(100);
expect(callback).not.toHaveBeenCalled();
});
it('should not set the interval if the delay is set to 0', () => {
const callback = jest.fn();
const interval = setOptionalInterval(callback, 0);
expect(setInterval).not.toHaveBeenCalled();
expect(interval).toBeNull();
expect(callback).not.toHaveBeenCalled();
jest.advanceTimersByTime(100);
expect(callback).not.toHaveBeenCalled();
});
it('should not set the interval if the delay is set to a very large value', () => {
const callback = jest.fn();
const interval = setOptionalInterval(callback, 9999999999);
expect(setInterval).not.toHaveBeenCalled();
expect(interval).toBeNull();
expect(callback).not.toHaveBeenCalled();
jest.advanceTimersByTime(10000000000);
expect(callback).not.toHaveBeenCalled();
});
});

Wyświetl plik

@ -0,0 +1,24 @@
/**
* Like `setInterval`, but only sets the interval if the `delay` value is positive.
*
* Browsers treat non-positive `delay` values as 0, which means the interval will
* run immediately (basically all the time). Instead of allowing this behavior,
* this function will not set the interval instead. This allows the interval to
* be disabled by setting the `delay` value to <= 0 (or a large enough value that
* it overflows to negative), which is useful for user-configurable intervals.
*
* @param func the callback function to call
* @param delay the interval delay in milliseconds
* @param args the arguments to pass to the callback function
* @returns the interval ID if the interval is valid, otherwise null
*/
export const setOptionalInterval = (
func: TimerHandler,
delay?: number,
...args: any[]
) => {
// "The `delay` argument is converted to a signed 32-bit integer."
// https://developer.mozilla.org/en-US/docs/Web/API/setInterval#return_value
if (!delay || delay <= 0 || delay >= 2 ** 31) return null;
return setInterval(func, delay, ...args);
};