Skip to content

Commit

Permalink
Merge pull request #10875 from getsentry/abhi-7.104.0-release
Browse files Browse the repository at this point in the history
meta: CHANGELOG for 7.104.0
  • Loading branch information
AbhiPrasad committed Feb 29, 2024
2 parents 763eb1f + 868a20e commit 9d2f623
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 10 deletions.
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,34 @@

- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott

## 7.104.0

### Important Changes

- **feat(performance): create Interaction standalone spans on inp events (#10709)**

This release adds support for the INP web vital. This is currently only supported for Saas Sentry, and product support
is released with the upcoming `24.3.0` release of self-hosted.

To opt-in to this feature, you can use the `enableInp` option in the `browserTracingIntegration`:

```js
Sentry.init({
integrations: [
Sentry.browserTracingIntegration({
enableInp: true,
});
]
})
```

### Other Changes

- feat(feedback): Flush replays when feedback form opens (#10567)
- feat(profiling-node): Expose `nodeProfilingIntegration` (#10864)
- fix(profiling-node): Fix dependencies to point to current versions (#10861)
- fix(replay): Add `errorHandler` for replayCanvas integration (#10796)

## 7.103.0

### Important Changes
Expand Down
Original file line number Diff line number Diff line change
@@ -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',
});
},
);
10 changes: 5 additions & 5 deletions packages/feedback/src/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,17 @@ export class Feedback implements Integration {
private _hasInsertedActorStyles: boolean;

public constructor({
autoInject = true,
id = 'sentry-feedback',
isEmailRequired = false,
isNameRequired = false,
showBranding = true,
autoInject = true,
showEmail = true,
showName = true,
useSentryUser = {
email: 'email',
name: 'username',
},
isEmailRequired = false,
isNameRequired = false,

themeDark,
themeLight,
Expand Down Expand Up @@ -123,9 +123,9 @@ export class Feedback implements Integration {
this._hasInsertedActorStyles = false;

this.options = {
id,
showBranding,
autoInject,
showBranding,
id,
isEmailRequired,
isNameRequired,
showEmail,
Expand Down
3 changes: 2 additions & 1 deletion packages/feedback/src/util/sendFeedbackRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export async function sendFeedbackRequest(
}

const feedbackEvent = await prepareFeedbackEvent({
scope,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
scope: scope as any,
client,
event: baseEvent,
});
Expand Down
24 changes: 23 additions & 1 deletion packages/feedback/src/widget/createWidget.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getCurrentScope } from '@sentry/core';
import { getClient, getCurrentScope } from '@sentry/core';
import { logger } from '@sentry/utils';

import type { FeedbackFormData, FeedbackInternalOptions, FeedbackWidget } from '../types';
Expand All @@ -9,6 +9,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
Expand Down Expand Up @@ -124,6 +126,24 @@ export function createWidget({
}
}

/**
* Internal handler when dialog is opened
*/
function handleOpenDialog(): void {
// Flush replay if integration exists
const client = getClient();
const replay =
client &&
client.getIntegrationByName &&
client.getIntegrationByName<{ name: string; flush: () => Promise<void>; setupOnce: () => void }>('Replay');
if (!replay) {
return;
}
replay.flush().catch(err => {
DEBUG_BUILD && logger.error(err);
});
}

/**
* Displays the default actor
*/
Expand Down Expand Up @@ -156,6 +176,7 @@ export function createWidget({
if (options.onFormOpen) {
options.onFormOpen();
}
handleOpenDialog();
return;
}

Expand Down Expand Up @@ -208,6 +229,7 @@ export function createWidget({
if (options.onFormOpen) {
options.onFormOpen();
}
handleOpenDialog();
} catch (err) {
// TODO: Error handling?
logger.error(err);
Expand Down
15 changes: 14 additions & 1 deletion packages/replay-canvas/src/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,20 @@ export const _replayCanvasIntegration = ((options: Partial<ReplayCanvasOptions>
enableManualSnapshot,
recordCanvas: true,
getCanvasManager: (options: CanvasManagerOptions) => {
const manager = new CanvasManager({ ...options, enableManualSnapshot });
const manager = new CanvasManager({
...options,
enableManualSnapshot,
errorHandler: (err: unknown) => {
try {
if (typeof err === 'object') {
(err as Error & { __rrweb__?: boolean }).__rrweb__ = true;
}
} catch (error) {
// ignore errors here
// this can happen if the error is frozen or does not allow mutation for other reasons
}
},
});
canvasManagerResolve(manager);
return manager;
},
Expand Down
2 changes: 0 additions & 2 deletions packages/replay/src/util/addGlobalListeners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,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;
}
Expand Down

0 comments on commit 9d2f623

Please sign in to comment.