diff --git a/src/app/features/store/pages/reset-password-page/reset-password-page.component.html b/src/app/features/store/pages/reset-password-page/reset-password-page.component.html index 582aaf6..647d450 100644 --- a/src/app/features/store/pages/reset-password-page/reset-password-page.component.html +++ b/src/app/features/store/pages/reset-password-page/reset-password-page.component.html @@ -13,11 +13,13 @@ @if (getControlError('password'); as errorMessage) { {{ errorMessage }} @@ -30,11 +32,13 @@ @if (getControlError('password_confirmation'); as errorMessage) { {{ errorMessage }} diff --git a/src/app/features/store/pages/reset-password-page/reset-password-page.component.spec.ts b/src/app/features/store/pages/reset-password-page/reset-password-page.component.spec.ts index fec20c9..636af77 100644 --- a/src/app/features/store/pages/reset-password-page/reset-password-page.component.spec.ts +++ b/src/app/features/store/pages/reset-password-page/reset-password-page.component.spec.ts @@ -50,6 +50,43 @@ describe('ResetPasswordPageComponent', () => { ]; } + it('shows and hides both password fields with either visibility control', async () => { + const modalService = { + openSimple: vi.fn(), + }; + + await TestBed.configureTestingModule({ + imports: [ResetPasswordPageComponent], + providers: resetProviders(modalService), + }).compileComponents(); + + const fixture = TestBed.createComponent(ResetPasswordPageComponent); + fixture.detectChanges(); + + const getPasswordInputs = () => + Array.from(fixture.nativeElement.querySelectorAll('input')) as HTMLInputElement[]; + const getVisibilityButtons = () => + Array.from( + fixture.nativeElement.querySelectorAll('button[aria-label]'), + ) as HTMLButtonElement[]; + + expect(getPasswordInputs().map((input) => input.type)).toEqual(['password', 'password']); + + getVisibilityButtons()[0].click(); + fixture.detectChanges(); + + expect(getPasswordInputs().map((input) => input.type)).toEqual(['text', 'text']); + expect(getVisibilityButtons().map((button) => button.getAttribute('aria-label'))).toEqual([ + 'Ocultar contraseña', + 'Ocultar contraseña', + ]); + + getVisibilityButtons()[1].click(); + fixture.detectChanges(); + + expect(getPasswordInputs().map((input) => input.type)).toEqual(['password', 'password']); + }); + it('rejects passwords that do not match', async () => { const modalService = { openSimple: vi.fn(), diff --git a/src/app/features/store/pages/reset-password-page/reset-password-page.component.ts b/src/app/features/store/pages/reset-password-page/reset-password-page.component.ts index eb1fb04..b320af8 100644 --- a/src/app/features/store/pages/reset-password-page/reset-password-page.component.ts +++ b/src/app/features/store/pages/reset-password-page/reset-password-page.component.ts @@ -49,6 +49,7 @@ export class ResetPasswordPageComponent { private readonly submittedState = signal(false); private readonly isSubmittingState = signal(false); private readonly serverErrorState = signal(null); + private readonly passwordVisibleState = signal(false); private readonly email = this.route.snapshot.queryParamMap.get('email') ?? ''; private readonly code = this.route.snapshot.queryParamMap.get('code') ?? ''; @@ -72,6 +73,11 @@ export class ResetPasswordPageComponent { protected readonly submitted = this.submittedState.asReadonly(); protected readonly isSubmitting = this.isSubmittingState.asReadonly(); protected readonly serverError = this.serverErrorState.asReadonly(); + protected readonly passwordVisible = this.passwordVisibleState.asReadonly(); + + protected setPasswordVisibility(visible: boolean): void { + this.passwordVisibleState.set(visible); + } protected updatePassword(controlName: PasswordControlName, value: string | number): void { this.form.controls[controlName].setValue(String(value));