Skip to content

Commit 7c11aad

Browse files
authored
[assert helpers] react-dom (pt2) (facebook#31902)
Converts more react-dom tests
1 parent d8a08f8 commit 7c11aad

File tree

7 files changed

+628
-448
lines changed

7 files changed

+628
-448
lines changed

packages/react-dom/src/__tests__/ReactDOMComponentTree-test.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ describe('ReactDOMComponentTree', () => {
1414
let ReactDOMClient;
1515
let act;
1616
let container;
17+
let assertConsoleErrorDev;
1718

1819
beforeEach(() => {
1920
React = require('react');
2021
ReactDOMClient = require('react-dom/client');
2122
act = require('internal-test-utils').act;
23+
assertConsoleErrorDev =
24+
require('internal-test-utils').assertConsoleErrorDev;
2225

2326
container = document.createElement('div');
2427
document.body.appendChild(container);
@@ -190,18 +193,18 @@ describe('ReactDOMComponentTree', () => {
190193
root.render(<Controlled />);
191194
});
192195

193-
await expect(
194-
async () =>
195-
await act(() => {
196-
simulateInput(inputRef.current, finishValue);
197-
}),
198-
).toErrorDev(
196+
await act(() => {
197+
simulateInput(inputRef.current, finishValue);
198+
});
199+
assertConsoleErrorDev([
199200
'A component is changing an uncontrolled input to be controlled. ' +
200201
'This is likely caused by the value changing from undefined to ' +
201202
'a defined value, which should not happen. ' +
202203
'Decide between using a controlled or uncontrolled input ' +
203204
'element for the lifetime of the component. More info: ' +
204-
'https://react.dev/link/controlled-components',
205-
);
205+
'https://react.dev/link/controlled-components\n' +
206+
' in input (at **)\n' +
207+
' in Controlled (at **)',
208+
]);
206209
});
207210
});

packages/react-dom/src/__tests__/ReactDOMFiber-test.js

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -746,8 +746,13 @@ describe('ReactDOMFiber', () => {
746746
root.render(<Parent />);
747747
});
748748
assertConsoleErrorDev([
749-
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
750-
'Component uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
749+
'Parent uses the legacy childContextTypes API which will soon be removed. ' +
750+
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
751+
' in Parent (at **)',
752+
'Component uses the legacy contextTypes API which will soon be removed. ' +
753+
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
754+
(gate('enableOwnerStacks') ? '' : ' in Component (at **)\n') +
755+
' in Parent (at **)',
751756
]);
752757
expect(container.innerHTML).toBe('');
753758
expect(portalContainer.innerHTML).toBe('<div>bar</div>');
@@ -957,15 +962,14 @@ describe('ReactDOMFiber', () => {
957962
return <div onClick="woops" />;
958963
}
959964
}
960-
expect(() => {
961-
ReactDOM.flushSync(() => {
962-
root.render(<Example />);
963-
});
964-
}).toErrorDev(
965+
ReactDOM.flushSync(() => {
966+
root.render(<Example />);
967+
});
968+
assertConsoleErrorDev([
965969
'Expected `onClick` listener to be a function, instead got a value of `string` type.\n' +
966970
' in div (at **)\n' +
967971
' in Example (at **)',
968-
);
972+
]);
969973
});
970974

971975
it('should warn with a special message for `false` event listeners', () => {
@@ -974,17 +978,16 @@ describe('ReactDOMFiber', () => {
974978
return <div onClick={false} />;
975979
}
976980
}
977-
expect(() => {
978-
ReactDOM.flushSync(() => {
979-
root.render(<Example />);
980-
});
981-
}).toErrorDev(
981+
ReactDOM.flushSync(() => {
982+
root.render(<Example />);
983+
});
984+
assertConsoleErrorDev([
982985
'Expected `onClick` listener to be a function, instead got `false`.\n\n' +
983986
'If you used to conditionally omit it with onClick={condition && value}, ' +
984987
'pass onClick={condition ? value : undefined} instead.\n' +
985988
' in div (at **)\n' +
986989
' in Example (at **)',
987-
);
990+
]);
988991
});
989992

990993
it('should not update event handlers until commit', async () => {

packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ let waitForAll;
1919
let waitFor;
2020
let waitForMicrotasks;
2121
let assertLog;
22+
let assertConsoleErrorDev;
2223

2324
const setUntrackedInputValue = Object.getOwnPropertyDescriptor(
2425
HTMLInputElement.prototype,
@@ -34,6 +35,8 @@ describe('ReactDOMFiberAsync', () => {
3435
ReactDOM = require('react-dom');
3536
ReactDOMClient = require('react-dom/client');
3637
act = require('internal-test-utils').act;
38+
assertConsoleErrorDev =
39+
require('internal-test-utils').assertConsoleErrorDev;
3740
Scheduler = require('scheduler');
3841

3942
const InternalTestUtils = require('internal-test-utils');
@@ -176,11 +179,15 @@ describe('ReactDOMFiberAsync', () => {
176179
root.render(<Component />);
177180
});
178181
// Update
179-
expect(() => {
180-
ReactDOM.flushSync(() => {
181-
root.render(<Component />);
182-
});
183-
}).toErrorDev('flushSync was called from inside a lifecycle method');
182+
ReactDOM.flushSync(() => {
183+
root.render(<Component />);
184+
});
185+
assertConsoleErrorDev([
186+
'flushSync was called from inside a lifecycle method. ' +
187+
'React cannot flush when React is already rendering. ' +
188+
'Consider moving this call to a scheduler task or micro task.\n' +
189+
' in Component (at **)',
190+
]);
184191
});
185192

186193
describe('concurrent mode', () => {

packages/react-dom/src/__tests__/ReactDOMFizzForm-test.js

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ let useFormStatus;
2626
let useOptimistic;
2727
let useActionState;
2828
let Scheduler;
29+
let assertConsoleErrorDev;
2930

3031
describe('ReactDOMFizzForm', () => {
3132
beforeEach(() => {
@@ -38,6 +39,8 @@ describe('ReactDOMFizzForm', () => {
3839
useFormStatus = require('react-dom').useFormStatus;
3940
useOptimistic = require('react').useOptimistic;
4041
act = require('internal-test-utils').act;
42+
assertConsoleErrorDev =
43+
require('internal-test-utils').assertConsoleErrorDev;
4144
container = document.createElement('div');
4245
document.body.appendChild(container);
4346
// TODO: Test the old api but it warns so needs warnings to be asserted.
@@ -195,12 +198,26 @@ describe('ReactDOMFizzForm', () => {
195198
ReactDOMServer.renderToReadableStream(<App />),
196199
);
197200
await readIntoContainer(stream);
198-
await expect(async () => {
199-
await act(async () => {
200-
ReactDOMClient.hydrateRoot(container, <App isClient={true} />);
201-
});
202-
}).toErrorDev(
203-
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties.",
201+
await act(async () => {
202+
ReactDOMClient.hydrateRoot(container, <App isClient={true} />);
203+
});
204+
assertConsoleErrorDev(
205+
[
206+
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. " +
207+
"This won't be patched up. This can happen if a SSR-ed Client Component used:\n\n" +
208+
"- A server/client branch `if (typeof window !== 'undefined')`.\n" +
209+
"- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.\n" +
210+
"- Date formatting in a user's locale which doesn't match the server.\n" +
211+
'- External changing data without sending a snapshot of it along with the HTML.\n' +
212+
'- Invalid HTML tag nesting.\n\n' +
213+
'It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.\n\n' +
214+
'https://react.dev/link/hydration-mismatch\n\n' +
215+
' <App isClient={true}>\n' +
216+
' <form\n' +
217+
'+ action="action"\n' +
218+
'- action="function"\n' +
219+
' >\n',
220+
],
204221
{withoutStack: true},
205222
);
206223
});
@@ -357,23 +374,56 @@ describe('ReactDOMFizzForm', () => {
357374

358375
// Specifying the extra form fields are a DEV error, but we expect it
359376
// to eventually still be patched up after an update.
360-
await expect(async () => {
361-
const stream = await serverAct(() =>
362-
ReactDOMServer.renderToReadableStream(<App />),
363-
);
364-
await readIntoContainer(stream);
365-
}).toErrorDev([
366-
'Cannot specify a encType or method for a form that specifies a function as the action.',
367-
'Cannot specify a formTarget for a button that specifies a function as a formAction.',
377+
const stream = await serverAct(() =>
378+
ReactDOMServer.renderToReadableStream(<App />),
379+
);
380+
await readIntoContainer(stream);
381+
assertConsoleErrorDev([
382+
'Cannot specify a encType or method for a form that specifies a function as the action. ' +
383+
'React provides those automatically. They will get overridden.\n' +
384+
' in form (at **)\n' +
385+
' in App (at **)',
386+
'Cannot specify a formTarget for a button that specifies a function as a formAction. ' +
387+
'The function will always be executed in the same window.\n' +
388+
' in input (at **)\n' +
389+
(gate('enableOwnerStacks') ? '' : ' in form (at **)\n') +
390+
' in App (at **)',
368391
]);
369392
let root;
370-
await expect(async () => {
371-
await act(async () => {
372-
root = ReactDOMClient.hydrateRoot(container, <App />);
373-
});
374-
}).toErrorDev(
393+
await act(async () => {
394+
root = ReactDOMClient.hydrateRoot(container, <App />);
395+
});
396+
assertConsoleErrorDev(
375397
[
376-
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties.",
398+
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. " +
399+
"This won't be patched up. This can happen if a SSR-ed Client Component used:\n\n" +
400+
"- A server/client branch `if (typeof window !== 'undefined')`.\n" +
401+
"- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.\n" +
402+
"- Date formatting in a user's locale which doesn't match the server.\n" +
403+
'- External changing data without sending a snapshot of it along with the HTML.\n' +
404+
'- Invalid HTML tag nesting.\n\n' +
405+
'It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.\n\n' +
406+
'https://react.dev/link/hydration-mismatch\n\n' +
407+
' <App>\n' +
408+
' <form\n' +
409+
' action={function action}\n' +
410+
' ref={{current:null}}\n' +
411+
'+ method="DELETE"\n' +
412+
'- method={null}\n' +
413+
' >\n' +
414+
' <input\n' +
415+
' type="submit"\n' +
416+
' formAction={function action}\n' +
417+
' ref={{current:null}}\n' +
418+
'+ formTarget="elsewhere"\n' +
419+
'- formTarget={null}\n' +
420+
' >\n' +
421+
' <button\n' +
422+
' formAction={function action}\n' +
423+
' ref={{current:null}}\n' +
424+
'+ formEncType="text/plain"\n' +
425+
'- formEncType={null}\n' +
426+
' >\n',
377427
],
378428
{withoutStack: true},
379429
);

0 commit comments

Comments
 (0)