From c45d03f1d18f625b461da09fd3fd333622b91565 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 7 Feb 2024 19:39:10 -0500 Subject: [PATCH 1/6] feat(feedback): Auto start buffering replays if enabled and flush on form open * By default (can be disabled), if replay integration exists, start buffering * Flush replay when the feedback form is first opened instead of at submit time We are making this change because we have noticed a lot of feedback replays only consist of the user submitting the feedback and not what they did prior to submitting feedback. This may result in false positives if users open but do not submit feedback, but this should make replays from feedback more useful. --- .../{ => hasSampling}/init.js | 0 .../hasSampling/test.ts | 107 ++++++++++++++++++ .../noSampling/init.js | 18 +++ .../noSampling/test.ts | 30 +++++ .../feedback/captureFeedbackAndReplay/test.ts | 91 --------------- packages/feedback/package.json | 3 + packages/feedback/src/integration.ts | 38 ++++++- packages/feedback/src/types/index.ts | 5 + packages/feedback/src/widget/createWidget.ts | 26 ++++- .../feedback/test/widget/createWidget.test.ts | 1 + .../replay/src/util/addGlobalListeners.ts | 2 - 11 files changed, 221 insertions(+), 100 deletions(-) rename dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/{ => hasSampling}/init.js (100%) create mode 100644 dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/hasSampling/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/init.js create mode 100644 dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/test.ts delete mode 100644 dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/test.ts diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/init.js b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/hasSampling/init.js similarity index 100% rename from dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/init.js rename to dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/hasSampling/init.js diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/hasSampling/test.ts b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/hasSampling/test.ts new file mode 100644 index 000000000000..6868caf99545 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/hasSampling/test.ts @@ -0,0 +1,107 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { envelopeRequestParser, getEnvelopeType } from '../../../../utils/helpers'; +import { getCustomRecordingEvents, getReplayEvent, waitForReplayRequest } from '../../../../utils/replayHelpers'; + +sentryTest( + 'should capture feedback (@sentry-internal/feedback import)', + async ({ forceFlushReplay, getLocalTestPath, page }) => { + if (process.env.PW_BUNDLE) { + sentryTest.skip(); + } + + const reqPromise0 = waitForReplayRequest(page, 0); + const reqPromise1 = waitForReplayRequest(page, 1); + const reqPromise2 = waitForReplayRequest(page, 2); + const feedbackRequestPromise = page.waitForResponse(res => { + const req = res.request(); + + const postData = req.postData(); + if (!postData) { + return false; + } + + try { + return getEnvelopeType(req) === 'feedback'; + } catch (err) { + return false; + } + }); + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestPath({ testDir: __dirname }); + + const [, , replayReq0] = await Promise.all([page.goto(url), page.getByText('Report a Bug').click(), reqPromise0]); + + // Inputs are slow, these need to be serial + await page.locator('[name="name"]').fill('Jane Doe'); + await page.locator('[name="email"]').fill('janedoe@example.org'); + await page.locator('[name="message"]').fill('my example feedback'); + + // Force flush here, as inputs are slow and can cause click event to be in unpredictable segments + await Promise.all([forceFlushReplay(), reqPromise1]); + + const [, feedbackResp, replayReq2] = await Promise.all([ + page.getByLabel('Send Bug Report').click(), + feedbackRequestPromise, + reqPromise2, + ]); + + const feedbackEvent = envelopeRequestParser(feedbackResp.request()); + const replayEvent = getReplayEvent(replayReq0); + // Feedback breadcrumb is on second segment because we flush when "Report a Bug" is clicked + // And then the breadcrumb is sent when feedback form is submitted + const { breadcrumbs } = getCustomRecordingEvents(replayReq2); + + expect(breadcrumbs).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + category: 'sentry.feedback', + data: { feedbackId: expect.any(String) }, + timestamp: expect.any(Number), + type: 'default', + }), + ]), + ); + + expect(feedbackEvent).toEqual({ + type: 'feedback', + breadcrumbs: expect.any(Array), + contexts: { + feedback: { + contact_email: 'janedoe@example.org', + message: 'my example feedback', + name: 'Jane Doe', + replay_id: replayEvent.event_id, + source: 'widget', + url: expect.stringContaining('/dist/index.html'), + }, + }, + level: 'info', + timestamp: expect.any(Number), + event_id: expect.stringMatching(/\w{32}/), + environment: 'production', + sdk: { + integrations: expect.arrayContaining(['Feedback']), + version: expect.any(String), + name: 'sentry.javascript.browser', + packages: expect.anything(), + }, + request: { + url: expect.stringContaining('/dist/index.html'), + headers: { + 'User-Agent': expect.stringContaining(''), + }, + }, + platform: 'javascript', + }); + }, +); diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/init.js b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/init.js new file mode 100644 index 000000000000..e9a3482e83b0 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/init.js @@ -0,0 +1,18 @@ +import { Feedback } from '@sentry-internal/feedback'; +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + replaysOnErrorSampleRate: 0, + replaysSessionSampleRate: 0, + integrations: [ + new Sentry.Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, + }), + new Feedback(), + ], +}); diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/test.ts b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/test.ts new file mode 100644 index 000000000000..3886d2221eeb --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/test.ts @@ -0,0 +1,30 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplayEvent, waitForReplayRequest } from '../../../../utils/replayHelpers'; + +sentryTest( + 'should capture feedback with no replay sampling when Form opens (@sentry-internal/feedback import)', + async ({ getLocalTestPath, page }) => { + if (process.env.PW_BUNDLE) { + sentryTest.skip(); + } + + const reqPromise0 = waitForReplayRequest(page, 0); + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestPath({ testDir: __dirname }); + + const [, , replayReq] = await Promise.all([page.goto(url), page.getByText('Report a Bug').click(), reqPromise0]); + + const replayEvent = getReplayEvent(replayReq); + expect(replayEvent.segment_id).toBe(0); + expect(replayEvent.replay_type).toBe('buffer'); + }, +); diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/test.ts b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/test.ts deleted file mode 100644 index 057b5d43a1c8..000000000000 --- a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../utils/fixtures'; -import { envelopeRequestParser, getEnvelopeType } from '../../../utils/helpers'; -import { getCustomRecordingEvents, getReplayEvent, waitForReplayRequest } from '../../../utils/replayHelpers'; - -sentryTest('should capture feedback (@sentry-internal/feedback import)', async ({ getLocalTestPath, page }) => { - if (process.env.PW_BUNDLE) { - sentryTest.skip(); - } - - const reqPromise0 = waitForReplayRequest(page, 0); - const feedbackRequestPromise = page.waitForResponse(res => { - const req = res.request(); - - const postData = req.postData(); - if (!postData) { - return false; - } - - try { - return getEnvelopeType(req) === 'feedback'; - } catch (err) { - return false; - } - }); - - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), - }); - }); - - const url = await getLocalTestPath({ testDir: __dirname }); - - await page.goto(url); - await page.getByText('Report a Bug').click(); - await page.locator('[name="name"]').fill('Jane Doe'); - await page.locator('[name="email"]').fill('janedoe@example.org'); - await page.locator('[name="message"]').fill('my example feedback'); - await page.getByLabel('Send Bug Report').click(); - - const [feedbackResp, replayReq] = await Promise.all([feedbackRequestPromise, reqPromise0]); - - const feedbackEvent = envelopeRequestParser(feedbackResp.request()); - const replayEvent = getReplayEvent(replayReq); - const { breadcrumbs } = getCustomRecordingEvents(replayReq); - - expect(breadcrumbs).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - category: 'sentry.feedback', - data: { feedbackId: expect.any(String) }, - }), - ]), - ); - - expect(feedbackEvent).toEqual({ - type: 'feedback', - breadcrumbs: expect.any(Array), - contexts: { - feedback: { - contact_email: 'janedoe@example.org', - message: 'my example feedback', - name: 'Jane Doe', - replay_id: replayEvent.event_id, - source: 'widget', - url: expect.stringContaining('/dist/index.html'), - }, - }, - level: 'info', - timestamp: expect.any(Number), - event_id: expect.stringMatching(/\w{32}/), - environment: 'production', - sdk: { - integrations: expect.arrayContaining(['Feedback']), - version: expect.any(String), - name: 'sentry.javascript.browser', - packages: expect.anything(), - }, - request: { - url: expect.stringContaining('/dist/index.html'), - headers: { - 'User-Agent': expect.stringContaining(''), - }, - }, - platform: 'javascript', - }); -}); diff --git a/packages/feedback/package.json b/packages/feedback/package.json index 060defb0510c..89547f4f47d7 100644 --- a/packages/feedback/package.json +++ b/packages/feedback/package.json @@ -33,6 +33,9 @@ "@sentry/types": "7.100.0", "@sentry/utils": "7.100.0" }, + "devDependencies": { + "@sentry/replay": "7.100.0" + }, "scripts": { "build": "run-p build:transpile build:types build:bundle", "build:transpile": "rollup -c rollup.npm.config.mjs", diff --git a/packages/feedback/src/integration.ts b/packages/feedback/src/integration.ts index 501f844abeaa..20f3f715ce17 100644 --- a/packages/feedback/src/integration.ts +++ b/packages/feedback/src/integration.ts @@ -1,4 +1,5 @@ -import type { Integration, IntegrationFn } from '@sentry/types'; +import { type replayIntegration } from '@sentry/replay'; +import type { BaseTransportOptions, Client, ClientOptions, Integration, IntegrationFn } from '@sentry/types'; import { isBrowser, logger } from '@sentry/utils'; import { @@ -79,17 +80,18 @@ export class Feedback implements Integration { private _hasInsertedActorStyles: boolean; public constructor({ + autoInject = true, id = 'sentry-feedback', + includeReplay = true, + isEmailRequired = false, + isNameRequired = false, showBranding = true, - autoInject = true, showEmail = true, showName = true, useSentryUser = { email: 'email', name: 'username', }, - isEmailRequired = false, - isNameRequired = false, themeDark, themeLight, @@ -123,9 +125,10 @@ export class Feedback implements Integration { this._hasInsertedActorStyles = false; this.options = { - id, - showBranding, autoInject, + showBranding, + id, + includeReplay, isEmailRequired, isNameRequired, showEmail, @@ -185,6 +188,29 @@ export class Feedback implements Integration { } } + /** + * Hook that is called after all integrations are setup. This is used to + * integrate with the Replay integration to save a replay when Feedback modal + * is opened. + */ + public afterAllSetup(client: Client>): void { + if (!this.options.includeReplay) { + return; + } + + const replay = client.getIntegrationByName>('Replay'); + + if (!replay) { + return; + } + + try { + replay.startBuffering(); + } catch (err) { + DEBUG_BUILD && logger.error(err); + } + } + /** * Allows user to open the dialog box. Creates a new widget if * `autoInject` was false, otherwise re-uses the default widget that was diff --git a/packages/feedback/src/types/index.ts b/packages/feedback/src/types/index.ts index c2642b54d09c..e0c6b81ce98e 100644 --- a/packages/feedback/src/types/index.ts +++ b/packages/feedback/src/types/index.ts @@ -72,6 +72,11 @@ export interface FeedbackGeneralConfiguration { */ showName: boolean; + /** + * Should Feedback attempt to include a Session Replay if the integration is installed? + */ + includeReplay: boolean; + /** * Fill in email/name input fields with Sentry user context if it exists. * The value of the email/name keys represent the properties of your user context. diff --git a/packages/feedback/src/widget/createWidget.ts b/packages/feedback/src/widget/createWidget.ts index b5e414803121..eba78b7e2eba 100644 --- a/packages/feedback/src/widget/createWidget.ts +++ b/packages/feedback/src/widget/createWidget.ts @@ -1,4 +1,5 @@ -import { getCurrentScope } from '@sentry/core'; +import { getClient, getCurrentScope } from '@sentry/core'; +import { type replayIntegration } from '@sentry/replay'; import { logger } from '@sentry/utils'; import type { FeedbackFormData, FeedbackInternalOptions, FeedbackWidget } from '../types'; @@ -9,6 +10,8 @@ import type { DialogComponent } from './Dialog'; import { Dialog } from './Dialog'; import { SuccessMessage } from './SuccessMessage'; +import { DEBUG_BUILD } from '../debug-build'; + interface CreateWidgetParams { /** * Shadow DOM to append to @@ -124,6 +127,25 @@ export function createWidget({ } } + /** + * Internal handler when dialog is opened + */ + function handleOpenDialog({ includeReplay }: { includeReplay?: boolean } = {}): void { + if (!includeReplay) { + return; + } + + // Flush replay if integration exists + const client = getClient(); + const replay = client && client.getIntegrationByName>('Replay'); + if (!replay) { + return; + } + replay.flush().catch(err => { + DEBUG_BUILD && logger.error(err); + }); + } + /** * Displays the default actor */ @@ -156,6 +178,7 @@ export function createWidget({ if (options.onFormOpen) { options.onFormOpen(); } + handleOpenDialog({ includeReplay: options.includeReplay }); return; } @@ -208,6 +231,7 @@ export function createWidget({ if (options.onFormOpen) { options.onFormOpen(); } + handleOpenDialog({ includeReplay: options.includeReplay }); } catch (err) { // TODO: Error handling? logger.error(err); diff --git a/packages/feedback/test/widget/createWidget.test.ts b/packages/feedback/test/widget/createWidget.test.ts index c2a5f50daebc..a196bfefe11a 100644 --- a/packages/feedback/test/widget/createWidget.test.ts +++ b/packages/feedback/test/widget/createWidget.test.ts @@ -30,6 +30,7 @@ const DEFAULT_OPTIONS = { email: 'email', name: 'username', }, + includeReplay: true, isEmailRequired: false, isNameRequired: false, diff --git a/packages/replay/src/util/addGlobalListeners.ts b/packages/replay/src/util/addGlobalListeners.ts index 9b57e7dafec8..a5900fdea696 100644 --- a/packages/replay/src/util/addGlobalListeners.ts +++ b/packages/replay/src/util/addGlobalListeners.ts @@ -59,8 +59,6 @@ export function addGlobalListeners(replay: ReplayContainer): void { const replayId = replay.getSessionId(); if (options && options.includeReplay && replay.isEnabled() && replayId) { // This should never reject - // eslint-disable-next-line @typescript-eslint/no-floating-promises - replay.flush(); if (feedbackEvent.contexts && feedbackEvent.contexts.feedback) { feedbackEvent.contexts.feedback.replay_id = replayId; } From 13f8a475e2a86d038d99d14b975d2e8134dbef82 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Thu, 29 Feb 2024 10:57:27 -0500 Subject: [PATCH 2/6] remove auto-start buffering --- packages/feedback/src/integration.ts | 28 +------------------- packages/feedback/src/types/index.ts | 5 ---- packages/feedback/src/widget/createWidget.ts | 13 +++------ 3 files changed, 5 insertions(+), 41 deletions(-) diff --git a/packages/feedback/src/integration.ts b/packages/feedback/src/integration.ts index 20f3f715ce17..b70bf008d24d 100644 --- a/packages/feedback/src/integration.ts +++ b/packages/feedback/src/integration.ts @@ -1,5 +1,4 @@ -import { type replayIntegration } from '@sentry/replay'; -import type { BaseTransportOptions, Client, ClientOptions, Integration, IntegrationFn } from '@sentry/types'; +import type { Integration, IntegrationFn } from '@sentry/types'; import { isBrowser, logger } from '@sentry/utils'; import { @@ -82,7 +81,6 @@ export class Feedback implements Integration { public constructor({ autoInject = true, id = 'sentry-feedback', - includeReplay = true, isEmailRequired = false, isNameRequired = false, showBranding = true, @@ -128,7 +126,6 @@ export class Feedback implements Integration { autoInject, showBranding, id, - includeReplay, isEmailRequired, isNameRequired, showEmail, @@ -188,29 +185,6 @@ export class Feedback implements Integration { } } - /** - * Hook that is called after all integrations are setup. This is used to - * integrate with the Replay integration to save a replay when Feedback modal - * is opened. - */ - public afterAllSetup(client: Client>): void { - if (!this.options.includeReplay) { - return; - } - - const replay = client.getIntegrationByName>('Replay'); - - if (!replay) { - return; - } - - try { - replay.startBuffering(); - } catch (err) { - DEBUG_BUILD && logger.error(err); - } - } - /** * Allows user to open the dialog box. Creates a new widget if * `autoInject` was false, otherwise re-uses the default widget that was diff --git a/packages/feedback/src/types/index.ts b/packages/feedback/src/types/index.ts index e0c6b81ce98e..c2642b54d09c 100644 --- a/packages/feedback/src/types/index.ts +++ b/packages/feedback/src/types/index.ts @@ -72,11 +72,6 @@ export interface FeedbackGeneralConfiguration { */ showName: boolean; - /** - * Should Feedback attempt to include a Session Replay if the integration is installed? - */ - includeReplay: boolean; - /** * Fill in email/name input fields with Sentry user context if it exists. * The value of the email/name keys represent the properties of your user context. diff --git a/packages/feedback/src/widget/createWidget.ts b/packages/feedback/src/widget/createWidget.ts index eba78b7e2eba..77b123c351f7 100644 --- a/packages/feedback/src/widget/createWidget.ts +++ b/packages/feedback/src/widget/createWidget.ts @@ -1,5 +1,4 @@ import { getClient, getCurrentScope } from '@sentry/core'; -import { type replayIntegration } from '@sentry/replay'; import { logger } from '@sentry/utils'; import type { FeedbackFormData, FeedbackInternalOptions, FeedbackWidget } from '../types'; @@ -130,14 +129,10 @@ export function createWidget({ /** * Internal handler when dialog is opened */ - function handleOpenDialog({ includeReplay }: { includeReplay?: boolean } = {}): void { - if (!includeReplay) { - return; - } - + function handleOpenDialog(): void { // Flush replay if integration exists const client = getClient(); - const replay = client && client.getIntegrationByName>('Replay'); + const replay = client && client.getIntegrationByName('Replay') as {flush: () => Promise}; if (!replay) { return; } @@ -178,7 +173,7 @@ export function createWidget({ if (options.onFormOpen) { options.onFormOpen(); } - handleOpenDialog({ includeReplay: options.includeReplay }); + handleOpenDialog(); return; } @@ -231,7 +226,7 @@ export function createWidget({ if (options.onFormOpen) { options.onFormOpen(); } - handleOpenDialog({ includeReplay: options.includeReplay }); + handleOpenDialog(); } catch (err) { // TODO: Error handling? logger.error(err); From 5420b936b27575fcb302113c332a71d3c7c5612e Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Thu, 29 Feb 2024 10:59:09 -0500 Subject: [PATCH 3/6] remove dev deps --- packages/feedback/package.json | 3 --- packages/feedback/test/widget/createWidget.test.ts | 1 - 2 files changed, 4 deletions(-) diff --git a/packages/feedback/package.json b/packages/feedback/package.json index deeb9e65eb09..3ae1af389b07 100644 --- a/packages/feedback/package.json +++ b/packages/feedback/package.json @@ -33,9 +33,6 @@ "@sentry/types": "8.0.0-alpha.0", "@sentry/utils": "8.0.0-alpha.0" }, - "devDependencies": { - "@sentry/replay": "7.100.0" - }, "scripts": { "build": "run-p build:transpile build:types build:bundle", "build:transpile": "rollup -c rollup.npm.config.mjs", diff --git a/packages/feedback/test/widget/createWidget.test.ts b/packages/feedback/test/widget/createWidget.test.ts index a196bfefe11a..c2a5f50daebc 100644 --- a/packages/feedback/test/widget/createWidget.test.ts +++ b/packages/feedback/test/widget/createWidget.test.ts @@ -30,7 +30,6 @@ const DEFAULT_OPTIONS = { email: 'email', name: 'username', }, - includeReplay: true, isEmailRequired: false, isNameRequired: false, From df47d958f48cf2c22946b080e28ee19cf507167a Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Thu, 29 Feb 2024 11:00:24 -0500 Subject: [PATCH 4/6] remove noSampling tests --- .../noSampling/init.js | 18 ----------- .../noSampling/test.ts | 30 ------------------- 2 files changed, 48 deletions(-) delete mode 100644 dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/init.js delete mode 100644 dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/test.ts diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/init.js b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/init.js deleted file mode 100644 index e9a3482e83b0..000000000000 --- a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/init.js +++ /dev/null @@ -1,18 +0,0 @@ -import { Feedback } from '@sentry-internal/feedback'; -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - replaysOnErrorSampleRate: 0, - replaysSessionSampleRate: 0, - integrations: [ - new Sentry.Replay({ - flushMinDelay: 200, - flushMaxDelay: 200, - minReplayDuration: 0, - }), - new Feedback(), - ], -}); diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/test.ts b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/test.ts deleted file mode 100644 index 3886d2221eeb..000000000000 --- a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/noSampling/test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../../utils/fixtures'; -import { getReplayEvent, waitForReplayRequest } from '../../../../utils/replayHelpers'; - -sentryTest( - 'should capture feedback with no replay sampling when Form opens (@sentry-internal/feedback import)', - async ({ getLocalTestPath, page }) => { - if (process.env.PW_BUNDLE) { - sentryTest.skip(); - } - - const reqPromise0 = waitForReplayRequest(page, 0); - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), - }); - }); - - const url = await getLocalTestPath({ testDir: __dirname }); - - const [, , replayReq] = await Promise.all([page.goto(url), page.getByText('Report a Bug').click(), reqPromise0]); - - const replayEvent = getReplayEvent(replayReq); - expect(replayEvent.segment_id).toBe(0); - expect(replayEvent.replay_type).toBe('buffer'); - }, -); From 9053bcf18c72ee2b7d2ce49a995b12d4a64dab6c Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Thu, 29 Feb 2024 11:04:24 -0500 Subject: [PATCH 5/6] lint --- packages/feedback/src/widget/createWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/feedback/src/widget/createWidget.ts b/packages/feedback/src/widget/createWidget.ts index 77b123c351f7..1c9beaf0c3f6 100644 --- a/packages/feedback/src/widget/createWidget.ts +++ b/packages/feedback/src/widget/createWidget.ts @@ -132,7 +132,7 @@ export function createWidget({ function handleOpenDialog(): void { // Flush replay if integration exists const client = getClient(); - const replay = client && client.getIntegrationByName('Replay') as {flush: () => Promise}; + const replay = client && (client.getIntegrationByName('Replay') as { flush: () => Promise }); if (!replay) { return; } From fd6cbd6814c9be6cdb5cc05bf725000e67a3320b Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Thu, 29 Feb 2024 11:16:20 -0500 Subject: [PATCH 6/6] fix types --- packages/feedback/src/widget/createWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/feedback/src/widget/createWidget.ts b/packages/feedback/src/widget/createWidget.ts index 1c9beaf0c3f6..05b52ca64725 100644 --- a/packages/feedback/src/widget/createWidget.ts +++ b/packages/feedback/src/widget/createWidget.ts @@ -132,7 +132,7 @@ export function createWidget({ function handleOpenDialog(): void { // Flush replay if integration exists const client = getClient(); - const replay = client && (client.getIntegrationByName('Replay') as { flush: () => Promise }); + const replay = client && client.getIntegrationByName<{ name: string; flush: () => Promise }>('Replay'); if (!replay) { return; }