Skip to content

Commit c203984

Browse files
committed
PD-5538
1 parent ea36b4e commit c203984

6 files changed

Lines changed: 321 additions & 130 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { TestBed } from '@angular/core/testing'
2+
import { take } from 'rxjs/operators'
3+
import { getUserRecord } from '../record/record.service.spec'
4+
import { RecordHeaderStateService } from './record-header-state.service'
5+
6+
describe('RecordHeaderStateService', () => {
7+
let service: RecordHeaderStateService
8+
9+
beforeEach(() => {
10+
TestBed.configureTestingModule({})
11+
service = TestBed.inject(RecordHeaderStateService)
12+
service.reset()
13+
})
14+
15+
it('should emit header loading separately from full record loading', (done) => {
16+
service.setLoadingUserRecord(true)
17+
service.setLoadingRecordHeader(false)
18+
19+
service.loadingRecordHeader$.pipe(take(1)).subscribe((loading) => {
20+
expect(loading).toBeFalse()
21+
done()
22+
})
23+
})
24+
25+
it('should share the latest user record with header consumers', (done) => {
26+
const userRecord = getUserRecord()
27+
28+
service.setUserRecord(userRecord)
29+
30+
service.userRecord$.pipe(take(1)).subscribe((value) => {
31+
expect(value).toBe(userRecord)
32+
done()
33+
})
34+
})
35+
36+
it('should reset header-specific state', (done) => {
37+
service.setLoadingRecordHeader(false)
38+
service.setUserRecord(getUserRecord())
39+
40+
service.reset()
41+
42+
service.loadingRecordHeader$.pipe(take(1)).subscribe((loading) => {
43+
expect(loading).toBeTrue()
44+
service.userRecord$.pipe(take(1)).subscribe((userRecord) => {
45+
expect(userRecord).toBeNull()
46+
done()
47+
})
48+
})
49+
})
50+
})

src/app/core/record-header-state/record-header-state.service.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Injectable } from '@angular/core'
22
import { BehaviorSubject } from 'rxjs'
3+
import { UserRecord } from 'src/app/types/record.local'
34

45
/**
56
* Shares state required by the Record Header between My ORCID and the Header.
@@ -8,7 +9,9 @@ import { BehaviorSubject } from 'rxjs'
89
@Injectable({ providedIn: 'root' })
910
export class RecordHeaderStateService {
1011
private readonly _loadingUserRecord = new BehaviorSubject<boolean>(true)
12+
private readonly _loadingRecordHeader = new BehaviorSubject<boolean>(true)
1113
private readonly _isPublicRecord = new BehaviorSubject<string | null>(null)
14+
private readonly _userRecord = new BehaviorSubject<UserRecord | null>(null)
1215
private readonly _affiliations = new BehaviorSubject<number>(0)
1316
private readonly _displaySideBar = new BehaviorSubject<boolean>(false)
1417
private readonly _displayBiography = new BehaviorSubject<boolean>(false)
@@ -17,7 +20,9 @@ export class RecordHeaderStateService {
1720
private readonly _hasCreditOrOtherNames = new BehaviorSubject<boolean>(false)
1821

1922
readonly loadingUserRecord$ = this._loadingUserRecord.asObservable()
23+
readonly loadingRecordHeader$ = this._loadingRecordHeader.asObservable()
2024
readonly isPublicRecord$ = this._isPublicRecord.asObservable()
25+
readonly userRecord$ = this._userRecord.asObservable()
2126
readonly affiliations$ = this._affiliations.asObservable()
2227
readonly displaySideBar$ = this._displaySideBar.asObservable()
2328
readonly displayBiography$ = this._displayBiography.asObservable()
@@ -29,9 +34,15 @@ export class RecordHeaderStateService {
2934
setLoadingUserRecord(val: boolean) {
3035
this._loadingUserRecord.next(val)
3136
}
37+
setLoadingRecordHeader(val: boolean) {
38+
this._loadingRecordHeader.next(val)
39+
}
3240
setIsPublicRecord(val: string | null) {
3341
this._isPublicRecord.next(val)
3442
}
43+
setUserRecord(val: UserRecord | null) {
44+
this._userRecord.next(val)
45+
}
3546
setAffiliations(val: number) {
3647
this._affiliations.next(val)
3748
}
@@ -53,7 +64,9 @@ export class RecordHeaderStateService {
5364

5465
reset() {
5566
this._loadingUserRecord.next(true)
67+
this._loadingRecordHeader.next(true)
5668
this._isPublicRecord.next(null)
69+
this._userRecord.next(null)
5770
this._affiliations.next(0)
5871
this._displaySideBar.next(false)
5972
this._displayBiography.next(false)
Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,72 @@
11
import { ComponentFixture, TestBed } from '@angular/core/testing'
22

33
import { RecordHeaderComponent } from './record-header.component'
4-
import { HttpClientTestingModule } from '@angular/common/http/testing'
54
import { WINDOW_PROVIDERS } from 'src/app/cdk/window'
65
import { PlatformInfoService } from 'src/app/cdk/platform-info'
7-
import { ErrorHandlerService } from 'src/app/core/error-handler/error-handler.service'
8-
import { SnackbarService } from 'src/app/cdk/snackbar/snackbar.service'
9-
import { MatSnackBar } from '@angular/material/snack-bar'
10-
import { MatDialog } from '@angular/material/dialog'
11-
import { Overlay } from '@angular/cdk/overlay'
126
import { RouterTestingModule } from '@angular/router/testing'
137
import { RecordService } from 'src/app/core/record/record.service'
14-
15-
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
168
import { MatTooltipModule } from '@angular/material/tooltip'
9+
import { of } from 'rxjs'
10+
import { HeaderCompactService } from 'src/app/core/header-compact/header-compact.service'
11+
import { RecordHeaderStateService } from 'src/app/core/record-header-state/record-header-state.service'
12+
import { TogglzService } from 'src/app/core/togglz/togglz.service'
13+
import { UserService } from 'src/app/core'
14+
import { getUserRecord } from 'src/app/core/record/record.service.spec'
15+
import { getUserSession } from 'src/app/core/user/user.service.spec'
16+
import { NoopAnimationsModule } from '@angular/platform-browser/animations'
17+
import { RumJourneyEventService } from 'src/app/rum/service/customEvent.service'
1718

1819
describe('RecordHeaderComponent', () => {
1920
let component: RecordHeaderComponent
2021
let fixture: ComponentFixture<RecordHeaderComponent>
22+
let state: RecordHeaderStateService
23+
let recordService: jasmine.SpyObj<RecordService>
2124

2225
beforeEach(async () => {
26+
recordService = jasmine.createSpyObj<RecordService>('RecordService', [
27+
'getRecord',
28+
])
29+
2330
await TestBed.configureTestingModule({
2431
imports: [
25-
HttpClientTestingModule,
2632
RouterTestingModule,
33+
NoopAnimationsModule,
2734
MatTooltipModule,
2835
RecordHeaderComponent,
2936
],
3037
providers: [
3138
WINDOW_PROVIDERS,
32-
RecordService,
33-
PlatformInfoService,
34-
ErrorHandlerService,
35-
SnackbarService,
36-
MatSnackBar,
37-
MatDialog,
38-
Overlay,
39+
RecordHeaderStateService,
40+
{ provide: RecordService, useValue: recordService },
41+
{
42+
provide: PlatformInfoService,
43+
useValue: { get: () => of({ columns12: true }) },
44+
},
45+
{
46+
provide: HeaderCompactService,
47+
useValue: { compactActive$: of(false) },
48+
},
49+
{
50+
provide: TogglzService,
51+
useValue: { getStateOf: () => of(false) },
52+
},
53+
{
54+
provide: UserService,
55+
useValue: { getUserSession: () => of(getUserSession()) },
56+
},
57+
{
58+
provide: RumJourneyEventService,
59+
useValue: {
60+
recordSimpleEvent: jasmine.createSpy('recordSimpleEvent'),
61+
},
62+
},
3963
],
40-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
4164
}).compileComponents()
4265
})
4366

4467
beforeEach(() => {
68+
state = TestBed.inject(RecordHeaderStateService)
69+
state.reset()
4570
fixture = TestBed.createComponent(RecordHeaderComponent)
4671
component = fixture.componentInstance
4772
fixture.detectChanges()
@@ -50,4 +75,41 @@ describe('RecordHeaderComponent', () => {
5075
it('should create', () => {
5176
expect(component).toBeTruthy()
5277
})
78+
79+
it('should render header data from shared record state', () => {
80+
const userRecord = getUserRecord()
81+
const orcid = userRecord.userInfo.REAL_USER_ORCID
82+
83+
state.setIsPublicRecord(orcid)
84+
state.setLoadingRecordHeader(false)
85+
state.setUserRecord(userRecord)
86+
fixture.detectChanges()
87+
88+
const text = fixture.nativeElement.textContent
89+
expect(component.bannerTitle).toBe('Published Name')
90+
expect(text).toContain('Published Name')
91+
expect(text).toContain(`https:${runtimeEnvironment.BASE_URL}${orcid}`)
92+
})
93+
94+
it('should not ask RecordService to load record data for the header', () => {
95+
state.setIsPublicRecord(getUserRecord().userInfo.REAL_USER_ORCID)
96+
state.setLoadingRecordHeader(false)
97+
state.setUserRecord(getUserRecord())
98+
fixture.detectChanges()
99+
100+
expect(recordService.getRecord).not.toHaveBeenCalled()
101+
})
102+
103+
it('should keep featured employment caption non-blocking', () => {
104+
const userRecord = getUserRecord()
105+
106+
state.setIsPublicRecord(userRecord.userInfo.REAL_USER_ORCID)
107+
state.setLoadingRecordHeader(false)
108+
state.setUserRecord({ ...userRecord, affiliations: undefined })
109+
fixture.detectChanges()
110+
111+
expect(component.loadingUserRecord).toBeFalse()
112+
expect(component.bannerTitle).toBe('Published Name')
113+
expect(component.bannerCaption).toBe('')
114+
})
53115
})

0 commit comments

Comments
 (0)