Skip to content

Commit 50817ac

Browse files
authored
fix(replay): Only call scope.getLastBreadcrumb if available (#6969)
`Scope.getLastBreadcrumb` was introduced quite recently for replay and it generally works fine. Just in the few edge cases, where the base SDK version can't be changed or multiple hubs cause conflicts, Replay will crash when the method is not available on the passed scope. This patch lets `handleScope` early-return `null` in case the `getLastBreadcrumb` method does not exist. This will lead to missing breadcrumbs in the replay but at least it will avoid a crash.
1 parent 0c641cf commit 50817ac

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

packages/replay/src/coreHandlers/handleScope.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ export const handleScopeListener: (replay: ReplayContainer) => (scope: Scope) =>
2626
* An event handler to handle scope changes.
2727
*/
2828
export function handleScope(scope: Scope): Breadcrumb | null {
29-
const newBreadcrumb = scope.getLastBreadcrumb();
29+
// TODO (v8): Remove this guard. This was put in place because we introduced
30+
// Scope.getLastBreadcrumb mid-v7 which caused incompatibilities with older SDKs.
31+
// For now, we'll just return null if the method doesn't exist but we should eventually
32+
// get rid of this guard.
33+
const newBreadcrumb = scope.getLastBreadcrumb && scope.getLastBreadcrumb();
3034

3135
// Listener can be called when breadcrumbs have not changed, so we store the
3236
// reference to the last crumb and only return a crumb if it has changed

packages/replay/test/unit/coreHandlers/handleScope.test.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import type { Breadcrumb, Scope } from '@sentry/types';
33
import * as HandleScope from '../../../src/coreHandlers/handleScope';
44

55
describe('Unit | coreHandlers | handleScope', () => {
6-
const mockHandleScope = jest.spyOn(HandleScope, 'handleScope');
6+
let mockHandleScope: jest.SpyInstance;
7+
8+
beforeEach(() => {
9+
mockHandleScope = jest.spyOn(HandleScope, 'handleScope');
10+
mockHandleScope.mockClear();
11+
});
712

813
it('returns a breadcrumb only if last breadcrumb has changed', function () {
914
const scope = {
@@ -47,4 +52,11 @@ describe('Unit | coreHandlers | handleScope', () => {
4752
expect(mockHandleScope).toHaveBeenCalledTimes(1);
4853
expect(mockHandleScope).toHaveReturnedWith(expect.objectContaining({ message: 'f00', category: 'console' }));
4954
});
55+
56+
it('returns null if the method does not exist on the scope', () => {
57+
const scope = {} as unknown as Scope;
58+
HandleScope.handleScope(scope);
59+
expect(mockHandleScope).toHaveBeenCalledTimes(1);
60+
expect(mockHandleScope).toHaveReturnedWith(null);
61+
});
5062
});

0 commit comments

Comments
 (0)