feat(19-04): AdminPage LOCAL ACCOUNTS + SettingsSheet change-password / link-OIDC
- Add hasLocalCredential to AdminMember type (mirrors API extension from plan 19-02) - Add createMember mutation + Surface 11A inline add-member form in AdminPage - Add Surface 11B Reset-password button in MemberRow (hasLocalCredential gate) - Add ResetPasswordSheet component (bottom-sheet, role=dialog, focus-managed, Escape closes) - Add Surface 12 Change-password row in SettingsSheet (hasLocalCredential gate) - Add Surface 13 Link-OIDC identity row in SettingsSheet (hasLocalCredential + oidcEnabled gate) - Add ChangePasswordSheet component (current/new/confirm fields, change-password mutation) - Add LinkOidcSheet component (confirmation dialog; uses generic OIDC copy per D-06, no provider branding) - Fix: update InstructionSheet.test.tsx to wrap with QueryClientProvider (Rule 1 - now uses useQuery) - Fix: remove stale eslint-disable in App.test.tsx (lint --max-warnings 0 would fail) - All 263 tests pass; typecheck clean; lint clean
This commit is contained in:
@@ -7,8 +7,10 @@
|
||||
* - onClose (the sheet-close prop) is NOT called when the dialog opens
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
|
||||
// ── Module mocks ──────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -22,6 +24,17 @@ vi.mock('../hooks/usePushSubscription.js', () => ({
|
||||
readNotificationsEnabled: vi.fn(() => false),
|
||||
}));
|
||||
|
||||
// Phase 19: SettingsSheet now calls fetchMe and fetchAuthMode inside useQuery.
|
||||
// Mock client so the test doesn't make real network calls.
|
||||
vi.mock('../api/client.js', () => ({
|
||||
fetchMe: vi.fn().mockResolvedValue({
|
||||
user: { id: 1, displayName: 'Test', color: '#4a90d9', isAdmin: false, needsProviderSetup: false, hasLocalCredential: false },
|
||||
}),
|
||||
fetchAuthMode: vi.fn().mockResolvedValue({ localEnabled: true, oidcEnabled: false }),
|
||||
fetchChangePassword: vi.fn().mockResolvedValue(undefined),
|
||||
fetchLinkOidc: vi.fn().mockResolvedValue({ redirectUrl: '/oidc' }),
|
||||
}));
|
||||
|
||||
// ── Minimal Notification stub (jsdom lacks it) ────────────────────────────────
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -44,12 +57,21 @@ beforeEach(() => {
|
||||
|
||||
import { SettingsSheet } from './SettingsSheet.js';
|
||||
|
||||
// ── Test helper ───────────────────────────────────────────────────────────────
|
||||
|
||||
function renderWithQueryClient(ui: React.ReactElement) {
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
|
||||
});
|
||||
return render(<QueryClientProvider client={queryClient}>{ui}</QueryClientProvider>);
|
||||
}
|
||||
|
||||
// ── Tests ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
describe('SettingsSheet — "How to enable" wiring (UAT-05-T4)', () => {
|
||||
it('clicking "How to enable" opens the InstructionSheet dialog and does NOT call onClose', () => {
|
||||
const onCloseSpy = vi.fn();
|
||||
render(<SettingsSheet isOpen={true} onClose={onCloseSpy} />);
|
||||
renderWithQueryClient(<SettingsSheet isOpen={true} onClose={onCloseSpy} />);
|
||||
|
||||
// No instruction dialog yet
|
||||
expect(screen.queryByRole('dialog', { name: /re-enable notifications/i })).toBeNull();
|
||||
@@ -71,7 +93,7 @@ describe('SettingsSheet — "How to enable" wiring (UAT-05-T4)', () => {
|
||||
|
||||
it('InstructionSheet "Done" button closes the instruction dialog without calling sheet onClose', () => {
|
||||
const onCloseSpy = vi.fn();
|
||||
render(<SettingsSheet isOpen={true} onClose={onCloseSpy} />);
|
||||
renderWithQueryClient(<SettingsSheet isOpen={true} onClose={onCloseSpy} />);
|
||||
|
||||
// Open the instruction sheet
|
||||
fireEvent.click(screen.getByText('How to enable'));
|
||||
|
||||
Reference in New Issue
Block a user