Skip to content

Commit 602a261

Browse files
UFAL/Broken matomo tracking with custom dimensions (#1237)
* fix: include dc_identifier in ViewTrackerResolverService event properties for Matomo custom dimensions * Fixed linting error
1 parent 39abed3 commit 602a261

2 files changed

Lines changed: 148 additions & 1 deletion

File tree

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import { ViewTrackerResolverService } from './view-tracker-resolver.service';
2+
import { Angulartics2 } from 'angulartics2';
3+
import { ReferrerService } from '../../../core/services/referrer.service';
4+
import { ActivatedRouteSnapshot, ResolveEnd, RouterStateSnapshot } from '@angular/router';
5+
import { of as observableOf, Subject } from 'rxjs';
6+
7+
describe('ViewTrackerResolverService', () => {
8+
let service: ViewTrackerResolverService;
9+
let angulartics2: Angulartics2;
10+
let referrerService: jasmine.SpyObj<ReferrerService>;
11+
let router: any;
12+
let routerEvents$: Subject<any>;
13+
let mockDso: { firstMetadataValue: jasmine.Spy };
14+
15+
const mockReferrer = 'https://www.referrer.com';
16+
17+
beforeEach(() => {
18+
routerEvents$ = new Subject();
19+
mockDso = {
20+
firstMetadataValue: jasmine.createSpy('firstMetadataValue').and.returnValue('http://hdl.handle.net/123456789/1'),
21+
};
22+
23+
angulartics2 = {
24+
eventTrack: new Subject(),
25+
} as any;
26+
27+
referrerService = jasmine.createSpyObj('ReferrerService', ['getReferrer']);
28+
referrerService.getReferrer.and.returnValue(observableOf(mockReferrer));
29+
30+
router = {
31+
events: routerEvents$.asObservable(),
32+
};
33+
34+
service = new ViewTrackerResolverService(angulartics2, referrerService, router);
35+
});
36+
37+
it('should be created', () => {
38+
expect(service).toBeTruthy();
39+
});
40+
41+
it('should include dc_identifier in event properties when dso has dc.identifier.uri metadata', () => {
42+
const routeSnapshot = {
43+
data: {
44+
dso: {
45+
payload: mockDso,
46+
},
47+
},
48+
} as any as ActivatedRouteSnapshot;
49+
const stateSnapshot = {} as RouterStateSnapshot;
50+
51+
let emittedEvent: any;
52+
(angulartics2.eventTrack as Subject<any>).subscribe(event => {
53+
emittedEvent = event;
54+
});
55+
56+
service.resolve(routeSnapshot, stateSnapshot);
57+
58+
// Simulate ResolveEnd event to trigger the subscription
59+
routerEvents$.next(new ResolveEnd(1, '/', '/', {} as any));
60+
61+
expect(emittedEvent).toBeDefined();
62+
expect(emittedEvent.action).toBe('page_view');
63+
expect(emittedEvent.properties.object).toBe(mockDso);
64+
expect(emittedEvent.properties.referrer).toBe(mockReferrer);
65+
expect(emittedEvent.properties.dc_identifier).toBe('http://hdl.handle.net/123456789/1');
66+
expect(mockDso.firstMetadataValue).toHaveBeenCalledWith('dc.identifier.uri');
67+
});
68+
69+
it('should set dc_identifier to undefined when dso does not have dc.identifier.uri metadata', () => {
70+
const mockDsoWithoutMetadata = {
71+
firstMetadataValue: jasmine.createSpy('firstMetadataValue').and.returnValue(undefined),
72+
};
73+
74+
const routeSnapshot = {
75+
data: {
76+
dso: {
77+
payload: mockDsoWithoutMetadata,
78+
},
79+
},
80+
} as any as ActivatedRouteSnapshot;
81+
const stateSnapshot = {} as RouterStateSnapshot;
82+
83+
let emittedEvent: any;
84+
(angulartics2.eventTrack as Subject<any>).subscribe(event => {
85+
emittedEvent = event;
86+
});
87+
88+
service.resolve(routeSnapshot, stateSnapshot);
89+
routerEvents$.next(new ResolveEnd(1, '/', '/', {} as any));
90+
91+
expect(emittedEvent).toBeDefined();
92+
expect(emittedEvent.action).toBe('page_view');
93+
expect(emittedEvent.properties.dc_identifier).toBeUndefined();
94+
});
95+
96+
it('should handle missing dso gracefully (dc_identifier undefined)', () => {
97+
const routeSnapshot = {
98+
data: {
99+
dso: {
100+
payload: undefined,
101+
},
102+
},
103+
} as any as ActivatedRouteSnapshot;
104+
const stateSnapshot = {} as RouterStateSnapshot;
105+
106+
let emittedEvent: any;
107+
(angulartics2.eventTrack as Subject<any>).subscribe(event => {
108+
emittedEvent = event;
109+
});
110+
111+
service.resolve(routeSnapshot, stateSnapshot);
112+
routerEvents$.next(new ResolveEnd(1, '/', '/', {} as any));
113+
114+
expect(emittedEvent).toBeDefined();
115+
expect(emittedEvent.action).toBe('page_view');
116+
expect(emittedEvent.properties.dc_identifier).toBeUndefined();
117+
});
118+
119+
it('should use custom dsoPath from route data when provided', () => {
120+
const mockDsoCustom = {
121+
firstMetadataValue: jasmine.createSpy('firstMetadataValue').and.returnValue('http://hdl.handle.net/custom/42'),
122+
};
123+
124+
const routeSnapshot = {
125+
data: {
126+
dsoPath: 'myCustomDso',
127+
myCustomDso: mockDsoCustom,
128+
},
129+
} as any as ActivatedRouteSnapshot;
130+
const stateSnapshot = {} as RouterStateSnapshot;
131+
132+
let emittedEvent: any;
133+
(angulartics2.eventTrack as Subject<any>).subscribe(event => {
134+
emittedEvent = event;
135+
});
136+
137+
service.resolve(routeSnapshot, stateSnapshot);
138+
routerEvents$.next(new ResolveEnd(1, '/', '/', {} as any));
139+
140+
expect(emittedEvent).toBeDefined();
141+
expect(emittedEvent.properties.object).toBe(mockDsoCustom);
142+
expect(emittedEvent.properties.dc_identifier).toBe('http://hdl.handle.net/custom/42');
143+
});
144+
});

src/app/statistics/angulartics/dspace/view-tracker-resolver.service.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ export class ViewTrackerResolverService {
2929
switchMap(() =>
3030
this.referrerService.getReferrer().pipe(take(1))))
3131
.subscribe((referrer: string) => {
32+
const object = this.getNestedProperty(routeSnapshot.data, dsoPath);
33+
const dc_identifier = object?.firstMetadataValue?.('dc.identifier.uri');
3234
this.angulartics2.eventTrack.next({
3335
action: 'page_view',
3436
properties: {
35-
object: this.getNestedProperty(routeSnapshot.data, dsoPath),
37+
object,
3638
referrer,
39+
dc_identifier,
3740
},
3841
});
3942
});

0 commit comments

Comments
 (0)