diff --git a/packages/feedback/src/sendFeedback.ts b/packages/feedback/src/sendFeedback.ts index e149a290e82a..c77013602d6b 100644 --- a/packages/feedback/src/sendFeedback.ts +++ b/packages/feedback/src/sendFeedback.ts @@ -10,13 +10,14 @@ interface SendFeedbackParams { name?: string; email?: string; url?: string; + source?: string; } /** * Public API to send a Feedback item to Sentry */ export function sendFeedback( - { name, email, message, url = getLocationHref() }: SendFeedbackParams, + { name, email, message, source = 'api', url = getLocationHref() }: SendFeedbackParams, { includeReplay = true }: SendFeedbackOptions = {}, ): ReturnType { const client = getCurrentHub().getClient(); @@ -37,6 +38,7 @@ export function sendFeedback( message, url, replay_id: replayId, + source, }, }); } diff --git a/packages/feedback/src/types/index.ts b/packages/feedback/src/types/index.ts index 6269e8a697a8..5772e6e8176b 100644 --- a/packages/feedback/src/types/index.ts +++ b/packages/feedback/src/types/index.ts @@ -12,6 +12,7 @@ export interface SendFeedbackData { email?: string; replay_id?: string; name?: string; + source?: string; }; } diff --git a/packages/feedback/src/util/handleFeedbackSubmit.ts b/packages/feedback/src/util/handleFeedbackSubmit.ts index 6e7b7c014de4..4e8f233b15fd 100644 --- a/packages/feedback/src/util/handleFeedbackSubmit.ts +++ b/packages/feedback/src/util/handleFeedbackSubmit.ts @@ -29,7 +29,7 @@ export async function handleFeedbackSubmit( dialog.hideError(); try { - const resp = await sendFeedback(feedback, options); + const resp = await sendFeedback({ ...feedback, source: 'widget' }, options); // Success! return resp; diff --git a/packages/feedback/src/util/sendFeedbackRequest.ts b/packages/feedback/src/util/sendFeedbackRequest.ts index 45a3bd493de9..d82375ded4d2 100644 --- a/packages/feedback/src/util/sendFeedbackRequest.ts +++ b/packages/feedback/src/util/sendFeedbackRequest.ts @@ -8,7 +8,7 @@ import { prepareFeedbackEvent } from './prepareFeedbackEvent'; * Send feedback using transport */ export async function sendFeedbackRequest({ - feedback: { message, email, name, replay_id, url }, + feedback: { message, email, name, source, replay_id, url }, }: SendFeedbackData): Promise { const hub = getCurrentHub(); const client = hub.getClient(); @@ -28,6 +28,7 @@ export async function sendFeedbackRequest({ message, replay_id, url, + source, }, }, type: 'feedback', diff --git a/packages/feedback/test/sendFeedback.test.ts b/packages/feedback/test/sendFeedback.test.ts new file mode 100644 index 000000000000..33474e2df673 --- /dev/null +++ b/packages/feedback/test/sendFeedback.test.ts @@ -0,0 +1,43 @@ +import { getCurrentHub } from '@sentry/core'; + +import { sendFeedback } from '../src/sendFeedback'; +import { mockSdk } from './utils/mockSdk'; + +describe('sendFeedback', () => { + it('sends feedback', async () => { + mockSdk(); + const mockTransport = jest.spyOn(getCurrentHub().getClient()!.getTransport()!, 'send'); + + await sendFeedback({ + name: 'doe', + email: 're@example.org', + message: 'mi', + }); + expect(mockTransport).toHaveBeenCalledWith([ + { event_id: expect.any(String), sent_at: expect.any(String) }, + [ + [ + { type: 'feedback' }, + { + breadcrumbs: undefined, + contexts: { + feedback: { + contact_email: 're@example.org', + message: 'mi', + name: 'doe', + replay_id: undefined, + source: 'api', + url: 'http://localhost/', + }, + }, + environment: 'production', + event_id: expect.any(String), + platform: 'javascript', + timestamp: expect.any(Number), + type: 'feedback', + }, + ], + ], + ]); + }); +}); diff --git a/packages/feedback/test/utils/mockSdk.ts b/packages/feedback/test/utils/mockSdk.ts new file mode 100644 index 000000000000..0dbc30c02cb6 --- /dev/null +++ b/packages/feedback/test/utils/mockSdk.ts @@ -0,0 +1,58 @@ +import type { Envelope, Transport, TransportMakeRequestResponse } from '@sentry/types'; + +import type { TestClientOptions } from '../utils/TestClient'; +import { getDefaultClientOptions, init } from '../utils/TestClient'; + +export interface MockSdkParams { + sentryOptions?: Partial; +} + +class MockTransport implements Transport { + send: (request: Envelope) => PromiseLike; + + constructor() { + const send: ((request: Envelope) => PromiseLike) & { + __sentry__baseTransport__?: boolean; + } = jest.fn(async () => { + return { + statusCode: 200, + }; + }); + + send.__sentry__baseTransport__ = true; + this.send = send; + } + + async flush() { + return true; + } + async sendEvent(_e: Event) { + return { + status: 'skipped', + event: 'ok', + type: 'transaction', + }; + } + async sendSession() { + return; + } + async recordLostEvent() { + return; + } + async close() { + return; + } +} + +export async function mockSdk({ sentryOptions }: MockSdkParams = {}): Promise { + init({ + ...getDefaultClientOptions(), + dsn: 'https://dsn@ingest.f00.f00/1', + autoSessionTracking: false, + sendClientReports: false, + transport: () => new MockTransport(), + replaysSessionSampleRate: 0.0, + replaysOnErrorSampleRate: 0.0, + ...sentryOptions, + }); +} diff --git a/packages/feedback/test/widget/createWidget.test.ts b/packages/feedback/test/widget/createWidget.test.ts index 1c39de8f26c1..fb1809de7ecf 100644 --- a/packages/feedback/test/widget/createWidget.test.ts +++ b/packages/feedback/test/widget/createWidget.test.ts @@ -155,6 +155,7 @@ describe('createWidget', () => { message: 'My feedback', url: 'http://localhost/', replay_id: undefined, + source: 'widget', }, }); @@ -194,6 +195,7 @@ describe('createWidget', () => { message: 'My feedback', url: 'http://localhost/', replay_id: undefined, + source: 'widget', }, });