chore(): sync with main

This commit is contained in:
Liam DeBeasi
2022-06-27 09:54:57 -04:00
391 changed files with 15762 additions and 40817 deletions

View File

@@ -1006,7 +1006,8 @@ export namespace Components {
}
interface IonInput {
/**
* If the value of the type attribute is `"file"`, then this attribute will indicate the types of files that the server accepts, otherwise it will be ignored. The value must be a comma-separated list of unique content type specifiers.
* This attribute is ignored.
* @deprecated
*/
"accept"?: string;
/**
@@ -1082,7 +1083,7 @@ export namespace Components {
*/
"mode"?: "ios" | "md";
/**
* If `true`, the user can enter more than one value. This attribute applies when the type attribute is set to `"email"` or `"file"`, otherwise it is ignored.
* If `true`, the user can enter more than one value. This attribute applies when the type attribute is set to `"email"`, otherwise it is ignored.
*/
"multiple"?: boolean;
/**
@@ -1604,7 +1605,7 @@ export namespace Components {
*/
"setCurrentBreakpoint": (breakpoint: number) => Promise<void>;
/**
* If `true`, a backdrop will be displayed behind the modal.
* If `true`, a backdrop will be displayed behind the modal. This property controls whether or not the backdrop darkens the screen when the modal is presented. It does not control whether or not the backdrop is active or present in the DOM.
*/
"showBackdrop": boolean;
/**
@@ -1623,7 +1624,7 @@ export namespace Components {
*/
"animated": boolean;
/**
* By default `ion-nav` animates transition between pages based in the mode (ios or material design). However, this property allows to create custom transition using `AnimateBuilder` functions.
* By default `ion-nav` animates transition between pages based in the mode (ios or material design). However, this property allows to create custom transition using `AnimationBuilder` functions.
*/
"animation"?: AnimationBuilder;
/**
@@ -1970,7 +1971,7 @@ export namespace Components {
*/
"reference": PositionReference;
/**
* If `true`, a backdrop will be displayed behind the popover.
* If `true`, a backdrop will be displayed behind the popover. This property controls whether or not the backdrop darkens the screen when the popover is presented. It does not control whether or not the backdrop is active or present in the DOM.
*/
"showBackdrop": boolean;
/**
@@ -2284,7 +2285,7 @@ export namespace Components {
*/
"animated": boolean;
/**
* This property allows to create custom transition using AnimateBuilder functions.
* This property allows to create custom transition using AnimationBuilder functions.
*/
"animation"?: AnimationBuilder;
"commit": (enteringEl: HTMLElement, leavingEl: HTMLElement | undefined, opts?: RouterOutletOptions | undefined) => Promise<boolean>;
@@ -4936,7 +4937,8 @@ declare namespace LocalJSX {
}
interface IonInput {
/**
* If the value of the type attribute is `"file"`, then this attribute will indicate the types of files that the server accepts, otherwise it will be ignored. The value must be a comma-separated list of unique content type specifiers.
* This attribute is ignored.
* @deprecated
*/
"accept"?: string;
/**
@@ -5008,7 +5010,7 @@ declare namespace LocalJSX {
*/
"mode"?: "ios" | "md";
/**
* If `true`, the user can enter more than one value. This attribute applies when the type attribute is set to `"email"` or `"file"`, otherwise it is ignored.
* If `true`, the user can enter more than one value. This attribute applies when the type attribute is set to `"email"`, otherwise it is ignored.
*/
"multiple"?: boolean;
/**
@@ -5536,7 +5538,7 @@ declare namespace LocalJSX {
*/
"presentingElement"?: HTMLElement;
/**
* If `true`, a backdrop will be displayed behind the modal.
* If `true`, a backdrop will be displayed behind the modal. This property controls whether or not the backdrop darkens the screen when the modal is presented. It does not control whether or not the backdrop is active or present in the DOM.
*/
"showBackdrop"?: boolean;
/**
@@ -5555,7 +5557,7 @@ declare namespace LocalJSX {
*/
"animated"?: boolean;
/**
* By default `ion-nav` animates transition between pages based in the mode (ios or material design). However, this property allows to create custom transition using `AnimateBuilder` functions.
* By default `ion-nav` animates transition between pages based in the mode (ios or material design). However, this property allows to create custom transition using `AnimationBuilder` functions.
*/
"animation"?: AnimationBuilder;
"delegate"?: FrameworkDelegate;
@@ -5824,7 +5826,7 @@ declare namespace LocalJSX {
*/
"reference"?: PositionReference;
/**
* If `true`, a backdrop will be displayed behind the popover.
* If `true`, a backdrop will be displayed behind the popover. This property controls whether or not the backdrop darkens the screen when the popover is presented. It does not control whether or not the backdrop is active or present in the DOM.
*/
"showBackdrop"?: boolean;
/**
@@ -6172,7 +6174,7 @@ declare namespace LocalJSX {
*/
"animated"?: boolean;
/**
* This property allows to create custom transition using AnimateBuilder functions.
* This property allows to create custom transition using AnimationBuilder functions.
*/
"animation"?: AnimationBuilder;
"delegate"?: FrameworkDelegate;

View File

@@ -0,0 +1,42 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('accordion: a11y', () => {
test('accordions should be keyboard navigable', async ({ page, browserName }) => {
// TODO(FW-1764): remove skip once issue is resolved
test.skip(browserName === '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';
const personalInfoHeader = page.locator('ion-accordion:first-child > ion-item');
const billingAddressHeader = page.locator('ion-accordion:nth-child(2) > ion-item');
const shippingAddressHeader = page.locator('ion-accordion:nth-child(3) > ion-item');
const addressInput = page.locator('#address1 input');
await page.keyboard.press(tabKey);
await expect(personalInfoHeader).toBeFocused();
await page.keyboard.press('ArrowDown');
await expect(billingAddressHeader).toBeFocused();
await page.keyboard.press('ArrowDown');
await expect(shippingAddressHeader).toBeFocused();
await page.keyboard.press('ArrowDown');
await expect(personalInfoHeader).toBeFocused();
await page.keyboard.press('ArrowUp');
await expect(shippingAddressHeader).toBeFocused();
// open Shipping Address accordion and move focus to the input inside it
await page.keyboard.press('Enter');
await page.waitForChanges();
await page.keyboard.press(tabKey);
await expect(addressInput).toBeFocused();
// ensure keyboard interaction doesn't move focus from body
await page.keyboard.press('ArrowDown');
await expect(addressInput).toBeFocused();
});
});

View File

@@ -1,63 +0,0 @@
import { newE2EPage } from '@stencil/core/testing';
const getActiveElementText = async (page) => {
const activeElement = await page.evaluateHandle(() => document.activeElement);
return page.evaluate((el) => el?.innerText, activeElement);
};
const getActiveInputID = async (page) => {
const activeElement = await page.evaluateHandle(() => document.activeElement);
return page.evaluate((el) => el?.closest('ion-input')?.id, activeElement);
};
test('accordion: a11y', async () => {
const page = await newE2EPage({
url: '/src/components/accordion/test/a11y?ionic:_testing=true',
});
const compare = await page.compareScreenshot();
expect(compare).toMatchScreenshot();
});
test('accordion:rtl: a11y', async () => {
const page = await newE2EPage({
url: '/src/components/accordion/test/a11y?ionic:_testing=true&rtl=true',
});
const compare = await page.compareScreenshot();
expect(compare).toMatchScreenshot();
});
test('accordion: keyboard navigation', async () => {
const page = await newE2EPage({
url: '/src/components/accordion/test/a11y?ionic:_testing=true',
});
await page.keyboard.press('Tab');
expect(await getActiveElementText(page)).toEqual('Personal Information');
await page.keyboard.press('ArrowDown');
expect(await getActiveElementText(page)).toEqual('Billing Address');
await page.keyboard.press('ArrowDown');
expect(await getActiveElementText(page)).toEqual('Shipping Address');
await page.keyboard.press('ArrowDown');
expect(await getActiveElementText(page)).toEqual('Personal Information');
await page.keyboard.press('ArrowUp');
expect(await getActiveElementText(page)).toEqual('Shipping Address');
// open Shipping Address accordion and move focus to the input inside it
await page.keyboard.press('Enter');
await page.waitForChanges();
await page.keyboard.press('Tab');
const activeID = await getActiveInputID(page);
expect(activeID).toEqual('address1');
// ensure keyboard interaction doesn't move focus from body
await page.keyboard.press('ArrowDown');
const activeIDAgain = await getActiveInputID(page);
expect(activeIDAgain).toEqual('address1');
});

View File

@@ -0,0 +1,12 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('accordion: basic', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/accordion/test/basic`);
await page.setIonViewport();
expect(await page.screenshot()).toMatchSnapshot(`accordion-basic-${page.getSnapshotSettings()}.png`);
});
});

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

View File

@@ -1,10 +0,0 @@
import { newE2EPage } from '@stencil/core/testing';
test('accordion: basic', async () => {
const page = await newE2EPage({
url: '/src/components/accordion/test/basic?ionic:_testing=true',
});
const compare = await page.compareScreenshot();
expect(compare).toMatchScreenshot();
});

View File

@@ -42,12 +42,12 @@
<div class="grid ion-padding">
<div class="grid-item">
<h2>Inset, Color - iOS</h2>
<ion-accordion-group mode="ios" expand="inset">
<h2>Inset, Color</h2>
<ion-accordion-group expand="inset" value="attractions">
<ion-accordion value="attractions">
<ion-item color="primary" slot="header" button detail="false">
<ion-icon slot="start" ios="film-outline" md="film"></ion-icon>
<ion-label> Attractions</ion-label>
<ion-label>Attractions</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
@@ -118,12 +118,12 @@
</div>
<div class="grid-item">
<h2>Inset - iOS</h2>
<ion-accordion-group mode="ios" expand="inset">
<h2>Inset</h2>
<ion-accordion-group expand="inset" value="attractions">
<ion-accordion value="attractions">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" ios="film-outline" md="film"></ion-icon>
<ion-label> Attractions</ion-label>
<ion-label>Attractions</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
@@ -194,12 +194,12 @@
</div>
<div class="grid-item">
<h2>Inset, Color - MD</h2>
<ion-accordion-group mode="md" expand="inset">
<h2>Compact, Color</h2>
<ion-accordion-group value="attractions">
<ion-accordion value="attractions">
<ion-item color="primary" slot="header" button detail="false">
<ion-icon slot="start" ios="film-outline" md="film"></ion-icon>
<ion-label> Attractions</ion-label>
<ion-label>Attractions</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
@@ -270,394 +270,12 @@
</div>
<div class="grid-item">
<h2>Inset - MD</h2>
<ion-accordion-group mode="md" expand="inset">
<h2>Compact</h2>
<ion-accordion-group value="attractions">
<ion-accordion value="attractions">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" ios="film-outline" md="film"></ion-icon>
<ion-label> Attractions</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Movie Theaters</ion-label>
</ion-item>
<ion-item>
<ion-label>Amusement Parks</ion-label>
</ion-item>
<ion-item>
<ion-label>Mini Golf</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="dining">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" name="pizza"></ion-icon>
<ion-label>Dining</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Breakfast & Brunch</ion-label>
</ion-item>
<ion-item>
<ion-label>New American</ion-label>
</ion-item>
<ion-item>
<ion-label>Sushi Bars</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="games">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" ios="game-controller-outline" md="game-controller"></ion-icon>
<ion-label>Games</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Xbox</ion-label>
</ion-item>
<ion-item>
<ion-label>Playstation</ion-label>
</ion-item>
<ion-item>
<ion-label>Switch</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="exercise">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" ios="bicycle-outline" md="bicycle"></ion-icon>
<ion-label>Exercise</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Jog</ion-label>
</ion-item>
<ion-item>
<ion-label>Swim</ion-label>
</ion-item>
<ion-item>
<ion-label>Nap</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
</ion-accordion-group>
</div>
</div>
<div class="grid ion-padding">
<div class="grid-item">
<h2>Compact, Color - iOS</h2>
<ion-accordion-group mode="ios">
<ion-accordion value="attractions">
<ion-item color="primary" slot="header" button detail="false">
<ion-icon slot="start" ios="film-outline" md="film"></ion-icon>
<ion-label> Attractions</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Movie Theaters</ion-label>
</ion-item>
<ion-item>
<ion-label>Amusement Parks</ion-label>
</ion-item>
<ion-item>
<ion-label>Mini Golf</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="dining">
<ion-item color="warning" slot="header" button detail="false">
<ion-icon slot="start" name="pizza"></ion-icon>
<ion-label>Dining</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Breakfast & Brunch</ion-label>
</ion-item>
<ion-item>
<ion-label>New American</ion-label>
</ion-item>
<ion-item>
<ion-label>Sushi Bars</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="games">
<ion-item color="danger" slot="header" button detail="false">
<ion-icon slot="start" ios="game-controller-outline" md="game-controller"></ion-icon>
<ion-label>Games</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Xbox</ion-label>
</ion-item>
<ion-item>
<ion-label>Playstation</ion-label>
</ion-item>
<ion-item>
<ion-label>Switch</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="exercise">
<ion-item color="success" slot="header" button detail="false">
<ion-icon slot="start" ios="bicycle-outline" md="bicycle"></ion-icon>
<ion-label>Exercise</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Jog</ion-label>
</ion-item>
<ion-item>
<ion-label>Swim</ion-label>
</ion-item>
<ion-item>
<ion-label>Nap</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
</ion-accordion-group>
</div>
<div class="grid-item">
<h2>Compact - iOS</h2>
<ion-accordion-group mode="ios">
<ion-accordion value="attractions">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" ios="film-outline" md="film"></ion-icon>
<ion-label> Attractions</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Movie Theaters</ion-label>
</ion-item>
<ion-item>
<ion-label>Amusement Parks</ion-label>
</ion-item>
<ion-item>
<ion-label>Mini Golf</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="dining">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" name="pizza"></ion-icon>
<ion-label>Dining</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Breakfast & Brunch</ion-label>
</ion-item>
<ion-item>
<ion-label>New American</ion-label>
</ion-item>
<ion-item>
<ion-label>Sushi Bars</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="games">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" ios="game-controller-outline" md="game-controller"></ion-icon>
<ion-label>Games</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Xbox</ion-label>
</ion-item>
<ion-item>
<ion-label>Playstation</ion-label>
</ion-item>
<ion-item>
<ion-label>Switch</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="exercise">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" ios="bicycle-outline" md="bicycle"></ion-icon>
<ion-label>Exercise</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Jog</ion-label>
</ion-item>
<ion-item>
<ion-label>Swim</ion-label>
</ion-item>
<ion-item>
<ion-label>Nap</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
</ion-accordion-group>
</div>
<div class="grid-item">
<h2>Compact, Color - MD</h2>
<ion-accordion-group mode="md">
<ion-accordion value="attractions">
<ion-item color="primary" slot="header" button detail="false">
<ion-icon slot="start" ios="film-outline" md="film"></ion-icon>
<ion-label> Attractions</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Movie Theaters</ion-label>
</ion-item>
<ion-item>
<ion-label>Amusement Parks</ion-label>
</ion-item>
<ion-item>
<ion-label>Mini Golf</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="dining">
<ion-item color="warning" slot="header" button detail="false">
<ion-icon slot="start" name="pizza"></ion-icon>
<ion-label>Dining</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Breakfast & Brunch</ion-label>
</ion-item>
<ion-item>
<ion-label>New American</ion-label>
</ion-item>
<ion-item>
<ion-label>Sushi Bars</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="games">
<ion-item color="danger" slot="header" button detail="false">
<ion-icon slot="start" ios="game-controller-outline" md="game-controller"></ion-icon>
<ion-label>Games</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Xbox</ion-label>
</ion-item>
<ion-item>
<ion-label>Playstation</ion-label>
</ion-item>
<ion-item>
<ion-label>Switch</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="exercise">
<ion-item color="success" slot="header" button detail="false">
<ion-icon slot="start" ios="bicycle-outline" md="bicycle"></ion-icon>
<ion-label>Exercise</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Jog</ion-label>
</ion-item>
<ion-item>
<ion-label>Swim</ion-label>
</ion-item>
<ion-item>
<ion-label>Nap</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
</ion-accordion-group>
</div>
<div class="grid-item">
<h2>Compact - MD</h2>
<ion-accordion-group mode="md">
<ion-accordion value="attractions">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" ios="film-outline" md="film"></ion-icon>
<ion-label> Attractions</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Movie Theaters</ion-label>
</ion-item>
<ion-item>
<ion-label>Amusement Parks</ion-label>
</ion-item>
<ion-item>
<ion-label>Mini Golf</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="dining">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" name="pizza"></ion-icon>
<ion-label>Dining</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Breakfast & Brunch</ion-label>
</ion-item>
<ion-item>
<ion-label>New American</ion-label>
</ion-item>
<ion-item>
<ion-label>Sushi Bars</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="games">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" ios="game-controller-outline" md="game-controller"></ion-icon>
<ion-label>Games</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Xbox</ion-label>
</ion-item>
<ion-item>
<ion-label>Playstation</ion-label>
</ion-item>
<ion-item>
<ion-label>Switch</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
<ion-accordion value="exercise">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" ios="bicycle-outline" md="bicycle"></ion-icon>
<ion-label>Exercise</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
<ion-label>Jog</ion-label>
</ion-item>
<ion-item>
<ion-label>Swim</ion-label>
</ion-item>
<ion-item>
<ion-label>Nap</ion-label>
</ion-item>
</ion-list>
</ion-accordion>
</ion-accordion-group>
</div>
</div>
<div class="grid ion-padding">
<div class="grid-item">
<h2>Multiple</h2>
<ion-accordion-group expand="inset" mode="md" multiple="true">
<ion-accordion value="attractions">
<ion-item slot="header" button detail="false">
<ion-icon slot="start" ios="film-outline" md="film"></ion-icon>
<ion-label> Attractions</ion-label>
<ion-label>Attractions</ion-label>
</ion-item>
<ion-list lines="none" slot="content">
<ion-item>
@@ -729,10 +347,5 @@
</div>
</ion-content>
</ion-app>
<script>
const multipleAccordion = document.querySelector('ion-accordion-group[multiple="true"]');
multipleAccordion.value = ['dining', 'exercise'];
</script>
</body>
</html>

View File

@@ -0,0 +1,30 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('accordion: multiple', () => {
test('should update value and not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/accordion/test/multiple`);
const accordionGroup = page.locator('ion-accordion-group');
const diningHeader = page.locator('ion-accordion[value="dining"] ion-item[slot="header"]');
const attractionsHeader = page.locator('ion-accordion[value="attractions"] ion-item[slot="header"]');
await expect(accordionGroup).toHaveJSProperty('value', 'attractions');
expect(await accordionGroup.screenshot()).toMatchSnapshot(`accordion-one-open-${page.getSnapshotSettings()}.png`);
await diningHeader.click();
await page.waitForChanges();
await expect(accordionGroup).toHaveJSProperty('value', ['attractions', 'dining']);
expect(await accordionGroup.screenshot()).toMatchSnapshot(`accordion-two-open-${page.getSnapshotSettings()}.png`);
await diningHeader.click();
await attractionsHeader.click();
await page.waitForChanges();
await expect(accordionGroup).toHaveJSProperty('value', []);
expect(await accordionGroup.screenshot()).toMatchSnapshot(`accordion-zero-open-${page.getSnapshotSettings()}.png`);
});
});

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -1,54 +0,0 @@
import { newE2EPage } from '@stencil/core/testing';
test('accordion: multiple - open', async () => {
const page = await newE2EPage({
url: '/src/components/accordion/test/multiple?ionic:_testing=true',
});
const screenshotCompares = [];
screenshotCompares.push(await page.compareScreenshot());
const accordionGroup = await page.find('ion-accordion-group');
const diningAccordion = await page.find('ion-accordion[value="dining"] ion-item[slot="header"]');
const groupValue = await accordionGroup.getProperty('value');
expect(groupValue).toEqual('attractions');
await diningAccordion.click();
await page.waitForChanges();
const groupValueAgain = await accordionGroup.getProperty('value');
expect(groupValueAgain).toEqual(['attractions', 'dining']);
screenshotCompares.push(await page.compareScreenshot());
for (const screenshotCompare of screenshotCompares) {
expect(screenshotCompare).toMatchScreenshot();
}
});
test('accordion: multiple - close', async () => {
const page = await newE2EPage({
url: '/src/components/accordion/test/multiple?ionic:_testing=true',
});
const screenshotCompares = [];
screenshotCompares.push(await page.compareScreenshot());
const accordionGroup = await page.find('ion-accordion-group');
const attractionsAccordion = await page.find('ion-accordion[value="attractions"] ion-item[slot="header"]');
await attractionsAccordion.click();
await page.waitForChanges();
const groupValue = await accordionGroup.getProperty('value');
expect(groupValue).toEqual([]);
screenshotCompares.push(await page.compareScreenshot());
for (const screenshotCompare of screenshotCompares) {
expect(screenshotCompare).toMatchScreenshot();
}
});

View File

@@ -0,0 +1,12 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('accordion: nested', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/accordion/test/nested`);
await page.setIonViewport();
expect(await page.screenshot()).toMatchSnapshot(`accordion-nested-${page.getSnapshotSettings()}.png`);
});
});

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View File

@@ -1,10 +0,0 @@
import { newE2EPage } from '@stencil/core/testing';
test('nested: basic', async () => {
const page = await newE2EPage({
url: '/src/components/accordion/test/nested?ionic:_testing=true',
});
const compare = await page.compareScreenshot();
expect(compare).toMatchScreenshot();
});

View File

@@ -0,0 +1,21 @@
import AxeBuilder from '@axe-core/playwright';
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('accordion: standalone', () => {
test('should not have accessibility violations', async ({ page }) => {
await page.goto(`/src/components/accordion/test/standalone`);
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/accordion/test/standalone`);
expect(await page.screenshot({ fullPage: true })).toMatchSnapshot(
`accordion-standalone-${page.getSnapshotSettings()}.png`
);
});
});

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@@ -1,20 +0,0 @@
import { AxePuppeteer } from '@axe-core/puppeteer';
import { newE2EPage } from '@stencil/core/testing';
test('accordion: axe', async () => {
const page = await newE2EPage({
url: '/src/components/accordion/test/standalone?ionic:_testing=true',
});
const results = await new AxePuppeteer(page).analyze();
expect(results.violations.length).toEqual(0);
});
test('accordion: standalone', async () => {
const page = await newE2EPage({
url: '/src/components/accordion/test/standalone?ionic:_testing=true',
});
const compare = await page.compareScreenshot();
expect(compare).toMatchScreenshot();
});

View File

@@ -0,0 +1,151 @@
import { expect } from '@playwright/test';
import type { Locator } from '@playwright/test';
import { test } from '@utils/test/playwright';
import type { E2EPage } from '@utils/test/playwright';
test.describe('action sheet: basic', () => {
let actionSheetFixture: ActionSheetFixture;
test.beforeEach(async ({ page }) => {
await page.goto(`/src/components/action-sheet/test/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.');
const ionActionSheetDidDismiss = await page.spyOnEvent('ionActionSheetDidDismiss');
await actionSheetFixture.open('#buttonData');
const buttonOption = page.locator('ion-action-sheet button#option');
await buttonOption.click();
await ionActionSheetDidDismiss.next();
expect(ionActionSheetDidDismiss).toHaveReceivedEventDetail({ data: { type: '1' } });
});
test('should return cancel button data', async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs. RTL layout.');
const ionActionSheetDidDismiss = await page.spyOnEvent('ionActionSheetDidDismiss');
await actionSheetFixture.open('#buttonData');
const buttonOption = page.locator('ion-action-sheet button.action-sheet-cancel');
await buttonOption.click();
await ionActionSheetDidDismiss.next();
expect(ionActionSheetDidDismiss).toHaveReceivedEventDetail({ data: { type: 'cancel' }, role: 'cancel' });
});
});
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.');
await actionSheetFixture.open('#basic');
const actionSheet = page.locator('ion-action-sheet');
expect(actionSheet).toHaveAttribute('data-testid', 'basic-action-sheet');
});
});
test.describe('action sheet: variants', () => {
test('should open basic action sheet', async () => {
await actionSheetFixture.open('#basic');
await actionSheetFixture.screenshot('basic');
/**
* We want to test that the dismiss method
* actually works, but we do not need to test
* it every time. As a result, we only
* call dismiss in this test.
*/
await actionSheetFixture.dismiss();
});
test('should open cancel only action sheet', async () => {
await actionSheetFixture.open('#cancelOnly');
await actionSheetFixture.screenshot('cancel-only');
});
test('should open custom action sheet', async () => {
await actionSheetFixture.open('#custom');
await actionSheetFixture.screenshot('custom');
});
test('should open scrollable action sheet', async () => {
await actionSheetFixture.open('#scrollableOptions');
await actionSheetFixture.screenshot('scrollable-options');
});
test('should open scrollable action sheet without cancel', async () => {
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.');
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.');
const ionAlertDidPresent = await page.spyOnEvent('ionAlertDidPresent');
await actionSheetFixture.open('#alertFromActionSheet');
await page.locator('#open-alert').click();
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.');
await actionSheetFixture.open('#noBackdropDismiss');
const actionSheet = page.locator('ion-action-sheet');
await actionSheet.locator('ion-backdrop').click();
expect(actionSheet).toBeVisible();
});
});
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.');
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
await actionSheetFixture.open('#basic');
const buttons = page.locator('ion-action-sheet button');
await page.keyboard.press(tabKey);
await expect(buttons.nth(0)).toBeFocused();
await page.keyboard.press(`Shift+${tabKey}`);
await expect(buttons.nth(4)).toBeFocused();
await page.keyboard.press(tabKey);
await expect(buttons.nth(0)).toBeFocused();
});
});
});
class ActionSheetFixture {
readonly page: E2EPage;
private actionSheet!: Locator;
constructor(page: E2EPage) {
this.page = page;
}
async open(selector: string) {
const ionActionSheetDidPresent = await this.page.spyOnEvent('ionActionSheetDidPresent');
await this.page.locator(selector).click();
await ionActionSheetDidPresent.next();
this.actionSheet = this.page.locator('ion-action-sheet');
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();
}
async screenshot(modifier: string) {
expect(await this.actionSheet.screenshot()).toMatchSnapshot(
`action-sheet-${modifier}-diff-${this.page.getSnapshotSettings()}.png`
);
}
}

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

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