123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- import {ReplayConsoleFrameFixture} from 'sentry-fixture/replay/replayBreadcrumbFrameData';
- import {ReplayRecordFixture} from 'sentry-fixture/replayRecord';
- import {render, screen} from 'sentry-test/reactTestingLibrary';
- import {BreadcrumbLevelType} from 'sentry/types/breadcrumbs';
- import hydrateBreadcrumbs from 'sentry/utils/replays/hydrateBreadcrumbs';
- import MessageFormatter from 'sentry/views/replays/detail/console/messageFormatter';
- const mockRRWebFrames = []; // This is only needed for replay.hydrate-error breadcrumbs.
- describe('MessageFormatter', () => {
- it('Should print console message with placeholders correctly', () => {
- const [frame] = hydrateBreadcrumbs(
- ReplayRecordFixture(),
- [
- ReplayConsoleFrameFixture({
- data: {
- arguments: ['This is a %s', 'test'],
- logger: 'console',
- },
- level: BreadcrumbLevelType.LOG,
- message: 'This is a %s test',
- timestamp: new Date('2022-06-22T20:00:39.959Z'),
- }),
- ],
- mockRRWebFrames
- );
- render(<MessageFormatter frame={frame} />);
- expect(screen.getByText('This is a test')).toBeInTheDocument();
- });
- it('Should print console message without data', () => {
- const [frame] = hydrateBreadcrumbs(
- ReplayRecordFixture(),
- [
- ReplayConsoleFrameFixture({
- level: BreadcrumbLevelType.LOG,
- message: 'This is only a test',
- timestamp: new Date('2022-06-22T20:00:39.959Z'),
- }),
- ],
- mockRRWebFrames
- );
- // Manually delete `data` from the mock.
- // This is reasonable because the type, at this point, `frame` is of type
- // `BreadcrumbFrame` and not `ConsoleFrame`.
- // When the type is narrowed to `ConsoleFrame` the `data` field is forced to exist.
- delete frame.data;
- render(<MessageFormatter frame={frame} />);
- expect(screen.getByText('This is only a test')).toBeInTheDocument();
- });
- it('Should print console message with objects correctly', () => {
- const [frame] = hydrateBreadcrumbs(
- ReplayRecordFixture(),
- [
- ReplayConsoleFrameFixture({
- data: {
- arguments: ['test', 1, false, {}],
- logger: 'console',
- },
- level: BreadcrumbLevelType.LOG,
- message: 'test 1 false [object Object]',
- timestamp: new Date('2022-06-22T16:49:11.198Z'),
- }),
- ],
- mockRRWebFrames
- );
- render(<MessageFormatter frame={frame} />);
- expect(screen.getByText('test 1 false')).toBeInTheDocument();
- expect(screen.getByText('{}')).toBeInTheDocument();
- });
- it('Should print console message correctly when it is an Error object', () => {
- const [frame] = hydrateBreadcrumbs(
- ReplayRecordFixture(),
- [
- ReplayConsoleFrameFixture({
- data: {
- arguments: [{}],
- logger: 'console',
- },
- level: BreadcrumbLevelType.ERROR,
- message: 'Error: this is my error message',
- timestamp: new Date('2022-06-22T20:00:39.958Z'),
- }),
- ],
- mockRRWebFrames
- );
- render(<MessageFormatter frame={frame} />);
- expect(screen.getByText('this is my error message')).toBeInTheDocument();
- });
- it('Should print empty object in case there is no message prop', () => {
- const [frame] = hydrateBreadcrumbs(
- ReplayRecordFixture(),
- [
- ReplayConsoleFrameFixture({
- data: {
- arguments: [{}],
- logger: 'console',
- },
- level: BreadcrumbLevelType.ERROR,
- timestamp: new Date('2022-06-22T20:00:39.958Z'),
- }),
- ],
- mockRRWebFrames
- );
- render(<MessageFormatter frame={frame} />);
- expect(screen.getByText('{}')).toBeInTheDocument();
- });
- it('Should style "%c" placeholder and print the console message correctly', () => {
- const [frame] = hydrateBreadcrumbs(
- ReplayRecordFixture(),
- [
- ReplayConsoleFrameFixture({
- data: {
- arguments: [
- '%c prev state',
- 'color: #9E9E9E; font-weight: bold; background-image: url(foo);',
- {
- cart: [],
- },
- ],
- logger: 'console',
- },
- level: BreadcrumbLevelType.LOG,
- message:
- '%c prev state color: #9E9E9E; font-weight: bold; background-image: url(foo); [object Object]',
- timestamp: new Date('2022-06-09T00:50:25.273Z'),
- }),
- ],
- mockRRWebFrames
- );
- render(<MessageFormatter frame={frame} />);
- const styledEl = screen.getByText('prev state');
- expect(styledEl).toBeInTheDocument();
- expect(styledEl).toHaveStyle('color: #9E9E9E;');
- expect(styledEl).toHaveStyle('font-weight: bold;');
- expect(styledEl).not.toHaveStyle('background-image: url(foo);');
- expect(screen.getByText('cart')).toBeInTheDocument();
- expect(screen.getByText('Array(0)')).toBeInTheDocument();
- });
- it('Should print arrays correctly', () => {
- const [frame] = hydrateBreadcrumbs(
- ReplayRecordFixture(),
- [
- ReplayConsoleFrameFixture({
- data: {
- arguments: ['test', ['foo', 'bar']],
- logger: 'console',
- },
- level: BreadcrumbLevelType.LOG,
- message: 'test foo,bar',
- timestamp: new Date('2022-06-23T17:09:31.158Z'),
- }),
- ],
- mockRRWebFrames
- );
- render(<MessageFormatter frame={frame} />);
- expect(screen.getByText('test')).toBeInTheDocument();
- expect(screen.getByText('(2)')).toBeInTheDocument();
- // expect(screen.getByText('[')).toBeInTheDocument();
- expect(screen.getByText('"foo"')).toBeInTheDocument();
- expect(screen.getByText('"bar"')).toBeInTheDocument();
- // expect(screen.getByText(']')).toBeInTheDocument();
- });
- it('Should print literal %', () => {
- const [frame] = hydrateBreadcrumbs(
- ReplayRecordFixture(),
- [
- ReplayConsoleFrameFixture({
- data: {
- arguments: ['This is a literal 100%'],
- logger: 'console',
- },
- level: BreadcrumbLevelType.LOG,
- message: 'This is a literal 100%',
- timestamp: new Date('2022-06-22T20:00:39.959Z'),
- }),
- ],
- mockRRWebFrames
- );
- render(<MessageFormatter frame={frame} />);
- expect(screen.getByText('This is a literal 100%')).toBeInTheDocument();
- });
- it('Should print unbound %s placeholder', () => {
- const [frame] = hydrateBreadcrumbs(
- ReplayRecordFixture(),
- [
- ReplayConsoleFrameFixture({
- data: {
- arguments: ['Unbound placeholder %s'],
- logger: 'console',
- },
- level: BreadcrumbLevelType.LOG,
- message: 'Unbound placeholder %s',
- timestamp: new Date('2022-06-22T20:00:39.959Z'),
- }),
- ],
- mockRRWebFrames
- );
- render(<MessageFormatter frame={frame} />);
- expect(screen.getByText('Unbound placeholder %s')).toBeInTheDocument();
- });
- it('Should print placeholder with literal %', () => {
- const [frame] = hydrateBreadcrumbs(
- ReplayRecordFixture(),
- [
- ReplayConsoleFrameFixture({
- data: {
- arguments: ['Placeholder %s with 100%', 'myPlaceholder'],
- logger: 'console',
- },
- level: BreadcrumbLevelType.LOG,
- message: 'Placeholder %s with 100%',
- timestamp: new Date('2022-06-22T20:00:39.959Z'),
- }),
- ],
- mockRRWebFrames
- );
- render(<MessageFormatter frame={frame} />);
- expect(screen.getByText('Placeholder myPlaceholder with 100%')).toBeInTheDocument();
- });
- it('should print non-console breadcrumbs', () => {
- const [frame] = hydrateBreadcrumbs(
- ReplayRecordFixture(),
- [
- {
- category: 'cypress',
- message: 'custom breadcrumb',
- timestamp: new Date('2022-06-22T20:00:39.959Z').getTime(),
- type: 'info',
- },
- ],
- mockRRWebFrames
- );
- render(<MessageFormatter frame={frame} />);
- expect(screen.getByText('cypress custom breadcrumb')).toBeInTheDocument();
- });
- });
|