chore(): sync with main

This commit is contained in:
Liam DeBeasi
2022-12-09 12:37:06 -05:00
97 changed files with 242 additions and 144 deletions

57
.github/CODEOWNERS vendored
View File

@ -13,3 +13,60 @@
# Global owners
* @ionic-team/framework
# Frameworks
## Angular
/angular/ @sean-perkins
/packages/angular-server @sean-perkins
/angular/test
## React
/packages/react/ @amandaejohnston
/packages/react-router @amandaejohnston
/packages/react/test-app/
/packages/react-router/test-app/
## Vue
/packages/vue/ @liamdebeasi
/packages/vue-router/ @liamdebeasi
/packages/vue/test/
/packages/vue-router/__tests__
# Components
/core/src/components/accordion/ @liamdebeasi
/core/src/components/accordion-group/ @liamdebeasi
/core/src/components/datetime/ @liamdebeasi @amandaejohnston @sean-perkins
/core/src/components/datetime-button/ @liamdebeasi
/core/src/components/menu/ @amandaejohnston
/core/src/components/menu-toggle/ @amandaejohnston
/core/src/components/nav/ @sean-perkins
/core/src/components/nav-link/ @sean-perkins
/core/src/components/picker-internal/ @liamdebeasi
/core/src/components/picker-column-internal/ @liamdebeasi
/core/src/components/refresher/ @liamdebeasi
/core/src/components/refresher-content/ @liamdebeasi
# Codeowner should own the source, but everyone should own the tests
/core/src/components/**/test/ @ionic-team/framework
# Utilities
/core/src/utils/animation/ @liamdebeasi
/core/src/utils/content/ @sean-perkins
/core/src/utils/gesture/ @liamdebeasi
/core/src/utils/input-shims/ @liamdebeasi
/core/src/utils/keyboard/ @liamdebeasi
/core/src/utils/logging/ @amandaejohnston
/core/src/utils/sanitization/ @liamdebeasi
/core/src/utils/tap-click/ @liamdebeasi
/core/src/utils/transition/ @liamdebeasi

View File

@ -47,13 +47,6 @@ jobs:
- uses: actions/checkout@v3
- uses: ./.github/workflows/actions/test-core-spec
test-core-e2e:
needs: [build-core]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/actions/test-core-e2e
test-core-screenshot:
strategy:
# This ensures that all screenshot shard

View File

@ -85,7 +85,10 @@ const config: PlaywrightTestConfig = {
},
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
/* Fail fast on CI */
maxFailures: process.env.CI ? 1 : 0,
/* Flaky test should be either addressed or disabled until we can address them */
retries: 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */

View File

@ -19,7 +19,7 @@ test.describe('accordion: states', () => {
const accordionGroup = page.locator('ion-accordion-group');
const accordion = page.locator('ion-accordion');
expect(accordion).toHaveJSProperty('readonly', false);
await expect(accordion).toHaveJSProperty('readonly', false);
await accordionGroup.evaluate((el: HTMLIonAccordionGroupElement) => {
el.readonly = true;
@ -27,7 +27,7 @@ test.describe('accordion: states', () => {
await page.waitForChanges();
expect(accordion).toHaveJSProperty('readonly', true);
await expect(accordion).toHaveJSProperty('readonly', true);
});
test('should properly set disabled on child accordions', async ({ page }) => {
@ -43,7 +43,7 @@ test.describe('accordion: states', () => {
const accordionGroup = page.locator('ion-accordion-group');
const accordion = page.locator('ion-accordion');
expect(accordion).toHaveJSProperty('disabled', false);
await expect(accordion).toHaveJSProperty('disabled', false);
await accordionGroup.evaluate((el: HTMLIonAccordionGroupElement) => {
el.disabled = true;
@ -51,6 +51,6 @@ test.describe('accordion: states', () => {
await page.waitForChanges();
expect(accordion).toHaveJSProperty('disabled', true);
await expect(accordion).toHaveJSProperty('disabled', true);
});
});

View File

@ -41,7 +41,7 @@ test.describe('action sheet: basic', () => {
await actionSheetFixture.open('#basic');
const actionSheet = page.locator('ion-action-sheet');
expect(actionSheet).toHaveAttribute('data-testid', 'basic-action-sheet');
await expect(actionSheet).toHaveAttribute('data-testid', 'basic-action-sheet');
});
});
test.describe('action sheet: variants', () => {
@ -78,7 +78,7 @@ test.describe('action sheet: basic', () => {
await actionSheetFixture.open('#customBackdrop');
const backdrop = page.locator('ion-action-sheet ion-backdrop');
expect(backdrop).toHaveCSS('opacity', '1');
await expect(backdrop).toHaveCSS('opacity', '1');
});
test('should open alert from action sheet', async ({ page, skip }) => {
skip.rtl();
@ -96,7 +96,7 @@ test.describe('action sheet: basic', () => {
const actionSheet = page.locator('ion-action-sheet');
await actionSheet.locator('ion-backdrop').click();
expect(actionSheet).toBeVisible();
await expect(actionSheet).toBeVisible();
});
});
test.describe('action sheet: focus trap', () => {
@ -133,14 +133,14 @@ class ActionSheetFixture {
await this.page.locator(selector).click();
await ionActionSheetDidPresent.next();
this.actionSheet = this.page.locator('ion-action-sheet');
expect(this.actionSheet).toBeVisible();
await expect(this.actionSheet).toBeVisible();
}
async dismiss() {
const ionActionSheetDidDismiss = await this.page.spyOnEvent('ionActionSheetDidDismiss');
await this.actionSheet.evaluate((el: HTMLIonActionSheetElement) => el.dismiss());
await ionActionSheetDidDismiss.next();
expect(this.actionSheet).not.toBeVisible();
await expect(this.actionSheet).not.toBeVisible();
}
async screenshot(modifier: string) {

View File

@ -51,7 +51,7 @@ test.describe('alert: basic', () => {
await page.goto(`/src/components/alert/test/basic`);
const alert = await openAlert(page, 'basic');
expect(alert).toHaveAttribute('data-testid', 'basic-alert');
await expect(alert).toHaveAttribute('data-testid', 'basic-alert');
});
test('should dismiss when async handler resolves', async ({ page, skip }) => {

View File

@ -14,21 +14,21 @@ test.describe('datetime-button: switching to correct view', () => {
});
test('should switch to a date-only view when the date button is clicked', async ({ page }) => {
const datetime = page.locator('ion-datetime');
expect(datetime).toHaveJSProperty('presentation', 'date-time');
await expect(datetime).toHaveJSProperty('presentation', 'date-time');
await page.locator('#date-button').click();
await page.waitForChanges();
expect(datetime).toHaveJSProperty('presentation', 'date');
await expect(datetime).toHaveJSProperty('presentation', 'date');
});
test('should switch to a time-only view when the time button is clicked', async ({ page }) => {
const datetime = page.locator('ion-datetime');
expect(datetime).toHaveJSProperty('presentation', 'date-time');
await expect(datetime).toHaveJSProperty('presentation', 'date-time');
await page.locator('#time-button').click();
await page.waitForChanges();
expect(datetime).toHaveJSProperty('presentation', 'time');
await expect(datetime).toHaveJSProperty('presentation', 'time');
});
});

View File

@ -68,38 +68,38 @@ test.describe('datetime-button: popover', () => {
await ionPopoverDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
});
test('should open the time popover', async ({ page }) => {
await page.locator('#time-button').click();
await ionPopoverDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
});
test('should open the date popover then the time popover', async ({ page }) => {
await page.locator('#date-button').click();
await ionPopoverDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
await popover.evaluate((el: HTMLIonPopoverElement) => el.dismiss());
await ionPopoverDidDismiss.next();
await page.locator('#time-button').click();
await ionPopoverDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
});
test('should open the time popover then the date popover', async ({ page }) => {
await page.locator('#time-button').click();
await ionPopoverDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
await popover.evaluate((el: HTMLIonPopoverElement) => el.dismiss());
await ionPopoverDidDismiss.next();
await page.locator('#date-button').click();
await ionPopoverDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
});
});
@ -130,37 +130,37 @@ test.describe('datetime-button: modal', () => {
await ionModalDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
});
test('should open the time modal', async ({ page }) => {
await page.locator('#time-button').click();
await ionModalDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
});
test('should open the date modal then the time modal', async ({ page }) => {
await page.locator('#date-button').click();
await ionModalDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
await ionModalDidDismiss.next();
await page.locator('#time-button').click();
await ionModalDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
});
test('should open the time modal then the date modal', async ({ page }) => {
await page.locator('#time-button').click();
await ionModalDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
await modal.evaluate((el: HTMLIonModalElement) => el.dismiss());
await ionModalDidDismiss.next();
await page.locator('#date-button').click();
await ionModalDidPresent.next();
expect(datetime).toBeVisible();
await expect(datetime).toBeVisible();
});
});

View File

@ -300,10 +300,13 @@ test.describe('datetime: visibility', () => {
await datetime.evaluate((el: HTMLIonDatetimeElement) => el.style.setProperty('display', 'none'));
await expect(datetime).toBeHidden();
await expect(datetime).not.toHaveClass(/datetime-ready/);
await datetime.evaluate((el: HTMLIonDatetimeElement) => el.style.removeProperty('display'));
await expect(datetime).toBeVisible();
await page.waitForSelector('.datetime-ready');
// month/year interface should be reset
await expect(monthYearInterface).toBeHidden();
});

View File

@ -214,8 +214,8 @@ test.describe('datetime: prefer wheel', () => {
const monthValues = page.locator('.month-column .picker-item:not(.picker-item-empty)');
const dayValues = page.locator('.day-column .picker-item:not(.picker-item-empty)');
expect(monthValues).toHaveText(['1月', '2月', '3月']);
expect(dayValues).toHaveText(['1日', '2日', '3日']);
await expect(monthValues).toHaveText(['1月', '2月', '3月']);
await expect(dayValues).toHaveText(['1日', '2日', '3日']);
});
test('should render the columns according to locale - en-US', async ({ page }) => {
await page.setContent(`
@ -334,7 +334,7 @@ test.describe('datetime: prefer wheel', () => {
const dateValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
expect(dateValues).toHaveText(['2月1日(火)', '2月2日(水)', '2月3日(木)']);
await expect(dateValues).toHaveText(['2月1日(火)', '2月2日(水)', '2月3日(木)']);
});
test('should respect min and max bounds even across years', async ({ page }) => {
await page.setContent(`
@ -495,7 +495,7 @@ test.describe('datetime: prefer wheel', () => {
const dateValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
expect(dateValues).toHaveText(['2月1日(火)', '2月2日(水)', '2月3日(木)']);
await expect(dateValues).toHaveText(['2月1日(火)', '2月2日(水)', '2月3日(木)']);
});
test('should respect min and max bounds even across years', async ({ page }) => {
await page.setContent(`

View File

@ -159,9 +159,10 @@ class TimePickerFixture {
}
async goto() {
await this.page.goto(`/src/components/datetime/test/presentation`);
await this.page.locator('select').selectOption('time');
await this.page.waitForSelector('.datetime-presentation-time');
await this.page.setContent(`
<ion-datetime presentation="time" value="2022-03-10T13:00:00"></ion-datetime>
`);
await this.page.waitForSelector('.datetime-ready');
this.timePicker = this.page.locator('ion-datetime');
}

View File

@ -47,28 +47,28 @@ test.describe('fab: basic (functionality checks)', () => {
const fab = page.locator('#fab1');
const fabList = fab.locator('ion-fab-list');
expect(fabList).not.toHaveClass(/fab-list-active/);
await expect(fabList).not.toHaveClass(/fab-list-active/);
// open fab
await fab.click();
await page.waitForChanges();
expect(fabList).toHaveClass(/fab-list-active/);
await expect(fabList).toHaveClass(/fab-list-active/);
// close fab
await fab.click();
await page.waitForChanges();
expect(fabList).not.toHaveClass(/fab-list-active/);
await expect(fabList).not.toHaveClass(/fab-list-active/);
});
test('should not open when disabled', async ({ page }) => {
const fab = page.locator('#fab2');
const fabList = fab.locator('ion-fab-list');
expect(fabList).not.toHaveClass(/fab-list-active/);
await expect(fabList).not.toHaveClass(/fab-list-active/);
// attempt to open fab
await fab.click();
await page.waitForChanges();
expect(fabList).not.toHaveClass(/fab-list-active/);
await expect(fabList).not.toHaveClass(/fab-list-active/);
});
});

View File

@ -40,7 +40,8 @@ test.describe('item-sliding: basic', () => {
expect(await item.screenshot()).toMatchSnapshot(`item-sliding-gesture-${page.getSnapshotSettings()}.png`);
});
test('should not scroll when the item-sliding is swiped', async ({ page, skip }) => {
// TODO FW-3006
test.skip('should not scroll when the item-sliding is swiped', async ({ page, skip }) => {
skip.browser('webkit', 'mouse.wheel is not available in WebKit');
skip.rtl();

View File

@ -2,7 +2,8 @@ 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, skip }) => {
// TODO FW-3006
test.skip('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();

View File

@ -2,14 +2,25 @@ import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('list: inset', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/list/test/inset');
});
test.describe('list: visual regression tests', () => {
test.describe('list: rendering', () => {
test('should not have visual regressions', async ({ page }) => {
await page.setIonViewport();
await page.setContent(`
<ion-content color="primary">
<div class="wrapper" style="display: flex">
<ion-list inset="true" style="width: 100%">
<ion-item>Pokémon Yellow</ion-item>
<ion-item>Super Metroid</ion-item>
<ion-item>Mega Man X</ion-item>
<ion-item>The Legend of Zelda</ion-item>
<ion-item lines="full">Halo</ion-item>
</ion-list>
</div>
</ion-content>
`);
expect(await page.screenshot()).toMatchSnapshot(`list-inset-diff-${page.getSnapshotSettings()}.png`);
const listWrapper = page.locator('.wrapper');
expect(await listWrapper.screenshot()).toMatchSnapshot(`list-inset-diff-${page.getSnapshotSettings()}.png`);
});
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -1,6 +1,5 @@
import { GESTURE } from '@utils/overlays';
import type { Animation } from '../../../interface';
import { GESTURE } from '../../../utils/overlays';
export const handleCanDismiss = async (el: HTMLIonModalElement, animation: Animation) => {
/**

View File

@ -60,7 +60,7 @@ test.describe('picker-column-internal: disabled', () => {
`);
const disabledItem = page.locator('ion-picker-column-internal .picker-item.picker-item-disabled');
expect(disabledItem).not.toBeEnabled();
await expect(disabledItem).not.toBeEnabled();
});
test('disabled picker item should not be considered active', async ({ page }) => {
await page.setContent(`
@ -79,7 +79,7 @@ test.describe('picker-column-internal: disabled', () => {
`);
const disabledItem = page.locator('ion-picker-column-internal .picker-item[data-value="b"]');
expect(disabledItem).not.toHaveClass(/picker-item-active/);
await expect(disabledItem).not.toHaveClass(/picker-item-active/);
});
test('setting the value to a disabled item should not cause that item to be active', async ({ page }) => {
await page.setContent(`
@ -103,8 +103,8 @@ test.describe('picker-column-internal: disabled', () => {
await page.waitForChanges();
const disabledItem = page.locator('ion-picker-column-internal .picker-item[data-value="b"]');
expect(disabledItem).toHaveClass(/picker-item-disabled/);
expect(disabledItem).not.toHaveClass(/picker-item-active/);
await expect(disabledItem).toHaveClass(/picker-item-disabled/);
await expect(disabledItem).not.toHaveClass(/picker-item-active/);
});
test('defaulting the value to a disabled item should not cause that item to be active', async ({ page }) => {
await page.setContent(`
@ -124,7 +124,7 @@ test.describe('picker-column-internal: disabled', () => {
`);
const disabledItem = page.locator('ion-picker-column-internal .picker-item[data-value="b"]');
expect(disabledItem).toHaveClass(/picker-item-disabled/);
expect(disabledItem).not.toHaveClass(/picker-item-active/);
await expect(disabledItem).toHaveClass(/picker-item-disabled/);
await expect(disabledItem).not.toHaveClass(/picker-item-active/);
});
});

View File

@ -47,13 +47,13 @@ test.describe('picker-internal', () => {
// Focus first column
await page.keyboard.press('Tab');
expect(firstColumn).toBeFocused();
await expect(firstColumn).toBeFocused();
await page.waitForChanges();
// Focus second column
await page.keyboard.press('Tab');
expect(secondColumn).toBeFocused();
await expect(secondColumn).toBeFocused();
});
test('tabbing should correctly move focus back', async ({ page }) => {
@ -61,13 +61,13 @@ test.describe('picker-internal', () => {
const secondColumn = page.locator('ion-picker-column-internal#second');
await secondColumn.focus();
expect(secondColumn).toBeFocused();
await expect(secondColumn).toBeFocused();
await page.waitForChanges();
// Focus first column
await page.keyboard.press('Shift+Tab');
expect(firstColumn).toBeFocused();
await expect(firstColumn).toBeFocused();
});
});

View File

@ -24,7 +24,7 @@ test.describe('radio-group', () => {
expect(radio).toBeHidden();
// ensure radio group has the same value
expect(radioGroup).toHaveJSProperty('value', 'two');
await expect(radioGroup).toHaveJSProperty('value', 'two');
// clear the search so the radio appears
await page.fill('ion-searchbar input', '');

View File

@ -12,6 +12,7 @@ test.describe('range: basic', () => {
/**
* The mouse events are flaky on CI
* TODO FW-2873
*/
test.fixme('should emit start/end events', async ({ page }, testInfo) => {
await page.setContent(`<ion-range value="20"></ion-range>`);
@ -57,7 +58,8 @@ test.describe('range: basic', () => {
expect(rangeEnd).toHaveReceivedEventDetail({ value: 21 });
});
test('should not scroll when the knob is swiped', async ({ page, skip }) => {
// TODO FW-2873
test.skip('should not scroll when the knob is swiped', async ({ page, skip }) => {
skip.browser('webkit', 'mouse.wheel is not available in WebKit');
skip.rtl();

View File

@ -1,7 +1,8 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('range: scroll-target', () => {
// TODO FW-2873
test.describe.skip('range: scroll-target', () => {
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();

View File

@ -1,28 +1,11 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('searchbar: basic', () => {
test.describe('searchbar: cancel button', () => {
test.beforeEach(async ({ page }) => {
await page.goto(`/src/components/searchbar/test/basic`);
});
test('should not have visual regressions', async ({ page }) => {
await page.setIonViewport();
/**
* The searchbar test template is rendering an ion-searchbar
* that is animated. This requires the searchbar to render,
* before the cancel button can be positioned correctly.
*
* We wait for changes to ensure the searchbar has rendered
* correctly before capturing the screenshot.
*/
await page.waitForChanges();
expect(await page.screenshot({ animations: 'disabled' })).toMatchSnapshot(
`searchbar-diff-${page.getSnapshotSettings()}.png`
);
});
test('should show cancel button on focus if show-cancel-button=focus', async ({ page }) => {
const searchbar = page.locator('#basic');
const cancelButton = searchbar.locator('.searchbar-cancel-button');
@ -89,3 +72,76 @@ test.describe('searchbar: clear button', () => {
await expect(nativeInput).toBeFocused();
});
});
test.describe('searchbar: rendering', () => {
test('should render searchbar', async ({ page }) => {
await page.setContent(`
<ion-searchbar></ion-searchbar>
`);
const searchbar = page.locator('ion-searchbar');
expect(await searchbar.screenshot()).toMatchSnapshot(`searchbar-${page.getSnapshotSettings()}.png`);
});
test('should render cancel and clear buttons', async ({ page }) => {
await page.setContent(`
<ion-searchbar show-cancel-button="always" show-clear-button="always"></ion-searchbar>
`);
const searchbar = page.locator('ion-searchbar');
expect(await searchbar.screenshot()).toMatchSnapshot(`searchbar-buttons-${page.getSnapshotSettings()}.png`);
});
test('should render searchbar with color', async ({ page, skip }) => {
skip.rtl();
await page.setContent(`
<ion-searchbar color="danger" show-cancel-button="always" show-clear-button="always"></ion-searchbar>
`);
const searchbar = page.locator('ion-searchbar');
expect(await searchbar.screenshot()).toMatchSnapshot(`searchbar-color-${page.getSnapshotSettings()}.png`);
});
test('should render disabled searchbar', async ({ page, skip }) => {
skip.rtl();
await page.setContent(`
<ion-searchbar disabled="true"></ion-searchbar>
`);
const searchbar = page.locator('ion-searchbar');
expect(await searchbar.screenshot()).toMatchSnapshot(`searchbar-disabled-${page.getSnapshotSettings()}.png`);
});
test('should render custom search icon', async ({ page, skip }) => {
skip.rtl();
await page.setContent(`
<ion-searchbar search-icon="home"></ion-searchbar>
`);
const icon = page.locator('ion-searchbar ion-icon.searchbar-search-icon');
expect(await icon.screenshot()).toMatchSnapshot(`searchbar-search-icon-${page.getSnapshotSettings()}.png`);
});
});
test.describe('searchbar: placeholder', () => {
test.beforeEach(({ skip }) => {
skip.rtl();
skip.mode('ios');
});
test('should set placeholder', async ({ page }) => {
await page.setContent(`
<ion-searchbar placeholder="My Placeholder"></ion-searchbar>
`);
const nativeInput = page.locator('ion-searchbar input');
await expect(nativeInput).toHaveAttribute('placeholder', 'My Placeholder');
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -11,30 +11,20 @@ test.describe('textarea: autogrow', () => {
});
test('should grow when typing', async ({ page }) => {
await page.setContent(
`
<ion-app>
<ion-content>
<ion-list>
<ion-item>
await page.setContent(`
<ion-textarea auto-grow="true"></ion-textarea>
</ion-item>
</ion-list>
</ion-content>
</ion-app>`
`);
const ionTextarea = page.locator('ion-textarea');
const nativeTextarea = ionTextarea.locator('textarea');
await nativeTextarea.type('Now, this is a story all about how');
expect(await ionTextarea.screenshot({})).toMatchSnapshot(
`textarea-autogrow-initial-${page.getSnapshotSettings()}.png`
);
const textarea = await page.waitForSelector('ion-textarea');
await textarea.click();
await textarea.type('Now, this is a story all about how');
await page.setIonViewport();
expect(await textarea.screenshot()).toMatchSnapshot(`textarea-autogrow-initial-${page.getSnapshotSettings()}.png`);
await textarea.type(
await nativeTextarea.type(
[
`\nMy life got flipped-turned upside down`,
`And I'd like to take a minute`,
@ -43,7 +33,7 @@ test.describe('textarea: autogrow', () => {
].join('\n')
);
expect(await textarea.screenshot()).toMatchSnapshot(`textarea-autogrow-after-${page.getSnapshotSettings()}.png`);
expect(await ionTextarea.screenshot()).toMatchSnapshot(`textarea-autogrow-after-${page.getSnapshotSettings()}.png`);
});
test('should break long lines without white space', async ({ page }) => {
@ -53,17 +43,13 @@ test.describe('textarea: autogrow', () => {
});
await page.setContent(
`<ion-app>
<ion-content>
<ion-textarea
`<ion-textarea
auto-grow="true"
value="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz">
</ion-textarea>
</ion-content>
</ion-app>`
</ion-textarea>`
);
const textarea = await page.locator('ion-textarea');
const textarea = page.locator('ion-textarea');
expect(await textarea.screenshot()).toMatchSnapshot(
`textarea-autogrow-word-break-${page.getSnapshotSettings()}.png`

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -1,6 +1,12 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('tap click utility', () => {
// TODO FW-3010
test.describe.skip('tap click utility', () => {
test.beforeEach(({ skip }) => {
skip.rtl();
skip.mode('ios');
});
test('it should apply activated class when clicking element', async ({ page }) => {
await page.setContent(`
<ion-app>
@ -14,8 +20,9 @@ test.describe('tap click utility', () => {
if (box) {
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
await page.mouse.down();
await page.waitForChanges();
}
await page.waitForSelector('button.ion-activated');
await expect(button).toHaveClass(/ion-activated/);
});
});

View File

@ -108,29 +108,6 @@ test.describe('overlays: focus', () => {
test.beforeEach(({ skip }) => {
skip.rtl();
});
test('should not focus the overlay container if element inside of overlay is focused', async ({ page }) => {
await page.setContent(`
<ion-button id="open-modal">Show Modal</ion-button>
<ion-modal trigger="open-modal">
<ion-content>
<ion-input autofocus="true"></ion-input>
</ion-content>
</ion-modal>
`);
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const button = page.locator('ion-button');
const input = page.locator('ion-input');
await button.click();
await input.evaluate((el: HTMLIonInputElement) => el.setFocus());
await ionModalDidPresent.next();
await page.waitForChanges();
await expect(page.locator('ion-input input')).toBeFocused();
});
test('should not select a hidden focusable element', async ({ page, browserName }) => {
await page.setContent(`
<style>