test(playwright): add new utilities for skipping tests (#25758)

This commit is contained in:
Liam DeBeasi
2022-08-16 08:18:42 -05:00
committed by GitHub
parent e750e33616
commit 79c65dc382
40 changed files with 222 additions and 145 deletions

View File

@ -33,12 +33,14 @@ const projects = [
{
name: 'Mobile Chrome',
use: {
browserName: 'chromium',
...devices['Pixel 5']
}
},
{
name: 'Mobile Safari',
use: {
browserName: 'webkit',
...devices['iPhone 12']
}
}

View File

@ -2,9 +2,9 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('accordion: a11y', () => {
test('accordions should be keyboard navigable', async ({ page, browserName }) => {
test('accordions should be keyboard navigable', async ({ page, skip, browserName }) => {
// TODO(FW-1764): remove skip once issue is resolved
test.skip(browserName === 'firefox', 'https://github.com/ionic-team/ionic-framework/issues/25529');
skip.browser('firefox', 'https://github.com/ionic-team/ionic-framework/issues/25529');
await page.goto(`/src/components/accordion/test/a11y`);
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';

View File

@ -10,8 +10,8 @@ test.describe('action sheet: basic', () => {
actionSheetFixture = new ActionSheetFixture(page);
});
test.describe('action sheet: data', () => {
test('should return data', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs. RTL layout.');
test('should return data', async ({ page, skip }) => {
skip.rtl();
const ionActionSheetDidDismiss = await page.spyOnEvent('ionActionSheetDidDismiss');
await actionSheetFixture.open('#buttonData');
@ -22,8 +22,8 @@ test.describe('action sheet: basic', () => {
await ionActionSheetDidDismiss.next();
expect(ionActionSheetDidDismiss).toHaveReceivedEventDetail({ data: { type: '1' }, role: undefined });
});
test('should return cancel button data', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs. RTL layout.');
test('should return cancel button data', async ({ page, skip }) => {
skip.rtl();
const ionActionSheetDidDismiss = await page.spyOnEvent('ionActionSheetDidDismiss');
await actionSheetFixture.open('#buttonData');
@ -36,8 +36,8 @@ test.describe('action sheet: basic', () => {
});
});
test.describe('action sheet: attributes', () => {
test('should set htmlAttributes', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs. RTL layout.');
test('should set htmlAttributes', async ({ page, skip }) => {
skip.rtl();
await actionSheetFixture.open('#basic');
const actionSheet = page.locator('ion-action-sheet');
@ -73,15 +73,15 @@ test.describe('action sheet: basic', () => {
await actionSheetFixture.open('#scrollWithoutCancel');
await actionSheetFixture.screenshot('scroll-without-cancel');
});
test('should open custom backdrop action sheet', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs. RTL layout.');
test('should open custom backdrop action sheet', async ({ page, skip }) => {
skip.rtl();
await actionSheetFixture.open('#customBackdrop');
const backdrop = page.locator('ion-action-sheet ion-backdrop');
expect(backdrop).toHaveCSS('opacity', '1');
});
test('should open alert from action sheet', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs. RTL layout.');
test('should open alert from action sheet', async ({ page, skip }) => {
skip.rtl();
const ionAlertDidPresent = await page.spyOnEvent('ionAlertDidPresent');
await actionSheetFixture.open('#alertFromActionSheet');
@ -89,8 +89,8 @@ test.describe('action sheet: basic', () => {
await ionAlertDidPresent.next();
});
test('should not dismiss action sheet when backdropDismiss: false', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs. RTL layout.');
test('should not dismiss action sheet when backdropDismiss: false', async ({ page, skip }) => {
skip.rtl();
await actionSheetFixture.open('#noBackdropDismiss');
const actionSheet = page.locator('ion-action-sheet');
@ -100,8 +100,8 @@ test.describe('action sheet: basic', () => {
});
});
test.describe('action sheet: focus trap', () => {
test('it should trap focus in action sheet', async ({ page, browserName }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs. RTL layout.');
test('it should trap focus in action sheet', async ({ page, skip, browserName }) => {
skip.rtl();
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
await actionSheetFixture.open('#basic');

View File

@ -2,12 +2,9 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('action sheet: translucent', () => {
test('should not have visual regressions', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.mode === 'md', 'Translucent effect is only active on iOS mode');
test.skip(
testInfo.project.metadata.rtl === true,
'This tests how the component is painted, not layout. RTL tests are not needed here'
);
test('should not have visual regressions', async ({ page, skip }) => {
skip.mode('md', 'Translucent effect is only active on iOS mode');
skip.rtl('This tests how the component is painted, not layout. RTL tests are not needed here');
await page.goto(`/src/components/action-sheet/test/translucent`);

View File

@ -14,11 +14,8 @@ test.describe('app: safe-area', () => {
expect(await page.screenshot()).toMatchSnapshot(`app-${screenshotModifier}-diff-${page.getSnapshotSettings()}.png`);
};
test.beforeEach(async ({ page }, testInfo) => {
test.skip(
testInfo.project.metadata.rtl === true,
'Safe area tests only check top and bottom edges. RTL checks are not required here.'
);
test.beforeEach(async ({ page, skip }) => {
skip.rtl('Safe area tests only check top and bottom edges. RTL checks are not required here.');
await page.goto(`/src/components/app/test/safe-area`);
});

View File

@ -12,8 +12,8 @@ test.describe('button: basic', () => {
});
test.describe('button: ripple effect', () => {
test('should not have visual regressions', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.mode !== 'md', 'Ripple effect is only available in MD mode.');
test('should not have visual regressions', async ({ page, skip }) => {
skip.mode('ios', 'Ripple effect is only available in MD mode.');
await page.goto(`/src/components/button/test/basic?ionic:_testing=false`);

View File

@ -2,9 +2,9 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('datetime-button: switching to correct view', () => {
test.beforeEach(async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === 'rtl', 'No layout tests');
test.skip(testInfo.project.metadata.mode === 'ios', 'No mode-specific logic');
test.beforeEach(async ({ page, skip }) => {
skip.rtl();
skip.mode('ios', 'No mode-specific logic');
await page.setContent(`
<ion-datetime-button datetime="datetime"></ion-datetime-button>
@ -31,10 +31,9 @@ test.describe('datetime-button: switching to correct view', () => {
});
test.describe('datetime-button: labels', () => {
// eslint-disable-next-line no-empty-pattern
test.beforeEach(({}, testInfo) => {
test.skip(testInfo.project.metadata.rtl === 'rtl', 'No layout tests');
test.skip(testInfo.project.metadata.mode === 'ios', 'No mode-specific logic');
test.beforeEach(({ skip }) => {
skip.rtl();
skip.mode('ios', 'No mode-specific logic');
});
test('should set date and time labels in separate buttons', async ({ page }) => {
await page.setContent(`
@ -106,10 +105,9 @@ test.describe('datetime-button: labels', () => {
});
test.describe('datetime-button: locale', () => {
// eslint-disable-next-line no-empty-pattern
test.beforeEach(({}, testInfo) => {
test.skip(testInfo.project.metadata.rtl === 'rtl', 'No layout tests');
test.skip(testInfo.project.metadata.mode === 'ios', 'No mode-specific logic');
test.beforeEach(({ skip }) => {
skip.rtl();
skip.mode('ios', 'No mode-specific logic');
});
test('should use the same locale as datetime', async ({ page }) => {
await page.setContent(`
@ -154,10 +152,9 @@ test.describe('datetime-button: locale', () => {
});
test.describe('datetime-button: wheel', () => {
// eslint-disable-next-line no-empty-pattern
test.beforeEach(({}, testInfo) => {
test.skip(testInfo.project.metadata.rtl === 'rtl', 'No layout tests');
test.skip(testInfo.project.metadata.mode === 'ios', 'No mode-specific logic');
test.beforeEach(({ skip }) => {
skip.rtl();
skip.mode('ios', 'No mode-specific logic');
});
test('should only show a single date button when presentation="date-time" and prefer-wheel="true"', async ({
page,

View File

@ -2,9 +2,9 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('datetime-button: disabled buttons', () => {
test('buttons should not be enabled when component is disabled', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === 'rtl', 'No layout tests');
test.skip(testInfo.project.metadata.mode === 'ios', 'No mode-specific logic');
test('buttons should not be enabled when component is disabled', async ({ page, skip }) => {
skip.rtl();
skip.mode('ios', 'No mode-specific logic');
await page.setContent(`
<ion-datetime-button datetime="datetime" disabled="true"></ion-datetime-button>

View File

@ -42,9 +42,9 @@ test.describe('datetime-button: popover', () => {
let popover: Locator;
let ionPopoverDidPresent: EventSpy;
let ionPopoverDidDismiss: EventSpy;
test.beforeEach(async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === 'rtl', 'No layout tests');
test.skip(testInfo.project.metadata.mode === 'ios', 'No mode-specific logic');
test.beforeEach(async ({ page, skip }) => {
skip.rtl();
skip.mode('ios', 'No mode-specific logic');
await page.setContent(`
<ion-datetime-button datetime="datetime"></ion-datetime-button>
@ -104,9 +104,9 @@ test.describe('datetime-button: modal', () => {
let modal: Locator;
let ionModalDidPresent: EventSpy;
let ionModalDidDismiss: EventSpy;
test.beforeEach(async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === 'rtl', 'No layout tests');
test.skip(testInfo.project.metadata.mode === 'ios', 'No mode-specific logic');
test.beforeEach(async ({ page, skip }) => {
skip.rtl();
skip.mode('ios', 'No mode-specific logic');
await page.setContent(`
<ion-datetime-button datetime="datetime"></ion-datetime-button>

View File

@ -185,10 +185,9 @@ test.describe('datetime: footer', () => {
});
test.describe('datetime: swiping', () => {
// eslint-disable-next-line no-empty-pattern
test.beforeEach(({}, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs RTL layouts.');
test.skip(testInfo.project.metadata.mode === 'ios', 'This does not have mode-specific logic.');
test.beforeEach(({ skip }) => {
skip.rtl();
skip.mode('ios', 'This does not have mode-specific logic.');
});
test('should move to prev month by swiping', async ({ page }) => {
await page.setContent(`
@ -224,8 +223,8 @@ test.describe('datetime: swiping', () => {
await expect(calendarHeader).toHaveText(/June 2022/);
});
test('should not re-render if swipe is in progress', async ({ page, browserName }) => {
test.skip(browserName === 'webkit', 'Wheel is not available in WebKit');
test('should not re-render if swipe is in progress', async ({ page, skip }) => {
skip.browser('webkit', 'Wheel is not available in WebKit');
await page.setContent(`
<ion-datetime value="2022-05-03"></ion-datetime>

View File

@ -13,13 +13,8 @@ const queryAllWorkingMonthDisabledDays = (page: E2EPage, datetimeSelector = 'ion
};
test.describe('datetime: disable dates', () => {
/**
* We need to access testInfo, but Playwright
* requires that we destructure the first parameter.
*/
// eslint-disable-next-line no-empty-pattern
test.beforeEach(({}, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'These tests do not check layout rendering functionality.');
test.beforeEach(({ skip }) => {
skip.rtl();
});
test.describe('check return values', () => {
test.beforeEach(async ({ page }) => {

View File

@ -32,9 +32,8 @@ test.describe('datetime: multiple date selection (visual regressions)', () => {
});
test.describe('datetime: multiple date selection (functionality)', () => {
// eslint-disable-next-line no-empty-pattern
test.beforeEach(async ({}, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'Does not test LTR vs. RTL layout.');
test.beforeEach(async ({ skip }) => {
skip.rtl();
});
test('clicking unselected days should select them', async ({ page }) => {

View File

@ -84,8 +84,8 @@ test.describe('datetime: presentation', () => {
expect(ionChangeSpy.length).toBe(1);
});
test('switching presentation should close month/year picker', async ({ page }, testInfo) => {
await test.skip(testInfo.project.metadata.rtl === true, 'This feature does not have RTL specific behaviors.');
test('switching presentation should close month/year picker', async ({ page, skip }) => {
await skip.rtl();
await page.setContent(`
<ion-datetime presentation="date"></ion-datetime>

View File

@ -2,9 +2,9 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('header: condense', () => {
test('should be hidden from screen readers when collapsed', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.mode === 'md', 'Logic only applies to iOS mode');
test.skip(testInfo.project.metadata.rtl === true, 'No RTL-specific logic');
test('should be hidden from screen readers when collapsed', async ({ page, skip }) => {
skip.mode('md');
skip.rtl();
await page.goto('/src/components/header/test/condense');
const header = page.locator('#collapsibleHeader');

View File

@ -2,10 +2,8 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('input: a11y', () => {
test('does not set a default aria-labelledby when there is not a neighboring ion-label', async ({
page,
}, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'Does not test LTR vs. RTL layout.');
test('does not set a default aria-labelledby when there is not a neighboring ion-label', async ({ page, skip }) => {
skip.rtl();
await page.setContent('<ion-input></ion-input>');
@ -15,8 +13,8 @@ test.describe('input: a11y', () => {
await expect(ariaLabelledBy).toBe(null);
});
test('set a default aria-labelledby when a neighboring ion-label exists', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'Does not test LTR vs. RTL layout.');
test('set a default aria-labelledby when a neighboring ion-label exists', async ({ page, skip }) => {
skip.rtl();
await page.setContent(
`

View File

@ -6,8 +6,8 @@ test.describe('input: masking', () => {
await page.goto('/src/components/input/test/masking');
});
test('should filter out spaces', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'Does not test LTR vs. RTL layout.');
test('should filter out spaces', async ({ page, skip }) => {
skip.rtl();
const input = page.locator('#inputTrimmed');

View File

@ -2,9 +2,9 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('item-sliding: basic', () => {
test('should not scroll when the item-sliding is swiped', async ({ page, browserName }, testInfo) => {
test.skip(browserName === 'webkit', 'mouse.wheel is not available in WebKit');
test.skip(testInfo.project.metadata.rtl === true, 'This feature does not have RTL-specific behaviors');
test('should not scroll when the item-sliding is swiped', async ({ page, skip }) => {
skip.browser('webkit', 'mouse.wheel is not available in WebKit');
skip.rtl();
await page.goto(`/src/components/item-sliding/test/basic`);

View File

@ -2,12 +2,9 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('item-sliding: scroll-target', () => {
test('should not scroll when the item-sliding is swiped in custom scroll target', async ({
page,
browserName,
}, testInfo) => {
test.skip(browserName === 'webkit', 'mouse.wheel is not available in WebKit');
test.skip(testInfo.project.metadata.rtl === true, 'This feature does not have RTL-specific behaviors');
test('should not scroll when the item-sliding is swiped in custom scroll target', async ({ page, skip }) => {
skip.browser('webkit', 'mouse.wheel is not available in WebKit');
skip.rtl();
await page.goto(`/src/components/item-sliding/test/scroll-target`);

View File

@ -41,9 +41,8 @@ test.describe('item: inputs', () => {
});
test.describe('form data', () => {
// eslint-disable-next-line no-empty-pattern
test.beforeEach(async ({}, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'Does not test LTR vs. RTL layout.');
test.beforeEach(async ({ skip }) => {
skip.rtl();
});
test('initial form data should be empty', async ({ page }) => {

View File

@ -3,9 +3,9 @@ import { test, Viewports } from '@utils/test/playwright';
import type { E2EPage } from '@utils/test/playwright';
test.describe('modal: focus trapping', () => {
test.beforeEach(async ({ browserName }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs. RTL layout.');
test.skip(browserName === 'firefox', 'Firefox incorrectly allows keyboard focus to move to ion-content');
test.beforeEach(async ({ skip }) => {
skip.rtl();
skip.browser('firefox', 'Firefox incorrectly allows keyboard focus to move to ion-content');
});
test('focus should be trapped inside of modal', async ({ page, browserName }) => {
/**

View File

@ -134,8 +134,8 @@ test.describe('modal: canDismiss', () => {
});
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.');
test.beforeEach(async ({ page, skip }) => {
skip.mode('md');
await page.click('#radio-card');
});

View File

@ -5,13 +5,13 @@ import { CardModalPage } from '../fixtures';
test.describe('card modal - nav', () => {
let cardModalPage: CardModalPage;
test.beforeEach(async ({ page, browserName }, testInfo) => {
test.skip(testInfo.project.metadata.mode !== 'ios', 'Card style modal is only available on iOS');
test.skip(
testInfo.project.metadata.rtl === true,
'This test only verifies that the gesture activates inside of a modal.'
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.'
);
test.skip(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');

View File

@ -2,8 +2,8 @@ import { expect } from '@playwright/test';
import { dragElementBy, test } from '@utils/test/playwright';
test.describe('card modal - with refresher', () => {
test.beforeEach(async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.mode !== 'ios', 'Card style modal is only available on iOS');
test.beforeEach(async ({ page, skip }) => {
skip.mode('md');
await page.goto('/src/components/modal/test/card-refresher');
});

View File

@ -2,8 +2,8 @@ import { expect } from '@playwright/test';
import { dragElementBy, test } from '@utils/test/playwright';
test.describe('card modal - scroll target', () => {
test.beforeEach(async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.mode !== 'ios', 'Card style modal is only available on iOS');
test.beforeEach(async ({ page, skip }) => {
skip.mode('md');
await page.goto('/src/components/modal/test/card-scroll-target');
});

View File

@ -5,8 +5,8 @@ import { CardModalPage } from '../fixtures';
test.describe('card modal', () => {
let cardModalPage: CardModalPage;
test.beforeEach(async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.mode !== 'ios', 'Card style modal is only available on iOS');
test.beforeEach(async ({ page, skip }) => {
skip.mode('md');
cardModalPage = new CardModalPage(page);
await cardModalPage.navigate('/src/components/modal/test/card');

View File

@ -2,8 +2,8 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('modal: custom dialog', () => {
test('should size custom modal correctly', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs. RTL layout.');
test('should size custom modal correctly', async ({ page, skip }) => {
skip.rtl();
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/24080',

View File

@ -32,8 +32,8 @@ test.describe('picker-column-internal', () => {
expect(activeColumn).not.toBeNull();
});
test('scrolling should change the active item', async ({ page, browserName }) => {
test.skip(browserName === 'firefox', 'https://bugzilla.mozilla.org/show_bug.cgi?id=1766890');
test('scrolling should change the active item', async ({ page, skip }) => {
skip.browser('firefox', 'https://bugzilla.mozilla.org/show_bug.cgi?id=1766890');
await page.locator('#default').evaluate((el: HTMLIonPickerColumnInternalElement) => {
el.scrollTop = 801;
@ -45,8 +45,8 @@ test.describe('picker-column-internal', () => {
expect(await activeColumn?.innerText()).toEqual('23');
});
test('should not emit ionChange when the value is modified externally', async ({ page, browserName }) => {
test.skip(browserName === 'firefox', 'https://bugzilla.mozilla.org/show_bug.cgi?id=1766890');
test('should not emit ionChange when the value is modified externally', async ({ page, skip }) => {
skip.browser('firefox', 'https://bugzilla.mozilla.org/show_bug.cgi?id=1766890');
const ionChangeSpy = await page.spyOnEvent('ionChange');
@ -57,8 +57,8 @@ test.describe('picker-column-internal', () => {
expect(ionChangeSpy).not.toHaveReceivedEvent();
});
test('should emit ionChange when the picker is scrolled', async ({ page, browserName }) => {
test.skip(browserName === 'firefox', 'https://bugzilla.mozilla.org/show_bug.cgi?id=1766890');
test('should emit ionChange when the picker is scrolled', async ({ page, skip }) => {
skip.browser('firefox', 'https://bugzilla.mozilla.org/show_bug.cgi?id=1766890');
const ionChangeSpy = await page.spyOnEvent('ionChange');

View File

@ -23,10 +23,10 @@ test.describe('popover: dismissOnSelect', async () => {
await expect(popover).toBeVisible();
});
test('should not dismiss a popover when clicking a click trigger', async ({ page, browserName }) => {
test('should not dismiss a popover when clicking a click trigger', async ({ page, skip }) => {
// TODO FW-1486
test.skip(
browserName === 'firefox',
skip.browser(
'firefox',
'Parent popover disappears when click trigger is clicked. Cannot replicate locally. Needs further investigation.'
);

View File

@ -16,8 +16,8 @@ test.describe('radio-group: basic', () => {
test.describe('radio-group: interaction', () => {
let radioFixture: RadioFixture;
test.beforeEach(({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs RTL logic.');
test.beforeEach(({ page, skip }) => {
skip.rtl();
radioFixture = new RadioFixture(page);
});

View File

@ -2,8 +2,8 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('radio-group', () => {
test.beforeEach(async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs RTL logic.');
test.beforeEach(async ({ page, skip }) => {
skip.rtl();
await page.goto('/src/components/radio-group/test/search');
});

View File

@ -2,9 +2,8 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('radio: a11y', () => {
// eslint-disable-next-line no-empty-pattern
test.beforeEach(({}, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs RTL logic.');
test.beforeEach(({ skip }) => {
skip.rtl();
});
test('tabbing should switch between radio groups', async ({ page, browserName }) => {
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';

View File

@ -97,9 +97,8 @@ test.describe('radio: rendering', () => {
});
test.describe('radio: interaction', () => {
// eslint-disable-next-line no-empty-pattern
test.beforeEach(({}, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs RTL logic.');
test.beforeEach(({ skip }) => {
skip.rtl();
});
test('radio should be checked when activated', async ({ page }) => {
await page.setContent(`

View File

@ -54,9 +54,9 @@ test.describe('range: basic', () => {
expect(rangeEnd).toHaveReceivedEventDetail({ value: 21 });
});
test('should not scroll when the knob is swiped', async ({ page, browserName }, testInfo) => {
test.skip(browserName === 'webkit', 'mouse.wheel is not available in WebKit');
test.skip(testInfo.project.metadata.rtl === true, 'This feature does not have RTL-specific behaviors');
test('should not scroll when the knob is swiped', async ({ page, skip }) => {
skip.browser('webkit', 'mouse.wheel is not available in WebKit');
skip.rtl();
await page.goto(`/src/components/range/test/basic`);

View File

@ -2,9 +2,9 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('range: scroll-target', () => {
test('should not scroll when the knob is swiped in custom scroll target', async ({ page, browserName }, testInfo) => {
test.skip(browserName === 'webkit', 'mouse.wheel is not available in WebKit');
test.skip(testInfo.project.metadata.rtl === true, 'This feature does not have RTL-specific behaviors');
test('should not scroll when the knob is swiped in custom scroll target', async ({ page, skip }) => {
skip.browser('webkit', 'mouse.wheel is not available in WebKit');
skip.rtl();
await page.goto(`/src/components/range/test/scroll-target`);

View File

@ -2,8 +2,8 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('select: async', () => {
test('should correctly set the value after a delay', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This is checking internal logic. RTL tests are not needed');
test('should correctly set the value after a delay', async ({ page, skip }) => {
skip.rtl('This is checking internal logic. RTL tests are not needed');
await page.goto(`/src/components/select/test/async`);
const selectValueSet = await page.spyOnEvent('selectValueSet');

View File

@ -2,8 +2,8 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('select: compare-with', () => {
test('should correctly set value when using compareWith property', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This is checking internal logic. RTL tests are not needed');
test('should correctly set value when using compareWith property', async ({ page, skip }) => {
skip.rtl('This is checking internal logic. RTL tests are not needed');
await page.goto('/src/components/select/test/compare-with');

View File

@ -2,8 +2,8 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('overlays: focus', () => {
test('should not focus the overlay container if element inside of overlay is focused', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'RTL tests are not needed as layout is not checked');
test('should not focus the overlay container if element inside of overlay is focused', async ({ page, skip }) => {
skip.rtl();
await page.setContent(`
<ion-button id="open-modal">Show Modal</ion-button>

View File

@ -0,0 +1,69 @@
# Playwright Test Utils
This directory contains utilities that can be used to more easily test Stencil projects with Playwright.
## Test Function
The default `test` function has been extended to provide two custom options.
| Fixture | Type | Description |
| ------- | ---- | ----------- |
| page | [E2EPage](https://github.com/ionic-team/ionic-framework/blob/main/core/src/utils/test/playwright/playwright-declarations.ts) | An extension of the base `page` test fixture within Playwright |
| skip | [E2ESkip](https://github.com/ionic-team/ionic-framework/blob/main/core/src/utils/test/playwright/playwright-declarations.ts) | Used to skip tests based on text direction, mode, or browser |
### Usage
**`page`**
```typescript
import { test } from '@utils/test/playwright';
test('my custom test', ({ page }) => {
await page.goto('path/to/file');
});
```
**`skip.mode`**
```typescript
import { test } from '@utils/test/playwright';
test('my custom test', ({ page, skip }) => {
skip.mode('md', 'This test is iOS-specific.');
await page.goto('path/to/file');
});
```
**`skip.rtl`**
```typescript
import { test } from '@utils/test/playwright';
test('my custom test', ({ page, skip }) => {
skip.rtl('This test does not have RTL-specific behaviors.');
await page.goto('path/to/file');
});
```
**`skip.browser`**
```typescript
import { test } from '@utils/test/playwright';
test('my custom test', ({ page, skip }) => {
skip.browser('webkit', 'This test does not work in WebKit yet.');
await page.goto('path/to/file');
});
```
**`skip.browser` with callback**
```typescript
import { test } from '@utils/test/playwright';
test('my custom test', ({ page, skip }) => {
skip.browser((browserName: string) => browserName !== 'webkit', 'This tests a WebKit-specific behavior.');
await page.goto('path/to/file');
});
```

View File

@ -96,6 +96,14 @@ export interface E2EPage extends Page {
_e2eEvents: Map<number, any>;
}
export type BrowserNameOrCallback = string | ((browserName: string) => boolean);
export interface E2ESkip {
rtl: (reason?: string) => void;
browser: (browserNameOrCallback: BrowserNameOrCallback, reason?: string) => void;
mode: (mode: string, reason?: string) => void;
}
export interface SetIonViewportOptions {
/**
* `true` if the viewport should be scaled to match the `ion-content`

View File

@ -18,7 +18,7 @@ import {
locator,
} from './page/utils';
import type { LocatorOptions } from './page/utils';
import type { E2EPage, SetIonViewportOptions } from './playwright-declarations';
import type { E2EPage, E2ESkip, BrowserNameOrCallback, SetIonViewportOptions } from './playwright-declarations';
type CustomTestArgs = PlaywrightTestArgs &
PlaywrightTestOptions &
@ -29,6 +29,7 @@ type CustomTestArgs = PlaywrightTestArgs &
type CustomFixtures = {
page: E2EPage;
skip: E2ESkip;
};
/**
@ -63,4 +64,25 @@ export const test = base.extend<CustomFixtures>({
page = await extendPageFixture(page, testInfo);
await use(page);
},
skip: {
rtl: (reason = 'The functionality that is being tested is not applicable to RTL layouts.') => {
const testInfo: TestInfo = base.info();
base.skip(testInfo.project.metadata.rtl === true, reason);
},
browser: (
browserNameOrFunction: BrowserNameOrCallback,
reason = `The functionality that is being tested is not applicable to this browser.`
) => {
const browserName = base.info().project.use.browserName!;
if (typeof browserNameOrFunction === 'function') {
base.skip(browserNameOrFunction(browserName), reason);
} else {
base.skip(browserName === browserNameOrFunction, reason);
}
},
mode: (mode: string, reason = `The functionality that is being tested is not applicable to ${mode} mode`) => {
base.skip(base.info().project.metadata.mode === mode, reason);
},
},
});