Skip to content

Commit 141bff8

Browse files
committed
Added unit tests.
1 parent ba64abb commit 141bff8

File tree

2 files changed

+176
-1
lines changed

2 files changed

+176
-1
lines changed

packages/react/tests/useQuery.test.tsx

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,91 @@ describe('useQuery', () => {
542542
// It should be the same data array reference, no update should have happened
543543
expect(result.current.data == previousData).false;
544544
});
545+
546+
it('should handle dependent query parameter changes with correct state transitions', async () => {
547+
const db = openPowerSync();
548+
549+
await db.execute(/* sql */ `
550+
INSERT INTO
551+
lists (id, name)
552+
VALUES
553+
(uuid (), 'item1')
554+
`);
555+
556+
// Track state transitions
557+
const stateTransitions: Array<{
558+
param: string | number;
559+
dataLength: number;
560+
isFetching: boolean;
561+
isLoading: boolean;
562+
}> = [];
563+
564+
const testHook = () => {
565+
// First query that provides the parameter - starts with 0, then returns 1
566+
const { data: paramData } = useQuery('SELECT 1 as result;', []);
567+
const param = paramData?.[0]?.result ?? 0;
568+
569+
// Second query that depends on the first query's result
570+
const { data, isFetching, isLoading } = useQuery('SELECT * FROM lists LIMIT ?', [param]);
571+
572+
const currentState = {
573+
param: param,
574+
dataLength: data?.length || 0,
575+
isFetching: isFetching,
576+
isLoading: isLoading
577+
};
578+
579+
stateTransitions.push(currentState);
580+
return currentState;
581+
};
582+
583+
const { result } = renderHook(() => testHook(), {
584+
wrapper: ({ children }) => testWrapper({ children, db })
585+
});
586+
587+
// Wait for final state
588+
await waitFor(
589+
() => {
590+
const { current } = result;
591+
expect(current.isLoading).toEqual(false);
592+
expect(current.isFetching).toEqual(false);
593+
expect(current.param).toEqual(1);
594+
expect(current.dataLength).toEqual(1);
595+
},
596+
{ timeout: 500, interval: 100 }
597+
);
598+
599+
// Find the index where param changes from 0 to 1
600+
let beforeParamChangeIndex = 0;
601+
for (const transition of stateTransitions) {
602+
if (transition.param === 1) {
603+
beforeParamChangeIndex = stateTransitions.indexOf(transition) - 1;
604+
break;
605+
}
606+
}
607+
608+
const indexMultiplier = isStrictMode ? 2 : 1; // StrictMode causes 1 extra render per state
609+
const initialState = stateTransitions[beforeParamChangeIndex];
610+
expect(initialState).toBeDefined();
611+
expect(initialState?.param).toEqual(0);
612+
expect(initialState?.dataLength).toEqual(0);
613+
expect(initialState?.isFetching).toEqual(true);
614+
expect(initialState?.isLoading).toEqual(true);
615+
616+
const paramChangedState = stateTransitions[beforeParamChangeIndex + 1 * indexMultiplier];
617+
expect(paramChangedState).toBeDefined();
618+
expect(paramChangedState?.param).toEqual(1);
619+
expect(paramChangedState?.dataLength).toEqual(0);
620+
expect(paramChangedState?.isFetching).toEqual(true);
621+
expect(paramChangedState?.isLoading).toEqual(true);
622+
623+
const finalState = stateTransitions[beforeParamChangeIndex + 2 * indexMultiplier];
624+
expect(finalState).toBeDefined();
625+
expect(finalState.param).toEqual(1);
626+
expect(finalState.dataLength).toEqual(1);
627+
expect(finalState.isFetching).toEqual(false);
628+
expect(finalState.isLoading).toEqual(false);
629+
});
545630
});
546631
});
547632

packages/vue/tests/useQuery.test.ts

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as commonSdk from '@powersync/common';
22
import { PowerSyncDatabase } from '@powersync/web';
33
import flushPromises from 'flush-promises';
44
import { describe, expect, it, onTestFinished, vi } from 'vitest';
5-
import { isProxy, isRef, ref } from 'vue';
5+
import { computed, isProxy, isRef, ref, watchEffect } from 'vue';
66
import { createPowerSyncPlugin } from '../src/composables/powerSync';
77
import { useQuery } from '../src/composables/useQuery';
88
import { useWatchedQuerySubscription } from '../src/composables/useWatchedQuerySubscription';
@@ -233,4 +233,94 @@ describe('useQuery', () => {
233233
'PowerSync failed to fetch data: You cannot pass parameters to a compiled query.'
234234
);
235235
});
236+
237+
it('should handle dependent query parameter changes with correct state transitions', async () => {
238+
const db = openPowerSync();
239+
240+
await db.execute(/* sql */ `
241+
INSERT INTO
242+
lists (id, name)
243+
VALUES
244+
(uuid (), 'item1')
245+
`);
246+
247+
// Track state transitions
248+
const stateTransitions: Array<{
249+
param: string | number;
250+
dataLength: number;
251+
isFetching: boolean;
252+
isLoading: boolean;
253+
}> = [];
254+
255+
const [state] = withPowerSyncSetup(() => {
256+
// First query that provides the parameter - starts with 0, then returns 1
257+
const paramQuery = useQuery('SELECT 1 as result;', []);
258+
const param = computed(() => paramQuery.data.value?.[0]?.result ?? 0);
259+
260+
// Second query that depends on the first query's result
261+
const dataQuery = useQuery(
262+
computed(() => 'SELECT * FROM lists LIMIT ?'),
263+
computed(() => [param.value])
264+
);
265+
266+
// Track state changes
267+
watchEffect(() => {
268+
const currentState = {
269+
param: param.value,
270+
dataLength: dataQuery.data.value?.length || 0,
271+
isFetching: dataQuery.isFetching.value,
272+
isLoading: dataQuery.isLoading.value
273+
};
274+
stateTransitions.push(currentState);
275+
});
276+
277+
return {
278+
paramData: paramQuery.data,
279+
data: dataQuery.data,
280+
isFetching: dataQuery.isFetching,
281+
isLoading: dataQuery.isLoading,
282+
param
283+
};
284+
});
285+
286+
// Wait for final state
287+
await vi.waitFor(
288+
() => {
289+
expect(state.isLoading.value).toEqual(false);
290+
expect(state.isFetching.value).toEqual(false);
291+
expect(state.data.value?.length).toEqual(1);
292+
expect(state.paramData.value[0].result).toEqual(1);
293+
},
294+
{ timeout: 1000 }
295+
);
296+
297+
// Find the index where param changes from 0 to 1
298+
let beforeParamChangeIndex = 0;
299+
for (const transition of stateTransitions) {
300+
if (transition.param === 1) {
301+
beforeParamChangeIndex = stateTransitions.indexOf(transition) - 1;
302+
break;
303+
}
304+
}
305+
const initialState = stateTransitions[beforeParamChangeIndex];
306+
expect(initialState).toBeDefined();
307+
expect(initialState?.param).toEqual(0);
308+
expect(initialState?.dataLength).toEqual(0);
309+
expect(initialState?.isFetching).toEqual(true);
310+
expect(initialState?.isLoading).toEqual(true);
311+
312+
const paramChangedState = stateTransitions[beforeParamChangeIndex + 1];
313+
expect(paramChangedState).toBeDefined();
314+
expect(paramChangedState?.param).toEqual(1);
315+
expect(paramChangedState?.dataLength).toEqual(0);
316+
expect(paramChangedState?.isFetching).toEqual(true);
317+
expect(paramChangedState?.isLoading).toEqual(true);
318+
319+
const finalState = stateTransitions[beforeParamChangeIndex + 2];
320+
expect(finalState).toBeDefined();
321+
expect(finalState.param).toEqual(1);
322+
expect(finalState.dataLength).toEqual(1);
323+
expect(finalState.isFetching).toEqual(false);
324+
expect(finalState.isLoading).toEqual(false);
325+
});
236326
});

0 commit comments

Comments
 (0)