Skip to content

Commit 639e5e5

Browse files
committed
Added kind param
1 parent 2250dc3 commit 639e5e5

File tree

9 files changed

+102
-17
lines changed

9 files changed

+102
-17
lines changed

special-pages/pages/duckplayer/app/embed-settings.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,17 @@ class VideoId {
103103
* @throws {Error}
104104
*/
105105
constructor(input) {
106-
if (typeof input !== 'string') throw new Error('string required, got: ' + input);
106+
if (typeof input !== 'string') {
107+
const error = new Error('string required, got: ' + input);
108+
error.name = 'VideoIdError';
109+
throw error;
110+
}
107111
const sanitized = sanitizeYoutubeId(input);
108-
if (sanitized === null) throw new Error('invalid ID from: ' + input);
112+
if (sanitized === null) {
113+
const error = new Error('invalid ID from: ' + input);
114+
error.name = 'VideoIdError';
115+
throw error;
116+
}
109117
this.id = sanitized;
110118
}
111119

@@ -126,9 +134,17 @@ class Timestamp {
126134
* @throws {Error}
127135
*/
128136
constructor(input) {
129-
if (typeof input !== 'string') throw new Error('string required for timestamp');
137+
if (typeof input !== 'string') {
138+
const error = new Error('string required for timestamp, got: ' + input);
139+
error.name = 'TimestampError';
140+
throw error;
141+
}
130142
const seconds = timestampInSeconds(input);
131-
if (seconds === null) throw new Error('invalid input for timestamp: ' + input);
143+
if (seconds === null) {
144+
const error = new Error('invalid input for timestamp: ' + input);
145+
error.name = 'TimestampError';
146+
throw error;
147+
}
132148
this.seconds = seconds;
133149
}
134150

special-pages/pages/duckplayer/app/index.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@ import { YouTubeErrorProvider } from './providers/YouTubeErrorProvider';
2727
export async function init(messaging, telemetry, baseEnvironment) {
2828
const result = await callWithRetry(() => messaging.initialSetup());
2929
if ('error' in result) {
30-
throw new Error(result.error);
30+
console.error('INITIAL SETUP ERROR', result.error);
31+
const error = new Error(result.error);
32+
error.name = 'InitialSetupError';
33+
throw error;
3134
}
3235

3336
const init = result.value;
34-
console.log('INITIAL DATA', init);
37+
console.log('INITIAL DATA');
3538

3639
// update the 'env' in case it was changed by native sides
3740
const environment = baseEnvironment
@@ -69,10 +72,13 @@ export async function init(messaging, telemetry, baseEnvironment) {
6972
const embed = createEmbedSettings(window.location.href, settings);
7073

7174
const didCatch = (error) => {
72-
const message = error?.message || 'unknown';
73-
messaging.reportException({ message });
75+
const message = error?.message;
76+
const kind = error?.error?.name;
77+
messaging.reportException({ message, kind });
78+
console.log('reportException', message, kind);
79+
7480
// TODO: Remove the following event once all native platforms are responding to 'reportMetric: exception'
75-
messaging.reportPageException({ message });
81+
messaging.reportPageException({ message: message || 'unknown error' });
7682
};
7783

7884
document.body.dataset.layout = settings.layout;

special-pages/pages/duckplayer/app/providers/UserValuesProvider.jsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,12 @@ export function UserValuesProvider({ initial, children }) {
6060
})
6161
.catch((err) => {
6262
console.error('could not set the enabled flag', err);
63-
messaging.reportException({ message: 'could not set the enabled flag: ' + err.toString() });
63+
const message = 'could not set the enabled flag: ' + err.toString();
64+
const kind = 'MessagingError';
65+
messaging.reportException({ message, kind });
66+
6467
// TODO: Remove the following event once all native platforms are responding to 'reportMetric: exception'
65-
messaging.reportPageException({ message: 'could not set the enabled flag: ' + err.toString() });
68+
messaging.reportPageException({ message });
6669
});
6770
}
6871

special-pages/pages/duckplayer/integration-tests/duck-player.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ export class DuckPlayerPage {
145145
this.mocks.defaultResponses(clone);
146146
}
147147

148+
initError() {
149+
const clone = structuredClone(this.defaults);
150+
// Force an init error by passing an empty response to initialSetup
151+
// @ts-expect-error - this is a test
152+
clone.initialSetup = undefined;
153+
this.mocks.defaultResponses(clone);
154+
}
155+
148156
/**
149157
* We don't need to actually load the content for these tests.
150158
* By mocking the response, we make the tests about 10x faster and also ensure they work offline.
@@ -537,6 +545,31 @@ export class DuckPlayerPage {
537545
]);
538546
}
539547

548+
/**
549+
* @param {import('../../../shared/types/shared.ts').ReportMetricEvent} evt
550+
*/
551+
async didSendReportMetric(evt) {
552+
const events = await this.mocks.waitForCallCount({ method: 'reportMetric', count: 1 });
553+
expect(events).toStrictEqual([
554+
{
555+
payload: {
556+
context: 'specialPages',
557+
featureName: 'duckPlayerPage',
558+
method: 'reportMetric',
559+
params: evt,
560+
},
561+
},
562+
]);
563+
}
564+
565+
/**
566+
* @param {string} kind
567+
* @param {string} message
568+
*/
569+
didSendException(kind, message) {
570+
return this.didSendReportMetric({ metricName: 'exception', params: { kind, message } });
571+
}
572+
540573
async withStorageValues() {
541574
await this.page.evaluate(() => {
542575
localStorage.setItem('foo', 'bar');

special-pages/pages/duckplayer/integration-tests/duckplayer.spec.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,14 @@ test.describe('reporting exceptions', () => {
333333
// load as normal
334334
await duckplayer.openWithException();
335335
await duckplayer.showsErrorMessage();
336+
await duckplayer.didSendException('Error', 'Simulated Exception');
337+
});
338+
test('initial setup error', async ({ page }, workerInfo) => {
339+
const duckplayer = DuckPlayerPage.create(page, workerInfo);
340+
// load as normal
341+
duckplayer.initError();
342+
await duckplayer.openWithVideoID();
343+
await duckplayer.didSendException('InitError', 'Max attempts reached: Error: response not found for initialSetup');
336344
});
337345
});
338346

special-pages/pages/duckplayer/src/index.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,12 @@ const telemetry = new Telemetry(messaging);
191191
init(duckplayerPage, telemetry, baseEnvironment).catch((e) => {
192192
// messages.
193193
console.error(e);
194-
const msg = typeof e?.message === 'string' ? e.message : 'unknown init error';
195-
duckplayerPage.reportException({ message: msg });
194+
const message = typeof e?.message === 'string' ? e.message : 'unknown error';
195+
const kind = 'InitError';
196+
duckplayerPage.reportException({ message, kind });
197+
196198
// TODO: Remove this event once all native platforms are responding to 'reportMetric: exception'
197-
duckplayerPage.reportInitException({ message: msg });
199+
duckplayerPage.reportInitException({ message });
198200
});
199201

200202
initStorage();

special-pages/shared/messages/reportMetric.notify.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
"properties": {
1818
"message": {
1919
"type": "string"
20+
},
21+
"kind": {
22+
"type": "string"
2023
}
2124
}
2225
}

special-pages/shared/report-metric.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ export const REPORT_METRIC_MESSAGE_ID = 'reportMetric';
22
export const METRIC_NAME_EXCEPTION = 'exception';
33

44
/**
5+
* @typedef {import('../shared/types/shared.ts').ExceptionMetric} ExceptionMetric
6+
* @typedef {import('../shared/types/shared.ts').ReportMetricEvent} ReportMetricEvent
57
* @typedef {import('../shared/types/shared.ts').SharedMessages} SharedMessages
68
* @typedef {import('@duckduckgo/messaging/lib/shared-types.js').MessagingBase<SharedMessages>|import('@duckduckgo/messaging').Messaging} SharedMessaging
79
*/
810

911
/**
1012
* Sends a standard 'reportMetric' event to the native layer
1113
* @param {SharedMessaging} messaging
12-
* @param {import('../shared/types/shared.ts').ReportMetricEvent} metricEvent
14+
* @param {ReportMetricEvent} metricEvent
1315
*/
1416
export function reportMetric(messaging, metricEvent) {
1517
if (!messaging?.notify) {
@@ -26,8 +28,19 @@ export function reportMetric(messaging, metricEvent) {
2628
/**
2729
* Sends a 'reportMetric' event with metric name 'exception'
2830
* @param {SharedMessaging} messaging
29-
* @param {import('../shared/types/shared.ts').ExceptionMetric['params']} params
31+
* @param {ExceptionMetric['params']} params
3032
*/
3133
export function reportException(messaging, params) {
32-
reportMetric(messaging, { metricName: METRIC_NAME_EXCEPTION, params });
34+
const message = typeof params?.message === 'string' ? params.message : 'unknown error';
35+
const kind = typeof params?.kind === 'string' ? params.kind : 'Error';
36+
37+
/** @type {ExceptionMetric} */
38+
const metric = {
39+
metricName: METRIC_NAME_EXCEPTION,
40+
params: {
41+
message,
42+
kind,
43+
},
44+
};
45+
reportMetric(messaging, metric);
3346
}

special-pages/shared/types/shared.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ export interface ExceptionMetric {
2525
metricName: "exception";
2626
params: {
2727
message: string;
28+
kind?: string;
2829
};
2930
}

0 commit comments

Comments
 (0)