Skip to content

Commit f57b8c0

Browse files
committed
chore(datacite-tracker): added tests to project and preprint components
1 parent 43bb3ef commit f57b8c0

10 files changed

Lines changed: 237 additions & 34 deletions

File tree

jest.config.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module.exports = {
88
'^@osf/(.*)$': '<rootDir>/src/app/$1',
99
'^@core/(.*)$': '<rootDir>/src/app/core/$1',
1010
'^@shared/(.*)$': '<rootDir>/src/app/shared/$1',
11-
'^@styles/(.*)$': '<rootDir>/src/styles/$1',
11+
'^@styles/(.*)$': '<rootDir>/assets/styles/$1',
1212
'^@testing/(.*)$': '<rootDir>/src/testing/$1',
1313
'^src/environments/environment$': '<rootDir>/src/environments/environment.ts',
1414
},
@@ -76,9 +76,10 @@ module.exports = {
7676
'<rootDir>/src/app/features/project/addons/components/confirm-account-connection-modal/',
7777
'<rootDir>/src/app/features/files/',
7878
'<rootDir>/src/app/features/my-projects/',
79-
'<rootDir>/src/app/features/preprints/',
79+
'<rootDir>/src/app/features/project/analytics/',
8080
'<rootDir>/src/app/features/project/contributors/',
81-
'<rootDir>/src/app/features/project/overview/',
81+
'<rootDir>/src/app/features/project/files/',
82+
'<rootDir>/src/app/features/project/metadata/',
8283
'<rootDir>/src/app/features/project/registrations',
8384
'<rootDir>/src/app/features/project/settings',
8485
'<rootDir>/src/app/features/project/wiki',
@@ -97,6 +98,9 @@ module.exports = {
9798
'<rootDir>/src/app/shared/components/pie-chart/',
9899
'<rootDir>/src/app/shared/components/resource-citations/',
99100
'<rootDir>/src/app/shared/components/reusable-filter/',
101+
'<rootDir>/src/app/shared/components/shared-metadata/dialogs/affiliated-institutions-dialog/',
102+
'<rootDir>/src/app/shared/components/shared-metadata/dialogs/contributors-dialog/',
103+
'<rootDir>/src/app/shared/components/shared-metadata/shared-metadata',
100104
'<rootDir>/src/app/shared/components/subjects/',
101105
'<rootDir>/src/app/shared/components/wiki/edit-section/',
102106
'<rootDir>/src/app/shared/components/wiki/wiki-list/',

src/app/features/preprints/models/preprint.models.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { ProjectIdentifiers } from '@osf/features/project/overview/models';
2-
import { UserPermissions } from '@osf/shared/enums';
3-
import { BooleanOrNull, StringOrNull } from '@osf/shared/helpers';
4-
import { IdName, License, LicenseOptions } from '@osf/shared/models';
1+
import { Identifier, IdName, License, LicenseOptions } from '@osf/shared/models';
2+
import { UserPermissions } from '@shared/enums';
3+
import { BooleanOrNull, StringOrNull } from '@shared/helpers';
54

65
import { ApplicabilityStatus, PreregLinkInfo, ReviewsState } from '../enums';
76

@@ -44,7 +43,7 @@ export interface Preprint {
4443
embeddedLicense?: License;
4544
preprintDoiLink?: string;
4645
articleDoiLink?: string;
47-
identifiers?: ProjectIdentifiers[];
46+
identifiers?: Identifier[];
4847
}
4948

5049
export interface PreprintFilesLinks {

src/app/features/preprints/pages/preprint-details/preprint-details.component.spec.ts

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import { MockComponents, MockPipe, MockProvider } from 'ng-mocks';
55

66
import { of } from 'rxjs';
77

8+
import { signal } from '@angular/core';
89
import { ComponentFixture, TestBed } from '@angular/core/testing';
10+
import { provideNoopAnimations } from '@angular/platform-browser/animations';
911
import { ActivatedRoute, Router } from '@angular/router';
1012

1113
import { AdditionalInfoComponent } from '@osf/features/preprints/components/preprint-details/additional-info/additional-info.component';
@@ -15,15 +17,21 @@ import { ShareAndDownloadComponent } from '@osf/features/preprints/components/pr
1517
import { PreprintSelectors } from '@osf/features/preprints/store/preprint';
1618
import { PreprintProvidersSelectors } from '@osf/features/preprints/store/preprint-providers';
1719
import { MOCK_PROVIDER, MOCK_STORE, TranslateServiceMock } from '@shared/mocks';
20+
import { Identifier } from '@shared/models';
21+
import { DataciteService } from '@shared/services/datacite/datacite.service';
1822

1923
import { PreprintDetailsComponent } from './preprint-details.component';
2024

21-
describe.skip('PreprintDetailsComponent', () => {
25+
describe('PreprintDetailsComponent', () => {
2226
let component: PreprintDetailsComponent;
2327
let fixture: ComponentFixture<PreprintDetailsComponent>;
2428

29+
let dataciteService: jest.Mocked<DataciteService>;
30+
31+
const preprintSignal = signal<any | null>({ id: 'p1', title: 'Test', description: '' });
2532
const mockRoute: Partial<ActivatedRoute> = {
2633
params: of({ providerId: 'osf', preprintId: 'p1' }),
34+
queryParams: of({ providerId: 'osf', preprintId: 'p1' }),
2735
};
2836

2937
beforeEach(async () => {
@@ -34,13 +42,17 @@ describe.skip('PreprintDetailsComponent', () => {
3442
case PreprintProvidersSelectors.isPreprintProviderDetailsLoading:
3543
return () => false;
3644
case PreprintSelectors.getPreprint:
37-
return () => ({ id: 'p1', title: 'Test', description: '' });
45+
return preprintSignal;
3846
case PreprintSelectors.isPreprintLoading:
3947
return () => false;
4048
default:
4149
return () => [];
4250
}
4351
});
52+
(MOCK_STORE.dispatch as jest.Mock).mockImplementation(() => of());
53+
dataciteService = {
54+
logView: jest.fn().mockReturnValue(of(void 0)),
55+
} as unknown as jest.Mocked<DataciteService>;
4456

4557
await TestBed.configureTestingModule({
4658
imports: [
@@ -55,6 +67,8 @@ describe.skip('PreprintDetailsComponent', () => {
5567
],
5668
providers: [
5769
MockProvider(Store, MOCK_STORE),
70+
provideNoopAnimations(),
71+
{ provide: DataciteService, useValue: dataciteService },
5872
MockProvider(Router),
5973
MockProvider(ActivatedRoute, mockRoute),
6074
TranslateServiceMock,
@@ -66,11 +80,36 @@ describe.skip('PreprintDetailsComponent', () => {
6680
fixture.detectChanges();
6781
});
6882

69-
it('should create', () => {
70-
expect(component).toBeTruthy();
71-
});
72-
7383
it('isOsfPreprint should be true if providerId === osf', () => {
7484
expect(component.isOsfPreprint()).toBeTruthy();
7585
});
86+
87+
it('reacts to sequence of state changes', () => {
88+
fixture.detectChanges();
89+
expect(dataciteService.logView).toHaveBeenCalledTimes(0);
90+
91+
preprintSignal.set(getPreprint([]));
92+
93+
fixture.detectChanges();
94+
expect(dataciteService.logView).toHaveBeenCalledTimes(0);
95+
96+
preprintSignal.set(getPreprint([{ category: 'dio', value: '123', id: '', type: 'identifier' }]));
97+
fixture.detectChanges();
98+
expect(dataciteService.logView).toHaveBeenCalledTimes(0);
99+
100+
preprintSignal.set(getPreprint([{ category: 'doi', value: '123', id: '', type: 'identifier' }]));
101+
102+
fixture.detectChanges();
103+
expect(dataciteService.logView).toHaveBeenCalled();
104+
105+
preprintSignal.set(getPreprint([{ category: 'doi', value: '456', id: '', type: 'identifier' }]));
106+
fixture.detectChanges();
107+
expect(dataciteService.logView).toHaveBeenLastCalledWith('123');
108+
});
76109
});
110+
111+
function getPreprint(identifiers: Identifier[]) {
112+
return {
113+
identifiers: identifiers,
114+
};
115+
}

src/app/features/preprints/pages/preprint-details/preprint-details.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ import {
4545
} from '@osf/features/preprints/store/preprint';
4646
import { GetPreprintProviderById, PreprintProvidersSelectors } from '@osf/features/preprints/store/preprint-providers';
4747
import { CreateNewVersion, PreprintStepperSelectors } from '@osf/features/preprints/store/preprint-stepper';
48-
import { ProjectIdentifiers } from '@osf/features/project/overview/models';
4948
import { IS_MEDIUM, pathJoin } from '@osf/shared/helpers';
5049
import { DataciteTrackerComponent } from '@shared/components/datacite-tracker/datacite-tracker.component';
5150
import { ReviewPermissions, UserPermissions } from '@shared/enums';
51+
import { Identifier } from '@shared/models';
5252
import { MetaTagsService } from '@shared/services';
5353
import { ContributorsSelectors } from '@shared/stores';
5454

@@ -291,7 +291,7 @@ export class PreprintDetailsComponent extends DataciteTrackerComponent implement
291291
this.actions.resetState();
292292
}
293293

294-
protected override get trackable(): Observable<{ identifiers?: ProjectIdentifiers[] } | null> {
294+
protected override get trackable(): Observable<{ identifiers?: Identifier[] } | null> {
295295
return this.preprint$;
296296
}
297297

Lines changed: 169 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,188 @@
1-
import { MockComponent } from 'ng-mocks';
1+
import { Store } from '@ngxs/store';
22

3+
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
4+
import { MockProvider } from 'ng-mocks';
5+
6+
import { ButtonGroupModule } from 'primeng/buttongroup';
7+
import { DialogService } from 'primeng/dynamicdialog';
8+
import { Message } from 'primeng/message';
9+
import { TagModule } from 'primeng/tag';
10+
11+
import { of } from 'rxjs';
12+
13+
import { DestroyRef, signal } from '@angular/core';
314
import { ComponentFixture, TestBed } from '@angular/core/testing';
15+
import { FormsModule } from '@angular/forms';
16+
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
417

5-
import { SubHeaderComponent } from '@osf/shared/components';
18+
import { CollectionSubmissionReviewAction } from '@osf/features/moderation/models';
19+
import { CollectionsModerationSelectors } from '@osf/features/moderation/store/collections-moderation';
20+
import { ProjectOverviewSelectors } from '@osf/features/project/overview/store';
21+
import {
22+
LoadingSpinnerComponent,
23+
ResourceMetadataComponent,
24+
SubHeaderComponent,
25+
ViewOnlyLinkMessageComponent,
26+
} from '@osf/shared/components';
27+
import { ToastService } from '@osf/shared/services';
28+
import { MOCK_STORE } from '@shared/mocks';
29+
import { Identifier } from '@shared/models';
30+
import { DataciteService } from '@shared/services/datacite/datacite.service';
31+
import {
32+
BookmarksSelectors,
33+
CitationsSelectors,
34+
CollectionsSelectors,
35+
MyResourcesSelectors,
36+
NodeLinksSelectors,
37+
} from '@shared/stores';
38+
import { ActivityLogsSelectors } from '@shared/stores/activity-logs';
639

40+
import {
41+
LinkedResourcesComponent,
42+
OverviewComponentsComponent,
43+
OverviewToolbarComponent,
44+
OverviewWikiComponent,
45+
RecentActivityComponent,
46+
} from './components';
747
import { ProjectOverviewComponent } from './project-overview.component';
848

49+
import { OSFTestingModule } from '@testing/osf.testing.module';
50+
51+
const sampleReviewAction: CollectionSubmissionReviewAction = {
52+
id: 'ra1',
53+
type: 'collection-submission-review-action',
54+
dateCreated: '2025-09-01T10:15:00Z',
55+
dateModified: '2025-09-01T10:30:00Z',
56+
fromState: 'pending',
57+
toState: 'accepted',
58+
comment: 'Submission approved by moderator',
59+
trigger: 'accept',
60+
targetId: 'sub123',
61+
targetNodeId: 'node456',
62+
createdBy: 'user789',
63+
};
64+
965
describe('ProjectOverviewComponent', () => {
10-
let component: ProjectOverviewComponent;
1166
let fixture: ComponentFixture<ProjectOverviewComponent>;
67+
let dataciteService: jest.Mocked<DataciteService>;
68+
const projectSignal = signal<any>(getProject());
69+
70+
const activatedRouteMock = {
71+
snapshot: {
72+
queryParams: {
73+
mode: 'moderation', // or whatever value you want to test
74+
},
75+
params: {
76+
id: '1234', // value for this.route.snapshot.params['id']
77+
},
78+
parent: {
79+
snapshot: {
80+
params: {
81+
id: '5678', // fallback if top-level param is undefined
82+
},
83+
},
84+
},
85+
},
86+
};
1287

1388
beforeEach(async () => {
89+
(MOCK_STORE.selectSignal as jest.Mock).mockImplementation((selector) => {
90+
switch (selector) {
91+
case ProjectOverviewSelectors.getProject:
92+
return projectSignal;
93+
case CollectionsModerationSelectors.getCurrentReviewAction:
94+
return signal(sampleReviewAction);
95+
case ProjectOverviewSelectors.getProjectLoading:
96+
case CollectionsSelectors.getCollectionProviderLoading:
97+
case CollectionsModerationSelectors.getCurrentReviewActionLoading:
98+
case ProjectOverviewSelectors.isProjectAnonymous:
99+
case MyResourcesSelectors.getBookmarksLoading:
100+
case BookmarksSelectors.getBookmarksCollectionIdSubmitting:
101+
case ProjectOverviewSelectors.getComponentsLoading:
102+
case NodeLinksSelectors.getLinkedResourcesLoading:
103+
case ActivityLogsSelectors.getActivityLogsLoading:
104+
return () => false;
105+
case ActivityLogsSelectors.getActivityLogsTotalCount:
106+
return () => 0;
107+
case BookmarksSelectors.getBookmarksCollectionId:
108+
return () => '123';
109+
case MyResourcesSelectors.getBookmarks:
110+
case ActivityLogsSelectors.getActivityLogs:
111+
case CitationsSelectors.getCitationStyles:
112+
case ProjectOverviewSelectors.getComponents:
113+
case NodeLinksSelectors.getLinkedResources:
114+
return () => [];
115+
default:
116+
return () => '';
117+
}
118+
});
119+
120+
dataciteService = {
121+
logView: jest.fn().mockReturnValue(of(void 0)),
122+
} as unknown as jest.Mocked<DataciteService>;
123+
14124
await TestBed.configureTestingModule({
15-
imports: [ProjectOverviewComponent, MockComponent(SubHeaderComponent)],
125+
imports: [
126+
ProjectOverviewComponent,
127+
OSFTestingModule,
128+
ButtonGroupModule,
129+
TagModule,
130+
SubHeaderComponent,
131+
FormsModule,
132+
LoadingSpinnerComponent,
133+
OverviewWikiComponent,
134+
OverviewComponentsComponent,
135+
LinkedResourcesComponent,
136+
RecentActivityComponent,
137+
OverviewToolbarComponent,
138+
ResourceMetadataComponent,
139+
TranslatePipe,
140+
Message,
141+
RouterLink,
142+
ViewOnlyLinkMessageComponent,
143+
],
144+
providers: [
145+
{ provide: ActivatedRoute, useValue: activatedRouteMock },
146+
{ provide: Store, useValue: MOCK_STORE },
147+
{ provide: DataciteService, useValue: dataciteService },
148+
Router,
149+
DestroyRef,
150+
MockProvider(ToastService),
151+
DialogService,
152+
TranslateService,
153+
],
16154
}).compileComponents();
17155

18156
fixture = TestBed.createComponent(ProjectOverviewComponent);
19-
component = fixture.componentInstance;
20157
fixture.detectChanges();
21158
});
22159

23-
it('should create', () => {
24-
expect(component).toBeTruthy();
160+
it('reacts to sequence of state changes', () => {
161+
fixture.detectChanges();
162+
expect(dataciteService.logView).toHaveBeenCalledTimes(0);
163+
164+
projectSignal.set(getProject());
165+
166+
fixture.detectChanges();
167+
expect(dataciteService.logView).toHaveBeenCalledTimes(0);
168+
169+
projectSignal.set(getProject([{ category: 'dio', value: '123', id: '', type: 'identifier' }]));
170+
fixture.detectChanges();
171+
expect(dataciteService.logView).toHaveBeenCalledTimes(0);
172+
173+
projectSignal.set(getProject([{ category: 'doi', value: '123', id: '', type: 'identifier' }]));
174+
175+
fixture.detectChanges();
176+
expect(dataciteService.logView).toHaveBeenCalled();
177+
178+
projectSignal.set(getProject([{ category: 'doi', value: '456', id: '', type: 'identifier' }]));
179+
fixture.detectChanges();
180+
expect(dataciteService.logView).toHaveBeenLastCalledWith('123');
25181
});
182+
183+
function getProject(identifiers?: Identifier[]) {
184+
return {
185+
identifiers: identifiers ?? [],
186+
};
187+
}
26188
});

src/app/features/project/overview/project-overview.component.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ import { FormsModule } from '@angular/forms';
2525
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
2626

2727
import { SubmissionReviewStatus } from '@osf/features/moderation/enums';
28-
import { ProjectIdentifiers } from '@osf/features/project/overview/models';
29-
3028
import {
3129
ClearCollectionModeration,
3230
CollectionsModerationSelectors,
@@ -54,6 +52,7 @@ import {
5452
SubHeaderComponent,
5553
ViewOnlyLinkMessageComponent,
5654
} from '@shared/components';
55+
import { Identifier } from '@shared/models';
5756

5857
import {
5958
LinkedResourcesComponent,
@@ -203,7 +202,7 @@ export class ProjectOverviewComponent extends DataciteTrackerComponent implement
203202
return null;
204203
});
205204

206-
protected override get trackable(): Observable<{ identifiers?: ProjectIdentifiers[] } | null> {
205+
protected override get trackable(): Observable<{ identifiers?: Identifier[] } | null> {
207206
return this.currentProject$;
208207
}
209208

0 commit comments

Comments
 (0)