Skip to content

Commit b8310d7

Browse files
committed
test(ui): add unit tests for ResetConnectionDialog
Covers the type-to-confirm gating, cancel and reset interactions, and the successful submit chain (delete + provider clear + wizard rewind + onClose).
1 parent defa503 commit b8310d7

2 files changed

Lines changed: 180 additions & 0 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import type { DeletedObjectResource, EnterpriseConnectionResource } from '@clerk/shared/types';
2+
import { describe, expect, it, vi } from 'vitest';
3+
4+
import { bindCreateFixtures } from '@/test/create-fixtures';
5+
import { render, screen, waitFor } from '@/test/utils';
6+
import { CardStateProvider } from '@/ui/elements/contexts';
7+
8+
const goToStep = vi.fn();
9+
10+
vi.mock('../elements/Wizard', () => ({
11+
useWizard: () => ({
12+
activeSteps: [],
13+
currentStep: undefined,
14+
currentIndex: -1,
15+
totalSteps: 0,
16+
isFirstStep: true,
17+
isLastStep: false,
18+
isNested: false,
19+
goNext: vi.fn(),
20+
goPrev: vi.fn(),
21+
goToStep,
22+
registerStep: vi.fn(),
23+
unregisterStep: vi.fn(),
24+
}),
25+
}));
26+
27+
const setProvider = vi.fn();
28+
const deleteEnterpriseConnection = vi.fn();
29+
30+
const connectionMockState = vi.hoisted(() => ({
31+
current: { id: 'idn_connection_1' } as Partial<EnterpriseConnectionResource> | null,
32+
}));
33+
34+
vi.mock('../ConfigureSSOContext', () => ({
35+
useConfigureSSO: () => ({
36+
enterpriseConnection: connectionMockState.current,
37+
provider: undefined,
38+
setProvider,
39+
deleteEnterpriseConnection,
40+
initialStepId: 'confirmation',
41+
contentRef: { current: null },
42+
createEnterpriseConnection: vi.fn(),
43+
updateEnterpriseConnection: vi.fn(),
44+
isDomainTakenByOtherOrg: false,
45+
}),
46+
}));
47+
48+
import { ResetConnectionDialog } from '../ResetConnectionDialog';
49+
50+
const { createFixtures } = bindCreateFixtures('ConfigureSSO');
51+
52+
const renderDialog = (
53+
wrapper: React.ComponentType<{ children?: React.ReactNode }>,
54+
props: { isOpen?: boolean; onClose?: () => void; confirmationValue?: string } = {},
55+
) => {
56+
const onClose = props.onClose ?? vi.fn();
57+
const utils = render(
58+
<CardStateProvider>
59+
<ResetConnectionDialog
60+
isOpen={props.isOpen ?? true}
61+
onClose={onClose}
62+
confirmationValue={props.confirmationValue ?? 'Acme Inc'}
63+
/>
64+
</CardStateProvider>,
65+
{ wrapper },
66+
);
67+
return { ...utils, onClose };
68+
};
69+
70+
const resetMocks = () => {
71+
goToStep.mockReset();
72+
setProvider.mockReset();
73+
deleteEnterpriseConnection.mockReset();
74+
deleteEnterpriseConnection.mockResolvedValue({} as DeletedObjectResource);
75+
goToStep.mockResolvedValue(undefined);
76+
connectionMockState.current = { id: 'idn_connection_1' };
77+
};
78+
79+
describe('ResetConnectionDialog', () => {
80+
it('returns null when isOpen is false', async () => {
81+
resetMocks();
82+
const { wrapper } = await createFixtures();
83+
renderDialog(wrapper, { isOpen: false });
84+
85+
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
86+
expect(screen.queryByRole('heading', { name: 'Reset connection' })).not.toBeInTheDocument();
87+
});
88+
89+
it('renders the dialog chrome and actions when isOpen is true', async () => {
90+
resetMocks();
91+
const { wrapper } = await createFixtures();
92+
renderDialog(wrapper, { confirmationValue: 'Acme Inc' });
93+
94+
expect(screen.getByRole('dialog')).toBeInTheDocument();
95+
expect(screen.getByRole('heading', { name: 'Reset connection' })).toBeInTheDocument();
96+
expect(
97+
screen.getByText(
98+
/Are you sure you want to reset the connection\? This action is irreversible and you will have to configure all steps again/i,
99+
),
100+
).toBeInTheDocument();
101+
expect(screen.getByRole('button', { name: 'Reset connection' })).toBeInTheDocument();
102+
expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
103+
});
104+
105+
it('keeps Reset disabled while the input is empty', async () => {
106+
resetMocks();
107+
const { wrapper } = await createFixtures();
108+
renderDialog(wrapper, { confirmationValue: 'Acme Inc' });
109+
110+
expect(screen.getByRole('button', { name: 'Reset connection' })).toBeDisabled();
111+
});
112+
113+
it('keeps Reset disabled when the input does not match the confirmation value', async () => {
114+
resetMocks();
115+
const { wrapper } = await createFixtures();
116+
const { userEvent } = renderDialog(wrapper, { confirmationValue: 'Acme Inc' });
117+
118+
await userEvent.type(screen.getByLabelText(/below to continue/i), 'wrong');
119+
expect(screen.getByRole('button', { name: 'Reset connection' })).toBeDisabled();
120+
});
121+
122+
it('enables Reset when the input matches the confirmation value exactly', async () => {
123+
resetMocks();
124+
const { wrapper } = await createFixtures();
125+
const { userEvent } = renderDialog(wrapper, { confirmationValue: 'Acme Inc' });
126+
127+
await userEvent.type(screen.getByLabelText(/below to continue/i), 'Acme Inc');
128+
await waitFor(() => {
129+
expect(screen.getByRole('button', { name: 'Reset connection' })).toBeEnabled();
130+
});
131+
});
132+
133+
it('invokes onClose when Cancel is clicked', async () => {
134+
resetMocks();
135+
const onClose = vi.fn();
136+
const { wrapper } = await createFixtures();
137+
const { userEvent } = renderDialog(wrapper, { onClose });
138+
139+
await userEvent.click(screen.getByRole('button', { name: 'Cancel' }));
140+
expect(onClose).toHaveBeenCalledTimes(1);
141+
expect(deleteEnterpriseConnection).not.toHaveBeenCalled();
142+
});
143+
144+
it('deletes the connection, clears the provider, rewinds the wizard, and closes on a successful submit', async () => {
145+
resetMocks();
146+
const onClose = vi.fn();
147+
const { wrapper } = await createFixtures();
148+
const { userEvent } = renderDialog(wrapper, { confirmationValue: 'Acme Inc', onClose });
149+
150+
await userEvent.type(screen.getByLabelText(/below to continue/i), 'Acme Inc');
151+
await userEvent.click(screen.getByRole('button', { name: 'Reset connection' }));
152+
153+
await waitFor(() => {
154+
expect(deleteEnterpriseConnection).toHaveBeenCalledWith('idn_connection_1');
155+
});
156+
expect(setProvider).toHaveBeenCalledWith(undefined);
157+
expect(goToStep).toHaveBeenCalledWith('select-provider');
158+
await waitFor(() => {
159+
expect(onClose).toHaveBeenCalledTimes(1);
160+
});
161+
});
162+
163+
it('does not delete when the active enterprise connection is missing', async () => {
164+
resetMocks();
165+
connectionMockState.current = null;
166+
const onClose = vi.fn();
167+
const { wrapper } = await createFixtures();
168+
const { userEvent } = renderDialog(wrapper, { confirmationValue: 'Acme Inc', onClose });
169+
170+
await userEvent.type(screen.getByLabelText(/below to continue/i), 'Acme Inc');
171+
await userEvent.click(screen.getByRole('button', { name: 'Reset connection' }));
172+
173+
expect(deleteEnterpriseConnection).not.toHaveBeenCalled();
174+
expect(setProvider).not.toHaveBeenCalled();
175+
expect(goToStep).not.toHaveBeenCalled();
176+
expect(onClose).not.toHaveBeenCalled();
177+
});
178+
});

0 commit comments

Comments
 (0)