81
let NoErrorExpected;
82
let Scheduler;
83
let assertLog;
84
+let assertConsoleErrorDev;
85
86
describe('ReactFlight', () => {
87
beforeEach(() => {
103
Scheduler = require('scheduler');
104
const InternalTestUtils = require('internal-test-utils');
105
assertLog = InternalTestUtils.assertLog;
106
+ assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
107
108
ErrorBoundary = class extends React.Component {
109
state = {hasError: false, error: null};
1443
<div>{Array(6).fill(<NoKey />)}</div>,
1444
);
1445
ReactNoopFlightClient.read(transport);
1444
- }).toErrorDev('Each child in a list should have a unique "key" prop.', {
1445
- withoutStack: gate(flags => flags.enableOwnerStacks),
1446
- });
1446
+ }).toErrorDev('Each child in a list should have a unique "key" prop.');
1447
});
1448
1449
it('should warn in DEV a child is missing keys in client component', async () => {
2728
2729
expect(ReactNoop).toMatchRenderedOutput(<span>Hello, Seb</span>);
2730
});
2731
+
2732
+ // @gate __DEV__ && enableOwnerStacks
2733
+ it('can get the component owner stacks during rendering in dev', () => {
2734
+ let stack;
2735
+
2736
+ function Foo() {
2737
+ return ReactServer.createElement(Bar, null);
2738
+ }
2739
+ function Bar() {
2740
+ return ReactServer.createElement(
2741
+ 'div',
2742
+ null,
2743
+ ReactServer.createElement(Baz, null),
2744
+ );
2745
+ }
2746
+
2747
+ function Baz() {
2748
+ stack = ReactServer.captureOwnerStack();
2749
+ return ReactServer.createElement('span', null, 'hi');
2750
+ }
2751
+ ReactNoopFlightServer.render(
2752
+ ReactServer.createElement(
2753
+ 'div',
2754
+ null,
2755
+ ReactServer.createElement(Foo, null),
2756
+ ),
2757
+ );
2758
+
2759
+ expect(normalizeCodeLocInfo(stack)).toBe(
2760
+ '\n in Bar (at **)' + '\n in Foo (at **)',
2761
+ );
2762
+ });
2763
+
2764
+ // @gate (enableOwnerStacks && enableServerComponentLogs) || !__DEV__
2765
+ it('should not include component stacks in replayed logs (unless DevTools add them)', () => {
2766
+ function Foo() {
2767
+ return 'hi';
2768
+ }
2769
+
2770
+ function Bar() {
2771
+ const array = [];
2772
+ // Trigger key warning
2773
+ array.push(ReactServer.createElement(Foo));
2774
+ return ReactServer.createElement('div', null, array);
2775
+ }
2776
+
2777
+ function App() {
2778
+ return ReactServer.createElement(Bar);
2779
+ }
2780
+
2781
+ const transport = ReactNoopFlightServer.render(
2782
+ ReactServer.createElement(App),
2783
+ );
2784
+ assertConsoleErrorDev([
2785
+ 'Each child in a list should have a unique "key" prop.' +
2786
+ ' See https://react.dev/link/warning-keys for more information.\n' +
2787
+ ' in Bar (at **)\n' +
2788
+ ' in App (at **)',
2789
+ ]);
2790
+
2791
+ // Replay logs on the client
2792
+ ReactNoopFlightClient.read(transport);
2793
+ assertConsoleErrorDev(
2794
+ [
2795
+ 'Each child in a list should have a unique "key" prop.' +
2796
+ ' See https://react.dev/link/warning-keys for more information.',
2797
+ ],
2798
+ // We should not have a stack in the replay because that should be added either by console.createTask
2799
+ // or React DevTools on the client. Neither of which we do here.
2800
+ {withoutStack: true},
2801
+ );
2802
+ });
2803
});