test(modal): migrate tests to Playwright (#25161)
@ -1,127 +0,0 @@
|
||||
import { newE2EPage } from '@stencil/core/testing';
|
||||
|
||||
import { openModal, testModal } from '../test.utils';
|
||||
|
||||
const DIRECTORY = 'basic';
|
||||
const getActiveElementText = async (page) => {
|
||||
const activeElement = await page.evaluateHandle(() => document.activeElement);
|
||||
return await page.evaluate((el) => el?.textContent, activeElement);
|
||||
};
|
||||
|
||||
test('modal: focus trap', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/modal/test/basic?ionic:_testing=true' });
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#basic-modal');
|
||||
await page.waitForSelector('#basic-modal');
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
expect(modal).not.toBe(null);
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
await page.keyboard.press('Tab');
|
||||
|
||||
const activeElementText = await getActiveElementText(page);
|
||||
expect(activeElementText).toEqual('Dismiss Modal');
|
||||
|
||||
await page.keyboard.down('Shift');
|
||||
await page.keyboard.press('Tab');
|
||||
await page.keyboard.up('Shift');
|
||||
|
||||
const activeElementTextTwo = await getActiveElementText(page);
|
||||
expect(activeElementTextTwo).toEqual('Dismiss Modal');
|
||||
|
||||
await page.keyboard.press('Tab');
|
||||
|
||||
const activeElementTextThree = await getActiveElementText(page);
|
||||
expect(activeElementTextThree).toEqual('Dismiss Modal');
|
||||
});
|
||||
|
||||
test('modal: return focus', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/modal/test/basic?ionic:_testing=true' });
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#basic-modal');
|
||||
await page.waitForSelector('#basic-modal');
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
expect(modal).not.toBe(null);
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
await Promise.all([
|
||||
await modal.callMethod('dismiss'),
|
||||
await ionModalDidDismiss.next(),
|
||||
await modal.waitForNotVisible(),
|
||||
]);
|
||||
|
||||
const activeElement = await page.evaluateHandle(() => document.activeElement);
|
||||
const id = await activeElement.evaluate((node) => node.id);
|
||||
expect(id).toEqual('basic-modal');
|
||||
});
|
||||
|
||||
test('modal: basic', async () => {
|
||||
await testModal(DIRECTORY, '#basic-modal', false);
|
||||
});
|
||||
|
||||
test('modal:rtl: basic', async () => {
|
||||
await testModal(DIRECTORY, '#basic-modal', false, true);
|
||||
});
|
||||
|
||||
test('modal: htmlAttributes', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/modal/test/basic?ionic:_testing=true' });
|
||||
|
||||
await page.click('#basic-modal');
|
||||
await page.waitForSelector('#basic-modal');
|
||||
|
||||
const alert = await page.find('ion-modal');
|
||||
|
||||
expect(alert).not.toBe(null);
|
||||
await alert.waitForVisible();
|
||||
|
||||
const attribute = await page.evaluate(() => document.querySelector('ion-modal').getAttribute('data-testid'));
|
||||
|
||||
expect(attribute).toEqual('basic-modal');
|
||||
});
|
||||
|
||||
test('it should dismiss the modal when clicking the backdrop', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/modal/test/basic?ionic:_testing=true' });
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
|
||||
await page.click('#basic-modal');
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
await page.mouse.click(20, 20);
|
||||
await ionModalDidDismiss.next();
|
||||
});
|
||||
|
||||
test('modal: setting the breakpoint should warn the developer', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/modal/test/basic?ionic:_testing=true' });
|
||||
|
||||
const warnings = [];
|
||||
|
||||
page.on('console', (ev) => {
|
||||
if (ev.type() === 'warning') {
|
||||
warnings.push(ev.text());
|
||||
}
|
||||
});
|
||||
|
||||
const modal = await openModal(page, '#basic-modal');
|
||||
|
||||
await modal.callMethod('setCurrentBreakpoint', 0.5);
|
||||
|
||||
expect(warnings.length).toBe(1);
|
||||
expect(warnings[0]).toBe('[Ionic Warning]: setCurrentBreakpoint is only supported on sheet modals.');
|
||||
});
|
||||
|
||||
test('modal: getting the breakpoint should return undefined', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/modal/test/basic?ionic:_testing=true' });
|
||||
|
||||
const modal = await openModal(page, '#basic-modal');
|
||||
|
||||
const breakpoint = await modal.callMethod('getCurrentBreakpoint');
|
||||
expect(breakpoint).toBeUndefined();
|
||||
});
|
182
core/src/components/modal/test/basic/modal.e2e.ts
Normal file
@ -0,0 +1,182 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { test } from '@utils/test/playwright';
|
||||
|
||||
test.describe('modal: focus trapping', () => {
|
||||
test('focus should be trapped inside of modal', async ({ page, browserName }) => {
|
||||
await page.goto('/src/components/modal/test/basic');
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#basic-modal');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
/**
|
||||
* The default WebKit behavior is to
|
||||
* highlight items on webpages with Option-Tab.
|
||||
* See "Press Tab to highlight each item on a webpage"
|
||||
* in Safari Preferences > Advanced.
|
||||
*/
|
||||
if (browserName === 'webkit') {
|
||||
await page.keyboard.down('Alt');
|
||||
}
|
||||
await page.keyboard.press('Tab');
|
||||
|
||||
const dismissButton = await page.locator('ion-button.dismiss');
|
||||
expect(dismissButton).toBeFocused();
|
||||
|
||||
await page.keyboard.down('Shift');
|
||||
await page.keyboard.press('Tab');
|
||||
await page.keyboard.up('Shift');
|
||||
|
||||
expect(dismissButton).toBeFocused();
|
||||
await page.keyboard.press('Tab');
|
||||
|
||||
if (browserName === 'webkit') {
|
||||
await page.keyboard.up('Alt');
|
||||
}
|
||||
|
||||
expect(dismissButton).toBeFocused();
|
||||
});
|
||||
|
||||
test('focus should be returned to previously focused element when dismissing modal', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/src/components/modal/test/basic');
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
const modalButton = await page.locator('#basic-modal');
|
||||
|
||||
if (browserName === 'webkit') {
|
||||
await page.keyboard.down('Alt');
|
||||
}
|
||||
|
||||
// Focus #basic-modal button
|
||||
await page.keyboard.press('Tab');
|
||||
expect(modalButton).toBeFocused();
|
||||
|
||||
if (browserName === 'webkit') {
|
||||
await page.keyboard.up('Alt');
|
||||
}
|
||||
|
||||
await page.keyboard.press('Space');
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
await page.keyboard.press('Escape');
|
||||
await ionModalDidDismiss.next();
|
||||
|
||||
expect(modalButton).toBeFocused();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('modal: rendering', () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
await page.goto('/src/components/modal/test/basic');
|
||||
|
||||
const ionModalWillDismiss = await page.spyOnEvent('ionModalWillDismiss');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
const ionModalWillPresent = await page.spyOnEvent('ionModalWillPresent');
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#basic-modal');
|
||||
|
||||
await ionModalWillPresent.next();
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.locator('ion-modal');
|
||||
|
||||
await page.setIonViewport();
|
||||
|
||||
expect(await page.screenshot()).toMatchSnapshot(`modal-basic-present-${page.getSnapshotSettings()}.png`);
|
||||
|
||||
await modal.evaluate((el: HTMLIonModalElement) => {
|
||||
el.dismiss();
|
||||
});
|
||||
|
||||
await ionModalWillDismiss.next();
|
||||
await ionModalDidDismiss.next();
|
||||
|
||||
expect(await page.screenshot()).toMatchSnapshot(`modal-basic-dismiss-${page.getSnapshotSettings()}.png`);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('modal: htmlAttributes inheritance', () => {
|
||||
test('should correctly inherit attributes on host', async ({ page }) => {
|
||||
await page.goto('/src/components/modal/test/basic');
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#basic-modal');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.locator('ion-modal');
|
||||
|
||||
const attribute = await modal.getAttribute('data-testid');
|
||||
expect(attribute).toBe('basic-modal');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('modal: backdrop', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/src/components/modal/test/basic');
|
||||
});
|
||||
|
||||
test('it should dismiss the modal when clicking the backdrop', async ({ page }, testInfo) => {
|
||||
test.skip(
|
||||
testInfo.project.name === 'Mobile Chrome' || testInfo.project.name === 'Mobile Safari',
|
||||
'The modal covers the entire screen on mobile, so the backdrop is not clickable.'
|
||||
);
|
||||
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
|
||||
await page.click('#basic-modal');
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
await page.mouse.click(20, 20);
|
||||
await ionModalDidDismiss.next();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('modal: incorrect usage', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/src/components/modal/test/basic');
|
||||
});
|
||||
|
||||
test('it should warn when setting a breakpoint on a non-sheet modal', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
const warnings: string[] = [];
|
||||
|
||||
page.on('console', (ev) => {
|
||||
if (ev.type() === 'warning') {
|
||||
warnings.push(ev.text());
|
||||
}
|
||||
});
|
||||
|
||||
await page.click('#basic-modal');
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.locator('ion-modal');
|
||||
await modal.evaluate((el: HTMLIonModalElement) => {
|
||||
el.setCurrentBreakpoint(0.5);
|
||||
});
|
||||
|
||||
expect(warnings.length).toBe(1);
|
||||
expect(warnings[0]).toBe('[Ionic Warning]: setCurrentBreakpoint is only supported on sheet modals.');
|
||||
});
|
||||
|
||||
test('it should return undefined when getting the breakpoint on a non-sheet modal', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#basic-modal');
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.locator('ion-modal');
|
||||
const breakpoint = await modal.evaluate((el: HTMLIonModalElement) => {
|
||||
return el.getCurrentBreakpoint();
|
||||
});
|
||||
|
||||
expect(breakpoint).toBe(undefined);
|
||||
});
|
||||
});
|
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 63 KiB |
@ -1,27 +1,25 @@
|
||||
import { newE2EPage, newE2EPage } from '@stencil/core/testing';
|
||||
import { dragElementBy } from '@utils/test';
|
||||
import { expect } from '@playwright/test';
|
||||
import { test, dragElementBy } from '@utils/test/playwright';
|
||||
|
||||
describe('modal - canDismiss handler', () => {
|
||||
let page: E2EPage;
|
||||
test.describe('modal: canDismiss', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/src/components/modal/test/canDismiss');
|
||||
});
|
||||
|
||||
describe('regular modal', () => {
|
||||
beforeEach(async () => {
|
||||
page = await newE2EPage({ url: '/src/components/modal/test/canDismiss?ionic:_testing=true' });
|
||||
});
|
||||
|
||||
it('should dismiss when canDismiss is true', async () => {
|
||||
test.describe('regular modal', () => {
|
||||
test('should dismiss when canDismiss is true', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#show-modal');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(true);
|
||||
});
|
||||
it('should not dismiss when canDismiss is false', async () => {
|
||||
test('should not dismiss when canDismiss is false', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#radio-false');
|
||||
@ -29,12 +27,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(false);
|
||||
});
|
||||
it('should dismiss when canDismiss is Promise<true>', async () => {
|
||||
test('should dismiss when canDismiss is Promise<true>', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#radio-promise-true');
|
||||
@ -42,12 +40,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(true);
|
||||
});
|
||||
it('should not dismiss when canDismiss is Promise<false>', async () => {
|
||||
test('should not dismiss when canDismiss is Promise<false>', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#radio-promise-false');
|
||||
@ -55,12 +53,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(false);
|
||||
});
|
||||
it('should dismiss when canDismiss is Action Sheet and user clicks confirm', async () => {
|
||||
test('should dismiss when canDismiss is Action Sheet and user clicks confirm', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent');
|
||||
@ -78,26 +76,23 @@ describe('modal - canDismiss handler', () => {
|
||||
await ionModalDidDismiss.next();
|
||||
});
|
||||
});
|
||||
|
||||
describe('card modal', () => {
|
||||
beforeEach(async () => {
|
||||
page = await newE2EPage({ url: '/src/components/modal/test/canDismiss?ionic:_testing=true&ionic:mode=ios' });
|
||||
test.describe('card modal', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.click('#radio-card');
|
||||
});
|
||||
|
||||
it('should dismiss when canDismiss is true', async () => {
|
||||
test('should dismiss when canDismiss is true', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#show-modal');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(true);
|
||||
});
|
||||
it('should not dismiss when canDismiss is false', async () => {
|
||||
test('should not dismiss when canDismiss is false', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#radio-false');
|
||||
@ -105,12 +100,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(false);
|
||||
});
|
||||
it('should dismiss when canDismiss is Promise<true>', async () => {
|
||||
test('should dismiss when canDismiss is Promise<true>', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#radio-promise-true');
|
||||
@ -118,12 +113,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(true);
|
||||
});
|
||||
it('should not dismiss when canDismiss is Promise<false>', async () => {
|
||||
test('should not dismiss when canDismiss is Promise<false>', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#radio-promise-false');
|
||||
@ -131,12 +126,21 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(false);
|
||||
});
|
||||
it('should dismiss on swipe when canDismiss is true', async () => {
|
||||
});
|
||||
|
||||
test.describe('card modal - iOS swiping', () => {
|
||||
test.beforeEach(async ({ page }, testInfo) => {
|
||||
test.skip(testInfo.project.metadata.mode !== 'ios', 'Swipe to close on a modal is only available in iOS mode.');
|
||||
|
||||
await page.click('#radio-card');
|
||||
});
|
||||
|
||||
test('should dismiss on swipe when canDismiss is true', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
|
||||
@ -144,12 +148,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('ion-modal #modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, 500);
|
||||
|
||||
await ionModalDidDismiss.next();
|
||||
});
|
||||
it('should not dismiss on swipe when canDismiss is false', async () => {
|
||||
test('should not dismiss on swipe when canDismiss is false', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#radio-false');
|
||||
@ -157,13 +161,13 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('#modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, 500);
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const modal = await page.locator('ion-modal');
|
||||
expect(modal).not.toBe(null);
|
||||
});
|
||||
it('should dismiss on swipe when canDismiss is Promise<true>', async () => {
|
||||
test('should dismiss on swipe when canDismiss is Promise<true>', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
|
||||
@ -172,12 +176,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('#modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, 500);
|
||||
|
||||
await ionModalDidDismiss.next();
|
||||
});
|
||||
it('should not dismiss on swipe when canDismiss is Promise<false>', async () => {
|
||||
test('should not dismiss on swipe when canDismiss is Promise<false>', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionHandlerDone = await page.spyOnEvent('ionHandlerDone');
|
||||
|
||||
@ -186,15 +190,15 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('#modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, 500);
|
||||
|
||||
await ionHandlerDone.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const modal = await page.locator('ion-modal');
|
||||
expect(modal).not.toBe(null);
|
||||
});
|
||||
it('should dismiss when canDismiss is Action Sheet and user clicks confirm', async () => {
|
||||
test('should dismiss when canDismiss is Action Sheet and user clicks confirm', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent');
|
||||
@ -204,7 +208,7 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('#modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, 500);
|
||||
|
||||
await ionActionSheetDidPresent.next();
|
||||
@ -214,25 +218,23 @@ describe('modal - canDismiss handler', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('sheet modal', () => {
|
||||
beforeEach(async () => {
|
||||
page = await newE2EPage({ url: '/src/components/modal/test/canDismiss?ionic:_testing=true' });
|
||||
test.describe('sheet modal', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.click('#radio-sheet');
|
||||
});
|
||||
|
||||
it('should dismiss when canDismiss is true', async () => {
|
||||
test('should dismiss when canDismiss is true', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#show-modal');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(true);
|
||||
});
|
||||
it('should not dismiss when canDismiss is true', async () => {
|
||||
test('should not dismiss when canDismiss is false', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#radio-false');
|
||||
@ -240,12 +242,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(false);
|
||||
});
|
||||
it('should dismiss when canDismiss is Promise<true>', async () => {
|
||||
test('should dismiss when canDismiss is Promise<true>', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#radio-promise-true');
|
||||
@ -253,12 +255,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(true);
|
||||
});
|
||||
it('should not dismiss when canDismiss is Promise<false>', async () => {
|
||||
test('should not dismiss when canDismiss is Promise<false>', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#radio-promise-false');
|
||||
@ -266,12 +268,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const returnValue = await modal.callMethod('dismiss');
|
||||
const modal = await page.locator('ion-modal');
|
||||
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
|
||||
|
||||
expect(returnValue).toBe(false);
|
||||
});
|
||||
it('should dismiss on swipe when canDismiss is true', async () => {
|
||||
test('should dismiss on swipe when canDismiss is true', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
|
||||
@ -279,12 +281,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('#modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, 500);
|
||||
|
||||
await ionModalDidDismiss.next();
|
||||
});
|
||||
it('should not dismiss on swipe when canDismiss is true', async () => {
|
||||
test('should not dismiss on swipe when canDismiss is false', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#radio-false');
|
||||
@ -292,13 +294,13 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('#modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, 500);
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const modal = await page.locator('ion-modal');
|
||||
expect(modal).not.toBe(null);
|
||||
});
|
||||
it('should dismiss on swipe when canDismiss is Promise<true>', async () => {
|
||||
test('should dismiss on swipe when canDismiss is Promise<true>', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
|
||||
@ -307,12 +309,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('#modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, 500);
|
||||
|
||||
await ionModalDidDismiss.next();
|
||||
});
|
||||
it('should not dismiss on swipe when canDismiss is Promise<false>', async () => {
|
||||
test('should not dismiss on swipe when canDismiss is Promise<false>', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionHandlerDone = await page.spyOnEvent('ionHandlerDone');
|
||||
|
||||
@ -321,37 +323,29 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('#modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, 500);
|
||||
|
||||
await ionHandlerDone.next();
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const modal = await page.locator('ion-modal');
|
||||
expect(modal).not.toBe(null);
|
||||
});
|
||||
|
||||
it('should not dismiss on swipe when not attempting to close', async () => {
|
||||
test('should not dismiss on swipe when not attempting to close', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const screenshotCompares = [];
|
||||
|
||||
await page.click('#radio-promise-true');
|
||||
await page.click('#show-modal');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('#modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, -500);
|
||||
|
||||
screenshotCompares.push(await page.compareScreenshot());
|
||||
|
||||
const modal = await page.find('ion-modal');
|
||||
const modal = await page.locator('ion-modal');
|
||||
expect(modal).not.toBe(null);
|
||||
|
||||
for (const screenshotCompare of screenshotCompares) {
|
||||
expect(screenshotCompare).toMatchScreenshot();
|
||||
}
|
||||
});
|
||||
it('should hit the dismiss threshold when swiping', async () => {
|
||||
test('should hit the dismiss threshold when swiping', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
|
||||
@ -360,12 +354,12 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('#modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, 100);
|
||||
|
||||
await ionModalDidDismiss.next();
|
||||
});
|
||||
it('should dismiss when canDismiss is Action Sheet and user clicks confirm', async () => {
|
||||
test('should dismiss when canDismiss is Action Sheet and user clicks confirm', async ({ page }) => {
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent');
|
||||
@ -375,7 +369,7 @@ describe('modal - canDismiss handler', () => {
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
const modalHeader = await page.$('#modal-header');
|
||||
const modalHeader = await page.locator('#modal-header');
|
||||
await dragElementBy(modalHeader, page, 0, 500);
|
||||
|
||||
await ionActionSheetDidPresent.next();
|
@ -1,103 +0,0 @@
|
||||
import { newE2EPage } from '@stencil/core/testing';
|
||||
|
||||
import { testModal } from '../test.utils';
|
||||
|
||||
const DIRECTORY = 'card';
|
||||
|
||||
test('modal: card', async () => {
|
||||
await testModal(DIRECTORY, '#card', true);
|
||||
});
|
||||
|
||||
test('modal: card - custom', async () => {
|
||||
await testModal(DIRECTORY, '#card-custom', true);
|
||||
});
|
||||
|
||||
test('modal: card - Stacked, Tablet', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/modal/test/card?ionic:_testing=true' });
|
||||
|
||||
// Ensure that we get tablet styles
|
||||
await page.setViewport({ width: 768, height: 500 });
|
||||
|
||||
const screenshotCompares = [];
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#card');
|
||||
await page.waitForSelector('#card');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
screenshotCompares.push(await page.compareScreenshot());
|
||||
|
||||
await page.click('.add');
|
||||
await page.waitForSelector('.add');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
screenshotCompares.push(await page.compareScreenshot());
|
||||
});
|
||||
|
||||
test('modal: card - Stacked, Mobile', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/modal/test/card?ionic:_testing=true' });
|
||||
|
||||
const screenshotCompares = [];
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#card');
|
||||
await page.waitForSelector('#card');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
screenshotCompares.push(await page.compareScreenshot());
|
||||
|
||||
await page.click('.add');
|
||||
await page.waitForSelector('.add');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
screenshotCompares.push(await page.compareScreenshot());
|
||||
});
|
||||
|
||||
test('modal: card - Custom, Stacked, Tablet', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/modal/test/card?ionic:_testing=true' });
|
||||
|
||||
// Ensure that we get tablet styles
|
||||
await page.setViewport({ width: 768, height: 500 });
|
||||
|
||||
const screenshotCompares = [];
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#card-custom');
|
||||
await page.waitForSelector('#card-custom');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
screenshotCompares.push(await page.compareScreenshot());
|
||||
|
||||
await page.click('.add');
|
||||
await page.waitForSelector('.add');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
screenshotCompares.push(await page.compareScreenshot());
|
||||
});
|
||||
|
||||
test('modal: card - Custom, Stacked, Mobile', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/modal/test/card?ionic:_testing=true' });
|
||||
|
||||
const screenshotCompares = [];
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#card-custom');
|
||||
await page.waitForSelector('#card-custom');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
screenshotCompares.push(await page.compareScreenshot());
|
||||
|
||||
await page.click('.add');
|
||||
await page.waitForSelector('.add');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
screenshotCompares.push(await page.compareScreenshot());
|
||||
});
|
51
core/src/components/modal/test/card/modal.e2e.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { test } from '@utils/test/playwright';
|
||||
|
||||
test.describe('card modal: rendering', () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
await page.goto('/src/components/modal/test/card');
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#card');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
expect(await page.screenshot()).toMatchSnapshot(`modal-card-present-${page.getSnapshotSettings()}.png`);
|
||||
});
|
||||
test('should not have visual regressions with custom modal', async ({ page }) => {
|
||||
await page.goto('/src/components/modal/test/card');
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#card-custom');
|
||||
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
expect(await page.screenshot()).toMatchSnapshot(`modal-card-custom-present-${page.getSnapshotSettings()}.png`);
|
||||
});
|
||||
test('should not have visual regressions with stacked cards', async ({ page }) => {
|
||||
await page.goto('/src/components/modal/test/card');
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#card');
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
await page.click('.add');
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
expect(await page.screenshot()).toMatchSnapshot(`modal-card-stacked-present-${page.getSnapshotSettings()}.png`);
|
||||
});
|
||||
test('should not have visual regressions with stacked custom cards', async ({ page }) => {
|
||||
await page.goto('/src/components/modal/test/card');
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await page.click('#card-custom');
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
await page.click('.add');
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
expect(await page.screenshot()).toMatchSnapshot(
|
||||
`modal-card-custom-stacked-present-${page.getSnapshotSettings()}.png`
|
||||
);
|
||||
});
|
||||
});
|
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 43 KiB |