1111import {
1212 DoesNotUseKey ,
1313 FragmentWithProp ,
14- ManualConsoleError ,
15- ManualConsoleErrorWithStack ,
1614} from './__fixtures__/ReactWarningFixtures' ;
1715import * as React from 'react' ;
1816
1917const LogBoxData = require ( '../Data/LogBoxData' ) ;
2018const TestRenderer = require ( 'react-test-renderer' ) ;
2119
22- const ExceptionsManager = require ( '../../Core/ExceptionsManager.js' ) ;
23-
2420const installLogBox = ( ) => {
25- const LogBox = require ( '../LogBox' ) . default ;
21+ const LogBox = require ( '../LogBox' ) ;
22+
2623 LogBox . install ( ) ;
2724} ;
2825
2926const uninstallLogBox = ( ) => {
30- const LogBox = require ( '../LogBox' ) . default ;
27+ const LogBox = require ( '../LogBox' ) ;
3128 LogBox . uninstall ( ) ;
3229} ;
3330
34- // TODO: we can remove all the symetric matchers once OSS lands component stack frames.
35- // For now, the component stack parsing differs in ways we can't easily detect in this test.
36- describe ( 'LogBox' , ( ) => {
31+ const BEFORE_SLASH_RE = / (?: \/ [ a - z A - Z ] + \/ ) ( .+ ?) (?: \/ .+ ) \/ / ;
32+
33+ const cleanPath = message => {
34+ return message . replace ( BEFORE_SLASH_RE , '/path/to/' ) ;
35+ } ;
36+
37+ const cleanLog = logs => {
38+ return logs . map ( log => {
39+ return {
40+ ...log ,
41+ componentStack : log . componentStack . map ( stack => ( {
42+ ...stack ,
43+ fileName : cleanPath ( stack . fileName ) ,
44+ } ) ) ,
45+ } ;
46+ } ) ;
47+ } ;
48+
49+ // TODO(T71117418): Re-enable skipped LogBox integration tests once React component
50+ // stack frames are the same internally and in open source.
51+ // eslint-disable-next-line jest/no-disabled-tests
52+ describe . skip ( 'LogBox' , ( ) => {
3753 const { error, warn} = console ;
3854 const mockError = jest . fn ( ) ;
3955 const mockWarn = jest . fn ( ) ;
4056
4157 beforeEach ( ( ) => {
4258 jest . resetModules ( ) ;
4359 jest . restoreAllMocks ( ) ;
44- jest . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } ) ;
4560
4661 mockError . mockClear ( ) ;
4762 mockWarn . mockClear ( ) ;
48- // Reset ExceptionManager patching.
49- if ( console . _errorOriginal ) {
50- console . _errorOriginal = null ;
51- }
63+
5264 ( console : any ) . error = mockError ;
5365 ( console : any ) . warn = mockWarn ;
5466 } ) ;
@@ -67,10 +79,7 @@ describe('LogBox', () => {
6779 // so we can assert on what React logs.
6880 jest . spyOn ( console , 'error' ) ;
6981
70- let output ;
71- TestRenderer . act ( ( ) => {
72- output = TestRenderer . create ( < DoesNotUseKey /> ) ;
73- } ) ;
82+ const output = TestRenderer . create ( < DoesNotUseKey /> ) ;
7483
7584 // The key error should always be the highest severity.
7685 // In LogBox, we expect these errors to:
@@ -79,37 +88,16 @@ describe('LogBox', () => {
7988 // - Pass to console.error, with a "Warning" prefix so it does not pop a RedBox.
8089 expect ( output ) . toBeDefined ( ) ;
8190 expect ( mockWarn ) . not . toBeCalled ( ) ;
82- expect ( console . error ) . toBeCalledTimes ( 1 ) ;
83- expect ( console . error . mock . calls [ 0 ] ) . toEqual ( [
84- 'Each child in a list should have a unique "key" prop.%s%s See https://react.dev/link/warning-keys for more information.%s' ,
85- '\n\nCheck the render method of `DoesNotUseKey`.' ,
86- '' ,
87- expect . stringMatching ( 'at DoesNotUseKey' ) ,
88- ] ) ;
89- expect ( spy ) . toHaveBeenCalledWith ( {
90- level : 'error' ,
91- category : expect . stringContaining (
92- 'Warning: Each child in a list should have a unique' ,
93- ) ,
94- componentStack : expect . anything ( ) ,
95- componentStackType : 'stack' ,
96- message : {
97- content :
98- 'Warning: Each child in a list should have a unique "key" prop.\n\nCheck the render method of `DoesNotUseKey`. See https://react.dev/link/warning-keys for more information.' ,
99- substitutions : [
100- { length : 45 , offset : 62 } ,
101- { length : 0 , offset : 107 } ,
102- ] ,
103- } ,
104- } ) ;
91+ expect ( console . error . mock . calls [ 0 ] . map ( cleanPath ) ) . toMatchSnapshot (
92+ 'Log sent from React' ,
93+ ) ;
94+ expect ( cleanLog ( spy . mock . calls [ 0 ] ) ) . toMatchSnapshot ( 'Log added to LogBox' ) ;
95+ expect ( mockError . mock . calls [ 0 ] . map ( cleanPath ) ) . toMatchSnapshot (
96+ 'Log passed to console error' ,
97+ ) ;
10598
10699 // The Warning: prefix is added due to a hack in LogBox to prevent double logging.
107- // We also interpolate the string before passing to the underlying console method.
108- expect ( mockError . mock . calls [ 0 ] ) . toEqual ( [
109- expect . stringMatching (
110- 'Warning: Each child in a list should have a unique "key" prop.\n\nCheck the render method of `DoesNotUseKey`. See https://react.dev/link/warning-keys for more information.\n at ' ,
111- ) ,
112- ] ) ;
100+ expect ( mockError . mock . calls [ 0 ] [ 0 ] . startsWith ( 'Warning: ' ) ) . toBe ( true ) ;
113101 } ) ;
114102
115103 it ( 'integrates with React and handles a fragment warning in LogBox' , ( ) => {
@@ -120,10 +108,7 @@ describe('LogBox', () => {
120108 // so we can assert on what React logs.
121109 jest . spyOn ( console , 'error' ) ;
122110
123- let output ;
124- TestRenderer . act ( ( ) => {
125- output = TestRenderer . create ( < FragmentWithProp /> ) ;
126- } ) ;
111+ const output = TestRenderer . create ( < FragmentWithProp /> ) ;
127112
128113 // The fragment warning is not as severe. For this warning we don't want to
129114 // pop open a dialog, so we show a collapsed error UI.
@@ -133,125 +118,15 @@ describe('LogBox', () => {
133118 // - Pass to console.error, with a "Warning" prefix so it does not pop a RedBox.
134119 expect ( output ) . toBeDefined ( ) ;
135120 expect ( mockWarn ) . not . toBeCalled ( ) ;
136- expect ( console . error ) . toBeCalledTimes ( 1 ) ;
137- expect ( console . error . mock . calls [ 0 ] ) . toEqual ( [
138- 'Invalid prop `%s` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.%s' ,
139- 'invalid' ,
140- expect . stringMatching ( 'at FragmentWithProp' ) ,
141- ] ) ;
142- expect ( spy ) . toHaveBeenCalledWith ( {
143- level : 'error' ,
144- category : expect . stringContaining ( 'Warning: Invalid prop' ) ,
145- componentStack : expect . anything ( ) ,
146- componentStackType : expect . stringMatching ( / ( s t a c k | l e g a c y ) / ) ,
147- message : {
148- content :
149- 'Warning: Invalid prop `invalid` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.' ,
150- substitutions : [ { length : 7 , offset : 23 } ] ,
151- } ,
152- } ) ;
153-
154- // The Warning: prefix is added due to a hack in LogBox to prevent double logging.
155- // We also interpolate the string before passing to the underlying console method.
156- expect ( mockError . mock . calls [ 0 ] ) . toEqual ( [
157- expect . stringMatching (
158- 'Warning: Invalid prop `invalid` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.\n at FragmentWithProp' ,
159- ) ,
160- ] ) ;
161- } ) ;
162-
163- it ( 'handles a manual console.error without a component stack in LogBox' , ( ) => {
164- const LogBox = require ( '../LogBox' ) . default ;
165- const spy = jest . spyOn ( LogBox , 'addException' ) ;
166- installLogBox ( ) ;
167-
168- // console.error handling depends on installing the ExceptionsManager error reporter.
169- ExceptionsManager . installConsoleErrorReporter ( ) ;
170-
171- // Spy console.error after LogBox is installed
172- // so we can assert on what React logs.
173- jest . spyOn ( console , 'error' ) ;
174-
175- let output ;
176- TestRenderer . act ( ( ) => {
177- output = TestRenderer . create ( < ManualConsoleError /> ) ;
178- } ) ;
179-
180- // Manual console errors should show a collapsed error dialog.
181- // When there is no component stack, we expect these errors to:
182- // - Go to the LogBox patch and fall through to console.error.
183- // - Get picked up by the ExceptionsManager console.error override.
184- // - Get passed back to LogBox via addException (non-fatal).
185- expect ( output ) . toBeDefined ( ) ;
186- expect ( mockWarn ) . not . toBeCalled ( ) ;
187- expect ( spy ) . toBeCalledTimes ( 1 ) ;
188- expect ( console . error ) . toBeCalledTimes ( 1 ) ;
189- expect ( console . error . mock . calls [ 0 ] ) . toEqual ( [ 'Manual console error' ] ) ;
190- expect ( spy ) . toHaveBeenCalledWith ( {
191- id : 1 ,
192- isComponentError : false ,
193- isFatal : false ,
194- name : 'console.error' ,
195- originalMessage : 'Manual console error' ,
196- message : 'console.error: Manual console error' ,
197- extraData : expect . anything ( ) ,
198- componentStack : null ,
199- stack : expect . anything ( ) ,
200- } ) ;
201-
202- // No Warning: prefix is added due since this is falling through.
203- expect ( mockError . mock . calls [ 0 ] ) . toEqual ( [ 'Manual console error' ] ) ;
204- } ) ;
205-
206- it ( 'handles a manual console.error with a component stack in LogBox' , ( ) => {
207- const spy = jest . spyOn ( LogBoxData , 'addLog' ) ;
208- installLogBox ( ) ;
209-
210- // console.error handling depends on installing the ExceptionsManager error reporter.
211- ExceptionsManager . installConsoleErrorReporter ( ) ;
212-
213- // Spy console.error after LogBox is installed
214- // so we can assert on what React logs.
215- jest . spyOn ( console , 'error' ) ;
216-
217- let output ;
218- TestRenderer . act ( ( ) => {
219- output = TestRenderer . create ( < ManualConsoleErrorWithStack /> ) ;
220- } ) ;
221-
222- // Manual console errors should show a collapsed error dialog.
223- // When there is a component stack, we expect these errors to:
224- // - Go to the LogBox patch and be detected as a React error.
225- // - Check the warning filter to see if there is a fiter setting.
226- // - Call console.error with the parsed error.
227- // - Get picked up by ExceptionsManager console.error override.
228- // - Log to console.error.
229- expect ( output ) . toBeDefined ( ) ;
230- expect ( mockWarn ) . not . toBeCalled ( ) ;
231- expect ( console . error ) . toBeCalledTimes ( 1 ) ;
232- expect ( spy ) . toBeCalledTimes ( 1 ) ;
233- expect ( console . error . mock . calls [ 0 ] ) . toEqual ( [
234- expect . stringContaining (
235- 'Manual console error\n at ManualConsoleErrorWithStack' ,
236- ) ,
237- ] ) ;
238- expect ( spy ) . toHaveBeenCalledWith ( {
239- level : 'error' ,
240- category : expect . stringContaining ( 'Warning: Manual console error' ) ,
241- componentStack : expect . anything ( ) ,
242- componentStackType : 'stack' ,
243- message : {
244- content : 'Warning: Manual console error' ,
245- substitutions : [ ] ,
246- } ,
247- } ) ;
121+ expect ( console . error . mock . calls [ 0 ] . map ( cleanPath ) ) . toMatchSnapshot (
122+ 'Log sent from React' ,
123+ ) ;
124+ expect ( cleanLog ( spy . mock . calls [ 0 ] ) ) . toMatchSnapshot ( 'Log added to LogBox' ) ;
125+ expect ( mockError . mock . calls [ 0 ] . map ( cleanPath ) ) . toMatchSnapshot (
126+ 'Log passed to console error' ,
127+ ) ;
248128
249129 // The Warning: prefix is added due to a hack in LogBox to prevent double logging.
250- // We also interpolate the string before passing to the underlying console method.
251- expect ( mockError . mock . calls [ 0 ] ) . toEqual ( [
252- expect . stringMatching (
253- 'Warning: Manual console error\n at ManualConsoleErrorWithStack' ,
254- ) ,
255- ] ) ;
130+ expect ( mockError . mock . calls [ 0 ] [ 0 ] . startsWith ( 'Warning: ' ) ) . toBe ( true ) ;
256131 } ) ;
257132} ) ;
0 commit comments