diff --git a/src/app/footer/footer.component.ts b/src/app/footer/footer.component.ts index c691203c02..2665a13e66 100644 --- a/src/app/footer/footer.component.ts +++ b/src/app/footer/footer.component.ts @@ -60,7 +60,7 @@ export class FooterComponent implements OnInit { } showCookieSettings() { - if (hasValue(this.cookies)) { + if (hasValue(this.cookies) && this.cookies.showSettings instanceof Function) { this.cookies.showSettings(); } return false; diff --git a/src/app/shared/cookies/orejime.service.ts b/src/app/shared/cookies/orejime.service.ts index 0640f8d6ff..52db11d385 100644 --- a/src/app/shared/cookies/orejime.service.ts +++ b/src/app/shared/cookies/orejime.service.ts @@ -4,7 +4,7 @@ import { Observable } from 'rxjs'; /** * Abstract class representing a service for handling Orejime consent preferences and UI */ -@Injectable() +@Injectable({ providedIn: 'root' }) export abstract class OrejimeService { /** * Initializes the service diff --git a/src/app/statistics/matomo.service.spec.ts b/src/app/statistics/matomo.service.spec.ts index be14585c2b..7e7a9cd847 100644 --- a/src/app/statistics/matomo.service.spec.ts +++ b/src/app/statistics/matomo.service.spec.ts @@ -1,3 +1,7 @@ +import { + Injector, + runInInjectionContext, +} from '@angular/core'; import { fakeAsync, TestBed, @@ -53,6 +57,7 @@ describe('MatomoService', () => { { provide: OrejimeService, useValue: orejimeService }, { provide: NativeWindowService, useValue: nativeWindowService }, { provide: ConfigurationDataService, useValue: configService }, + { provide: Injector, useValue: TestBed }, ], }); @@ -70,11 +75,13 @@ describe('MatomoService', () => { }); it('should call setConsentGiven when consent is true', () => { + service.matomoTracker = matomoTracker; service.changeMatomoConsent(true); expect(matomoTracker.setConsentGiven).toHaveBeenCalled(); }); it('should call forgetConsentGiven when consent is false', () => { + service.matomoTracker = matomoTracker; service.changeMatomoConsent(false); expect(matomoTracker.forgetConsentGiven).toHaveBeenCalled(); }); @@ -91,7 +98,10 @@ describe('MatomoService', () => { configService.findByPropertyName.withArgs(MATOMO_SITE_ID).and.returnValue( createSuccessfulRemoteDataObject$(Object.assign(new ConfigurationProperty(), { values: ['1'] }))); orejimeService.getSavedPreferences.and.returnValue(of({ matomo: true })); - service.init(); + + runInInjectionContext(TestBed, () => { + service.init(); + }); expect(matomoTracker.setConsentGiven).toHaveBeenCalled(); expect(matomoInitializer.initializeTracker).toHaveBeenCalledWith({ @@ -100,7 +110,7 @@ describe('MatomoService', () => { }); }); - it('should initialize tracker with REST configuration correct parameters in production', () => { + it('should initialize tracker with REST configuration correct parameters in production', fakeAsync(() => { environment.production = true; environment.matomo = { trackerUrl: '' }; configService.findByPropertyName.withArgs(MATOMO_TRACKER_URL).and.returnValue( @@ -113,19 +123,25 @@ describe('MatomoService', () => { createSuccessfulRemoteDataObject$(Object.assign(new ConfigurationProperty(), { values: ['1'] }))); orejimeService.getSavedPreferences.and.returnValue(of({ matomo: true })); - service.init(); + runInInjectionContext(TestBed, () => { + service.init(); + }); + + tick(); expect(matomoTracker.setConsentGiven).toHaveBeenCalled(); expect(matomoInitializer.initializeTracker).toHaveBeenCalledWith({ siteId: '1', trackerUrl: 'http://example.com', }); - }); + })); it('should not initialize tracker if not in production', () => { environment.production = false; - service.init(); + runInInjectionContext(TestBed, () => { + service.init(); + }); expect(matomoInitializer.initializeTracker).not.toHaveBeenCalled(); }); @@ -143,7 +159,9 @@ describe('MatomoService', () => { createSuccessfulRemoteDataObject$(Object.assign(new ConfigurationProperty(), { values: ['1'] }))); orejimeService.getSavedPreferences.and.returnValue(of({ matomo: true })); - service.init(); + runInInjectionContext(TestBed, () => { + service.init(); + }); expect(matomoInitializer.initializeTracker).not.toHaveBeenCalled(); }); @@ -151,6 +169,7 @@ describe('MatomoService', () => { describe('with visitorId set', () => { beforeEach(() => { matomoTracker.getVisitorId.and.returnValue(Promise.resolve('12345')); + service.matomoTracker = matomoTracker; }); it('should add trackerId parameter', fakeAsync(() => { diff --git a/src/app/statistics/matomo.service.ts b/src/app/statistics/matomo.service.ts index a30e82f93a..e1c4758975 100644 --- a/src/app/statistics/matomo.service.ts +++ b/src/app/statistics/matomo.service.ts @@ -1,6 +1,8 @@ import { + EnvironmentInjector, inject, Injectable, + runInInjectionContext, } from '@angular/core'; import { MatomoInitializerService, @@ -11,12 +13,10 @@ import { from as fromPromise, Observable, of, - switchMap, } from 'rxjs'; import { map, take, - tap, } from 'rxjs/operators'; import { environment } from '../../environments/environment'; @@ -47,10 +47,10 @@ export const MATOMO_ENABLED = 'matomo.enabled'; export class MatomoService { /** Injects the MatomoInitializerService to initialize the Matomo tracker. */ - matomoInitializer = inject(MatomoInitializerService); + matomoInitializer: MatomoInitializerService; /** Injects the MatomoTracker to manage Matomo tracking operations. */ - matomoTracker = inject(MatomoTracker); + matomoTracker: MatomoTracker; /** Injects the OrejimeService to manage cookie consent preferences. */ orejimeService = inject(OrejimeService); @@ -61,6 +61,10 @@ export class MatomoService { /** Injects the ConfigurationService. */ configService = inject(ConfigurationDataService); + constructor(private injector: EnvironmentInjector) { + + } + /** * Initializes the Matomo tracker if in production environment. * Sets up the changeMatomoConsent function on the native window object. @@ -74,14 +78,15 @@ export class MatomoService { if (environment.production) { const preferences$ = this.orejimeService.getSavedPreferences(); - preferences$ - .pipe( - tap(preferences => this.changeMatomoConsent(preferences?.matomo)), - switchMap(_ => combineLatest([this.isMatomoEnabled$(), this.getSiteId$(), this.getTrackerUrl$()])), - ) - .subscribe(([isMatomoEnabled, siteId, trackerUrl]) => { + combineLatest([preferences$, this.isMatomoEnabled$(), this.getSiteId$(), this.getTrackerUrl$()]) + .subscribe(([preferences, isMatomoEnabled, siteId, trackerUrl]) => { if (isMatomoEnabled && siteId && trackerUrl) { + runInInjectionContext(this.injector, () => { + this.matomoTracker = inject(MatomoTracker); + this.matomoInitializer = inject(MatomoInitializerService); + }); this.matomoInitializer.initializeTracker({ siteId, trackerUrl }); + this.changeMatomoConsent(preferences?.matomo); } }); } @@ -93,9 +98,9 @@ export class MatomoService { */ changeMatomoConsent = (consent: boolean) => { if (consent) { - this.matomoTracker.setConsentGiven(); + this.matomoTracker?.setConsentGiven(); } else { - this.matomoTracker.forgetConsentGiven(); + this.matomoTracker?.forgetConsentGiven(); } }; @@ -105,7 +110,7 @@ export class MatomoService { * @returns An Observable that emits the URL with the visitor ID appended. */ appendVisitorId(url: string): Observable { - return fromPromise(this.matomoTracker.getVisitorId()) + return fromPromise(this.matomoTracker?.getVisitorId()) .pipe( map(visitorId => this.appendTrackerId(url, visitorId)), take(1),