Skip to content

Commit 7376bb3

Browse files
committed
test(modal): verifying a very depply nested modal will still be closed when a containing component is removed
1 parent 0f7fc80 commit 7376bb3

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

core/src/components/modal/test/inline/modal.e2e.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,5 +191,83 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
191191
// Verify the container was actually removed
192192
await expect(modalContainer).not.toBeAttached();
193193
});
194+
195+
test('it should dismiss modals when top-level ancestor is removed', async ({ page }) => {
196+
// We need to make sure we can close a modal when a much higher
197+
// element is removed from the DOM. This will be a common
198+
// use case in frameworks like Angular and React, where an entire
199+
// page container for much more than the modal might be swapped out.
200+
await page.setContent(
201+
`
202+
<ion-app>
203+
<div class="ion-page">
204+
<ion-header>
205+
<ion-toolbar>
206+
<ion-title>Top Level Removal Test</ion-title>
207+
</ion-toolbar>
208+
</ion-header>
209+
<ion-content class="ion-padding">
210+
<div id="top-level-container">
211+
<div id="nested-container">
212+
<button id="open-nested-modal">Open Nested Modal</button>
213+
<ion-modal id="nested-modal">
214+
<ion-header>
215+
<ion-toolbar>
216+
<ion-title>Nested Modal</ion-title>
217+
</ion-toolbar>
218+
</ion-header>
219+
<ion-content class="ion-padding">
220+
<p>This modal's original parent is deeply nested</p>
221+
<button id="remove-top-level">Remove Top Level Container</button>
222+
</ion-content>
223+
</ion-modal>
224+
</div>
225+
</div>
226+
</ion-content>
227+
</div>
228+
</ion-app>
229+
230+
<script>
231+
const nestedModal = document.querySelector('#nested-modal');
232+
nestedModal.presentingElement = document.querySelector('.ion-page');
233+
234+
document.getElementById('open-nested-modal').addEventListener('click', () => {
235+
nestedModal.isOpen = true;
236+
});
237+
238+
document.getElementById('remove-top-level').addEventListener('click', () => {
239+
document.querySelector('#top-level-container').remove();
240+
});
241+
</script>
242+
`,
243+
config
244+
);
245+
246+
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
247+
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
248+
249+
const nestedModal = page.locator('#nested-modal');
250+
const topLevelContainer = page.locator('#top-level-container');
251+
252+
// Open the nested modal
253+
await page.click('#open-nested-modal');
254+
await ionModalDidPresent.next();
255+
await expect(nestedModal).toBeVisible();
256+
257+
// Remove the top-level container
258+
await page.click('#remove-top-level');
259+
260+
// Wait for modal to be dismissed
261+
const dismissEvent = await ionModalDidDismiss.next();
262+
263+
// Verify the modal was dismissed with the correct role
264+
expect(dismissEvent.detail.role).toBe('parent-removed');
265+
266+
// Verify the modal is no longer visible
267+
await expect(nestedModal).toBeHidden();
268+
269+
// Verify the container was actually removed
270+
await expect(topLevelContainer).not.toBeAttached();
271+
});
194272
});
195273
});

0 commit comments

Comments
 (0)