@accounter/client
Version:
Accounter client application
71 lines (54 loc) • 1.99 kB
text/typescript
// @vitest-environment happy-dom
import React, { act } from 'react';
import { createRoot, type Root } from 'react-dom/client';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { useStableValue } from '../use-stable-value.js';
let container: HTMLDivElement;
let root: Root;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
root = createRoot(container);
});
afterEach(() => {
act(() => root.unmount());
container.remove();
});
function renderStableValue<T>(): { render: (value: T) => T } {
const seen: T[] = [];
function Harness({ value }: { value: T }): null {
seen.push(useStableValue(value));
return null;
}
return {
render(value: T): T {
act(() => root.render(React.createElement(Harness, { value })));
return seen[seen.length - 1] as T;
},
};
}
describe('useStableValue', () => {
it('returns the same reference when a deeply-equal value is passed', () => {
const harness = renderStableValue<{ id: string }[]>();
const first = harness.render([{ id: 'a' }]);
// New array + object identity, same content (simulating a urql refetch).
const second = harness.render([{ id: 'a' }]);
expect(second).toBe(first);
});
it('returns a new reference when the value actually changes', () => {
const harness = renderStableValue<{ id: string }[]>();
const first = harness.render([{ id: 'a' }]);
const second = harness.render([{ id: 'b' }]);
expect(second).not.toBe(first);
expect(second).toEqual([{ id: 'b' }]);
});
it('tracks the latest value across a stable then changed sequence', () => {
const harness = renderStableValue<number[]>();
const first = harness.render([1, 2, 3]);
const stable = harness.render([1, 2, 3]);
const changed = harness.render([1, 2, 3, 4]);
expect(stable).toBe(first);
expect(changed).not.toBe(first);
expect(changed).toEqual([1, 2, 3, 4]);
});
});