test(radio-group): add e2e test for supporting text

This commit is contained in:
Brandy Smith
2025-02-27 14:21:04 -05:00
parent 0827a4cffe
commit a8d5165675
2 changed files with 421 additions and 0 deletions

View File

@@ -0,0 +1,174 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Radio Group - Supporting Text</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<style>
.grid {
display: grid;
grid-template-columns: repeat(3, minmax(200px, 1fr));
grid-row-gap: 20px;
grid-column-gap: 20px;
}
h2 {
font-size: 12px;
font-weight: normal;
color: #6f7378;
margin-top: 10px;
}
ion-radio {
width: 100%;
}
</style>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Radio Group - Supporting Text</ion-title>
</ion-toolbar>
</ion-header>
<ion-content id="content" class="ion-padding">
<div class="grid">
<div class="grid-item">
<h2>No Supporting Text</h2>
<ion-radio-group value="1">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
<ion-radio value="4">Label</ion-radio>
<ion-radio value="5">Label</ion-radio>
</ion-radio-group>
</div>
<div class="grid-item">
<h2>Helper Text</h2>
<ion-radio-group value="1" helper-text="Helper text" error-text="Error text">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
<ion-radio value="4">Label</ion-radio>
<ion-radio value="5">Label</ion-radio>
</ion-radio-group>
</div>
<div class="grid-item">
<h2>Error Text</h2>
<ion-radio-group
value="1"
helper-text="Helper text"
error-text="Error text"
class="ion-invalid ion-touched"
>
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
<ion-radio value="4">Label</ion-radio>
<ion-radio value="5">Label</ion-radio>
</ion-radio-group>
</div>
<div class="grid-item">
<ion-list>
<ion-list-header>List</ion-list-header>
<ion-radio-group value="1">
<ion-item>
<ion-radio value="1">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="2">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="3">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="4">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="5">Label</ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
</div>
<div class="grid-item">
<ion-list>
<ion-list-header>Supporting Text: List</ion-list-header>
<ion-radio-group value="1" helper-text="Helper text" error-text="Error text">
<ion-item>
<ion-radio value="1">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="2">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="3">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="4">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="5">Label</ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
</div>
<div class="grid-item">
<ion-list>
<ion-list-header>Error Text: List</ion-list-header>
<ion-radio-group
value="1"
helper-text="Helper text"
error-text="Error text"
class="ion-invalid ion-touched"
>
<ion-item>
<ion-radio value="1">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="2">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="3">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="4">Label</ion-radio>
</ion-item>
<ion-item>
<ion-radio value="5">Label</ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
</div>
</div>
<button onclick="toggleValid()" class="expand">Toggle error</button>
<script>
const radioGroups = document.querySelectorAll('ion-radio-group[helper-text]');
function toggleValid() {
radioGroups.forEach((radioGroup) => {
radioGroup.classList.toggle('ion-invalid');
radioGroup.classList.toggle('ion-touched');
});
}
</script>
</ion-content>
</ion-app>
</body>
</html>

View File

@@ -0,0 +1,247 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
/**
* Functionality is the same across modes & directions
*/
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('radio group: supporting text functionality'), () => {
test('should not render bottom content if no hint is enabled', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const bottomEl = page.locator('ion-radio-group .radio-bottom');
await expect(bottomEl).toHaveCount(0);
});
test('helper text should be visible initially', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1" helper-text="Helper text" error-text="Error text">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const helperText = page.locator('ion-radio-group .helper-text');
const errorText = page.locator('ion-radio-group .error-text');
await expect(helperText).toBeVisible();
await expect(helperText).toHaveText('Helper text');
await expect(errorText).toBeHidden();
});
test('radio group should have an aria-describedby attribute when helper text is present', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1" helper-text="Helper text" error-text="Error text">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const radioGroup = page.locator('ion-radio-group');
const helperText = page.locator('ion-radio-group .helper-text');
const helperTextId = await helperText.getAttribute('id');
const ariaDescribedBy = await radioGroup.getAttribute('aria-describedby');
expect(ariaDescribedBy).toBe(helperTextId);
});
test('error text should be visible when radio group is invalid', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1" class="ion-invalid ion-touched" helper-text="Helper text" error-text="Error text">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const helperText = page.locator('ion-radio-group .helper-text');
const errorText = page.locator('ion-radio-group .error-text');
await expect(helperText).toBeHidden();
await expect(errorText).toBeVisible();
await expect(errorText).toHaveText('Error text');
});
test('radio group should have an aria-describedby attribute when error text is present', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1" class="ion-invalid ion-touched" helper-text="Helper text" error-text="Error text">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const radioGroup = page.locator('ion-radio-group');
const errorText = page.locator('ion-radio-group .error-text');
const errorTextId = await errorText.getAttribute('id');
const ariaDescribedBy = await radioGroup.getAttribute('aria-describedby');
expect(ariaDescribedBy).toBe(errorTextId);
});
test('radio group should have aria-invalid attribute when radio group is invalid', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1" class="ion-invalid ion-touched" helper-text="Helper text" error-text="Error text">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const radioGroup = page.locator('ion-radio-group');
await expect(radioGroup).toHaveAttribute('aria-invalid');
});
test('radio group should not have aria-invalid attribute when radio group is valid', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1" helper-text="Helper text" error-text="Error text">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const radioGroup = page.locator('ion-radio-group');
await expect(radioGroup).not.toHaveAttribute('aria-invalid');
});
test('radio group should not have aria-describedby attribute when no hint or error text is present', async ({
page,
}) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const radioGroup = page.locator('ion-radio-group');
await expect(radioGroup).not.toHaveAttribute('aria-describedby');
});
});
});
/**
* Rendering is different across modes
*/
configs({ modes: ['ios', 'md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('radio-group: supporting text rendering'), () => {
test('should not have visual regressions when rendering helper text', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1" helper-text="Helper text">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const radioGroup = page.locator('ion-radio-group');
await expect(radioGroup).toHaveScreenshot(screenshot(`radio-group-helper-text`));
});
test('should not have visual regressions when rendering error text', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1" class="ion-invalid ion-touched" error-text="Error text">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const radioGroup = page.locator('ion-radio-group');
await expect(radioGroup).toHaveScreenshot(screenshot(`radio-group-error-text`));
});
});
});
/**
* Customizing supporting text is the same across modes and directions
*/
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('radio group: supporting text customization'), () => {
test('should not have visual regressions when rendering helper text with custom css', async ({ page }) => {
await page.setContent(
`
<style>
.supporting-text {
font-size: 20px;
}
.helper-text {
color: green;
}
</style>
<ion-radio-group value="1" helper-text="Helper text">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const radioGroup = page.locator('ion-radio-group');
await expect(radioGroup).toHaveScreenshot(screenshot(`radio-group-helper-text-custom-css`));
});
test('should not have visual regressions when rendering error text with custom css', async ({ page }) => {
await page.setContent(
`
<style>
.supporting-text {
font-size: 20px;
}
.error-text {
color: purple;
}
</style>
<ion-radio-group value="1" class="ion-invalid ion-touched" error-text="Error text">
<ion-radio value="1">Label</ion-radio>
<ion-radio value="2">Label</ion-radio>
<ion-radio value="3">Label</ion-radio>
</ion-radio-group>
`,
config
);
const radioGroup = page.locator('ion-radio-group');
await expect(radioGroup).toHaveScreenshot(screenshot(`radio-group-error-text-custom-css`));
});
});
});