fix(web): cablear ResetPasswordModal en UserDetailPage [UDT-008]
El componente ResetPasswordModal estaba implementado pero nunca montado en una pagina. Ahora se renderiza en UserDetailPage, oculto cuando el target es el usuario logueado (evita hit de cannot-self-reset en backend).
This commit is contained in:
@@ -4,11 +4,14 @@ import { Badge } from '@/components/ui/badge'
|
||||
import { useUser } from '../hooks/useUser'
|
||||
import { useDeactivateUser } from '../hooks/useDeactivateUser'
|
||||
import { useReactivateUser } from '../hooks/useReactivateUser'
|
||||
import { ResetPasswordModal } from '../components/ResetPasswordModal'
|
||||
import { useAuthStore } from '@/stores/authStore'
|
||||
|
||||
export function UserDetailPage() {
|
||||
const { id } = useParams<{ id: string }>()
|
||||
const userId = Number(id)
|
||||
const navigate = useNavigate()
|
||||
const loggedUserId = useAuthStore((s) => s.user?.id)
|
||||
|
||||
const { data: user, isLoading } = useUser(userId)
|
||||
const { mutate: deactivate, isPending: deactivating } = useDeactivateUser()
|
||||
@@ -90,6 +93,8 @@ export function UserDetailPage() {
|
||||
{reactivating ? 'Reactivando...' : 'Reactivar'}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{loggedUserId !== userId && <ResetPasswordModal userId={userId} />}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
78
src/web/src/tests/features/users/UserDetailPage.test.tsx
Normal file
78
src/web/src/tests/features/users/UserDetailPage.test.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import { http, HttpResponse } from 'msw'
|
||||
import { setupServer } from 'msw/node'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { MemoryRouter, Routes, Route } from 'react-router-dom'
|
||||
import { UserDetailPage } from '../../../features/users/pages/UserDetailPage'
|
||||
import { useAuthStore } from '../../../stores/authStore'
|
||||
|
||||
const API_URL = 'http://localhost:5000'
|
||||
|
||||
const adminUser = {
|
||||
id: 1, username: 'admin', nombre: 'Admin', rol: 'admin',
|
||||
permisos: ['administracion:usuarios:gestionar'],
|
||||
mustChangePassword: false,
|
||||
}
|
||||
|
||||
const target = {
|
||||
id: 5,
|
||||
username: 'cajero1',
|
||||
nombre: 'Juan',
|
||||
apellido: 'Perez',
|
||||
email: 'juan@test.com',
|
||||
rol: 'cajero',
|
||||
activo: true,
|
||||
permisosJson: '[]',
|
||||
fechaModificacion: null,
|
||||
ultimoLogin: null,
|
||||
}
|
||||
|
||||
const server = setupServer()
|
||||
|
||||
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
|
||||
afterEach(() => {
|
||||
server.resetHandlers()
|
||||
useAuthStore.getState().clearAuth()
|
||||
})
|
||||
afterAll(() => server.close())
|
||||
|
||||
function renderDetail(userId: number) {
|
||||
useAuthStore.setState({ user: adminUser })
|
||||
const qc = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false } } })
|
||||
return render(
|
||||
<QueryClientProvider client={qc}>
|
||||
<MemoryRouter initialEntries={[`/usuarios/${userId}`]}>
|
||||
<Routes>
|
||||
<Route path="/usuarios/:id" element={<UserDetailPage />} />
|
||||
</Routes>
|
||||
</MemoryRouter>
|
||||
</QueryClientProvider>,
|
||||
)
|
||||
}
|
||||
|
||||
describe('UserDetailPage — reset password wiring', () => {
|
||||
it('shows "Resetear contraseña" button when viewing another user', async () => {
|
||||
server.use(
|
||||
http.get(`${API_URL}/api/v1/users/5`, () => HttpResponse.json(target)),
|
||||
)
|
||||
|
||||
renderDetail(5)
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Juan Perez')).toBeInTheDocument())
|
||||
expect(screen.getByRole('button', { name: /resetear contraseña/i })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('hides "Resetear contraseña" button when viewing own profile (prevent cannot-self-reset)', async () => {
|
||||
server.use(
|
||||
http.get(`${API_URL}/api/v1/users/1`, () =>
|
||||
HttpResponse.json({ ...target, id: 1, username: 'admin', nombre: 'Admin', apellido: 'Root', rol: 'admin' }),
|
||||
),
|
||||
)
|
||||
|
||||
renderDetail(1)
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Admin Root')).toBeInTheDocument())
|
||||
expect(screen.queryByRole('button', { name: /resetear contraseña/i })).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user