Skip to content

Commit 23a5f24

Browse files
authored
Test/1088 improvement (#662)
* fix(tests): fixed skipped tests * fix(tests): added tests for skipped files * fix(tests): fixed tests for registry and token-add-edit-form * fix(tests): fixed tests preprint-withdrawal-submissions * test(registry-components): added new tests
1 parent 4b66cfb commit 23a5f24

File tree

37 files changed

+3056
-189
lines changed

37 files changed

+3056
-189
lines changed

jest.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,13 @@ module.exports = {
6464
'<rootDir>/src/environments',
6565
'<rootDir>/src/app/app.config.ts',
6666
'<rootDir>/src/app/app.routes.ts',
67-
'<rootDir>/src/app/features/files/components',
6867
'<rootDir>/src/app/features/files/pages/file-detail',
6968
'<rootDir>/src/app/features/project/addons/',
7069
'<rootDir>/src/app/features/project/overview/',
7170
'<rootDir>/src/app/features/project/registrations',
7271
'<rootDir>/src/app/features/project/wiki',
73-
'<rootDir>/src/app/features/registry/',
72+
'<rootDir>/src/app/features/registry/components',
73+
'<rootDir>/src/app/features/registry/pages/registry-wiki/registry-wiki',
7474
'<rootDir>/src/app/features/settings/addons/',
7575
'<rootDir>/src/app/features/settings/tokens/store/',
7676
'<rootDir>/src/app/shared/components/file-menu/',
Lines changed: 170 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,66 @@
1-
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
2-
import { MockPipe, MockProvider } from 'ng-mocks';
1+
import { MockProvider } from 'ng-mocks';
32

3+
import { NO_ERRORS_SCHEMA, signal } from '@angular/core';
44
import { ComponentFixture, TestBed } from '@angular/core/testing';
5-
import { provideNoopAnimations } from '@angular/platform-browser/animations';
6-
import { ActivatedRoute } from '@angular/router';
5+
import { ActivatedRoute, Router } from '@angular/router';
6+
7+
import { CustomMenuItem } from '@osf/core/models';
8+
import { AuthService } from '@osf/core/services';
9+
import { ProviderSelectors } from '@osf/core/store/provider/provider.selectors';
10+
import { UserSelectors } from '@osf/core/store/user/user.selectors';
11+
import { CurrentResourceSelectors } from '@osf/shared/stores';
712

813
import { NavMenuComponent } from './nav-menu.component';
914

10-
describe.skip('NavMenuComponent', () => {
15+
import { MOCK_USER } from '@testing/mocks';
16+
import { OSFTestingModule } from '@testing/osf.testing.module';
17+
import { ActivatedRouteMockBuilder } from '@testing/providers/route-provider.mock';
18+
import { RouterMockBuilder } from '@testing/providers/router-provider.mock';
19+
import { provideMockStore } from '@testing/providers/store-provider.mock';
20+
21+
describe('NavMenuComponent', () => {
1122
let component: NavMenuComponent;
1223
let fixture: ComponentFixture<NavMenuComponent>;
24+
let mockAuthService: any;
1325

1426
beforeEach(async () => {
27+
Object.defineProperty(window, 'open', {
28+
writable: true,
29+
value: jest.fn(),
30+
});
31+
mockAuthService = {
32+
navigateToSignIn: jest.fn(),
33+
logout: jest.fn(),
34+
};
35+
1536
await TestBed.configureTestingModule({
16-
imports: [NavMenuComponent, MockPipe(TranslatePipe)],
17-
providers: [MockProvider(ActivatedRoute), MockProvider(TranslateService), provideNoopAnimations()],
37+
imports: [NavMenuComponent, OSFTestingModule],
38+
providers: [
39+
provideMockStore({
40+
signals: [
41+
{ selector: UserSelectors.isAuthenticated, value: signal(false) },
42+
{ selector: UserSelectors.getCurrentUser, value: signal(MOCK_USER) },
43+
{ selector: UserSelectors.getCanViewReviews, value: signal(false) },
44+
{ selector: ProviderSelectors.getCurrentProvider, value: signal(null) },
45+
{ selector: CurrentResourceSelectors.getCurrentResource, value: signal(null) },
46+
],
47+
}),
48+
{
49+
provide: Router,
50+
useValue: {
51+
...RouterMockBuilder.create().withUrl('/test').build(),
52+
serializeUrl: jest.fn(() => '/test'),
53+
parseUrl: jest.fn(() => ({})),
54+
isActive: jest.fn(() => false),
55+
},
56+
},
57+
{
58+
provide: ActivatedRoute,
59+
useValue: ActivatedRouteMockBuilder.create().build(),
60+
},
61+
MockProvider(AuthService, mockAuthService),
62+
],
63+
schemas: [NO_ERRORS_SCHEMA],
1864
}).compileComponents();
1965

2066
fixture = TestBed.createComponent(NavMenuComponent);
@@ -25,4 +71,121 @@ describe.skip('NavMenuComponent', () => {
2571
it('should create', () => {
2672
expect(component).toBeTruthy();
2773
});
74+
75+
it('should open external links in new tab for support and donate items', () => {
76+
const openSpy = jest.spyOn(window, 'open');
77+
const supportItem: CustomMenuItem = { id: 'support', url: 'https://support.example.com' };
78+
const donateItem: CustomMenuItem = { id: 'donate', url: 'https://donate.example.com' };
79+
80+
component.goToLink(supportItem);
81+
expect(openSpy).toHaveBeenCalledWith('https://support.example.com', '_blank');
82+
83+
component.goToLink(donateItem);
84+
expect(openSpy).toHaveBeenCalledWith('https://donate.example.com', '_blank');
85+
});
86+
87+
it('should navigate to sign in for sign-in item', () => {
88+
const signInItem: CustomMenuItem = { id: 'sign-in' };
89+
90+
component.goToLink(signInItem);
91+
expect(mockAuthService.navigateToSignIn).toHaveBeenCalled();
92+
});
93+
94+
it('should logout for log-out item', () => {
95+
const logOutItem: CustomMenuItem = { id: 'log-out' };
96+
97+
component.goToLink(logOutItem);
98+
expect(mockAuthService.logout).toHaveBeenCalled();
99+
});
100+
101+
it('should emit closeMenu for items without children', () => {
102+
const emitSpy = jest.spyOn(component.closeMenu, 'emit');
103+
const menuItem: CustomMenuItem = { id: 'test-item' };
104+
105+
component.goToLink(menuItem);
106+
expect(emitSpy).toHaveBeenCalled();
107+
});
108+
109+
it('should not emit closeMenu for items with children', () => {
110+
const emitSpy = jest.spyOn(component.closeMenu, 'emit');
111+
const menuItemWithChildren: CustomMenuItem = {
112+
id: 'test-item',
113+
items: [{ id: 'child-item' }],
114+
};
115+
116+
component.goToLink(menuItemWithChildren);
117+
expect(emitSpy).not.toHaveBeenCalled();
118+
});
119+
120+
it('should return false for items without items array', () => {
121+
const menuItem: CustomMenuItem = { id: 'test-item' };
122+
expect(component.hasVisibleChildren(menuItem)).toBe(false);
123+
});
124+
125+
it('should return false for items with empty items array', () => {
126+
const menuItem: CustomMenuItem = { id: 'test-item', items: [] };
127+
expect(component.hasVisibleChildren(menuItem)).toBe(false);
128+
});
129+
130+
it('should return false for items with all invisible children', () => {
131+
const menuItem: CustomMenuItem = {
132+
id: 'test-item',
133+
items: [
134+
{ id: 'child1', visible: false },
135+
{ id: 'child2', visible: false },
136+
],
137+
};
138+
expect(component.hasVisibleChildren(menuItem)).toBe(false);
139+
});
140+
141+
it('should return true for items with at least one visible child', () => {
142+
const menuItem: CustomMenuItem = {
143+
id: 'test-item',
144+
items: [
145+
{ id: 'child1', visible: false },
146+
{ id: 'child2', visible: true },
147+
],
148+
};
149+
expect(component.hasVisibleChildren(menuItem)).toBe(true);
150+
});
151+
152+
it('should return false for items with children that have visible property undefined', () => {
153+
const menuItem: CustomMenuItem = {
154+
id: 'test-item',
155+
items: [{ id: 'child1' }],
156+
};
157+
expect(component.hasVisibleChildren(menuItem)).toBe(false);
158+
});
159+
160+
it('should have mainMenuItems computed property', () => {
161+
expect(component.mainMenuItems).toBeDefined();
162+
expect(typeof component.mainMenuItems).toBe('function');
163+
});
164+
165+
it('should have currentRoute computed property', () => {
166+
expect(component.currentRoute).toBeDefined();
167+
});
168+
169+
it('should have currentResourceId computed property', () => {
170+
expect(component.currentResourceId).toBeDefined();
171+
expect(typeof component.currentResourceId).toBe('function');
172+
});
173+
174+
it('should have isCollectionsRoute computed property', () => {
175+
expect(component.isCollectionsRoute).toBeDefined();
176+
expect(typeof component.isCollectionsRoute).toBe('function');
177+
});
178+
179+
it('should have isPreprintRoute computed property', () => {
180+
expect(component.isPreprintRoute).toBeDefined();
181+
expect(typeof component.isPreprintRoute).toBe('function');
182+
});
183+
184+
it('should emit closeMenu event', () => {
185+
const emitSpy = jest.spyOn(component.closeMenu, 'emit');
186+
187+
component.closeMenu.emit();
188+
189+
expect(emitSpy).toHaveBeenCalled();
190+
});
28191
});

src/app/core/components/osf-banners/services/maintenance.service.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ describe('MaintenanceService', () => {
3838
httpMock = TestBed.inject(HttpTestingController);
3939
});
4040

41-
afterEach(() => {});
41+
afterEach(() => {
42+
httpMock.verify();
43+
});
4244

4345
it('should return maintenance when within window and map severity correctly', (done) => {
4446
service.fetchMaintenanceStatus().subscribe((result) => {
Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,129 @@
1-
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
2-
import { MockComponent, MockPipe, MockProvider } from 'ng-mocks';
1+
import { MockComponent, MockDirective, MockPipe } from 'ng-mocks';
32

43
import { DatePipe } from '@angular/common';
54
import { ComponentRef } from '@angular/core';
65
import { ComponentFixture, TestBed } from '@angular/core/testing';
76

8-
import { TableCellData, TableColumn } from '@osf/features/admin-institutions/models';
7+
import { TableCellLink } from '@osf/features/admin-institutions/models';
98
import { CustomPaginatorComponent } from '@shared/components';
9+
import { StopPropagationDirective } from '@shared/directives';
1010

1111
import { AdminTableComponent } from './admin-table.component';
1212

13+
import { OSFTestingModule } from '@testing/osf.testing.module';
14+
1315
describe('AdminTableComponent', () => {
1416
let component: AdminTableComponent;
1517
let componentRef: ComponentRef<AdminTableComponent>;
1618
let fixture: ComponentFixture<AdminTableComponent>;
17-
const mockColumns: TableColumn[] = [];
18-
const mockData: TableCellData[] = [];
1919

2020
beforeEach(async () => {
2121
await TestBed.configureTestingModule({
2222
imports: [
2323
AdminTableComponent,
2424
MockComponent(CustomPaginatorComponent),
25-
MockPipe(TranslatePipe),
25+
OSFTestingModule,
2626
MockPipe(DatePipe),
27+
MockComponent(CustomPaginatorComponent),
28+
MockDirective(StopPropagationDirective),
2729
],
28-
providers: [MockProvider(TranslateService)],
2930
}).compileComponents();
3031

3132
fixture = TestBed.createComponent(AdminTableComponent);
3233
component = fixture.componentInstance;
3334
componentRef = fixture.componentRef;
3435

35-
componentRef.setInput('tableColumns', mockColumns);
36-
componentRef.setInput('tableData', mockData);
36+
componentRef.setInput('tableColumns', []);
37+
componentRef.setInput('tableData', []);
3738
fixture.detectChanges();
3839
});
3940

4041
it('should create', () => {
4142
expect(component).toBeTruthy();
4243
});
44+
45+
it('should identify TableCellLink objects correctly', () => {
46+
const link: TableCellLink = { text: 'Test', url: '/test' };
47+
const stringValue = 'test string';
48+
const numberValue = 123;
49+
50+
expect(component.isLink(link)).toBe(true);
51+
expect(component.isLink(stringValue)).toBe(false);
52+
expect(component.isLink(numberValue)).toBe(false);
53+
expect(component.isLink(undefined)).toBe(false);
54+
});
55+
56+
it('should identify TableCellLink arrays correctly', () => {
57+
const linkArray: TableCellLink[] = [
58+
{ text: 'Test1', url: '/test1' },
59+
{ text: 'Test2', url: '/test2' },
60+
];
61+
const stringArray = ['test1', 'test2'];
62+
const emptyArray: any[] = [];
63+
64+
expect(component.isLinkArray(linkArray)).toBe(true);
65+
expect(component.isLinkArray(stringArray)).toBe(false);
66+
expect(component.isLinkArray(emptyArray)).toBe(true);
67+
expect(component.isLinkArray(undefined)).toBe(false);
68+
});
69+
70+
it('should get cell value for TableCellLink', () => {
71+
const link: TableCellLink = { text: 'Test Link', url: '/test' };
72+
const result = component.getCellValue(link);
73+
74+
expect(result).toBe('Test Link');
75+
});
76+
77+
it('should compute first link correctly', () => {
78+
const paginationLinks = {
79+
first: { href: '/api/users?page=1' },
80+
prev: { href: '/api/users?page=1' },
81+
next: { href: '/api/users?page=3' },
82+
};
83+
84+
componentRef.setInput('paginationLinks', paginationLinks);
85+
fixture.detectChanges();
86+
87+
expect(component.firstLink()).toBe('/api/users?page=1');
88+
});
89+
90+
it('should compute prev link correctly', () => {
91+
const paginationLinks = {
92+
first: { href: '/api/users?page=1' },
93+
prev: { href: '/api/users?page=1' },
94+
next: { href: '/api/users?page=3' },
95+
};
96+
97+
componentRef.setInput('paginationLinks', paginationLinks);
98+
fixture.detectChanges();
99+
100+
expect(component.prevLink()).toBe('/api/users?page=1');
101+
});
102+
103+
it('should compute next link correctly', () => {
104+
const paginationLinks = {
105+
first: { href: '/api/users?page=1' },
106+
prev: { href: '/api/users?page=1' },
107+
next: { href: '/api/users?page=3' },
108+
};
109+
110+
componentRef.setInput('paginationLinks', paginationLinks);
111+
fixture.detectChanges();
112+
113+
expect(component.nextLink()).toBe('/api/users?page=3');
114+
});
115+
116+
it('should return empty string when pagination links are undefined', () => {
117+
componentRef.setInput('paginationLinks', undefined);
118+
fixture.detectChanges();
119+
120+
expect(component.firstLink()).toBe('');
121+
expect(component.prevLink()).toBe('');
122+
expect(component.nextLink()).toBe('');
123+
});
124+
125+
it('should have download menu items', () => {
126+
expect(component.downloadMenuItems).toBeDefined();
127+
expect(Array.isArray(component.downloadMenuItems)).toBe(true);
128+
});
43129
});

0 commit comments

Comments
 (0)