diff --git a/jest.config.js b/jest.config.js index ad155721d..4d2d69fcc 100644 --- a/jest.config.js +++ b/jest.config.js @@ -54,10 +54,10 @@ module.exports = { extensionsToTreatAsEsm: ['.ts'], coverageThreshold: { global: { - branches: 39.5, - functions: 41.1, - lines: 68.0, - statements: 68.4, + branches: 43.3, + functions: 42.7, + lines: 69.3, + statements: 69.8, }, }, watchPathIgnorePatterns: [ diff --git a/src/app/features/preprints/components/advisory-board/advisory-board.component.spec.ts b/src/app/features/preprints/components/advisory-board/advisory-board.component.spec.ts index 588caf723..8119d7b99 100644 --- a/src/app/features/preprints/components/advisory-board/advisory-board.component.spec.ts +++ b/src/app/features/preprints/components/advisory-board/advisory-board.component.spec.ts @@ -9,84 +9,54 @@ describe('AdvisoryBoardComponent', () => { const mockHtmlContent = '
This is advisory board content.
Footer
'); fixture.detectChanges(); - expect(component).toBeTruthy(); + const section = fixture.nativeElement.querySelector('section'); + expect(section).not.toBeNull(); + expect(section.innerHTML).toContain('Footer'); }); - it('should not render section when footerHtml is null', () => { - fixture.componentRef.setInput('footerHtml', null); + it.each([null, undefined, ''])('should not render section when footerHtml is %p', (value) => { + fixture.componentRef.setInput('footerHtml', value); fixture.detectChanges(); - const compiled = fixture.nativeElement; - const section = compiled.querySelector('section'); - - expect(section).toBeNull(); - }); - - it('should not render section when footerHtml is undefined', () => { - fixture.componentRef.setInput('footerHtml', undefined); - fixture.detectChanges(); - - const compiled = fixture.nativeElement; - const section = compiled.querySelector('section'); - - expect(section).toBeNull(); - }); - - it('should not render section when footerHtml is empty string', () => { - fixture.componentRef.setInput('footerHtml', ''); - fixture.detectChanges(); - - const compiled = fixture.nativeElement; - const section = compiled.querySelector('section'); - - expect(section).toBeNull(); + expect(fixture.nativeElement.querySelector('section')).toBeNull(); }); }); diff --git a/src/app/features/preprints/components/preprint-provider-footer/preprint-provider-footer.component.ts b/src/app/features/preprints/components/preprint-provider-footer/preprint-provider-footer.component.ts index 6b7e2fa65..da4d77af4 100644 --- a/src/app/features/preprints/components/preprint-provider-footer/preprint-provider-footer.component.ts +++ b/src/app/features/preprints/components/preprint-provider-footer/preprint-provider-footer.component.ts @@ -11,5 +11,5 @@ import { SafeHtmlPipe } from '@osf/shared/pipes/safe-html.pipe'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class PreprintProviderFooterComponent { - footerHtml = input.requiredOpen preprints for all disciplines
'); + expect(query('.preprint-provider-name')?.textContent).toBe('OSF Preprints'); + expect((query('img') as HTMLImageElement).getAttribute('src')).toBe('https://osf.io/assets/hero-logo.png'); + expect(query('.provider-description div')?.innerHTML).toContain('Open preprints for all disciplines
'); }); - it('should display add preprint button when allowSubmissions is true', () => { - fixture.componentRef.setInput('searchControl', new FormControl('')); - fixture.componentRef.setInput('preprintProvider', mockPreprintProvider); - fixture.componentRef.setInput('isPreprintProviderLoading', false); - fixture.detectChanges(); - - const compiled = fixture.nativeElement; - const addButton = compiled.querySelector('p-button'); + it('should hide provider-dependent content when provider is undefined and not loading', () => { + setup({ preprintProvider: undefined, isPreprintProviderLoading: false }); - expect(addButton).toBeTruthy(); - expect(addButton?.getAttribute('ng-reflect-label')).toBe('Preprints.addpreprint'); - expect(addButton?.getAttribute('ng-reflect-router-link')).toBe('/preprints,osf-preprints,submi'); + expect(query('.preprint-provider-name')).toBeNull(); + expect(query('img')).toBeNull(); }); - it('should display search input when not loading', () => { - fixture.componentRef.setInput('searchControl', new FormControl('')); - fixture.componentRef.setInput('preprintProvider', mockPreprintProvider); - fixture.componentRef.setInput('isPreprintProviderLoading', false); - fixture.detectChanges(); + it('should emit normalized search value', () => { + setup(); + jest.spyOn(component.triggerSearch, 'emit'); - const compiled = fixture.nativeElement; - const searchInput = compiled.querySelector('osf-search-input'); + component.onTriggerSearch('test “quoted” value'); - expect(searchInput).toBeTruthy(); - expect(searchInput?.getAttribute('ng-reflect-show-help-icon')).toBe('true'); - expect(searchInput?.getAttribute('ng-reflect-placeholder')).toBe('Preprints.searchplaceholder'); + expect(component.triggerSearch.emit).toHaveBeenCalledWith('test "quoted" value'); }); - it('should emit triggerSearch when onTriggerSearch is called', () => { - fixture.componentRef.setInput('searchControl', new FormControl('')); - fixture.componentRef.setInput('preprintProvider', mockPreprintProvider); - fixture.componentRef.setInput('isPreprintProviderLoading', false); - fixture.detectChanges(); - + it('should emit empty string when search value is missing', () => { + setup(); jest.spyOn(component.triggerSearch, 'emit'); - const searchValue = 'test search query'; - component.onTriggerSearch(searchValue); + component.onTriggerSearch(undefined as unknown as string); - expect(component.triggerSearch.emit).toHaveBeenCalledWith(searchValue); + expect(component.triggerSearch.emit).toHaveBeenCalledWith(''); }); - it('should open help dialog when openHelpDialog is called', () => { - fixture.componentRef.setInput('searchControl', new FormControl('')); - fixture.componentRef.setInput('preprintProvider', mockPreprintProvider); - fixture.componentRef.setInput('isPreprintProviderLoading', false); - fixture.detectChanges(); - - expect(mockDialogService.open).toBeDefined(); - expect(typeof mockDialogService.open).toBe('function'); + it('should open help dialog with expected header', () => { + setup(); component.openHelpDialog(); - expect(mockDialogService.open).toHaveBeenCalledWith(expect.any(Function), { - focusOnShow: false, + expect(customDialogMock.open).toHaveBeenCalledWith(PreprintsHelpDialogComponent, { header: 'preprints.helpDialog.header', - closeOnEscape: true, - modal: true, - closable: true, - breakpoints: { '768px': '95vw' }, }); }); - - it('should update when input properties change', () => { - fixture.componentRef.setInput('searchControl', new FormControl('')); - fixture.componentRef.setInput('preprintProvider', undefined); - fixture.componentRef.setInput('isPreprintProviderLoading', true); - fixture.detectChanges(); - - let compiled = fixture.nativeElement; - expect(compiled.querySelectorAll('p-skeleton').length).toBeGreaterThan(0); - expect(compiled.querySelector('.preprint-provider-name')).toBeNull(); - - fixture.componentRef.setInput('preprintProvider', mockPreprintProvider); - fixture.componentRef.setInput('isPreprintProviderLoading', false); - fixture.detectChanges(); - - compiled = fixture.nativeElement; - expect(compiled.querySelectorAll('p-skeleton').length).toBe(0); - expect(compiled.querySelector('.preprint-provider-name')).toBeTruthy(); - expect(compiled.querySelector('.preprint-provider-name')?.textContent).toBe('OSF Preprints'); - }); }); diff --git a/src/app/features/preprints/components/preprint-provider-hero/preprint-provider-hero.component.ts b/src/app/features/preprints/components/preprint-provider-hero/preprint-provider-hero.component.ts index 826d17eca..2fa2bc2aa 100644 --- a/src/app/features/preprints/components/preprint-provider-hero/preprint-provider-hero.component.ts +++ b/src/app/features/preprints/components/preprint-provider-hero/preprint-provider-hero.component.ts @@ -18,24 +18,24 @@ import { PreprintsHelpDialogComponent } from '../preprints-help-dialog/preprints @Component({ selector: 'osf-preprint-provider-hero', - imports: [Button, RouterLink, SearchInputComponent, Skeleton, TranslatePipe, TitleCasePipe, SafeHtmlPipe], + imports: [Button, Skeleton, RouterLink, SearchInputComponent, SafeHtmlPipe, TitleCasePipe, TranslatePipe], templateUrl: './preprint-provider-hero.component.html', styleUrl: './preprint-provider-hero.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) export class PreprintProviderHeroComponent { - customDialogService = inject(CustomDialogService); + private readonly customDialogService = inject(CustomDialogService); - searchControl = input{{ 'preprints.helpDialog.message' | translate }} - {{ 'preprints.helpDialog.linkText' | translate }}. + {{ 'preprints.helpDialog.linkText' | translate }}.