Skip to content

Commit 4976409

Browse files
committed
merge test
1 parent bbcea4f commit 4976409

1 file changed

Lines changed: 142 additions & 8 deletions

File tree

packages/clients/tanstack-query/test/react-query.test.tsx

Lines changed: 142 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';
66
import { act, cleanup, renderHook, waitFor } from '@testing-library/react';
7+
import { deserialize, serialize } from '@zenstackhq/client-helpers/fetch';
78
import nock from 'nock';
89
import React from 'react';
910
import { afterEach, describe, expect, it } from 'vitest';
1011
import { getQueryKey } from '../src/common/query-key';
11-
import { QuerySettingsProvider, useClientQueries } from '../src/react';
12+
import { AnyNull, DbNull, JsonNull, QuerySettingsProvider, useClientQueries } from '../src/react';
1213
import { schema } from './schemas/basic/schema-lite';
1314

1415
const BASE_URL = 'http://localhost';
@@ -1817,10 +1818,9 @@ describe('React Query Test', () => {
18171818
return { data: [users[0], posts[0]] };
18181819
});
18191820

1820-
const { result: txResult } = renderHook(
1821-
() => useClientQueries(schema).$transaction.useSequential(),
1822-
{ wrapper },
1823-
);
1821+
const { result: txResult } = renderHook(() => useClientQueries(schema).$transaction.useSequential(), {
1822+
wrapper,
1823+
});
18241824

18251825
act(() =>
18261826
txResult.current.mutate([
@@ -1865,9 +1865,7 @@ describe('React Query Test', () => {
18651865
{ wrapper },
18661866
);
18671867

1868-
act(() =>
1869-
txResult.current.mutate([{ model: 'User', op: 'create', args: { data: { email: 'foo@bar.com' } } }]),
1870-
);
1868+
act(() => txResult.current.mutate([{ model: 'User', op: 'create', args: { data: { email: 'foo@bar.com' } } }]));
18711869

18721870
await waitFor(() => {
18731871
expect(txResult.current.isSuccess).toBe(true);
@@ -1876,4 +1874,140 @@ describe('React Query Test', () => {
18761874
expect(cachedUsers).toHaveLength(0);
18771875
});
18781876
});
1877+
1878+
describe('JSON null value serialization', () => {
1879+
function createWrapper() {
1880+
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
1881+
const wrapper = ({ children }: { children: React.ReactNode }) => (
1882+
<QueryClientProvider client={queryClient}>
1883+
<QuerySettingsProvider value={{ endpoint: `${BASE_URL}/api/model` }}>
1884+
{children}
1885+
</QuerySettingsProvider>
1886+
</QueryClientProvider>
1887+
);
1888+
return { queryClient, wrapper };
1889+
}
1890+
1891+
it('encodes DbNull in query filter and includes serialization metadata in URL', async () => {
1892+
const { wrapper } = createWrapper();
1893+
let capturedUri = '';
1894+
1895+
nock(BASE_URL)
1896+
.get(/.*/)
1897+
.reply(200, function (uri) {
1898+
capturedUri = uri;
1899+
return { data: [] };
1900+
});
1901+
1902+
const { result } = renderHook(
1903+
() => useClientQueries(schema).user.useFindMany({ where: { name: DbNull } } as any),
1904+
{ wrapper },
1905+
);
1906+
1907+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
1908+
1909+
const url = new URL(capturedUri, BASE_URL);
1910+
expect(url.searchParams.has('meta')).toBe(true);
1911+
1912+
const q = JSON.parse(decodeURIComponent(url.searchParams.get('q')!));
1913+
const meta = JSON.parse(decodeURIComponent(url.searchParams.get('meta')!));
1914+
const reconstructed = deserialize(q, meta.serialization) as any;
1915+
expect(reconstructed.where.name.__brand).toBe('DbNull');
1916+
});
1917+
1918+
it('encodes JsonNull in query filter and includes serialization metadata in URL', async () => {
1919+
const { wrapper } = createWrapper();
1920+
let capturedUri = '';
1921+
1922+
nock(BASE_URL)
1923+
.get(/.*/)
1924+
.reply(200, function (uri) {
1925+
capturedUri = uri;
1926+
return { data: [] };
1927+
});
1928+
1929+
const { result } = renderHook(
1930+
() => useClientQueries(schema).user.useFindMany({ where: { name: JsonNull } } as any),
1931+
{ wrapper },
1932+
);
1933+
1934+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
1935+
1936+
const url = new URL(capturedUri, BASE_URL);
1937+
expect(url.searchParams.has('meta')).toBe(true);
1938+
1939+
const q = JSON.parse(decodeURIComponent(url.searchParams.get('q')!));
1940+
const meta = JSON.parse(decodeURIComponent(url.searchParams.get('meta')!));
1941+
const reconstructed = deserialize(q, meta.serialization) as any;
1942+
expect(reconstructed.where.name.__brand).toBe('JsonNull');
1943+
});
1944+
1945+
it('encodes AnyNull in query filter and includes serialization metadata in URL', async () => {
1946+
const { wrapper } = createWrapper();
1947+
let capturedUri = '';
1948+
1949+
nock(BASE_URL)
1950+
.get(/.*/)
1951+
.reply(200, function (uri) {
1952+
capturedUri = uri;
1953+
return { data: [] };
1954+
});
1955+
1956+
const { result } = renderHook(
1957+
() => useClientQueries(schema).user.useFindMany({ where: { name: AnyNull } } as any),
1958+
{ wrapper },
1959+
);
1960+
1961+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
1962+
1963+
const url = new URL(capturedUri, BASE_URL);
1964+
expect(url.searchParams.has('meta')).toBe(true);
1965+
1966+
const q = JSON.parse(decodeURIComponent(url.searchParams.get('q')!));
1967+
const meta = JSON.parse(decodeURIComponent(url.searchParams.get('meta')!));
1968+
const reconstructed = deserialize(q, meta.serialization) as any;
1969+
expect(reconstructed.where.name.__brand).toBe('AnyNull');
1970+
});
1971+
1972+
it('encodes DbNull in mutation body with serialization metadata', async () => {
1973+
const { wrapper } = createWrapper();
1974+
let capturedBody: any;
1975+
1976+
nock(BASE_URL)
1977+
.post(/.*/)
1978+
.reply(200, function (_uri, body) {
1979+
capturedBody = body;
1980+
return { data: { id: '1', name: null } };
1981+
});
1982+
1983+
const { result } = renderHook(() => useClientQueries(schema).user.useCreate(), { wrapper });
1984+
1985+
act(() => result.current.mutate({ data: { email: 'test@example.com', name: DbNull } } as any));
1986+
1987+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
1988+
1989+
expect(capturedBody.meta?.serialization).toBeDefined();
1990+
const reconstructed = deserialize({ data: capturedBody.data }, capturedBody.meta.serialization) as any;
1991+
expect(reconstructed.data.name.__brand).toBe('DbNull');
1992+
});
1993+
1994+
it('deserializes null sentinels in server response back to branded instances', async () => {
1995+
const { wrapper } = createWrapper();
1996+
1997+
const responseData = { id: '1', email: 'test@example.com', name: DbNull };
1998+
const { data: serializedData, meta: serializedMeta } = serialize(responseData);
1999+
2000+
nock(BASE_URL)
2001+
.get(/.*/)
2002+
.reply(200, { data: serializedData, meta: { serialization: serializedMeta } });
2003+
2004+
const { result } = renderHook(() => useClientQueries(schema).user.useFindUnique({ where: { id: '1' } }), {
2005+
wrapper,
2006+
});
2007+
2008+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
2009+
2010+
expect((result.current.data as any).name.__brand).toBe('DbNull');
2011+
});
2012+
});
18792013
});

0 commit comments

Comments
 (0)