Skip to content

Commit

Permalink
fix(replay): Handle multiple clicks in a short time
Browse files Browse the repository at this point in the history
  • Loading branch information
mydea committed Aug 10, 2023
1 parent 695a671 commit b118e92
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
8 changes: 8 additions & 0 deletions packages/replay/src/coreHandlers/handleClick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ export class ClickDetector implements ReplayClickDetector {
clickCount: 0,
node,
};

// If there was a click in the last 1s on the same element, ignore it - only keep a single reference per second
if (
this._clicks.some(click => click.node === newClick.node && Math.abs(click.timestamp - newClick.timestamp) < 1)
) {
return;
}

this._clicks.push(newClick);

// If this is the first new click, set a timeout to check for multi clicks
Expand Down
91 changes: 91 additions & 0 deletions packages/replay/test/unit/coreHandlers/handleClick.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,97 @@ describe('Unit | coreHandlers | handleClick', () => {
expect(mockAddBreadcrumbEvent).toHaveBeenCalledTimes(1);
});

test('it captures multiple clicks', async () => {
const replay = {
getCurrentRoute: () => 'test-route',
} as ReplayContainer;

const mockAddBreadcrumbEvent = jest.fn();

const detector = new ClickDetector(
replay,
{
threshold: 1_000,
timeout: 3_000,
scrollTimeout: 200,
ignoreSelector: '',
},
mockAddBreadcrumbEvent,
);

const breadcrumb1: Breadcrumb = {
timestamp: BASE_TIMESTAMP / 1000,
data: {
nodeId: 1,
},
};
const breadcrumb2: Breadcrumb = {
timestamp: (BASE_TIMESTAMP + 200) / 1000,
data: {
nodeId: 1,
},
};
const breadcrumb3: Breadcrumb = {
timestamp: (BASE_TIMESTAMP + 1200) / 1000,
data: {
nodeId: 1,
},
};
const node = document.createElement('button');
detector.handleClick(breadcrumb1, node);
detector.handleClick(breadcrumb2, node);
detector.handleClick(breadcrumb3, node);

expect(mockAddBreadcrumbEvent).toHaveBeenCalledTimes(0);

jest.advanceTimersByTime(1_000);

expect(mockAddBreadcrumbEvent).toHaveBeenCalledTimes(0);

jest.advanceTimersByTime(1_000);

expect(mockAddBreadcrumbEvent).toHaveBeenCalledTimes(0);

jest.advanceTimersByTime(1_000);

expect(mockAddBreadcrumbEvent).toHaveBeenCalledTimes(1);
expect(mockAddBreadcrumbEvent).toHaveBeenCalledWith(replay, {
category: 'ui.slowClickDetected',
type: 'default',
data: {
clickCount: 1,
endReason: 'timeout',
nodeId: 1,
route: 'test-route',
timeAfterClickMs: 3000,
url: 'http://localhost/',
},
message: undefined,
timestamp: BASE_TIMESTAMP / 1000,
});

jest.advanceTimersByTime(2_000);

expect(mockAddBreadcrumbEvent).toHaveBeenCalledTimes(2);
expect(mockAddBreadcrumbEvent).toHaveBeenLastCalledWith(replay, {
category: 'ui.slowClickDetected',
type: 'default',
data: {
clickCount: 1,
endReason: 'timeout',
nodeId: 1,
route: 'test-route',
timeAfterClickMs: 3000,
url: 'http://localhost/',
},
message: undefined,
timestamp: (BASE_TIMESTAMP + 1200) / 1000,
});

jest.advanceTimersByTime(5_000);
expect(mockAddBreadcrumbEvent).toHaveBeenCalledTimes(2);
});

test('it captures clicks on different elements', async () => {
const replay = {
getCurrentRoute: () => 'test-route',
Expand Down

0 comments on commit b118e92

Please sign in to comment.