Skip to content

Commit 6bd4f04

Browse files
[CST-18964] PR review
1 parent 601c6cd commit 6bd4f04

9 files changed

Lines changed: 229 additions & 53 deletions

src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.spec.ts

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { CommonModule } from '@angular/common';
1+
import {
2+
CommonModule,
3+
Location,
4+
} from '@angular/common';
25
import { PLATFORM_ID } from '@angular/core';
36
import {
47
ComponentFixture,
@@ -14,13 +17,15 @@ import { of as observableOf } from 'rxjs';
1417

1518
import { getForbiddenRoute } from '../../app-routing-paths';
1619
import { AuthService } from '../../core/auth/auth.service';
20+
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
1721
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
1822
import { SignpostingDataService } from '../../core/data/signposting-data.service';
1923
import { HardRedirectService } from '../../core/services/hard-redirect.service';
2024
import { ServerResponseService } from '../../core/services/server-response.service';
2125
import { Bitstream } from '../../core/shared/bitstream.model';
2226
import { FileService } from '../../core/shared/file.service';
2327
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
28+
import { MatomoService } from '../../statistics/matomo.service';
2429
import { BitstreamDownloadPageComponent } from './bitstream-download-page.component';
2530

2631
describe('BitstreamDownloadPageComponent', () => {
@@ -33,10 +38,13 @@ describe('BitstreamDownloadPageComponent', () => {
3338
let hardRedirectService: HardRedirectService;
3439
let activatedRoute;
3540
let router;
41+
let location: Location;
42+
let dsoNameService: DSONameService;
3643

3744
let bitstream: Bitstream;
3845
let serverResponseService: jasmine.SpyObj<ServerResponseService>;
3946
let signpostingDataService: jasmine.SpyObj<SignpostingDataService>;
47+
let matomoService: jasmine.SpyObj<MatomoService>;
4048

4149
const mocklink = {
4250
href: 'http://test.org',
@@ -54,6 +62,7 @@ describe('BitstreamDownloadPageComponent', () => {
5462
authService = jasmine.createSpyObj('authService', {
5563
isAuthenticated: observableOf(true),
5664
setRedirectUrl: {},
65+
getShortlivedToken: observableOf('token'),
5766
});
5867
authorizationService = jasmine.createSpyObj('authorizationSerivice', {
5968
isAuthorized: observableOf(true),
@@ -63,9 +72,18 @@ describe('BitstreamDownloadPageComponent', () => {
6372
retrieveFileDownloadLink: observableOf('content-url-with-headers'),
6473
});
6574

66-
hardRedirectService = jasmine.createSpyObj('fileService', {
75+
hardRedirectService = jasmine.createSpyObj('hardRedirectService', {
6776
redirect: {},
6877
});
78+
79+
location = jasmine.createSpyObj('location', {
80+
back: {},
81+
});
82+
83+
dsoNameService = jasmine.createSpyObj('dsoNameService', {
84+
getName: 'Test Bitstream',
85+
});
86+
6987
bitstream = Object.assign(new Bitstream(), {
7088
uuid: 'bitstreamUuid',
7189
_links: {
@@ -94,6 +112,8 @@ describe('BitstreamDownloadPageComponent', () => {
94112
signpostingDataService = jasmine.createSpyObj('SignpostingDataService', {
95113
getLinks: observableOf([mocklink, mocklink2]),
96114
});
115+
matomoService = jasmine.createSpyObj('MatomoService', ['appendVisitorId']);
116+
matomoService.appendVisitorId.and.callFake((link) => observableOf(link));
97117
}
98118

99119
function initTestbed() {
@@ -108,7 +128,10 @@ describe('BitstreamDownloadPageComponent', () => {
108128
{ provide: HardRedirectService, useValue: hardRedirectService },
109129
{ provide: ServerResponseService, useValue: serverResponseService },
110130
{ provide: SignpostingDataService, useValue: signpostingDataService },
131+
{ provide: MatomoService, useValue: matomoService },
111132
{ provide: PLATFORM_ID, useValue: 'server' },
133+
{ provide: Location, useValue: location },
134+
{ provide: DSONameService, useValue: dsoNameService },
112135
],
113136
})
114137
.compileComponents();
@@ -142,9 +165,11 @@ describe('BitstreamDownloadPageComponent', () => {
142165
component = fixture.componentInstance;
143166
fixture.detectChanges();
144167
});
145-
it('should redirect to the content link', () => {
146-
expect(hardRedirectService.redirect).toHaveBeenCalledWith('bitstream-content-link');
147-
});
168+
it('should redirect to the content link', waitForAsync(() => {
169+
fixture.whenStable().then(() => {
170+
expect(hardRedirectService.redirect).toHaveBeenCalledWith('bitstream-content-link');
171+
});
172+
}));
148173
it('should add the signposting links', () => {
149174
expect(serverResponseService.setHeader).toHaveBeenCalled();
150175
});
@@ -159,9 +184,11 @@ describe('BitstreamDownloadPageComponent', () => {
159184
component = fixture.componentInstance;
160185
fixture.detectChanges();
161186
});
162-
it('should redirect to an updated content link', () => {
163-
expect(hardRedirectService.redirect).toHaveBeenCalledWith('content-url-with-headers');
164-
});
187+
it('should redirect to an updated content link', waitForAsync(() => {
188+
fixture.whenStable().then(() => {
189+
expect(hardRedirectService.redirect).toHaveBeenCalledWith('content-url-with-headers');
190+
});
191+
}));
165192
});
166193
describe('when the user is not authorized and logged in', () => {
167194
beforeEach(waitForAsync(() => {
@@ -174,9 +201,11 @@ describe('BitstreamDownloadPageComponent', () => {
174201
component = fixture.componentInstance;
175202
fixture.detectChanges();
176203
});
177-
it('should navigate to the forbidden route', () => {
178-
expect(router.navigateByUrl).toHaveBeenCalledWith(getForbiddenRoute(), { skipLocationChange: true });
179-
});
204+
it('should navigate to the forbidden route', waitForAsync(() => {
205+
fixture.whenStable().then(() => {
206+
expect(router.navigateByUrl).toHaveBeenCalledWith(getForbiddenRoute(), { skipLocationChange: true });
207+
});
208+
}));
180209
});
181210
describe('when the user is not authorized and not logged in', () => {
182211
beforeEach(waitForAsync(() => {
@@ -190,10 +219,12 @@ describe('BitstreamDownloadPageComponent', () => {
190219
component = fixture.componentInstance;
191220
fixture.detectChanges();
192221
});
193-
it('should navigate to the login page', () => {
194-
expect(authService.setRedirectUrl).toHaveBeenCalled();
195-
expect(router.navigateByUrl).toHaveBeenCalledWith('login');
196-
});
222+
it('should navigate to the login page', waitForAsync(() => {
223+
fixture.whenStable().then(() => {
224+
expect(authService.setRedirectUrl).toHaveBeenCalled();
225+
expect(router.navigateByUrl).toHaveBeenCalledWith('login');
226+
});
227+
}));
197228
});
198229
});
199230
});

src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
hasValue,
4545
isNotEmpty,
4646
} from '../../shared/empty.util';
47+
import { MatomoService } from '../../statistics/matomo.service';
4748

4849
@Component({
4950
selector: 'ds-bitstream-download-page',
@@ -73,6 +74,7 @@ export class BitstreamDownloadPageComponent implements OnInit {
7374
public dsoNameService: DSONameService,
7475
private signpostingDataService: SignpostingDataService,
7576
private responseService: ServerResponseService,
77+
private matomoService: MatomoService,
7678
@Inject(PLATFORM_ID) protected platformId: string,
7779
) {
7880
this.initPageLinks();
@@ -109,14 +111,20 @@ export class BitstreamDownloadPageComponent implements OnInit {
109111
return [isAuthorized, isLoggedIn, bitstream, fileLink];
110112
}));
111113
} else {
112-
return [[isAuthorized, isLoggedIn, bitstream, '']];
114+
return [[isAuthorized, isLoggedIn, bitstream, bitstream._links.content.href]];
113115
}
114116
}),
115-
).subscribe(([isAuthorized, isLoggedIn, bitstream, fileLink]: [boolean, boolean, Bitstream, string]) => {
117+
switchMap(([isAuthorized, isLoggedIn, bitstream, fileLink]: [boolean, boolean, Bitstream, string]) =>
118+
this.matomoService.appendVisitorId(fileLink)
119+
.pipe(
120+
map((fileLinkWithVisitorId) => [isAuthorized, isLoggedIn, bitstream, fileLinkWithVisitorId]),
121+
),
122+
),
123+
).subscribe(([isAuthorized, isLoggedIn, , fileLink]: [boolean, boolean, Bitstream, string]) => {
116124
if (isAuthorized && isLoggedIn && isNotEmpty(fileLink)) {
117125
this.hardRedirectService.redirect(fileLink);
118126
} else if (isAuthorized && !isLoggedIn) {
119-
this.hardRedirectService.redirect(bitstream._links.content.href);
127+
this.hardRedirectService.redirect(fileLink);
120128
} else if (!isAuthorized && isLoggedIn) {
121129
this.router.navigateByUrl(getForbiddenRoute(), { skipLocationChange: true });
122130
} else if (!isAuthorized && !isLoggedIn) {

src/app/shared/cookies/browser-orejime.service.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { ANONYMOUS_STORAGE_NAME_OREJIME } from './orejime-configuration';
2828
describe('BrowserOrejimeService', () => {
2929
const trackingIdProp = 'google.analytics.key';
3030
const trackingIdTestValue = 'mock-tracking-id';
31+
const matomoTrackingId = 'matomo-tracking-id';
3132
const googleAnalytics = 'google-analytics';
3233
const recaptchaProp = 'registration.verification.enabled';
3334
const recaptchaValue = 'true';
@@ -310,9 +311,11 @@ describe('BrowserOrejimeService', () => {
310311
describe('initialize google analytics configuration', () => {
311312
let GOOGLE_ANALYTICS_KEY;
312313
let REGISTRATION_VERIFICATION_ENABLED_KEY;
314+
let MATOMO_ENABLED;
313315
beforeEach(() => {
314316
GOOGLE_ANALYTICS_KEY = clone((service as any).GOOGLE_ANALYTICS_KEY);
315317
REGISTRATION_VERIFICATION_ENABLED_KEY = clone((service as any).REGISTRATION_VERIFICATION_ENABLED_KEY);
318+
MATOMO_ENABLED = clone((service as any).MATOMO_ENABLED);
316319
spyOn((service as any), 'getUser$').and.returnValue(observableOf(user));
317320
translateService.get.and.returnValue(observableOf('loading...'));
318321
spyOn(service, 'addAppMessages');
@@ -361,6 +364,15 @@ describe('BrowserOrejimeService', () => {
361364
name: trackingIdTestValue,
362365
values: ['false'],
363366
}),
367+
)
368+
.withArgs(MATOMO_ENABLED)
369+
.and
370+
.returnValue(
371+
createSuccessfulRemoteDataObject$({
372+
... new ConfigurationProperty(),
373+
name: matomoTrackingId,
374+
values: ['false'],
375+
}),
364376
);
365377

366378
service.initialize();
@@ -380,6 +392,15 @@ describe('BrowserOrejimeService', () => {
380392
name: trackingIdTestValue,
381393
values: ['false'],
382394
}),
395+
)
396+
.withArgs(MATOMO_ENABLED)
397+
.and
398+
.returnValue(
399+
createSuccessfulRemoteDataObject$({
400+
... new ConfigurationProperty(),
401+
name: matomoTrackingId,
402+
values: ['false'],
403+
}),
383404
);
384405
service.initialize();
385406
expect(service.orejimeConfig.apps).not.toContain(jasmine.objectContaining({ name: googleAnalytics }));
@@ -398,6 +419,15 @@ describe('BrowserOrejimeService', () => {
398419
name: trackingIdTestValue,
399420
values: ['false'],
400421
}),
422+
)
423+
.withArgs(MATOMO_ENABLED)
424+
.and
425+
.returnValue(
426+
createSuccessfulRemoteDataObject$({
427+
... new ConfigurationProperty(),
428+
name: matomoTrackingId,
429+
values: ['false'],
430+
}),
401431
);
402432
service.initialize();
403433
expect(service.orejimeConfig.apps).not.toContain(jasmine.objectContaining({ name: googleAnalytics }));

src/app/shared/cookies/browser-orejime.service.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export class BrowserOrejimeService extends OrejimeService {
9090

9191
private readonly GOOGLE_ANALYTICS_SERVICE_NAME = 'google-analytics';
9292

93+
private readonly MATOMO_ENABLED = 'matomo.enabled';
9394

9495
/**
9596
* Initial Orejime configuration
@@ -134,7 +135,13 @@ export class BrowserOrejimeService extends OrejimeService {
134135
),
135136
);
136137

137-
const hideMatomo$ = observableOf(!(environment.matomo?.trackerUrl && environment.matomo?.siteId));
138+
const hideMatomo$ =
139+
this.configService.findByPropertyName(this.MATOMO_ENABLED).pipe(
140+
getFirstCompletedRemoteData(),
141+
map((remoteData) =>
142+
!remoteData.hasSucceeded || !remoteData.payload || isEmpty(remoteData.payload.values) || remoteData.payload.values[0].toLowerCase() !== 'true',
143+
),
144+
);
138145

139146
const appsToHide$: Observable<string[]> = observableCombineLatest([hideGoogleAnalytics$, hideRegistrationVerification$, hideMatomo$]).pipe(
140147
map(([hideGoogleAnalytics, hideRegistrationVerification, hideMatomo]) => {

src/app/statistics/matomo.service.spec.ts

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { TestBed } from '@angular/core/testing';
1+
import {
2+
fakeAsync,
3+
TestBed,
4+
tick,
5+
} from '@angular/core/testing';
26
import {
37
MatomoInitializerService,
48
MatomoTracker,
@@ -7,25 +11,34 @@ import { MatomoTestingModule } from 'ngx-matomo-client/testing';
711
import { of } from 'rxjs';
812

913
import { environment } from '../../environments/environment';
14+
import { ConfigurationDataService } from '../core/data/configuration-data.service';
1015
import {
1116
NativeWindowRef,
1217
NativeWindowService,
1318
} from '../core/services/window.service';
19+
import { ConfigurationProperty } from '../core/shared/configuration-property.model';
1420
import { OrejimeService } from '../shared/cookies/orejime.service';
15-
import { MatomoService } from './matomo.service';
21+
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
22+
import {
23+
MATOMO_SITE_ID,
24+
MATOMO_TRACKER_URL,
25+
MatomoService,
26+
} from './matomo.service';
1627

1728
describe('MatomoService', () => {
1829
let service: MatomoService;
1930
let matomoTracker: jasmine.SpyObj<MatomoTracker>;
2031
let matomoInitializer: jasmine.SpyObj<MatomoInitializerService>;
2132
let orejimeService: jasmine.SpyObj<OrejimeService>;
2233
let nativeWindowService: jasmine.SpyObj<NativeWindowRef>;
34+
let configService: jasmine.SpyObj<ConfigurationDataService>;
2335

2436
beforeEach(() => {
25-
matomoTracker = jasmine.createSpyObj('MatomoTracker', ['setConsentGiven', 'forgetConsentGiven']);
37+
matomoTracker = jasmine.createSpyObj('MatomoTracker', ['setConsentGiven', 'forgetConsentGiven', 'getVisitorId']);
2638
matomoInitializer = jasmine.createSpyObj('MatomoInitializerService', ['initializeTracker']);
2739
orejimeService = jasmine.createSpyObj('OrejimeService', ['getSavedPreferences']);
2840
nativeWindowService = jasmine.createSpyObj('NativeWindowService', [], { nativeWindow: {} });
41+
configService = jasmine.createSpyObj('ConfigurationDataService', ['findByPropertyName']);
2942

3043
TestBed.configureTestingModule({
3144
imports: [MatomoTestingModule.forRoot()],
@@ -34,6 +47,7 @@ describe('MatomoService', () => {
3447
{ provide: MatomoInitializerService, useValue: matomoInitializer },
3548
{ provide: OrejimeService, useValue: orejimeService },
3649
{ provide: NativeWindowService, useValue: nativeWindowService },
50+
{ provide: ConfigurationDataService, useValue: configService },
3751
],
3852
});
3953

@@ -50,9 +64,23 @@ describe('MatomoService', () => {
5064
expect(nativeWindowService.nativeWindow.changeMatomoConsent).toBe(service.changeMatomoConsent);
5165
});
5266

67+
it('should call setConsentGiven when consent is true', () => {
68+
service.changeMatomoConsent(true);
69+
expect(matomoTracker.setConsentGiven).toHaveBeenCalled();
70+
});
71+
72+
it('should call forgetConsentGiven when consent is false', () => {
73+
service.changeMatomoConsent(false);
74+
expect(matomoTracker.forgetConsentGiven).toHaveBeenCalled();
75+
});
76+
5377
it('should initialize tracker with correct parameters in production', () => {
5478
environment.production = true;
55-
environment.matomo = { siteId: '1', trackerUrl: 'http://example.com' };
79+
configService.findByPropertyName.withArgs(MATOMO_TRACKER_URL).and.returnValue(
80+
createSuccessfulRemoteDataObject$(Object.assign(new ConfigurationProperty(),{ values: ['http://example.com'] })),
81+
);
82+
configService.findByPropertyName.withArgs(MATOMO_SITE_ID).and.returnValue(
83+
createSuccessfulRemoteDataObject$(Object.assign(new ConfigurationProperty(), { values: ['1'] })));
5684
orejimeService.getSavedPreferences.and.returnValue(of({ matomo: true }));
5785

5886
service.init();
@@ -72,13 +100,17 @@ describe('MatomoService', () => {
72100
expect(matomoInitializer.initializeTracker).not.toHaveBeenCalled();
73101
});
74102

75-
it('should call setConsentGiven when consent is true', () => {
76-
service.changeMatomoConsent(true);
77-
expect(matomoTracker.setConsentGiven).toHaveBeenCalled();
78-
});
103+
describe('with visitorId set', () => {
104+
beforeEach(() => {
105+
matomoTracker.getVisitorId.and.returnValue(Promise.resolve('12345'));
106+
});
107+
108+
it('should add trackerId parameter', fakeAsync(() => {
109+
service.appendVisitorId('http://example.com/')
110+
.subscribe(url => expect(url).toEqual('http://example.com/?trackerId=12345'));
111+
tick();
112+
}));
79113

80-
it('should call forgetConsentGiven when consent is false', () => {
81-
service.changeMatomoConsent(false);
82-
expect(matomoTracker.forgetConsentGiven).toHaveBeenCalled();
83114
});
115+
84116
});

0 commit comments

Comments
 (0)