Skip to content

Commit a1bf190

Browse files
committed
PD-4790 improve tests
1 parent fd848c6 commit a1bf190

2 files changed

Lines changed: 54 additions & 14 deletions

File tree

projects/orcid-ui/src/lib/components/auth-challenge/auth-challenge.component.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@
209209
</div>
210210
</div>
211211
} @if (showHelpText) {
212-
<ul class="leading-5.25">
212+
<ul class="leading-5.25" data-testid="help-text-links">
213213
@if (!showRecoveryCode) {
214214
<li>
215215
<div class="orc-font-body-small">
@@ -220,6 +220,7 @@
220220
(click)="toggleRecoveryCode($event)"
221221
i18n="@@account.useARecoveryCode"
222222
class="underline"
223+
data-testid="recovery-toggle"
223224
>Use a recovery code instead</a
224225
>
225226
</div>
@@ -232,6 +233,7 @@
232233
>&nbsp;<a
233234
href="#"
234235
(click)="toggleRecoveryCode($event)"
236+
data-testid="recovery-toggle"
235237
i18n="@@account.useYourAuthenticationAppInstead"
236238
class="underline"
237239
>Use your authentication app instead</a

projects/orcid-ui/src/lib/components/auth-challenge/auth-challenge.component.spec.ts

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'
99
import { NoopAnimationsModule } from '@angular/platform-browser/animations'
1010
import { AuthChallengeComponent } from './auth-challenge.component'
11+
import { AlertMessageComponent } from '../alert-message/alert-message.component'
1112
import { By } from '@angular/platform-browser'
1213
import '@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
})
3034
class 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

Comments
 (0)