Skip to content

Commit a2afe96

Browse files
authored
Test/760 moderation pages (#475)
* test(moderation-pages): added tests * test(moderation-pages): added use of mocks
1 parent 217c552 commit a2afe96

File tree

4 files changed

+461
-75
lines changed

4 files changed

+461
-75
lines changed
Lines changed: 160 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,45 @@
1-
import { MockProvider } from 'ng-mocks';
1+
import { MockComponents, MockProvider } from 'ng-mocks';
22

33
import { BehaviorSubject } from 'rxjs';
44

55
import { ComponentFixture, TestBed } from '@angular/core/testing';
66
import { ActivatedRoute, Router } from '@angular/router';
77

88
import { IS_MEDIUM } from '@osf/shared/helpers';
9+
import { SelectComponent, SubHeaderComponent } from '@shared/components';
10+
11+
import { CollectionModerationTab } from '../../enums';
912

1013
import { CollectionModerationComponent } from './collection-moderation.component';
1114

1215
import { OSFTestingStoreModule } from '@testing/osf.testing.module';
16+
import { ActivatedRouteMockBuilder } from '@testing/providers/route-provider.mock';
17+
import { RouterMockBuilder } from '@testing/providers/router-provider.mock';
1318

1419
describe('Component: Collection Moderation', () => {
1520
let component: CollectionModerationComponent;
1621
let fixture: ComponentFixture<CollectionModerationComponent>;
1722
let isMediumSubject: BehaviorSubject<boolean>;
18-
19-
const mockActivatedRoute = {
20-
snapshot: {
21-
firstChild: {
22-
data: {
23-
tab: null,
24-
},
25-
},
26-
params: { providerId: 'osf' },
27-
},
28-
};
29-
30-
const mockRouter = {
31-
navigate: jest.fn(),
32-
};
23+
let mockRouter: ReturnType<RouterMockBuilder['build']>;
24+
let mockActivatedRoute: ReturnType<ActivatedRouteMockBuilder['build']>;
3325

3426
beforeEach(async () => {
3527
isMediumSubject = new BehaviorSubject<boolean>(true);
28+
mockRouter = RouterMockBuilder.create().build();
29+
mockActivatedRoute = ActivatedRouteMockBuilder.create()
30+
.withParams({ providerId: 'test-provider-id' })
31+
.withData({ tab: CollectionModerationTab.AllItems })
32+
.build();
3633

3734
await TestBed.configureTestingModule({
38-
imports: [CollectionModerationComponent, OSFTestingStoreModule],
35+
imports: [
36+
CollectionModerationComponent,
37+
OSFTestingStoreModule,
38+
...MockComponents(SubHeaderComponent, SelectComponent),
39+
],
3940
providers: [
40-
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
41-
{ provide: Router, useValue: mockRouter },
41+
MockProvider(ActivatedRoute, mockActivatedRoute),
42+
MockProvider(Router, mockRouter),
4243
MockProvider(IS_MEDIUM, isMediumSubject),
4344
],
4445
}).compileComponents();
@@ -51,4 +52,144 @@ describe('Component: Collection Moderation', () => {
5152
it('should create', () => {
5253
expect(component).toBeTruthy();
5354
});
55+
56+
it('should initialize with default values', () => {
57+
expect(component.selectedTab).toBeUndefined();
58+
expect(component.tabOptions).toBeDefined();
59+
expect(component.isMedium).toBeDefined();
60+
});
61+
62+
it('should initialize selected tab from route data', async () => {
63+
const mockFirstChild = {
64+
data: { tab: CollectionModerationTab.Moderators },
65+
};
66+
67+
const routeWithFirstChild = ActivatedRouteMockBuilder.create()
68+
.withParams({ providerId: 'test-provider-id' })
69+
.build();
70+
71+
Object.defineProperty(routeWithFirstChild.snapshot, 'firstChild', {
72+
value: mockFirstChild,
73+
writable: true,
74+
});
75+
76+
await TestBed.configureTestingModule({
77+
imports: [
78+
CollectionModerationComponent,
79+
OSFTestingStoreModule,
80+
...MockComponents(SubHeaderComponent, SelectComponent),
81+
],
82+
providers: [
83+
MockProvider(ActivatedRoute, routeWithFirstChild),
84+
MockProvider(Router, mockRouter),
85+
MockProvider(IS_MEDIUM, isMediumSubject),
86+
],
87+
}).compileComponents();
88+
89+
const testFixture = TestBed.createComponent(CollectionModerationComponent);
90+
const testComponent = testFixture.componentInstance;
91+
92+
testComponent.ngOnInit();
93+
94+
expect(testComponent.selectedTab).toBe(CollectionModerationTab.Moderators);
95+
});
96+
97+
it('should navigate to not-found when providerId is missing', async () => {
98+
const routeWithoutProviderId = ActivatedRouteMockBuilder.create().withParams({}).build();
99+
100+
await TestBed.configureTestingModule({
101+
imports: [
102+
CollectionModerationComponent,
103+
OSFTestingStoreModule,
104+
...MockComponents(SubHeaderComponent, SelectComponent),
105+
],
106+
providers: [
107+
MockProvider(ActivatedRoute, routeWithoutProviderId),
108+
MockProvider(Router, mockRouter),
109+
MockProvider(IS_MEDIUM, isMediumSubject),
110+
],
111+
}).compileComponents();
112+
113+
const testFixture = TestBed.createComponent(CollectionModerationComponent);
114+
const testComponent = testFixture.componentInstance;
115+
116+
testComponent.ngOnInit();
117+
118+
expect(mockRouter.navigate).toHaveBeenCalledWith(['/not-found']);
119+
});
120+
121+
it('should call getCollectionProvider action on init when providerId exists', () => {
122+
const getCollectionProviderSpy = jest.fn();
123+
component.actions = {
124+
...component.actions,
125+
getCollectionProvider: getCollectionProviderSpy,
126+
};
127+
128+
component.ngOnInit();
129+
130+
expect(getCollectionProviderSpy).toHaveBeenCalledWith('test-provider-id');
131+
});
132+
133+
it('should handle tab change and navigate to new tab', () => {
134+
const newTab = CollectionModerationTab.Moderators;
135+
136+
component.onTabChange(newTab);
137+
138+
expect(component.selectedTab).toBe(newTab);
139+
expect(mockRouter.navigate).toHaveBeenCalledWith([newTab], { relativeTo: expect.any(Object) });
140+
});
141+
142+
it('should call clearCurrentProvider on destroy', () => {
143+
const clearCurrentProviderSpy = jest.fn();
144+
component.actions = {
145+
...component.actions,
146+
clearCurrentProvider: clearCurrentProviderSpy,
147+
};
148+
149+
component.ngOnDestroy();
150+
151+
expect(clearCurrentProviderSpy).toHaveBeenCalled();
152+
});
153+
154+
it('should have actions defined', () => {
155+
expect(component.actions).toBeDefined();
156+
expect(component.actions.getCollectionProvider).toBeDefined();
157+
expect(component.actions.clearCurrentProvider).toBeDefined();
158+
});
159+
160+
it('should have tab options defined', () => {
161+
expect(component.tabOptions).toBeDefined();
162+
expect(component.tabOptions.length).toBeGreaterThan(0);
163+
});
164+
165+
it('should handle isMedium observable', () => {
166+
expect(component.isMedium()).toBe(true);
167+
168+
isMediumSubject.next(false);
169+
fixture.detectChanges();
170+
171+
expect(component.isMedium()).toBe(false);
172+
});
173+
174+
it('should handle tab change with different tab values', () => {
175+
const tabs = [
176+
CollectionModerationTab.AllItems,
177+
CollectionModerationTab.Moderators,
178+
CollectionModerationTab.Settings,
179+
];
180+
181+
tabs.forEach((tab) => {
182+
component.onTabChange(tab);
183+
expect(component.selectedTab).toBe(tab);
184+
expect(mockRouter.navigate).toHaveBeenCalledWith([tab], { relativeTo: expect.any(Object) });
185+
});
186+
});
187+
188+
it('should not navigate when providerId is present', () => {
189+
mockActivatedRoute = ActivatedRouteMockBuilder.create().withParams({ providerId: 'valid-id' }).build();
190+
191+
component.ngOnInit();
192+
193+
expect(mockRouter.navigate).not.toHaveBeenCalledWith(['/not-found']);
194+
});
54195
});
Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,47 @@
1-
import { Store } from '@ngxs/store';
2-
3-
import { TranslatePipe } from '@ngx-translate/core';
4-
import { MockComponents, MockPipe, MockProvider } from 'ng-mocks';
1+
import { MockComponents } from 'ng-mocks';
52

63
import { ComponentFixture, TestBed } from '@angular/core/testing';
74

5+
import {
6+
MyReviewingNavigationComponent,
7+
PreprintRecentActivityListComponent,
8+
} from '@osf/features/moderation/components';
89
import { SubHeaderComponent } from '@osf/shared/components';
9-
import { MOCK_STORE } from '@shared/mocks';
1010

11-
import { MyReviewingNavigationComponent, PreprintRecentActivityListComponent } from '../../components';
1211
import { PreprintModerationSelectors } from '../../store/preprint-moderation';
1312

1413
import { MyPreprintReviewingComponent } from './my-preprint-reviewing.component';
1514

15+
import { MOCK_PREPRINT_PROVIDER_MODERATION_INFO } from '@testing/mocks/preprint-provider-moderation-info.mock';
16+
import { MOCK_PREPRINT_REVIEW_ACTIONS } from '@testing/mocks/preprint-review-action.mock';
17+
import { OSFTestingStoreModule } from '@testing/osf.testing.module';
18+
import { provideMockStore } from '@testing/providers/store-provider.mock';
19+
1620
describe('MyPreprintReviewingComponent', () => {
1721
let component: MyPreprintReviewingComponent;
1822
let fixture: ComponentFixture<MyPreprintReviewingComponent>;
1923

20-
beforeEach(async () => {
21-
(MOCK_STORE.selectSignal as jest.Mock).mockImplementation((selector) => {
22-
if (selector === PreprintModerationSelectors.getPreprintProviders) return () => [];
23-
if (selector === PreprintModerationSelectors.arePreprintProviderLoading) return () => false;
24-
if (selector === PreprintModerationSelectors.getPreprintReviews) return () => [];
25-
if (selector === PreprintModerationSelectors.arePreprintReviewsLoading) return () => false;
26-
if (selector === PreprintModerationSelectors.getPreprintReviewsTotalCount) return () => 0;
27-
return () => null;
28-
});
24+
const mockPreprintProviders = [MOCK_PREPRINT_PROVIDER_MODERATION_INFO];
25+
const mockPreprintReviews = MOCK_PREPRINT_REVIEW_ACTIONS;
2926

27+
beforeEach(async () => {
3028
await TestBed.configureTestingModule({
3129
imports: [
3230
MyPreprintReviewingComponent,
33-
...MockComponents(SubHeaderComponent, MyReviewingNavigationComponent, PreprintRecentActivityListComponent),
34-
MockPipe(TranslatePipe),
31+
OSFTestingStoreModule,
32+
...MockComponents(SubHeaderComponent, PreprintRecentActivityListComponent, MyReviewingNavigationComponent),
33+
],
34+
providers: [
35+
provideMockStore({
36+
signals: [
37+
{ selector: PreprintModerationSelectors.getPreprintProviders, value: mockPreprintProviders },
38+
{ selector: PreprintModerationSelectors.arePreprintProviderLoading, value: false },
39+
{ selector: PreprintModerationSelectors.getPreprintReviews, value: mockPreprintReviews },
40+
{ selector: PreprintModerationSelectors.arePreprintReviewsLoading, value: false },
41+
{ selector: PreprintModerationSelectors.getPreprintReviewsTotalCount, value: 2 },
42+
],
43+
}),
3544
],
36-
providers: [MockProvider(Store, MOCK_STORE)],
3745
}).compileComponents();
3846

3947
fixture = TestBed.createComponent(MyPreprintReviewingComponent);
@@ -44,4 +52,24 @@ describe('MyPreprintReviewingComponent', () => {
4452
it('should create', () => {
4553
expect(component).toBeTruthy();
4654
});
55+
56+
it('should initialize with default values', () => {
57+
expect(component.preprintProviders()).toEqual(mockPreprintProviders);
58+
expect(component.isPreprintProvidersLoading()).toBe(false);
59+
expect(component.preprintReviews()).toEqual(mockPreprintReviews);
60+
expect(component.isReviewsLoading()).toBe(false);
61+
expect(component.preprintReviewsTotalCount()).toBe(2);
62+
});
63+
64+
it('should handle page change', () => {
65+
expect(() => component.pageChanged(2)).not.toThrow();
66+
});
67+
68+
it('should handle page change with different page numbers', () => {
69+
const pages = [1, 2, 3, 5, 10];
70+
71+
pages.forEach((page) => {
72+
expect(() => component.pageChanged(page)).not.toThrow();
73+
});
74+
});
4775
});

0 commit comments

Comments
 (0)