From c40dd553fa951178e09d6215bd83414c23a67cdb Mon Sep 17 00:00:00 2001 From: harish-sundar_akto Date: Fri, 22 May 2026 15:47:48 +0530 Subject: [PATCH 1/5] refactor: domain table hook architecture separation --- .../__tests__/domain-table.test.tsx | 28 +- .../auth0/my-organization/domain-table.tsx | 87 ++- packages/react/src/hooks/index.ts | 1 - .../__tests__/use-domain-table-logic.test.ts | 594 ------------------ .../use-domain-table-service.test.ts} | 16 +- .../services/use-domain-table-service.ts | 222 +++++++ .../my-organization/use-domain-table-logic.ts | 257 -------- .../hooks/my-organization/use-domain-table.ts | 395 +++++++----- .../domain-management/domain.mocks.ts | 31 +- .../domain-management/domain-table-types.ts | 59 +- 10 files changed, 567 insertions(+), 1123 deletions(-) delete mode 100644 packages/react/src/hooks/my-organization/__tests__/use-domain-table-logic.test.ts rename packages/react/src/hooks/my-organization/{__tests__/use-domain-table.test.ts => shared/__tests__/use-domain-table-service.test.ts} (97%) create mode 100644 packages/react/src/hooks/my-organization/shared/services/use-domain-table-service.ts delete mode 100644 packages/react/src/hooks/my-organization/use-domain-table-logic.ts diff --git a/packages/react/src/components/auth0/my-organization/__tests__/domain-table.test.tsx b/packages/react/src/components/auth0/my-organization/__tests__/domain-table.test.tsx index 1908ddcb2..17417e5f8 100644 --- a/packages/react/src/components/auth0/my-organization/__tests__/domain-table.test.tsx +++ b/packages/react/src/components/auth0/my-organization/__tests__/domain-table.test.tsx @@ -13,8 +13,7 @@ import { createMockCreateAction, createMockVerifyAction, createMockDeleteAction, - createMockLogic, - createMockApi, + createMockDomainTableReturn, } from '@/tests/utils/__mocks__/my-organization/domain-management/domain.mocks'; import { renderWithProviders } from '@/tests/utils/test-provider'; import { mockCore, mockToast } from '@/tests/utils/test-setup'; @@ -681,27 +680,32 @@ describe('DomainTable', () => { }); describe('DomainTableView', () => { - // Provide all required handlers and properties for UseDomainTableResult & DomainTableProps - const logic = createMockLogic(); - const handlers = createMockApi(); + const mockDomainTable = createMockDomainTableReturn(); + const defaultViewProps = { + domainTable: mockDomainTable, + schema: undefined, + styling: { variables: { common: {}, light: {}, dark: {} }, classes: {} }, + hideHeader: false, + readOnly: false, + customMessages: {}, + createAction: undefined, + onOpenProvider: undefined, + onCreateProvider: undefined, + }; it('renders the table and header', () => { - renderWithProviders(); + renderWithProviders(); expect(screen.getByRole('table')).toBeInTheDocument(); expect(screen.getByText(/header.title/i)).toBeInTheDocument(); }); it('does not render header if hideHeader is true', () => { - renderWithProviders( - , - ); + renderWithProviders(); expect(screen.queryByText(/header.title/i)).not.toBeInTheDocument(); }); it('disables create button if readOnly is true', () => { - renderWithProviders( - , - ); + renderWithProviders(); expect(screen.getByRole('button', { name: /create/i })).toBeDisabled(); }); }); diff --git a/packages/react/src/components/auth0/my-organization/domain-table.tsx b/packages/react/src/components/auth0/my-organization/domain-table.tsx index 10d01c95b..85f2955a6 100644 --- a/packages/react/src/components/auth0/my-organization/domain-table.tsx +++ b/packages/react/src/components/auth0/my-organization/domain-table.tsx @@ -15,14 +15,10 @@ import { Header } from '@/components/auth0/shared/header'; import { StyledScope } from '@/components/auth0/shared/styled-scope'; import { Badge } from '@/components/ui/badge'; import { useDomainTable } from '@/hooks/my-organization/use-domain-table'; -import { useDomainTableLogic } from '@/hooks/my-organization/use-domain-table-logic'; import { useTheme } from '@/hooks/shared/use-theme'; import { useTranslator } from '@/hooks/shared/use-translator'; import { getStatusBadgeVariant } from '@/lib/utils/my-organization/domain-management/domain-management-utils'; -import type { - DomainTableProps, - DomainTableViewProps, -} from '@/types/my-organization/domain-management/domain-table-types'; +import type { DomainTableProps } from '@/types/my-organization/domain-management/domain-table-types'; /** * DomainTable container component. @@ -46,9 +42,7 @@ function DomainTable(props: DomainTableProps) { onCreateProvider, } = props; - const { t } = useTranslator('domain_management', customMessages); - - const domainTableState = useDomainTable({ + const domainTable = useDomainTable({ createAction, verifyAction, deleteAction, @@ -57,46 +51,52 @@ function DomainTable(props: DomainTableProps) { customMessages, }); - const domainTableHandlers = useDomainTableLogic({ - t, - onCreateDomain: domainTableState.onCreateDomain, - onVerifyDomain: domainTableState.onVerifyDomain, - onDeleteDomain: domainTableState.onDeleteDomain, - onAssociateToProvider: domainTableState.onAssociateToProvider, - onDeleteFromProvider: domainTableState.onDeleteFromProvider, - fetchProviders: domainTableState.fetchProviders, - fetchDomains: domainTableState.fetchDomains, - }); - - const domainTableLogic = { - ...domainTableState, - schema, - styling, - hideHeader, - readOnly, - onOpenProvider, - onCreateProvider, - }; - return ( - - + + ); } /** * DomainTableView — Presentational component. - * @param props - View props with logic and handlers + * @param props - View props * @returns Domain table view element * @internal */ function DomainTableView({ - logic, - handlers, -}: DomainTableViewProps & { handlers: ReturnType }) { + domainTable, + schema, + styling, + hideHeader, + readOnly = false, + customMessages, + createAction, + onOpenProvider, + onCreateProvider, +}: { + domainTable: ReturnType; + schema: DomainTableProps['schema']; + styling: DomainTableProps['styling']; + hideHeader: DomainTableProps['hideHeader']; + readOnly: DomainTableProps['readOnly']; + customMessages: DomainTableProps['customMessages']; + createAction: DomainTableProps['createAction']; + onOpenProvider: DomainTableProps['onOpenProvider']; + onCreateProvider: DomainTableProps['onCreateProvider']; +}) { const { isDarkMode } = useTheme(); - const { t } = useTranslator('domain_management', logic.customMessages); + const { t } = useTranslator('domain_management', customMessages); const { domains, @@ -106,17 +106,6 @@ function DomainTableView({ isFetching, isLoadingProviders, isDeleting, - schema, - styling, - hideHeader, - readOnly = false, - customMessages, - createAction, - onOpenProvider, - onCreateProvider, - } = logic; - - const { showCreateModal, showConfigureModal, showVerifyModal, @@ -135,7 +124,7 @@ function DomainTableView({ handleConfigureClick, handleVerifyClick, handleDeleteClick, - } = handlers; + } = domainTable; const currentStyles = React.useMemo( () => getComponentStyles(styling, isDarkMode), @@ -172,7 +161,7 @@ function DomainTableView({ , -): UseDomainTableLogicOptions => ({ - t: createMockI18nService().translator('my-organization'), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - ...overrides, -}); - -// ===== Tests ===== - -describe('useDomainTableLogic', () => { - let mockCoreClient: ReturnType; - let mockHandleError: ReturnType; - let mockOptions: UseDomainTableLogicOptions; - - beforeEach(() => { - vi.clearAllMocks(); - - mockCoreClient = initMockCoreClient(); - mockHandleError = vi.fn(); - mockOptions = createMockOptions(); - - vi.spyOn(useCoreClientModule, 'useCoreClient').mockReturnValue({ - coreClient: mockCoreClient, - }); - - vi.spyOn(useErrorHandlerModule, 'useErrorHandler').mockReturnValue(mockHandleError); - }); - - describe('Initial State', () => { - it('should initialize with correct default state', () => { - const { result } = renderHook(() => useDomainTableLogic(mockOptions)); - - expect(result.current.showCreateModal).toBe(false); - expect(result.current.showConfigureModal).toBe(false); - expect(result.current.showVerifyModal).toBe(false); - expect(result.current.showDeleteModal).toBe(false); - expect(result.current.verifyError).toBeUndefined(); - expect(result.current.selectedDomain).toBeNull(); - }); - - it('should call fetchDomains on mount when coreClient is available', async () => { - renderHook(() => useDomainTableLogic(mockOptions)); - - await waitFor(() => { - expect(mockOptions.fetchDomains).toHaveBeenCalledTimes(1); - }); - }); - - it('should handle fetchDomains error on initialization', async () => { - const error = new Error('Fetch domains failed'); - const mockFetchDomains = vi.fn().mockImplementation(() => { - throw error; - }); - const options = createMockOptions({ fetchDomains: mockFetchDomains }); - - renderHook(() => useDomainTableLogic(options)); - - await waitFor(() => { - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.fetch_domains_error', - }); - }); - }); - }); - - describe('Modal State Management', () => { - it('should update create modal state', () => { - const { result } = renderHook(() => useDomainTableLogic(mockOptions)); - - act(() => { - result.current.setShowCreateModal(true); - }); - - expect(result.current.showCreateModal).toBe(true); - }); - - it('should update configure modal state', () => { - const { result } = renderHook(() => useDomainTableLogic(mockOptions)); - - act(() => { - result.current.setShowConfigureModal(true); - }); - - expect(result.current.showConfigureModal).toBe(true); - }); - - it('should update verify modal state', () => { - const { result } = renderHook(() => useDomainTableLogic(mockOptions)); - - act(() => { - result.current.setShowVerifyModal(true); - }); - - expect(result.current.showVerifyModal).toBe(true); - }); - - it('should update delete modal state', () => { - const { result } = renderHook(() => useDomainTableLogic(mockOptions)); - - act(() => { - result.current.setShowDeleteModal(true); - }); - - expect(result.current.showDeleteModal).toBe(true); - }); - }); - - describe('handleCreate', () => { - it('should create domain successfully and show verify modal', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - const mockOnCreateDomain = vi.fn().mockResolvedValue(mockDomain); - const options = createMockOptions({ onCreateDomain: mockOnCreateDomain }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleCreate('test.com'); - }); - - expect(mockOnCreateDomain).toHaveBeenCalledWith({ domain: 'test.com' }); - expect(mockedShowToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_create.success', - }); - expect(result.current.selectedDomain).toEqual(mockDomain); - expect(result.current.showCreateModal).toBe(false); - expect(result.current.showVerifyModal).toBe(true); - }); - - it('should handle create domain error', async () => { - const error = new Error('Create failed'); - const mockOnCreateDomain = vi.fn().mockRejectedValue(error); - const options = createMockOptions({ onCreateDomain: mockOnCreateDomain }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleCreate('test.com'); - }); - - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_create.error', - }); - }); - }); - - describe('handleVerify', () => { - it('should verify domain successfully and close verify modal', async () => { - const mockDomain = createMockDomain(); - const mockOnVerifyDomain = vi.fn().mockResolvedValue(true); - const options = createMockOptions({ onVerifyDomain: mockOnVerifyDomain }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleVerify(mockDomain); - }); - - expect(mockOnVerifyDomain).toHaveBeenCalledWith(mockDomain); - expect(result.current.showVerifyModal).toBe(false); - expect(mockedShowToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_verify.success', - }); - }); - - it('should handle verification failure and set verify error', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - const mockOnVerifyDomain = vi.fn().mockResolvedValue(false); - const options = createMockOptions({ onVerifyDomain: mockOnVerifyDomain }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleVerify(mockDomain); - }); - - expect(result.current.verifyError).toBe('domain_verify.modal.errors.verification_failed'); - }); - - it('should handle verify domain error', async () => { - const mockDomain = createMockDomain(); - const error = new Error('Verify failed'); - const mockOnVerifyDomain = vi.fn().mockRejectedValue(error); - const options = createMockOptions({ onVerifyDomain: mockOnVerifyDomain }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleVerify(mockDomain); - }); - - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_verify.error', - }); - }); - }); - - describe('handleDelete', () => { - it('should delete domain successfully', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - const mockOnDeleteDomain = vi.fn().mockResolvedValue(undefined); - const options = createMockOptions({ onDeleteDomain: mockOnDeleteDomain }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleDelete(mockDomain); - }); - - expect(mockOnDeleteDomain).toHaveBeenCalledWith(mockDomain); - expect(mockedShowToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_delete.success', - }); - expect(result.current.showDeleteModal).toBe(false); - expect(result.current.showVerifyModal).toBe(false); - }); - - it('should handle delete domain error', async () => { - const mockDomain = createMockDomain(); - const error = new Error('Delete failed'); - const mockOnDeleteDomain = vi.fn().mockRejectedValue(error); - const options = createMockOptions({ onDeleteDomain: mockOnDeleteDomain }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleDelete(mockDomain); - }); - - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_delete.error', - }); - }); - }); - - describe('handleToggleSwitch', () => { - it('should associate domain to provider when checked is true', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - const mockProvider = createMockIdentityProvider({ name: 'TestIDP' }); - const mockOnAssociateToProvider = vi.fn().mockResolvedValue(undefined); - const options = createMockOptions({ onAssociateToProvider: mockOnAssociateToProvider }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleToggleSwitch(mockDomain, mockProvider, true); - }); - - expect(mockOnAssociateToProvider).toHaveBeenCalledWith(mockDomain, mockProvider); - expect(mockedShowToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_associate_provider.success', - }); - }); - - it('should delete domain from provider when checked is false', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - const mockProvider = createMockIdentityProvider({ name: 'TestIDP' }); - const mockOnDeleteFromProvider = vi.fn().mockResolvedValue(undefined); - const options = createMockOptions({ onDeleteFromProvider: mockOnDeleteFromProvider }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleToggleSwitch(mockDomain, mockProvider, false); - }); - - expect(mockOnDeleteFromProvider).toHaveBeenCalledWith(mockDomain, mockProvider); - expect(mockedShowToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_delete_provider.success', - }); - }); - - it('should handle associate to provider error', async () => { - const mockDomain = createMockDomain(); - const mockProvider = createMockIdentityProvider(); - const error = new Error('Associate failed'); - const mockOnAssociateToProvider = vi.fn().mockRejectedValue(error); - const options = createMockOptions({ onAssociateToProvider: mockOnAssociateToProvider }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleToggleSwitch(mockDomain, mockProvider, true); - }); - - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_associate_provider.error', - }); - }); - - it('should handle delete from provider error', async () => { - const mockDomain = createMockDomain(); - const mockProvider = createMockIdentityProvider(); - const error = new Error('Delete from provider failed'); - const mockOnDeleteFromProvider = vi.fn().mockRejectedValue(error); - const options = createMockOptions({ onDeleteFromProvider: mockOnDeleteFromProvider }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleToggleSwitch(mockDomain, mockProvider, false); - }); - - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_delete_provider.error', - }); - }); - }); - - describe('handleCloseVerifyModal', () => { - it('should close verify modal and clear verify error', async () => { - const { result } = renderHook(() => useDomainTableLogic(mockOptions)); - - // Set initial state - act(() => { - result.current.setShowVerifyModal(true); - }); - - // Simulate verify error - await act(async () => { - await result.current.handleVerify(createMockDomain()); - }); - - // Close modal - act(() => { - result.current.handleCloseVerifyModal(); - }); - - expect(result.current.showVerifyModal).toBe(false); - expect(result.current.verifyError).toBeUndefined(); - }); - }); - - describe('handleCreateClick', () => { - it('should show create modal', () => { - const { result } = renderHook(() => useDomainTableLogic(mockOptions)); - - act(() => { - result.current.handleCreateClick(); - }); - - expect(result.current.showCreateModal).toBe(true); - }); - }); - - describe('handleConfigureClick', () => { - it('should show verify modal for unverified domain', async () => { - const mockDomain = createMockDomain({ status: 'pending' }); - const { result } = renderHook(() => useDomainTableLogic(mockOptions)); - - await act(async () => { - await result.current.handleConfigureClick(mockDomain); - }); - - expect(result.current.selectedDomain).toEqual(mockDomain); - expect(result.current.showVerifyModal).toBe(true); - }); - - it('should fetch providers and show configure modal for verified domain', async () => { - const mockDomain = createMockDomain({ status: 'verified' }); - const mockFetchProviders = vi.fn().mockResolvedValue(undefined); - const options = createMockOptions({ fetchProviders: mockFetchProviders }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleConfigureClick(mockDomain); - }); - - expect(result.current.selectedDomain).toEqual(mockDomain); - expect(mockFetchProviders).toHaveBeenCalledWith(mockDomain); - expect(result.current.showConfigureModal).toBe(true); - }); - - it('should handle fetchProviders error for verified domain', async () => { - const mockDomain = createMockDomain({ status: 'verified' }); - const error = new Error('Fetch providers failed'); - const mockFetchProviders = vi.fn().mockRejectedValue(error); - const options = createMockOptions({ fetchProviders: mockFetchProviders }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleConfigureClick(mockDomain); - }); - - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.fetch_providers_error', - }); - }); - }); - - describe('handleVerifyClick', () => { - it('should verify domain, fetch providers, and show configure modal on success', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - const mockOnVerifyDomain = vi.fn().mockResolvedValue(true); - const mockFetchProviders = vi.fn().mockResolvedValue(undefined); - const options = createMockOptions({ - onVerifyDomain: mockOnVerifyDomain, - fetchProviders: mockFetchProviders, - }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleVerifyClick(mockDomain); - }); - - expect(result.current.selectedDomain).toEqual(mockDomain); - expect(mockOnVerifyDomain).toHaveBeenCalledWith(mockDomain); - expect(mockFetchProviders).toHaveBeenCalledWith(mockDomain); - expect(result.current.showConfigureModal).toBe(true); - expect(mockedShowToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_verify.success', - }); - }); - - it('should show error toast on verification failure', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - const mockOnVerifyDomain = vi.fn().mockResolvedValue(false); - const options = createMockOptions({ onVerifyDomain: mockOnVerifyDomain }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleVerifyClick(mockDomain); - }); - - expect(mockedShowToast).toHaveBeenCalledWith({ - type: 'error', - message: 'domain_table.notifications.domain_verify.verification_failed', - }); - }); - - it('should handle verify click error', async () => { - const mockDomain = createMockDomain(); - const error = new Error('Verify click failed'); - const mockOnVerifyDomain = vi.fn().mockRejectedValue(error); - const options = createMockOptions({ onVerifyDomain: mockOnVerifyDomain }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleVerifyClick(mockDomain); - }); - - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_verify.error', - }); - }); - }); - - describe('handleDeleteClick', () => { - it('should set selected domain and show delete modal', () => { - const mockDomain = createMockDomain(); - const { result } = renderHook(() => useDomainTableLogic(mockOptions)); - - // Set verify modal to true initially - act(() => { - result.current.setShowVerifyModal(true); - }); - - act(() => { - result.current.handleDeleteClick(mockDomain); - }); - - expect(result.current.selectedDomain).toEqual(mockDomain); - expect(result.current.showVerifyModal).toBe(false); - expect(result.current.showDeleteModal).toBe(true); - }); - }); - - describe('Edge Cases and Integration', () => { - it('should handle multiple modal state changes correctly', () => { - const { result } = renderHook(() => useDomainTableLogic(mockOptions)); - - act(() => { - result.current.setShowCreateModal(true); - result.current.setShowConfigureModal(true); - result.current.setShowVerifyModal(true); - result.current.setShowDeleteModal(true); - }); - - expect(result.current.showCreateModal).toBe(true); - expect(result.current.showConfigureModal).toBe(true); - expect(result.current.showVerifyModal).toBe(true); - expect(result.current.showDeleteModal).toBe(true); - - act(() => { - result.current.setShowCreateModal(false); - result.current.setShowConfigureModal(false); - result.current.setShowVerifyModal(false); - result.current.setShowDeleteModal(false); - }); - - expect(result.current.showCreateModal).toBe(false); - expect(result.current.showConfigureModal).toBe(false); - expect(result.current.showVerifyModal).toBe(false); - expect(result.current.showDeleteModal).toBe(false); - }); - - it('should handle domain creation with null return value', async () => { - const mockOnCreateDomain = vi.fn().mockResolvedValue(null); - const options = createMockOptions({ onCreateDomain: mockOnCreateDomain }); - - const { result } = renderHook(() => useDomainTableLogic(options)); - - await act(async () => { - await result.current.handleCreate('test.com'); - }); - - expect(result.current.selectedDomain).toBeNull(); - expect(result.current.showCreateModal).toBe(false); - expect(result.current.showVerifyModal).toBe(true); - }); - - it('should handle various domain statuses in handleConfigureClick', async () => { - const { result } = renderHook(() => useDomainTableLogic(mockOptions)); - - // Test with 'failed' status - const failedDomain = createMockDomain({ status: 'failed' }); - await act(async () => { - await result.current.handleConfigureClick(failedDomain); - }); - expect(result.current.showVerifyModal).toBe(true); - - // Reset state - act(() => { - result.current.setShowVerifyModal(false); - }); - - // Test with 'verified' status - const verifiedDomain = createMockDomain({ status: 'verified' }); - await act(async () => { - await result.current.handleConfigureClick(verifiedDomain); - }); - expect(result.current.showConfigureModal).toBe(true); - }); - }); - - describe('Callback Dependencies', () => { - it('should update callbacks when dependencies change', () => { - const { result, rerender } = renderHook((options) => useDomainTableLogic(options), { - initialProps: mockOptions, - }); - - const initialHandleCreate = result.current.handleCreate; - - // Update the options with a new onCreateDomain function - const newOptions = createMockOptions({ - onCreateDomain: vi.fn(), - }); - - rerender(newOptions); - - // The callback should be different due to dependency change - expect(result.current.handleCreate).not.toBe(initialHandleCreate); - }); - }); -}); diff --git a/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts b/packages/react/src/hooks/my-organization/shared/__tests__/use-domain-table-service.test.ts similarity index 97% rename from packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts rename to packages/react/src/hooks/my-organization/shared/__tests__/use-domain-table-service.test.ts index 2ea12ea98..f3c59907a 100644 --- a/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts +++ b/packages/react/src/hooks/my-organization/shared/__tests__/use-domain-table-service.test.ts @@ -6,7 +6,7 @@ import { BusinessError } from '@auth0/universal-components-core'; import { renderHook, waitFor } from '@testing-library/react'; import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { useDomainTable } from '@/hooks/my-organization/use-domain-table'; +import { useDomainTableService } from '@/hooks/my-organization/shared/services/use-domain-table-service'; import * as useCoreClientModule from '@/hooks/shared/use-core-client'; import * as useTranslatorModule from '@/hooks/shared/use-translator'; import { @@ -16,7 +16,7 @@ import { createMockI18nService, } from '@/tests/utils'; import { createTestQueryClientWrapper } from '@/tests/utils/test-provider'; -import type { UseDomainTableOptions } from '@/types/my-organization/domain-management/domain-table-types'; +import type { UseDomainTableServiceOptions } from '@/types/my-organization/domain-management/domain-table-types'; // ===== Mock packages ===== @@ -24,7 +24,9 @@ const { initMockCoreClient } = mockCore(); // ===== Mock Data ===== -const createMockOptions = (overrides?: Partial): UseDomainTableOptions => ({ +const createMockOptions = ( + overrides?: Partial, +): UseDomainTableServiceOptions => ({ createAction: { onBefore: vi.fn().mockReturnValue(true), onAfter: vi.fn(), @@ -49,19 +51,19 @@ const createMockOptions = (overrides?: Partial): UseDomai ...overrides, }); -const renderUseDomainTable = (options: UseDomainTableOptions) => { +const renderUseDomainTable = (options: UseDomainTableServiceOptions) => { const { wrapper, queryClient } = createTestQueryClientWrapper(); return { queryClient, - ...renderHook(() => useDomainTable(options), { wrapper }), + ...renderHook(() => useDomainTableService(options), { wrapper }), }; }; // ===== Tests ===== -describe('useDomainTable', () => { +describe('useDomainTableService', () => { let mockCoreClient: ReturnType; - let mockOptions: UseDomainTableOptions; + let mockOptions: UseDomainTableServiceOptions; let mockT: EnhancedTranslationFunction; beforeEach(() => { diff --git a/packages/react/src/hooks/my-organization/shared/services/use-domain-table-service.ts b/packages/react/src/hooks/my-organization/shared/services/use-domain-table-service.ts new file mode 100644 index 000000000..63d8cdaae --- /dev/null +++ b/packages/react/src/hooks/my-organization/shared/services/use-domain-table-service.ts @@ -0,0 +1,222 @@ +/** + * Internal domain table service hook. + * Handles data fetching and CRUD operations for domains. + * @module use-domain-table-service + * @internal + */ + +import { + type Domain, + type IdpKnownResponse, + type CreateOrganizationDomainRequestContent, + type IdentityProviderAssociatedWithDomain, + BusinessError, +} from '@auth0/universal-components-core'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { useCallback, useState } from 'react'; + +import { useCoreClient } from '@/hooks/shared/use-core-client'; +import { useTranslator } from '@/hooks/shared/use-translator'; +import type { + UseDomainTableServiceOptions, + UseDomainTableServiceReturn, +} from '@/types/my-organization/domain-management/domain-table-types'; + +export const domainQueryKeys = { + all: ['domains'] as const, + list: () => [...domainQueryKeys.all, 'list'] as const, + providers: (domainId: string) => [...domainQueryKeys.all, 'providers', domainId] as const, +}; + +/** + * Internal service hook for domain table data and CRUD operations. + * @param options - Service options including actions and custom messages. + * @returns Domain data, mutations, and actions. + * @internal + */ +export function useDomainTableService({ + createAction, + deleteAction, + verifyAction, + associateToProviderAction, + deleteFromProviderAction, + customMessages, +}: UseDomainTableServiceOptions): UseDomainTableServiceReturn { + const { t } = useTranslator('domain_management.domain_table.notifications', customMessages); + const { coreClient } = useCoreClient(); + const queryClient = useQueryClient(); + + const [selectedDomainId, setSelectedDomainId] = useState(null); + const [selectedDomainName, setSelectedDomainName] = useState(null); + + const fetchProvidersForDomain = async (domainName: string) => { + const api = coreClient!.getMyOrganizationApiClient(); + + const allProvidersResponse = await api.organization.identityProviders.list(); + const allProviders = allProvidersResponse?.identity_providers ?? []; + + return allProviders.map( + (provider): IdentityProviderAssociatedWithDomain => ({ + ...provider, + is_associated: provider.domains?.includes(domainName) ?? false, + }), + ); + }; + + const domainsQuery = useQuery({ + queryKey: domainQueryKeys.list(), + queryFn: async () => { + const { response } = await coreClient! + .getMyOrganizationApiClient() + .organization.domains.list(); + return response?.organization_domains ?? []; + }, + enabled: !!coreClient, + }); + + const providersQuery = useQuery({ + queryKey: domainQueryKeys.providers(selectedDomainId ?? ''), + queryFn: () => fetchProvidersForDomain(selectedDomainName!), + enabled: !!coreClient && !!selectedDomainId && !!selectedDomainName, + }); + + const createDomainMutation = useMutation({ + mutationFn: async (data: CreateOrganizationDomainRequestContent): Promise => { + if (createAction?.onBefore && !createAction.onBefore(data as Domain)) { + throw new BusinessError({ message: t('domain_create.on_before') }); + } + return coreClient!.getMyOrganizationApiClient().organization.domains.create(data); + }, + onSuccess: (result) => { + createAction?.onAfter?.(result); + queryClient.invalidateQueries({ queryKey: domainQueryKeys.list() }); + }, + }); + + const verifyDomainMutation = useMutation({ + mutationFn: async (domain: Domain): Promise => { + if (verifyAction?.onBefore && !verifyAction.onBefore(domain)) { + throw new BusinessError({ message: t('domain_verify.on_before') }); + } + const response = await coreClient! + .getMyOrganizationApiClient() + .organization.domains.verify.create(domain.id); + return response.status === 'verified'; + }, + onSuccess: (_, domain) => { + verifyAction?.onAfter?.(domain); + queryClient.invalidateQueries({ queryKey: domainQueryKeys.list() }); + }, + }); + + const deleteDomainMutation = useMutation({ + mutationFn: async (domain: Domain): Promise => { + if (deleteAction?.onBefore && !deleteAction.onBefore(domain)) { + throw new BusinessError({ message: t('domain_delete.on_before') }); + } + await coreClient!.getMyOrganizationApiClient().organization.domains.delete(domain.id); + }, + onSuccess: (_, domain) => { + deleteAction?.onAfter?.(domain); + queryClient.invalidateQueries({ queryKey: domainQueryKeys.list() }); + queryClient.removeQueries({ queryKey: domainQueryKeys.providers(domain.id) }); + }, + }); + + const associateToProviderMutation = useMutation({ + mutationFn: async ({ domain, provider }: { domain: Domain; provider: IdpKnownResponse }) => { + if ( + associateToProviderAction?.onBefore && + !associateToProviderAction.onBefore(domain, provider) + ) { + throw new BusinessError({ message: t('domain_associate_provider.on_before') }); + } + await coreClient! + .getMyOrganizationApiClient() + .organization.identityProviders.domains.create(provider.id!, { domain: domain.domain }); + }, + onSuccess: (_, { domain, provider }) => { + associateToProviderAction?.onAfter?.(domain, provider); + queryClient.invalidateQueries({ queryKey: domainQueryKeys.providers(domain.id) }); + }, + }); + + const deleteFromProviderMutation = useMutation({ + mutationFn: async ({ domain, provider }: { domain: Domain; provider: IdpKnownResponse }) => { + if ( + deleteFromProviderAction?.onBefore && + !deleteFromProviderAction.onBefore(domain, provider) + ) { + throw new BusinessError({ message: t('domain_delete_provider.on_before') }); + } + await coreClient! + .getMyOrganizationApiClient() + .organization.identityProviders.domains.delete(provider.id!, domain.domain); + }, + onSuccess: (_, { domain, provider }) => { + deleteFromProviderAction?.onAfter?.(domain, provider); + queryClient.invalidateQueries({ queryKey: domainQueryKeys.providers(domain.id) }); + }, + }); + + const onCreateDomain = useCallback( + (data: CreateOrganizationDomainRequestContent) => createDomainMutation.mutateAsync(data), + [createDomainMutation], + ); + + const onVerifyDomain = useCallback( + (domain: Domain) => verifyDomainMutation.mutateAsync(domain), + [verifyDomainMutation], + ); + + const onDeleteDomain = useCallback( + (domain: Domain) => deleteDomainMutation.mutateAsync(domain), + [deleteDomainMutation], + ); + + const onAssociateToProvider = useCallback( + (domain: Domain, provider: IdpKnownResponse) => + associateToProviderMutation.mutateAsync({ domain, provider }), + [associateToProviderMutation], + ); + + const onDeleteFromProvider = useCallback( + (domain: Domain, provider: IdpKnownResponse) => + deleteFromProviderMutation.mutateAsync({ domain, provider }), + [deleteFromProviderMutation], + ); + + const fetchProviders = useCallback( + async (domain: Domain) => { + setSelectedDomainId(domain.id); + setSelectedDomainName(domain.domain); + await queryClient.ensureQueryData({ + queryKey: domainQueryKeys.providers(domain.id), + queryFn: () => fetchProvidersForDomain(domain.domain), + }); + }, + [queryClient, coreClient], + ); + + const fetchDomains = useCallback(async () => { + await queryClient.getQueryData(domainQueryKeys.list()); + }, [queryClient]); + + return { + domains: domainsQuery.data ?? [], + providers: providersQuery.data ?? [], + isFetching: domainsQuery.isLoading, + isCreating: createDomainMutation.isPending, + isDeleting: deleteDomainMutation.isPending, + isVerifying: verifyDomainMutation.isPending, + isLoadingProviders: providersQuery.isLoading, + + fetchProviders, + fetchDomains, + onCreateDomain, + onVerifyDomain, + onDeleteDomain, + onAssociateToProvider, + onDeleteFromProvider, + }; +} diff --git a/packages/react/src/hooks/my-organization/use-domain-table-logic.ts b/packages/react/src/hooks/my-organization/use-domain-table-logic.ts deleted file mode 100644 index 4d9ab05f8..000000000 --- a/packages/react/src/hooks/my-organization/use-domain-table-logic.ts +++ /dev/null @@ -1,257 +0,0 @@ -/** - * Domain table UI logic hook. - * @module use-domain-table-logic - * @internal - */ - -import { type Domain, type IdpKnownResponse } from '@auth0/universal-components-core'; -import { useCallback, useEffect, useState } from 'react'; - -import { showToast } from '@/components/auth0/shared/toast'; -import { useErrorHandler } from '@/hooks/shared/use-error-handler'; -import type { - UseDomainTableLogicOptions, - UseDomainTableLogicResult, -} from '@/types/my-organization/domain-management/domain-table-types'; - -/** - * Hook for domain table modal state and action handlers. - * @param props - Component props. - * @param props.t - Translation function - * @param props.onCreateDomain - The on create domain - * @param props.onVerifyDomain - The on verify domain - * @param props.onDeleteDomain - The on delete domain - * @param props.onAssociateToProvider - The on associate to provider - * @param props.onDeleteFromProvider - The on delete from provider - * @param props.fetchProviders - The fetch providers - * @param props.fetchDomains - The fetch domains - * @internal - * @returns Hook state and methods - */ -export function useDomainTableLogic({ - t, - onCreateDomain, - onVerifyDomain, - onDeleteDomain, - onAssociateToProvider, - onDeleteFromProvider, - fetchProviders, - fetchDomains, -}: UseDomainTableLogicOptions): UseDomainTableLogicResult { - const handleError = useErrorHandler(); - const [showCreateModal, setShowCreateModal] = useState(false); - const [showConfigureModal, setShowConfigureModal] = useState(false); - const [showVerifyModal, setShowVerifyModal] = useState(false); - const [verifyError, setVerifyError] = useState(undefined); - const [showDeleteModal, setShowDeleteModal] = useState(false); - const [selectedDomain, setSelectedDomain] = useState(null); - - const handleCreate = useCallback( - async (domainUrl: string) => { - try { - const newDomain = await onCreateDomain({ domain: domainUrl }); - showToast({ - type: 'success', - message: t('domain_table.notifications.domain_create.success', { - domainName: newDomain?.domain, - }), - }); - setSelectedDomain(newDomain); - setShowCreateModal(false); - setShowVerifyModal(true); - } catch (error) { - handleError(error, { - fallbackMessage: t('domain_table.notifications.domain_create.error'), - }); - } - }, - [onCreateDomain, t, handleError], - ); - - const handleVerify = useCallback( - async (domain: Domain) => { - try { - const isVerified = await onVerifyDomain(domain); - if (isVerified) { - setShowVerifyModal(false); - showToast({ - type: 'success', - message: t('domain_table.notifications.domain_verify.success', { - domainName: domain.domain, - }), - }); - } else { - setVerifyError( - t('domain_verify.modal.errors.verification_failed', { domainName: domain.domain }), - ); - } - } catch (error) { - handleError(error, { - fallbackMessage: t('domain_table.notifications.domain_verify.error'), - }); - } - }, - [onVerifyDomain, t, handleError], - ); - - const handleDelete = useCallback( - async (domain: Domain) => { - try { - await onDeleteDomain(domain); - showToast({ - type: 'success', - message: t('domain_table.notifications.domain_delete.success', { - domainName: domain.domain, - }), - }); - setShowDeleteModal(false); - setShowVerifyModal(false); - } catch (error) { - handleError(error, { - fallbackMessage: t('domain_table.notifications.domain_delete.error'), - }); - } - }, - [onDeleteDomain, t, handleError], - ); - - const handleToggleSwitch = useCallback( - async (domain: Domain, provider: IdpKnownResponse, newCheckedValue: boolean) => { - if (newCheckedValue) { - try { - await onAssociateToProvider(domain, provider); - showToast({ - type: 'success', - message: t('domain_table.notifications.domain_associate_provider.success', { - domain: domain.domain, - idp: provider.name, - }), - }); - } catch (error) { - handleError(error, { - fallbackMessage: t('domain_table.notifications.domain_associate_provider.error'), - }); - } - } else { - try { - await onDeleteFromProvider(domain, provider); - showToast({ - type: 'success', - message: t('domain_table.notifications.domain_delete_provider.success', { - domain: domain.domain, - idp: provider.name, - }), - }); - } catch (error) { - handleError(error, { - fallbackMessage: t('domain_table.notifications.domain_delete_provider.error'), - }); - } - } - }, - [onAssociateToProvider, onDeleteFromProvider, t, handleError], - ); - - const handleCloseVerifyModal = useCallback(() => { - setShowVerifyModal(false); - setVerifyError(undefined); - }, []); - - const handleCreateClick = useCallback(() => { - setShowCreateModal(true); - }, []); - - const handleConfigureClick = useCallback( - async (domain: Domain) => { - setSelectedDomain(domain); - if (domain.status !== 'verified') { - setShowVerifyModal(true); - } else { - try { - await fetchProviders(domain); - setShowConfigureModal(true); - } catch (error) { - handleError(error, { - fallbackMessage: t('domain_table.notifications.fetch_providers_error'), - }); - } - } - }, - [fetchProviders, t, handleError], - ); - - const handleVerifyClick = useCallback( - async (domain: Domain) => { - setSelectedDomain(domain); - try { - const isVerified = await onVerifyDomain(domain); - if (isVerified) { - await fetchProviders(domain); - setShowConfigureModal(true); - showToast({ - type: 'success', - message: t('domain_table.notifications.domain_verify.success', { - domainName: domain.domain, - }), - }); - } else { - showToast({ - type: 'error', - message: t('domain_table.notifications.domain_verify.verification_failed', { - domainName: domain.domain, - }), - }); - } - } catch (error) { - handleError(error, { - fallbackMessage: t('domain_table.notifications.domain_verify.error'), - }); - } - }, - [onVerifyDomain, fetchProviders, t, handleError], - ); - - const handleDeleteClick = useCallback((domain: Domain) => { - setSelectedDomain(domain); - setShowVerifyModal(false); - setShowDeleteModal(true); - }, []); - - // Initialization - useEffect(() => { - try { - fetchDomains(); - } catch (error) { - handleError(error, { - fallbackMessage: t('domain_table.notifications.fetch_domains_error'), - }); - } - }, []); - - return { - // Modal state - showCreateModal, - showConfigureModal, - showVerifyModal, - showDeleteModal, - verifyError, - selectedDomain, - - // State setters - setShowCreateModal, - setShowConfigureModal, - setShowVerifyModal, - setShowDeleteModal, - - // Handlers - handleCreate, - handleVerify, - handleDelete, - handleToggleSwitch, - handleCloseVerifyModal, - handleCreateClick, - handleConfigureClick, - handleVerifyClick, - handleDeleteClick, - }; -} diff --git a/packages/react/src/hooks/my-organization/use-domain-table.ts b/packages/react/src/hooks/my-organization/use-domain-table.ts index 6da2f8402..0d6cdc9f8 100644 --- a/packages/react/src/hooks/my-organization/use-domain-table.ts +++ b/packages/react/src/hooks/my-organization/use-domain-table.ts @@ -1,41 +1,26 @@ /** - * Domain table data and mutations hook. + * Domain table hook. + * Single public hook combining data operations and UI logic. * @module use-domain-table */ -import { - type Domain, - type IdpKnownResponse, - type CreateOrganizationDomainRequestContent, - type IdentityProviderAssociatedWithDomain, - BusinessError, -} from '@auth0/universal-components-core'; -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -import { useState } from 'react'; - -import { useCoreClient } from '@/hooks/shared/use-core-client'; +import { type Domain, type IdpKnownResponse } from '@auth0/universal-components-core'; +import { useCallback, useEffect, useState } from 'react'; + +import { showToast } from '@/components/auth0/shared/toast'; +import { useDomainTableService } from '@/hooks/my-organization/shared/services/use-domain-table-service'; +import { useErrorHandler } from '@/hooks/shared/use-error-handler'; import { useTranslator } from '@/hooks/shared/use-translator'; import type { UseDomainTableOptions, - UseDomainTableResult, + UseDomainTableReturn, } from '@/types/my-organization/domain-management/domain-table-types'; -const domainQueryKeys = { - all: ['domains'] as const, - list: () => [...domainQueryKeys.all, 'list'] as const, - providers: (domainId: string) => [...domainQueryKeys.all, 'providers', domainId] as const, -}; - /** - * Hook for domain table data fetching and CRUD operations. - * @param props - Component props. - * @param props.createAction - Configuration for the create action - * @param props.deleteAction - Configuration for the delete action - * @param props.verifyAction - Configuration for the verify action - * @param props.associateToProviderAction - Configuration for associating to a provider - * @param props.deleteFromProviderAction - Configuration for deleting from a provider - * @param props.customMessages - Custom translation messages to override defaults - * @returns Hook state and methods + * Hook for domain table data, CRUD operations, and UI logic. + * Consumes the internal service hook and manages modal/UI state. + * @param options - Hook options including actions and custom messages. + * @returns Combined data, loading states, UI state, and handlers. */ export function useDomainTable({ createAction, @@ -44,149 +29,257 @@ export function useDomainTable({ associateToProviderAction, deleteFromProviderAction, customMessages, -}: UseDomainTableOptions): UseDomainTableResult { - const { t } = useTranslator('domain_management.domain_table.notifications', customMessages); - const { coreClient } = useCoreClient(); - const queryClient = useQueryClient(); - - const [selectedDomainId, setSelectedDomainId] = useState(null); - const [selectedDomainName, setSelectedDomainName] = useState(null); - - const fetchProvidersForDomain = async (domainName: string) => { - const api = coreClient!.getMyOrganizationApiClient(); - - const allProvidersResponse = await api.organization.identityProviders.list(); - const allProviders = allProvidersResponse?.identity_providers ?? []; - - return allProviders.map( - (provider): IdentityProviderAssociatedWithDomain => ({ - ...provider, - is_associated: provider.domains?.includes(domainName) ?? false, - }), - ); - }; +}: UseDomainTableOptions): UseDomainTableReturn { + const { t } = useTranslator('domain_management', customMessages); + const handleError = useErrorHandler(); - const domainsQuery = useQuery({ - queryKey: domainQueryKeys.list(), - queryFn: async () => { - const { response } = await coreClient! - .getMyOrganizationApiClient() - .organization.domains.list(); - return response?.organization_domains ?? []; - }, - enabled: !!coreClient, + const { + domains, + providers, + isFetching, + isCreating, + isDeleting, + isVerifying, + isLoadingProviders, + fetchProviders, + fetchDomains, + onCreateDomain, + onVerifyDomain, + onDeleteDomain, + onAssociateToProvider, + onDeleteFromProvider, + } = useDomainTableService({ + createAction, + deleteAction, + verifyAction, + associateToProviderAction, + deleteFromProviderAction, + customMessages, }); - const providersQuery = useQuery({ - queryKey: domainQueryKeys.providers(selectedDomainId ?? ''), - queryFn: () => fetchProvidersForDomain(selectedDomainName!), - enabled: !!coreClient && !!selectedDomainId && !!selectedDomainName, - }); + const [showCreateModal, setShowCreateModal] = useState(false); + const [showConfigureModal, setShowConfigureModal] = useState(false); + const [showVerifyModal, setShowVerifyModal] = useState(false); + const [verifyError, setVerifyError] = useState(undefined); + const [showDeleteModal, setShowDeleteModal] = useState(false); + const [selectedDomain, setSelectedDomain] = useState(null); - const createDomainMutation = useMutation({ - mutationFn: async (data: CreateOrganizationDomainRequestContent): Promise => { - if (createAction?.onBefore && !createAction.onBefore(data as Domain)) { - throw new BusinessError({ message: t('domain_create.on_before') }); + const handleCreate = useCallback( + async (domainUrl: string) => { + try { + const newDomain = await onCreateDomain({ domain: domainUrl }); + showToast({ + type: 'success', + message: t('domain_table.notifications.domain_create.success', { + domainName: newDomain?.domain, + }), + }); + setSelectedDomain(newDomain); + setShowCreateModal(false); + setShowVerifyModal(true); + } catch (error) { + handleError(error, { + fallbackMessage: t('domain_table.notifications.domain_create.error'), + }); } - return coreClient!.getMyOrganizationApiClient().organization.domains.create(data); - }, - onSuccess: (result) => { - createAction?.onAfter?.(result); - queryClient.invalidateQueries({ queryKey: domainQueryKeys.list() }); }, - }); + [onCreateDomain, t, handleError], + ); - const verifyDomainMutation = useMutation({ - mutationFn: async (domain: Domain): Promise => { - if (verifyAction?.onBefore && !verifyAction.onBefore(domain)) { - throw new BusinessError({ message: t('domain_verify.on_before') }); + const handleVerify = useCallback( + async (domain: Domain) => { + try { + const isVerified = await onVerifyDomain(domain); + if (isVerified) { + setShowVerifyModal(false); + showToast({ + type: 'success', + message: t('domain_table.notifications.domain_verify.success', { + domainName: domain.domain, + }), + }); + } else { + setVerifyError( + t('domain_verify.modal.errors.verification_failed', { domainName: domain.domain }), + ); + } + } catch (error) { + handleError(error, { + fallbackMessage: t('domain_table.notifications.domain_verify.error'), + }); } - const response = await coreClient! - .getMyOrganizationApiClient() - .organization.domains.verify.create(domain.id); - return response.status === 'verified'; }, - onSuccess: (_, domain) => { - verifyAction?.onAfter?.(domain); - queryClient.invalidateQueries({ queryKey: domainQueryKeys.list() }); - }, - }); + [onVerifyDomain, t, handleError], + ); - const deleteDomainMutation = useMutation({ - mutationFn: async (domain: Domain): Promise => { - if (deleteAction?.onBefore && !deleteAction.onBefore(domain)) { - throw new BusinessError({ message: t('domain_delete.on_before') }); + const handleDelete = useCallback( + async (domain: Domain) => { + try { + await onDeleteDomain(domain); + showToast({ + type: 'success', + message: t('domain_table.notifications.domain_delete.success', { + domainName: domain.domain, + }), + }); + setShowDeleteModal(false); + setShowVerifyModal(false); + } catch (error) { + handleError(error, { + fallbackMessage: t('domain_table.notifications.domain_delete.error'), + }); } - await coreClient!.getMyOrganizationApiClient().organization.domains.delete(domain.id); }, - onSuccess: (_, domain) => { - deleteAction?.onAfter?.(domain); - queryClient.invalidateQueries({ queryKey: domainQueryKeys.list() }); - queryClient.removeQueries({ queryKey: domainQueryKeys.providers(domain.id) }); - }, - }); + [onDeleteDomain, t, handleError], + ); - const associateToProviderMutation = useMutation({ - mutationFn: async ({ domain, provider }: { domain: Domain; provider: IdpKnownResponse }) => { - if ( - associateToProviderAction?.onBefore && - !associateToProviderAction.onBefore(domain, provider) - ) { - throw new BusinessError({ message: t('domain_associate_provider.on_before') }); + const handleToggleSwitch = useCallback( + async (domain: Domain, provider: IdpKnownResponse, newCheckedValue: boolean) => { + if (newCheckedValue) { + try { + await onAssociateToProvider(domain, provider); + showToast({ + type: 'success', + message: t('domain_table.notifications.domain_associate_provider.success', { + domain: domain.domain, + idp: provider.name, + }), + }); + } catch (error) { + handleError(error, { + fallbackMessage: t('domain_table.notifications.domain_associate_provider.error'), + }); + } + } else { + try { + await onDeleteFromProvider(domain, provider); + showToast({ + type: 'success', + message: t('domain_table.notifications.domain_delete_provider.success', { + domain: domain.domain, + idp: provider.name, + }), + }); + } catch (error) { + handleError(error, { + fallbackMessage: t('domain_table.notifications.domain_delete_provider.error'), + }); + } } - await coreClient! - .getMyOrganizationApiClient() - .organization.identityProviders.domains.create(provider.id!, { domain: domain.domain }); }, - onSuccess: (_, { domain, provider }) => { - associateToProviderAction?.onAfter?.(domain, provider); - queryClient.invalidateQueries({ queryKey: domainQueryKeys.providers(domain.id) }); - }, - }); + [onAssociateToProvider, onDeleteFromProvider, t, handleError], + ); + + const handleCloseVerifyModal = useCallback(() => { + setShowVerifyModal(false); + setVerifyError(undefined); + }, []); - const deleteFromProviderMutation = useMutation({ - mutationFn: async ({ domain, provider }: { domain: Domain; provider: IdpKnownResponse }) => { - if ( - deleteFromProviderAction?.onBefore && - !deleteFromProviderAction.onBefore(domain, provider) - ) { - throw new BusinessError({ message: t('domain_delete_provider.on_before') }); + const handleCreateClick = useCallback(() => { + setShowCreateModal(true); + }, []); + + const handleConfigureClick = useCallback( + async (domain: Domain) => { + setSelectedDomain(domain); + if (domain.status !== 'verified') { + setShowVerifyModal(true); + } else { + try { + await fetchProviders(domain); + setShowConfigureModal(true); + } catch (error) { + handleError(error, { + fallbackMessage: t('domain_table.notifications.fetch_providers_error'), + }); + } } - await coreClient! - .getMyOrganizationApiClient() - .organization.identityProviders.domains.delete(provider.id!, domain.domain); }, - onSuccess: (_, { domain, provider }) => { - deleteFromProviderAction?.onAfter?.(domain, provider); - queryClient.invalidateQueries({ queryKey: domainQueryKeys.providers(domain.id) }); + [fetchProviders, t, handleError], + ); + + const handleVerifyClick = useCallback( + async (domain: Domain) => { + setSelectedDomain(domain); + try { + const isVerified = await onVerifyDomain(domain); + if (isVerified) { + await fetchProviders(domain); + setShowConfigureModal(true); + showToast({ + type: 'success', + message: t('domain_table.notifications.domain_verify.success', { + domainName: domain.domain, + }), + }); + } else { + showToast({ + type: 'error', + message: t('domain_table.notifications.domain_verify.verification_failed', { + domainName: domain.domain, + }), + }); + } + } catch (error) { + handleError(error, { + fallbackMessage: t('domain_table.notifications.domain_verify.error'), + }); + } }, - }); + [onVerifyDomain, fetchProviders, t, handleError], + ); - return { - domains: domainsQuery.data ?? [], - providers: providersQuery.data ?? [], - isFetching: domainsQuery.isLoading, - isCreating: createDomainMutation.isPending, - isDeleting: deleteDomainMutation.isPending, - isVerifying: verifyDomainMutation.isPending, - isLoadingProviders: providersQuery.isLoading, - fetchProviders: async (domain: Domain) => { - setSelectedDomainId(domain.id); - setSelectedDomainName(domain.domain); - await queryClient.ensureQueryData({ - queryKey: domainQueryKeys.providers(domain.id), - queryFn: () => fetchProvidersForDomain(domain.domain), + const handleDeleteClick = useCallback((domain: Domain) => { + setSelectedDomain(domain); + setShowVerifyModal(false); + setShowDeleteModal(true); + }, []); + + useEffect(() => { + try { + fetchDomains(); + } catch (error) { + handleError(error, { + fallbackMessage: t('domain_table.notifications.fetch_domains_error'), }); - }, - fetchDomains: async () => { - await queryClient.getQueryData(domainQueryKeys.list()); - }, - onCreateDomain: (data) => createDomainMutation.mutateAsync(data), - onVerifyDomain: (domain) => verifyDomainMutation.mutateAsync(domain), - onDeleteDomain: (domain) => deleteDomainMutation.mutateAsync(domain), - onAssociateToProvider: (domain, provider) => - associateToProviderMutation.mutateAsync({ domain, provider }), - onDeleteFromProvider: (domain, provider) => - deleteFromProviderMutation.mutateAsync({ domain, provider }), + } + }, []); + + return { + // Data + domains, + providers, + + // Loading states + isFetching, + isCreating, + isDeleting, + isVerifying, + isLoadingProviders, + + // Modal state + showCreateModal, + showConfigureModal, + showVerifyModal, + showDeleteModal, + verifyError, + selectedDomain, + + // State setters + setShowCreateModal, + setShowConfigureModal, + setShowVerifyModal, + setShowDeleteModal, + + // Handlers + handleCreate, + handleVerify, + handleDelete, + handleToggleSwitch, + handleCloseVerifyModal, + handleCreateClick, + handleConfigureClick, + handleVerifyClick, + handleDeleteClick, }; } diff --git a/packages/react/src/tests/utils/__mocks__/my-organization/domain-management/domain.mocks.ts b/packages/react/src/tests/utils/__mocks__/my-organization/domain-management/domain.mocks.ts index d4baa2733..208276cd1 100644 --- a/packages/react/src/tests/utils/__mocks__/my-organization/domain-management/domain.mocks.ts +++ b/packages/react/src/tests/utils/__mocks__/my-organization/domain-management/domain.mocks.ts @@ -8,8 +8,7 @@ import { vi } from 'vitest'; import type { DomainTableProps, - UseDomainTableLogicOptions, - UseDomainTableResult, + UseDomainTableReturn, } from '@/types/my-organization/domain-management/domain-table-types'; export const createMockDomain = (overrides?: Partial): Domain => ({ @@ -68,7 +67,6 @@ export const createMockIdentityProviderAssociatedWithDomain = ( export const createMockIdentityProviderWithoutProvisioning = ( overrides: Partial = {}, ): IdpKnownResponse => { - // Use a strategy that doesn't have provisioning enabled by default const baseProvider = { id: 'con_abc123xyz456', name: 'mock-provider-no-provisioning', @@ -119,9 +117,9 @@ export const createMockDeleteAction = (): ComponentAction => ({ onAfter: vi.fn(), }); -export const createMockLogic = ( - overrides: Partial = {}, -) => ({ +export const createMockDomainTableReturn = ( + overrides: Partial = {}, +): UseDomainTableReturn => ({ domains: [createMockDomain(), createMockVerifiedDomain()], providers: [], isCreating: false, @@ -129,25 +127,6 @@ export const createMockLogic = ( isFetching: false, isLoadingProviders: false, isDeleting: false, - schema: undefined, - styling: { variables: { common: {}, light: {}, dark: {} }, classes: {} }, - hideHeader: false, - readOnly: false, - customMessages: {}, - createAction: undefined, - onOpenProvider: undefined, - onCreateProvider: undefined, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - ...overrides, -}); - -export const createMockApi = (overrides: Partial = {}) => ({ showCreateModal: false, showConfigureModal: false, showVerifyModal: false, @@ -156,8 +135,8 @@ export const createMockApi = (overrides: Partial = { selectedDomain: null, setShowCreateModal: vi.fn(), setShowConfigureModal: vi.fn(), - setShowDeleteModal: vi.fn(), setShowVerifyModal: vi.fn(), + setShowDeleteModal: vi.fn(), handleCreate: vi.fn(), handleVerify: vi.fn(), handleDelete: vi.fn(), diff --git a/packages/react/src/types/my-organization/domain-management/domain-table-types.ts b/packages/react/src/types/my-organization/domain-management/domain-table-types.ts index e7aa84bb4..0a27ed961 100644 --- a/packages/react/src/types/my-organization/domain-management/domain-table-types.ts +++ b/packages/react/src/types/my-organization/domain-management/domain-table-types.ts @@ -15,9 +15,9 @@ import type { DomainVerifyMessages, DomainTableMessages, CreateOrganizationDomainRequestContent, - EnhancedTranslationFunction, IdentityProviderAssociatedWithDomain, } from '@auth0/universal-components-core'; +import type React from 'react'; export type { Domain }; @@ -56,12 +56,6 @@ export interface DomainTableProps onCreateProvider?: () => void; } -// DomainTableView component props -export interface DomainTableViewProps { - logic: UseDomainTableResult & DomainTableProps; - handlers: UseDomainTableLogicResult; -} - /** Props for DomainTable actions column. */ export interface DomainTableActionsColumnProps { customMessages?: Partial; @@ -73,6 +67,17 @@ export interface DomainTableActionsColumnProps { onDelete: (domain: Domain) => void; } +/** Options for the internal domain table service hook. */ +export interface UseDomainTableServiceOptions { + createAction?: DomainTableProps['createAction']; + verifyAction?: DomainTableProps['verifyAction']; + deleteAction?: DomainTableProps['deleteAction']; + associateToProviderAction?: DomainTableProps['associateToProviderAction']; + deleteFromProviderAction?: DomainTableProps['deleteFromProviderAction']; + customMessages?: DomainTableProps['customMessages']; +} + +/** Options for the public domain table hook. */ export interface UseDomainTableOptions { createAction?: DomainTableProps['createAction']; verifyAction?: DomainTableProps['verifyAction']; @@ -82,7 +87,8 @@ export interface UseDomainTableOptions { customMessages?: DomainTableProps['customMessages']; } -export interface UseDomainTableResult extends SharedComponentProps { +/** Return type for the internal domain table service hook. */ +export interface UseDomainTableServiceReturn { domains: Domain[]; providers: IdentityProviderAssociatedWithDomain[]; isFetching: boolean; @@ -92,25 +98,26 @@ export interface UseDomainTableResult extends SharedComponentProps { isVerifying: boolean; fetchProviders: (domain: Domain) => Promise; fetchDomains: () => Promise; - onCreateDomain: (data: CreateOrganizationDomainRequestContent) => Promise; - onVerifyDomain: (data: Domain) => Promise; + onCreateDomain: (data: CreateOrganizationDomainRequestContent) => Promise; + onVerifyDomain: (domain: Domain) => Promise; onDeleteDomain: (domain: Domain) => Promise; onAssociateToProvider: (domain: Domain, provider: IdpKnownResponse) => Promise; onDeleteFromProvider: (domain: Domain, provider: IdpKnownResponse) => Promise; } -export interface UseDomainTableLogicOptions { - t: EnhancedTranslationFunction; - onCreateDomain: UseDomainTableResult['onCreateDomain']; - onVerifyDomain: UseDomainTableResult['onVerifyDomain']; - onDeleteDomain: UseDomainTableResult['onDeleteDomain']; - onAssociateToProvider: UseDomainTableResult['onAssociateToProvider']; - onDeleteFromProvider: UseDomainTableResult['onDeleteFromProvider']; - fetchProviders: UseDomainTableResult['fetchProviders']; - fetchDomains: UseDomainTableResult['fetchDomains']; -} +/** Return type for the public domain table hook. */ +export interface UseDomainTableReturn { + // Data + domains: Domain[]; + providers: IdentityProviderAssociatedWithDomain[]; + + // Loading states + isFetching: boolean; + isCreating: boolean; + isDeleting: boolean; + isVerifying: boolean; + isLoadingProviders: boolean; -export interface UseDomainTableLogicResult { // Modal state showCreateModal: boolean; showConfigureModal: boolean; @@ -120,15 +127,15 @@ export interface UseDomainTableLogicResult { selectedDomain: Domain | null; // State setters - setShowCreateModal: (show: boolean) => void; - setShowConfigureModal: (show: boolean) => void; - setShowVerifyModal: (show: boolean) => void; - setShowDeleteModal: (show: boolean) => void; + setShowCreateModal: React.Dispatch>; + setShowConfigureModal: React.Dispatch>; + setShowVerifyModal: React.Dispatch>; + setShowDeleteModal: React.Dispatch>; // Handlers handleCreate: (domainUrl: string) => Promise; handleVerify: (domain: Domain) => Promise; - handleDelete: (domain: Domain) => void; + handleDelete: (domain: Domain) => Promise; handleToggleSwitch: (domain: Domain, provider: IdpKnownResponse, checked: boolean) => void; handleCloseVerifyModal: () => void; handleCreateClick: () => void; From acc05c53fab4ccea95d71a49d39da4008f635945 Mon Sep 17 00:00:00 2001 From: harish-sundar_akto Date: Mon, 25 May 2026 11:11:40 +0530 Subject: [PATCH 2/5] test: add coverage for public use-domain-table hook --- .../__tests__/use-domain-table.test.ts | 428 ++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts diff --git a/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts b/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts new file mode 100644 index 000000000..ee5ec8964 --- /dev/null +++ b/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts @@ -0,0 +1,428 @@ +import { renderHook, act } from '@testing-library/react'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +import { useDomainTable } from '../use-domain-table'; + +import { showToast } from '@/components/auth0/shared/toast'; +import { useErrorHandler } from '@/hooks/shared/use-error-handler'; +import { createMockDomain, createMockIdentityProvider } from '@/tests/utils'; + +vi.mock('@/hooks/shared/use-translator', () => ({ + useTranslator: () => ({ t: (key: string) => key }), +})); + +const mockHandleError = vi.fn(); +vi.mock('@/hooks/shared/use-error-handler', () => ({ + useErrorHandler: () => mockHandleError, +})); + +vi.mock('@/components/auth0/shared/toast', () => ({ + showToast: vi.fn(), +})); + +const mockService = { + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), +}; + +vi.mock('@/hooks/my-organization/shared/services/use-domain-table-service', () => ({ + useDomainTableService: () => mockService, +})); + +describe('useDomainTable', () => { + const defaultOptions = { + createAction: { onBefore: vi.fn(() => true), onAfter: vi.fn() }, + deleteAction: { onBefore: vi.fn(() => true), onAfter: vi.fn() }, + verifyAction: { onBefore: vi.fn(() => true), onAfter: vi.fn() }, + associateToProviderAction: { onBefore: vi.fn(() => true), onAfter: vi.fn() }, + deleteFromProviderAction: { onBefore: vi.fn(() => true), onAfter: vi.fn() }, + customMessages: {}, + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe('Initial State', () => { + it('should return correct initial state', () => { + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + expect(result.current.showCreateModal).toBe(false); + expect(result.current.showConfigureModal).toBe(false); + expect(result.current.showVerifyModal).toBe(false); + expect(result.current.showDeleteModal).toBe(false); + expect(result.current.verifyError).toBeUndefined(); + expect(result.current.selectedDomain).toBeNull(); + expect(result.current.domains).toEqual([]); + expect(result.current.providers).toEqual([]); + }); + + it('should call fetchDomains on mount', () => { + renderHook(() => useDomainTable(defaultOptions)); + expect(mockService.fetchDomains).toHaveBeenCalledTimes(1); + }); + }); + + describe('handleCreateClick', () => { + it('should show create modal', () => { + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + act(() => { + result.current.handleCreateClick(); + }); + + expect(result.current.showCreateModal).toBe(true); + }); + }); + + describe('handleCreate', () => { + it('should create domain, show toast, and open verify modal', async () => { + const mockDomain = createMockDomain({ domain: 'test.com' }); + mockService.onCreateDomain.mockResolvedValue(mockDomain); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleCreate('test.com'); + }); + + expect(mockService.onCreateDomain).toHaveBeenCalledWith({ domain: 'test.com' }); + expect(showToast).toHaveBeenCalledWith({ + type: 'success', + message: 'domain_table.notifications.domain_create.success', + }); + expect(result.current.selectedDomain).toEqual(mockDomain); + expect(result.current.showCreateModal).toBe(false); + expect(result.current.showVerifyModal).toBe(true); + }); + + it('should handle create error', async () => { + const error = new Error('Create failed'); + mockService.onCreateDomain.mockRejectedValue(error); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleCreate('test.com'); + }); + + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_create.error', + }); + }); + }); + + describe('handleVerify', () => { + it('should verify domain successfully and close verify modal', async () => { + const mockDomain = createMockDomain(); + mockService.onVerifyDomain.mockResolvedValue(true); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleVerify(mockDomain); + }); + + expect(result.current.showVerifyModal).toBe(false); + expect(showToast).toHaveBeenCalledWith({ + type: 'success', + message: 'domain_table.notifications.domain_verify.success', + }); + }); + + it('should set verify error on verification failure', async () => { + const mockDomain = createMockDomain({ domain: 'test.com' }); + mockService.onVerifyDomain.mockResolvedValue(false); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleVerify(mockDomain); + }); + + expect(result.current.verifyError).toBe('domain_verify.modal.errors.verification_failed'); + }); + + it('should handle verify error', async () => { + const mockDomain = createMockDomain(); + const error = new Error('Verify failed'); + mockService.onVerifyDomain.mockRejectedValue(error); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleVerify(mockDomain); + }); + + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_verify.error', + }); + }); + }); + + describe('handleDelete', () => { + it('should delete domain and close modals', async () => { + const mockDomain = createMockDomain({ domain: 'test.com' }); + mockService.onDeleteDomain.mockResolvedValue(undefined); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleDelete(mockDomain); + }); + + expect(mockService.onDeleteDomain).toHaveBeenCalledWith(mockDomain); + expect(showToast).toHaveBeenCalledWith({ + type: 'success', + message: 'domain_table.notifications.domain_delete.success', + }); + expect(result.current.showDeleteModal).toBe(false); + expect(result.current.showVerifyModal).toBe(false); + }); + + it('should handle delete error', async () => { + const mockDomain = createMockDomain(); + const error = new Error('Delete failed'); + mockService.onDeleteDomain.mockRejectedValue(error); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleDelete(mockDomain); + }); + + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_delete.error', + }); + }); + }); + + describe('handleToggleSwitch', () => { + it('should associate domain to provider when checked is true', async () => { + const mockDomain = createMockDomain({ domain: 'test.com' }); + const mockProvider = createMockIdentityProvider({ name: 'TestIDP' }); + mockService.onAssociateToProvider.mockResolvedValue(undefined); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleToggleSwitch(mockDomain, mockProvider, true); + }); + + expect(mockService.onAssociateToProvider).toHaveBeenCalledWith(mockDomain, mockProvider); + expect(showToast).toHaveBeenCalledWith({ + type: 'success', + message: 'domain_table.notifications.domain_associate_provider.success', + }); + }); + + it('should delete domain from provider when checked is false', async () => { + const mockDomain = createMockDomain({ domain: 'test.com' }); + const mockProvider = createMockIdentityProvider({ name: 'TestIDP' }); + mockService.onDeleteFromProvider.mockResolvedValue(undefined); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleToggleSwitch(mockDomain, mockProvider, false); + }); + + expect(mockService.onDeleteFromProvider).toHaveBeenCalledWith(mockDomain, mockProvider); + expect(showToast).toHaveBeenCalledWith({ + type: 'success', + message: 'domain_table.notifications.domain_delete_provider.success', + }); + }); + + it('should handle associate to provider error', async () => { + const mockDomain = createMockDomain(); + const mockProvider = createMockIdentityProvider(); + const error = new Error('Associate failed'); + mockService.onAssociateToProvider.mockRejectedValue(error); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleToggleSwitch(mockDomain, mockProvider, true); + }); + + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_associate_provider.error', + }); + }); + + it('should handle delete from provider error', async () => { + const mockDomain = createMockDomain(); + const mockProvider = createMockIdentityProvider(); + const error = new Error('Delete from provider failed'); + mockService.onDeleteFromProvider.mockRejectedValue(error); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleToggleSwitch(mockDomain, mockProvider, false); + }); + + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_delete_provider.error', + }); + }); + }); + + describe('handleCloseVerifyModal', () => { + it('should close verify modal and clear verify error', async () => { + const mockDomain = createMockDomain(); + mockService.onVerifyDomain.mockResolvedValue(false); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + // Trigger verify error + await act(async () => { + await result.current.handleVerify(mockDomain); + }); + expect(result.current.verifyError).toBeDefined(); + + // Close modal + act(() => { + result.current.handleCloseVerifyModal(); + }); + + expect(result.current.showVerifyModal).toBe(false); + expect(result.current.verifyError).toBeUndefined(); + }); + }); + + describe('handleConfigureClick', () => { + it('should show verify modal for unverified domain', async () => { + const mockDomain = createMockDomain({ status: 'pending' }); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleConfigureClick(mockDomain); + }); + + expect(result.current.selectedDomain).toEqual(mockDomain); + expect(result.current.showVerifyModal).toBe(true); + }); + + it('should fetch providers and show configure modal for verified domain', async () => { + const mockDomain = createMockDomain({ status: 'verified' }); + mockService.fetchProviders.mockResolvedValue(undefined); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleConfigureClick(mockDomain); + }); + + expect(result.current.selectedDomain).toEqual(mockDomain); + expect(mockService.fetchProviders).toHaveBeenCalledWith(mockDomain); + expect(result.current.showConfigureModal).toBe(true); + }); + + it('should handle fetchProviders error for verified domain', async () => { + const mockDomain = createMockDomain({ status: 'verified' }); + const error = new Error('Fetch providers failed'); + mockService.fetchProviders.mockRejectedValue(error); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleConfigureClick(mockDomain); + }); + + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.fetch_providers_error', + }); + }); + }); + + describe('handleVerifyClick', () => { + it('should verify, fetch providers, and show configure modal on success', async () => { + const mockDomain = createMockDomain({ domain: 'test.com' }); + mockService.onVerifyDomain.mockResolvedValue(true); + mockService.fetchProviders.mockResolvedValue(undefined); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleVerifyClick(mockDomain); + }); + + expect(result.current.selectedDomain).toEqual(mockDomain); + expect(mockService.onVerifyDomain).toHaveBeenCalledWith(mockDomain); + expect(mockService.fetchProviders).toHaveBeenCalledWith(mockDomain); + expect(result.current.showConfigureModal).toBe(true); + expect(showToast).toHaveBeenCalledWith({ + type: 'success', + message: 'domain_table.notifications.domain_verify.success', + }); + }); + + it('should show error toast on verification failure', async () => { + const mockDomain = createMockDomain({ domain: 'test.com' }); + mockService.onVerifyDomain.mockResolvedValue(false); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleVerifyClick(mockDomain); + }); + + expect(showToast).toHaveBeenCalledWith({ + type: 'error', + message: 'domain_table.notifications.domain_verify.verification_failed', + }); + }); + + it('should handle verify click error', async () => { + const mockDomain = createMockDomain(); + const error = new Error('Verify click failed'); + mockService.onVerifyDomain.mockRejectedValue(error); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + await act(async () => { + await result.current.handleVerifyClick(mockDomain); + }); + + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_verify.error', + }); + }); + }); + + describe('handleDeleteClick', () => { + it('should set selected domain, close verify modal, and show delete modal', () => { + const mockDomain = createMockDomain(); + + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + // Open verify modal first + act(() => { + result.current.setShowVerifyModal(true); + }); + + act(() => { + result.current.handleDeleteClick(mockDomain); + }); + + expect(result.current.selectedDomain).toEqual(mockDomain); + expect(result.current.showVerifyModal).toBe(false); + expect(result.current.showDeleteModal).toBe(true); + }); + }); +}); From 0ca2e35115c2b308385de3d7149dda1d6d8b7b3a Mon Sep 17 00:00:00 2001 From: harish-sundar_akto Date: Mon, 25 May 2026 11:22:51 +0530 Subject: [PATCH 3/5] fix: resolve type error in domain table test mock provider --- .../__tests__/use-domain-table.test.ts | 861 ++++++++++++------ 1 file changed, 573 insertions(+), 288 deletions(-) diff --git a/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts b/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts index ee5ec8964..1e5c22b2b 100644 --- a/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts +++ b/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts @@ -3,15 +3,12 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { useDomainTable } from '../use-domain-table'; -import { showToast } from '@/components/auth0/shared/toast'; -import { useErrorHandler } from '@/hooks/shared/use-error-handler'; -import { createMockDomain, createMockIdentityProvider } from '@/tests/utils'; +const mockHandleError = vi.fn(); vi.mock('@/hooks/shared/use-translator', () => ({ useTranslator: () => ({ t: (key: string) => key }), })); -const mockHandleError = vi.fn(); vi.mock('@/hooks/shared/use-error-handler', () => ({ useErrorHandler: () => mockHandleError, })); @@ -20,28 +17,45 @@ vi.mock('@/components/auth0/shared/toast', () => ({ showToast: vi.fn(), })); -const mockService = { - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), -}; - vi.mock('@/hooks/my-organization/shared/services/use-domain-table-service', () => ({ - useDomainTableService: () => mockService, + useDomainTableService: vi.fn(() => ({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + })), })); describe('useDomainTable', () => { + const mockDomain = { + id: 'domain_abc123', + org_id: 'org_123', + domain: 'test.com', + status: 'pending' as const, + verification_txt: 'txt', + verification_host: 'host', + }; + + const verifiedDomain = { ...mockDomain, status: 'verified' as const }; + + const mockProvider = { + id: 'con_abc123', + name: 'TestIDP', + display_name: 'Test IDP', + options: {}, + strategy: 'waad' as const, + }; + const defaultOptions = { createAction: { onBefore: vi.fn(() => true), onAfter: vi.fn() }, deleteAction: { onBefore: vi.fn(() => true), onAfter: vi.fn() }, @@ -55,374 +69,645 @@ describe('useDomainTable', () => { vi.clearAllMocks(); }); - describe('Initial State', () => { - it('should return correct initial state', () => { - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should return correct initial state', () => { + const { result } = renderHook(() => useDomainTable(defaultOptions)); + + expect(result.current.showCreateModal).toBe(false); + expect(result.current.showConfigureModal).toBe(false); + expect(result.current.showVerifyModal).toBe(false); + expect(result.current.showDeleteModal).toBe(false); + expect(result.current.verifyError).toBeUndefined(); + expect(result.current.selectedDomain).toBeNull(); + expect(result.current.domains).toEqual([]); + expect(result.current.providers).toEqual([]); + }); - expect(result.current.showCreateModal).toBe(false); - expect(result.current.showConfigureModal).toBe(false); - expect(result.current.showVerifyModal).toBe(false); - expect(result.current.showDeleteModal).toBe(false); - expect(result.current.verifyError).toBeUndefined(); - expect(result.current.selectedDomain).toBeNull(); - expect(result.current.domains).toEqual([]); - expect(result.current.providers).toEqual([]); + it('should call fetchDomains on mount', async () => { + const mockFetchDomains = vi.fn(); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: mockFetchDomains, + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), }); - it('should call fetchDomains on mount', () => { - renderHook(() => useDomainTable(defaultOptions)); - expect(mockService.fetchDomains).toHaveBeenCalledTimes(1); - }); + renderHook(() => useDomainTable(defaultOptions)); + expect(mockFetchDomains).toHaveBeenCalledTimes(1); }); - describe('handleCreateClick', () => { - it('should show create modal', () => { - const { result } = renderHook(() => useDomainTable(defaultOptions)); - - act(() => { - result.current.handleCreateClick(); - }); + it('should show create modal on handleCreateClick', () => { + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(result.current.showCreateModal).toBe(true); + act(() => { + result.current.handleCreateClick(); }); - }); - describe('handleCreate', () => { - it('should create domain, show toast, and open verify modal', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - mockService.onCreateDomain.mockResolvedValue(mockDomain); + expect(result.current.showCreateModal).toBe(true); + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should create domain, show toast, and open verify modal on handleCreate', async () => { + const mockOnCreateDomain = vi.fn().mockResolvedValue(mockDomain); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: mockOnCreateDomain, + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + }); - await act(async () => { - await result.current.handleCreate('test.com'); - }); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(mockService.onCreateDomain).toHaveBeenCalledWith({ domain: 'test.com' }); - expect(showToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_create.success', - }); - expect(result.current.selectedDomain).toEqual(mockDomain); - expect(result.current.showCreateModal).toBe(false); - expect(result.current.showVerifyModal).toBe(true); + await act(async () => { + await result.current.handleCreate('test.com'); }); - it('should handle create error', async () => { - const error = new Error('Create failed'); - mockService.onCreateDomain.mockRejectedValue(error); + expect(mockOnCreateDomain).toHaveBeenCalledWith({ domain: 'test.com' }); + expect(result.current.selectedDomain).toEqual(mockDomain); + expect(result.current.showCreateModal).toBe(false); + expect(result.current.showVerifyModal).toBe(true); + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should handle create error on handleCreate', async () => { + const error = new Error('Create failed'); + const mockOnCreateDomain = vi.fn().mockRejectedValue(error); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: mockOnCreateDomain, + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + }); - await act(async () => { - await result.current.handleCreate('test.com'); - }); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_create.error', - }); + await act(async () => { + await result.current.handleCreate('test.com'); }); - }); - describe('handleVerify', () => { - it('should verify domain successfully and close verify modal', async () => { - const mockDomain = createMockDomain(); - mockService.onVerifyDomain.mockResolvedValue(true); + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_create.error', + }); + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should verify domain and close verify modal on handleVerify success', async () => { + const mockOnVerifyDomain = vi.fn().mockResolvedValue(true); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: mockOnVerifyDomain, + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + }); - await act(async () => { - await result.current.handleVerify(mockDomain); - }); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(result.current.showVerifyModal).toBe(false); - expect(showToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_verify.success', - }); + await act(async () => { + await result.current.handleVerify(mockDomain); }); - it('should set verify error on verification failure', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - mockService.onVerifyDomain.mockResolvedValue(false); + expect(mockOnVerifyDomain).toHaveBeenCalledWith(mockDomain); + expect(result.current.showVerifyModal).toBe(false); + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should set verify error on handleVerify failure', async () => { + const mockOnVerifyDomain = vi.fn().mockResolvedValue(false); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: mockOnVerifyDomain, + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + }); - await act(async () => { - await result.current.handleVerify(mockDomain); - }); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(result.current.verifyError).toBe('domain_verify.modal.errors.verification_failed'); + await act(async () => { + await result.current.handleVerify(mockDomain); }); - it('should handle verify error', async () => { - const mockDomain = createMockDomain(); - const error = new Error('Verify failed'); - mockService.onVerifyDomain.mockRejectedValue(error); + expect(result.current.verifyError).toBe('domain_verify.modal.errors.verification_failed'); + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should handle verify error on handleVerify', async () => { + const error = new Error('Verify failed'); + const mockOnVerifyDomain = vi.fn().mockRejectedValue(error); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: mockOnVerifyDomain, + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + }); - await act(async () => { - await result.current.handleVerify(mockDomain); - }); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_verify.error', - }); + await act(async () => { + await result.current.handleVerify(mockDomain); }); - }); - describe('handleDelete', () => { - it('should delete domain and close modals', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - mockService.onDeleteDomain.mockResolvedValue(undefined); + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_verify.error', + }); + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should delete domain and close modals on handleDelete', async () => { + const mockOnDeleteDomain = vi.fn().mockResolvedValue(undefined); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: mockOnDeleteDomain, + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + }); - await act(async () => { - await result.current.handleDelete(mockDomain); - }); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(mockService.onDeleteDomain).toHaveBeenCalledWith(mockDomain); - expect(showToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_delete.success', - }); - expect(result.current.showDeleteModal).toBe(false); - expect(result.current.showVerifyModal).toBe(false); + await act(async () => { + await result.current.handleDelete(mockDomain); }); - it('should handle delete error', async () => { - const mockDomain = createMockDomain(); - const error = new Error('Delete failed'); - mockService.onDeleteDomain.mockRejectedValue(error); + expect(mockOnDeleteDomain).toHaveBeenCalledWith(mockDomain); + expect(result.current.showDeleteModal).toBe(false); + expect(result.current.showVerifyModal).toBe(false); + }); + + it('should handle delete error on handleDelete', async () => { + const error = new Error('Delete failed'); + const mockOnDeleteDomain = vi.fn().mockRejectedValue(error); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: mockOnDeleteDomain, + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - await act(async () => { - await result.current.handleDelete(mockDomain); - }); + await act(async () => { + await result.current.handleDelete(mockDomain); + }); - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_delete.error', - }); + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_delete.error', }); }); - describe('handleToggleSwitch', () => { - it('should associate domain to provider when checked is true', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - const mockProvider = createMockIdentityProvider({ name: 'TestIDP' }); - mockService.onAssociateToProvider.mockResolvedValue(undefined); - - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should associate domain to provider on handleToggleSwitch with true', async () => { + const mockOnAssociateToProvider = vi.fn().mockResolvedValue(undefined); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: mockOnAssociateToProvider, + onDeleteFromProvider: vi.fn(), + }); - await act(async () => { - await result.current.handleToggleSwitch(mockDomain, mockProvider, true); - }); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(mockService.onAssociateToProvider).toHaveBeenCalledWith(mockDomain, mockProvider); - expect(showToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_associate_provider.success', - }); + await act(async () => { + await result.current.handleToggleSwitch(mockDomain, mockProvider, true); }); - it('should delete domain from provider when checked is false', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - const mockProvider = createMockIdentityProvider({ name: 'TestIDP' }); - mockService.onDeleteFromProvider.mockResolvedValue(undefined); + expect(mockOnAssociateToProvider).toHaveBeenCalledWith(mockDomain, mockProvider); + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should delete domain from provider on handleToggleSwitch with false', async () => { + const mockOnDeleteFromProvider = vi.fn().mockResolvedValue(undefined); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: mockOnDeleteFromProvider, + }); - await act(async () => { - await result.current.handleToggleSwitch(mockDomain, mockProvider, false); - }); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(mockService.onDeleteFromProvider).toHaveBeenCalledWith(mockDomain, mockProvider); - expect(showToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_delete_provider.success', - }); + await act(async () => { + await result.current.handleToggleSwitch(mockDomain, mockProvider, false); }); - it('should handle associate to provider error', async () => { - const mockDomain = createMockDomain(); - const mockProvider = createMockIdentityProvider(); - const error = new Error('Associate failed'); - mockService.onAssociateToProvider.mockRejectedValue(error); + expect(mockOnDeleteFromProvider).toHaveBeenCalledWith(mockDomain, mockProvider); + }); + + it('should handle associate to provider error on handleToggleSwitch', async () => { + const error = new Error('Associate failed'); + const mockOnAssociateToProvider = vi.fn().mockRejectedValue(error); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: mockOnAssociateToProvider, + onDeleteFromProvider: vi.fn(), + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - await act(async () => { - await result.current.handleToggleSwitch(mockDomain, mockProvider, true); - }); + await act(async () => { + await result.current.handleToggleSwitch(mockDomain, mockProvider, true); + }); - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_associate_provider.error', - }); + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_associate_provider.error', }); + }); - it('should handle delete from provider error', async () => { - const mockDomain = createMockDomain(); - const mockProvider = createMockIdentityProvider(); - const error = new Error('Delete from provider failed'); - mockService.onDeleteFromProvider.mockRejectedValue(error); + it('should handle delete from provider error on handleToggleSwitch', async () => { + const error = new Error('Delete from provider failed'); + const mockOnDeleteFromProvider = vi.fn().mockRejectedValue(error); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: mockOnDeleteFromProvider, + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - await act(async () => { - await result.current.handleToggleSwitch(mockDomain, mockProvider, false); - }); + await act(async () => { + await result.current.handleToggleSwitch(mockDomain, mockProvider, false); + }); - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_delete_provider.error', - }); + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_delete_provider.error', }); }); - describe('handleCloseVerifyModal', () => { - it('should close verify modal and clear verify error', async () => { - const mockDomain = createMockDomain(); - mockService.onVerifyDomain.mockResolvedValue(false); - - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should close verify modal and clear error on handleCloseVerifyModal', async () => { + const mockOnVerifyDomain = vi.fn().mockResolvedValue(false); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: mockOnVerifyDomain, + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + }); - // Trigger verify error - await act(async () => { - await result.current.handleVerify(mockDomain); - }); - expect(result.current.verifyError).toBeDefined(); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - // Close modal - act(() => { - result.current.handleCloseVerifyModal(); - }); + await act(async () => { + await result.current.handleVerify(mockDomain); + }); + expect(result.current.verifyError).toBeDefined(); - expect(result.current.showVerifyModal).toBe(false); - expect(result.current.verifyError).toBeUndefined(); + act(() => { + result.current.handleCloseVerifyModal(); }); + + expect(result.current.showVerifyModal).toBe(false); + expect(result.current.verifyError).toBeUndefined(); }); - describe('handleConfigureClick', () => { - it('should show verify modal for unverified domain', async () => { - const mockDomain = createMockDomain({ status: 'pending' }); + it('should show verify modal for unverified domain on handleConfigureClick', async () => { + const { result } = renderHook(() => useDomainTable(defaultOptions)); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + await act(async () => { + await result.current.handleConfigureClick(mockDomain); + }); - await act(async () => { - await result.current.handleConfigureClick(mockDomain); - }); + expect(result.current.selectedDomain).toEqual(mockDomain); + expect(result.current.showVerifyModal).toBe(true); + }); - expect(result.current.selectedDomain).toEqual(mockDomain); - expect(result.current.showVerifyModal).toBe(true); + it('should fetch providers and show configure modal for verified domain on handleConfigureClick', async () => { + const mockFetchProviders = vi.fn().mockResolvedValue(undefined); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: mockFetchProviders, + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), }); - it('should fetch providers and show configure modal for verified domain', async () => { - const mockDomain = createMockDomain({ status: 'verified' }); - mockService.fetchProviders.mockResolvedValue(undefined); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + await act(async () => { + await result.current.handleConfigureClick(verifiedDomain); + }); - await act(async () => { - await result.current.handleConfigureClick(mockDomain); - }); + expect(result.current.selectedDomain).toEqual(verifiedDomain); + expect(mockFetchProviders).toHaveBeenCalledWith(verifiedDomain); + expect(result.current.showConfigureModal).toBe(true); + }); - expect(result.current.selectedDomain).toEqual(mockDomain); - expect(mockService.fetchProviders).toHaveBeenCalledWith(mockDomain); - expect(result.current.showConfigureModal).toBe(true); + it('should handle fetchProviders error on handleConfigureClick', async () => { + const error = new Error('Fetch providers failed'); + const mockFetchProviders = vi.fn().mockRejectedValue(error); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: mockFetchProviders, + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), }); - it('should handle fetchProviders error for verified domain', async () => { - const mockDomain = createMockDomain({ status: 'verified' }); - const error = new Error('Fetch providers failed'); - mockService.fetchProviders.mockRejectedValue(error); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - const { result } = renderHook(() => useDomainTable(defaultOptions)); - - await act(async () => { - await result.current.handleConfigureClick(mockDomain); - }); + await act(async () => { + await result.current.handleConfigureClick(verifiedDomain); + }); - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.fetch_providers_error', - }); + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.fetch_providers_error', }); }); - describe('handleVerifyClick', () => { - it('should verify, fetch providers, and show configure modal on success', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - mockService.onVerifyDomain.mockResolvedValue(true); - mockService.fetchProviders.mockResolvedValue(undefined); - - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should verify, fetch providers, and show configure modal on handleVerifyClick success', async () => { + const mockOnVerifyDomain = vi.fn().mockResolvedValue(true); + const mockFetchProviders = vi.fn().mockResolvedValue(undefined); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: mockFetchProviders, + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: mockOnVerifyDomain, + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + }); - await act(async () => { - await result.current.handleVerifyClick(mockDomain); - }); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(result.current.selectedDomain).toEqual(mockDomain); - expect(mockService.onVerifyDomain).toHaveBeenCalledWith(mockDomain); - expect(mockService.fetchProviders).toHaveBeenCalledWith(mockDomain); - expect(result.current.showConfigureModal).toBe(true); - expect(showToast).toHaveBeenCalledWith({ - type: 'success', - message: 'domain_table.notifications.domain_verify.success', - }); + await act(async () => { + await result.current.handleVerifyClick(mockDomain); }); - it('should show error toast on verification failure', async () => { - const mockDomain = createMockDomain({ domain: 'test.com' }); - mockService.onVerifyDomain.mockResolvedValue(false); + expect(result.current.selectedDomain).toEqual(mockDomain); + expect(mockOnVerifyDomain).toHaveBeenCalledWith(mockDomain); + expect(mockFetchProviders).toHaveBeenCalledWith(mockDomain); + expect(result.current.showConfigureModal).toBe(true); + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should show error toast on handleVerifyClick failure', async () => { + const mockOnVerifyDomain = vi.fn().mockResolvedValue(false); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: mockOnVerifyDomain, + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + }); - await act(async () => { - await result.current.handleVerifyClick(mockDomain); - }); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(showToast).toHaveBeenCalledWith({ - type: 'error', - message: 'domain_table.notifications.domain_verify.verification_failed', - }); + await act(async () => { + await result.current.handleVerifyClick(mockDomain); }); - it('should handle verify click error', async () => { - const mockDomain = createMockDomain(); - const error = new Error('Verify click failed'); - mockService.onVerifyDomain.mockRejectedValue(error); + expect(result.current.selectedDomain).toEqual(mockDomain); + }); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + it('should handle error on handleVerifyClick', async () => { + const error = new Error('Verify click failed'); + const mockOnVerifyDomain = vi.fn().mockRejectedValue(error); + const { useDomainTableService } = await import( + '@/hooks/my-organization/shared/services/use-domain-table-service' + ); + vi.mocked(useDomainTableService).mockReturnValue({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: mockOnVerifyDomain, + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + }); - await act(async () => { - await result.current.handleVerifyClick(mockDomain); - }); + const { result } = renderHook(() => useDomainTable(defaultOptions)); - expect(mockHandleError).toHaveBeenCalledWith(error, { - fallbackMessage: 'domain_table.notifications.domain_verify.error', - }); + await act(async () => { + await result.current.handleVerifyClick(mockDomain); }); - }); - - describe('handleDeleteClick', () => { - it('should set selected domain, close verify modal, and show delete modal', () => { - const mockDomain = createMockDomain(); - const { result } = renderHook(() => useDomainTable(defaultOptions)); + expect(mockHandleError).toHaveBeenCalledWith(error, { + fallbackMessage: 'domain_table.notifications.domain_verify.error', + }); + }); - // Open verify modal first - act(() => { - result.current.setShowVerifyModal(true); - }); + it('should set selected domain, close verify modal, and show delete modal on handleDeleteClick', () => { + const { result } = renderHook(() => useDomainTable(defaultOptions)); - act(() => { - result.current.handleDeleteClick(mockDomain); - }); + act(() => { + result.current.setShowVerifyModal(true); + }); - expect(result.current.selectedDomain).toEqual(mockDomain); - expect(result.current.showVerifyModal).toBe(false); - expect(result.current.showDeleteModal).toBe(true); + act(() => { + result.current.handleDeleteClick(mockDomain); }); + + expect(result.current.selectedDomain).toEqual(mockDomain); + expect(result.current.showVerifyModal).toBe(false); + expect(result.current.showDeleteModal).toBe(true); }); }); From 4cef3309a1cf66c0529dbbb19fe2721650f17409 Mon Sep 17 00:00:00 2001 From: harish-sundar_akto Date: Tue, 26 May 2026 11:47:06 +0530 Subject: [PATCH 4/5] refactor(react): merge domain-table-logic into public hook --- .../auth0/my-organization/domain-table.tsx | 17 +++------- .../__tests__/use-domain-table.test.ts | 26 -------------- .../services/use-domain-table-service.ts | 2 +- .../hooks/my-organization/use-domain-table.ts | 13 +------ .../domain-management/domain-table-types.ts | 34 ++++++++++++------- 5 files changed, 29 insertions(+), 63 deletions(-) diff --git a/packages/react/src/components/auth0/my-organization/domain-table.tsx b/packages/react/src/components/auth0/my-organization/domain-table.tsx index 85f2955a6..97d3a6cb8 100644 --- a/packages/react/src/components/auth0/my-organization/domain-table.tsx +++ b/packages/react/src/components/auth0/my-organization/domain-table.tsx @@ -18,7 +18,10 @@ import { useDomainTable } from '@/hooks/my-organization/use-domain-table'; import { useTheme } from '@/hooks/shared/use-theme'; import { useTranslator } from '@/hooks/shared/use-translator'; import { getStatusBadgeVariant } from '@/lib/utils/my-organization/domain-management/domain-management-utils'; -import type { DomainTableProps } from '@/types/my-organization/domain-management/domain-table-types'; +import type { + DomainTableProps, + DomainTableViewProps, +} from '@/types/my-organization/domain-management/domain-table-types'; /** * DomainTable container component. @@ -84,17 +87,7 @@ function DomainTableView({ createAction, onOpenProvider, onCreateProvider, -}: { - domainTable: ReturnType; - schema: DomainTableProps['schema']; - styling: DomainTableProps['styling']; - hideHeader: DomainTableProps['hideHeader']; - readOnly: DomainTableProps['readOnly']; - customMessages: DomainTableProps['customMessages']; - createAction: DomainTableProps['createAction']; - onOpenProvider: DomainTableProps['onOpenProvider']; - onCreateProvider: DomainTableProps['onCreateProvider']; -}) { +}: DomainTableViewProps) { const { isDarkMode } = useTheme(); const { t } = useTranslator('domain_management', customMessages); diff --git a/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts b/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts index 1e5c22b2b..615ce5058 100644 --- a/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts +++ b/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts @@ -82,32 +82,6 @@ describe('useDomainTable', () => { expect(result.current.providers).toEqual([]); }); - it('should call fetchDomains on mount', async () => { - const mockFetchDomains = vi.fn(); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' - ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: mockFetchDomains, - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); - - renderHook(() => useDomainTable(defaultOptions)); - expect(mockFetchDomains).toHaveBeenCalledTimes(1); - }); - it('should show create modal on handleCreateClick', () => { const { result } = renderHook(() => useDomainTable(defaultOptions)); diff --git a/packages/react/src/hooks/my-organization/shared/services/use-domain-table-service.ts b/packages/react/src/hooks/my-organization/shared/services/use-domain-table-service.ts index 63d8cdaae..6c3023f65 100644 --- a/packages/react/src/hooks/my-organization/shared/services/use-domain-table-service.ts +++ b/packages/react/src/hooks/my-organization/shared/services/use-domain-table-service.ts @@ -22,7 +22,7 @@ import type { UseDomainTableServiceReturn, } from '@/types/my-organization/domain-management/domain-table-types'; -export const domainQueryKeys = { +const domainQueryKeys = { all: ['domains'] as const, list: () => [...domainQueryKeys.all, 'list'] as const, providers: (domainId: string) => [...domainQueryKeys.all, 'providers', domainId] as const, diff --git a/packages/react/src/hooks/my-organization/use-domain-table.ts b/packages/react/src/hooks/my-organization/use-domain-table.ts index 0d6cdc9f8..afc9b2f6d 100644 --- a/packages/react/src/hooks/my-organization/use-domain-table.ts +++ b/packages/react/src/hooks/my-organization/use-domain-table.ts @@ -5,7 +5,7 @@ */ import { type Domain, type IdpKnownResponse } from '@auth0/universal-components-core'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useState } from 'react'; import { showToast } from '@/components/auth0/shared/toast'; import { useDomainTableService } from '@/hooks/my-organization/shared/services/use-domain-table-service'; @@ -42,7 +42,6 @@ export function useDomainTable({ isVerifying, isLoadingProviders, fetchProviders, - fetchDomains, onCreateDomain, onVerifyDomain, onDeleteDomain, @@ -235,16 +234,6 @@ export function useDomainTable({ setShowDeleteModal(true); }, []); - useEffect(() => { - try { - fetchDomains(); - } catch (error) { - handleError(error, { - fallbackMessage: t('domain_table.notifications.fetch_domains_error'), - }); - } - }, []); - return { // Data domains, diff --git a/packages/react/src/types/my-organization/domain-management/domain-table-types.ts b/packages/react/src/types/my-organization/domain-management/domain-table-types.ts index 0a27ed961..e4da2d010 100644 --- a/packages/react/src/types/my-organization/domain-management/domain-table-types.ts +++ b/packages/react/src/types/my-organization/domain-management/domain-table-types.ts @@ -67,17 +67,7 @@ export interface DomainTableActionsColumnProps { onDelete: (domain: Domain) => void; } -/** Options for the internal domain table service hook. */ -export interface UseDomainTableServiceOptions { - createAction?: DomainTableProps['createAction']; - verifyAction?: DomainTableProps['verifyAction']; - deleteAction?: DomainTableProps['deleteAction']; - associateToProviderAction?: DomainTableProps['associateToProviderAction']; - deleteFromProviderAction?: DomainTableProps['deleteFromProviderAction']; - customMessages?: DomainTableProps['customMessages']; -} - -/** Options for the public domain table hook. */ +/** Options for domain table hooks (shared by service and public hook). */ export interface UseDomainTableOptions { createAction?: DomainTableProps['createAction']; verifyAction?: DomainTableProps['verifyAction']; @@ -87,6 +77,9 @@ export interface UseDomainTableOptions { customMessages?: DomainTableProps['customMessages']; } +/** @internal */ +export type UseDomainTableServiceOptions = UseDomainTableOptions; + /** Return type for the internal domain table service hook. */ export interface UseDomainTableServiceReturn { domains: Domain[]; @@ -136,10 +129,27 @@ export interface UseDomainTableReturn { handleCreate: (domainUrl: string) => Promise; handleVerify: (domain: Domain) => Promise; handleDelete: (domain: Domain) => Promise; - handleToggleSwitch: (domain: Domain, provider: IdpKnownResponse, checked: boolean) => void; + handleToggleSwitch: ( + domain: Domain, + provider: IdpKnownResponse, + checked: boolean, + ) => Promise; handleCloseVerifyModal: () => void; handleCreateClick: () => void; handleConfigureClick: (domain: Domain) => void; handleVerifyClick: (domain: Domain) => Promise; handleDeleteClick: (domain: Domain) => void; } + +/** Props for the DomainTableView presentational component. @internal */ +export interface DomainTableViewProps { + domainTable: UseDomainTableReturn; + schema: DomainTableProps['schema']; + styling: DomainTableProps['styling']; + hideHeader: DomainTableProps['hideHeader']; + readOnly: DomainTableProps['readOnly']; + customMessages: DomainTableProps['customMessages']; + createAction: DomainTableProps['createAction']; + onOpenProvider: DomainTableProps['onOpenProvider']; + onCreateProvider: DomainTableProps['onCreateProvider']; +} From 8edf58a697cfbe0ec118afb34f6a53a8b5853b7c Mon Sep 17 00:00:00 2001 From: harish-sundar_akto Date: Mon, 1 Jun 2026 10:42:18 +0530 Subject: [PATCH 5/5] refactor(react): extract domain table test mocks to shared mock file --- .../__tests__/use-domain-table.test.ts | 370 +++--------------- .../use-domain-table-service.test.ts | 56 +-- .../domain-management/domain.mocks.ts | 49 +++ 3 files changed, 106 insertions(+), 369 deletions(-) diff --git a/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts b/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts index 615ce5058..e80a5767c 100644 --- a/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts +++ b/packages/react/src/hooks/my-organization/__tests__/use-domain-table.test.ts @@ -3,6 +3,9 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { useDomainTable } from '../use-domain-table'; +import { useDomainTableService } from '@/hooks/my-organization/shared/services/use-domain-table-service'; +import { mockToast, createMockDomainTableServiceReturn } from '@/tests/utils'; + const mockHandleError = vi.fn(); vi.mock('@/hooks/shared/use-translator', () => ({ @@ -13,29 +16,14 @@ vi.mock('@/hooks/shared/use-error-handler', () => ({ useErrorHandler: () => mockHandleError, })); -vi.mock('@/components/auth0/shared/toast', () => ({ - showToast: vi.fn(), -})); +mockToast(); vi.mock('@/hooks/my-organization/shared/services/use-domain-table-service', () => ({ - useDomainTableService: vi.fn(() => ({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - })), + useDomainTableService: vi.fn(), })); +const mockUseDomainTableService = vi.mocked(useDomainTableService); + describe('useDomainTable', () => { const mockDomain = { id: 'domain_abc123', @@ -67,6 +55,7 @@ describe('useDomainTable', () => { beforeEach(() => { vi.clearAllMocks(); + mockUseDomainTableService.mockReturnValue(createMockDomainTableServiceReturn()); }); it('should return correct initial state', () => { @@ -94,25 +83,9 @@ describe('useDomainTable', () => { it('should create domain, show toast, and open verify modal on handleCreate', async () => { const mockOnCreateDomain = vi.fn().mockResolvedValue(mockDomain); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onCreateDomain: mockOnCreateDomain }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: mockOnCreateDomain, - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -129,25 +102,9 @@ describe('useDomainTable', () => { it('should handle create error on handleCreate', async () => { const error = new Error('Create failed'); const mockOnCreateDomain = vi.fn().mockRejectedValue(error); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onCreateDomain: mockOnCreateDomain }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: mockOnCreateDomain, - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -162,25 +119,9 @@ describe('useDomainTable', () => { it('should verify domain and close verify modal on handleVerify success', async () => { const mockOnVerifyDomain = vi.fn().mockResolvedValue(true); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onVerifyDomain: mockOnVerifyDomain }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: mockOnVerifyDomain, - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -194,25 +135,9 @@ describe('useDomainTable', () => { it('should set verify error on handleVerify failure', async () => { const mockOnVerifyDomain = vi.fn().mockResolvedValue(false); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onVerifyDomain: mockOnVerifyDomain }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: mockOnVerifyDomain, - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -226,25 +151,9 @@ describe('useDomainTable', () => { it('should handle verify error on handleVerify', async () => { const error = new Error('Verify failed'); const mockOnVerifyDomain = vi.fn().mockRejectedValue(error); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onVerifyDomain: mockOnVerifyDomain }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: mockOnVerifyDomain, - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -259,25 +168,9 @@ describe('useDomainTable', () => { it('should delete domain and close modals on handleDelete', async () => { const mockOnDeleteDomain = vi.fn().mockResolvedValue(undefined); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onDeleteDomain: mockOnDeleteDomain }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: mockOnDeleteDomain, - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -293,25 +186,9 @@ describe('useDomainTable', () => { it('should handle delete error on handleDelete', async () => { const error = new Error('Delete failed'); const mockOnDeleteDomain = vi.fn().mockRejectedValue(error); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onDeleteDomain: mockOnDeleteDomain }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: mockOnDeleteDomain, - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -326,25 +203,9 @@ describe('useDomainTable', () => { it('should associate domain to provider on handleToggleSwitch with true', async () => { const mockOnAssociateToProvider = vi.fn().mockResolvedValue(undefined); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onAssociateToProvider: mockOnAssociateToProvider }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: mockOnAssociateToProvider, - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -357,25 +218,9 @@ describe('useDomainTable', () => { it('should delete domain from provider on handleToggleSwitch with false', async () => { const mockOnDeleteFromProvider = vi.fn().mockResolvedValue(undefined); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onDeleteFromProvider: mockOnDeleteFromProvider }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: mockOnDeleteFromProvider, - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -389,25 +234,9 @@ describe('useDomainTable', () => { it('should handle associate to provider error on handleToggleSwitch', async () => { const error = new Error('Associate failed'); const mockOnAssociateToProvider = vi.fn().mockRejectedValue(error); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onAssociateToProvider: mockOnAssociateToProvider }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: mockOnAssociateToProvider, - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -423,25 +252,9 @@ describe('useDomainTable', () => { it('should handle delete from provider error on handleToggleSwitch', async () => { const error = new Error('Delete from provider failed'); const mockOnDeleteFromProvider = vi.fn().mockRejectedValue(error); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onDeleteFromProvider: mockOnDeleteFromProvider }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: mockOnDeleteFromProvider, - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -456,25 +269,9 @@ describe('useDomainTable', () => { it('should close verify modal and clear error on handleCloseVerifyModal', async () => { const mockOnVerifyDomain = vi.fn().mockResolvedValue(false); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onVerifyDomain: mockOnVerifyDomain }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: mockOnVerifyDomain, - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -504,25 +301,9 @@ describe('useDomainTable', () => { it('should fetch providers and show configure modal for verified domain on handleConfigureClick', async () => { const mockFetchProviders = vi.fn().mockResolvedValue(undefined); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ fetchProviders: mockFetchProviders }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: mockFetchProviders, - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -538,25 +319,9 @@ describe('useDomainTable', () => { it('should handle fetchProviders error on handleConfigureClick', async () => { const error = new Error('Fetch providers failed'); const mockFetchProviders = vi.fn().mockRejectedValue(error); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ fetchProviders: mockFetchProviders }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: mockFetchProviders, - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: vi.fn(), - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -572,25 +337,12 @@ describe('useDomainTable', () => { it('should verify, fetch providers, and show configure modal on handleVerifyClick success', async () => { const mockOnVerifyDomain = vi.fn().mockResolvedValue(true); const mockFetchProviders = vi.fn().mockResolvedValue(undefined); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ + onVerifyDomain: mockOnVerifyDomain, + fetchProviders: mockFetchProviders, + }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: mockFetchProviders, - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: mockOnVerifyDomain, - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -606,25 +358,9 @@ describe('useDomainTable', () => { it('should show error toast on handleVerifyClick failure', async () => { const mockOnVerifyDomain = vi.fn().mockResolvedValue(false); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onVerifyDomain: mockOnVerifyDomain }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: mockOnVerifyDomain, - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); @@ -638,25 +374,9 @@ describe('useDomainTable', () => { it('should handle error on handleVerifyClick', async () => { const error = new Error('Verify click failed'); const mockOnVerifyDomain = vi.fn().mockRejectedValue(error); - const { useDomainTableService } = await import( - '@/hooks/my-organization/shared/services/use-domain-table-service' + mockUseDomainTableService.mockReturnValue( + createMockDomainTableServiceReturn({ onVerifyDomain: mockOnVerifyDomain }), ); - vi.mocked(useDomainTableService).mockReturnValue({ - domains: [], - providers: [], - isFetching: false, - isCreating: false, - isDeleting: false, - isVerifying: false, - isLoadingProviders: false, - fetchProviders: vi.fn(), - fetchDomains: vi.fn(), - onCreateDomain: vi.fn(), - onVerifyDomain: mockOnVerifyDomain, - onDeleteDomain: vi.fn(), - onAssociateToProvider: vi.fn(), - onDeleteFromProvider: vi.fn(), - }); const { result } = renderHook(() => useDomainTable(defaultOptions)); diff --git a/packages/react/src/hooks/my-organization/shared/__tests__/use-domain-table-service.test.ts b/packages/react/src/hooks/my-organization/shared/__tests__/use-domain-table-service.test.ts index f3c59907a..371f05594 100644 --- a/packages/react/src/hooks/my-organization/shared/__tests__/use-domain-table-service.test.ts +++ b/packages/react/src/hooks/my-organization/shared/__tests__/use-domain-table-service.test.ts @@ -14,43 +14,13 @@ import { createMockDomain, createMockIdentityProvider, createMockI18nService, + createMockDomainTableServiceOptions, } from '@/tests/utils'; import { createTestQueryClientWrapper } from '@/tests/utils/test-provider'; import type { UseDomainTableServiceOptions } from '@/types/my-organization/domain-management/domain-table-types'; -// ===== Mock packages ===== - const { initMockCoreClient } = mockCore(); -// ===== Mock Data ===== - -const createMockOptions = ( - overrides?: Partial, -): UseDomainTableServiceOptions => ({ - createAction: { - onBefore: vi.fn().mockReturnValue(true), - onAfter: vi.fn(), - }, - deleteAction: { - onBefore: vi.fn().mockReturnValue(true), - onAfter: vi.fn(), - }, - verifyAction: { - onBefore: vi.fn().mockReturnValue(true), - onAfter: vi.fn(), - }, - associateToProviderAction: { - onBefore: vi.fn().mockReturnValue(true), - onAfter: vi.fn(), - }, - deleteFromProviderAction: { - onBefore: vi.fn().mockReturnValue(true), - onAfter: vi.fn(), - }, - customMessages: {}, - ...overrides, -}); - const renderUseDomainTable = (options: UseDomainTableServiceOptions) => { const { wrapper, queryClient } = createTestQueryClientWrapper(); return { @@ -59,8 +29,6 @@ const renderUseDomainTable = (options: UseDomainTableServiceOptions) => { }; }; -// ===== Tests ===== - describe('useDomainTableService', () => { let mockCoreClient: ReturnType; let mockOptions: UseDomainTableServiceOptions; @@ -70,7 +38,7 @@ describe('useDomainTableService', () => { vi.clearAllMocks(); mockCoreClient = initMockCoreClient(); - mockOptions = createMockOptions(); + mockOptions = createMockDomainTableServiceOptions(); mockT = createMockI18nService().translator('my-organization'); vi.spyOn(useCoreClientModule, 'useCoreClient').mockReturnValue({ @@ -476,7 +444,7 @@ describe('useDomainTableService', () => { it('should handle onBefore callback returning false', async () => { const createData: CreateOrganizationDomainRequestContent = { domain: 'test.com' }; - const mockOptionsWithFalseBefore = createMockOptions({ + const mockOptionsWithFalseBefore = createMockDomainTableServiceOptions({ createAction: { onBefore: vi.fn().mockReturnValue(false), onAfter: vi.fn(), @@ -513,7 +481,7 @@ describe('useDomainTableService', () => { it('should work without onBefore and onAfter callbacks', async () => { const mockDomain = createMockDomain(); const createData: CreateOrganizationDomainRequestContent = { domain: mockDomain.domain }; - const mockOptionsWithoutCallbacks = createMockOptions({ + const mockOptionsWithoutCallbacks = createMockDomainTableServiceOptions({ createAction: undefined, }); @@ -570,7 +538,7 @@ describe('useDomainTableService', () => { it('should handle onBefore callback returning false', async () => { const mockDomain = createMockDomain(); - const mockOptionsWithFalseBefore = createMockOptions({ + const mockOptionsWithFalseBefore = createMockDomainTableServiceOptions({ verifyAction: { onBefore: vi.fn().mockReturnValue(false), onAfter: vi.fn(), @@ -588,7 +556,7 @@ describe('useDomainTableService', () => { it('should work without onBefore and onAfter callbacks', async () => { const mockDomain = createMockDomain(); - const mockOptionsWithoutCallbacks = createMockOptions({ + const mockOptionsWithoutCallbacks = createMockDomainTableServiceOptions({ verifyAction: undefined, }); @@ -627,7 +595,7 @@ describe('useDomainTableService', () => { it('should handle onBefore callback returning false', async () => { const mockDomain = createMockDomain(); - const mockOptionsWithFalseBefore = createMockOptions({ + const mockOptionsWithFalseBefore = createMockDomainTableServiceOptions({ deleteAction: { onBefore: vi.fn().mockReturnValue(false), onAfter: vi.fn(), @@ -645,7 +613,7 @@ describe('useDomainTableService', () => { it('should work without onBefore and onAfter callbacks', async () => { const mockDomain = createMockDomain(); - const mockOptionsWithoutCallbacks = createMockOptions({ + const mockOptionsWithoutCallbacks = createMockDomainTableServiceOptions({ deleteAction: undefined, }); @@ -688,7 +656,7 @@ describe('useDomainTableService', () => { it('should handle onBefore callback returning false', async () => { const mockDomain = createMockDomain(); const mockProvider = createMockIdentityProvider(); - const mockOptionsWithFalseBefore = createMockOptions({ + const mockOptionsWithFalseBefore = createMockDomainTableServiceOptions({ associateToProviderAction: { onBefore: vi.fn().mockReturnValue(false), onAfter: vi.fn(), @@ -709,7 +677,7 @@ describe('useDomainTableService', () => { it('should work without onBefore and onAfter callbacks', async () => { const mockDomain = createMockDomain(); const mockProvider = createMockIdentityProvider(); - const mockOptionsWithoutCallbacks = createMockOptions({ + const mockOptionsWithoutCallbacks = createMockDomainTableServiceOptions({ associateToProviderAction: undefined, }); @@ -752,7 +720,7 @@ describe('useDomainTableService', () => { it('should handle onBefore callback returning false', async () => { const mockDomain = createMockDomain(); const mockProvider = createMockIdentityProvider(); - const mockOptionsWithFalseBefore = createMockOptions({ + const mockOptionsWithFalseBefore = createMockDomainTableServiceOptions({ deleteFromProviderAction: { onBefore: vi.fn().mockReturnValue(false), onAfter: vi.fn(), @@ -773,7 +741,7 @@ describe('useDomainTableService', () => { it('should work without onBefore and onAfter callbacks', async () => { const mockDomain = createMockDomain(); const mockProvider = createMockIdentityProvider(); - const mockOptionsWithoutCallbacks = createMockOptions({ + const mockOptionsWithoutCallbacks = createMockDomainTableServiceOptions({ deleteFromProviderAction: undefined, }); diff --git a/packages/react/src/tests/utils/__mocks__/my-organization/domain-management/domain.mocks.ts b/packages/react/src/tests/utils/__mocks__/my-organization/domain-management/domain.mocks.ts index 208276cd1..137512983 100644 --- a/packages/react/src/tests/utils/__mocks__/my-organization/domain-management/domain.mocks.ts +++ b/packages/react/src/tests/utils/__mocks__/my-organization/domain-management/domain.mocks.ts @@ -9,6 +9,8 @@ import { vi } from 'vitest'; import type { DomainTableProps, UseDomainTableReturn, + UseDomainTableServiceOptions, + UseDomainTableServiceReturn, } from '@/types/my-organization/domain-management/domain-table-types'; export const createMockDomain = (overrides?: Partial): Domain => ({ @@ -148,3 +150,50 @@ export const createMockDomainTableReturn = ( handleDeleteClick: vi.fn(), ...overrides, }); + +export const createMockDomainTableServiceOptions = ( + overrides?: Partial, +): UseDomainTableServiceOptions => ({ + createAction: { + onBefore: vi.fn().mockReturnValue(true), + onAfter: vi.fn(), + }, + deleteAction: { + onBefore: vi.fn().mockReturnValue(true), + onAfter: vi.fn(), + }, + verifyAction: { + onBefore: vi.fn().mockReturnValue(true), + onAfter: vi.fn(), + }, + associateToProviderAction: { + onBefore: vi.fn().mockReturnValue(true), + onAfter: vi.fn(), + }, + deleteFromProviderAction: { + onBefore: vi.fn().mockReturnValue(true), + onAfter: vi.fn(), + }, + customMessages: {}, + ...overrides, +}); + +export const createMockDomainTableServiceReturn = ( + overrides: Partial = {}, +): UseDomainTableServiceReturn => ({ + domains: [], + providers: [], + isFetching: false, + isCreating: false, + isDeleting: false, + isVerifying: false, + isLoadingProviders: false, + fetchProviders: vi.fn(), + fetchDomains: vi.fn(), + onCreateDomain: vi.fn(), + onVerifyDomain: vi.fn(), + onDeleteDomain: vi.fn(), + onAssociateToProvider: vi.fn(), + onDeleteFromProvider: vi.fn(), + ...overrides, +});