mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
166 lines
4.6 KiB
TypeScript
166 lines
4.6 KiB
TypeScript
import { afterEach, describe, expect, it } from 'vitest';
|
|
|
|
import { createState, flush } from '../../../core/state';
|
|
import { createTestHost } from '../../tests/test-utils';
|
|
import { SnapshotController } from '../snapshot-controller';
|
|
|
|
describe('SnapshotController', () => {
|
|
afterEach(() => {
|
|
document.body.innerHTML = '';
|
|
});
|
|
|
|
describe('without selector', () => {
|
|
it('returns full state', () => {
|
|
const state = createState({ volume: 0.8, muted: false });
|
|
const host = createTestHost();
|
|
|
|
const controller = new SnapshotController(host, state);
|
|
document.body.appendChild(host);
|
|
|
|
expect(controller.value).toEqual({ volume: 0.8, muted: false });
|
|
});
|
|
|
|
it('triggers update on any state change', async () => {
|
|
const state = createState({ volume: 1, muted: false });
|
|
const host = createTestHost();
|
|
|
|
new SnapshotController(host, state);
|
|
document.body.appendChild(host);
|
|
|
|
await Promise.resolve();
|
|
const initialCount = host.updateCount;
|
|
|
|
state.patch({ volume: 0.5 });
|
|
flush();
|
|
await Promise.resolve();
|
|
|
|
expect(host.updateCount).toBeGreaterThan(initialCount);
|
|
});
|
|
});
|
|
|
|
describe('with selector', () => {
|
|
it('returns selected value', () => {
|
|
const state = createState({ volume: 0.7, muted: true });
|
|
const host = createTestHost();
|
|
|
|
const controller = new SnapshotController(host, state, (s) => s.volume);
|
|
document.body.appendChild(host);
|
|
|
|
expect(controller.value).toBe(0.7);
|
|
});
|
|
|
|
it('triggers update when selected state changes', async () => {
|
|
const state = createState({ volume: 1, muted: false });
|
|
const host = createTestHost();
|
|
|
|
const controller = new SnapshotController(host, state, (s) => s.volume);
|
|
document.body.appendChild(host);
|
|
|
|
expect(controller.value).toBe(1);
|
|
|
|
state.patch({ volume: 0.5 });
|
|
flush();
|
|
await Promise.resolve();
|
|
|
|
expect(controller.value).toBe(0.5);
|
|
expect(host.updateCount).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('does not trigger update when unrelated state changes', async () => {
|
|
const state = createState({ volume: 1, muted: false });
|
|
const host = createTestHost();
|
|
|
|
new SnapshotController(host, state, (s) => s.volume);
|
|
document.body.appendChild(host);
|
|
|
|
await Promise.resolve();
|
|
const initialCount = host.updateCount;
|
|
|
|
state.patch({ muted: true });
|
|
flush();
|
|
await Promise.resolve();
|
|
|
|
expect(host.updateCount).toBe(initialCount);
|
|
});
|
|
});
|
|
|
|
describe('lifecycle', () => {
|
|
it('unsubscribes on disconnect', async () => {
|
|
const state = createState({ volume: 1, muted: false });
|
|
const host = createTestHost();
|
|
|
|
new SnapshotController(host, state, (s) => s.volume);
|
|
document.body.appendChild(host);
|
|
host.remove();
|
|
|
|
const updateCountBefore = host.updateCount;
|
|
|
|
state.patch({ volume: 0.5 });
|
|
flush();
|
|
await Promise.resolve();
|
|
|
|
expect(host.updateCount).toBe(updateCountBefore);
|
|
});
|
|
|
|
it('resubscribes on reconnect', async () => {
|
|
const state = createState({ volume: 1, muted: false });
|
|
const host = createTestHost();
|
|
|
|
const controller = new SnapshotController(host, state, (s) => s.volume);
|
|
document.body.appendChild(host);
|
|
|
|
expect(controller.value).toBe(1);
|
|
|
|
host.remove();
|
|
|
|
state.patch({ volume: 0.8 });
|
|
flush();
|
|
|
|
// Reconnect
|
|
document.body.appendChild(host);
|
|
|
|
expect(controller.value).toBe(0.8);
|
|
});
|
|
});
|
|
|
|
describe('track', () => {
|
|
it('switches to a different state container', async () => {
|
|
const state1 = createState({ volume: 1, muted: false });
|
|
const state2 = createState({ volume: 0.3, muted: true });
|
|
const host = createTestHost();
|
|
|
|
const controller = new SnapshotController(host, state1, (s) => s.volume);
|
|
document.body.appendChild(host);
|
|
|
|
expect(controller.value).toBe(1);
|
|
|
|
controller.track(state2);
|
|
|
|
expect(controller.value).toBe(0.3);
|
|
});
|
|
|
|
it('unsubscribes from previous state on track', async () => {
|
|
const state1 = createState({ volume: 1, muted: false });
|
|
const state2 = createState({ volume: 0.5, muted: false });
|
|
const host = createTestHost();
|
|
|
|
const controller = new SnapshotController(host, state1, (s) => s.volume);
|
|
document.body.appendChild(host);
|
|
|
|
await Promise.resolve();
|
|
|
|
// Switch to state2
|
|
controller.track(state2);
|
|
|
|
const countAfterTrack = host.updateCount;
|
|
|
|
// Mutate state1 — should NOT trigger update
|
|
state1.patch({ volume: 0.2 });
|
|
flush();
|
|
await Promise.resolve();
|
|
|
|
expect(host.updateCount).toBe(countAfterTrack);
|
|
});
|
|
});
|
|
});
|