Skip to content

Commit eb2c7cf

Browse files
authored
[ENG-10364] Part 3: Add unit tests for preprints (#900)
- Ticket: [ENG-10364] - Feature flag: n/a ## Summary of Changes 1. Update unit tests for preprints details components.
1 parent 266a2da commit eb2c7cf

File tree

47 files changed

+1928
-1182
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1928
-1182
lines changed

src/app/features/preprints/components/preprint-details/additional-info/additional-info.component.html

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
<p-card>
2-
@if (preprint()) {
3-
@let preprintValue = preprint()!;
1+
@let preprintValue = preprint();
42

3+
<p-card>
4+
@if (preprintValue) {
55
<div class="flex flex-column gap-4">
66
@if (preprintValue.customPublicationCitation) {
77
<section class="flex flex-column gap-2">
@@ -19,12 +19,17 @@ <h3>{{ 'preprints.details.originalPublicationDate' | translate }}</h3>
1919
</section>
2020
}
2121

22-
@if (preprintValue.doi) {
22+
@if (preprintValue.articleDoiLink) {
2323
<section class="flex flex-column gap-2">
2424
<h3>{{ 'preprints.details.publicationDoi' | translate }}</h3>
2525

26-
<a class="font-bold word-break-word" [href]="preprint()?.articleDoiLink">
27-
{{ preprint()?.articleDoiLink }}
26+
<a
27+
class="font-bold word-break-word"
28+
[href]="preprintValue.articleDoiLink"
29+
target="_blank"
30+
rel="noopener noreferrer"
31+
>
32+
{{ preprintValue.articleDoiLink }}
2833
</a>
2934
</section>
3035
}
Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +0,0 @@
1-
.white-space-pre-line {
2-
white-space: pre-line;
3-
}
Lines changed: 63 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,59 @@
1-
import { MockComponents, MockPipe } from 'ng-mocks';
1+
import { Store } from '@ngxs/store';
2+
3+
import { MockComponents } from 'ng-mocks';
24

35
import { ComponentFixture, TestBed } from '@angular/core/testing';
46
import { Router } from '@angular/router';
57

68
import { PreprintSelectors } from '@osf/features/preprints/store/preprint';
79
import { LicenseDisplayComponent } from '@osf/shared/components/license-display/license-display.component';
8-
import { InterpolatePipe } from '@osf/shared/pipes/interpolate.pipe';
910
import { SubjectsSelectors } from '@osf/shared/stores/subjects';
1011

1112
import { CitationSectionComponent } from '../citation-section/citation-section.component';
1213

1314
import { AdditionalInfoComponent } from './additional-info.component';
1415

1516
import { PREPRINT_MOCK } from '@testing/mocks/preprint.mock';
16-
import { OSFTestingModule } from '@testing/osf.testing.module';
17-
import { provideMockStore } from '@testing/providers/store-provider.mock';
17+
import { provideOSFCore } from '@testing/osf.testing.provider';
18+
import { BaseSetupOverrides, mergeSignalOverrides, provideMockStore } from '@testing/providers/store-provider.mock';
1819

1920
describe('AdditionalInfoComponent', () => {
2021
let component: AdditionalInfoComponent;
2122
let fixture: ComponentFixture<AdditionalInfoComponent>;
23+
let store: Store;
2224

23-
const mockPreprint = PREPRINT_MOCK;
25+
interface SetupOverrides extends BaseSetupOverrides {
26+
preprintProviderId?: string;
27+
}
2428

25-
beforeEach(async () => {
26-
await TestBed.configureTestingModule({
27-
imports: [
28-
AdditionalInfoComponent,
29-
OSFTestingModule,
30-
...MockComponents(CitationSectionComponent, LicenseDisplayComponent),
31-
MockPipe(InterpolatePipe),
32-
],
29+
function setup(overrides: SetupOverrides = {}) {
30+
TestBed.configureTestingModule({
31+
imports: [AdditionalInfoComponent, ...MockComponents(CitationSectionComponent, LicenseDisplayComponent)],
3332
providers: [
33+
provideOSFCore(),
3434
provideMockStore({
35-
signals: [
36-
{
37-
selector: PreprintSelectors.getPreprint,
38-
value: mockPreprint,
39-
},
40-
{
41-
selector: PreprintSelectors.isPreprintLoading,
42-
value: false,
43-
},
44-
{
45-
selector: SubjectsSelectors.getSelectedSubjects,
46-
value: [],
47-
},
48-
{
49-
selector: SubjectsSelectors.areSelectedSubjectsLoading,
50-
value: false,
51-
},
52-
],
35+
signals: mergeSignalOverrides(
36+
[
37+
{ selector: PreprintSelectors.getPreprint, value: PREPRINT_MOCK },
38+
{ selector: PreprintSelectors.isPreprintLoading, value: false },
39+
{ selector: SubjectsSelectors.getSelectedSubjects, value: [] },
40+
{ selector: SubjectsSelectors.areSelectedSubjectsLoading, value: false },
41+
],
42+
overrides.selectorOverrides
43+
),
5344
}),
5445
],
55-
}).compileComponents();
46+
});
5647

5748
fixture = TestBed.createComponent(AdditionalInfoComponent);
5849
component = fixture.componentInstance;
59-
fixture.componentRef.setInput('preprintProviderId', 'osf');
50+
store = TestBed.inject(Store);
51+
fixture.componentRef.setInput('preprintProviderId', overrides.preprintProviderId ?? 'osf');
6052
fixture.detectChanges();
53+
}
54+
55+
beforeEach(() => {
56+
setup();
6157
});
6258

6359
it('should create', () => {
@@ -66,12 +62,12 @@ describe('AdditionalInfoComponent', () => {
6662

6763
it('should return license from preprint when available', () => {
6864
const license = component.license();
69-
expect(license).toBe(mockPreprint.embeddedLicense);
65+
expect(license).toBe(PREPRINT_MOCK.embeddedLicense);
7066
});
7167

7268
it('should return license options record from preprint when available', () => {
7369
const licenseOptionsRecord = component.licenseOptionsRecord();
74-
expect(licenseOptionsRecord).toEqual(mockPreprint.licenseOptions);
70+
expect(licenseOptionsRecord).toEqual(PREPRINT_MOCK.licenseOptions);
7571
});
7672

7773
it('should have skeleton data array with 5 null elements', () => {
@@ -89,4 +85,36 @@ describe('AdditionalInfoComponent', () => {
8985
queryParams: { search: 'test-tag' },
9086
});
9187
});
88+
89+
it('should not render DOI link when articleDoiLink is missing', () => {
90+
const doiLink = fixture.nativeElement.querySelector('a[href*="doi.org"]');
91+
expect(doiLink).toBeNull();
92+
});
93+
94+
it('should render DOI link when articleDoiLink is available', () => {
95+
setup({
96+
selectorOverrides: [
97+
{
98+
selector: PreprintSelectors.getPreprint,
99+
value: {
100+
...PREPRINT_MOCK,
101+
articleDoiLink: 'https://doi.org/10.1234/sample.article-doi',
102+
},
103+
},
104+
],
105+
});
106+
107+
const doiLink = fixture.nativeElement.querySelector('a[href*="doi.org"]') as HTMLAnchorElement | null;
108+
expect(doiLink).not.toBeNull();
109+
expect(doiLink?.getAttribute('href')).toBe('https://doi.org/10.1234/sample.article-doi');
110+
expect(doiLink?.textContent?.trim()).toBe('https://doi.org/10.1234/sample.article-doi');
111+
});
112+
113+
it('should not dispatch subject fetch when preprint id is missing', () => {
114+
setup({
115+
selectorOverrides: [{ selector: PreprintSelectors.getPreprint, value: null }],
116+
});
117+
118+
expect(store.dispatch).not.toHaveBeenCalled();
119+
});
92120
});

src/app/features/preprints/components/preprint-details/additional-info/additional-info.component.ts

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,41 +19,33 @@ import { CitationSectionComponent } from '../citation-section/citation-section.c
1919

2020
@Component({
2121
selector: 'osf-preprint-additional-info',
22-
imports: [Card, TranslatePipe, Tag, Skeleton, DatePipe, CitationSectionComponent, LicenseDisplayComponent],
22+
imports: [Card, Tag, Skeleton, CitationSectionComponent, LicenseDisplayComponent, DatePipe, TranslatePipe],
2323
templateUrl: './additional-info.component.html',
2424
styleUrl: './additional-info.component.scss',
2525
changeDetection: ChangeDetectionStrategy.OnPush,
2626
})
2727
export class AdditionalInfoComponent {
28-
private actions = createDispatchMap({
29-
fetchSubjects: FetchSelectedSubjects,
30-
});
31-
private router = inject(Router);
28+
private readonly router = inject(Router);
29+
private readonly actions = createDispatchMap({ fetchSubjects: FetchSelectedSubjects });
3230

33-
preprintProviderId = input.required<string>();
31+
readonly preprintProviderId = input.required<string>();
3432

35-
preprint = select(PreprintSelectors.getPreprint);
36-
isPreprintLoading = select(PreprintSelectors.isPreprintLoading);
33+
readonly preprint = select(PreprintSelectors.getPreprint);
34+
readonly isPreprintLoading = select(PreprintSelectors.isPreprintLoading);
3735

38-
subjects = select(SubjectsSelectors.getSelectedSubjects);
39-
areSelectedSubjectsLoading = select(SubjectsSelectors.areSelectedSubjectsLoading);
36+
readonly subjects = select(SubjectsSelectors.getSelectedSubjects);
37+
readonly areSelectedSubjectsLoading = select(SubjectsSelectors.areSelectedSubjectsLoading);
4038

41-
license = computed(() => {
42-
const preprint = this.preprint();
43-
if (!preprint) return null;
44-
return preprint.embeddedLicense;
45-
});
39+
readonly license = computed(() => this.preprint()?.embeddedLicense ?? null);
40+
readonly licenseOptionsRecord = computed(() => (this.preprint()?.licenseOptions ?? {}) as Record<string, string>);
4641

47-
licenseOptionsRecord = computed(() => (this.preprint()?.licenseOptions ?? {}) as Record<string, string>);
48-
49-
skeletonData = Array.from({ length: 5 }, () => null);
42+
readonly skeletonData = new Array(5).fill(null);
5043

5144
constructor() {
5245
effect(() => {
53-
const preprint = this.preprint();
54-
if (!preprint) return;
55-
56-
this.actions.fetchSubjects(this.preprint()!.id, ResourceType.Preprint);
46+
const preprintId = this.preprint()?.id;
47+
if (!preprintId) return;
48+
this.actions.fetchSubjects(preprintId, ResourceType.Preprint);
5749
});
5850
}
5951

src/app/features/preprints/components/preprint-details/citation-section/citation-section.component.html

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<p-accordion-header class="p-0 justify-content-between">
55
<h3>{{ 'project.overview.metadata.citation' | translate }}</h3>
66
</p-accordion-header>
7+
78
<p-accordion-content>
89
@if (areCitationsLoading()) {
910
<p-skeleton height="3.5rem"></p-skeleton>
@@ -18,25 +19,28 @@ <h3>{{ citation.title }}</h3>
1819
</div>
1920

2021
<p-divider />
22+
2123
<p>{{ 'project.overview.metadata.getMoreCitations' | translate }}</p>
24+
2225
<p-select
2326
class="mt-2 w-full"
24-
[placeholder]="'project.overview.metadata.citationInputPlaceholder' | translate"
25-
[loading]="areCitationStylesLoading()"
26-
[options]="citationStylesOptions()"
27-
[filter]="true"
28-
(onFilter)="handleCitationStyleFilterSearch($event)"
2927
optionLabel="label"
3028
optionValue="value"
3129
appendTo="body"
32-
[emptyFilterMessage]="filterMessage() | translate"
30+
[filter]="true"
31+
[placeholder]="'project.overview.metadata.citationInputPlaceholder' | translate"
3332
[emptyMessage]="'project.overview.metadata.citationInputPlaceholder' | translate"
33+
[emptyFilterMessage]="filterMessage() | translate"
34+
[loading]="areCitationStylesLoading()"
35+
[options]="citationStylesOptions()"
3436
(onChange)="handleGetStyledCitation($event)"
37+
(onFilter)="handleCitationStyleFilterSearch($event)"
3538
>
3639
<ng-template #selectedItem let-selectedOption>
3740
{{ selectedOption.label }}
3841
</ng-template>
3942
</p-select>
43+
4044
@if (styledCitation()) {
4145
<p class="mt-2">{{ styledCitation()?.citation }}</p>
4246
}

0 commit comments

Comments
 (0)