Skip to content

Commit bc8eb22

Browse files
committed
test(toggle): add e2e tests for bottom content
1 parent d1260b2 commit bc8eb22

File tree

3 files changed

+382
-0
lines changed

3 files changed

+382
-0
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<!DOCTYPE html>
2+
<html lang="en" dir="ltr">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Toggle - Bottom Content</title>
6+
<meta
7+
name="viewport"
8+
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
9+
/>
10+
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
11+
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
12+
<script src="../../../../../scripts/testing/scripts.js"></script>
13+
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
14+
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
15+
<style>
16+
.grid {
17+
display: grid;
18+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
19+
grid-row-gap: 20px;
20+
grid-column-gap: 20px;
21+
}
22+
h2 {
23+
font-size: 12px;
24+
font-weight: normal;
25+
26+
color: #6f7378;
27+
28+
margin-top: 10px;
29+
}
30+
ion-toggle {
31+
width: 100%;
32+
}
33+
</style>
34+
</head>
35+
36+
<body>
37+
<ion-app>
38+
<ion-header>
39+
<ion-toolbar>
40+
<ion-title>Toggle - Bottom Content</ion-title>
41+
</ion-toolbar>
42+
</ion-header>
43+
44+
<ion-content id="content" class="ion-padding">
45+
<div class="grid">
46+
<div class="grid-item">
47+
<h2>No Hint</h2>
48+
<ion-toggle>Label</ion-toggle>
49+
</div>
50+
51+
<div class="grid-item">
52+
<h2>No Hint: Stacked</h2>
53+
<ion-toggle label-placement="stacked">Label</ion-toggle>
54+
</div>
55+
56+
<div class="grid-item">
57+
<h2>Helper Text: Label Start</h2>
58+
<ion-toggle helper-text="Helper text" error-text="Error text">Label</ion-toggle>
59+
</div>
60+
61+
<div class="grid-item">
62+
<h2>Helper Text: Label End</h2>
63+
<ion-toggle label-placement="end" helper-text="Helper text" error-text="Error text">Label</ion-toggle>
64+
</div>
65+
66+
<div class="grid-item">
67+
<h2>Helper Text: Label Stacked</h2>
68+
<ion-toggle label-placement="stacked" helper-text="Helper text" error-text="Error text">Label</ion-toggle>
69+
</div>
70+
71+
<div class="grid-item">
72+
<h2>Helper Text: Label Fixed</h2>
73+
<ion-toggle label-placement="fixed" helper-text="Helper text" error-text="Error text">Label</ion-toggle>
74+
</div>
75+
76+
<div class="grid-item">
77+
<h2>Error Text: Label Start</h2>
78+
<ion-toggle helper-text="Helper text" error-text="Error text" class="ion-invalid ion-touched"
79+
>Label</ion-toggle
80+
>
81+
</div>
82+
83+
<div class="grid-item">
84+
<h2>Error Text: Label End</h2>
85+
<ion-toggle
86+
label-placement="end"
87+
helper-text="Helper text"
88+
error-text="Error text"
89+
class="ion-invalid ion-touched"
90+
>Label</ion-toggle
91+
>
92+
</div>
93+
94+
<div class="grid-item">
95+
<h2>Error Text: Label Stacked</h2>
96+
<ion-toggle
97+
label-placement="stacked"
98+
helper-text="Helper text"
99+
error-text="Error text"
100+
class="ion-invalid ion-touched"
101+
>Label</ion-toggle
102+
>
103+
</div>
104+
105+
<div class="grid-item">
106+
<h2>Error Text: Label Fixed</h2>
107+
<ion-toggle
108+
label-placement="fixed"
109+
helper-text="Helper text"
110+
error-text="Error text"
111+
class="ion-invalid ion-touched"
112+
>Label</ion-toggle
113+
>
114+
</div>
115+
</div>
116+
117+
<button onclick="toggleValid()" class="expand">Toggle error</button>
118+
119+
<script>
120+
const toggles = document.querySelectorAll('ion-toggle[helper-text]');
121+
122+
function toggleValid() {
123+
toggles.forEach((toggle) => {
124+
toggle.classList.toggle('ion-invalid');
125+
toggle.classList.toggle('ion-touched');
126+
});
127+
}
128+
</script>
129+
</ion-content>
130+
</ion-app>
131+
</body>
132+
</html>
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
import { expect } from '@playwright/test';
2+
import { configs, test } from '@utils/test/playwright';
3+
4+
/**
5+
* Functionality is the same across modes & directions
6+
*/
7+
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
8+
test.describe(title('toggle: bottom content functionality'), () => {
9+
test('should not render bottom content if no hint is enabled', async ({ page }) => {
10+
await page.setContent(`<ion-toggle>Label</ion-toggle>`, config);
11+
12+
const bottomEl = page.locator('ion-toggle .toggle-bottom');
13+
await expect(bottomEl).toHaveCount(0);
14+
});
15+
test('helper text should be visible initially', async ({ page }) => {
16+
await page.setContent(`<ion-toggle helper-text="Helper text" error-text="Error text">Label</ion-toggle>`, config);
17+
18+
const helperText = page.locator('ion-toggle .helper-text');
19+
const errorText = page.locator('ion-toggle .error-text');
20+
await expect(helperText).toBeVisible();
21+
await expect(helperText).toHaveText('Helper text');
22+
await expect(errorText).toBeHidden();
23+
});
24+
test('input should have an aria-describedby attribute when helper text is present', async ({ page }) => {
25+
await page.setContent(`<ion-toggle helper-text="Helper text" error-text="Error text">Label</ion-toggle>`, config);
26+
27+
const input = page.locator('ion-toggle input[type=checkbox]');
28+
const helperText = page.locator('ion-toggle .helper-text');
29+
const helperTextId = await helperText.getAttribute('id');
30+
const ariaDescribedBy = await input.getAttribute('aria-describedby');
31+
32+
expect(ariaDescribedBy).toBe(helperTextId);
33+
});
34+
test('error text should be visible when toggleis invalid', async ({ page }) => {
35+
await page.setContent(
36+
`<ion-toggle class="ion-invalid ion-touched" helper-text="Helper text" error-text="Error text">Label</ion-toggle>`,
37+
config
38+
);
39+
40+
const helperText = page.locator('ion-toggle .helper-text');
41+
const errorText = page.locator('ion-toggle .error-text');
42+
await expect(helperText).toBeHidden();
43+
await expect(errorText).toBeVisible();
44+
await expect(errorText).toHaveText('Error text');
45+
});
46+
47+
test('input should have an aria-describedby attribute when error text is present', async ({ page }) => {
48+
await page.setContent(
49+
`<ion-toggle class="ion-invalid ion-touched" helper-text="Helper text" error-text="Error text">Label</ion-toggle>`,
50+
config
51+
);
52+
53+
const input = page.locator('ion-toggle input[type=checkbox]');
54+
const errorText = page.locator('ion-toggle .error-text');
55+
const errorTextId = await errorText.getAttribute('id');
56+
const ariaDescribedBy = await input.getAttribute('aria-describedby');
57+
58+
expect(ariaDescribedBy).toBe(errorTextId);
59+
});
60+
test('input should have aria-invalid attribute when toggleis invalid', async ({ page }) => {
61+
await page.setContent(
62+
`<ion-toggle class="ion-invalid ion-touched" helper-text="Helper text" error-text="Error text">Label</ion-toggle>`,
63+
config
64+
);
65+
66+
const input = page.locator('ion-toggle input[type=checkbox]');
67+
68+
await expect(input).toHaveAttribute('aria-invalid');
69+
});
70+
test('input should not have aria-invalid attribute when toggleis valid', async ({ page }) => {
71+
await page.setContent(`<ion-toggle helper-text="Helper text" error-text="Error text">Label</ion-toggle>`, config);
72+
73+
const input = page.locator('ion-toggle input[type=checkbox]');
74+
75+
await expect(input).not.toHaveAttribute('aria-invalid');
76+
});
77+
test('input should not have aria-describedby attribute when no hint or error text is present', async ({ page }) => {
78+
await page.setContent(`<ion-toggle>Label</ion-toggle>`, config);
79+
80+
const input = page.locator('ion-toggle input[type=checkbox]');
81+
82+
await expect(input).not.toHaveAttribute('aria-describedby');
83+
});
84+
});
85+
});
86+
87+
/**
88+
* Rendering is different across modes
89+
*/
90+
configs({ modes: ['ios', 'md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
91+
test.describe(title('toggle: helper text rendering'), () => {
92+
// Check the default label placement, end, and stacked
93+
[undefined, 'end', 'stacked'].forEach((labelPlacement) => {
94+
test(`${
95+
labelPlacement ? `${labelPlacement} label - ` : ''
96+
}should not have visual regressions when rendering helper text`, async ({ page }) => {
97+
await page.setContent(
98+
`<ion-toggle ${
99+
labelPlacement ? `label-placement="${labelPlacement}"` : ''
100+
} helper-text="Helper text">Label</ion-toggle>`,
101+
config
102+
);
103+
104+
const bottomEl = page.locator('ion-toggle');
105+
await expect(bottomEl).toHaveScreenshot(
106+
screenshot(`toggle-helper-text${labelPlacement ? `-${labelPlacement}` : ''}`)
107+
);
108+
});
109+
110+
test(`${
111+
labelPlacement ? `${labelPlacement} label - ` : ''
112+
}should not have visual regressions when rendering helper text with wrapping text`, async ({ page }) => {
113+
await page.setContent(
114+
`<ion-toggle ${
115+
labelPlacement ? `label-placement="${labelPlacement}"` : ''
116+
} helper-text="Helper text helper text helper text helper text helper text helper text helper text helper text helper text">Label</ion-toggle>`,
117+
config
118+
);
119+
120+
const bottomEl = page.locator('ion-toggle');
121+
await expect(bottomEl).toHaveScreenshot(
122+
screenshot(`toggle-helper-text${labelPlacement ? `-${labelPlacement}` : ''}-wrapping`)
123+
);
124+
});
125+
});
126+
});
127+
128+
test.describe(title('toggle: error text rendering'), () => {
129+
test('should not have visual regressions when rendering error text', async ({ page }) => {
130+
await page.setContent(
131+
`<ion-toggle class="ion-invalid ion-touched" error-text="Error text">Label</ion-toggle>`,
132+
config
133+
);
134+
135+
const bottomEl = page.locator('ion-toggle');
136+
await expect(bottomEl).toHaveScreenshot(screenshot(`toggle-error-text`));
137+
});
138+
test('should not have visual regressions when rendering error text with a stacked label', async ({ page }) => {
139+
await page.setContent(
140+
`<ion-toggle class="ion-invalid ion-touched" error-text="Error text" label-placement="stacked">Label</ion-toggle>`,
141+
config
142+
);
143+
144+
const bottomEl = page.locator('ion-toggle');
145+
await expect(bottomEl).toHaveScreenshot(screenshot(`toggle-error-text-stacked-label`));
146+
});
147+
});
148+
});
149+
150+
/**
151+
* Customizing supporting text is the same across modes and directions
152+
*/
153+
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
154+
test.describe(title('toggle: supporting text customization'), () => {
155+
test('should not have visual regressions when rendering helper text with custom css', async ({ page }) => {
156+
await page.setContent(
157+
`
158+
<style>
159+
ion-toggle::part(supporting-text) {
160+
font-size: 20px;
161+
}
162+
163+
ion-toggle::part(helper-text) {
164+
color: green;
165+
}
166+
</style>
167+
<ion-toggle helper-text="Helper text">Label</ion-toggle>
168+
`,
169+
config
170+
);
171+
172+
const helperText = page.locator('ion-toggle');
173+
await expect(helperText).toHaveScreenshot(screenshot(`toggle-helper-text-custom-css`));
174+
});
175+
test('should not have visual regressions when rendering error text with custom css', async ({ page }) => {
176+
await page.setContent(
177+
`
178+
<style>
179+
ion-toggle::part(supporting-text) {
180+
font-size: 20px;
181+
}
182+
183+
ion-toggle::part(error-text) {
184+
color: purple;
185+
}
186+
</style>
187+
<ion-toggle class="ion-invalid ion-touched" error-text="Error text">Label</ion-toggle>
188+
`,
189+
config
190+
);
191+
192+
const errorText = page.locator('ion-toggle');
193+
await expect(errorText).toHaveScreenshot(screenshot(`toggle-error-text-custom-css`));
194+
});
195+
});
196+
});

0 commit comments

Comments
 (0)