diff --git a/src/app/item-page/clarin-ref-citation/clarin-ref-citation.component.spec.ts b/src/app/item-page/clarin-ref-citation/clarin-ref-citation.component.spec.ts new file mode 100644 index 00000000000..9be03b198f6 --- /dev/null +++ b/src/app/item-page/clarin-ref-citation/clarin-ref-citation.component.spec.ts @@ -0,0 +1,56 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; +import { of as observableOf } from 'rxjs'; +import { ClarinRefCitationComponent } from './clarin-ref-citation.component'; +import { ConfigurationDataService } from '../../core/data/configuration-data.service'; +import { RequestService } from '../../core/data/request.service'; +import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service'; +import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; +import { Item } from '../../core/shared/item.model'; +import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils'; + +describe('ClarinRefCitationComponent', () => { + const handleUrl = 'https://hdl.handle.net/123456789/1'; + const displayText = 'Doe, 2024, Title, ' + + 'bad link, ' + handleUrl + '.' + + ''; + + let fixture: ComponentFixture; + let citation: HTMLElement; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ClarinRefCitationComponent], + imports: [TranslateModule.forRoot(), NgbTooltipModule], + providers: [ + { provide: ConfigurationDataService, useValue: {} }, + { provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['generateRequestId', 'send']) }, + { provide: HALEndpointService, useValue: { getRootHref: () => 'https://rest.test/server/api' } }, + { + provide: RemoteDataBuildService, useValue: jasmine.createSpyObj('rdbService', { + buildFromRequestUUID: observableOf(createSuccessfulRemoteDataObject({ displayText })), + }) + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(ClarinRefCitationComponent); + fixture.componentInstance.item = Object.assign(new Item(), { handle: '123456789/1', metadata: {} }); + fixture.detectChanges(); + await fixture.whenStable(); + fixture.detectChanges(); + citation = fixture.nativeElement.querySelector('.clarin-ref-box-text'); + }); + + it('should not render scripts or event handlers from the display text', () => { + expect(citation.querySelector('script')).toBeNull(); + expect(citation.querySelector('[onerror]')).toBeNull(); + expect(citation.querySelector('a[href^="javascript:"]')).toBeNull(); + }); + + it('should keep the citation formatting', () => { + expect(citation.querySelector('i').textContent).toBe('Title'); + expect(citation.querySelector('a[href="' + handleUrl + '"]').textContent).toBe(handleUrl); + }); +}); diff --git a/src/app/item-page/clarin-ref-citation/clarin-ref-citation.component.ts b/src/app/item-page/clarin-ref-citation/clarin-ref-citation.component.ts index 94980315738..b014bf8bedb 100644 --- a/src/app/item-page/clarin-ref-citation/clarin-ref-citation.component.ts +++ b/src/app/item-page/clarin-ref-citation/clarin-ref-citation.component.ts @@ -10,7 +10,6 @@ import { RequestService } from '../../core/data/request.service'; import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service'; import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; import { BehaviorSubject } from 'rxjs'; -import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; /** @@ -42,9 +41,9 @@ export class ClarinRefCitationComponent implements OnInit { /** * The content of the reference box, which will be displayed in the tooltip. - * This content is fetched from the RefBox Controller. + * This content is fetched from the RefBox Controller and sanitized by Angular when rendered. */ - refboxContent: BehaviorSubject = new BehaviorSubject(null); + refboxContent: BehaviorSubject = new BehaviorSubject(null); /** * The raw content of the reference box, which is fetched from the RefBox Controller. @@ -62,8 +61,7 @@ export class ClarinRefCitationComponent implements OnInit { private modalService: NgbModal, private requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected halService: HALEndpointService, - private sanitizer: DomSanitizer) { + protected halService: HALEndpointService) { // Configure the tooltip to show on click - `Copied` message config.triggers = 'click'; } @@ -72,7 +70,7 @@ export class ClarinRefCitationComponent implements OnInit { void this.fetchRefBoxContent() .then((content) => { this.refboxCopyContent = content; // Store raw HTML - this.refboxContent.next(this.sanitizer.bypassSecurityTrustHtml(content)); + this.refboxContent.next(content); }).catch((error) => { console.error('Failed to fetch refbox content:', error); this.refboxCopyContent = this.EMPTY_CONTENT;