Skip to content

Commit 6b99400

Browse files
feat(account-creation): set up tracking
ref: #MANAGER-19491 Signed-off-by: Jacques Larique <[email protected]>
1 parent 8e435a1 commit 6b99400

File tree

22 files changed

+681
-50
lines changed

22 files changed

+681
-50
lines changed

packages/manager/apps/account-creation/__mocks__/gcj-module.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react';
2+
3+
export const usePrivacyPolicyLink = () => 'https://fake-link.com';
4+
5+
type DataUsagePolicyProps = {
6+
subsidiary: string;
7+
region: string;
8+
};
9+
10+
export const DataUsagePolicy = ({ subsidiary, region }: DataUsagePolicyProps) => (
11+
<div data-testid="data-usage-policy">
12+
{subsidiary}-{region}
13+
</div>
14+
);

packages/manager/apps/account-creation/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"element-internals-polyfill": "^3.0.0",
3838
"i18next": "^23.8.2",
3939
"i18next-http-backend": "^2.4.2",
40+
"piano-analytics-js": "^6.12.0",
4041
"react": "^18.2.0",
4142
"react-dom": "^18.2.0",
4243
"react-hook-form": "^7.55.0",

packages/manager/apps/account-creation/src/components/header/Header.component.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,38 @@
1-
import { useCallback, useEffect, useState } from 'react';
1+
import { useCallback } from 'react';
22
import { useTranslation } from 'react-i18next';
3+
34
import { saveUserLocale } from '@ovh-ux/manager-config';
45
import { LanguageMenu } from '@ovh-ux/manager-gcj-module';
6+
import {
7+
ButtonType,
8+
PageLocation,
9+
usePageTracking,
10+
} from '@ovh-ux/manager-react-shell-client';
11+
512
import ovhCloudLogo from '@/assets/logo-ovhcloud.png';
13+
import { useTrackingContext } from '@/context/tracking/useTracking';
614

715
export default function HeaderComponent() {
816
const { i18n } = useTranslation();
17+
const pageTracking = usePageTracking();
18+
const { trackClick } = useTrackingContext();
919

1020
const onLocalUpdate = useCallback(
1121
(newLocale: string) => {
22+
if (pageTracking) {
23+
trackClick(pageTracking, {
24+
location: PageLocation.page,
25+
buttonType: ButtonType.button,
26+
actions: [
27+
'change_language_interface',
28+
`${i18n.language}_to_${newLocale}`,
29+
],
30+
});
31+
}
1232
i18n.changeLanguage(newLocale);
1333
saveUserLocale(newLocale);
1434
},
15-
[i18n],
35+
[i18n, pageTracking],
1636
);
1737

1838
return (

packages/manager/apps/account-creation/src/context/tracking/tracking.context.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
import { createContext } from 'react';
2+
3+
import { User } from '@ovh-ux/manager-config';
24
import {
35
TrackingClickParams,
46
TrackingPageParams,
57
} from '@ovh-ux/manager-react-shell-client';
6-
import { User } from '@ovh-ux/manager-config';
8+
9+
import { AdditionalTrackingParams } from '@/types/tracking';
710

811
export type TrackingContext = {
912
setUser: (user: User) => void;
10-
trackPage: (params: TrackingPageParams) => void;
13+
trackPage: (params: TrackingPageParams & AdditionalTrackingParams) => void;
1114
trackClick: (
1215
page: TrackingPageParams,
13-
{ location, buttonType, actions, actionType }: TrackingClickParams,
16+
{
17+
location,
18+
buttonType,
19+
actions,
20+
actionType,
21+
pageCategory,
22+
}: TrackingClickParams & AdditionalTrackingParams,
1423
) => void;
1524
};
1625

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
import { describe, expect, it, vi, beforeEach } from 'vitest';
2+
import { render, screen, waitFor } from '@testing-library/react';
3+
import { TrackingPlugin } from '@ovh-ux/shell';
4+
import { Region, User } from '@ovh-ux/manager-config';
5+
import * as shellClient from '@ovh-ux/manager-react-shell-client';
6+
import { TrackingProvider } from './tracking.provider';
7+
import { APP_NAME, LEVEL2, SUB_UNIVERSE, UNIVERSE } from '@/tracking.constant';
8+
import { useTrackingContext } from './useTracking';
9+
10+
const mockConfigureTracking = vi.fn();
11+
// Mock dependencies
12+
vi.mock('@ovh-ux/shell', () => ({
13+
TrackingPlugin: vi.fn().mockImplementation(() => ({
14+
configureTracking: mockConfigureTracking,
15+
trackPage: vi.fn(),
16+
trackClick: vi.fn(),
17+
})),
18+
}));
19+
20+
vi.mock('@ovh-ux/manager-react-shell-client', () => ({
21+
getClickProps: vi.fn((params) => params),
22+
getPageProps: vi.fn((params) => params),
23+
}));
24+
25+
describe('TrackingProvider', () => {
26+
let mockPlugin: any;
27+
const mockRegion = Region.EU;
28+
const mockUser: User = {
29+
ovhSubsidiary: 'FR',
30+
31+
} as User;
32+
33+
const renderTrackingTest = (component: JSX.Element = <div>Test</div>) => {
34+
let contextValue: any;
35+
36+
const TestComponent = () => {
37+
contextValue = useTrackingContext();
38+
return component;
39+
};
40+
41+
const renderResult = render(
42+
<TrackingProvider region={mockRegion}>
43+
<TestComponent />
44+
</TrackingProvider>,
45+
);
46+
47+
return {
48+
context: contextValue,
49+
...renderResult,
50+
}
51+
}
52+
53+
beforeEach(() => {
54+
vi.clearAllMocks();
55+
mockPlugin = {
56+
configureTracking: mockConfigureTracking,
57+
trackPage: vi.fn(),
58+
trackClick: vi.fn(),
59+
};
60+
(TrackingPlugin as any).mockImplementation(() => mockPlugin);
61+
});
62+
63+
it('should render DataUsagePolicy component', () => {
64+
render(
65+
<TrackingProvider region={mockRegion}>
66+
<div>Test</div>
67+
</TrackingProvider>,
68+
);
69+
70+
expect(screen.getByTestId('data-usage-policy')).toBeInTheDocument();
71+
});
72+
73+
it('should initialize TrackingPlugin and configure tracking', async () => {
74+
render(
75+
<TrackingProvider region={mockRegion}>
76+
<div>Test</div>
77+
</TrackingProvider>,
78+
);
79+
80+
expect(TrackingPlugin).toHaveBeenCalledTimes(1);
81+
82+
await waitFor(() => {
83+
expect(mockPlugin.configureTracking).toHaveBeenCalledWith(
84+
mockRegion,
85+
expect.any(Object),
86+
'fr_FR',
87+
);
88+
});
89+
});
90+
91+
it('should provide trackClick, trackPage and setUser functions in context', () => {
92+
const { context } = renderTrackingTest();
93+
94+
expect(context).toBeDefined();
95+
expect(context.trackClick).toBeDefined();
96+
expect(typeof context.trackClick).toBe('function');
97+
98+
expect(context).toBeDefined();
99+
expect(context.trackPage).toBeDefined();
100+
expect(typeof context.trackPage).toBe('function');
101+
102+
expect(context).toBeDefined();
103+
expect(context.setUser).toBeDefined();
104+
expect(typeof context.setUser).toBe('function');
105+
});
106+
107+
it('should configure tracking when setUser is called', async () => {
108+
const { context } = renderTrackingTest();
109+
110+
mockPlugin.configureTracking.mockClear();
111+
112+
context.setUser(mockUser);
113+
114+
await waitFor(() => {
115+
expect(mockPlugin.configureTracking).toHaveBeenCalledWith(
116+
mockRegion,
117+
mockUser,
118+
'fr_FR',
119+
);
120+
});
121+
});
122+
123+
it('should call trackPage with correct parameters', async () => {
124+
const getPagePropsSpy = vi.spyOn(shellClient, 'getPageProps');
125+
const { context } = renderTrackingTest();
126+
127+
const trackingParams = {
128+
pageName: 'test-page',
129+
pageType: 'form',
130+
};
131+
132+
context.trackPage(trackingParams);
133+
134+
await waitFor(() => {
135+
expect(getPagePropsSpy).toHaveBeenCalledWith({
136+
chapter1: UNIVERSE,
137+
chapter2: SUB_UNIVERSE,
138+
chapter3: APP_NAME,
139+
appName: APP_NAME,
140+
pageTheme: UNIVERSE,
141+
level2Config: LEVEL2,
142+
...trackingParams,
143+
level2: LEVEL2[mockRegion].config.level2,
144+
});
145+
});
146+
147+
expect(mockPlugin.trackPage).toHaveBeenCalledWith(
148+
expect.objectContaining({
149+
...trackingParams,
150+
page_category: 'Authentication',
151+
}),
152+
);
153+
});
154+
155+
it('should call trackPage with custom pageCategory', async () => {
156+
const { context } = renderTrackingTest();
157+
158+
const trackingParams = {
159+
pageName: 'test-page',
160+
pageType: 'form',
161+
pageCategory: 'CustomCategory',
162+
};
163+
164+
context.trackPage(trackingParams);
165+
166+
await waitFor(() => {
167+
expect(mockPlugin.trackPage).toHaveBeenCalledWith(
168+
expect.objectContaining({
169+
page_category: 'CustomCategory',
170+
}),
171+
);
172+
});
173+
});
174+
175+
it('should call trackClick with correct parameters', async () => {
176+
const getClickPropsSpy = vi.spyOn(shellClient, 'getClickProps');
177+
const { context } = renderTrackingTest();
178+
179+
const pageTracking = {
180+
pageName: 'test-page',
181+
pageType: 'form',
182+
};
183+
184+
const clickParams = {
185+
location: 'header',
186+
buttonType: 'button',
187+
actions: ['click-action'],
188+
actionType: 'navigation',
189+
};
190+
191+
context.trackClick(pageTracking, clickParams);
192+
193+
await waitFor(() => {
194+
expect(getClickPropsSpy).toHaveBeenCalledWith({
195+
chapter1: UNIVERSE,
196+
chapter2: SUB_UNIVERSE,
197+
chapter3: APP_NAME,
198+
appName: APP_NAME,
199+
pageTheme: UNIVERSE,
200+
level2Config: LEVEL2,
201+
...pageTracking,
202+
...clickParams,
203+
level2: LEVEL2[mockRegion].config.level2,
204+
});
205+
});
206+
207+
expect(mockPlugin.trackClick).toHaveBeenCalledWith(
208+
expect.objectContaining({
209+
page_category: 'Authentication',
210+
}),
211+
);
212+
});
213+
214+
it('should call trackClick with custom pageCategory', async () => {
215+
const { context } = renderTrackingTest();
216+
217+
const pageTracking = {
218+
pageName: 'test-page',
219+
pageType: 'form',
220+
};
221+
222+
const clickParams = {
223+
location: 'header',
224+
buttonType: 'button',
225+
actions: ['click-action'],
226+
actionType: 'navigation',
227+
pageCategory: 'CustomClickCategory',
228+
};
229+
230+
context.trackClick(pageTracking, clickParams);
231+
232+
await waitFor(() => {
233+
expect(mockPlugin.trackClick).toHaveBeenCalledWith(
234+
expect.objectContaining({
235+
page_category: 'CustomClickCategory',
236+
}),
237+
);
238+
});
239+
});
240+
});

0 commit comments

Comments
 (0)