Compare commits

..
2 Commits
Author SHA1 Message Date
lobo b8f70e7578 feat(registration): send the browser language
Build, Test & Push Frontend / docker (push) Successful in 25s
Build, Test & Push Frontend / quality-check (push) Successful in 22s
2026-10-01 08:30:24 +02:00
lobo 43968b3b7a test(import): wait for the URL without the store list 2026-10-01 08:30:24 +02:00
4 changed files with 19 additions and 3 deletions

No files matched your search

+2 -1
View File
@@ -83,7 +83,8 @@ To Be Played is split into three repositories:
- **Appearance**: accent color, corner style, wide layout, page background and banner from your own game art.
Saved in Auth, so it follows you to every device.
- **Language**: kept in the browser and saved in Auth; after the login Auth's language wins when one is saved. Dark
mode stays per device.
mode stays per device. The registration sends the browser language (`de` for a German browser, else `en`): Auth
writes its mails in it and saves it as the user's language.
- **Broken pictures**: a Steam cover or achievement icon that does not load shows a placeholder and is reported
to Core once per page load (`POST /api/library/broken-images`, only with a session). Core repairs it at night;
a repaired cover comes back as `imageUrl`.
+3 -2
View File
@@ -171,7 +171,8 @@ describe('ImportPage', () => {
expect(await screen.findByText('IMPORT.STORE_READ:2')).toBeTruthy();
expect(screen.getByText('Pokémon Scarlet · Switch')).toBeTruthy();
expect(screen.getByLabelText('url').textContent).toBe('/import');
// The router takes the new URL in a later render than the rows.
await waitFor(() => expect(screen.getByLabelText('url').textContent).toBe('/import'));
fireEvent.click(screen.getByRole('button', {name: 'IMPORT.START'}));
await screen.findByText('IMPORT.MATCHING');
@@ -185,7 +186,7 @@ describe('ImportPage', () => {
renderPage({'GET ': json(200, {imports: []})}, '/import#data=broken');
await waitFor(() => expect(toast.error).toHaveBeenCalledWith('IMPORT.STORE_LIST_BROKEN'));
expect(screen.getByLabelText('url').textContent).toBe('/import');
await waitFor(() => expect(screen.getByLabelText('url').textContent).toBe('/import'));
expect(await screen.findByLabelText('IMPORT.TEXT_LABEL')).toBeTruthy();
});
+2
View File
@@ -54,6 +54,8 @@ export default function RegistrationPage() {
password: values.password,
inviteCode: values.inviteCode,
displayName: values.displayName,
// Auth's mails use it: a German browser gets German, every other one English.
language: navigator.language?.toLowerCase().startsWith('de') ? 'de' : 'en',
}),
});
+12
View File
@@ -30,6 +30,7 @@ function submitValidForm() {
describe('RegistrationPage', () => {
afterEach(() => {
cleanup();
vi.restoreAllMocks();
});
it('shows the wait time when the IP is blocked', async () => {
@@ -50,6 +51,17 @@ describe('RegistrationPage', () => {
expect(JSON.parse(fetch.mock.calls[0][1].body)).not.toHaveProperty('steamId');
});
it.each([['de-DE', 'de'], ['de', 'de'], ['en-US', 'en'], ['fr-FR', 'en'], [undefined, 'en']])(
'sends the browser language %s as %s, for the mails', async (browser, sent) => {
vi.spyOn(navigator, 'language', 'get').mockReturnValue(browser);
answerRegistration(400, 'INVALID_INVITATION_CODE');
submitValidForm();
await screen.findByText('REGISTRATION.ERROR_INVALID_INVITE_CODE');
expect(JSON.parse(fetch.mock.calls[0][1].body).language).toBe(sent);
});
it('maps a known backend error to its message', async () => {
answerRegistration(400, 'INVALID_INVITATION_CODE');