From 8ba7f32c543e932af7d4ee9b8606d96e0daed4fa Mon Sep 17 00:00:00 2001 From: Matus Kasak Date: Tue, 18 Aug 2026 09:04:27 +0200 Subject: [PATCH 1/2] VSB-TUO/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 | 22 +++++++++++-- src/app/static-page/static-page.component.ts | 32 ++++++++----------- 3 files changed, 52 insertions(+), 22 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 1ad4e607c3c..4a1eed7cac6 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'; @@ -9,12 +11,14 @@ 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 responseService: jasmine.SpyObj; let appConfig: any; const htmlContent = '
TEST MESSAGE
'; @@ -25,6 +29,8 @@ describe('StaticPageComponent', () => { getHmtlContentByPathAndLocale: Promise.resolve(htmlContent) }); + responseService = jasmine.createSpyObj('responseService', ['setNotFound']); + appConfig = Object.assign(environment, { ui: { namespace: 'testNamespace' @@ -34,13 +40,16 @@ describe('StaticPageComponent', () => { TestBed.configureTestingModule({ declarations: [ StaticPageComponent, ClarinSafeHtmlPipe ], imports: [ + CommonModule, TranslateModule.forRoot() ], providers: [ { provide: HtmlContentService, useValue: htmlContentService }, { provide: Router, useValue: new RouterMock() }, + { provide: ServerResponseService, useValue: responseService }, { provide: APP_CONFIG, useValue: appConfig } - ] + ], + schemas: [NO_ERRORS_SCHEMA] }); }); @@ -58,5 +67,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.getHmtlContentByPathAndLocale.and.returnValue(Promise.resolve(undefined)); + 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 bb19403a704..05e6198131b 100644 --- a/src/app/static-page/static-page.component.ts +++ b/src/app/static-page/static-page.component.ts @@ -1,10 +1,11 @@ -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 { BehaviorSubject } from 'rxjs'; import { Router } from '@angular/router'; import { isEmpty, isNotEmpty } from '../shared/empty.util'; -import { STATIC_FILES_DEFAULT_ERROR_PAGE_PATH, STATIC_PAGE_PATH } from './static-page-routing-paths'; +import { 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. @@ -19,9 +20,12 @@ export class StaticPageComponent implements OnInit { static readonly no_static: string = 'no_static_'; htmlContent: BehaviorSubject = new BehaviorSubject(''); htmlFileName: string; + contentState: 'loading' | 'found' | 'not-found' = 'loading'; constructor(private htmlContentService: HtmlContentService, private router: Router, + private responseService: ServerResponseService, + private changeDetector: ChangeDetectorRef, @Inject(APP_CONFIG) protected appConfig?: AppConfig) { } async ngOnInit(): Promise { @@ -31,11 +35,15 @@ export class StaticPageComponent implements OnInit { const htmlContent = await this.htmlContentService.getHmtlContentByPathAndLocale(this.htmlFileName); if (isNotEmpty(htmlContent)) { this.htmlContent.next(htmlContent); + 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(); } /** @@ -119,24 +127,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 b22551c8ec12a5d30b4b2a3b4d538b294a50eaf8 Mon Sep 17 00:00:00 2001 From: Matus Kasak Date: Wed, 19 Aug 2026 11:01:39 +0200 Subject: [PATCH 2/2] VSB-TUO/fix(static-page): address review - a11y attrs on 404 link + typed spy - Add role="link" tabindex="0" to the inline 404 home link so it matches PageNotFoundComponent (same as dtq-dev), per Copilot review. - Type the HtmlContentService test spy as jasmine.SpyObj instead of `any`. Refs dataquest-dev/dspace-customers#566 Co-Authored-By: Claude Opus 4.8 --- src/app/static-page/static-page.component.html | 2 +- src/app/static-page/static-page.component.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/static-page/static-page.component.html b/src/app/static-page/static-page.component.html index 8f33ff3f714..f6fe86f806e 100644 --- a/src/app/static-page/static-page.component.html +++ b/src/app/static-page/static-page.component.html @@ -16,6 +16,6 @@

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

{{"404.help" | translate}}


- {{"404.link.home-page" | 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 4a1eed7cac6..a005ae5177f 100644 --- a/src/app/static-page/static-page.component.spec.ts +++ b/src/app/static-page/static-page.component.spec.ts @@ -17,7 +17,7 @@ describe('StaticPageComponent', () => { let component: StaticPageComponent; let fixture: ComponentFixture; - let htmlContentService: any; + let htmlContentService: jasmine.SpyObj; let responseService: jasmine.SpyObj; let appConfig: any;