zivl / sentry-testkit

A Sentry plugin to allow Sentry report interception and further inspection of the data being sent
https://zivl.github.io/sentry-testkit/
MIT License
112 stars 26 forks source link

[BUG]: Testing ErrorBoundary records 3 reports instead of 1 #184

Closed tayfun-corp closed 1 year ago

tayfun-corp commented 1 year ago

Describe the bug

I'm testing ErrorBoundary and getting 3 reports for a single exception.

To Reproduce

Simple test:

/* eslint-disable no-console */

import { render } from '@testing-library/react';
import * as Sentry from '@sentry/react';
import sentryTestkit from 'sentry-testkit';

const { testkit, sentryTransport } = sentryTestkit();

const ThrowError = () => {
  // eslint-disable-next-line functional/no-throw-statements
  throw Error('test error');
};

describe('Inside ErrorBoundary', () => {
  const consoleError = console.error;
  beforeAll(() => {
    console.error = jest.fn();
    Sentry.init({ dsn: 'https://acacaeaccacacacabcaacdacdacadaca@sentry.io/000001', transport: sentryTransport });
  });
  afterAll(() => {
    console.error = consoleError;
  });

  it('should render Fallback component and captureException when error is thrown', async () => {
    expect(testkit.reports()).toHaveLength(0);
    render(
      <Sentry.ErrorBoundary fallback={<div>some error</div>}>
        <ThrowError />
      </Sentry.ErrorBoundary>
    );
    // FIXME: This throws 3 errors
    expect(testkit.reports()).toHaveLength(1);
  });
});

Expected behavior

I expect 1 report to be tracked. Instead it is:

 FAIL  src/ErrorBoundary.test.tsx
  Inside ErrorBoundary
    ✕ should render Fallback component and captureException when error is thrown (28 ms)

  ● Inside ErrorBoundary › should render Fallback component and captureException when error is thrown

    expect(received).toHaveLength(expected)

    Expected length: 1
    Received length: 3
    Received array:  [{"breadcrumbs": [Array], "error": [Object], "extra": [Object], "level": "error", "message": undefined, "originalReport": [Object], "release": undefined, "tags": [Object], "user": undefined}, {"breadcrumbs": [Array], "error": [Object], "extra": [Object], "level": "error", "message": undefined, "originalReport": [Object], "release": undefined, "tags": [Object], "user": undefined}, {"breadcrumbs": [Array], "error": [Object], "extra": undefined, "level": "error", "message": undefined, "originalReport": [Object], "release": undefined, "tags": [Object], "user": undefined}]

      29 |       </Sentry.ErrorBoundary>
      30 |     );
    > 31 |     expect(testkit.reports()).toHaveLength(1);
         |                               ^
      32 |   });
      33 | });
      34 |

      at Object.<anonymous> (src/ErrorBoundary.test.tsx:31:31)
      at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
      at runJest (node_modules/@jest/core/build/runJest.js:404:19)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        0.378 s, estimated 1 s
Ran all test suites matching /src\/ErrorBoundary.test.tsx/i.

Screenshots

Debugger shows these in reports:

Screenshot 2023-11-09 at 19 31 28

Sentry Versions (please complete the following information):

zivl commented 1 year ago

thanks @tayfun-corp for this issue report, I'll investigate

tayfun-corp commented 1 year ago

Thanks @zivl , I originally created this on Sentry with https://github.com/getsentry/sentry-javascript/issues/9514

As far as I understand this may not be an error but a feature? I'm confused though:

  1. What does report mean here, and for a single exception, 3 reports is normal? Is there a document on what report has?
  2. Is there a document on events and exceptions and other items inside an event on Sentry website? I gather this data would be different for different runtimes (JS/Py etc.) but would be good to know about it.

Again, thanks for your contributions!

zivl commented 1 year ago

hey @tayfun-corp ! I was just about to open this issue to Sentry guys myself, as after debugging this I also see that it the issue is not originated by the testkit but with how Sentry functions, as they explained in @AbhiPrasad's comment.

I'll try to answer your questions as far as I understand:

  1. First, let's understand some terminology, the difference between a Sentry event and a Sentry report is that an event is one instance of sending data to Sentry, generally an error or exception, while a report is the action of capturing and sending an event to Sentry. In other words, an event is the data being sent, and a report is the process of sending that data to Sentry.

    So it looks like 3 reports is normal, in terms of how Sentry work under the hood. Though, you can alway customize it through Integrations (e.g. disable the GlobalHandler Integration and etc.)

  2. Sure, you can go to Sentry Docs and find more info about the differences between events, exceptions and reports and how you can control the data being sent.

As for sentry-testkit - I will:

  1. update the documentation regarding the usage with <Sentry.ErrorBoundary> component
  2. add your test above as an example to show, which I even learned something new today thanks to it - so I appreciate that ✌️

I'll leave this issue open until I complete those 2 items

zivl commented 1 year ago

released in sentry-testkit@5.0.7

AbhiPrasad commented 1 year ago

Awesome, thanks for the quick turnaround on this @zivl!!