From 255cd3bc0df67cffd2d42e2710b906881ae7147e Mon Sep 17 00:00:00 2001 From: Matus Kasak Date: Tue, 18 Aug 2026 09:12:26 +0200 Subject: [PATCH 1/2] ZCU-DATA/fix(static-page): return HTTP 404 for missing static pages StaticPageComponent rendered an empty shell and answered HTTP 200 when a `/static/` page did not exist: it tried to load `static-files/error.html` and, when that was empty/missing, showed nothing and never set a 404 status. UNIVERSAL-016 (dspace-ui-tests notFoundPage.spec.ts) therefore failed on the "non-existent static page shows 404 page" case. Set the SSR response to 404 via ServerResponseService and render the inline 404 page (same markup + reused `404.*` i18n keys as PageNotFoundComponent) when the content is not found. Drop the legacy error.html loading path. Behaviour now matches dtq-dev: /static/ returns 404 with the "404 / Take me to the home page" page. Refs dataquest-dev/dspace-customers#566 Co-Authored-By: Claude Opus 4.8 --- .../static-page/static-page.component.html | 20 +++++++++++- .../static-page/static-page.component.spec.ts | 21 +++++++++++-- src/app/static-page/static-page.component.ts | 31 ++++++++----------- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/app/static-page/static-page.component.html b/src/app/static-page/static-page.component.html index 99b85f71fb9..8f33ff3f714 100644 --- a/src/app/static-page/static-page.component.html +++ b/src/app/static-page/static-page.component.html @@ -1,3 +1,21 @@ -
+ +
+ +
+ + +
+ + +
+

404

+

{{"404.page-not-found" | translate}}

+
+

{{"404.help" | translate}}

+
+

+ {{"404.link.home-page" | translate}} +

+
diff --git a/src/app/static-page/static-page.component.spec.ts b/src/app/static-page/static-page.component.spec.ts index 153675f146c..c0ecab1202e 100644 --- a/src/app/static-page/static-page.component.spec.ts +++ b/src/app/static-page/static-page.component.spec.ts @@ -1,4 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { CommonModule } from '@angular/common'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { StaticPageComponent } from './static-page.component'; import { HtmlContentService } from '../shared/html-content.service'; @@ -10,13 +12,15 @@ import { of } from 'rxjs'; import { APP_CONFIG } from '../../config/app-config.interface'; import { environment } from '../../environments/environment'; import { ClarinSafeHtmlPipe } from '../shared/utils/clarin-safehtml.pipe'; +import { ServerResponseService } from '../core/services/server-response.service'; describe('StaticPageComponent', () => { let component: StaticPageComponent; let fixture: ComponentFixture; - let htmlContentService: HtmlContentService; + let htmlContentService: any; let localeService: any; + let responseService: jasmine.SpyObj; let appConfig: any; beforeEach(async () => { @@ -26,6 +30,7 @@ describe('StaticPageComponent', () => { localeService = jasmine.createSpyObj('LocaleService', { getCurrentLanguageCode: jasmine.createSpy('getCurrentLanguageCode'), }); + responseService = jasmine.createSpyObj('responseService', ['setNotFound']); // Do not mutate the shared `environment` object - replacing `environment.ui` would // break any later spec that reads e.g. environment.ui.nameSpace @@ -38,14 +43,17 @@ describe('StaticPageComponent', () => { TestBed.configureTestingModule({ declarations: [ StaticPageComponent, ClarinSafeHtmlPipe ], imports: [ + CommonModule, TranslateModule.forRoot() ], providers: [ { provide: HtmlContentService, useValue: htmlContentService }, { provide: Router, useValue: new RouterMock() }, { provide: LocaleService, useValue: localeService }, + { provide: ServerResponseService, useValue: responseService }, { provide: APP_CONFIG, useValue: appConfig } - ] + ], + schemas: [NO_ERRORS_SCHEMA] }); localeService = TestBed.inject(LocaleService); @@ -65,5 +73,14 @@ describe('StaticPageComponent', () => { it('should load html file content', async () => { await component.ngOnInit(); expect(component.htmlContent.value).toBe('
TEST MESSAGE
'); + expect(component.contentState).toBe('found'); + }); + + // When the file is missing, set a 404 status for SSR and switch to the not-found state + it('should set 404 status when content is not found', async () => { + htmlContentService.fetchHtmlContent.and.returnValue(of('')); + await component.ngOnInit(); + expect(responseService.setNotFound).toHaveBeenCalled(); + expect(component.contentState).toBe('not-found'); }); }); diff --git a/src/app/static-page/static-page.component.ts b/src/app/static-page/static-page.component.ts index c44d5fb6ebd..8710fdb3110 100644 --- a/src/app/static-page/static-page.component.ts +++ b/src/app/static-page/static-page.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core'; import { HtmlContentService } from '../shared/html-content.service'; import { BehaviorSubject, firstValueFrom } from 'rxjs'; import { Router } from '@angular/router'; @@ -6,10 +6,10 @@ import { isEmpty, isNotEmpty } from '../shared/empty.util'; import { LocaleService } from '../core/locale/locale.service'; import { HTML_SUFFIX, - STATIC_FILES_DEFAULT_ERROR_PAGE_PATH, STATIC_FILES_PROJECT_PATH, STATIC_PAGE_PATH } from './static-page-routing-paths'; import { APP_CONFIG, AppConfig } from '../../config/app-config.interface'; +import { ServerResponseService } from '../core/services/server-response.service'; /** * Component which load and show static files from the `static-files` folder. @@ -23,10 +23,13 @@ import { APP_CONFIG, AppConfig } from '../../config/app-config.interface'; export class StaticPageComponent implements OnInit { htmlContent: BehaviorSubject = new BehaviorSubject(''); htmlFileName: string; + contentState: 'loading' | 'found' | 'not-found' = 'loading'; constructor(private htmlContentService: HtmlContentService, private router: Router, private localeService: LocaleService, + private responseService: ServerResponseService, + private changeDetector: ChangeDetectorRef, @Inject(APP_CONFIG) protected appConfig?: AppConfig) { } async ngOnInit(): Promise { @@ -48,6 +51,8 @@ export class StaticPageComponent implements OnInit { let potentialContent = await firstValueFrom(this.htmlContentService.fetchHtmlContent(url)); if (isNotEmpty(potentialContent)) { this.htmlContent.next(potentialContent); + this.contentState = 'found'; + this.changeDetector.detectChanges(); return; } @@ -56,11 +61,15 @@ export class StaticPageComponent implements OnInit { potentialContent = await firstValueFrom(this.htmlContentService.fetchHtmlContent(url)); if (isNotEmpty(potentialContent)) { this.htmlContent.next(potentialContent); + this.contentState = 'found'; + this.changeDetector.detectChanges(); return; } - // Show error page - await this.loadErrorPage(); + // Content not found - set 404 status for SSR and show the inline 404 page + this.responseService.setNotFound(); + this.contentState = 'not-found'; + this.changeDetector.detectChanges(); } /** @@ -139,24 +148,10 @@ export class StaticPageComponent implements OnInit { urlInList = urlInList.filter(n => n); // if length is 1 - html file name wasn't defined. if (isEmpty(urlInList) || urlInList.length === 1) { - void this.loadErrorPage(); return null; } // If the url is too long take just the first string after `/static` prefix. return urlInList[1]?.split('#')?.[0]; } - - /** - * Load `static-files/error.html` - * @private - */ - private async loadErrorPage() { - let errorPage = await firstValueFrom(this.htmlContentService.fetchHtmlContent(STATIC_FILES_DEFAULT_ERROR_PAGE_PATH)); - if (isEmpty(errorPage)) { - console.error('Cannot load error page from the path: ' + STATIC_FILES_DEFAULT_ERROR_PAGE_PATH); - return; - } - this.htmlContent.next(errorPage); - } } From 18bae226c5e18c984b66f23f1aadb1e2a71c6e2f Mon Sep 17 00:00:00 2001 From: Matus Kasak Date: Wed, 19 Aug 2026 11:01:46 +0200 Subject: [PATCH 2/2] ZCU-DATA/test(static-page): type HtmlContentService spy (review nit) Use jasmine.SpyObj instead of `any` for the test spy, per Copilot review. Refs dataquest-dev/dspace-customers#566 Co-Authored-By: Claude Opus 4.8 --- src/app/static-page/static-page.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/static-page/static-page.component.spec.ts b/src/app/static-page/static-page.component.spec.ts index c0ecab1202e..0d3df7afec0 100644 --- a/src/app/static-page/static-page.component.spec.ts +++ b/src/app/static-page/static-page.component.spec.ts @@ -18,7 +18,7 @@ describe('StaticPageComponent', () => { let component: StaticPageComponent; let fixture: ComponentFixture; - let htmlContentService: any; + let htmlContentService: jasmine.SpyObj; let localeService: any; let responseService: jasmine.SpyObj; let appConfig: any;