test: data router, one render helper, fetchRoutes in every test

This commit is contained in:
lobo committed 2026-09-29 16:15:50 +02:00
1 parent d0ea9e900d
commit 2a22789435
37 files changed
+454 -425

No files matched your search

+23 -15
View File
@@ -1,10 +1,9 @@
// @vitest-environment jsdom
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
import {act, cleanup, fireEvent, render, screen, waitFor, within} from '@testing-library/react';
import {MemoryRouter} from 'react-router-dom';
import {act, cleanup, fireEvent, screen, waitFor, within} from '@testing-library/react';
import SettingsPage from './SettingsPage.jsx';
import {PreferencesProvider} from '../context/PreferencesContext.jsx';
import {CurrentUserProvider} from '../context/CurrentUserContext.jsx';
import {fetchRoutes, json} from '../test/fetchRoutes.js';
import {renderWithProviders} from '../test/renderWithProviders.jsx';
vi.mock('react-i18next', async () => {
const mock = await import('../test/i18n-mock.js');
@@ -22,12 +21,21 @@ const appearanceCard = () => within(screen.getByText('SETTINGS.APPEARANCE').clos
const puts = () => fetch.mock.calls.filter(([, init]) => init?.method === 'PUT').map(([, init]) => JSON.parse(init.body));
// Every PUT answers 204 without a body, like Auth does.
const noBody = {ok: true, status: 204, json: async () => { throw new SyntaxError('no body'); }};
const authRoutes = (me) => ({
'GET /api/users/me': () => json(200, me()),
'PUT /api/users/settings': noBody,
'PUT /api/users/settings/appearance': noBody,
'PUT /api/users/settings/profile-style': noBody,
'PUT /api/users/settings/favorite-platform': noBody,
'GET /api/version': json(404, {}),
});
function renderPage(me) {
globalThis.fetch = vi.fn(async (url, init) => (init?.method === 'PUT'
// Both PUTs answer 204 without a body, like Auth does.
? {ok: true, status: 204, json: async () => { throw new SyntaxError('no body'); }}
: {ok: true, status: 200, json: async () => me}));
render(<MemoryRouter><PreferencesProvider><CurrentUserProvider><SettingsPage/></CurrentUserProvider></PreferencesProvider></MemoryRouter>);
fetchRoutes(authRoutes(() => me));
renderWithProviders(<SettingsPage/>);
}
/**
@@ -36,14 +44,14 @@ function renderPage(me) {
function fakeAuth(me) {
const saved = structuredClone(me);
const open = [];
globalThis.fetch = vi.fn((url, init) => {
if (init?.method !== 'PUT') return Promise.resolve({ok: true, status: 200, json: async () => structuredClone(saved)});
return new Promise((resolve) => open.push(() => {
fetchRoutes({
...authRoutes(() => structuredClone(saved)),
'PUT /api/users/settings': (url, init) => new Promise((resolve) => open.push(() => {
const body = JSON.parse(init.body);
saved.displayName = body.displayName;
Object.assign(saved.settings, {useDarkTheme: body.useDarkTheme, language: body.language, publicProfile: body.publicProfile});
resolve({ok: true, status: 204, json: async () => { throw new SyntaxError('no body'); }});
}));
resolve(noBody);
})),
});
return {answer: () => open.shift()()};
}
@@ -67,7 +75,7 @@ describe('SettingsPage public profile', () => {
it('builds a save on the one before it, also while that one is still open', async () => {
const auth = fakeAuth(profile());
render(<MemoryRouter><PreferencesProvider><CurrentUserProvider><SettingsPage/></CurrentUserProvider></PreferencesProvider></MemoryRouter>);
renderWithProviders(<SettingsPage/>);
fireEvent.click(await screen.findByRole('switch', {name: 'SETTINGS.PUBLIC_PROFILE'}));
await waitFor(() => expect(puts()).toHaveLength(1));