Skip to content

Commit d53b808

Browse files
committed
test(angular): add tests for input-otp in standalone tests
1 parent c6ae0d4 commit d53b808

File tree

5 files changed

+126
-1
lines changed

5 files changed

+126
-1
lines changed

packages/angular/test/base/e2e/src/standalone/value-accessors.spec.ts

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
describe('Value Accessors', () => {
32

43
describe('Checkbox', () => {
@@ -147,4 +146,79 @@ describe('Value Accessors', () => {
147146
});
148147
});
149148

149+
describe('Input OTP', () => {
150+
beforeEach(() => cy.visit('/standalone/value-accessors/input-otp'));
151+
152+
it('should update the form value', () => {
153+
cy.get('#formValue').should('have.text', JSON.stringify({
154+
inputOtpString: '',
155+
inputOtpNumber: ''
156+
}, null, 2));
157+
cy.get('ion-input-otp[formControlName="inputOtpString"]').should('have.class', 'ion-pristine');
158+
cy.get('ion-input-otp[formControlName="inputOtpNumber"]').should('have.class', 'ion-pristine');
159+
160+
cy.get('ion-input-otp[formControlName="inputOtpString"]').should('have.class', 'ion-invalid');
161+
cy.get('ion-input-otp[formControlName="inputOtpNumber"]').should('have.class', 'ion-invalid');
162+
163+
// Type into the string OTP input
164+
cy.get('ion-input-otp[formControlName="inputOtpString"] input').eq(0).type('a');
165+
cy.get('ion-input-otp[formControlName="inputOtpString"] input').eq(1).type('b');
166+
cy.get('ion-input-otp[formControlName="inputOtpString"] input').eq(2).type('c');
167+
cy.get('ion-input-otp[formControlName="inputOtpString"] input').eq(3).type('d');
168+
cy.get('ion-input-otp[formControlName="inputOtpString"] input').eq(3).blur();
169+
170+
// Type into the number OTP input
171+
cy.get('ion-input-otp[formControlName="inputOtpNumber"] input').eq(0).type('1');
172+
cy.get('ion-input-otp[formControlName="inputOtpNumber"] input').eq(1).type('2');
173+
cy.get('ion-input-otp[formControlName="inputOtpNumber"] input').eq(2).type('3');
174+
cy.get('ion-input-otp[formControlName="inputOtpNumber"] input').eq(3).type('4');
175+
cy.get('ion-input-otp[formControlName="inputOtpNumber"] input').eq(3).blur();
176+
177+
cy.get('#formValue').should('have.text', JSON.stringify({
178+
inputOtpString: 'abcd',
179+
inputOtpNumber: 1234
180+
}, null, 2));
181+
182+
cy.get('ion-input-otp[formControlName="inputOtpString"]').should('have.class', 'ion-dirty');
183+
cy.get('ion-input-otp[formControlName="inputOtpNumber"]').should('have.class', 'ion-dirty');
184+
185+
cy.get('ion-input-otp[formControlName="inputOtpString"]').should('have.class', 'ion-valid');
186+
cy.get('ion-input-otp[formControlName="inputOtpNumber"]').should('have.class', 'ion-valid');
187+
});
188+
189+
it('should remain invalid when partially filled', () => {
190+
cy.get('#formValue').should('have.text', JSON.stringify({
191+
inputOtpString: '',
192+
inputOtpNumber: ''
193+
}, null, 2));
194+
cy.get('ion-input-otp[formControlName="inputOtpString"]').should('have.class', 'ion-pristine');
195+
cy.get('ion-input-otp[formControlName="inputOtpNumber"]').should('have.class', 'ion-pristine');
196+
197+
cy.get('ion-input-otp[formControlName="inputOtpString"]').should('have.class', 'ion-invalid');
198+
cy.get('ion-input-otp[formControlName="inputOtpNumber"]').should('have.class', 'ion-invalid');
199+
200+
// Type only 2 characters into the string OTP input
201+
cy.get('ion-input-otp[formControlName="inputOtpString"] input').eq(0).type('a');
202+
cy.get('ion-input-otp[formControlName="inputOtpString"] input').eq(1).type('b');
203+
cy.get('ion-input-otp[formControlName="inputOtpString"] input').eq(2).blur();
204+
205+
// Type only 2 characters into the number OTP input
206+
cy.get('ion-input-otp[formControlName="inputOtpNumber"] input').eq(0).type('1');
207+
cy.get('ion-input-otp[formControlName="inputOtpNumber"] input').eq(1).type('2');
208+
cy.get('ion-input-otp[formControlName="inputOtpNumber"] input').eq(2).blur();
209+
210+
cy.get('#formValue').should('have.text', JSON.stringify({
211+
inputOtpString: 'ab',
212+
inputOtpNumber: 12
213+
}, null, 2));
214+
215+
cy.get('ion-input-otp[formControlName="inputOtpString"]').should('have.class', 'ion-dirty');
216+
cy.get('ion-input-otp[formControlName="inputOtpNumber"]').should('have.class', 'ion-dirty');
217+
218+
// Verify both inputs remain invalid when partially filled
219+
cy.get('ion-input-otp[formControlName="inputOtpString"]').should('have.class', 'ion-invalid');
220+
cy.get('ion-input-otp[formControlName="inputOtpNumber"]').should('have.class', 'ion-invalid');
221+
});
222+
});
223+
150224
});

packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export const routes: Routes = [
4444
{ path: 'checkbox', loadComponent: () => import('../value-accessors/checkbox/checkbox.component').then(c => c.CheckboxComponent) },
4545
{ path: 'datetime', loadComponent: () => import('../value-accessors/datetime/datetime.component').then(c => c.DatetimeComponent) },
4646
{ path: 'input', loadComponent: () => import('../value-accessors/input/input.component').then(c => c.InputComponent) },
47+
{ path: 'input-otp', loadComponent: () => import('../value-accessors/input-otp/input-otp.component').then(c => c.InputOtpComponent) },
4748
{ path: 'radio-group', loadComponent: () => import('../value-accessors/radio-group/radio-group.component').then(c => c.RadioGroupComponent) },
4849
{ path: 'range', loadComponent: () => import('../value-accessors/range/range.component').then(c => c.RangeComponent) },
4950
{ path: 'searchbar', loadComponent: () => import('../value-accessors/searchbar/searchbar.component').then(c => c.SearchbarComponent) },

packages/angular/test/base/src/app/standalone/home-page/home-page.component.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@
116116
Input Test
117117
</ion-label>
118118
</ion-item>
119+
<ion-item routerLink="/standalone/value-accessors/input-otp">
120+
<ion-label>
121+
Input OTP Test
122+
</ion-label>
123+
</ion-item>
119124
<ion-item routerLink="/standalone/value-accessors/radio-group">
120125
<ion-label>
121126
Radio Group Test
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<div>
2+
<h1>IonInputOtp Value Accessors</h1>
3+
<p>
4+
This test checks the form integrations with ion-input-otp to make sure values are correctly assigned to the form group.
5+
</p>
6+
7+
<app-value-accessor-test [formGroup]="form">
8+
<ion-input-otp type="text" formControlName="inputOtpString">String</ion-input-otp>
9+
<ion-input-otp type="number" formControlName="inputOtpNumber">Number</ion-input-otp>
10+
</app-value-accessor-test>
11+
</div>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Component } from "@angular/core";
2+
import { FormBuilder, FormsModule, ReactiveFormsModule, Validators, AbstractControl, ValidationErrors } from "@angular/forms";
3+
import { IonInputOtp } from "@ionic/angular/standalone";
4+
import { ValueAccessorTestComponent } from "../value-accessor-test/value-accessor-test.component";
5+
6+
function otpRequiredLength(length: number) {
7+
return (control: AbstractControl): ValidationErrors | null => {
8+
const value = control.value;
9+
if (!value || value.toString().length !== length) {
10+
return { otpLength: true };
11+
}
12+
return null;
13+
};
14+
}
15+
16+
@Component({
17+
selector: 'app-input-otp',
18+
templateUrl: 'input-otp.component.html',
19+
standalone: true,
20+
imports: [
21+
IonInputOtp,
22+
ReactiveFormsModule,
23+
FormsModule,
24+
ValueAccessorTestComponent
25+
]
26+
})
27+
export class InputOtpComponent {
28+
form = this.fb.group({
29+
inputOtpString: ['', [Validators.required, otpRequiredLength(4)]],
30+
inputOtpNumber: ['', [Validators.required, otpRequiredLength(4)]],
31+
});
32+
33+
constructor(private fb: FormBuilder) { }
34+
}

0 commit comments

Comments
 (0)