mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-14 08:45:20 +08:00
docs(testing, components): clarify testing and focusable usage (#29424)
This PR makes the following changes: 1. Clarifies when `.ion-focusable` should be used versus `:focus-visible`. 2. Clarifies that `Locator` needs to be typecast when using `Locator.spyOnEvent`.
This commit is contained in:
@ -152,9 +152,6 @@ The focused state should be enabled for elements with actions when tabbed to via
|
||||
> [!WARNING]
|
||||
> Do not use `:focus` because that will cause the focus to apply even when an element is tapped (because the element is now focused). Instead, we only want the focus state to be shown when it makes sense which is what the `.ion-focusable` utility mentioned below does.
|
||||
|
||||
> [!NOTE]
|
||||
> The [`:focus-visible`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible) pseudo-class mostly does the same thing as our JavaScript-driven utility. However, it does not work well with Shadow DOM components as the element that receives focus is typically inside of the Shadow DOM, but we usually want to set the `:focus-visible` state on the host so we can style other parts of the component. Using other combinations such as `:has(:focus-visible)` does not work because `:has` does not pierce the Shadow DOM (as that would leak implementation details about the Shadow DOM contents). `:focus-within` does work with the Shadow DOM, but that has the same problem as `:focus` that was mentioned before. Unfortunately, a [`:focus-visible-within` pseudo-class does not exist yet](https://github.com/WICG/focus-visible/issues/151).
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Make sure the component has the correct [component structure](#component-structure) before continuing.
|
||||
|
||||
@ -215,6 +212,15 @@ ion-button {
|
||||
}
|
||||
```
|
||||
|
||||
#### When to use `.ion-focusable` versus `:focus-visible`
|
||||
|
||||
The [`:focus-visible`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible) pseudo-class mostly does the same thing as our JavaScript-driven utility. However, it does not work well with Shadow DOM components as the element that receives focus is typically inside of the Shadow DOM, but we usually want to set the `:focus-visible` state on the host so we can style other parts of the component.
|
||||
|
||||
Using other combinations such as `:has(:focus-visible)` does not work because `:has` does not pierce the Shadow DOM (as that would leak implementation details about the Shadow DOM contents). `:focus-within` does work with the Shadow DOM, but that has the same problem as `:focus` that was mentioned before. Unfortunately, a [`:focus-visible-within` pseudo-class does not exist yet](https://github.com/WICG/focus-visible/issues/151).
|
||||
|
||||
The `.ion-focusable` class should be used when you want to style Element A based on the state of Element B. For example, the Button component styles the host of the component (Element A) when the native `button` inside the Shadow DOM (Element B) has focus.
|
||||
|
||||
On the other hand, the `:focus-visible` pseudo-class can be used when you want to style the element based on its own state. For example, we could use `:focus-visible` to style the clear icon on Input when the icon itself is focused.
|
||||
|
||||
### Hover
|
||||
|
||||
|
@ -174,6 +174,19 @@ configs().forEach(({ config, title }) => {
|
||||
});
|
||||
```
|
||||
|
||||
#### `spyOnEvent` with Locators
|
||||
|
||||
Locators have been updated with a `spyOnEvent` method which allows you to listen for an event on the element that the locator matches. Note that Playwright does not support changing the type of an existing fixture, so Locators that use `spyOnEvent` need to be manually cast as `E2ELocator`:
|
||||
|
||||
```typescript
|
||||
import type { E2ELocator } from '@utils/test/playwright';
|
||||
|
||||
...
|
||||
|
||||
const alert = page.locator('ion-alert') as E2ELocator;
|
||||
const ionAlertDidPresent = await alert.spyOnEvent('ionAlertDidPresent');
|
||||
```
|
||||
|
||||
### Using `setIonViewport`
|
||||
|
||||
`setIonViewport` is only needed when a) you are using `ion-content` and b) you need to take a screenshot of the full page (including content that may overflow offscreen).
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Reference in New Issue
Block a user