Skip to content

Commit d7608a1

Browse files
committed
test: add integration tests for POST body cache key update and refetch behavior
1 parent 09de9e3 commit d7608a1

File tree

2 files changed

+100
-78
lines changed

2 files changed

+100
-78
lines changed

test/react/integration/hook.spec.tsx

Lines changed: 0 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1662,80 +1662,4 @@ describe('React Integration Tests', () => {
16621662
global.localStorage = originalLocalStorage;
16631663
});
16641664
});
1665-
1666-
describe('POST body cache key update', () => {
1667-
it('should regenerate cache key and use updated body when POST body changes and refetch is called', async () => {
1668-
const testUrl = '/api/post-body-cache-key';
1669-
const initialBody = { value: 'first' };
1670-
const updatedBody = { value: 'second' };
1671-
let currentBody = initialBody;
1672-
1673-
// Mock fetch to echo back the request body
1674-
global.fetch = jest.fn().mockImplementation((_url, config) => {
1675-
const parsedBody =
1676-
config && config.body ? JSON.parse(config.body) : undefined;
1677-
return Promise.resolve({
1678-
ok: true,
1679-
status: 200,
1680-
data: parsedBody,
1681-
body: parsedBody,
1682-
json: () => Promise.resolve(parsedBody),
1683-
});
1684-
});
1685-
1686-
// React state simulation
1687-
let setBody: (b: typeof initialBody) => void = () => {};
1688-
function BodyComponent() {
1689-
const [body, _setBody] = React.useState(currentBody);
1690-
setBody = _setBody;
1691-
const { data, refetch, isLoading } = useFetcher(testUrl, {
1692-
method: 'POST',
1693-
body,
1694-
});
1695-
return (
1696-
<div>
1697-
<div data-testid="data">
1698-
{data ? JSON.stringify(data) : 'No Data'}
1699-
</div>
1700-
<div data-testid="loading">
1701-
{isLoading ? 'Loading...' : 'Not Loading'}
1702-
</div>
1703-
<button data-testid="refetch-btn" onClick={() => refetch(true)}>
1704-
Refetch
1705-
</button>
1706-
</div>
1707-
);
1708-
}
1709-
1710-
render(<BodyComponent />);
1711-
1712-
// Wait for initial fetch
1713-
await waitFor(() => {
1714-
expect(screen.getByTestId('data')).toHaveTextContent('No Data');
1715-
});
1716-
1717-
// Act: update the body asynchronously
1718-
act(() => {
1719-
currentBody = updatedBody;
1720-
setBody(updatedBody);
1721-
});
1722-
1723-
// Refetch with new body
1724-
fireEvent.click(screen.getByTestId('refetch-btn'));
1725-
1726-
// Assert: data should match updated body
1727-
await waitFor(() => {
1728-
expect(screen.getByTestId('data')).toHaveTextContent('second');
1729-
});
1730-
1731-
// Also check that fetch was called with the updated body
1732-
expect(global.fetch).toHaveBeenLastCalledWith(
1733-
testUrl,
1734-
expect.objectContaining({
1735-
method: 'POST',
1736-
body: JSON.stringify(updatedBody),
1737-
}),
1738-
);
1739-
});
1740-
});
17411665
});

test/react/integration/post-body-cache-key.spec.tsx

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
/**
22
* @jest-environment jsdom
33
*/
4+
import '@testing-library/jest-dom';
45
import { useState } from 'react';
5-
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
6+
import {
7+
render,
8+
screen,
9+
fireEvent,
10+
waitFor,
11+
act,
12+
} from '@testing-library/react';
613
import { mockFetchResponse } from '../../utils/mockFetchResponse';
714
import { useFetcher } from '../../../src/react/index';
815

916
describe('POST body cache key update and refetch', () => {
10-
it('uses new body on refetch, keeps static cache key, and updates UI state', async () => {
17+
it('should not update cache key but use new body when refetch is called after body changes and retries are active', async () => {
1118
mockFetchResponse('/api/user', {
1219
ok: true,
1320
status: 200,
@@ -26,6 +33,7 @@ describe('POST body cache key update and refetch', () => {
2633
retry: { retries: 5, delay: 1000, backoff: 2 },
2734
},
2835
);
36+
2937
return (
3038
<div>
3139
<div data-testid="result">{data?.echoed?.name}</div>
@@ -39,6 +47,8 @@ describe('POST body cache key update and refetch', () => {
3947
}
4048

4149
render(<TestComponent />);
50+
51+
// Initial fetch with name "Alice"
4252
await waitFor(() =>
4353
expect(screen.getByTestId('result').textContent).toBe('Alice'),
4454
);
@@ -48,20 +58,108 @@ describe('POST body cache key update and refetch', () => {
4858
status: 200,
4959
body: { echoed: { name: 'Bob' } },
5060
});
61+
62+
// Change name to "Bob"
5163
fireEvent.click(screen.getByText('Change Name'));
64+
65+
// Refetch with new body
5266
fireEvent.click(screen.getByText('Refetch'));
67+
68+
// Should show loading state
5369
expect(screen.getByTestId('loading').textContent).toBe('loading');
5470
expect(screen.getByTestId('fetching').textContent).toBe('fetching');
71+
72+
// Wait for fetch to complete and check new body is used
5573
await waitFor(() =>
5674
expect(screen.getByTestId('result').textContent).toBe('Bob'),
5775
);
76+
77+
// Should show idle state after fetch completes
5878
expect(screen.getByTestId('loading').textContent).toBe('idle');
5979
expect(screen.getByTestId('fetching').textContent).toBe('idle');
80+
81+
// Check if the body used in fetch is updated
6082
expect(screen.getByTestId('config').textContent).toContain(
6183
'"body":"{\\"name\\":\\"Bob\\"}"',
6284
);
85+
86+
// Check the cache key is updated
6387
expect(screen.getByTestId('config').textContent).toContain(
6488
'"cacheKey":"/api/user"',
6589
);
6690
});
91+
92+
it('should regenerate cache key and use updated body when POST body changes and refetch is called', async () => {
93+
const testUrl = '/api/post-body-cache-key';
94+
const initialBody = { value: 'first' };
95+
const updatedBody = { value: 'second' };
96+
let currentBody = initialBody;
97+
98+
// Mock fetch to echo back the request body
99+
global.fetch = jest.fn().mockImplementation((_url, config) => {
100+
const parsedBody =
101+
config && config.body ? JSON.parse(config.body) : undefined;
102+
return Promise.resolve({
103+
ok: true,
104+
status: 200,
105+
data: parsedBody,
106+
body: parsedBody,
107+
json: () => Promise.resolve(parsedBody),
108+
});
109+
});
110+
111+
// React state simulation
112+
let setBody: (b: typeof initialBody) => void = () => {};
113+
function BodyComponent() {
114+
const [body, _setBody] = useState(currentBody);
115+
setBody = _setBody;
116+
const { data, refetch, isLoading } = useFetcher(testUrl, {
117+
method: 'POST',
118+
body,
119+
});
120+
return (
121+
<div>
122+
<div data-testid="data">
123+
{data ? JSON.stringify(data) : 'No Data'}
124+
</div>
125+
<div data-testid="loading">
126+
{isLoading ? 'Loading...' : 'Not Loading'}
127+
</div>
128+
<button data-testid="refetch-btn" onClick={() => refetch(true)}>
129+
Refetch
130+
</button>
131+
</div>
132+
);
133+
}
134+
135+
render(<BodyComponent />);
136+
137+
// Wait for initial fetch
138+
await waitFor(() => {
139+
expect(screen.getByTestId('data')).toHaveTextContent('No Data');
140+
});
141+
142+
// Act: update the body asynchronously
143+
act(() => {
144+
currentBody = updatedBody;
145+
setBody(updatedBody);
146+
});
147+
148+
// Refetch with new body
149+
fireEvent.click(screen.getByTestId('refetch-btn'));
150+
151+
// Assert: data should match updated body
152+
await waitFor(() => {
153+
expect(screen.getByTestId('data')).toHaveTextContent('second');
154+
});
155+
156+
// Also check that fetch was called with the updated body
157+
expect(global.fetch).toHaveBeenLastCalledWith(
158+
testUrl,
159+
expect.objectContaining({
160+
method: 'POST',
161+
body: JSON.stringify(updatedBody),
162+
}),
163+
);
164+
});
67165
});

0 commit comments

Comments
 (0)