Skip to content

Commit 0659881

Browse files
committed
update tests for sketchlist and create tests for addtocollectionsketchlist
1 parent a03b8e7 commit 0659881

2 files changed

Lines changed: 487 additions & 88 deletions

File tree

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
import React, { Suspense } from 'react';
2+
import { setupServer } from 'msw/node';
3+
import { rest } from 'msw';
4+
import { reduxRender, fireEvent, screen, waitFor } from '../../../test-utils';
5+
import { initialTestState } from '../../../testData/testReduxStore';
6+
import AddToCollectionSketchList from './AddToCollectionSketchList';
7+
import i18n from '../../../i18n';
8+
9+
let lastSearchParams;
10+
let requestCount = 0;
11+
let addRequestCount = 0;
12+
let removeRequestCount = 0;
13+
14+
// helper to create test project data
15+
const makeProjects = (prefix, count) =>
16+
Array.from({ length: count }).map((_, i) => ({
17+
id: `${prefix}-${i + 1}`,
18+
name: `${prefix}-sketch-${i + 1}`,
19+
createdAt: new Date().toISOString(),
20+
updatedAt: new Date().toISOString(),
21+
visibility: 'public'
22+
}));
23+
24+
const server = setupServer(
25+
rest.get('/projects', (req, res, ctx) => {
26+
requestCount += 1;
27+
lastSearchParams = req.url.searchParams;
28+
29+
const page = Number(req.url.searchParams.get('page') ?? 1);
30+
const limit = Number(req.url.searchParams.get('limit') ?? 10);
31+
32+
const projects =
33+
page === 1 ? makeProjects('page1', limit) : makeProjects('page2', limit);
34+
35+
return res(
36+
ctx.status(200),
37+
ctx.json({
38+
projects,
39+
metadata: {
40+
page,
41+
totalPages: 6,
42+
totalProjects: 54,
43+
limit,
44+
hasPagination: true
45+
}
46+
})
47+
);
48+
}),
49+
50+
rest.post('/collections/:collectionId/:projectId', (req, res, ctx) => {
51+
addRequestCount += 1;
52+
return res(ctx.status(200));
53+
}),
54+
55+
rest.delete('/collections/:collectionId/:projectId', (req, res, ctx) => {
56+
removeRequestCount += 1;
57+
return res(ctx.status(200));
58+
})
59+
);
60+
61+
beforeAll(async () => {
62+
await i18n.init({
63+
lng: 'en-US',
64+
fallbackLng: 'en-US',
65+
resources: { 'en-US': { translation: {} } },
66+
react: { useSuspense: false },
67+
interpolation: { escapeValue: false }
68+
});
69+
});
70+
71+
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
72+
73+
afterEach(() => {
74+
server.resetHandlers();
75+
requestCount = 0;
76+
addRequestCount = 0;
77+
removeRequestCount = 0;
78+
lastSearchParams = undefined;
79+
});
80+
81+
afterAll(() => server.close());
82+
83+
describe('<AddToCollectionSketchList />', () => {
84+
const collection = {
85+
id: 'col-1',
86+
name: 'My Collection',
87+
items: []
88+
};
89+
90+
const subject = (overrideState) =>
91+
reduxRender(
92+
<Suspense fallback={<div>loading</div>}>
93+
<AddToCollectionSketchList collection={collection} />
94+
</Suspense>,
95+
{ preloadedState: overrideState ?? initialTestState }
96+
);
97+
98+
it('calls the server on mount with page/limit/q', async () => {
99+
subject();
100+
101+
await screen.findByText('page1-sketch-1');
102+
103+
expect(lastSearchParams.get('page')).toBe('1');
104+
expect(lastSearchParams.get('limit')).toBe('10');
105+
106+
const q = lastSearchParams.get('q');
107+
const expectedQ = initialTestState.search.sketchSearchTerm;
108+
109+
if (expectedQ && expectedQ.length > 0) {
110+
expect(q).toBe(expectedQ);
111+
} else {
112+
expect([null, '']).toContain(q);
113+
}
114+
});
115+
116+
it('clicking "Next Page" requests page 2 and updates list', async () => {
117+
subject();
118+
await screen.findByText('page1-sketch-1');
119+
120+
const before = requestCount;
121+
122+
fireEvent.click(screen.getByRole('button', { name: 'Next Page' }));
123+
124+
await waitFor(() => {
125+
expect(requestCount).toBeGreaterThan(before);
126+
expect(lastSearchParams.get('page')).toBe('2');
127+
});
128+
129+
await screen.findByText('page2-sketch-1');
130+
});
131+
132+
it('Previous Page is disabled on page 1', async () => {
133+
subject();
134+
await screen.findByText('page1-sketch-1');
135+
136+
expect(
137+
screen.getByRole('button', { name: 'Previous Page' })
138+
).toBeDisabled();
139+
});
140+
141+
it('shows empty state when server returns no projects', async () => {
142+
server.use(
143+
rest.get('/projects', (req, res, ctx) => {
144+
requestCount += 1;
145+
lastSearchParams = req.url.searchParams;
146+
147+
return res(
148+
ctx.status(200),
149+
ctx.json({
150+
projects: [],
151+
metadata: {
152+
page: 1,
153+
totalPages: 1,
154+
totalProjects: 0,
155+
limit: 10,
156+
hasPagination: false
157+
}
158+
})
159+
);
160+
})
161+
);
162+
163+
subject();
164+
165+
await screen.findByText('AddToCollectionSketchList.NoCollections');
166+
167+
expect(
168+
screen.queryByRole('button', { name: 'Next Page' })
169+
).not.toBeInTheDocument();
170+
});
171+
172+
it('allows user to add a sketch to the collection', async () => {
173+
reduxRender(
174+
<AddToCollectionSketchList
175+
collection={{ id: 'col-1', name: 'My Collection', items: [] }}
176+
/>,
177+
{ preloadedState: initialTestState }
178+
);
179+
180+
await screen.findByText('page1-sketch-1');
181+
182+
fireEvent.click(
183+
screen.getAllByLabelText('QuickAddList.ButtonAddToCollectionARIA')[0]
184+
);
185+
186+
await waitFor(() => {
187+
expect(addRequestCount).toBe(1);
188+
});
189+
});
190+
191+
it('allows user to remove a sketch from the collection', async () => {
192+
reduxRender(
193+
<AddToCollectionSketchList
194+
collection={{
195+
id: 'col-1',
196+
name: 'My Collection',
197+
items: [{ projectId: 'page1-1', isDeleted: false }]
198+
}}
199+
/>,
200+
{ preloadedState: initialTestState }
201+
);
202+
203+
await screen.findByText('page1-sketch-1');
204+
205+
fireEvent.click(
206+
screen.getAllByLabelText('QuickAddList.ButtonRemoveARIA')[0]
207+
);
208+
209+
await waitFor(() => {
210+
expect(removeRequestCount).toBe(1);
211+
});
212+
});
213+
214+
it('renders correct pagination text when totalProjects is not a multiple of 10', async () => {
215+
server.use(
216+
rest.get('/projects', (req, res, ctx) => {
217+
const page = Number(req.url.searchParams.get('page') ?? 1);
218+
const limit = 10;
219+
220+
const totalProjects = 23;
221+
const totalPages = 3;
222+
223+
const start = (page - 1) * limit;
224+
const end = Math.min(start + limit, totalProjects);
225+
226+
const projects = makeProjects(`page${page}`, end - start);
227+
228+
return res(
229+
ctx.status(200),
230+
ctx.json({
231+
projects,
232+
metadata: {
233+
page,
234+
totalPages,
235+
totalProjects,
236+
limit,
237+
hasPagination: true
238+
}
239+
})
240+
);
241+
})
242+
);
243+
244+
reduxRender(
245+
<AddToCollectionSketchList
246+
collection={{ id: 'col-1', name: 'Test', items: [] }}
247+
/>,
248+
{ preloadedState: initialTestState }
249+
);
250+
251+
await screen.findByText('page1-sketch-1');
252+
253+
let info = document.querySelector('.pagination-info');
254+
expect(info.textContent.replace(/\s+/g, ' ').trim()).toContain(
255+
'1 - 10 of 23'
256+
);
257+
258+
fireEvent.click(screen.getByRole('button', { name: 'Next Page' }));
259+
await screen.findByText('page2-sketch-1');
260+
261+
info = document.querySelector('.pagination-info');
262+
expect(info.textContent.replace(/\s+/g, ' ').trim()).toContain(
263+
'11 - 20 of 23'
264+
);
265+
266+
fireEvent.click(screen.getByRole('button', { name: 'Next Page' }));
267+
await screen.findByText('page3-sketch-1');
268+
269+
info = document.querySelector('.pagination-info');
270+
expect(info.textContent.replace(/\s+/g, ' ').trim()).toContain(
271+
'21 - 23 of 23'
272+
);
273+
});
274+
});

0 commit comments

Comments
 (0)