115 lines
3.1 KiB
TypeScript
115 lines
3.1 KiB
TypeScript
|
|
import assert from 'node:assert/strict';
|
||
|
|
import test from 'node:test';
|
||
|
|
|
||
|
|
import {
|
||
|
|
EMPTY_NOTES_SNAPSHOT,
|
||
|
|
getEmptyNotesSnapshot,
|
||
|
|
getNotesActions,
|
||
|
|
getNotesSnapshot,
|
||
|
|
publishNotesSnapshot,
|
||
|
|
registerNotesActions,
|
||
|
|
subscribeNotes,
|
||
|
|
subscribeNotesNoop,
|
||
|
|
} from './notesStore.ts';
|
||
|
|
|
||
|
|
test('notesStore notifies subscribers only when snapshot identity changes', () => {
|
||
|
|
const events: number[] = [];
|
||
|
|
const unsubscribe = subscribeNotes(() => {
|
||
|
|
events.push(getNotesSnapshot().notes.length);
|
||
|
|
});
|
||
|
|
|
||
|
|
const firstNotes = [{
|
||
|
|
id: 'n1',
|
||
|
|
title: 'One',
|
||
|
|
content: 'body',
|
||
|
|
tags: [],
|
||
|
|
createdAt: 1,
|
||
|
|
updatedAt: 1,
|
||
|
|
order: 1000,
|
||
|
|
}];
|
||
|
|
const firstGroups = ['Ops'];
|
||
|
|
publishNotesSnapshot({ notes: firstNotes, noteGroups: firstGroups });
|
||
|
|
assert.equal(events.at(-1), 1);
|
||
|
|
assert.equal(getNotesSnapshot().notes, firstNotes);
|
||
|
|
assert.equal(getNotesSnapshot().noteGroups, firstGroups);
|
||
|
|
|
||
|
|
publishNotesSnapshot({ notes: firstNotes, noteGroups: firstGroups });
|
||
|
|
assert.equal(events.length, 1);
|
||
|
|
|
||
|
|
const secondNotes = [
|
||
|
|
...firstNotes,
|
||
|
|
{
|
||
|
|
id: 'n2',
|
||
|
|
title: 'Two',
|
||
|
|
content: 'more',
|
||
|
|
tags: [],
|
||
|
|
createdAt: 2,
|
||
|
|
updatedAt: 2,
|
||
|
|
order: 2000,
|
||
|
|
},
|
||
|
|
];
|
||
|
|
publishNotesSnapshot({ notes: secondNotes, noteGroups: firstGroups });
|
||
|
|
assert.equal(events.at(-1), 2);
|
||
|
|
|
||
|
|
publishNotesSnapshot({ notes: secondNotes, noteGroups: ['Ops', 'DB'] });
|
||
|
|
assert.equal(events.length, 3);
|
||
|
|
assert.deepEqual(getNotesSnapshot().noteGroups, ['Ops', 'DB']);
|
||
|
|
|
||
|
|
unsubscribe();
|
||
|
|
});
|
||
|
|
|
||
|
|
test('notesStore gated helpers stay empty and never notify', () => {
|
||
|
|
let called = 0;
|
||
|
|
const unsub = subscribeNotesNoop(() => {
|
||
|
|
called += 1;
|
||
|
|
});
|
||
|
|
publishNotesSnapshot({
|
||
|
|
notes: [{
|
||
|
|
id: 'n1',
|
||
|
|
title: 'One',
|
||
|
|
content: 'body',
|
||
|
|
tags: [],
|
||
|
|
createdAt: 1,
|
||
|
|
updatedAt: 1,
|
||
|
|
order: 1000,
|
||
|
|
}],
|
||
|
|
noteGroups: ['Ops'],
|
||
|
|
});
|
||
|
|
assert.equal(called, 0);
|
||
|
|
assert.equal(getEmptyNotesSnapshot(), EMPTY_NOTES_SNAPSHOT);
|
||
|
|
assert.equal(getEmptyNotesSnapshot().notes.length, 0);
|
||
|
|
unsub();
|
||
|
|
});
|
||
|
|
|
||
|
|
test('useNotesStore source gates subscribe when enabled is false', async () => {
|
||
|
|
const { readFileSync } = await import('node:fs');
|
||
|
|
const source = readFileSync(new URL('./notesStore.ts', import.meta.url), 'utf8');
|
||
|
|
assert.match(source, /enabled \? subscribeNotes : subscribeNotesNoop/);
|
||
|
|
assert.match(source, /enabled \? subscribeNotesActions : subscribeNotesNoop/);
|
||
|
|
assert.match(source, /getNotesSnapshot/);
|
||
|
|
assert.doesNotMatch(
|
||
|
|
source,
|
||
|
|
/enabled \? getNotesSnapshot : getEmptyNotesSnapshot/,
|
||
|
|
'hidden notes mounts should keep the last live snapshot, not flash empty',
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('registerNotesActions exposes update handlers', () => {
|
||
|
|
const calls: string[] = [];
|
||
|
|
registerNotesActions({
|
||
|
|
updateNotes: () => {
|
||
|
|
calls.push('notes');
|
||
|
|
},
|
||
|
|
updateNoteGroups: () => {
|
||
|
|
calls.push('groups');
|
||
|
|
},
|
||
|
|
});
|
||
|
|
const actions = getNotesActions();
|
||
|
|
assert.ok(actions);
|
||
|
|
actions!.updateNotes([]);
|
||
|
|
actions!.updateNoteGroups([]);
|
||
|
|
assert.deepEqual(calls, ['notes', 'groups']);
|
||
|
|
registerNotesActions(null);
|
||
|
|
assert.equal(getNotesActions(), null);
|
||
|
|
});
|