Skip to content

Commit bc72326

Browse files
committed
test(angular): add missing input checks
1 parent b1e3383 commit bc72326

File tree

3 files changed

+360
-50
lines changed

3 files changed

+360
-50
lines changed

packages/angular/test/base/e2e/src/lazy/form.spec.ts

Lines changed: 272 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,60 +5,293 @@ test.describe('Form', () => {
55
await page.goto('/lazy/form');
66
});
77

8-
test('should have form control initial value', async ({ page }) => {
9-
await expect(page.locator('ion-input.required input')).toHaveValue('');
8+
test.describe('status updates', () => {
9+
test('should update Ionic form classes when calling form methods programmatically', async ({ page }) => {
10+
await page.locator('#input-touched').click();
11+
await expect(page.locator('#touched-input-test')).toHaveClass(/ion-touched/);
12+
await page.locator('#input-otp-touched').click();
13+
await expect(page.locator('#touched-input-otp-number-test')).toHaveClass(/ion-touched/);
14+
});
15+
16+
test('markAllAsTouched should apply .ion-touched to nearest ion-item', async ({ page }) => {
17+
await page.locator('#mark-all-touched-button').click();
18+
const items = page.locator('form ion-item');
19+
const count = await items.count();
20+
for (let i = 0; i < count; i++) {
21+
await expect(items.nth(i)).toHaveClass(/ion-touched/);
22+
}
23+
});
1024
});
1125

12-
test('should reflect Ionic form control status classes', async ({ page }) => {
13-
// Control is initially invalid
14-
await expect(page.locator('ion-input.required')).toHaveClass(/ion-invalid/);
15-
await expect(page.locator('ion-input.required')).toHaveClass(/ion-pristine/);
16-
await expect(page.locator('ion-input.required')).toHaveClass(/ion-untouched/);
26+
test.describe('change', () => {
27+
test('should have default values', async ({ page }) => {
28+
await testStatus(page, 'INVALID');
29+
await expect(page.locator('#submit')).toHaveText('false');
30+
await testData(page, {
31+
datetime: '2010-08-20',
32+
select: null,
33+
toggle: false,
34+
input: '',
35+
input2: 'Default Value',
36+
inputMin: 1,
37+
inputMax: 1,
38+
inputOtp: null,
39+
inputOtpText: '',
40+
inputOtp2: 1234,
41+
checkbox: false,
42+
radio: null
43+
});
44+
});
1745

18-
// Fill the input to make it valid
19-
await page.locator('ion-input.required input').fill('Some value');
20-
await page.locator('ion-input.required input').blur();
46+
test('should become valid', async ({ page }) => {
47+
await page.locator('ion-input.required input').fill('Some value');
48+
await page.locator('ion-input.required input').blur();
2149

22-
await expect(page.locator('ion-input.required')).toHaveClass(/ion-valid/);
23-
await expect(page.locator('ion-input.required')).toHaveClass(/ion-dirty/);
24-
await expect(page.locator('ion-input.required')).toHaveClass(/ion-touched/);
25-
});
50+
// Test number OTP input
51+
await page.locator('#touched-input-otp-number-test input').nth(0).fill('5');
52+
await page.locator('#touched-input-otp-number-test input').nth(1).fill('6');
53+
await page.locator('#touched-input-otp-number-test input').nth(2).fill('7');
54+
await page.locator('#touched-input-otp-number-test input').nth(3).fill('8');
55+
await page.locator('#touched-input-otp-number-test input').last().focus();
56+
await page.locator('#touched-input-otp-number-test input').last().blur();
2657

27-
test('should become valid when filled', async ({ page }) => {
28-
await page.locator('ion-input.required input').fill('Some value');
29-
await page.locator('ion-input.required input').blur();
58+
// Test text OTP input
59+
await page.locator('#touched-input-otp-text-test input').nth(0).fill('A');
60+
await page.locator('#touched-input-otp-text-test input').nth(1).fill('B');
61+
await page.locator('#touched-input-otp-text-test input').nth(2).fill('C');
62+
await page.locator('#touched-input-otp-text-test input').nth(3).fill('D');
63+
await page.locator('#touched-input-otp-text-test input').last().focus();
64+
await page.locator('#touched-input-otp-text-test input').last().blur();
3065

31-
// Test number OTP input
32-
await page.locator('ion-input-otp input').nth(0).fill('1');
33-
await page.locator('ion-input-otp input').nth(1).fill('2');
34-
await page.locator('ion-input-otp input').nth(2).fill('3');
35-
await page.locator('ion-input-otp input').nth(3).fill('4');
66+
await testStatus(page, 'INVALID');
3667

37-
// Check that the OTP input is valid
38-
await expect(page.locator('#touched-input-otp-number-test')).toHaveClass(/ion-valid/);
39-
});
68+
await page.locator('ion-select').click();
69+
await expect(page.locator('ion-alert')).toBeVisible();
70+
// NES option
71+
await page.locator('ion-alert .alert-radio-button').nth(1).click();
72+
// Click confirm button
73+
await page.locator('ion-alert .alert-button:not(.alert-button-role-cancel)').click();
74+
75+
await testStatus(page, 'VALID');
76+
77+
await testData(page, {
78+
datetime: '2010-08-20',
79+
select: 'nes',
80+
toggle: false,
81+
input: 'Some value',
82+
input2: 'Default Value',
83+
inputMin: 1,
84+
inputMax: 1,
85+
inputOtp: 5678,
86+
inputOtpText: 'ABCD',
87+
inputOtp2: 1234,
88+
checkbox: false,
89+
radio: null
90+
});
91+
});
92+
93+
test('ion-toggle should change', async ({ page }) => {
94+
await page.locator('form ion-toggle').click();
95+
await testData(page, {
96+
datetime: '2010-08-20',
97+
select: null,
98+
toggle: true,
99+
input: '',
100+
input2: 'Default Value',
101+
inputMin: 1,
102+
inputMax: 1,
103+
inputOtp: null,
104+
inputOtpText: '',
105+
inputOtp2: 1234,
106+
checkbox: false,
107+
radio: null
108+
});
109+
});
110+
111+
test('ion-checkbox should change', async ({ page }) => {
112+
await page.locator('ion-checkbox').click();
113+
await testData(page, {
114+
datetime: '2010-08-20',
115+
select: null,
116+
toggle: false,
117+
input: '',
118+
input2: 'Default Value',
119+
inputMin: 1,
120+
inputMax: 1,
121+
inputOtp: null,
122+
inputOtpText: '',
123+
inputOtp2: 1234,
124+
checkbox: true,
125+
radio: null
126+
});
127+
});
128+
129+
test('ion-radio should change', async ({ page }) => {
130+
await page.locator('ion-radio').click();
131+
await testData(page, {
132+
datetime: '2010-08-20',
133+
select: null,
134+
toggle: false,
135+
input: '',
136+
input2: 'Default Value',
137+
inputMin: 1,
138+
inputMax: 1,
139+
inputOtp: null,
140+
inputOtpText: '',
141+
inputOtp2: 1234,
142+
checkbox: false,
143+
radio: 'nes',
144+
});
145+
});
146+
147+
test('ion-input-otp should change', async ({ page }) => {
148+
// Test number OTP input
149+
await page.locator('#touched-input-otp-number-test input').nth(0).fill('5');
150+
await page.locator('#touched-input-otp-number-test input').nth(1).fill('6');
151+
await page.locator('#touched-input-otp-number-test input').nth(2).fill('7');
152+
await page.locator('#touched-input-otp-number-test input').nth(3).fill('8');
153+
await page.locator('#touched-input-otp-number-test input').last().focus();
154+
await page.locator('#touched-input-otp-number-test input').last().blur();
155+
156+
// Test text OTP input
157+
await page.locator('#touched-input-otp-text-test input').nth(0).fill('A');
158+
await page.locator('#touched-input-otp-text-test input').nth(1).fill('B');
159+
await page.locator('#touched-input-otp-text-test input').nth(2).fill('C');
160+
await page.locator('#touched-input-otp-text-test input').nth(3).fill('D');
161+
await page.locator('#touched-input-otp-text-test input').last().focus();
162+
await page.locator('#touched-input-otp-text-test input').last().blur();
163+
164+
await testData(page, {
165+
datetime: '2010-08-20',
166+
select: null,
167+
toggle: false,
168+
input: '',
169+
input2: 'Default Value',
170+
inputMin: 1,
171+
inputMax: 1,
172+
inputOtp: 5678,
173+
inputOtpText: 'ABCD',
174+
inputOtp2: 1234,
175+
checkbox: false,
176+
radio: null
177+
});
178+
});
40179

41-
test('ion-input should error with min set', async ({ page }) => {
42-
const control = page.locator('form ion-input[formControlName="inputMin"]');
180+
test('should submit', async ({ page }) => {
181+
await page.locator('#set-values').click();
182+
await page.locator('#submit-button').click();
183+
await expect(page.locator('#submit')).toHaveText('true');
184+
});
43185

44-
// Control is initially valid
45-
await expect(control).toHaveClass(/ng-valid/);
186+
test('ion-input-otp should validate both number and text types', async ({ page }) => {
187+
// Test number OTP validation
188+
await expect(page.locator('#touched-input-otp-number-test')).toHaveClass(/ng-invalid/);
189+
await page.locator('#touched-input-otp-number-test input').nth(0).fill('5');
190+
await page.locator('#touched-input-otp-number-test input').nth(1).fill('6');
191+
await page.locator('#touched-input-otp-number-test input').nth(2).fill('7');
192+
await page.locator('#touched-input-otp-number-test input').nth(3).fill('8');
193+
await page.locator('#touched-input-otp-number-test input').last().focus();
194+
await page.locator('#touched-input-otp-number-test input').last().blur();
195+
await expect(page.locator('#touched-input-otp-number-test')).toHaveClass(/ng-valid/);
46196

47-
await control.locator('input').fill('0');
48-
await control.locator('input').blur();
197+
// Test text OTP validation
198+
await expect(page.locator('#touched-input-otp-text-test')).toHaveClass(/ng-invalid/);
199+
await page.locator('#touched-input-otp-text-test input').nth(0).fill('A');
200+
await page.locator('#touched-input-otp-text-test input').nth(1).fill('B');
201+
await page.locator('#touched-input-otp-text-test input').nth(2).fill('C');
202+
await page.locator('#touched-input-otp-text-test input').nth(3).fill('D');
203+
await page.locator('#touched-input-otp-text-test input').last().focus();
204+
await page.locator('#touched-input-otp-text-test input').last().blur();
205+
await expect(page.locator('#touched-input-otp-text-test')).toHaveClass(/ng-valid/);
206+
});
49207

50-
await expect(control).toHaveClass(/ng-invalid/);
208+
test('ion-input-otp should remain invalid when partially filled', async ({ page }) => {
209+
// Test number OTP with only first digit
210+
await expect(page.locator('#touched-input-otp-number-test')).toHaveClass(/ng-invalid/);
211+
await page.locator('#touched-input-otp-number-test input').nth(0).fill('5');
212+
await page.locator('#touched-input-otp-number-test input').nth(1).focus();
213+
await page.locator('#touched-input-otp-number-test input').nth(1).blur();
214+
await expect(page.locator('#touched-input-otp-number-test')).toHaveClass(/ng-invalid/);
215+
216+
// Test text OTP with only first character
217+
await expect(page.locator('#touched-input-otp-text-test')).toHaveClass(/ng-invalid/);
218+
await page.locator('#touched-input-otp-text-test input').nth(0).fill('A');
219+
await page.locator('#touched-input-otp-text-test input').nth(1).focus();
220+
await page.locator('#touched-input-otp-text-test input').nth(1).blur();
221+
await expect(page.locator('#touched-input-otp-text-test')).toHaveClass(/ng-invalid/);
222+
223+
// Verify form status is still invalid
224+
await testStatus(page, 'INVALID');
225+
});
51226
});
52227

53-
test('ion-input should error with max set', async ({ page }) => {
54-
const control = page.locator('form ion-input[formControlName="inputMax"]');
228+
test.describe('blur', () => {
229+
test('ion-toggle should change only after blur', async ({ page }) => {
230+
await page.locator('form ion-toggle').click();
231+
await testData(page, {
232+
datetime: '2010-08-20',
233+
select: null,
234+
toggle: true,
235+
input: '',
236+
input2: 'Default Value',
237+
inputMin: 1,
238+
inputMax: 1,
239+
inputOtp: null,
240+
inputOtpText: '',
241+
inputOtp2: 1234,
242+
checkbox: false,
243+
radio: null
244+
});
245+
await page.locator('ion-checkbox').click();
246+
await testData(page, {
247+
datetime: '2010-08-20',
248+
select: null,
249+
toggle: true,
250+
input: '',
251+
input2: 'Default Value',
252+
inputMin: 1,
253+
inputMax: 1,
254+
inputOtp: null,
255+
inputOtpText: '',
256+
inputOtp2: 1234,
257+
checkbox: true,
258+
radio: null
259+
});
260+
});
261+
});
262+
263+
test.describe('validators', () => {
264+
test('ion-input should error with min set', async ({ page }) => {
265+
const control = page.locator('form ion-input[formControlName="inputMin"]');
266+
267+
await expect(control).toHaveClass(/ng-valid/);
55268

56-
// Control is initially valid
57-
await expect(control).toHaveClass(/ng-valid/);
269+
await control.locator('input').fill('0');
270+
await control.locator('input').blur();
58271

59-
await control.locator('input').fill('2');
60-
await control.locator('input').blur();
272+
await expect(control).toHaveClass(/ng-invalid/);
273+
});
61274

62-
await expect(control).toHaveClass(/ng-invalid/);
275+
test('ion-input should error with max set', async ({ page }) => {
276+
const control = page.locator('form ion-input[formControlName="inputMax"]');
277+
278+
await expect(control).toHaveClass(/ng-valid/);
279+
280+
await control.locator('input').fill('2');
281+
await control.locator('input').blur();
282+
283+
await expect(control).toHaveClass(/ng-invalid/);
284+
});
63285
});
286+
287+
// Helper functions
288+
async function testStatus(page: any, status: string) {
289+
await expect(page.locator('#status')).toHaveText(status);
290+
}
291+
292+
async function testData(page: any, data: any) {
293+
const text = await page.locator('#data').textContent();
294+
const value = JSON.parse(text!);
295+
expect(value).toEqual(data);
296+
}
64297
});

0 commit comments

Comments
 (0)