Skip to content

Commit ddb551e

Browse files
committed
refactor: make dialogManagersStore reactive to adjust for provider props change
1 parent 4279275 commit ddb551e

File tree

3 files changed

+365
-35
lines changed

3 files changed

+365
-35
lines changed
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
import React from 'react';
2+
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
3+
import {
4+
DialogManagerProvider,
5+
useDialogManager,
6+
} from '../../../context/DialogManagerContext';
7+
8+
import '@testing-library/jest-dom';
9+
import { useDialogIsOpen, useOpenedDialogCount } from '../hooks';
10+
11+
const TEST_IDS = {
12+
CLOSE_DIALOG: 'close-dialog',
13+
DIALOG_COUNT: 'dialog-count',
14+
DIALOG_OPEN: 'dialog-open',
15+
MANAGER_ID_DISPLAY: 'manager-id-display',
16+
OPEN_DIALOG: 'open-dialog',
17+
TEST_COMPONENT: 'test-component',
18+
};
19+
20+
const TEST_MANAGER_ID = 'test-manager';
21+
const SHARED_MANAGER_ID = 'shared-manager';
22+
const MANAGER_1_ID = 'manager-1';
23+
const MANAGER_2_ID = 'manager-2';
24+
25+
const TestComponent = ({ dialogId, dialogManagerId, testId }) => {
26+
const { dialogManager } = useDialogManager({ dialogId, dialogManagerId });
27+
const openDialogCount = useOpenedDialogCount({ dialogManagerId });
28+
const isOpen = useDialogIsOpen(dialogId, dialogManagerId);
29+
return (
30+
<div data-testid={testId ?? TEST_IDS.TEST_COMPONENT}>
31+
<span data-testid={TEST_IDS.MANAGER_ID_DISPLAY}>{dialogManager?.id}</span>
32+
<span data-testid={TEST_IDS.DIALOG_COUNT}>{openDialogCount}</span>
33+
<span data-testid={TEST_IDS.DIALOG_OPEN}>{isOpen ? 'true' : 'false'}</span>
34+
</div>
35+
);
36+
};
37+
38+
const DialogTestComponent = ({ dialogId, managerId }) => {
39+
const { dialogManager } = useDialogManager({ dialogManagerId: managerId });
40+
41+
const handleOpenDialog = () => {
42+
if (dialogManager) {
43+
dialogManager.open({ id: dialogId });
44+
}
45+
};
46+
47+
const handleCloseDialog = () => {
48+
if (dialogManager) {
49+
dialogManager.close(dialogId);
50+
}
51+
};
52+
53+
return (
54+
<div>
55+
<button data-testid={TEST_IDS.OPEN_DIALOG} onClick={handleOpenDialog}>
56+
Open
57+
</button>
58+
<button data-testid={TEST_IDS.CLOSE_DIALOG} onClick={handleCloseDialog}>
59+
Close
60+
</button>
61+
</div>
62+
);
63+
};
64+
65+
describe('DialogManagerContext', () => {
66+
describe('DialogManagerProvider', () => {
67+
it('does not create a new dialog manager when no id is provided', () => {
68+
render(
69+
<DialogManagerProvider>
70+
<TestComponent />
71+
</DialogManagerProvider>,
72+
);
73+
74+
expect(screen.getByTestId(TEST_IDS.DIALOG_COUNT).textContent).toBe('0');
75+
});
76+
77+
it('creates a new dialog manager and adds it to the manager pool when id is provided', () => {
78+
render(
79+
<DialogManagerProvider id={TEST_MANAGER_ID}>
80+
<TestComponent dialogManagerId={TEST_MANAGER_ID} />
81+
</DialogManagerProvider>,
82+
);
83+
84+
const managerId = screen.getByTestId(TEST_IDS.MANAGER_ID_DISPLAY).textContent;
85+
expect(managerId).toBe(TEST_MANAGER_ID);
86+
expect(screen.getByTestId(TEST_IDS.DIALOG_COUNT).textContent).toBe('0');
87+
});
88+
89+
it('provides dialog manager to non-child components', () => {
90+
render(
91+
<DialogManagerProvider id={MANAGER_1_ID}>
92+
<DialogManagerProvider id={MANAGER_2_ID} />
93+
<TestComponent dialogManagerId={MANAGER_2_ID} />
94+
</DialogManagerProvider>,
95+
);
96+
const managerId = screen.getByTestId(TEST_IDS.MANAGER_ID_DISPLAY).textContent;
97+
expect(managerId).toBe(MANAGER_2_ID);
98+
expect(screen.getByTestId(TEST_IDS.DIALOG_COUNT).textContent).toBe('0');
99+
});
100+
101+
it('removes the dialog manager from the pool upon unmount', () => {
102+
const { rerender } = render(
103+
<DialogManagerProvider id={TEST_MANAGER_ID}>
104+
<TestComponent dialogManagerId={TEST_MANAGER_ID} />
105+
</DialogManagerProvider>,
106+
);
107+
108+
const managerId = screen.getByTestId(TEST_IDS.MANAGER_ID_DISPLAY).textContent;
109+
expect(managerId).toBe(TEST_MANAGER_ID);
110+
111+
rerender(
112+
<DialogManagerProvider id='different-manager'>
113+
<TestComponent dialogManagerId={TEST_MANAGER_ID} />
114+
</DialogManagerProvider>,
115+
);
116+
117+
expect(screen.getByTestId(TEST_IDS.MANAGER_ID_DISPLAY)).toHaveTextContent(
118+
'different-manager',
119+
);
120+
expect(screen.getByTestId(TEST_IDS.DIALOG_COUNT)).toHaveTextContent('0');
121+
});
122+
123+
it('retrieves existing dialog manager and does not create a new dialog manager', () => {
124+
const dialogId = 'shared-dialog';
125+
render(
126+
<DialogManagerProvider id={SHARED_MANAGER_ID}>
127+
<TestComponent
128+
dialogId={dialogId}
129+
dialogManagerId={SHARED_MANAGER_ID}
130+
testId={'component-1'}
131+
/>
132+
<DialogManagerProvider id={SHARED_MANAGER_ID}>
133+
<DialogTestComponent dialogId={dialogId} managerId={SHARED_MANAGER_ID} />
134+
<TestComponent
135+
dialogId={dialogId}
136+
dialogManagerId={SHARED_MANAGER_ID}
137+
testId={'component-2'}
138+
/>
139+
</DialogManagerProvider>
140+
</DialogManagerProvider>,
141+
);
142+
143+
const component1 = screen.getByTestId('component-1');
144+
const component2 = screen.getByTestId('component-2');
145+
146+
expect(
147+
component1.querySelector(`[data-testid="${TEST_IDS.MANAGER_ID_DISPLAY}"`),
148+
).toHaveTextContent(SHARED_MANAGER_ID);
149+
expect(
150+
component2.querySelector(`[data-testid="${TEST_IDS.MANAGER_ID_DISPLAY}"`),
151+
).toHaveTextContent(SHARED_MANAGER_ID);
152+
153+
act(() => {
154+
fireEvent.click(screen.getByTestId(TEST_IDS.OPEN_DIALOG));
155+
});
156+
expect(
157+
component1.querySelector(`[data-testid="${TEST_IDS.DIALOG_COUNT}"`),
158+
).toHaveTextContent('1');
159+
expect(
160+
component2.querySelector(`[data-testid="${TEST_IDS.DIALOG_COUNT}"`),
161+
).toHaveTextContent('1');
162+
expect(
163+
component1.querySelector(`[data-testid="${TEST_IDS.DIALOG_OPEN}"`),
164+
).toHaveTextContent('true');
165+
expect(
166+
component2.querySelector(`[data-testid="${TEST_IDS.DIALOG_OPEN}"`),
167+
).toHaveTextContent('true');
168+
});
169+
170+
it('creates different managers for different IDs', () => {
171+
render(
172+
<DialogManagerProvider id={MANAGER_1_ID}>
173+
<DialogManagerProvider id={MANAGER_2_ID}>
174+
<DialogTestComponent dialogId='dialog-1' managerId={MANAGER_1_ID} />
175+
<DialogTestComponent dialogId='dialog-2' managerId={MANAGER_2_ID} />
176+
<TestComponent dialogManagerId={MANAGER_1_ID} />
177+
<TestComponent dialogManagerId={MANAGER_2_ID} />
178+
</DialogManagerProvider>
179+
</DialogManagerProvider>,
180+
);
181+
182+
const testComponents = screen.getAllByTestId(TEST_IDS.TEST_COMPONENT);
183+
expect(testComponents).toHaveLength(2);
184+
185+
const manager1Id = testComponents[0].querySelector(
186+
`[data-testid="${TEST_IDS.MANAGER_ID_DISPLAY}"]`,
187+
).textContent;
188+
const manager2Id = testComponents[1].querySelector(
189+
`[data-testid="${TEST_IDS.MANAGER_ID_DISPLAY}"]`,
190+
).textContent;
191+
192+
expect(manager1Id).toBe(MANAGER_1_ID);
193+
expect(manager2Id).toBe(MANAGER_2_ID);
194+
195+
act(() => {
196+
screen.getAllByTestId(TEST_IDS.OPEN_DIALOG)[0].click();
197+
});
198+
199+
const manager1Count = testComponents[0].querySelector(
200+
`[data-testid="${TEST_IDS.DIALOG_COUNT}"]`,
201+
).textContent;
202+
const manager2Count = testComponents[1].querySelector(
203+
`[data-testid="${TEST_IDS.DIALOG_COUNT}"]`,
204+
).textContent;
205+
206+
expect(manager1Count).toBe('1');
207+
expect(manager2Count).toBe('0');
208+
209+
act(() => {
210+
screen.getAllByTestId(TEST_IDS.OPEN_DIALOG)[1].click();
211+
});
212+
213+
const manager1CountAfter = testComponents[0].querySelector(
214+
`[data-testid="${TEST_IDS.DIALOG_COUNT}"]`,
215+
).textContent;
216+
const manager2CountAfter = testComponents[1].querySelector(
217+
`[data-testid="${TEST_IDS.DIALOG_COUNT}"]`,
218+
).textContent;
219+
220+
expect(manager1CountAfter).toBe('1');
221+
expect(manager2CountAfter).toBe('1');
222+
});
223+
224+
it('does not retrieve dialog manager only by dialog id', async () => {
225+
render(
226+
<DialogManagerProvider id={MANAGER_1_ID}>
227+
<DialogTestComponent dialogId='manager-1-dialog' managerId={MANAGER_1_ID} />
228+
<DialogManagerProvider id={MANAGER_2_ID}>
229+
<TestComponent dialogId='manager-1-dialog' />
230+
</DialogManagerProvider>
231+
</DialogManagerProvider>,
232+
);
233+
234+
await act(() => {
235+
fireEvent.click(screen.getByTestId(TEST_IDS.OPEN_DIALOG));
236+
});
237+
238+
await waitFor(async () => {
239+
expect(await screen.findByTestId(TEST_IDS.DIALOG_COUNT)).toHaveTextContent('0');
240+
const managerId = screen.getByTestId(TEST_IDS.MANAGER_ID_DISPLAY).textContent;
241+
expect(managerId).toBe(MANAGER_2_ID);
242+
});
243+
});
244+
245+
it('uses the manager from the nearest context provider when manager is not found by id', () => {
246+
render(
247+
<DialogManagerProvider id={MANAGER_1_ID}>
248+
<TestComponent dialogManagerId='non-existent' />
249+
</DialogManagerProvider>,
250+
);
251+
252+
expect(screen.getByTestId(TEST_IDS.MANAGER_ID_DISPLAY)).toHaveTextContent(
253+
MANAGER_1_ID,
254+
);
255+
});
256+
});
257+
});

src/components/Dialog/hooks/useDialog.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ const openedDialogCountSelector = (nextValue: DialogManagerState) => ({
4949
}, 0),
5050
});
5151

52-
export const useOpenedDialogCount = () => {
53-
const { dialogManager } = useDialogManager();
52+
export const useOpenedDialogCount = ({
53+
dialogManagerId,
54+
}: { dialogManagerId?: string } = {}) => {
55+
const { dialogManager } = useDialogManager({ dialogManagerId });
5456
return useStateStore(dialogManager.state, openedDialogCountSelector).openedDialogCount;
5557
};

0 commit comments

Comments
 (0)