fix(ci): library_test Mount arg + 4 web test selectors + forgot-pw catch
Five fixes in one commit, all from the U1+U2+U3 push:
1. internal/api/library_test.go's Mount call wasn't updated when
U3-T4 added the mailer.Sender param. 17 args, sig wants 18.
Adds a trailing nil for the mailer. Same shape of test-fixture
lag the project has hit before — flagged as a recurring pattern
for the DRY-pass slice.
2. web/src/routes/settings/settings.test.ts mocked $lib/api/me with
`getAPIToken: vi.fn()` (no return value). The new /settings API
Token card's $effect calls `getAPIToken().then(...)` which threw
"Cannot read properties of undefined (reading 'then')" on every
ListenBrainz test. Default the mock to mockResolvedValue so any
test that doesn't override gets a valid resolution.
3. web/src/routes/admin/users/users.test.ts queried row buttons by
/^Delete$/ but T3 added per-user aria-labels ("Delete alice"),
so the row buttons' accessible name is no longer "Delete". The
modal's confirm button has no aria-label so its name IS "Delete"
exactly. Tests now click by per-user aria-label first, then by
/^Delete$/ for the modal confirm.
4. Same file: /Set password/i regex matched both the dialog's
submit button AND the row's "Reset password for ..." buttons
(because regex `Set` matches "ReSet" case-insensitively). Switched
to /^Set password$/ exact-match.
5. web/src/routes/reset-password/[token]/reset-password.test.ts had
/New password/i which matched both the "New password" and
"Confirm new password" labels. Switched to exact-match string
selectors.
6. web/src/routes/forgot-password/+page.svelte's onSubmit handler
had no catch — a rejected forgotPassword() bubbled as an
unhandled rejection in vitest. Added a silent catch since the
page intentionally shows the same success message regardless of
outcome (no-enumeration posture).
This commit is contained in:
@@ -163,13 +163,11 @@ describe('/admin/users', () => {
|
||||
setup();
|
||||
await waitFor(() => screen.getByText('alice'));
|
||||
|
||||
const deleteButtons = screen.getAllByRole('button', { name: /^Delete$/i });
|
||||
await fireEvent.click(deleteButtons[0]);
|
||||
// Row buttons carry per-user aria-labels ("Delete alice"). The modal's
|
||||
// confirm button has no aria-label so its accessible name is "Delete" exactly.
|
||||
await fireEvent.click(screen.getByRole('button', { name: 'Delete alice' }));
|
||||
await waitFor(() => screen.getByRole('dialog'));
|
||||
|
||||
// The confirm Delete button is inside the dialog; it is the last "Delete" in the DOM.
|
||||
const allDeleteButtons = screen.getAllByRole('button', { name: /^Delete$/i });
|
||||
await fireEvent.click(allDeleteButtons[allDeleteButtons.length - 1]);
|
||||
await fireEvent.click(screen.getByRole('button', { name: /^Delete$/ }));
|
||||
|
||||
expect(deleteUser).toHaveBeenCalled();
|
||||
});
|
||||
@@ -179,11 +177,9 @@ describe('/admin/users', () => {
|
||||
setup();
|
||||
await waitFor(() => screen.getByText('alice'));
|
||||
|
||||
const deleteButtons = screen.getAllByRole('button', { name: /^Delete$/i });
|
||||
await fireEvent.click(deleteButtons[0]);
|
||||
await fireEvent.click(screen.getByRole('button', { name: 'Delete alice' }));
|
||||
await waitFor(() => screen.getByRole('dialog'));
|
||||
const allDeleteButtons = screen.getAllByRole('button', { name: /^Delete$/i });
|
||||
await fireEvent.click(allDeleteButtons[allDeleteButtons.length - 1]);
|
||||
await fireEvent.click(screen.getByRole('button', { name: /^Delete$/ }));
|
||||
|
||||
await waitFor(() => screen.getByRole('status'));
|
||||
expect(screen.getByRole('status').textContent).toMatch(/last admin/i);
|
||||
@@ -194,12 +190,14 @@ describe('/admin/users', () => {
|
||||
setup();
|
||||
await waitFor(() => screen.getByText('alice'));
|
||||
|
||||
await fireEvent.click(screen.getAllByRole('button', { name: /Reset password/i })[0]);
|
||||
await fireEvent.click(screen.getByRole('button', { name: 'Reset password for alice' }));
|
||||
await waitFor(() => screen.getByRole('dialog'));
|
||||
|
||||
await fireEvent.input(screen.getByLabelText(/New password/i), { target: { value: 'abcd1234' } });
|
||||
await fireEvent.input(screen.getByLabelText(/^New password$/i), { target: { value: 'abcd1234' } });
|
||||
await fireEvent.input(screen.getByLabelText(/^Confirm$/i), { target: { value: 'abcd1234' } });
|
||||
await fireEvent.click(screen.getByRole('button', { name: /Set password/i }));
|
||||
// /^Set password$/ avoids matching the row's "Reset password" buttons
|
||||
// (regex `Set password` matches "ReSet password" case-insensitively).
|
||||
await fireEvent.click(screen.getByRole('button', { name: /^Set password$/i }));
|
||||
|
||||
expect(resetUserPassword).toHaveBeenCalledWith(expect.any(String), 'abcd1234');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user