Remove ReactDOM.render tests in ReactDOMConsoleErrorReporting-test (#28053)
Each it block here was duplicated to cover ReactDOM.render and ReactDOMClient.createRoot. Here we delete the ReactDOM.render coverage. Co-authored-by: Jack Pope <jackpope@meta.com>
Jack Pope committed
Jan 26, 2024 at 19:29 UTC
407faf5a69955f23f3549cff77b1a37199daa95f
2 files changed
+589
-535
packages/react-dom/src/__tests__/ReactDOMConsoleErrorReporting-test.js
-535
@@ -10,7 +10,6 @@
10
describe('ReactDOMConsoleErrorReporting', () => {
11
let act;
12
let React;
13
- let ReactDOM;
13
let ReactDOMClient;
14
15
let ErrorBoundary;
@@ -23,7 +22,6 @@ describe('ReactDOMConsoleErrorReporting', () => {
22
jest.resetModules();
23
act = require('internal-test-utils').act;
24
React = require('react');
26
- ReactDOM = require('react-dom');
25
ReactDOMClient = require('react-dom/client');
26
27
const InternalTestUtils = require('internal-test-utils');
@@ -607,537 +605,4 @@ describe('ReactDOMConsoleErrorReporting', () => {
605
}
606
});
607
});
610
-
611
- describe('ReactDOM.render', () => {
612
- it('logs errors during event handlers', async () => {
613
- spyOnDevAndProd(console, 'error');
614
-
615
- function Foo() {
616
- return (
617
- <button
618
- onClick={() => {
619
- throw Error('Boom');
620
- }}>
621
- click me
622
- </button>
623
- );
624
- }
625
-
626
- await act(() => {
627
- ReactDOM.render(<Foo />, container);
628
- });
629
-
630
- await act(() => {
631
- container.firstChild.dispatchEvent(
632
- new MouseEvent('click', {
633
- bubbles: true,
634
- }),
635
- );
636
- });
637
-
638
- if (__DEV__) {
639
- expect(windowOnError.mock.calls).toEqual([
640
- [
641
- // Reported because we're in a browser click event:
642
- expect.objectContaining({
643
- message: 'Boom',
644
- }),
645
- ],
646
- [
647
- // This one is jsdom-only. Real browser deduplicates it.
648
- // (In DEV, we have a nested event due to guarded callback.)
649
- expect.objectContaining({
650
- message: 'Boom',
651
- }),
652
- ],
653
- ]);
654
- expect(console.error.mock.calls).toEqual([
655
- [expect.stringContaining('ReactDOM.render is no longer supported')],
656
- [
657
- // Reported because we're in a browser click event:
658
- expect.objectContaining({
659
- detail: expect.objectContaining({
660
- message: 'Boom',
661
- }),
662
- type: 'unhandled exception',
663
- }),
664
- ],
665
- [
666
- // This one is jsdom-only. Real browser deduplicates it.
667
- // (In DEV, we have a nested event due to guarded callback.)
668
- expect.objectContaining({
669
- detail: expect.objectContaining({
670
- message: 'Boom',
671
- }),
672
- type: 'unhandled exception',
673
- }),
674
- ],
675
- ]);
676
- } else {
677
- expect(windowOnError.mock.calls).toEqual([
678
- [
679
- // Reported because we're in a browser click event:
680
- expect.objectContaining({
681
- message: 'Boom',
682
- }),
683
- ],
684
- ]);
685
- expect(console.error.mock.calls).toEqual([
686
- [
687
- // Reported because we're in a browser click event:
688
- expect.objectContaining({
689
- detail: expect.objectContaining({
690
- message: 'Boom',
691
- }),
692
- type: 'unhandled exception',
693
- }),
694
- ],
695
- ]);
696
- }
697
-
698
- // Check next render doesn't throw.
699
- windowOnError.mockReset();
700
- console.error.mockReset();
701
- await act(() => {
702
- ReactDOM.render(<NoError />, container);
703
- });
704
- expect(container.textContent).toBe('OK');
705
- expect(windowOnError.mock.calls).toEqual([]);
706
- if (__DEV__) {
707
- expect(console.error.mock.calls).toEqual([
708
- [expect.stringContaining('ReactDOM.render is no longer supported')],
709
- ]);
710
- }
711
- });
712
-
713
- it('logs render errors without an error boundary', async () => {
714
- spyOnDevAndProd(console, 'error');
715
-
716
- function Foo() {
717
- throw Error('Boom');
718
- }
719
-
720
- expect(() => {
721
- ReactDOM.render(<Foo />, container);
722
- }).toThrow('Boom');
723
-
724
- if (__DEV__) {
725
- expect(windowOnError.mock.calls).toEqual([
726
- [
727
- // Reported due to guarded callback:
728
- expect.objectContaining({
729
- message: 'Boom',
730
- }),
731
- ],
732
- ]);
733
- expect(console.error.mock.calls).toEqual([
734
- [expect.stringContaining('ReactDOM.render is no longer supported')],
735
- [
736
- // Reported due to the guarded callback:
737
- expect.objectContaining({
738
- detail: expect.objectContaining({
739
- message: 'Boom',
740
- }),
741
- type: 'unhandled exception',
742
- }),
743
- ],
744
- [
745
- // Addendum by React:
746
- expect.stringContaining(
747
- 'The above error occurred in the <Foo> component',
748
- ),
749
- ],
750
- ]);
751
- } else {
752
- // The top-level error was caught with try/catch, and there's no guarded callback,
753
- // so in production we don't see an error event.
754
- expect(windowOnError.mock.calls).toEqual([]);
755
- expect(console.error.mock.calls).toEqual([
756
- [
757
- // Reported by React with no extra message:
758
- expect.objectContaining({
759
- message: 'Boom',
760
- }),
761
- ],
762
- ]);
763
- }
764
-
765
- // Check next render doesn't throw.
766
- windowOnError.mockReset();
767
- console.error.mockReset();
768
- await act(() => {
769
- ReactDOM.render(<NoError />, container);
770
- });
771
- expect(container.textContent).toBe('OK');
772
- expect(windowOnError.mock.calls).toEqual([]);
773
- if (__DEV__) {
774
- expect(console.error.mock.calls).toEqual([
775
- [expect.stringContaining('ReactDOM.render is no longer supported')],
776
- ]);
777
- }
778
- });
779
-
780
- it('logs render errors with an error boundary', async () => {
781
- spyOnDevAndProd(console, 'error');
782
-
783
- function Foo() {
784
- throw Error('Boom');
785
- }
786
-
787
- await act(() => {
788
- ReactDOM.render(
789
- <ErrorBoundary>
790
- <Foo />
791
- </ErrorBoundary>,
792
- container,
793
- );
794
- });
795
-
796
- if (__DEV__) {
797
- expect(windowOnError.mock.calls).toEqual([
798
- [
799
- // Reported due to guarded callback:
800
- expect.objectContaining({
801
- message: 'Boom',
802
- }),
803
- ],
804
- ]);
805
- expect(console.error.mock.calls).toEqual([
806
- [expect.stringContaining('ReactDOM.render is no longer supported')],
807
- [
808
- // Reported by jsdom due to the guarded callback:
809
- expect.objectContaining({
810
- detail: expect.objectContaining({
811
- message: 'Boom',
812
- }),
813
- type: 'unhandled exception',
814
- }),
815
- ],
816
- [
817
- // Addendum by React:
818
- expect.stringContaining(
819
- 'The above error occurred in the <Foo> component',
820
- ),
821
- ],
822
- ]);
823
- } else {
824
- // The top-level error was caught with try/catch, and there's no guarded callback,
825
- // so in production we don't see an error event.
826
- expect(windowOnError.mock.calls).toEqual([]);
827
- expect(console.error.mock.calls).toEqual([
828
- [
829
- // Reported by React with no extra message:
830
- expect.objectContaining({
831
- message: 'Boom',
832
- }),
833
- ],
834
- ]);
835
- }
836
-
837
- // Check next render doesn't throw.
838
- windowOnError.mockReset();
839
- console.error.mockReset();
840
- await act(() => {
841
- ReactDOM.render(<NoError />, container);
842
- });
843
- expect(container.textContent).toBe('OK');
844
- expect(windowOnError.mock.calls).toEqual([]);
845
- if (__DEV__) {
846
- expect(console.error.mock.calls).toEqual([
847
- [expect.stringContaining('ReactDOM.render is no longer supported')],
848
- ]);
849
- }
850
- });
851
-
852
- it('logs layout effect errors without an error boundary', async () => {
853
- spyOnDevAndProd(console, 'error');
854
-
855
- function Foo() {
856
- React.useLayoutEffect(() => {
857
- throw Error('Boom');
858
- }, []);
859
- return null;
860
- }
861
-
862
- expect(() => {
863
- ReactDOM.render(<Foo />, container);
864
- }).toThrow('Boom');
865
-
866
- if (__DEV__) {
867
- expect(windowOnError.mock.calls).toEqual([
868
- [
869
- // Reported due to guarded callback:
870
- expect.objectContaining({
871
- message: 'Boom',
872
- }),
873
- ],
874
- ]);
875
- expect(console.error.mock.calls).toEqual([
876
- [expect.stringContaining('ReactDOM.render is no longer supported')],
877
- [
878
- // Reported due to the guarded callback:
879
- expect.objectContaining({
880
- detail: expect.objectContaining({
881
- message: 'Boom',
882
- }),
883
- type: 'unhandled exception',
884
- }),
885
- ],
886
- [
887
- // Addendum by React:
888
- expect.stringContaining(
889
- 'The above error occurred in the <Foo> component',
890
- ),
891
- ],
892
- ]);
893
- } else {
894
- // The top-level error was caught with try/catch, and there's no guarded callback,
895
- // so in production we don't see an error event.
896
- expect(windowOnError.mock.calls).toEqual([]);
897
- expect(console.error.mock.calls).toEqual([
898
- [
899
- // Reported by React with no extra message:
900
- expect.objectContaining({
901
- message: 'Boom',
902
- }),
903
- ],
904
- ]);
905
- }
906
-
907
- // Check next render doesn't throw.
908
- windowOnError.mockReset();
909
- console.error.mockReset();
910
- await act(() => {
911
- ReactDOM.render(<NoError />, container);
912
- });
913
- expect(container.textContent).toBe('OK');
914
- expect(windowOnError.mock.calls).toEqual([]);
915
- if (__DEV__) {
916
- expect(console.error.mock.calls).toEqual([
917
- [expect.stringContaining('ReactDOM.render is no longer supported')],
918
- ]);
919
- }
920
- });
921
-
922
- it('logs layout effect errors with an error boundary', async () => {
923
- spyOnDevAndProd(console, 'error');
924
-
925
- function Foo() {
926
- React.useLayoutEffect(() => {
927
- throw Error('Boom');
928
- }, []);
929
- return null;
930
- }
931
-
932
- await act(() => {
933
- ReactDOM.render(
934
- <ErrorBoundary>
935
- <Foo />
936
- </ErrorBoundary>,
937
- container,
938
- );
939
- });
940
-
941
- if (__DEV__) {
942
- expect(windowOnError.mock.calls).toEqual([
943
- [
944
- // Reported due to guarded callback:
945
- expect.objectContaining({
946
- message: 'Boom',
947
- }),
948
- ],
949
- ]);
950
- expect(console.error.mock.calls).toEqual([
951
- [expect.stringContaining('ReactDOM.render is no longer supported')],
952
- [
953
- // Reported by jsdom due to the guarded callback:
954
- expect.objectContaining({
955
- detail: expect.objectContaining({
956
- message: 'Boom',
957
- }),
958
- type: 'unhandled exception',
959
- }),
960
- ],
961
- [
962
- // Addendum by React:
963
- expect.stringContaining(
964
- 'The above error occurred in the <Foo> component',
965
- ),
966
- ],
967
- ]);
968
- } else {
969
- // The top-level error was caught with try/catch, and there's no guarded callback,
970
- // so in production we don't see an error event.
971
- expect(windowOnError.mock.calls).toEqual([]);
972
- expect(console.error.mock.calls).toEqual([
973
- [
974
- // Reported by React with no extra message:
975
- expect.objectContaining({
976
- message: 'Boom',
977
- }),
978
- ],
979
- ]);
980
- }
981
-
982
- // Check next render doesn't throw.
983
- windowOnError.mockReset();
984
- console.error.mockReset();
985
- await act(() => {
986
- ReactDOM.render(<NoError />, container);
987
- });
988
- expect(container.textContent).toBe('OK');
989
- expect(windowOnError.mock.calls).toEqual([]);
990
- if (__DEV__) {
991
- expect(console.error.mock.calls).toEqual([
992
- [expect.stringContaining('ReactDOM.render is no longer supported')],
993
- ]);
994
- }
995
- });
996
-
997
- it('logs passive effect errors without an error boundary', async () => {
998
- spyOnDevAndProd(console, 'error');
999
-
1000
- function Foo() {
1001
- React.useEffect(() => {
1002
- throw Error('Boom');
1003
- }, []);
1004
- return null;
1005
- }
1006
-
1007
- await act(async () => {
1008
- ReactDOM.render(<Foo />, container);
1009
- await waitForThrow('Boom');
1010
- });
1011
-
1012
- if (__DEV__) {
1013
- expect(windowOnError.mock.calls).toEqual([
1014
- [
1015
- // Reported due to guarded callback:
1016
- expect.objectContaining({
1017
- message: 'Boom',
1018
- }),
1019
- ],
1020
- ]);
1021
- expect(console.error.mock.calls).toEqual([
1022
- [expect.stringContaining('ReactDOM.render is no longer supported')],
1023
- [
1024
- // Reported due to the guarded callback:
1025
- expect.objectContaining({
1026
- detail: expect.objectContaining({
1027
- message: 'Boom',
1028
- }),
1029
- type: 'unhandled exception',
1030
- }),
1031
- ],
1032
- [
1033
- // Addendum by React:
1034
- expect.stringContaining(
1035
- 'The above error occurred in the <Foo> component',
1036
- ),
1037
- ],
1038
- ]);
1039
- } else {
1040
- // The top-level error was caught with try/catch, and there's no guarded callback,
1041
- // so in production we don't see an error event.
1042
- expect(windowOnError.mock.calls).toEqual([]);
1043
- expect(console.error.mock.calls).toEqual([
1044
- [
1045
- // Reported by React with no extra message:
1046
- expect.objectContaining({
1047
- message: 'Boom',
1048
- }),
1049
- ],
1050
- ]);
1051
- }
1052
-
1053
- // Check next render doesn't throw.
1054
- windowOnError.mockReset();
1055
- console.error.mockReset();
1056
- await act(() => {
1057
- ReactDOM.render(<NoError />, container);
1058
- });
1059
- expect(container.textContent).toBe('OK');
1060
- expect(windowOnError.mock.calls).toEqual([]);
1061
- if (__DEV__) {
1062
- expect(console.error.mock.calls).toEqual([
1063
- [expect.stringContaining('ReactDOM.render is no longer supported')],
1064
- ]);
1065
- }
1066
- });
1067
-
1068
- it('logs passive effect errors with an error boundary', async () => {
1069
- spyOnDevAndProd(console, 'error');
1070
-
1071
- function Foo() {
1072
- React.useEffect(() => {
1073
- throw Error('Boom');
1074
- }, []);
1075
- return null;
1076
- }
1077
-
1078
- await act(() => {
1079
- ReactDOM.render(
1080
- <ErrorBoundary>
1081
- <Foo />
1082
- </ErrorBoundary>,
1083
- container,
1084
- );
1085
- });
1086
-
1087
- if (__DEV__) {
1088
- // Reported due to guarded callback:
1089
- expect(windowOnError.mock.calls).toEqual([
1090
- [
1091
- expect.objectContaining({
1092
- message: 'Boom',
1093
- }),
1094
- ],
1095
- ]);
1096
- expect(console.error.mock.calls).toEqual([
1097
- [expect.stringContaining('ReactDOM.render is no longer supported')],
1098
- [
1099
- // Reported by jsdom due to the guarded callback:
1100
- expect.objectContaining({
1101
- detail: expect.objectContaining({
1102
- message: 'Boom',
1103
- }),
1104
- type: 'unhandled exception',
1105
- }),
1106
- ],
1107
- [
1108
- // Addendum by React:
1109
- expect.stringContaining(
1110
- 'The above error occurred in the <Foo> component',
1111
- ),
1112
- ],
1113
- ]);
1114
- } else {
1115
- // The top-level error was caught with try/catch, and there's no guarded callback,
1116
- // so in production we don't see an error event.
1117
- expect(windowOnError.mock.calls).toEqual([]);
1118
- expect(console.error.mock.calls).toEqual([
1119
- [
1120
- // Reported by React with no extra message:
1121
- expect.objectContaining({
1122
- message: 'Boom',
1123
- }),
1124
- ],
1125
- ]);
1126
- }
1127
-
1128
- // Check next render doesn't throw.
1129
- windowOnError.mockReset();
1130
- console.error.mockReset();
1131
- await act(() => {
1132
- ReactDOM.render(<NoError />, container);
1133
- });
1134
- expect(container.textContent).toBe('OK');
1135
- expect(windowOnError.mock.calls).toEqual([]);
1136
- if (__DEV__) {
1137
- expect(console.error.mock.calls).toEqual([
1138
- [expect.stringContaining('ReactDOM.render is no longer supported')],
1139
- ]);
1140
- }
1141
- });
1142
- });
608
});
packages/react-dom/src/__tests__/ReactDOMConsoleErrorReportingLegacy-test.js
new
+589
@@ -0,0 +1,589 @@
1
+/**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+'use strict';
9
+
10
+describe('ReactDOMConsoleErrorReporting', () => {
11
+ let act;
12
+ let React;
13
+ let ReactDOM;
14
+
15
+ let ErrorBoundary;
16
+ let NoError;
17
+ let container;
18
+ let windowOnError;
19
+ let waitForThrow;
20
+
21
+ beforeEach(() => {
22
+ jest.resetModules();
23
+ act = require('internal-test-utils').act;
24
+ React = require('react');
25
+ ReactDOM = require('react-dom');
26
+
27
+ const InternalTestUtils = require('internal-test-utils');
28
+ waitForThrow = InternalTestUtils.waitForThrow;
29
+
30
+ ErrorBoundary = class extends React.Component {
31
+ state = {error: null};
32
+ static getDerivedStateFromError(error) {
33
+ return {error};
34
+ }
35
+ render() {
36
+ if (this.state.error) {
37
+ return <h1>Caught: {this.state.error.message}</h1>;
38
+ }
39
+ return this.props.children;
40
+ }
41
+ };
42
+ NoError = function () {
43
+ return <h1>OK</h1>;
44
+ };
45
+ container = document.createElement('div');
46
+ document.body.appendChild(container);
47
+ windowOnError = jest.fn();
48
+ window.addEventListener('error', windowOnError);
49
+ });
50
+
51
+ afterEach(() => {
52
+ document.body.removeChild(container);
53
+ window.removeEventListener('error', windowOnError);
54
+ jest.restoreAllMocks();
55
+ });
56
+
57
+ describe('ReactDOM.render', () => {
58
+ it('logs errors during event handlers', async () => {
59
+ spyOnDevAndProd(console, 'error');
60
+
61
+ function Foo() {
62
+ return (
63
+ <button
64
+ onClick={() => {
65
+ throw Error('Boom');
66
+ }}>
67
+ click me
68
+ </button>
69
+ );
70
+ }
71
+
72
+ await act(() => {
73
+ ReactDOM.render(<Foo />, container);
74
+ });
75
+
76
+ await act(() => {
77
+ container.firstChild.dispatchEvent(
78
+ new MouseEvent('click', {
79
+ bubbles: true,
80
+ }),
81
+ );
82
+ });
83
+
84
+ if (__DEV__) {
85
+ expect(windowOnError.mock.calls).toEqual([
86
+ [
87
+ // Reported because we're in a browser click event:
88
+ expect.objectContaining({
89
+ message: 'Boom',
90
+ }),
91
+ ],
92
+ [
93
+ // This one is jsdom-only. Real browser deduplicates it.
94
+ // (In DEV, we have a nested event due to guarded callback.)
95
+ expect.objectContaining({
96
+ message: 'Boom',
97
+ }),
98
+ ],
99
+ ]);
100
+ expect(console.error.mock.calls).toEqual([
101
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
102
+ [
103
+ // Reported because we're in a browser click event:
104
+ expect.objectContaining({
105
+ detail: expect.objectContaining({
106
+ message: 'Boom',
107
+ }),
108
+ type: 'unhandled exception',
109
+ }),
110
+ ],
111
+ [
112
+ // This one is jsdom-only. Real browser deduplicates it.
113
+ // (In DEV, we have a nested event due to guarded callback.)
114
+ expect.objectContaining({
115
+ detail: expect.objectContaining({
116
+ message: 'Boom',
117
+ }),
118
+ type: 'unhandled exception',
119
+ }),
120
+ ],
121
+ ]);
122
+ } else {
123
+ expect(windowOnError.mock.calls).toEqual([
124
+ [
125
+ // Reported because we're in a browser click event:
126
+ expect.objectContaining({
127
+ message: 'Boom',
128
+ }),
129
+ ],
130
+ ]);
131
+ expect(console.error.mock.calls).toEqual([
132
+ [
133
+ // Reported because we're in a browser click event:
134
+ expect.objectContaining({
135
+ detail: expect.objectContaining({
136
+ message: 'Boom',
137
+ }),
138
+ type: 'unhandled exception',
139
+ }),
140
+ ],
141
+ ]);
142
+ }
143
+
144
+ // Check next render doesn't throw.
145
+ windowOnError.mockReset();
146
+ console.error.mockReset();
147
+ await act(() => {
148
+ ReactDOM.render(<NoError />, container);
149
+ });
150
+ expect(container.textContent).toBe('OK');
151
+ expect(windowOnError.mock.calls).toEqual([]);
152
+ if (__DEV__) {
153
+ expect(console.error.mock.calls).toEqual([
154
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
155
+ ]);
156
+ }
157
+ });
158
+
159
+ it('logs render errors without an error boundary', async () => {
160
+ spyOnDevAndProd(console, 'error');
161
+
162
+ function Foo() {
163
+ throw Error('Boom');
164
+ }
165
+
166
+ expect(() => {
167
+ ReactDOM.render(<Foo />, container);
168
+ }).toThrow('Boom');
169
+
170
+ if (__DEV__) {
171
+ expect(windowOnError.mock.calls).toEqual([
172
+ [
173
+ // Reported due to guarded callback:
174
+ expect.objectContaining({
175
+ message: 'Boom',
176
+ }),
177
+ ],
178
+ ]);
179
+ expect(console.error.mock.calls).toEqual([
180
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
181
+ [
182
+ // Reported due to the guarded callback:
183
+ expect.objectContaining({
184
+ detail: expect.objectContaining({
185
+ message: 'Boom',
186
+ }),
187
+ type: 'unhandled exception',
188
+ }),
189
+ ],
190
+ [
191
+ // Addendum by React:
192
+ expect.stringContaining(
193
+ 'The above error occurred in the <Foo> component',
194
+ ),
195
+ ],
196
+ ]);
197
+ } else {
198
+ // The top-level error was caught with try/catch, and there's no guarded callback,
199
+ // so in production we don't see an error event.
200
+ expect(windowOnError.mock.calls).toEqual([]);
201
+ expect(console.error.mock.calls).toEqual([
202
+ [
203
+ // Reported by React with no extra message:
204
+ expect.objectContaining({
205
+ message: 'Boom',
206
+ }),
207
+ ],
208
+ ]);
209
+ }
210
+
211
+ // Check next render doesn't throw.
212
+ windowOnError.mockReset();
213
+ console.error.mockReset();
214
+ await act(() => {
215
+ ReactDOM.render(<NoError />, container);
216
+ });
217
+ expect(container.textContent).toBe('OK');
218
+ expect(windowOnError.mock.calls).toEqual([]);
219
+ if (__DEV__) {
220
+ expect(console.error.mock.calls).toEqual([
221
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
222
+ ]);
223
+ }
224
+ });
225
+
226
+ it('logs render errors with an error boundary', async () => {
227
+ spyOnDevAndProd(console, 'error');
228
+
229
+ function Foo() {
230
+ throw Error('Boom');
231
+ }
232
+
233
+ await act(() => {
234
+ ReactDOM.render(
235
+ <ErrorBoundary>
236
+ <Foo />
237
+ </ErrorBoundary>,
238
+ container,
239
+ );
240
+ });
241
+
242
+ if (__DEV__) {
243
+ expect(windowOnError.mock.calls).toEqual([
244
+ [
245
+ // Reported due to guarded callback:
246
+ expect.objectContaining({
247
+ message: 'Boom',
248
+ }),
249
+ ],
250
+ ]);
251
+ expect(console.error.mock.calls).toEqual([
252
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
253
+ [
254
+ // Reported by jsdom due to the guarded callback:
255
+ expect.objectContaining({
256
+ detail: expect.objectContaining({
257
+ message: 'Boom',
258
+ }),
259
+ type: 'unhandled exception',
260
+ }),
261
+ ],
262
+ [
263
+ // Addendum by React:
264
+ expect.stringContaining(
265
+ 'The above error occurred in the <Foo> component',
266
+ ),
267
+ ],
268
+ ]);
269
+ } else {
270
+ // The top-level error was caught with try/catch, and there's no guarded callback,
271
+ // so in production we don't see an error event.
272
+ expect(windowOnError.mock.calls).toEqual([]);
273
+ expect(console.error.mock.calls).toEqual([
274
+ [
275
+ // Reported by React with no extra message:
276
+ expect.objectContaining({
277
+ message: 'Boom',
278
+ }),
279
+ ],
280
+ ]);
281
+ }
282
+
283
+ // Check next render doesn't throw.
284
+ windowOnError.mockReset();
285
+ console.error.mockReset();
286
+ await act(() => {
287
+ ReactDOM.render(<NoError />, container);
288
+ });
289
+ expect(container.textContent).toBe('OK');
290
+ expect(windowOnError.mock.calls).toEqual([]);
291
+ if (__DEV__) {
292
+ expect(console.error.mock.calls).toEqual([
293
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
294
+ ]);
295
+ }
296
+ });
297
+
298
+ it('logs layout effect errors without an error boundary', async () => {
299
+ spyOnDevAndProd(console, 'error');
300
+
301
+ function Foo() {
302
+ React.useLayoutEffect(() => {
303
+ throw Error('Boom');
304
+ }, []);
305
+ return null;
306
+ }
307
+
308
+ expect(() => {
309
+ ReactDOM.render(<Foo />, container);
310
+ }).toThrow('Boom');
311
+
312
+ if (__DEV__) {
313
+ expect(windowOnError.mock.calls).toEqual([
314
+ [
315
+ // Reported due to guarded callback:
316
+ expect.objectContaining({
317
+ message: 'Boom',
318
+ }),
319
+ ],
320
+ ]);
321
+ expect(console.error.mock.calls).toEqual([
322
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
323
+ [
324
+ // Reported due to the guarded callback:
325
+ expect.objectContaining({
326
+ detail: expect.objectContaining({
327
+ message: 'Boom',
328
+ }),
329
+ type: 'unhandled exception',
330
+ }),
331
+ ],
332
+ [
333
+ // Addendum by React:
334
+ expect.stringContaining(
335
+ 'The above error occurred in the <Foo> component',
336
+ ),
337
+ ],
338
+ ]);
339
+ } else {
340
+ // The top-level error was caught with try/catch, and there's no guarded callback,
341
+ // so in production we don't see an error event.
342
+ expect(windowOnError.mock.calls).toEqual([]);
343
+ expect(console.error.mock.calls).toEqual([
344
+ [
345
+ // Reported by React with no extra message:
346
+ expect.objectContaining({
347
+ message: 'Boom',
348
+ }),
349
+ ],
350
+ ]);
351
+ }
352
+
353
+ // Check next render doesn't throw.
354
+ windowOnError.mockReset();
355
+ console.error.mockReset();
356
+ await act(() => {
357
+ ReactDOM.render(<NoError />, container);
358
+ });
359
+ expect(container.textContent).toBe('OK');
360
+ expect(windowOnError.mock.calls).toEqual([]);
361
+ if (__DEV__) {
362
+ expect(console.error.mock.calls).toEqual([
363
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
364
+ ]);
365
+ }
366
+ });
367
+
368
+ it('logs layout effect errors with an error boundary', async () => {
369
+ spyOnDevAndProd(console, 'error');
370
+
371
+ function Foo() {
372
+ React.useLayoutEffect(() => {
373
+ throw Error('Boom');
374
+ }, []);
375
+ return null;
376
+ }
377
+
378
+ await act(() => {
379
+ ReactDOM.render(
380
+ <ErrorBoundary>
381
+ <Foo />
382
+ </ErrorBoundary>,
383
+ container,
384
+ );
385
+ });
386
+
387
+ if (__DEV__) {
388
+ expect(windowOnError.mock.calls).toEqual([
389
+ [
390
+ // Reported due to guarded callback:
391
+ expect.objectContaining({
392
+ message: 'Boom',
393
+ }),
394
+ ],
395
+ ]);
396
+ expect(console.error.mock.calls).toEqual([
397
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
398
+ [
399
+ // Reported by jsdom due to the guarded callback:
400
+ expect.objectContaining({
401
+ detail: expect.objectContaining({
402
+ message: 'Boom',
403
+ }),
404
+ type: 'unhandled exception',
405
+ }),
406
+ ],
407
+ [
408
+ // Addendum by React:
409
+ expect.stringContaining(
410
+ 'The above error occurred in the <Foo> component',
411
+ ),
412
+ ],
413
+ ]);
414
+ } else {
415
+ // The top-level error was caught with try/catch, and there's no guarded callback,
416
+ // so in production we don't see an error event.
417
+ expect(windowOnError.mock.calls).toEqual([]);
418
+ expect(console.error.mock.calls).toEqual([
419
+ [
420
+ // Reported by React with no extra message:
421
+ expect.objectContaining({
422
+ message: 'Boom',
423
+ }),
424
+ ],
425
+ ]);
426
+ }
427
+
428
+ // Check next render doesn't throw.
429
+ windowOnError.mockReset();
430
+ console.error.mockReset();
431
+ await act(() => {
432
+ ReactDOM.render(<NoError />, container);
433
+ });
434
+ expect(container.textContent).toBe('OK');
435
+ expect(windowOnError.mock.calls).toEqual([]);
436
+ if (__DEV__) {
437
+ expect(console.error.mock.calls).toEqual([
438
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
439
+ ]);
440
+ }
441
+ });
442
+
443
+ it('logs passive effect errors without an error boundary', async () => {
444
+ spyOnDevAndProd(console, 'error');
445
+
446
+ function Foo() {
447
+ React.useEffect(() => {
448
+ throw Error('Boom');
449
+ }, []);
450
+ return null;
451
+ }
452
+
453
+ await act(async () => {
454
+ ReactDOM.render(<Foo />, container);
455
+ await waitForThrow('Boom');
456
+ });
457
+
458
+ if (__DEV__) {
459
+ expect(windowOnError.mock.calls).toEqual([
460
+ [
461
+ // Reported due to guarded callback:
462
+ expect.objectContaining({
463
+ message: 'Boom',
464
+ }),
465
+ ],
466
+ ]);
467
+ expect(console.error.mock.calls).toEqual([
468
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
469
+ [
470
+ // Reported due to the guarded callback:
471
+ expect.objectContaining({
472
+ detail: expect.objectContaining({
473
+ message: 'Boom',
474
+ }),
475
+ type: 'unhandled exception',
476
+ }),
477
+ ],
478
+ [
479
+ // Addendum by React:
480
+ expect.stringContaining(
481
+ 'The above error occurred in the <Foo> component',
482
+ ),
483
+ ],
484
+ ]);
485
+ } else {
486
+ // The top-level error was caught with try/catch, and there's no guarded callback,
487
+ // so in production we don't see an error event.
488
+ expect(windowOnError.mock.calls).toEqual([]);
489
+ expect(console.error.mock.calls).toEqual([
490
+ [
491
+ // Reported by React with no extra message:
492
+ expect.objectContaining({
493
+ message: 'Boom',
494
+ }),
495
+ ],
496
+ ]);
497
+ }
498
+
499
+ // Check next render doesn't throw.
500
+ windowOnError.mockReset();
501
+ console.error.mockReset();
502
+ await act(() => {
503
+ ReactDOM.render(<NoError />, container);
504
+ });
505
+ expect(container.textContent).toBe('OK');
506
+ expect(windowOnError.mock.calls).toEqual([]);
507
+ if (__DEV__) {
508
+ expect(console.error.mock.calls).toEqual([
509
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
510
+ ]);
511
+ }
512
+ });
513
+
514
+ it('logs passive effect errors with an error boundary', async () => {
515
+ spyOnDevAndProd(console, 'error');
516
+
517
+ function Foo() {
518
+ React.useEffect(() => {
519
+ throw Error('Boom');
520
+ }, []);
521
+ return null;
522
+ }
523
+
524
+ await act(() => {
525
+ ReactDOM.render(
526
+ <ErrorBoundary>
527
+ <Foo />
528
+ </ErrorBoundary>,
529
+ container,
530
+ );
531
+ });
532
+
533
+ if (__DEV__) {
534
+ // Reported due to guarded callback:
535
+ expect(windowOnError.mock.calls).toEqual([
536
+ [
537
+ expect.objectContaining({
538
+ message: 'Boom',
539
+ }),
540
+ ],
541
+ ]);
542
+ expect(console.error.mock.calls).toEqual([
543
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
544
+ [
545
+ // Reported by jsdom due to the guarded callback:
546
+ expect.objectContaining({
547
+ detail: expect.objectContaining({
548
+ message: 'Boom',
549
+ }),
550
+ type: 'unhandled exception',
551
+ }),
552
+ ],
553
+ [
554
+ // Addendum by React:
555
+ expect.stringContaining(
556
+ 'The above error occurred in the <Foo> component',
557
+ ),
558
+ ],
559
+ ]);
560
+ } else {
561
+ // The top-level error was caught with try/catch, and there's no guarded callback,
562
+ // so in production we don't see an error event.
563
+ expect(windowOnError.mock.calls).toEqual([]);
564
+ expect(console.error.mock.calls).toEqual([
565
+ [
566
+ // Reported by React with no extra message:
567
+ expect.objectContaining({
568
+ message: 'Boom',
569
+ }),
570
+ ],
571
+ ]);
572
+ }
573
+
574
+ // Check next render doesn't throw.
575
+ windowOnError.mockReset();
576
+ console.error.mockReset();
577
+ await act(() => {
578
+ ReactDOM.render(<NoError />, container);
579
+ });
580
+ expect(container.textContent).toBe('OK');
581
+ expect(windowOnError.mock.calls).toEqual([]);
582
+ if (__DEV__) {
583
+ expect(console.error.mock.calls).toEqual([
584
+ [expect.stringContaining('ReactDOM.render is no longer supported')],
585
+ ]);
586
+ }
587
+ });
588
+ });
589
+});