test(modal): migrate to generators (#27331)

Issue number: N/A

---------

<!-- Please refer to our contributing documentation for any questions on
submitting a pull request, or let us know here if you need any help:
https://ionicframework.com/docs/building/contributing -->

<!-- Some docs updates need to be made in the `ionic-docs` repo, in a
separate PR. See
https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#modifying-documentation
for details. -->

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

Modal tests are using legacy syntax

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Modal tests use generator syntax


e3e83ef92f

- This had an unused screenshot test, so I removed it

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->


Note: Some of these tests are quite slow, so you may see a CI slowdown
if this merges. However, I am working on addressing this in
https://github.com/ionic-team/ionic-framework/pull/27397.
This commit is contained in:
Liam DeBeasi
2023-05-08 08:53:42 -04:00
committed by GitHub
parent 759f0f8a55
commit c67a0f2fb7
167 changed files with 1303 additions and 1308 deletions

View File

@ -1,39 +0,0 @@
import AxeBuilder from '@axe-core/playwright';
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('modal: a11y', () => {
test.beforeEach(async ({ skip }) => {
skip.rtl();
skip.mode('md');
});
test('should not have accessibility violations', async ({ page }) => {
await page.goto(`/src/components/modal/test/a11y`);
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const button = page.locator('#open-modal');
const modal = page.locator('ion-modal .modal-wrapper');
await expect(modal).toHaveAttribute('role', 'dialog');
await button.click();
await ionModalDidPresent.next();
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
test('should allow for custom role', async ({ page }) => {
/**
* Note: This example should not be used in production.
* This only serves to check that `role` can be customized.
*/
await page.setContent(`
<ion-modal role="alertdialog"></ion-modal>
`);
const modal = page.locator('ion-modal .modal-wrapper');
await expect(modal).toHaveAttribute('role', 'alertdialog');
});
});

View File

@ -0,0 +1,39 @@
import AxeBuilder from '@axe-core/playwright';
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('modal: a11y'), () => {
test('should not have accessibility violations', async ({ page }) => {
await page.goto(`/src/components/modal/test/a11y`, config);
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const button = page.locator('#open-modal');
const modal = page.locator('ion-modal .modal-wrapper');
await expect(modal).toHaveAttribute('role', 'dialog');
await button.click();
await ionModalDidPresent.next();
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
test('should allow for custom role', async ({ page }) => {
/**
* Note: This example should not be used in production.
* This only serves to check that `role` can be customized.
*/
await page.setContent(
`
<ion-modal role="alertdialog"></ion-modal>
`,
config
);
const modal = page.locator('ion-modal .modal-wrapper');
await expect(modal).toHaveAttribute('role', 'alertdialog');
});
});
});

View File

@ -1,184 +0,0 @@
import { expect } from '@playwright/test';
import { test, Viewports } from '@utils/test/playwright';
import type { E2EPage } from '@utils/test/playwright';
test.describe('modal: focus trapping', () => {
test.beforeEach(async ({ skip }) => {
skip.rtl();
skip.mode('md');
skip.browser('firefox', 'Firefox incorrectly allows keyboard focus to move to ion-content');
});
test('focus should be trapped inside of modal', async ({ page, browserName }) => {
/**
* 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.
*/
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
await page.goto('/src/components/modal/test/basic');
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#basic-modal');
await ionModalDidPresent.next();
const dismissButton = page.locator('ion-button.dismiss');
await page.keyboard.press(tabKey);
await expect(dismissButton).toBeFocused();
await page.keyboard.press(`Shift+${tabKey}`);
await expect(dismissButton).toBeFocused();
await page.keyboard.press(tabKey);
await 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 = page.locator('#basic-modal');
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
// Focus #basic-modal button
await page.keyboard.press(tabKey);
await expect(modalButton).toBeFocused();
await page.keyboard.press('Space');
await ionModalDidPresent.next();
await page.keyboard.press('Escape');
await ionModalDidDismiss.next();
await expect(modalButton).toBeFocused();
});
});
test.describe('modal: rendering', () => {
const runVisualTests = async (page: E2EPage, screenshotModifier = '') => {
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 = page.locator('ion-modal');
await expect(modal).toHaveClass(/show-modal/);
await page.setIonViewport();
await expect(page).toHaveScreenshot(`modal-basic-present-${screenshotModifier}${page.getSnapshotSettings()}.png`);
await modal.evaluate((el: HTMLIonModalElement) => {
el.dismiss();
});
await ionModalWillDismiss.next();
await ionModalDidDismiss.next();
await expect(modal).not.toHaveClass(/show-modal/);
await expect(modal).toBeHidden();
};
test('should not have visual regressions', async ({ page }) => {
await runVisualTests(page);
});
test('should not have visual regressions with tablet viewport', async ({ page }) => {
await page.setViewportSize(Viewports.tablet.portrait);
await runVisualTests(page, 'tablet-');
});
});
test.describe('modal: htmlAttributes inheritance', () => {
test('should correctly inherit attributes on host', async ({ page, skip }) => {
skip.rtl();
skip.mode('md');
await page.goto('/src/components/modal/test/basic');
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#basic-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const attribute = await modal.getAttribute('data-testid');
expect(attribute).toBe('basic-modal');
});
});
test.describe('modal: backdrop', () => {
test.beforeEach(async ({ page, skip }) => {
skip.rtl();
skip.mode('md');
await page.goto('/src/components/modal/test/basic');
});
test('it should dismiss the modal when clicking the backdrop', async ({ page }) => {
await page.setViewportSize(Viewports.tablet.portrait);
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, skip }) => {
skip.rtl();
skip.mode('md');
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 = 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 = page.locator('ion-modal');
const breakpoint = await modal.evaluate((el: HTMLIonModalElement) => {
return el.getCurrentBreakpoint();
});
expect(breakpoint).toBe(undefined);
});
});

View File

@ -0,0 +1,181 @@
import { expect } from '@playwright/test';
import { configs, test, Viewports } from '@utils/test/playwright';
import type { E2EPage } from '@utils/test/playwright';
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('modal: focus trapping'), () => {
test.beforeEach(async ({ skip }) => {
skip.browser('firefox', 'Firefox incorrectly allows keyboard focus to move to ion-content');
});
test('focus should be trapped inside of modal', async ({ page, browserName }) => {
/**
* 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.
*/
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
await page.goto('/src/components/modal/test/basic', config);
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#basic-modal');
await ionModalDidPresent.next();
const dismissButton = page.locator('ion-button.dismiss');
await page.keyboard.press(tabKey);
await expect(dismissButton).toBeFocused();
await page.keyboard.press(`Shift+${tabKey}`);
await expect(dismissButton).toBeFocused();
await page.keyboard.press(tabKey);
await 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', config);
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
const modalButton = page.locator('#basic-modal');
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
// Focus #basic-modal button
await page.keyboard.press(tabKey);
await expect(modalButton).toBeFocused();
await page.keyboard.press('Space');
await ionModalDidPresent.next();
await page.keyboard.press('Escape');
await ionModalDidDismiss.next();
await expect(modalButton).toBeFocused();
});
});
});
configs().forEach(({ title, screenshot, config }) => {
test.describe(title('modal: rendering'), () => {
const runVisualTests = async (page: E2EPage, screenshotModifier = '') => {
await page.goto('/src/components/modal/test/basic', config);
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 = page.locator('ion-modal');
await expect(modal).toHaveClass(/show-modal/);
await page.setIonViewport();
await expect(page).toHaveScreenshot(screenshot(`modal-basic-present${screenshotModifier}`));
await modal.evaluate((el: HTMLIonModalElement) => {
el.dismiss();
});
await ionModalWillDismiss.next();
await ionModalDidDismiss.next();
await expect(modal).not.toHaveClass(/show-modal/);
await expect(modal).toBeHidden();
};
test('should not have visual regressions', async ({ page }) => {
await runVisualTests(page);
});
test('should not have visual regressions with tablet viewport', async ({ page }) => {
await page.setViewportSize(Viewports.tablet.portrait);
await runVisualTests(page, '-tablet');
});
});
});
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('modal: htmlAttributes inheritance'), () => {
test('should correctly inherit attributes on host', async ({ page }) => {
await page.goto('/src/components/modal/test/basic', config);
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#basic-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const attribute = await modal.getAttribute('data-testid');
expect(attribute).toBe('basic-modal');
});
});
test.describe(title('modal: backdrop'), () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/modal/test/basic', config);
});
test('it should dismiss the modal when clicking the backdrop', async ({ page }) => {
await page.setViewportSize(Viewports.tablet.portrait);
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(title('modal: incorrect usage'), () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/modal/test/basic', config);
});
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 = 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 = page.locator('ion-modal');
const breakpoint = await modal.evaluate((el: HTMLIonModalElement) => {
return el.getCurrentBreakpoint();
});
expect(breakpoint).toBe(undefined);
});
});
});

View File

@ -1,425 +0,0 @@
import { expect } from '@playwright/test';
import { test, dragElementBy } from '@utils/test/playwright';
test.describe('modal: canDismiss', () => {
test.describe('regular modal', () => {
test.beforeEach(async ({ page, skip }) => {
skip.rtl();
await page.goto('/src/components/modal/test/can-dismiss');
});
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 = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is false', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
test('should dismiss when canDismiss is Promise<true>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is Promise<false>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
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');
await page.click('#radio-action-sheet');
await page.click('#show-modal');
await ionModalDidPresent.next();
await page.keyboard.press('Escape');
await ionActionSheetDidPresent.next();
await page.click('.button-confirm');
await ionModalDidDismiss.next();
});
});
test.describe('card modal', () => {
test.beforeEach(async ({ page, skip }) => {
skip.rtl();
skip.mode('md');
await page.goto('/src/components/modal/test/can-dismiss');
await page.click('#radio-card');
});
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 = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is false', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
test('should dismiss when canDismiss is Promise<true>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is Promise<false>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
});
test.describe('card modal - iOS swiping', () => {
test.beforeEach(async ({ page, skip }) => {
skip.rtl();
skip.mode('md');
await page.goto('/src/components/modal/test/can-dismiss');
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');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('ion-modal #modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionModalDidDismiss.next();
});
test('should not dismiss on swipe when canDismiss is false', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
const modal = page.locator('ion-modal');
expect(modal).not.toBe(null);
});
test('should dismiss on swipe when canDismiss is Promise<true>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionModalDidDismiss.next();
});
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');
await page.click('#radio-promise-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionHandlerDone.next();
const modal = page.locator('ion-modal');
expect(modal).not.toBe(null);
});
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');
await page.click('#radio-action-sheet');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionActionSheetDidPresent.next();
await page.click('.button-confirm');
await ionModalDidDismiss.next();
});
});
test.describe('sheet modal', () => {
test.beforeEach(async ({ page, skip }) => {
skip.rtl();
await page.goto('/src/components/modal/test/can-dismiss');
await page.click('#radio-sheet');
});
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 = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is false', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
test('should dismiss when canDismiss is Promise<true>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is Promise<false>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
test('should dismiss on swipe when canDismiss is true', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionModalDidDismiss.next();
});
test('should not dismiss on swipe when canDismiss is false', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
const modal = page.locator('ion-modal');
expect(modal).not.toBe(null);
});
test('should dismiss on swipe when canDismiss is Promise<true>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionModalDidDismiss.next();
});
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');
await page.click('#radio-promise-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionHandlerDone.next();
const modal = page.locator('ion-modal');
expect(modal).not.toBe(null);
});
test('should not dismiss on swipe when not attempting to close', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, -500);
const modal = page.locator('ion-modal');
expect(modal).not.toBe(null);
});
test('should hit the dismiss threshold when swiping', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 100);
await ionModalDidDismiss.next();
});
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');
await page.click('#radio-action-sheet');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionActionSheetDidPresent.next();
await page.click('.button-confirm');
await ionModalDidDismiss.next();
});
});
test.describe('function params', () => {
test.beforeEach(async ({ page, skip }) => {
skip.mode('md');
skip.rtl();
await page.goto('/src/components/modal/test/can-dismiss');
});
test('should pass data and role when calling dismiss', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionHandlerDone = await page.spyOnEvent('ionHandlerDone');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
await modal.evaluate((el: HTMLIonModalElement) => el.dismiss('my data', 'my role'));
await ionHandlerDone.next();
await expect(ionHandlerDone).toHaveReceivedEventDetail({ data: 'my data', role: 'my role' });
});
test('should pass data and role when swiping', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionHandlerDone = await page.spyOnEvent('ionHandlerDone');
await page.click('#radio-card');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionHandlerDone.next();
await expect(ionHandlerDone).toHaveReceivedEventDetail({ data: undefined, role: 'gesture' });
});
});
});

View File

@ -0,0 +1,422 @@
import { expect } from '@playwright/test';
import { configs, test, dragElementBy } from '@utils/test/playwright';
/**
* This behavior does not vary across modes/directions
*/
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('modal: canDismiss'), () => {
test.describe('regular modal', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/modal/test/can-dismiss', config);
});
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 = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is false', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
test('should dismiss when canDismiss is Promise<true>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is Promise<false>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
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');
await page.click('#radio-action-sheet');
await page.click('#show-modal');
await ionModalDidPresent.next();
await page.keyboard.press('Escape');
await ionActionSheetDidPresent.next();
await page.click('.button-confirm');
await ionModalDidDismiss.next();
});
});
test.describe('card modal', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/modal/test/can-dismiss', config);
await page.click('#radio-card');
});
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 = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is false', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
test('should dismiss when canDismiss is Promise<true>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is Promise<false>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
});
test.describe('card modal - iOS swiping', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/modal/test/can-dismiss', config);
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');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('ion-modal #modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionModalDidDismiss.next();
});
test('should not dismiss on swipe when canDismiss is false', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
const modal = page.locator('ion-modal');
expect(modal).not.toBe(null);
});
test('should dismiss on swipe when canDismiss is Promise<true>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionModalDidDismiss.next();
});
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');
await page.click('#radio-promise-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionHandlerDone.next();
const modal = page.locator('ion-modal');
expect(modal).not.toBe(null);
});
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');
await page.click('#radio-action-sheet');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionActionSheetDidPresent.next();
await page.click('.button-confirm');
await ionModalDidDismiss.next();
});
});
test.describe('sheet modal', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/modal/test/can-dismiss', config);
await page.click('#radio-sheet');
});
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 = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is false', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
test('should dismiss when canDismiss is Promise<true>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(true);
});
test('should not dismiss when canDismiss is Promise<false>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const returnValue = await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
expect(returnValue).toBe(false);
});
test('should dismiss on swipe when canDismiss is true', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionModalDidDismiss.next();
});
test('should not dismiss on swipe when canDismiss is false', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
const modal = page.locator('ion-modal');
expect(modal).not.toBe(null);
});
test('should dismiss on swipe when canDismiss is Promise<true>', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionModalDidDismiss.next();
});
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');
await page.click('#radio-promise-false');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionHandlerDone.next();
const modal = page.locator('ion-modal');
expect(modal).not.toBe(null);
});
test('should not dismiss on swipe when not attempting to close', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, -500);
const modal = page.locator('ion-modal');
expect(modal).not.toBe(null);
});
test('should hit the dismiss threshold when swiping', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 100);
await ionModalDidDismiss.next();
});
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');
await page.click('#radio-action-sheet');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionActionSheetDidPresent.next();
await page.click('.button-confirm');
await ionModalDidDismiss.next();
});
});
test.describe('function params', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/modal/test/can-dismiss', config);
});
test('should pass data and role when calling dismiss', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionHandlerDone = await page.spyOnEvent('ionHandlerDone');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
await modal.evaluate((el: HTMLIonModalElement) => el.dismiss('my data', 'my role'));
await ionHandlerDone.next();
await expect(ionHandlerDone).toHaveReceivedEventDetail({ data: 'my data', role: 'my role' });
});
test('should pass data and role when swiping', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionHandlerDone = await page.spyOnEvent('ionHandlerDone');
await page.click('#radio-card');
await page.click('#radio-promise-true');
await page.click('#show-modal');
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 500);
await ionHandlerDone.next();
await expect(ionHandlerDone).toHaveReceivedEventDetail({ data: undefined, role: 'gesture' });
});
});
});
});

View File

@ -1,50 +0,0 @@
import { expect } from '@playwright/test';
import { test, dragElementBy } from '@utils/test/playwright';
import { CardModalPage } from '../fixtures';
test.describe('card modal - nav', () => {
let cardModalPage: CardModalPage;
test.beforeEach(async ({ page, skip }) => {
skip.mode('md');
skip.rtl('This test only verifies that the gesture activates inside of a modal.');
skip.browser(
(browserName: string) => browserName !== 'chromium',
'dragElementBy is flaky outside of Chrome browsers.'
);
cardModalPage = new CardModalPage(page);
await cardModalPage.navigate('/src/components/modal/test/card-nav?ionic:_testing=false');
});
test('it should swipe to go back', async ({ page }) => {
await cardModalPage.openModalByTrigger('#open-modal');
const nav = page.locator('ion-nav') as any;
const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
await page.click('#go-page-two');
await ionNavDidChange.next();
const pageOne = page.locator('page-one');
await expect(pageOne).toHaveClass(/ion-page-hidden/);
const content = page.locator('.page-two-content');
await dragElementBy(content, page, 1000, 0, 10);
await ionNavDidChange.next();
});
test('should swipe to close', async ({ page }) => {
await cardModalPage.openModalByTrigger('#open-modal');
const nav = page.locator('ion-nav') as any;
const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
await page.click('#go-page-two');
await ionNavDidChange.next();
await cardModalPage.swipeToCloseModal('ion-modal ion-content.page-two-content');
});
});

View File

@ -0,0 +1,53 @@
import { expect } from '@playwright/test';
import { configs, test, dragElementBy } from '@utils/test/playwright';
import { CardModalPage } from '../fixtures';
/**
* This test only verifies that the gesture activates inside of a modal.
*/
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('card modal - nav'), () => {
let cardModalPage: CardModalPage;
test.beforeEach(async ({ page, skip }) => {
skip.browser(
(browserName: string) => browserName !== 'chromium',
'dragElementBy is flaky outside of Chrome browsers.'
);
cardModalPage = new CardModalPage(page);
await cardModalPage.navigate('/src/components/modal/test/card-nav?ionic:_testing=false', config);
});
test('it should swipe to go back', async ({ page }) => {
await cardModalPage.openModalByTrigger('#open-modal');
const nav = page.locator('ion-nav') as any;
const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
await page.click('#go-page-two');
await ionNavDidChange.next();
const pageOne = page.locator('page-one');
await expect(pageOne).toHaveClass(/ion-page-hidden/);
const content = page.locator('.page-two-content');
await dragElementBy(content, page, 1000, 0, 10);
await ionNavDidChange.next();
});
test('should swipe to close', async ({ page }) => {
await cardModalPage.openModalByTrigger('#open-modal');
const nav = page.locator('ion-nav') as any;
const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
await page.click('#go-page-two');
await ionNavDidChange.next();
await cardModalPage.swipeToCloseModal('ion-modal ion-content.page-two-content');
});
});
});

View File

@ -1,26 +0,0 @@
import { expect } from '@playwright/test';
import { dragElementBy, test } from '@utils/test/playwright';
test.describe('card modal - with refresher', () => {
test.beforeEach(async ({ page, skip }) => {
skip.mode('md');
skip.rtl();
await page.goto('/src/components/modal/test/card-refresher');
});
test('it should not swipe to close on the content due to the presence of the refresher', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#card');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const content = (await page.$('ion-modal ion-content'))!;
await dragElementBy(content, page, 0, 500);
await content.waitForElementState('stable');
await expect(modal).toBeVisible();
});
});

View File

@ -0,0 +1,25 @@
import { expect } from '@playwright/test';
import { configs, dragElementBy, test } from '@utils/test/playwright';
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('card modal - with refresher'), () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/modal/test/card-refresher', config);
});
test('it should not swipe to close on the content due to the presence of the refresher', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#card');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const content = (await page.$('ion-modal ion-content'))!;
await dragElementBy(content, page, 0, 500);
await content.waitForElementState('stable');
await expect(modal).toBeVisible();
});
});
});

View File

@ -1,53 +0,0 @@
import { expect } from '@playwright/test';
import { dragElementBy, test } from '@utils/test/playwright';
test.describe('card modal - scroll target', () => {
test.beforeEach(async ({ page, skip }) => {
skip.mode('md');
skip.rtl();
await page.goto('/src/components/modal/test/card-scroll-target');
});
test.describe('card modal: swipe to close', () => {
test('it should swipe to close when swiped on the content', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
await page.click('#card');
await ionModalDidPresent.next();
const content = page.locator('ion-modal .ion-content-scroll-host');
await dragElementBy(content, page, 0, 500);
await ionModalDidDismiss.next();
});
test('it should not swipe to close when swiped on the content but the content is scrolled', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#card');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const content = (await page.$('ion-modal .ion-content-scroll-host'))!;
await content.evaluate((el: HTMLElement) => (el.scrollTop = 500));
await dragElementBy(content, page, 0, 500);
await content.waitForElementState('stable');
await expect(modal).toBeVisible();
});
test('content should be scrollable after gesture ends', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#card');
await ionModalDidPresent.next();
const content = page.locator('ion-modal .ion-content-scroll-host');
await dragElementBy(content, page, 0, 20);
await expect(content).not.toHaveCSS('overflow', 'hidden');
});
});
});

View File

@ -0,0 +1,52 @@
import { expect } from '@playwright/test';
import { configs, dragElementBy, test } from '@utils/test/playwright';
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('card modal - scroll target'), () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/modal/test/card-scroll-target', config);
});
test.describe('card modal: swipe to close', () => {
test('it should swipe to close when swiped on the content', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
await page.click('#card');
await ionModalDidPresent.next();
const content = page.locator('ion-modal .ion-content-scroll-host');
await dragElementBy(content, page, 0, 500);
await ionModalDidDismiss.next();
});
test('it should not swipe to close when swiped on the content but the content is scrolled', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#card');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const content = (await page.$('ion-modal .ion-content-scroll-host'))!;
await content.evaluate((el: HTMLElement) => (el.scrollTop = 500));
await dragElementBy(content, page, 0, 500);
await content.waitForElementState('stable');
await expect(modal).toBeVisible();
});
test('content should be scrollable after gesture ends', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#card');
await ionModalDidPresent.next();
const content = page.locator('ion-modal .ion-content-scroll-host');
await dragElementBy(content, page, 0, 20);
await expect(content).not.toHaveCSS('overflow', 'hidden');
});
});
});
});

View File

@ -1,49 +1,48 @@
import { expect } from '@playwright/test';
import { test, Viewports } from '@utils/test/playwright';
import { configs, test, Viewports } from '@utils/test/playwright';
import { CardModalPage } from '../fixtures';
test.describe('card modal', () => {
test.beforeEach(async ({ skip }) => {
skip.mode('md');
});
test.describe('card modal: rendering', () => {
configs({ modes: ['ios'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('card modal: rendering'), () => {
let cardModalPage: CardModalPage;
test.beforeEach(async ({ page }) => {
cardModalPage = new CardModalPage(page);
await cardModalPage.navigate('/src/components/modal/test/card');
await cardModalPage.navigate('/src/components/modal/test/card', config);
});
test('should not have visual regressions', async ({ page }) => {
await cardModalPage.openModalByTrigger('#card');
await expect(page).toHaveScreenshot(`modal-card-present-${page.getSnapshotSettings()}.png`);
await expect(page).toHaveScreenshot(screenshot(`modal-card-present`));
});
test('should not have visual regressions with custom modal', async ({ page }) => {
await cardModalPage.openModalByTrigger('#card-custom');
await expect(page).toHaveScreenshot(`modal-card-custom-present-${page.getSnapshotSettings()}.png`);
await expect(page).toHaveScreenshot(screenshot(`modal-card-custom-present`));
});
test('should not have visual regressions with stacked cards', async ({ page }) => {
await cardModalPage.openModalByTrigger('#card');
await cardModalPage.openModalByTrigger('.add');
await expect(page).toHaveScreenshot(`modal-card-stacked-present-${page.getSnapshotSettings()}.png`);
await expect(page).toHaveScreenshot(screenshot(`modal-card-stacked-present`));
});
test('should not have visual regressions with stacked custom cards', async ({ page }) => {
await cardModalPage.openModalByTrigger('#card-custom');
await cardModalPage.openModalByTrigger('.add');
await expect(page).toHaveScreenshot(`modal-card-custom-stacked-present-${page.getSnapshotSettings()}.png`);
await expect(page).toHaveScreenshot(screenshot(`modal-card-custom-stacked-present`));
});
});
test.describe('card modal: functionality', () => {
});
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('card modal: functionality'), () => {
let cardModalPage: CardModalPage;
test.beforeEach(async ({ page, skip }) => {
skip.rtl();
test.beforeEach(async ({ page }) => {
cardModalPage = new CardModalPage(page);
await cardModalPage.navigate('/src/components/modal/test/card');
await cardModalPage.navigate('/src/components/modal/test/card', config);
});
test.describe('card modal: swipe to close', () => {
test.describe(title('card modal: swipe to close'), () => {
test('it should swipe to close when swiped on the header', async () => {
await cardModalPage.openModalByTrigger('#card');
await cardModalPage.swipeToCloseModal('ion-modal ion-header');
@ -86,36 +85,34 @@ test.describe('card modal', () => {
await expect(content).toHaveJSProperty('scrollY', true);
});
});
test.describe('card modal: rendering - tablet', () => {
test.describe(title('card modal: rendering - tablet'), () => {
test.beforeEach(async ({ page }) => {
await page.setViewportSize(Viewports.tablet.portrait);
});
test('should not have visual regressions', async ({ page }) => {
await cardModalPage.openModalByTrigger('#card');
await expect(page).toHaveScreenshot(`modal-card-present-tablet-${page.getSnapshotSettings()}.png`);
await expect(page).toHaveScreenshot(screenshot(`modal-card-present-tablet`));
});
test('should not have visual regressions with custom modal', async ({ page }) => {
await cardModalPage.openModalByTrigger('#card-custom');
await expect(page).toHaveScreenshot(`modal-card-custom-present-tablet-${page.getSnapshotSettings()}.png`);
await expect(page).toHaveScreenshot(screenshot(`modal-card-custom-present-tablet`));
});
test('should not have visual regressions with stacked cards', async ({ page }) => {
await cardModalPage.openModalByTrigger('#card');
await cardModalPage.openModalByTrigger('.add');
await expect(page).toHaveScreenshot(`modal-card-stacked-present-tablet-${page.getSnapshotSettings()}.png`);
await expect(page).toHaveScreenshot(screenshot(`modal-card-stacked-present-tablet`));
});
test('should not have visual regressions with stacked custom cards', async ({ page }) => {
await cardModalPage.openModalByTrigger('#card-custom');
await cardModalPage.openModalByTrigger('.add');
await expect(page).toHaveScreenshot(
`modal-card-custom-stacked-present-tablet-${page.getSnapshotSettings()}.png`
);
await expect(page).toHaveScreenshot(screenshot(`modal-card-custom-stacked-present-tablet`));
});
});
test.describe('card modal: swipe to close - tablet', () => {
test.describe(title('card modal: swipe to close - tablet'), () => {
test.beforeEach(async ({ page }) => {
await page.setViewportSize(Viewports.tablet.portrait);
});

Some files were not shown because too many files have changed in this diff Show More