Skip to content

Commit bdd58f2

Browse files
ryan953andrewshie-sentry
authored andcommitted
feat(replay): Show the correct level of each issue in Replay Details breadcrumbs (#97552)
Depends on #97551 Fixes REPLAY-335
1 parent ea4687e commit bdd58f2

File tree

17 files changed

+71
-88
lines changed

17 files changed

+71
-88
lines changed

static/app/components/events/eventReplay/index.spec.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import {EventFixture} from 'sentry-fixture/event';
22
import {OrganizationFixture} from 'sentry-fixture/organization';
33
import {ProjectFixture} from 'sentry-fixture/project';
4+
import {RawReplayErrorFixture} from 'sentry-fixture/replay/error';
45
import {RRWebInitFrameEventsFixture} from 'sentry-fixture/replay/rrweb';
5-
import {ReplayErrorFixture} from 'sentry-fixture/replayError';
66
import {ReplayRecordFixture} from 'sentry-fixture/replayRecord';
77

88
import {render, screen} from 'sentry-test/reactTestingLibrary';
@@ -15,7 +15,7 @@ import {
1515
useReplayOnboardingSidebarPanel,
1616
} from 'sentry/utils/replays/hooks/useReplayOnboarding';
1717
import ReplayReader from 'sentry/utils/replays/replayReader';
18-
import type {ReplayError} from 'sentry/views/replays/types';
18+
import type {RawReplayError} from 'sentry/utils/replays/types';
1919

2020
jest.mock('sentry/utils/replays/hooks/useReplayOnboarding');
2121
jest.mock('sentry/utils/replays/hooks/useLoadReplayReader');
@@ -32,25 +32,23 @@ jest.mock(
3232
const mockEventTimestamp = new Date('2022-09-22T16:59:41Z');
3333
const mockReplayId = '761104e184c64d439ee1014b72b4d83b';
3434

35-
const mockErrors: ReplayError[] = [
36-
ReplayErrorFixture({
35+
const mockErrors: RawReplayError[] = [
36+
RawReplayErrorFixture({
3737
id: '1',
3838
issue: 'JAVASCRIPT-101',
3939
'issue.id': 101,
40-
'error.value': ['Something bad happened.'],
4140
'error.type': ['error'],
4241
'project.name': 'javascript',
43-
timestamp: mockEventTimestamp.toISOString(),
42+
timestamp: mockEventTimestamp,
4443
title: 'Something bad happened.',
4544
}),
46-
ReplayErrorFixture({
45+
RawReplayErrorFixture({
4746
id: '2',
4847
issue: 'JAVASCRIPT-102',
4948
'issue.id': 102,
50-
'error.value': ['Something bad happened 2.'],
5149
'error.type': ['error'],
5250
'project.name': 'javascript',
53-
timestamp: mockEventTimestamp.toISOString(),
51+
timestamp: mockEventTimestamp,
5452
title: 'Something bad happened 2.',
5553
}),
5654
];

static/app/components/replays/breadcrumbs/errorTitle.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default function CrumbErrorTitle({frame}: {frame: ErrorFrame}) {
1616

1717
return (
1818
<Fragment>
19-
Error:{' '}
19+
{frame.data.level || 'Error'}:{' '}
2020
<Link
2121
to={`/organizations/${organization.slug}/issues/${frame.data.groupId}/events/${frame.data.eventId}/#replay`}
2222
>

static/app/components/replays/header/errorCounts.spec.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {OrganizationFixture} from 'sentry-fixture/organization';
22
import {ProjectFixture} from 'sentry-fixture/project';
3-
import {ReplayErrorFixture} from 'sentry-fixture/replayError';
3+
import {RawReplayErrorFixture} from 'sentry-fixture/replay/error';
44
import {ReplayRecordFixture} from 'sentry-fixture/replayRecord';
55

66
import {render, screen} from 'sentry-test/reactTestingLibrary';
@@ -11,7 +11,7 @@ import ProjectsStore from 'sentry/stores/projectsStore';
1111
const replayRecord = ReplayRecordFixture();
1212
const organization = OrganizationFixture();
1313

14-
const baseErrorProps = {id: '1', issue: '', timestamp: new Date().toISOString()};
14+
const baseErrorProps = {id: '1', issue: '', timestamp: new Date()};
1515

1616
describe('ErrorCounts', () => {
1717
beforeEach(() => {
@@ -43,7 +43,9 @@ describe('ErrorCounts', () => {
4343
});
4444

4545
it('should render an icon & count when all errors come from a single project', async () => {
46-
const errors = [ReplayErrorFixture({...baseErrorProps, 'project.name': 'my-js-app'})];
46+
const errors = [
47+
RawReplayErrorFixture({...baseErrorProps, 'project.name': 'my-js-app'}),
48+
];
4749

4850
render(<ErrorCounts replayErrors={errors} replayRecord={replayRecord} />, {
4951
organization,
@@ -63,9 +65,9 @@ describe('ErrorCounts', () => {
6365

6466
it('should render an icon & count with links when there are errors in two unique projects', async () => {
6567
const errors = [
66-
ReplayErrorFixture({...baseErrorProps, 'project.name': 'my-js-app'}),
67-
ReplayErrorFixture({...baseErrorProps, 'project.name': 'my-py-backend'}),
68-
ReplayErrorFixture({...baseErrorProps, 'project.name': 'my-py-backend'}),
68+
RawReplayErrorFixture({...baseErrorProps, 'project.name': 'my-js-app'}),
69+
RawReplayErrorFixture({...baseErrorProps, 'project.name': 'my-py-backend'}),
70+
RawReplayErrorFixture({...baseErrorProps, 'project.name': 'my-py-backend'}),
6971
];
7072

7173
render(<ErrorCounts replayErrors={errors} replayRecord={replayRecord} />, {
@@ -93,12 +95,12 @@ describe('ErrorCounts', () => {
9395

9496
it('should render multiple icons, but a single count and link, when there are errors in three or more projects', async () => {
9597
const errors = [
96-
ReplayErrorFixture({...baseErrorProps, 'project.name': 'my-js-app'}),
97-
ReplayErrorFixture({...baseErrorProps, 'project.name': 'my-py-backend'}),
98-
ReplayErrorFixture({...baseErrorProps, 'project.name': 'my-py-backend'}),
99-
ReplayErrorFixture({...baseErrorProps, 'project.name': 'my-node-service'}),
100-
ReplayErrorFixture({...baseErrorProps, 'project.name': 'my-node-service'}),
101-
ReplayErrorFixture({...baseErrorProps, 'project.name': 'my-node-service'}),
98+
RawReplayErrorFixture({...baseErrorProps, 'project.name': 'my-js-app'}),
99+
RawReplayErrorFixture({...baseErrorProps, 'project.name': 'my-py-backend'}),
100+
RawReplayErrorFixture({...baseErrorProps, 'project.name': 'my-py-backend'}),
101+
RawReplayErrorFixture({...baseErrorProps, 'project.name': 'my-node-service'}),
102+
RawReplayErrorFixture({...baseErrorProps, 'project.name': 'my-node-service'}),
103+
RawReplayErrorFixture({...baseErrorProps, 'project.name': 'my-node-service'}),
102104
];
103105

104106
render(<ErrorCounts replayErrors={errors} replayRecord={replayRecord} />, {

static/app/components/replays/header/errorCounts.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ import {t, tn} from 'sentry/locale';
1212
import {space} from 'sentry/styles/space';
1313
import type {Project} from 'sentry/types/project';
1414
import {TabKey} from 'sentry/utils/replays/hooks/useActiveReplayTab';
15+
import type {RawReplayError} from 'sentry/utils/replays/types';
1516
import {useLocation} from 'sentry/utils/useLocation';
16-
import type {HydratedReplayRecord, ReplayError} from 'sentry/views/replays/types';
17+
import type {HydratedReplayRecord} from 'sentry/views/replays/types';
1718

1819
type Props = {
19-
replayErrors: ReplayError[];
20+
replayErrors: RawReplayError[];
2021
replayRecord: HydratedReplayRecord;
2122
};
2223

static/app/components/replays/header/replayMetaData.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ import {space} from 'sentry/styles/space';
1111
import EventView from 'sentry/utils/discover/eventView';
1212
import getRouteStringFromRoutes from 'sentry/utils/getRouteStringFromRoutes';
1313
import {TabKey} from 'sentry/utils/replays/hooks/useActiveReplayTab';
14+
import type {RawReplayError} from 'sentry/utils/replays/types';
1415
import {useLocation} from 'sentry/utils/useLocation';
1516
import {useRoutes} from 'sentry/utils/useRoutes';
16-
import type {ReplayError, ReplayRecord} from 'sentry/views/replays/types';
17+
import type {ReplayRecord} from 'sentry/views/replays/types';
1718

1819
interface Props {
19-
replayErrors: ReplayError[];
20+
replayErrors: RawReplayError[];
2021
replayRecord: ReplayRecord;
2122
showDeadRageClicks?: boolean;
2223
}

static/app/components/replays/header/useErrorCountPerProject.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import {useMemo} from 'react';
22
import countBy from 'lodash/countBy';
33

4+
import type {RawReplayError} from 'sentry/utils/replays/types';
45
import useProjects from 'sentry/utils/useProjects';
5-
import type {ReplayError, ReplayRecord} from 'sentry/views/replays/types';
6+
import type {ReplayRecord} from 'sentry/views/replays/types';
67

78
type Props = {
8-
replayErrors: ReplayError[];
9+
replayErrors: RawReplayError[];
910
replayRecord: ReplayRecord;
1011
};
1112

static/app/utils/replays/getDiffTimestamps.spec.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import {
2020
IncrementalSource,
2121
isHydrationErrorFrame,
2222
type RawBreadcrumbFrame,
23+
type RawReplayError,
2324
} from 'sentry/utils/replays/types';
24-
import type {ReplayError} from 'sentry/views/replays/types';
2525

2626
const START_DATE = new Date('2022-06-15T00:40:00.000Z');
2727
const INIT_DATE = new Date('2022-06-15T00:40:00.100Z');
@@ -62,7 +62,7 @@ const RRWEB_EVENTS = [
6262
}),
6363
];
6464

65-
function getMockReplay(rrwebEvents: any[], errors: ReplayError[]) {
65+
function getMockReplay(rrwebEvents: any[], errors: RawReplayError[]) {
6666
const attachments = [...rrwebEvents];
6767
const replay = ReplayReader.factory({
6868
replayRecord,
@@ -77,7 +77,7 @@ function getMockReplay(rrwebEvents: any[], errors: ReplayError[]) {
7777
function getMockReplayWithCrumbFrame(
7878
rrwebEvents: any[],
7979
crumbFrame: RawBreadcrumbFrame,
80-
errors: ReplayError[]
80+
errors: RawReplayError[]
8181
) {
8282
const attachments = [...rrwebEvents];
8383

@@ -155,7 +155,7 @@ describe('getReplayDiffOffsetsFromEvent', () => {
155155
});
156156
const errorEvent = EventFixture({dateCreated: ERROR_DATE.toISOString()});
157157
const {replay} = getMockReplayWithCrumbFrame(RRWEB_EVENTS, rawHydrationCrumbFrame, [
158-
errorEvent as any as ReplayError,
158+
errorEvent as any as RawReplayError,
159159
]);
160160

161161
const [hydratedHydrationCrumbFrame] = hydrateBreadcrumbs(replayRecord, [
@@ -170,7 +170,7 @@ describe('getReplayDiffOffsetsFromEvent', () => {
170170

171171
it('should get offsets when no hydration breadcrumb exists', () => {
172172
const errorEvent = EventFixture({dateCreated: ERROR_DATE.toISOString()});
173-
const {replay} = getMockReplay(RRWEB_EVENTS, [errorEvent as any as ReplayError]);
173+
const {replay} = getMockReplay(RRWEB_EVENTS, [errorEvent as any as RawReplayError]);
174174

175175
expect(getReplayDiffOffsetsFromEvent(replay!, errorEvent)).toEqual({
176176
frameOrEvent: errorEvent,

static/app/utils/replays/hooks/useReplayData.spec.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import type {ReactNode} from 'react';
22
import {duration} from 'moment-timezone';
3+
import {RawReplayErrorFixture} from 'sentry-fixture/replay/error';
34
import {
45
ReplayConsoleEventFixture,
56
ReplayNavigateEventFixture,
67
} from 'sentry-fixture/replay/helpers';
78
import {RRWebInitFrameEventsFixture} from 'sentry-fixture/replay/rrweb';
8-
import {ReplayErrorFixture} from 'sentry-fixture/replayError';
99
import {ReplayRecordFixture} from 'sentry-fixture/replayRecord';
1010

1111
import {initializeOrg} from 'sentry-test/initializeOrg';
@@ -278,31 +278,31 @@ describe('useReplayData', () => {
278278
});
279279

280280
const mockErrorResponse1 = [
281-
ReplayErrorFixture({
281+
RawReplayErrorFixture({
282282
id: ERROR_IDS[0]!,
283283
issue: 'JAVASCRIPT-123E',
284-
timestamp: startedAt.toISOString(),
284+
timestamp: startedAt,
285285
}),
286286
];
287287
const mockErrorResponse2 = [
288-
ReplayErrorFixture({
288+
RawReplayErrorFixture({
289289
id: ERROR_IDS[1]!,
290290
issue: 'JAVASCRIPT-789Z',
291-
timestamp: startedAt.toISOString(),
291+
timestamp: startedAt,
292292
}),
293293
];
294294
const mockErrorResponse3 = [
295-
ReplayErrorFixture({
295+
RawReplayErrorFixture({
296296
id: ERROR_IDS[0]!,
297297
issue: 'JAVASCRIPT-123E',
298-
timestamp: startedAt.toISOString(),
298+
timestamp: startedAt,
299299
}),
300300
];
301301
const mockErrorResponse4 = [
302-
ReplayErrorFixture({
302+
RawReplayErrorFixture({
303303
id: ERROR_IDS[1]!,
304304
issue: 'JAVASCRIPT-789Z',
305-
timestamp: startedAt.toISOString(),
305+
timestamp: startedAt,
306306
}),
307307
];
308308

@@ -418,10 +418,10 @@ describe('useReplayData', () => {
418418
timestamp: startedAt,
419419
});
420420
const mockErrorResponse = [
421-
ReplayErrorFixture({
421+
RawReplayErrorFixture({
422422
id: ERROR_IDS[0]!,
423423
issue: 'JAVASCRIPT-123E',
424-
timestamp: startedAt.toISOString(),
424+
timestamp: startedAt,
425425
}),
426426
];
427427

static/app/utils/replays/hooks/useReplayData.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ import {useApiQuery, useQueryClient} from 'sentry/utils/queryClient';
1111
import useFeedbackEvents from 'sentry/utils/replays/hooks/useFeedbackEvents';
1212
import {useReplayProjectSlug} from 'sentry/utils/replays/hooks/useReplayProjectSlug';
1313
import {mapResponseToReplayRecord} from 'sentry/utils/replays/replayDataUtils';
14+
import type {RawReplayError} from 'sentry/utils/replays/types';
1415
import type RequestError from 'sentry/utils/requestError/requestError';
15-
import type {ReplayError, ReplayRecord} from 'sentry/views/replays/types';
16+
import type {ReplayRecord} from 'sentry/views/replays/types';
1617

1718
type Options = {
1819
/**
@@ -41,7 +42,7 @@ type Options = {
4142
interface Result {
4243
attachmentError: undefined | RequestError[];
4344
attachments: unknown[];
44-
errors: ReplayError[];
45+
errors: RawReplayError[];
4546
fetchError: undefined | RequestError;
4647
isError: boolean;
4748
isPending: boolean;
@@ -200,7 +201,7 @@ function useReplayData({
200201
pages: errorPages,
201202
status: fetchErrorsStatus,
202203
getLastResponseHeader: lastErrorsResponseHeader,
203-
} = useFetchParallelPages<{data: ReplayError[]}>({
204+
} = useFetchParallelPages<{data: RawReplayError[]}>({
204205
enabled: enableErrors,
205206
hits: replayRecord?.count_errors ?? 0,
206207
getQueryKey: getErrorsQueryKey,
@@ -214,15 +215,15 @@ function useReplayData({
214215
(!replayRecord?.count_errors || Boolean(links.next?.results)) &&
215216
fetchErrorsStatus === 'success';
216217
const {pages: extraErrorPages, status: fetchExtraErrorsStatus} =
217-
useFetchSequentialPages<{data: ReplayError[]}>({
218+
useFetchSequentialPages<{data: RawReplayError[]}>({
218219
enabled: enableExtraErrors,
219220
initialCursor: links.next?.cursor,
220221
getQueryKey: getErrorsQueryKey,
221222
perPage: errorsPerPage,
222223
});
223224

224225
const {pages: platformErrorPages, status: fetchPlatformErrorsStatus} =
225-
useFetchSequentialPages<{data: ReplayError[]}>({
226+
useFetchSequentialPages<{data: RawReplayError[]}>({
226227
enabled: true,
227228
getQueryKey: getPlatformErrorsQueryKey,
228229
perPage: errorsPerPage,

static/app/utils/replays/hydrateErrors.spec.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ describe('hydrateErrors', () => {
2525
groupShortId: 'JS-374',
2626
label: '',
2727
labels: [],
28+
level: 'Error',
2829
projectSlug: 'javascript',
2930
},
3031
message: 'A Redirect with :orgId param on customer domain',
@@ -41,6 +42,7 @@ describe('hydrateErrors', () => {
4142
groupShortId: 'JS-374',
4243
label: '',
4344
labels: [],
45+
level: 'Error',
4446
projectSlug: 'javascript',
4547
},
4648
message: 'A Redirect with :orgId param on customer domain',
@@ -57,6 +59,7 @@ describe('hydrateErrors', () => {
5759
groupShortId: 'JS-374',
5860
label: '',
5961
labels: [],
62+
level: 'Error',
6063
projectSlug: 'javascript',
6164
},
6265
message: 'A Redirect with :orgId param on customer domain',

0 commit comments

Comments
 (0)