test(toast): migrate tests to playwright (#25751)
@ -1,44 +0,0 @@
|
|||||||
import { AxePuppeteer } from '@axe-core/puppeteer';
|
|
||||||
import { newE2EPage } from '@stencil/core/testing';
|
|
||||||
|
|
||||||
describe('toast accessibility tests', () => {
|
|
||||||
test('it should not have any axe violations with polite toasts', async () => {
|
|
||||||
const page = await newE2EPage({
|
|
||||||
url: '/src/components/toast/test/a11y?ionic:_testing=true',
|
|
||||||
});
|
|
||||||
|
|
||||||
const ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent');
|
|
||||||
|
|
||||||
await page.click('#polite');
|
|
||||||
|
|
||||||
await ionToastDidPresent.next();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IonToast overlays the entire screen, so
|
|
||||||
* Axe will be unable to verify color contrast
|
|
||||||
* on elements under the toast.
|
|
||||||
*/
|
|
||||||
const results = await new AxePuppeteer(page).disableRules('color-contrast').analyze();
|
|
||||||
expect(results.violations.length).toEqual(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('it should not have any axe violations with assertive toasts', async () => {
|
|
||||||
const page = await newE2EPage({
|
|
||||||
url: '/src/components/toast/test/a11y?ionic:_testing=true',
|
|
||||||
});
|
|
||||||
|
|
||||||
const ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent');
|
|
||||||
|
|
||||||
await page.click('#assertive');
|
|
||||||
|
|
||||||
await ionToastDidPresent.next();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IonToast overlays the entire screen, so
|
|
||||||
* Axe will be unable to verify color contrast
|
|
||||||
* on elements under the toast.
|
|
||||||
*/
|
|
||||||
const results = await new AxePuppeteer(page).disableRules('color-contrast').analyze();
|
|
||||||
expect(results.violations.length).toEqual(0);
|
|
||||||
});
|
|
||||||
});
|
|
42
core/src/components/toast/test/a11y/toast.e2e.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import AxeBuilder from '@axe-core/playwright';
|
||||||
|
import { expect } from '@playwright/test';
|
||||||
|
import { test } from '@utils/test/playwright';
|
||||||
|
|
||||||
|
test.describe('toast: a11y', () => {
|
||||||
|
test.beforeEach(async ({ page }, testInfo) => {
|
||||||
|
test.skip(testInfo.project.metadata.rtl === true, 'This test does not check LTR vs RTL layouts');
|
||||||
|
await page.goto(`/src/components/toast/test/a11y`);
|
||||||
|
});
|
||||||
|
test('should not have any axe violations with polite toasts', async ({ page }) => {
|
||||||
|
const ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent');
|
||||||
|
|
||||||
|
const politeButton = page.locator('#polite');
|
||||||
|
await politeButton.click();
|
||||||
|
|
||||||
|
await ionToastDidPresent.next();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IonToast overlays the entire screen, so
|
||||||
|
* Axe will be unable to verify color contrast
|
||||||
|
* on elements under the toast.
|
||||||
|
*/
|
||||||
|
const results = await new AxeBuilder({ page }).disableRules('color-contrast').analyze();
|
||||||
|
expect(results.violations).toEqual([]);
|
||||||
|
});
|
||||||
|
test('should not have any axe violations with assertive toasts', async ({ page }) => {
|
||||||
|
const ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent');
|
||||||
|
|
||||||
|
const politeButton = page.locator('#assertive');
|
||||||
|
await politeButton.click();
|
||||||
|
|
||||||
|
await ionToastDidPresent.next();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IonToast overlays the entire screen, so
|
||||||
|
* Axe will be unable to verify color contrast
|
||||||
|
* on elements under the toast.
|
||||||
|
*/
|
||||||
|
const results = await new AxeBuilder({ page }).disableRules('color-contrast').analyze();
|
||||||
|
expect(results.violations).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
@ -1,123 +0,0 @@
|
|||||||
import { newE2EPage } from '@stencil/core/testing';
|
|
||||||
|
|
||||||
import { testToast } from '../test.utils';
|
|
||||||
|
|
||||||
const DIRECTORY = 'basic';
|
|
||||||
|
|
||||||
test('toast: basic, bottom', async () => {
|
|
||||||
await testToast(DIRECTORY, '#show-bottom-toast');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: basic, middle', async () => {
|
|
||||||
await testToast(DIRECTORY, '#show-middle-toast');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: basic, top', async () => {
|
|
||||||
await testToast(DIRECTORY, '#show-top-toast');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: basic, two lines', async () => {
|
|
||||||
await testToast(DIRECTORY, '#two-line-toast');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: basic, close button', async () => {
|
|
||||||
await testToast(DIRECTORY, '#close-button-toast');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: basic, custom close text', async () => {
|
|
||||||
await testToast(DIRECTORY, '#custom-close-text-toast');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: basic, custom buttons', async () => {
|
|
||||||
await testToast(DIRECTORY, '#custom-action-buttons-toast');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: basic, translucent', async () => {
|
|
||||||
await testToast(DIRECTORY, '#translucent-toast');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: basic, color', async () => {
|
|
||||||
await testToast(DIRECTORY, '#color-toast');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: basic, custom class', async () => {
|
|
||||||
await testToast(DIRECTORY, '#custom-class-toast');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: start end position', async () => {
|
|
||||||
await testToast(DIRECTORY, '#toast-start-and-end');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: html', async () => {
|
|
||||||
await testToast(DIRECTORY, '#toast-html');
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RTL Tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
test('toast:rtl: basic, bottom', async () => {
|
|
||||||
await testToast(DIRECTORY, '#show-bottom-toast', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: basic, middle', async () => {
|
|
||||||
await testToast(DIRECTORY, '#show-middle-toast', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: basic, top', async () => {
|
|
||||||
await testToast(DIRECTORY, '#show-top-toast', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: basic, two lines', async () => {
|
|
||||||
await testToast(DIRECTORY, '#two-line-toast', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: basic, close button', async () => {
|
|
||||||
await testToast(DIRECTORY, '#close-button-toast', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: basic, custom close text', async () => {
|
|
||||||
await testToast(DIRECTORY, '#custom-close-text-toast', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: basic, custom buttons', async () => {
|
|
||||||
await testToast(DIRECTORY, '#custom-action-buttons-toast');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: basic, translucent', async () => {
|
|
||||||
await testToast(DIRECTORY, '#translucent-toast', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: basic, color', async () => {
|
|
||||||
await testToast(DIRECTORY, '#color-toast', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: basic, custom class', async () => {
|
|
||||||
await testToast(DIRECTORY, '#custom-class-toast', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: start end position', async () => {
|
|
||||||
await testToast(DIRECTORY, '#toast-start-and-end', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: html', async () => {
|
|
||||||
await testToast(DIRECTORY, '#toast-html', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Attributes
|
|
||||||
|
|
||||||
test('toast: htmlAttributes', async () => {
|
|
||||||
const page = await newE2EPage({ url: '/src/components/toast/test/basic?ionic:_testing=true' });
|
|
||||||
|
|
||||||
await page.click('#show-bottom-toast');
|
|
||||||
await page.waitForSelector('#show-bottom-toast');
|
|
||||||
|
|
||||||
const toast = await page.find('ion-toast');
|
|
||||||
|
|
||||||
expect(toast).not.toBe(null);
|
|
||||||
await toast.waitForVisible();
|
|
||||||
|
|
||||||
const attribute = await page.evaluate(() => document.querySelector('ion-toast').getAttribute('data-testid'));
|
|
||||||
|
|
||||||
expect(attribute).toEqual('basic-toast');
|
|
||||||
});
|
|
@ -67,7 +67,7 @@
|
|||||||
<ion-button
|
<ion-button
|
||||||
expand="block"
|
expand="block"
|
||||||
id="two-line-toast"
|
id="two-line-toast"
|
||||||
onclick="openToast({message: 'Two-line message\nwith action.', buttons: ['Action'] })"
|
onclick="openToast({message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum in elit varius, maximus sem in, bibendum justo.', buttons: ['Action'] })"
|
||||||
>
|
>
|
||||||
Long Message
|
Long Message
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
136
core/src/components/toast/test/basic/toast.e2e.ts
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import { expect } from '@playwright/test';
|
||||||
|
import type { Locator, TestInfo } from '@playwright/test';
|
||||||
|
import type { E2EPage, EventSpy } from '@utils/test/playwright';
|
||||||
|
import { test } from '@utils/test/playwright';
|
||||||
|
|
||||||
|
class ToastFixture {
|
||||||
|
readonly page: E2EPage;
|
||||||
|
readonly testInfo: TestInfo;
|
||||||
|
|
||||||
|
private ionToastDidPresent!: EventSpy;
|
||||||
|
|
||||||
|
constructor(page: E2EPage, testInfo: TestInfo) {
|
||||||
|
this.page = page;
|
||||||
|
this.testInfo = testInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
async goto() {
|
||||||
|
const { page } = this;
|
||||||
|
await page.goto(`/src/components/toast/test/basic`);
|
||||||
|
this.ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent');
|
||||||
|
}
|
||||||
|
|
||||||
|
async openToast(selector: string) {
|
||||||
|
const { page, ionToastDidPresent } = this;
|
||||||
|
const button = page.locator(selector);
|
||||||
|
await button.click();
|
||||||
|
|
||||||
|
await ionToastDidPresent.next();
|
||||||
|
|
||||||
|
return {
|
||||||
|
toast: page.locator('ion-toast'),
|
||||||
|
container: page.locator('ion-toast .toast-container'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async screenshot(screenshotModifier: string, el?: Locator) {
|
||||||
|
const { page } = this;
|
||||||
|
|
||||||
|
const reference = el !== undefined ? el : page;
|
||||||
|
expect(await reference.screenshot()).toMatchSnapshot(
|
||||||
|
`toast-${screenshotModifier}-${page.getSnapshotSettings()}.png`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
skipRTL(testRef: typeof test, reason = 'This functionality does not have RTL-specific behaviors.') {
|
||||||
|
const { testInfo } = this;
|
||||||
|
testRef.skip(testInfo.project.metadata.rtl === true, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
skipMode(testRef: typeof test, mode: string, reason: string) {
|
||||||
|
const { testInfo } = this;
|
||||||
|
testRef.skip(testInfo.project.metadata.mode === mode, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test.describe('toast: rendering', () => {
|
||||||
|
let toastFixture: ToastFixture;
|
||||||
|
test.beforeEach(async ({ page }, testInfo) => {
|
||||||
|
toastFixture = new ToastFixture(page, testInfo);
|
||||||
|
await toastFixture.goto();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('toast: position', () => {
|
||||||
|
test.beforeEach(() => {
|
||||||
|
toastFixture.skipRTL(test);
|
||||||
|
});
|
||||||
|
test('should render toast at the top', async () => {
|
||||||
|
await toastFixture.openToast('#show-top-toast');
|
||||||
|
await toastFixture.screenshot('top');
|
||||||
|
});
|
||||||
|
test('should render toast at the middle', async () => {
|
||||||
|
await toastFixture.openToast('#show-middle-toast');
|
||||||
|
await toastFixture.screenshot('middle');
|
||||||
|
});
|
||||||
|
test('should render toast at the bottom', async () => {
|
||||||
|
await toastFixture.openToast('#show-bottom-toast');
|
||||||
|
await toastFixture.screenshot('bottom');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should set buttons correctly', async () => {
|
||||||
|
const { container } = await toastFixture.openToast('#custom-action-buttons-toast');
|
||||||
|
await toastFixture.screenshot('buttons', container);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should set start/end positioning correctly', async () => {
|
||||||
|
const { container } = await toastFixture.openToast('#toast-start-and-end');
|
||||||
|
await toastFixture.screenshot('start-end', container);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should wrap text correctly', async () => {
|
||||||
|
toastFixture.skipRTL(test);
|
||||||
|
const { container } = await toastFixture.openToast('#two-line-toast');
|
||||||
|
await toastFixture.screenshot('text', container);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should set color correctly', async () => {
|
||||||
|
toastFixture.skipRTL(test);
|
||||||
|
const { container } = await toastFixture.openToast('#color-toast');
|
||||||
|
await toastFixture.screenshot('color', container);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should set translucency correctly', async () => {
|
||||||
|
toastFixture.skipRTL(test);
|
||||||
|
toastFixture.skipMode(test, 'md', 'Translucency only works on iOS');
|
||||||
|
|
||||||
|
const { container } = await toastFixture.openToast('#translucent-toast');
|
||||||
|
await toastFixture.screenshot('translucent', container);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('toast: properties', () => {
|
||||||
|
let toastFixture: ToastFixture;
|
||||||
|
test.beforeEach(async ({ page }, testInfo) => {
|
||||||
|
toastFixture = new ToastFixture(page, testInfo);
|
||||||
|
|
||||||
|
toastFixture.skipMode(test, 'md', 'This functionality has no mode specific logic.');
|
||||||
|
toastFixture.skipRTL(test);
|
||||||
|
|
||||||
|
await toastFixture.goto();
|
||||||
|
});
|
||||||
|
test('should correctly set htmlAttributes', async () => {
|
||||||
|
const { toast } = await toastFixture.openToast('#show-bottom-toast');
|
||||||
|
await expect(toast).toHaveAttribute('data-testid', 'basic-toast');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should correctly set custom html', async () => {
|
||||||
|
const { toast } = await toastFixture.openToast('#toast-html');
|
||||||
|
await expect(toast.locator('ion-button')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should correctly set custom class', async () => {
|
||||||
|
const { toast } = await toastFixture.openToast('#custom-class-toast');
|
||||||
|
await expect(toast).toHaveClass(/my-custom-class/);
|
||||||
|
});
|
||||||
|
});
|
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 111 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 113 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 95 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 13 KiB |
@ -1,39 +0,0 @@
|
|||||||
import { testToast } from '../test.utils';
|
|
||||||
|
|
||||||
const DIRECTORY = 'buttons';
|
|
||||||
|
|
||||||
test('toast: buttons, close array', async () => {
|
|
||||||
await testToast(DIRECTORY, '#closeArray');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: buttons, two buttons', async () => {
|
|
||||||
await testToast(DIRECTORY, '#twoButtons');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: buttons, multiple buttons', async () => {
|
|
||||||
await testToast(DIRECTORY, '#multipleButtons');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast: buttons, long button', async () => {
|
|
||||||
await testToast(DIRECTORY, '#longButton');
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RTL Tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
test('toast:rtl: buttons, close array', async () => {
|
|
||||||
await testToast(DIRECTORY, '#closeArray', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: buttons, two buttons', async () => {
|
|
||||||
await testToast(DIRECTORY, '#twoButtons', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: buttons, multiple buttons', async () => {
|
|
||||||
await testToast(DIRECTORY, '#multipleButtons', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toast:rtl: buttons, long button', async () => {
|
|
||||||
await testToast(DIRECTORY, '#longButton', true);
|
|
||||||
});
|
|
@ -1,7 +0,0 @@
|
|||||||
import { testToast } from '../test.utils';
|
|
||||||
|
|
||||||
const DIRECTORY = 'standalone';
|
|
||||||
|
|
||||||
test('toast: standalone', async () => {
|
|
||||||
await testToast(DIRECTORY, '#basic-toast');
|
|
||||||
});
|
|
19
core/src/components/toast/test/standalone/toast.e2e.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { expect } from '@playwright/test';
|
||||||
|
import { test } from '@utils/test/playwright';
|
||||||
|
|
||||||
|
test.describe('toast: standalone', () => {
|
||||||
|
test.beforeEach(async ({ page }, testInfo) => {
|
||||||
|
test.skip(testInfo.project.metadata.rtl === true, 'This test does not check LTR vs RTL layouts');
|
||||||
|
await page.goto(`/src/components/toast/test/standalone`);
|
||||||
|
});
|
||||||
|
test('should not have visual regressions', async ({ page }) => {
|
||||||
|
const ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent');
|
||||||
|
|
||||||
|
const basicButton = page.locator('#basic-toast');
|
||||||
|
await basicButton.click();
|
||||||
|
|
||||||
|
await ionToastDidPresent.next();
|
||||||
|
|
||||||
|
expect(await page.screenshot()).toMatchSnapshot(`toast-standalone-${page.getSnapshotSettings()}.png`);
|
||||||
|
});
|
||||||
|
});
|
After Width: | Height: | Size: 113 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 116 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 87 KiB |