88import { FormControl , FormGroup , ReactiveFormsModule } from '@angular/forms'
99import { NoopAnimationsModule } from '@angular/platform-browser/animations'
1010import { AuthChallengeComponent } from './auth-challenge.component'
11+ import { AlertMessageComponent } from '../alert-message/alert-message.component'
1112import { By } from '@angular/platform-browser'
1213import '@angular/localize/init'
1314
@@ -18,8 +19,11 @@ import '@angular/localize/init'
1819 <app-auth-challenge
1920 [showAlert]="showAlert"
2021 [showHelpText]="showHelpText"
22+ [showTwoFactorField]="showTwoFactorField"
23+ [showPasswordField]="showPasswordField"
2124 codeControlName="twoFactorCode"
2225 recoveryControlName="twoFactorRecoveryCode"
26+ passwordControlName="passwordControl"
2327 >
2428 </app-auth-challenge>
2529 </form>
@@ -29,10 +33,12 @@ import '@angular/localize/init'
2933} )
3034class TestHostComponent {
3135 @ViewChild ( AuthChallengeComponent )
32- childComponent : AuthChallengeComponent
36+ childComponent ! : AuthChallengeComponent
3337
3438 showAlert = false
3539 showHelpText = true
40+ showTwoFactorField = true
41+ showPasswordField = true
3642
3743 form = new FormGroup ( {
3844 passwordControl : new FormControl ( '' ) ,
@@ -77,7 +83,10 @@ describe('AuthChallengeComponent', () => {
7783
7884 describe ( 'Toggling Recovery Code Mode' , ( ) => {
7985 it ( 'should switch to Recovery mode when toggle link is clicked' , fakeAsync ( ( ) => {
80- const toggleLink = fixture . debugElement . query ( By . css ( 'a' ) ) . nativeElement
86+ // Robust query using data-testid instead of CSS classes
87+ const toggleLink = fixture . debugElement . query (
88+ By . css ( '[data-testid="recovery-toggle"]' )
89+ ) . nativeElement
8190
8291 toggleLink . click ( )
8392 fixture . detectChanges ( )
@@ -94,6 +103,7 @@ describe('AuthChallengeComponent', () => {
94103 recoveryControl ?. setValue ( '' )
95104 expect ( recoveryControl ?. hasError ( 'required' ) ) . toBeTrue ( )
96105
106+ // IDs are safe to query by, as they are functionally required for a11y labels
97107 const recoveryInput = fixture . debugElement . query (
98108 By . css ( '#twoFactorRecoveryCode' )
99109 )
@@ -107,7 +117,6 @@ describe('AuthChallengeComponent', () => {
107117 component . toggleRecoveryCode ( new Event ( 'click' ) )
108118
109119 fixture . detectChanges ( )
110-
111120 tick ( )
112121
113122 const recoveryInputEl = fixture . debugElement . query (
@@ -125,33 +134,33 @@ describe('AuthChallengeComponent', () => {
125134 } )
126135
127136 describe ( 'Backend Response Handling' , ( ) => {
128- it ( 'should handle invalidPassword (reset all)' , ( ) => {
129- hostComponent . form . get ( 'twoFactorCode' ) ?. setValue ( '123456' )
130-
137+ it ( 'should apply backend error to password control' , ( ) => {
131138 component . processBackendResponse ( { invalidPassword : true } )
132139
133- expect ( hostComponent . form . get ( 'twoFactorCode' ) ?. value ) . toBeNull ( )
134- expect ( hostComponent . form . get ( 'twoFactorCode' ) ?. touched ) . toBeFalse ( )
140+ const control = hostComponent . form . get ( 'passwordControl' )
141+ expect ( control ?. hasError ( 'invalid' ) ) . toBeTrue ( )
135142 } )
136143
137144 it ( 'should apply backend error to 2FA code' , ( ) => {
138145 component . processBackendResponse ( { invalidTwoFactorCode : true } )
139146
140147 const control = hostComponent . form . get ( 'twoFactorCode' )
141- expect ( control ?. hasError ( 'backendInvalid ' ) ) . toBeTrue ( )
148+ expect ( control ?. hasError ( 'invalid ' ) ) . toBeTrue ( )
142149 } )
143150
144151 it ( 'should apply backend error to Recovery code' , ( ) => {
145152 component . processBackendResponse ( { invalidTwoFactorRecoveryCode : true } )
146153
147154 const control = hostComponent . form . get ( 'twoFactorRecoveryCode' )
148- expect ( control ?. hasError ( 'backendInvalid ' ) ) . toBeTrue ( )
155+ expect ( control ?. hasError ( 'invalid ' ) ) . toBeTrue ( )
149156 } )
150157
151158 it ( 'should refocus input if response indicates success/continuation' , fakeAsync ( ( ) => {
152159 component . processBackendResponse ( {
153160 twoFactorEnabled : true ,
154161 invalidPassword : false ,
162+ invalidTwoFactorCode : false ,
163+ invalidTwoFactorRecoveryCode : false ,
155164 } )
156165
157166 fixture . detectChanges ( )
@@ -165,11 +174,29 @@ describe('AuthChallengeComponent', () => {
165174 } )
166175
167176 describe ( 'Inputs (@Input)' , ( ) => {
168- it ( 'should display alert message if showAlert is true' , ( ) => {
177+ it ( 'should display verification alert message if showAlert and showPasswordField are true' , ( ) => {
178+ hostComponent . showAlert = true
179+ hostComponent . showPasswordField = true
180+ fixture . detectChanges ( )
181+
182+ // Robust query by Angular Directive rather than HTML tag
183+ const alert = fixture . debugElement . query (
184+ By . directive ( AlertMessageComponent )
185+ )
186+ expect ( alert ) . toBeTruthy ( )
187+ expect ( alert . nativeElement . textContent ) . toContain (
188+ 'Verify your ORCID account to continue'
189+ )
190+ } )
191+
192+ it ( 'should display active 2FA alert message if showAlert is true but showPasswordField is false' , ( ) => {
169193 hostComponent . showAlert = true
194+ hostComponent . showPasswordField = false
170195 fixture . detectChanges ( )
171196
172- const alert = fixture . debugElement . query ( By . css ( 'app-alert-message' ) )
197+ const alert = fixture . debugElement . query (
198+ By . directive ( AlertMessageComponent )
199+ )
173200 expect ( alert ) . toBeTruthy ( )
174201 expect ( alert . nativeElement . textContent ) . toContain (
175202 'As two-factor authentication is currently active'
@@ -180,8 +207,19 @@ describe('AuthChallengeComponent', () => {
180207 hostComponent . showHelpText = false
181208 fixture . detectChanges ( )
182209
183- const links = fixture . debugElement . query ( By . css ( 'ul.leading-5\\.25' ) )
210+ // Querying by data-testid instead of utility classes
211+ const links = fixture . debugElement . query (
212+ By . css ( '[data-testid="help-text-links"]' )
213+ )
184214 expect ( links ) . toBeFalsy ( )
185215 } )
216+
217+ it ( 'should hide two-factor field if showTwoFactorField is false' , ( ) => {
218+ hostComponent . showTwoFactorField = false
219+ fixture . detectChanges ( )
220+
221+ const codeInput = fixture . debugElement . query ( By . css ( '#twoFactorCode' ) )
222+ expect ( codeInput ) . toBeFalsy ( )
223+ } )
186224 } )
187225} )
0 commit comments