messageFormatter.spec.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import {render, screen} from 'sentry-test/reactTestingLibrary';
  2. import {BreadcrumbLevelType} from 'sentry/types/breadcrumbs';
  3. import hydrateBreadcrumbs from 'sentry/utils/replays/hydrateBreadcrumbs';
  4. import MessageFormatter from 'sentry/views/replays/detail/console/messageFormatter';
  5. describe('MessageFormatter', () => {
  6. it('Should print console message with placeholders correctly', () => {
  7. const [frame] = hydrateBreadcrumbs(TestStubs.ReplayRecord(), [
  8. TestStubs.Replay.ConsoleFrame({
  9. data: {
  10. arguments: ['This is a %s', 'test'],
  11. logger: 'console',
  12. },
  13. level: BreadcrumbLevelType.LOG,
  14. message: 'This is a %s test',
  15. timestamp: new Date('2022-06-22T20:00:39.959Z'),
  16. }),
  17. ]);
  18. render(<MessageFormatter frame={frame} />);
  19. expect(screen.getByText('This is a test')).toBeInTheDocument();
  20. });
  21. it('Should print console message without data', () => {
  22. const [frame] = hydrateBreadcrumbs(TestStubs.ReplayRecord(), [
  23. TestStubs.Replay.ConsoleFrame({
  24. level: BreadcrumbLevelType.LOG,
  25. message: 'This is only a test',
  26. timestamp: new Date('2022-06-22T20:00:39.959Z'),
  27. }),
  28. ]);
  29. // Manually delete `data` from the mock.
  30. // This is reasonable because the type, at this point, `frame` is of type
  31. // `BreadcrumbFrame` and not `ConsoleFrame`.
  32. // When the type is narrowed to `ConsoleFrame` the `data` field is forced to exist.
  33. delete frame.data;
  34. render(<MessageFormatter frame={frame} />);
  35. expect(screen.getByText('This is only a test')).toBeInTheDocument();
  36. });
  37. it('Should print console message with objects correctly', () => {
  38. const [frame] = hydrateBreadcrumbs(TestStubs.ReplayRecord(), [
  39. TestStubs.Replay.ConsoleFrame({
  40. data: {
  41. arguments: ['test', 1, false, {}],
  42. logger: 'console',
  43. },
  44. level: BreadcrumbLevelType.LOG,
  45. message: 'test 1 false [object Object]',
  46. timestamp: new Date('2022-06-22T16:49:11.198Z'),
  47. }),
  48. ]);
  49. render(<MessageFormatter frame={frame} />);
  50. expect(screen.getByText('test 1 false')).toBeInTheDocument();
  51. expect(screen.getByText('{}')).toBeInTheDocument();
  52. });
  53. it('Should print console message correctly when it is an Error object', () => {
  54. const [frame] = hydrateBreadcrumbs(TestStubs.ReplayRecord(), [
  55. TestStubs.Replay.ConsoleFrame({
  56. data: {
  57. arguments: [{}],
  58. logger: 'console',
  59. },
  60. level: BreadcrumbLevelType.ERROR,
  61. message: 'Error: this is my error message',
  62. timestamp: new Date('2022-06-22T20:00:39.958Z'),
  63. }),
  64. ]);
  65. render(<MessageFormatter frame={frame} />);
  66. expect(screen.getByText('this is my error message')).toBeInTheDocument();
  67. });
  68. it('Should print empty object in case there is no message prop', () => {
  69. const [frame] = hydrateBreadcrumbs(TestStubs.ReplayRecord(), [
  70. TestStubs.Replay.ConsoleFrame({
  71. data: {
  72. arguments: [{}],
  73. logger: 'console',
  74. },
  75. level: BreadcrumbLevelType.ERROR,
  76. timestamp: new Date('2022-06-22T20:00:39.958Z'),
  77. }),
  78. ]);
  79. render(<MessageFormatter frame={frame} />);
  80. expect(screen.getByText('{}')).toBeInTheDocument();
  81. });
  82. it('Should style "%c" placeholder and print the console message correctly', () => {
  83. const [frame] = hydrateBreadcrumbs(TestStubs.ReplayRecord(), [
  84. TestStubs.Replay.ConsoleFrame({
  85. data: {
  86. arguments: [
  87. '%c prev state',
  88. 'color: #9E9E9E; font-weight: bold; background-image: url(foo);',
  89. {
  90. cart: [],
  91. },
  92. ],
  93. logger: 'console',
  94. },
  95. level: BreadcrumbLevelType.LOG,
  96. message:
  97. '%c prev state color: #9E9E9E; font-weight: bold; background-image: url(foo); [object Object]',
  98. timestamp: new Date('2022-06-09T00:50:25.273Z'),
  99. }),
  100. ]);
  101. render(<MessageFormatter frame={frame} />);
  102. const styledEl = screen.getByText('prev state');
  103. expect(styledEl).toBeInTheDocument();
  104. expect(styledEl).toHaveStyle('color: #9E9E9E;');
  105. expect(styledEl).toHaveStyle('font-weight: bold;');
  106. expect(styledEl).not.toHaveStyle('background-image: url(foo);');
  107. expect(screen.getByText('cart')).toBeInTheDocument();
  108. expect(screen.getByText('Array(0)')).toBeInTheDocument();
  109. });
  110. it('Should print arrays correctly', () => {
  111. const [frame] = hydrateBreadcrumbs(TestStubs.ReplayRecord(), [
  112. TestStubs.Replay.ConsoleFrame({
  113. data: {
  114. arguments: ['test', ['foo', 'bar']],
  115. logger: 'console',
  116. },
  117. level: BreadcrumbLevelType.LOG,
  118. message: 'test foo,bar',
  119. timestamp: new Date('2022-06-23T17:09:31.158Z'),
  120. }),
  121. ]);
  122. render(<MessageFormatter frame={frame} />);
  123. expect(screen.getByText('test')).toBeInTheDocument();
  124. expect(screen.getByText('(2)')).toBeInTheDocument();
  125. // expect(screen.getByText('[')).toBeInTheDocument();
  126. expect(screen.getByText('"foo"')).toBeInTheDocument();
  127. expect(screen.getByText('"bar"')).toBeInTheDocument();
  128. // expect(screen.getByText(']')).toBeInTheDocument();
  129. });
  130. it('Should print literal %', () => {
  131. const [frame] = hydrateBreadcrumbs(TestStubs.ReplayRecord(), [
  132. TestStubs.Replay.ConsoleFrame({
  133. data: {
  134. arguments: ['This is a literal 100%'],
  135. logger: 'console',
  136. },
  137. level: BreadcrumbLevelType.LOG,
  138. message: 'This is a literal 100%',
  139. timestamp: new Date('2022-06-22T20:00:39.959Z'),
  140. }),
  141. ]);
  142. render(<MessageFormatter frame={frame} />);
  143. expect(screen.getByText('This is a literal 100%')).toBeInTheDocument();
  144. });
  145. it('Should print unbound %s placeholder', () => {
  146. const [frame] = hydrateBreadcrumbs(TestStubs.ReplayRecord(), [
  147. TestStubs.Replay.ConsoleFrame({
  148. data: {
  149. arguments: ['Unbound placeholder %s'],
  150. logger: 'console',
  151. },
  152. level: BreadcrumbLevelType.LOG,
  153. message: 'Unbound placeholder %s',
  154. timestamp: new Date('2022-06-22T20:00:39.959Z'),
  155. }),
  156. ]);
  157. render(<MessageFormatter frame={frame} />);
  158. expect(screen.getByText('Unbound placeholder %s')).toBeInTheDocument();
  159. });
  160. it('Should print placeholder with literal %', () => {
  161. const [frame] = hydrateBreadcrumbs(TestStubs.ReplayRecord(), [
  162. TestStubs.Replay.ConsoleFrame({
  163. data: {
  164. arguments: ['Placeholder %s with 100%', 'myPlaceholder'],
  165. logger: 'console',
  166. },
  167. level: BreadcrumbLevelType.LOG,
  168. message: 'Placeholder %s with 100%',
  169. timestamp: new Date('2022-06-22T20:00:39.959Z'),
  170. }),
  171. ]);
  172. render(<MessageFormatter frame={frame} />);
  173. expect(screen.getByText('Placeholder myPlaceholder with 100%')).toBeInTheDocument();
  174. });
  175. });