diff --git a/packages/phoenix-event-display/src/event-display.ts b/packages/phoenix-event-display/src/event-display.ts index 323942ac..934dd2b5 100644 --- a/packages/phoenix-event-display/src/event-display.ts +++ b/packages/phoenix-event-display/src/event-display.ts @@ -584,18 +584,36 @@ export class EventDisplay { * Add a callback to onDisplayedEventChange array to call * the callback on changes to the displayed event. * @param callback Callback to be added to the onDisplayedEventChange array. + * @returns Unsubscribe function to remove the callback. */ - public listenToDisplayedEventChange(callback: (event: any) => any) { + public listenToDisplayedEventChange( + callback: (event: any) => any, + ): () => void { this.onDisplayedEventChange.push(callback); + return () => { + const index = this.onDisplayedEventChange.indexOf(callback); + if (index > -1) { + this.onDisplayedEventChange.splice(index, 1); + } + }; } /** * Add a callback to onEventsChange array to call * the callback on changes to the events. * @param callback Callback to be added to the onEventsChange array. + * @returns Unsubscribe function to remove the callback. */ - public listenToLoadedEventsChange(callback: (events: any) => any) { + public listenToLoadedEventsChange( + callback: (events: any) => any, + ): () => void { this.onEventsChange.push(callback); + return () => { + const index = this.onEventsChange.indexOf(callback); + if (index > -1) { + this.onEventsChange.splice(index, 1); + } + }; } /** diff --git a/packages/phoenix-event-display/src/helpers/active-variable.ts b/packages/phoenix-event-display/src/helpers/active-variable.ts index 57fcd598..d05351d3 100644 --- a/packages/phoenix-event-display/src/helpers/active-variable.ts +++ b/packages/phoenix-event-display/src/helpers/active-variable.ts @@ -28,8 +28,15 @@ export class ActiveVariable { /** * Call a function on updating the value of variable. * @param callback Callback to call with updated value when the variable is updated. + * @returns Unsubscribe function to remove the callback. */ - public onUpdate(callback: CallbackFunction) { + public onUpdate(callback: CallbackFunction): () => void { this.callbacks.push(callback); + return () => { + const index = this.callbacks.indexOf(callback); + if (index > -1) { + this.callbacks.splice(index, 1); + } + }; } } diff --git a/packages/phoenix-ng/projects/phoenix-app/src/app/sections/playground/playground.component.test.ts b/packages/phoenix-ng/projects/phoenix-app/src/app/sections/playground/playground.component.test.ts index 76136760..8f4c0cd9 100644 --- a/packages/phoenix-ng/projects/phoenix-app/src/app/sections/playground/playground.component.test.ts +++ b/packages/phoenix-ng/projects/phoenix-app/src/app/sections/playground/playground.component.test.ts @@ -24,7 +24,7 @@ describe('PlaygroundComponent', () => { clippingEnabled: jest.fn().mockReturnThis(), startClippingAngle: jest.fn().mockReturnThis(), openingClippingAngle: jest.fn().mockReturnThis(), - listenToLoadedEventsChange: jest.fn(), + listenToLoadedEventsChange: jest.fn(() => jest.fn()), getUIManager: jest.fn().mockReturnThis(), getThreeManager: jest.fn().mockReturnThis(), getPresetViews: jest.fn().mockReturnThis().mockReturnValue([]), @@ -37,9 +37,9 @@ describe('PlaygroundComponent', () => { }; const mockStateManager = mockEventDisplay.getStateManager(); - mockStateManager.clippingEnabled.onUpdate = jest.fn(); - mockStateManager.startClippingAngle.onUpdate = jest.fn(); - mockStateManager.openingClippingAngle.onUpdate = jest.fn(); + mockStateManager.clippingEnabled.onUpdate = jest.fn(() => jest.fn()); + mockStateManager.startClippingAngle.onUpdate = jest.fn(() => jest.fn()); + mockStateManager.openingClippingAngle.onUpdate = jest.fn(() => jest.fn()); beforeEach(() => { TestBed.configureTestingModule({ diff --git a/packages/phoenix-ng/projects/phoenix-app/src/app/sections/trackml/trackml.component.test.ts b/packages/phoenix-ng/projects/phoenix-app/src/app/sections/trackml/trackml.component.test.ts index eccec07a..62f08e4f 100644 --- a/packages/phoenix-ng/projects/phoenix-app/src/app/sections/trackml/trackml.component.test.ts +++ b/packages/phoenix-ng/projects/phoenix-app/src/app/sections/trackml/trackml.component.test.ts @@ -29,7 +29,7 @@ describe('TrackmlComponent', () => { addLoadListenerWithCheck: jest.fn().mockImplementation(() => { component.loaded = true; }), - listenToLoadedEventsChange: jest.fn(), + listenToLoadedEventsChange: jest.fn(() => jest.fn()), getUIManager: jest.fn().mockReturnThis(), getThreeManager: jest.fn().mockReturnThis(), getPresetViews: jest.fn().mockReturnValue([]), @@ -43,9 +43,9 @@ describe('TrackmlComponent', () => { }; const mockStateManager = mockEventDisplay.getStateManager(); - mockStateManager.clippingEnabled.onUpdate = jest.fn(); - mockStateManager.startClippingAngle.onUpdate = jest.fn(); - mockStateManager.openingClippingAngle.onUpdate = jest.fn(); + mockStateManager.clippingEnabled.onUpdate = jest.fn(() => jest.fn()); + mockStateManager.startClippingAngle.onUpdate = jest.fn(() => jest.fn()); + mockStateManager.openingClippingAngle.onUpdate = jest.fn(() => jest.fn()); beforeEach(async () => { await TestBed.configureTestingModule({ diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.test.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.test.ts index 0ab567ea..ad6b90b6 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.test.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.test.ts @@ -10,7 +10,10 @@ describe('CollectionsInfoOverlayComponent', () => { let fixture: ComponentFixture; const mockEventDisplay = { - listenToDisplayedEventChange: jest.fn((callback) => callback()), + listenToDisplayedEventChange: jest.fn((callback) => { + callback(); + return jest.fn(); + }), getCollections: jest.fn().mockReturnValue({ Hits: ['hitsCollection1', 'hitsCollection2'], Tracks: ['trackCollection1'], @@ -18,6 +21,7 @@ describe('CollectionsInfoOverlayComponent', () => { getActiveObjectId: () => ({ onUpdate: (callback) => { callback(); + return jest.fn(); }, }), enableHighlighting: jest.fn(), @@ -55,7 +59,7 @@ describe('CollectionsInfoOverlayComponent', () => { component.activeObject = { value: '', update: jest.fn(), - onUpdate: jest.fn(), + onUpdate: jest.fn(() => jest.fn()), } as any; }); diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.ts index 5c3c2325..7469682d 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/collections-info/collections-info-overlay/collections-info-overlay.component.ts @@ -1,4 +1,10 @@ -import { Component, ElementRef, Input, type OnInit } from '@angular/core'; +import { + Component, + ElementRef, + Input, + type OnInit, + type OnDestroy, +} from '@angular/core'; import { ActiveVariable, PrettySymbols, @@ -12,7 +18,7 @@ import { EventDisplayService } from '../../../../services/event-display.service' templateUrl: './collections-info-overlay.component.html', styleUrls: ['./collections-info-overlay.component.scss'], }) -export class CollectionsInfoOverlayComponent implements OnInit { +export class CollectionsInfoOverlayComponent implements OnInit, OnDestroy { @Input() showObjectsInfo: boolean; hideInvisible: boolean; collections: { type: string; collections: string[] }[]; @@ -21,6 +27,7 @@ export class CollectionsInfoOverlayComponent implements OnInit { collectionColumns: string[]; getPrettySymbol = PrettySymbols.getPrettySymbol; activeObject: ActiveVariable; + private unsubscribes: (() => void)[] = []; constructor( private elementRef: ElementRef, @@ -28,23 +35,31 @@ export class CollectionsInfoOverlayComponent implements OnInit { ) {} ngOnInit() { - this.eventDisplay.listenToDisplayedEventChange(() => { - const collectionsGrouped: { [key: string]: string[] } = - this.eventDisplay.getCollections(); - this.collections = Object.entries(collectionsGrouped).map( - ([type, collections]: [string, string[]]) => ({ - type, - collections, - }), - ); - }); + this.unsubscribes.push( + this.eventDisplay.listenToDisplayedEventChange(() => { + const collectionsGrouped: { [key: string]: string[] } = + this.eventDisplay.getCollections(); + this.collections = Object.entries(collectionsGrouped).map( + ([type, collections]: [string, string[]]) => ({ + type, + collections, + }), + ); + }), + ); this.activeObject = this.eventDisplay.getActiveObjectId(); - this.activeObject.onUpdate((value: string) => { - if (document.getElementById(value)) { - document.getElementById(value).scrollIntoView(false); - } - }); + this.unsubscribes.push( + this.activeObject.onUpdate((value: string) => { + if (document.getElementById(value)) { + document.getElementById(value).scrollIntoView(false); + } + }), + ); + } + + ngOnDestroy() { + this.unsubscribes.forEach((unsubscribe) => unsubscribe?.()); } changeCollection(selectedCollection: string) { diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.test.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.test.ts index ef376c8f..77cc9aa1 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.test.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.test.ts @@ -9,9 +9,10 @@ describe('CycleEventsComponent', () => { let fixture: ComponentFixture; const mockEventDisplay = { - listenToLoadedEventsChange: jest.fn((callback) => - callback(['eventKey1', 'eventKey2']), - ), + listenToLoadedEventsChange: jest.fn((callback) => { + callback(['eventKey1', 'eventKey2']); + return jest.fn(); + }), loadEvent: jest.fn(), }; diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.ts index 56fbb10d..5067a51c 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/cycle-events/cycle-events.component.ts @@ -25,6 +25,7 @@ export class CycleEventsComponent implements OnInit, OnDestroy { private events: string[]; private eventsChangeCallback: (events: string[]) => void; + private unsubscribe: () => void; constructor( private eventDisplay: EventDisplayService, @@ -40,7 +41,9 @@ export class CycleEventsComponent implements OnInit, OnDestroy { this.startCycleInterval(); } }; - this.eventDisplay.listenToLoadedEventsChange(this.eventsChangeCallback); + this.unsubscribe = this.eventDisplay.listenToLoadedEventsChange( + this.eventsChangeCallback, + ); } ngOnDestroy(): void { @@ -49,6 +52,8 @@ export class CycleEventsComponent implements OnInit, OnDestroy { clearInterval(this.intervalId); this.intervalId = null; } + // Unsubscribe from events change listener + this.unsubscribe?.(); } toggleCycle() { diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-selector/event-selector.component.test.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-selector/event-selector.component.test.ts index 4ebd7c4a..d5b89d29 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-selector/event-selector.component.test.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-selector/event-selector.component.test.ts @@ -9,7 +9,7 @@ describe('EventSelectorComponent', () => { let fixture: ComponentFixture; const mockEventDisplayService = { - listenToLoadedEventsChange: jest.fn(), + listenToLoadedEventsChange: jest.fn(() => jest.fn()), loadEvent: jest.fn(), }; diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-selector/event-selector.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-selector/event-selector.component.ts index 2922397d..b2598a3a 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-selector/event-selector.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/event-selector/event-selector.component.ts @@ -10,6 +10,7 @@ import { EventDisplayService } from '../../../services/event-display.service'; export class EventSelectorComponent implements OnInit, OnDestroy { // Array containing the keys of the multiple loaded events events: string[]; + private unsubscribe: () => void; /** Prevents callbacks on destroyed component */ private isDestroyed = false; @@ -17,15 +18,18 @@ export class EventSelectorComponent implements OnInit, OnDestroy { constructor(private eventDisplay: EventDisplayService) {} ngOnInit() { - this.eventDisplay.listenToLoadedEventsChange((events) => { - if (!this.isDestroyed) { - this.events = events; - } - }); + this.unsubscribe = this.eventDisplay.listenToLoadedEventsChange( + (events) => { + if (!this.isDestroyed) { + this.events = events; + } + }, + ); } ngOnDestroy() { this.isDestroyed = true; + this.unsubscribe?.(); } changeEvent(selected: any) { diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/experiment-info/experiment-info.component.test.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/experiment-info/experiment-info.component.test.ts index ccdae7b9..9ca942da 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/experiment-info/experiment-info.component.test.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/experiment-info/experiment-info.component.test.ts @@ -10,7 +10,7 @@ describe('ExperimentInfoComponent', () => { const mockEventDisplayService = { getEventMetadata: jest.fn(), - listenToDisplayedEventChange: jest.fn(), + listenToDisplayedEventChange: jest.fn(() => jest.fn()), }; beforeEach(() => { diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/experiment-info/experiment-info.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/experiment-info/experiment-info.component.ts index 9b4f8da1..41d51d28 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/experiment-info/experiment-info.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/experiment-info/experiment-info.component.ts @@ -1,4 +1,4 @@ -import { Component, type OnInit, Input } from '@angular/core'; +import { Component, type OnInit, type OnDestroy, Input } from '@angular/core'; import { EventDisplayService } from '../../../services/event-display.service'; @Component({ @@ -7,17 +7,22 @@ import { EventDisplayService } from '../../../services/event-display.service'; templateUrl: './experiment-info.component.html', styleUrls: ['./experiment-info.component.scss'], }) -export class ExperimentInfoComponent implements OnInit { +export class ExperimentInfoComponent implements OnInit, OnDestroy { experimentInfo: any[]; @Input() url: string; @Input() logo: string; @Input() tagline: string; + private unsubscribe: () => void; constructor(private eventDisplay: EventDisplayService) {} ngOnInit(): void { - this.eventDisplay.listenToDisplayedEventChange(() => { + this.unsubscribe = this.eventDisplay.listenToDisplayedEventChange(() => { this.experimentInfo = this.eventDisplay.getEventMetadata(); }); } + + ngOnDestroy(): void { + this.unsubscribe?.(); + } } diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.ts index 6b202bed..abc743a5 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/geometry-browser/geometry-browser-overlay/geometry-browser-overlay.component.ts @@ -1,4 +1,4 @@ -import { Component, type OnInit, Input } from '@angular/core'; +import { Component, type OnInit, type OnDestroy, Input } from '@angular/core'; import { ActiveVariable } from 'phoenix-event-display'; import { EventDisplayService } from '../../../../services/event-display.service'; import { Object3D, type Object3DEventMap } from 'three'; @@ -9,12 +9,13 @@ import { Object3D, type Object3DEventMap } from 'three'; templateUrl: './geometry-browser-overlay.component.html', styleUrls: ['./geometry-browser-overlay.component.scss'], }) -export class GeometryBrowserOverlayComponent implements OnInit { +export class GeometryBrowserOverlayComponent implements OnInit, OnDestroy { @Input() browseDetectorParts: boolean; selectedCollection: string; showingCollection: any; activeObject: ActiveVariable; children: Object3D[]; + private unsubscribe: () => void; constructor(private eventDisplay: EventDisplayService) {} @@ -25,13 +26,17 @@ export class GeometryBrowserOverlayComponent implements OnInit { .getGeometries().children; this.activeObject = this.eventDisplay.getActiveObjectId(); - this.activeObject.onUpdate((value: string) => { + this.unsubscribe = this.activeObject.onUpdate((value: string) => { if (document.getElementById(value)) { document.getElementById(value).scrollIntoView(false); } }); } + ngOnDestroy() { + this.unsubscribe?.(); + } + changeCollection(selectedCollection: string) { this.selectedCollection = selectedCollection; for (const child of this.children) { diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/object-clipping/object-clipping.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/object-clipping/object-clipping.component.ts index 80fb4959..383812f0 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/object-clipping/object-clipping.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/object-clipping/object-clipping.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, type OnInit, type OnDestroy } from '@angular/core'; import { MatCheckboxChange } from '@angular/material/checkbox'; import { EventDisplayService } from '../../../services/event-display.service'; @@ -8,24 +8,37 @@ import { EventDisplayService } from '../../../services/event-display.service'; templateUrl: './object-clipping.component.html', styleUrls: ['./object-clipping.component.scss'], }) -export class ObjectClippingComponent { +export class ObjectClippingComponent implements OnInit, OnDestroy { clippingEnabled: boolean; startClippingAngle: number; openingClippingAngle: number; + private unsubscribes: (() => void)[] = []; - constructor(private eventDisplay: EventDisplayService) { + constructor(private eventDisplay: EventDisplayService) {} + + ngOnInit() { const stateManager = this.eventDisplay.getStateManager(); - stateManager.clippingEnabled.onUpdate( - (clippingValue) => (this.clippingEnabled = clippingValue), + this.unsubscribes.push( + stateManager.clippingEnabled.onUpdate( + (clippingValue) => (this.clippingEnabled = clippingValue), + ), ); - stateManager.startClippingAngle.onUpdate( - (value) => (this.startClippingAngle = value), + this.unsubscribes.push( + stateManager.startClippingAngle.onUpdate( + (value) => (this.startClippingAngle = value), + ), ); - stateManager.openingClippingAngle.onUpdate( - (value) => (this.openingClippingAngle = value), + this.unsubscribes.push( + stateManager.openingClippingAngle.onUpdate( + (value) => (this.openingClippingAngle = value), + ), ); } + ngOnDestroy() { + this.unsubscribes.forEach((unsubscribe) => unsubscribe?.()); + } + changeStartClippingAngle(startingAngle: number) { this.eventDisplay.getUIManager().rotateStartAngleClipping(startingAngle); } diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/share-link/share-link-dialog/share-link-dialog.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/share-link/share-link-dialog/share-link-dialog.component.ts index f7ab000b..443b1eba 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/share-link/share-link-dialog/share-link-dialog.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/share-link/share-link-dialog/share-link-dialog.component.ts @@ -2,6 +2,7 @@ import { type AfterViewInit, Component, ElementRef, + type OnDestroy, ViewChild, } from '@angular/core'; import { MatDialogRef } from '@angular/material/dialog'; @@ -14,12 +15,13 @@ import QRCode from 'qrcode'; templateUrl: './share-link-dialog.component.html', styleUrls: ['./share-link-dialog.component.scss'], }) -export class ShareLinkDialogComponent implements AfterViewInit { +export class ShareLinkDialogComponent implements AfterViewInit, OnDestroy { baseLink: string; shareLink: ActiveVariable; embedLink: string; urlOptions = Object.assign({}, phoenixURLOptions); @ViewChild('qrcodeCanvas') qrcodeCanvas: ElementRef; + private unsubscribe: () => void; constructor(private dialogRef: MatDialogRef) { const locationHref = window.location.href; @@ -35,7 +37,11 @@ export class ShareLinkDialogComponent implements AfterViewInit { ngAfterViewInit() { this.updateQRCode(this.shareLink.value); - this.shareLink.onUpdate(this.updateQRCode.bind(this)); + this.unsubscribe = this.shareLink.onUpdate(this.updateQRCode.bind(this)); + } + + ngOnDestroy() { + this.unsubscribe?.(); } onClose() { diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/ui-menu.component.test.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/ui-menu.component.test.ts index 4bd59242..7f401580 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/ui-menu.component.test.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/ui-menu.component.test.ts @@ -23,7 +23,7 @@ describe('UiMenuComponent', () => { clippingEnabled: jest.fn().mockReturnThis(), startClippingAngle: jest.fn().mockReturnThis(), openingClippingAngle: jest.fn().mockReturnThis(), - listenToLoadedEventsChange: jest.fn(), + listenToLoadedEventsChange: jest.fn(() => jest.fn()), getUIManager: jest.fn().mockReturnThis(), getThreeManager: jest.fn().mockReturnThis(), getPresetViews: jest.fn().mockReturnThis().mockReturnValue([]), @@ -37,9 +37,9 @@ describe('UiMenuComponent', () => { }; const mockStateManager = mockEventDisplay.getStateManager(); - mockStateManager.clippingEnabled.onUpdate = jest.fn(); - mockStateManager.startClippingAngle.onUpdate = jest.fn(); - mockStateManager.openingClippingAngle.onUpdate = jest.fn(); + mockStateManager.clippingEnabled.onUpdate = jest.fn(() => jest.fn()); + mockStateManager.startClippingAngle.onUpdate = jest.fn(() => jest.fn()); + mockStateManager.openingClippingAngle.onUpdate = jest.fn(() => jest.fn()); beforeEach(() => { TestBed.configureTestingModule({