mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
fix(app): keep timers running while the window is visible but unfocused (#1682)
This commit is contained in:
1 parent
438f11adda
commit
30a1271774
2 files changed
+69
-4
No files matched your search
@@ -0,0 +1,65 @@
|
|||||||
|
// @vitest-environment happy-dom
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
import {autorun} from 'mobx';
|
||||||
|
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
|
||||||
|
|
||||||
|
async function loadTick() {
|
||||||
|
vi.resetModules();
|
||||||
|
const {default: Window} = await import('@app/features/window/state/Window');
|
||||||
|
const {default: Tick} = await import('@app/features/ui/state/Tick');
|
||||||
|
return {Tick, Window};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Tick', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.useFakeTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.useRealTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps counting while the window is visible but not focused', async () => {
|
||||||
|
const {Tick, Window} = await loadTick();
|
||||||
|
const dispose = autorun(() => Tick.nowSecond);
|
||||||
|
const started = Tick.nowSecond;
|
||||||
|
Window.setFocused(false);
|
||||||
|
vi.advanceTimersByTime(3000);
|
||||||
|
expect(Window.visible).toBe(true);
|
||||||
|
expect(Tick.nowSecond).toBe(started + 3);
|
||||||
|
dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('stops counting while the window is hidden', async () => {
|
||||||
|
const {Tick, Window} = await loadTick();
|
||||||
|
const dispose = autorun(() => Tick.nowSecond);
|
||||||
|
Window.setVisible(false);
|
||||||
|
const stopped = Tick.nowSecond;
|
||||||
|
vi.advanceTimersByTime(5000);
|
||||||
|
expect(Tick.nowSecond).toBe(stopped);
|
||||||
|
dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resynchronises to wall clock as soon as the window becomes visible again', async () => {
|
||||||
|
const {Tick, Window} = await loadTick();
|
||||||
|
const dispose = autorun(() => Tick.nowSecond);
|
||||||
|
Window.setVisible(false);
|
||||||
|
const stopped = Tick.nowSecond;
|
||||||
|
vi.advanceTimersByTime(60_000);
|
||||||
|
expect(Tick.nowSecond).toBe(stopped);
|
||||||
|
Window.setVisible(true);
|
||||||
|
expect(Tick.nowSecond).toBe(stopped + 60);
|
||||||
|
dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not run an interval while nothing observes the clock', async () => {
|
||||||
|
const {Tick} = await loadTick();
|
||||||
|
const idle = Tick.nowSecond;
|
||||||
|
vi.advanceTimersByTime(5000);
|
||||||
|
expect(Tick.nowSecond).toBe(idle);
|
||||||
|
const dispose = autorun(() => Tick.nowSecond);
|
||||||
|
expect(Tick.nowSecond).toBe(idle + 5);
|
||||||
|
dispose();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -20,9 +20,9 @@ class TickRegistryImpl {
|
|||||||
this.stop();
|
this.stop();
|
||||||
});
|
});
|
||||||
reaction(
|
reaction(
|
||||||
() => Window.focused,
|
() => Window.visible,
|
||||||
(focused) => {
|
(visible) => {
|
||||||
if (focused) this.start();
|
if (visible) this.start();
|
||||||
else this.stop();
|
else this.stop();
|
||||||
},
|
},
|
||||||
{fireImmediately: true},
|
{fireImmediately: true},
|
||||||
@@ -30,7 +30,7 @@ class TickRegistryImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private start(): void {
|
private start(): void {
|
||||||
if (!this.observed || !Window.focused || this.intervalId !== null) return;
|
if (!this.observed || !Window.visible || this.intervalId !== null) return;
|
||||||
this.tick();
|
this.tick();
|
||||||
this.intervalId = window.setInterval(() => this.tick(), 1000);
|
this.intervalId = window.setInterval(() => this.tick(), 1000);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user