Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref(browser): Extract getReportDialogEndpoint from API class #4274

Merged
merged 7 commits into from
Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/browser/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { API, captureException, withScope } from '@sentry/core';
import { captureException, getReportDialogEndpoint, withScope } from '@sentry/core';
import { DsnLike, Event as SentryEvent, Mechanism, Scope, WrappedFunction } from '@sentry/types';
import { addExceptionMechanism, addExceptionTypeValue, getGlobalObject, logger } from '@sentry/utils';

Expand Down Expand Up @@ -210,7 +210,7 @@ export function injectReportDialog(options: ReportDialogOptions = {}): void {

const script = global.document.createElement('script');
script.async = true;
script.src = new API(options.dsn).getReportDialogEndpoint(options);
script.src = getReportDialogEndpoint(options.dsn, options);

if (options.onLoad) {
// eslint-disable-next-line @typescript-eslint/unbound-method
Expand Down
86 changes: 44 additions & 42 deletions packages/core/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ export class API {
/** Returns the prefix to construct Sentry ingestion API endpoints. */
public getBaseApiEndpoint(): string {
const dsn = this.getDsn();
const protocol = dsn.protocol ? `${dsn.protocol}:` : '';
const port = dsn.port ? `:${dsn.port}` : '';
return `${protocol}//${dsn.host}${port}${dsn.path ? `/${dsn.path}` : ''}/api/`;
return getBaseApiEndpoint(dsn);
}

/** Returns the store endpoint URL. */
Expand Down Expand Up @@ -99,45 +97,6 @@ export class API {
};
}

/** Returns the url to the report dialog endpoint. */
public getReportDialogEndpoint(
dialogOptions: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
user?: { name?: string; email?: string };
} = {},
): string {
const dsn = this.getDsn();
const endpoint = `${this.getBaseApiEndpoint()}embed/error-page/`;

const encodedOptions = [];
encodedOptions.push(`dsn=${dsn.toString()}`);
for (const key in dialogOptions) {
if (key === 'dsn') {
continue;
}

if (key === 'user') {
if (!dialogOptions.user) {
continue;
}
if (dialogOptions.user.name) {
encodedOptions.push(`name=${encodeURIComponent(dialogOptions.user.name)}`);
}
if (dialogOptions.user.email) {
encodedOptions.push(`email=${encodeURIComponent(dialogOptions.user.email)}`);
}
} else {
encodedOptions.push(`${encodeURIComponent(key)}=${encodeURIComponent(dialogOptions[key] as string)}`);
}
}
if (encodedOptions.length) {
return `${endpoint}?${encodedOptions.join('&')}`;
}

return endpoint;
Comment on lines -134 to -138
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this logic because encodedOptions.push(dsn=${dsn.toString()}); meant that the return endpoint; would never be hit

}

/** Returns the envelope endpoint URL. */
private _getEnvelopeEndpoint(): string {
return this._getIngestEndpoint('envelope');
Expand Down Expand Up @@ -165,3 +124,46 @@ export class API {
return urlEncode(auth);
}
}

/** Returns the prefix to construct Sentry ingestion API endpoints. */
function getBaseApiEndpoint(dsn: Dsn): string {
const protocol = dsn.protocol ? `${dsn.protocol}:` : '';
const port = dsn.port ? `:${dsn.port}` : '';
return `${protocol}//${dsn.host}${port}${dsn.path ? `/${dsn.path}` : ''}/api/`;
}

/** Returns the url to the report dialog endpoint. */
export function getReportDialogEndpoint(
dsnLike: DsnLike,
dialogOptions: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
user?: { name?: string; email?: string };
},
): string {
const dsn = new Dsn(dsnLike);
const endpoint = `${getBaseApiEndpoint(dsn)}embed/error-page/`;

let encodedOptions = `dsn=${dsn.toString()}`;
for (const key in dialogOptions) {
if (key === 'dsn') {
continue;
}

if (key === 'user') {
if (!dialogOptions.user) {
continue;
}
if (dialogOptions.user.name) {
encodedOptions += `&name=${encodeURIComponent(dialogOptions.user.name)}`;
}
if (dialogOptions.user.email) {
encodedOptions += `&email=${encodeURIComponent(dialogOptions.user.email)}`;
}
} else {
encodedOptions += `&${encodeURIComponent(key)}=${encodeURIComponent(dialogOptions[key] as string)}`;
}
}

return `${endpoint}?${encodedOptions}`;
}
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export {
withScope,
} from '@sentry/minimal';
export { addGlobalEventProcessor, getCurrentHub, getHubFromCarrier, Hub, makeMain, Scope } from '@sentry/hub';
export { API } from './api';
export { API, getReportDialogEndpoint } from './api';
export { BaseClient } from './baseclient';
export { BackendClass, BaseBackend } from './basebackend';
export { eventToSentryRequest, sessionToSentryRequest } from './request';
Expand Down
114 changes: 78 additions & 36 deletions packages/core/test/lib/api.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Dsn } from '@sentry/utils';

import { API } from '../../src/api';
import { API, getReportDialogEndpoint } from '../../src/api';

const ingestDsn = 'https://abc@xxxx.ingest.sentry.io:1234/subpath/123';
const dsnPublic = 'https://abc@sentry.io:1234/subpath/123';
Expand Down Expand Up @@ -37,44 +37,86 @@ describe('API', () => {
});
});

test('getReportDialogEndpoint', () => {
expect(new API(ingestDsn).getReportDialogEndpoint({})).toEqual(
'https://xxxx.ingest.sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@xxxx.ingest.sentry.io:1234/subpath/123',
);

expect(new API(dsnPublic).getReportDialogEndpoint({})).toEqual(
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@sentry.io:1234/subpath/123',
);
expect(
new API(dsnPublic).getReportDialogEndpoint({
eventId: 'abc',
testy: '2',
}),
).toEqual(
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@sentry.io:1234/subpath/123&eventId=abc&testy=2',
);

expect(
new API(dsnPublic).getReportDialogEndpoint({
eventId: 'abc',
user: {
email: 'email',
name: 'yo',
describe('getReportDialogEndpoint', () => {
test.each([
[
'with Ingest DSN',
ingestDsn,
{},
'https://xxxx.ingest.sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@xxxx.ingest.sentry.io:1234/subpath/123',
],
[
'with Public DSN',
dsnPublic,
{},
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@sentry.io:1234/subpath/123',
],
[
'with Public DSN and dynamic options',
dsnPublic,
{ eventId: 'abc', testy: '2' },
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@sentry.io:1234/subpath/123&eventId=abc&testy=2',
],
[
'with Public DSN, dynamic options and user name and email',
dsnPublic,
{
eventId: 'abc',
user: {
email: 'email',
name: 'yo',
},
},
}),
).toEqual(
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@sentry.io:1234/subpath/123&eventId=abc&name=yo&email=email',
);

expect(
new API(dsnPublic).getReportDialogEndpoint({
eventId: 'abc',
user: undefined,
}),
).toEqual(
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@sentry.io:1234/subpath/123&eventId=abc',
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@sentry.io:1234/subpath/123&eventId=abc&name=yo&email=email',
],
[
'with Public DSN and user name',
dsnPublic,
{
user: {
name: 'yo',
},
},
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@sentry.io:1234/subpath/123&name=yo',
],
[
'with Public DSN and user email',
dsnPublic,
{
user: {
email: 'email',
},
},
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@sentry.io:1234/subpath/123&email=email',
],
[
'with Public DSN, dynamic options and undefined user',
dsnPublic,
{
eventId: 'abc',
user: undefined,
},
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@sentry.io:1234/subpath/123&eventId=abc',
],
[
'with Public DSN and undefined user',
dsnPublic,
{ user: undefined },
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://abc@sentry.io:1234/subpath/123',
],
])(
'%s',
(
_: string,
dsn: Parameters<typeof getReportDialogEndpoint>[0],
options: Parameters<typeof getReportDialogEndpoint>[1],
output: ReturnType<typeof getReportDialogEndpoint>,
) => {
expect(getReportDialogEndpoint(dsn, options)).toBe(output);
},
);
});

test('getDsn', () => {
expect(new API(dsnPublic).getDsn()).toEqual(new Dsn(dsnPublic));
});
Expand Down