mirror of
https://github.com/jcreek/LivingDexTracker.git
synced 2026-09-16 02:22:17 +00:00
fix(sync): keep queued catch-record writes from crossing an account change
The queue held whole records and flushed whatever was in it, so edits made before a sign-out could be written against the account that signed in next. Queue patches and merge them per key, so two edits to one entry combine instead of one replacing the other; drop everything when the owning account is no longer the current one; and stop scheduling flushes while offline, where they could only fail and back off.
This commit is contained in:
@@ -28,6 +28,27 @@ describe('createCatchRecordWriteQueue()', () => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it('merges partial notes/status patches without inventing omitted fields', async () => {
|
||||
const fetchFn = vi.fn(async () => new Response('[]'));
|
||||
const queue = createCatchRecordWriteQueue({ endpointUrl: '/api/catches', fetchFn });
|
||||
const identity = { userId: 'u', pokedexId: 'd', pokemonId: '1' };
|
||||
queue.enqueue({ ...identity, personalNotes: 'Keep' }, { flushSoon: false });
|
||||
queue.enqueue({ ...identity, inHome: true }, { flushSoon: false });
|
||||
expect(queue.getPendingPatch('1')).toEqual({
|
||||
...identity,
|
||||
personalNotes: 'Keep',
|
||||
inHome: true
|
||||
});
|
||||
await queue.flushNow();
|
||||
const payload = JSON.parse(
|
||||
String((fetchFn.mock.calls[0] as unknown as [string, RequestInit])[1].body)
|
||||
);
|
||||
expect(payload).toEqual([{ ...identity, personalNotes: 'Keep', inHome: true }]);
|
||||
queue.enqueue({ ...identity, personalNotes: '' }, { flushSoon: false });
|
||||
expect(queue.getPendingPatch('1')?.personalNotes).toBe('');
|
||||
await queue.flushNow();
|
||||
});
|
||||
|
||||
it('coalesces multiple updates for the same key and flushes only the latest state', async () => {
|
||||
const fetchFn = vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
|
||||
return new Response(init?.body as string, { status: 200 });
|
||||
@@ -141,6 +162,21 @@ describe('createCatchRecordWriteQueue()', () => {
|
||||
expect(queue.getPendingCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('discards queued edits after the owning account changes', async () => {
|
||||
const fetchFn = vi.fn<typeof fetch>();
|
||||
let current = true;
|
||||
const queue = createCatchRecordWriteQueue({
|
||||
endpointUrl: '/catch-records',
|
||||
fetchFn,
|
||||
isCurrentUser: () => current
|
||||
});
|
||||
queue.enqueue(mkRecord(), { debounceMs: 100, flushSoon: false });
|
||||
current = false;
|
||||
await queue.flushNow();
|
||||
expect(fetchFn).not.toHaveBeenCalled();
|
||||
expect(queue.getPendingCount()).toBe(0);
|
||||
});
|
||||
|
||||
it('does not discard a newer version enqueued during an in-flight request', async () => {
|
||||
let resolveFirst: ((response: Response) => void) | undefined;
|
||||
const firstResponse = new Promise<Response>((resolve) => (resolveFirst = resolve));
|
||||
|
||||
Reference in New Issue
Block a user