import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor, fireEvent, cleanup } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import type { ReactNode } from 'react';
// Bundle 2 Phase 8 — OIDCProviderDetailPage tests. Pins:
// - 403 ErrorState when caller lacks auth.oidc.list.
// - "Edit"/"Refresh"/"Delete" buttons HIDDEN without their respective perms.
// - "Edit"/"Refresh"/"Delete" buttons SHOWN when perms present.
// - Refresh button calls refreshOIDCProvider.
// - Delete confirmation flow + button enabled only when typed text matches.
vi.mock('../../api/client', () => ({
listOIDCProviders: vi.fn(),
updateOIDCProvider: vi.fn(),
deleteOIDCProvider: vi.fn(),
refreshOIDCProvider: vi.fn(),
authMe: vi.fn(),
}));
import OIDCProviderDetailPage from './OIDCProviderDetailPage';
import * as client from '../../api/client';
function renderRoute(ui: ReactNode, path = '/auth/oidc/providers/op-okta') {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
});
return render(
,
);
}
beforeEach(() => {
vi.clearAllMocks();
cleanup();
});
const sampleProvider = {
id: 'op-okta',
tenant_id: 't-default',
name: 'Okta',
issuer_url: 'https://example.okta.com',
client_id: 'certctl',
redirect_uri: 'https://certctl.example.com/auth/oidc/callback',
groups_claim_path: 'groups',
groups_claim_format: 'string-array',
fetch_userinfo: false,
scopes: ['openid'],
iat_window_seconds: 300,
jwks_cache_ttl_seconds: 3600,
created_at: '2026-05-10T00:00:00Z',
updated_at: '2026-05-10T00:00:00Z',
};
describe('OIDCProviderDetailPage', () => {
it('renders ErrorState when caller lacks auth.oidc.list', async () => {
vi.mocked(client.authMe).mockResolvedValue({
actor_id: 'u-x',
actor_type: 'User',
tenant_id: 't-default',
admin: false,
roles: [],
effective_permissions: [],
});
renderRoute();
await waitFor(() => {
expect(screen.queryByText(/auth\.oidc\.list/)).toBeTruthy();
});
});
it('renders provider config and edit/delete/refresh buttons with full perms', async () => {
vi.mocked(client.listOIDCProviders).mockResolvedValue({ providers: [sampleProvider] });
vi.mocked(client.authMe).mockResolvedValue({
actor_id: 'u-admin',
actor_type: 'User',
tenant_id: 't-default',
admin: true,
roles: ['r-admin'],
effective_permissions: [
{ permission: 'auth.oidc.list', scope_type: 'global' },
{ permission: 'auth.oidc.edit', scope_type: 'global' },
{ permission: 'auth.oidc.delete', scope_type: 'global' },
],
});
renderRoute();
await waitFor(() => {
expect(screen.getByTestId('oidc-provider-edit-button')).toBeTruthy();
});
expect(screen.getByTestId('oidc-provider-refresh-button')).toBeTruthy();
expect(screen.getByTestId('oidc-provider-delete-button')).toBeTruthy();
expect(screen.getByTestId('oidc-provider-mappings-link')).toBeTruthy();
// The provider's issuer_url renders in the dl.
expect(screen.getAllByText('https://example.okta.com').length).toBeGreaterThan(0);
});
it('hides edit/refresh/delete when caller has only auth.oidc.list', async () => {
vi.mocked(client.listOIDCProviders).mockResolvedValue({ providers: [sampleProvider] });
vi.mocked(client.authMe).mockResolvedValue({
actor_id: 'u-viewer',
actor_type: 'User',
tenant_id: 't-default',
admin: false,
roles: ['r-viewer'],
effective_permissions: [{ permission: 'auth.oidc.list', scope_type: 'global' }],
});
renderRoute();
await waitFor(() => {
expect(screen.getByTestId('oidc-provider-mappings-link')).toBeTruthy();
});
expect(screen.queryByTestId('oidc-provider-edit-button')).toBeNull();
expect(screen.queryByTestId('oidc-provider-refresh-button')).toBeNull();
expect(screen.queryByTestId('oidc-provider-delete-button')).toBeNull();
});
it('refresh button calls refreshOIDCProvider', async () => {
vi.mocked(client.listOIDCProviders).mockResolvedValue({ providers: [sampleProvider] });
vi.mocked(client.refreshOIDCProvider).mockResolvedValue({ refreshed: true });
vi.mocked(client.authMe).mockResolvedValue({
actor_id: 'u-admin',
actor_type: 'User',
tenant_id: 't-default',
admin: true,
roles: ['r-admin'],
effective_permissions: [
{ permission: 'auth.oidc.list', scope_type: 'global' },
{ permission: 'auth.oidc.edit', scope_type: 'global' },
],
});
renderRoute();
await waitFor(() => {
expect(screen.getByTestId('oidc-provider-refresh-button')).toBeTruthy();
});
fireEvent.click(screen.getByTestId('oidc-provider-refresh-button'));
await waitFor(() => {
expect(client.refreshOIDCProvider).toHaveBeenCalledWith('op-okta');
});
});
it('delete confirm button stays disabled until typed text matches provider name', async () => {
vi.mocked(client.listOIDCProviders).mockResolvedValue({ providers: [sampleProvider] });
vi.mocked(client.authMe).mockResolvedValue({
actor_id: 'u-admin',
actor_type: 'User',
tenant_id: 't-default',
admin: true,
roles: ['r-admin'],
effective_permissions: [
{ permission: 'auth.oidc.list', scope_type: 'global' },
{ permission: 'auth.oidc.delete', scope_type: 'global' },
],
});
renderRoute();
await waitFor(() => {
expect(screen.getByTestId('oidc-provider-delete-button')).toBeTruthy();
});
fireEvent.click(screen.getByTestId('oidc-provider-delete-button'));
await waitFor(() => {
expect(screen.getByTestId('oidc-provider-delete-confirm')).toBeTruthy();
});
const confirmBtn = screen.getByTestId('oidc-provider-delete-confirm-button') as HTMLButtonElement;
expect(confirmBtn.disabled).toBe(true);
fireEvent.change(screen.getByTestId('oidc-provider-delete-confirm-input'), {
target: { value: 'Wrong' },
});
expect(confirmBtn.disabled).toBe(true);
fireEvent.change(screen.getByTestId('oidc-provider-delete-confirm-input'), {
target: { value: 'Okta' },
});
expect(confirmBtn.disabled).toBe(false);
});
});