Phase 19: Local Auth (No-OIDC Mode) #23
@@ -654,3 +654,33 @@ describe('calendarStore — delete/sync keys', () => {
|
|||||||
expect(state.lastSyncedUid).toBeNull();
|
expect(state.lastSyncedUid).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ── Phase 19 (AUTH-LOCAL-08): admin reset-password URL contract ───────────────
|
||||||
|
// Regression guard for the post-merge blocker: client.ts targeted
|
||||||
|
// /members/:id/reset-password but the API registers /members/:id/password, so the
|
||||||
|
// Admin reset sheet 404'd in production. Unit tests on both sides missed it (API
|
||||||
|
// tests hit the real path directly; PWA tests mock the fetcher). Pin the exact URL.
|
||||||
|
describe('fetchAdminResetPassword — URL contract (Phase 19, AUTH-LOCAL-08)', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.stubGlobal('fetch', vi.fn());
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
vi.unstubAllGlobals();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('POSTs to /api/admin/members/:id/password (must match admin.ts route)', async () => {
|
||||||
|
vi.mocked(fetch).mockResolvedValueOnce({
|
||||||
|
ok: true,
|
||||||
|
type: 'basic',
|
||||||
|
status: 200,
|
||||||
|
} as unknown as Response);
|
||||||
|
|
||||||
|
const { fetchAdminResetPassword } = await import('./client.js');
|
||||||
|
await fetchAdminResetPassword(7, 'new-password-123');
|
||||||
|
|
||||||
|
expect(fetch).toHaveBeenCalledWith(
|
||||||
|
'/api/admin/members/7/password',
|
||||||
|
expect.objectContaining({ method: 'POST' }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -194,14 +194,15 @@ export async function fetchCreateMember(body: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POST /api/admin/members/:id/reset-password — admin reset of a member's password (Surface 11B).
|
* POST /api/admin/members/:id/password — admin reset of a member's password (Surface 11B).
|
||||||
* Admin-only; server enforces requireAdmin.
|
* Admin-only; server enforces requireAdmin. (Route is registered as `/members/:id/password`
|
||||||
|
* in apps/api/src/routes/admin.ts — must match exactly or the sheet 404s.)
|
||||||
*/
|
*/
|
||||||
export async function fetchAdminResetPassword(
|
export async function fetchAdminResetPassword(
|
||||||
memberId: number,
|
memberId: number,
|
||||||
newPassword: string,
|
newPassword: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const res = await fetch(`/api/admin/members/${memberId}/reset-password`, {
|
const res = await fetch(`/api/admin/members/${memberId}/password`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
|
|||||||
Reference in New Issue
Block a user