Skip to content

Commit 4015ee4

Browse files
committed
fix(input-otp): properly handle value updates and add tests
1 parent 9d905b2 commit 4015ee4

File tree

6 files changed

+50
-22
lines changed

6 files changed

+50
-22
lines changed

core/src/components.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1355,7 +1355,7 @@ export namespace Components {
13551355
*/
13561356
"readonly": boolean;
13571357
/**
1358-
* Resets the input values and focus state.
1358+
* Resets the value and focus state.
13591359
*/
13601360
"reset": () => Promise<void>;
13611361
/**

core/src/components/input-otp/input-otp.tsx

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -261,24 +261,31 @@ export class InputOTP implements ComponentInterface {
261261
* input boxes and the value of the input group is updated.
262262
*/
263263
private initializeValues() {
264-
if (this.value != null && String(this.value).length > 0) {
265-
const chars = String(this.value).split('').slice(0, this.length);
266-
chars.forEach((char, index) => {
267-
if (this.validKeyPattern.test(char)) {
268-
this.inputValues[index] = char;
269-
}
270-
});
271-
// Update the value without emitting events
272-
this.value = this.inputValues.join('');
264+
// Clear all input values
265+
this.inputValues = Array(this.length).fill('');
266+
267+
// If the value is null, undefined, or an empty string, return
268+
if (this.value == null || String(this.value).length === 0) {
269+
return;
273270
}
271+
272+
// Split the value into individual characters and validate
273+
// them against the allowed pattern
274+
const chars = String(this.value).split('').slice(0, this.length);
275+
chars.forEach((char, index) => {
276+
if (this.validKeyPattern.test(char)) {
277+
this.inputValues[index] = char;
278+
}
279+
});
280+
// Update the value without emitting events
281+
this.value = this.inputValues.join('');
274282
}
275283

276284
/**
277-
* Resets the input values and focus state.
285+
* Resets the value and focus state.
278286
*/
279287
@Method()
280288
async reset() {
281-
this.inputValues = Array(this.length).fill('');
282289
this.value = '';
283290

284291
this.focusedValue = null;
@@ -790,7 +797,8 @@ export class InputOTP implements ComponentInterface {
790797
class={{
791798
'input-otp-description': true,
792799
'input-otp-description-hidden': !hasDescription,
793-
}}>
800+
}}
801+
>
794802
<slot></slot>
795803
</div>
796804
</Host>

core/src/components/input-otp/test/a11y/input-otp.e2e.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ configs().forEach(({ title, config }) => {
7878
});
7979

8080
test('should update aria-label and aria-labelledby when set on host', async ({ page }) => {
81-
await page.setContent(`<ion-input-otp aria-label="Custom label" aria-labelledby="my-label"></ion-input-otp>`, config);
81+
await page.setContent(
82+
`<ion-input-otp aria-label="Custom label" aria-labelledby="my-label"></ion-input-otp>`,
83+
config
84+
);
8285

8386
const inputOtpGroup = page.locator('ion-input-otp .input-otp-group');
8487
await expect(inputOtpGroup).toHaveAttribute('aria-label', 'Custom label');

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

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@ describe('Inputs', () => {
33
cy.visit('/lazy/inputs');
44
})
55

6-
it('should have default value', () => {
6+
it('should have default values', () => {
77
cy.get('ion-checkbox').should('have.prop', 'checked').and('equal', true);
88
cy.get('ion-radio-group').should('have.prop', 'value').and('equal', 'nes');
99
cy.get('ion-toggle').should('have.prop', 'checked').and('equal', true);
1010
cy.get('ion-input').should('have.prop', 'value').and('equal', 'some text');
11+
cy.get('ion-input-otp').should('have.prop', 'value').and('equal', '1234');
1112
cy.get('ion-datetime').should('have.prop', 'value').and('equal', '1994-03-15');
1213
cy.get('ion-select').should('have.prop', 'value').and('equal', 'nes');
1314
cy.get('ion-range').should('have.prop', 'value').and('equal', 50);
1415
});
1516

16-
it('should have reset value', () => {
17+
it('should reset values', () => {
1718
cy.get('#reset-button').click();
1819

1920
cy.get('ion-checkbox').should('have.prop', 'checked').and('equal', false);
@@ -26,33 +27,38 @@ describe('Inputs', () => {
2627
* value property is undefined.
2728
*/
2829
cy.get('ion-input').should('not.have.prop', 'value');
30+
cy.get('ion-input-otp').should('not.have.prop', 'value');
2931
cy.get('ion-datetime').should('not.have.prop', 'value');
3032
cy.get('ion-select').should('not.have.prop', 'value');
3133
cy.get('ion-range').should('not.have.prop', 'value');
3234
});
3335

34-
it('should get some value', () => {
36+
it('should set values', () => {
3537
cy.get('#reset-button').click();
3638
cy.get('#set-button').click();
3739

3840
cy.get('ion-checkbox').should('have.prop', 'checked').and('equal', true);
3941
cy.get('ion-radio-group').should('have.prop', 'value').and('equal', 'nes');
4042
cy.get('ion-toggle').should('have.prop', 'checked').and('equal', true);
4143
cy.get('ion-input').should('have.prop', 'value').and('equal', 'some text');
44+
cy.get('ion-input-otp').should('have.prop', 'value').and('equal', '1234');
4245
cy.get('ion-datetime').should('have.prop', 'value').and('equal', '1994-03-15');
4346
cy.get('ion-select').should('have.prop', 'value').and('equal', 'nes');
4447
cy.get('ion-range').should('have.prop', 'value').and('equal', 50);
4548
});
4649

47-
it('change values should update angular', () => {
50+
it('should update angular when values change', () => {
4851
cy.get('#reset-button').click();
4952

5053
cy.get('ion-checkbox#first-checkbox').click();
5154
cy.get('ion-radio').first().click();
5255
cy.get('ion-toggle').first().click();
5356

5457
cy.get('ion-input').eq(0).type('hola');
55-
cy.get('ion-input input').eq(0).blur();
58+
cy.focused().blur();
59+
60+
cy.get('ion-input-otp input').eq(0).type('1234');
61+
cy.focused().blur();
5662

5763
// Set date to 1994-03-14
5864
cy.get('ion-datetime').first().shadow().find('.calendar-day:not([disabled])').first().click();
@@ -68,7 +74,18 @@ describe('Inputs', () => {
6874
cy.get('#radio-note').should('have.text', 'nes');
6975
cy.get('#toggle-note').should('have.text', 'true');
7076
cy.get('#input-note').should('have.text', 'hola');
77+
cy.get('#input-otp-note').should('have.text', '1234');
7178
cy.get('#datetime-note').should('have.text', '1994-03-14');
7279
cy.get('#select-note').should('have.text', 'ps');
7380
});
81+
82+
it('should update values when erasing input', () => {
83+
cy.get('ion-input').eq(0).type('{backspace}');
84+
cy.get('ion-input').should('have.prop', 'value').and('equal', 'some tex');
85+
cy.get('#input-note').should('have.text', 'some tex');
86+
87+
cy.get('ion-input-otp input:last').eq(0).type('{backspace}');
88+
cy.get('ion-input-otp').should('have.prop', 'value').and('equal', '123');
89+
cy.get('#input-otp-note').should('have.text', '123');
90+
});
7491
});

packages/angular/test/base/src/app/lazy/form/form.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@
4848
<ion-input-otp id="touched-input-otp-number-test" formControlName="inputOtp" class="required">Input OTP (required)</ion-input-otp>
4949
</ion-item>
5050

51+
<ion-button id="input-otp-touched" (click)="setOtpTouched()">Set Input OTP Touched</ion-button>
52+
5153
<ion-item>
5254
<ion-input-otp id="touched-input-otp-text-test" type="text" formControlName="inputOtpText" class="required">Input OTP Text (required)</ion-input-otp>
5355
</ion-item>
5456

55-
<ion-button id="input-otp-touched" (click)="setOtpTouched()">Set Input OTP Touched</ion-button>
56-
5757
<ion-item>
5858
<ion-input-otp formControlName="inputOtp2">Input OTP</ion-input-otp>
5959
</ion-item>

packages/angular/test/base/src/app/lazy/inputs/inputs.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373

7474
<ion-item>
7575
<ion-input-otp [(ngModel)]="inputOtp">Input OTP</ion-input-otp>
76-
<ion-note slot="end">{{inputOtp}}</ion-note>
76+
<ion-note slot="end" id="input-otp-note">{{inputOtp}}</ion-note>
7777
</ion-item>
7878

7979
<ion-item color="dark">

0 commit comments

Comments
 (0)