Files
react/packages/react-dom/src/__tests__/ReactDOMServerIntegrationReconnecting-test.js
T
Sunil Pai e1c5e8720d warn if passive effects get queued outside of an act() call. (#15763)
* warn if passive effects get queued outside of an act() call

While the code itself isn't much (it adds the warning to mountEffect() and updateEffect() in ReactFiberHooks), it does change a lot of our tests. We follow a bad-ish pattern here, which is doing asserts inside act() scopes, but it makes sense for *us* because we're testing intermediate states, and we're manually flush/yield what we need in these tests.

This commit has one last failing test. Working on it.

* pass lint

* pass failing test, fixes another

- a test was failing in ReactDOMServerIntegrationHooks while testing an effect; the behaviour of yields was different from browser and server when wrapped with act(). further, because of how we initialized modules, act() around renders wasn't working corrrectly. solved by passing in ReactTestUtils in initModules, and checking on the finally yielded values in the specific test.
- in ReactUpdates, while testing an infinite recursion detection, the test needed to be wrapped in an act(), which would have caused the recusrsion error to throw. solived by rethrowing the error from inside the act().

* pass ReactDOMServerSuspense

* stray todo

* a better message, consistent with the state update one.
2019-06-24 11:18:24 +01:00

462 lines
14 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils');
let React;
let ReactDOM;
let ReactDOMServer;
let ReactTestUtils;
function initModules() {
// Reset warning cache.
jest.resetModuleRegistry();
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
ReactTestUtils,
};
}
const {
resetModules,
expectMarkupMismatch,
expectMarkupMatch,
} = ReactDOMServerIntegrationUtils(initModules);
describe('ReactDOMServerIntegration', () => {
beforeEach(() => {
resetModules();
});
describe('reconnecting to server markup', function() {
let EmptyComponent;
beforeEach(() => {
EmptyComponent = class extends React.Component {
render() {
return null;
}
};
});
describe('elements', function() {
describe('reconnecting different component implementations', function() {
let ES6ClassComponent, PureComponent, bareElement;
beforeEach(() => {
// try each type of component on client and server.
ES6ClassComponent = class extends React.Component {
render() {
return <div id={this.props.id} />;
}
};
PureComponent = props => <div id={props.id} />;
bareElement = <div id="foobarbaz" />;
});
it('should reconnect ES6 Class to ES6 Class', () =>
expectMarkupMatch(
<ES6ClassComponent id="foobarbaz" />,
<ES6ClassComponent id="foobarbaz" />,
));
it('should reconnect Pure Component to ES6 Class', () =>
expectMarkupMatch(
<ES6ClassComponent id="foobarbaz" />,
<PureComponent id="foobarbaz" />,
));
it('should reconnect Bare Element to ES6 Class', () =>
expectMarkupMatch(<ES6ClassComponent id="foobarbaz" />, bareElement));
it('should reconnect ES6 Class to Pure Component', () =>
expectMarkupMatch(
<PureComponent id="foobarbaz" />,
<ES6ClassComponent id="foobarbaz" />,
));
it('should reconnect Pure Component to Pure Component', () =>
expectMarkupMatch(
<PureComponent id="foobarbaz" />,
<PureComponent id="foobarbaz" />,
));
it('should reconnect Bare Element to Pure Component', () =>
expectMarkupMatch(<PureComponent id="foobarbaz" />, bareElement));
it('should reconnect ES6 Class to Bare Element', () =>
expectMarkupMatch(bareElement, <ES6ClassComponent id="foobarbaz" />));
it('should reconnect Pure Component to Bare Element', () =>
expectMarkupMatch(bareElement, <PureComponent id="foobarbaz" />));
it('should reconnect Bare Element to Bare Element', () =>
expectMarkupMatch(bareElement, bareElement));
});
it('should error reconnecting different element types', () =>
expectMarkupMismatch(<div />, <span />));
it('should error reconnecting fewer root children', () =>
expectMarkupMismatch(<span key="a" />, [
<span key="a" />,
<span key="b" />,
]));
it('should error reconnecting missing attributes', () =>
expectMarkupMismatch(<div id="foo" />, <div />));
it('should error reconnecting added attributes', () =>
expectMarkupMismatch(<div />, <div id="foo" />));
it('should error reconnecting different attribute values', () =>
expectMarkupMismatch(<div id="foo" />, <div id="bar" />));
it('can explicitly ignore errors reconnecting different element types of children', () =>
expectMarkupMatch(
<div>
<div />
</div>,
<div suppressHydrationWarning={true}>
<span />
</div>,
));
it('can explicitly ignore errors reconnecting missing attributes', () =>
expectMarkupMatch(
<div id="foo" />,
<div suppressHydrationWarning={true} />,
));
it('can explicitly ignore errors reconnecting added attributes', () =>
expectMarkupMatch(
<div />,
<div id="foo" suppressHydrationWarning={true} />,
));
it('can explicitly ignore errors reconnecting different attribute values', () =>
expectMarkupMatch(
<div id="foo" />,
<div id="bar" suppressHydrationWarning={true} />,
));
it('can not deeply ignore errors reconnecting different attribute values', () =>
expectMarkupMismatch(
<div>
<div id="foo" />
</div>,
<div suppressHydrationWarning={true}>
<div id="bar" />
</div>,
));
});
describe('inline styles', function() {
it('should error reconnecting missing style attribute', () =>
expectMarkupMismatch(<div style={{width: '1px'}} />, <div />));
it('should error reconnecting added style attribute', () =>
expectMarkupMismatch(<div />, <div style={{width: '1px'}} />));
it('should error reconnecting empty style attribute', () =>
expectMarkupMismatch(
<div style={{width: '1px'}} />,
<div style={{}} />,
));
it('should error reconnecting added style values', () =>
expectMarkupMismatch(
<div style={{}} />,
<div style={{width: '1px'}} />,
));
it('should error reconnecting different style values', () =>
expectMarkupMismatch(
<div style={{width: '1px'}} />,
<div style={{width: '2px'}} />,
));
it('should reconnect number and string versions of a number', () =>
expectMarkupMatch(
<div style={{width: '1px', height: 2}} />,
<div style={{width: 1, height: '2px'}} />,
));
it('should error reconnecting reordered style values', () =>
expectMarkupMismatch(
<div style={{width: '1px', fontSize: '2px'}} />,
<div style={{fontSize: '2px', width: '1px'}} />,
));
it('can explicitly ignore errors reconnecting added style values', () =>
expectMarkupMatch(
<div style={{}} />,
<div style={{width: '1px'}} suppressHydrationWarning={true} />,
));
it('can explicitly ignore reconnecting different style values', () =>
expectMarkupMatch(
<div style={{width: '1px'}} />,
<div style={{width: '2px'}} suppressHydrationWarning={true} />,
));
});
describe('text nodes', function() {
it('should error reconnecting different text', () =>
expectMarkupMismatch(<div>Text</div>, <div>Other Text</div>));
it('should reconnect a div with a number and string version of number', () =>
expectMarkupMatch(<div>{2}</div>, <div>2</div>));
it('should error reconnecting different numbers', () =>
expectMarkupMismatch(<div>{2}</div>, <div>{3}</div>));
it('should error reconnecting different number from text', () =>
expectMarkupMismatch(<div>{2}</div>, <div>3</div>));
it('should error reconnecting different text in two code blocks', () =>
expectMarkupMismatch(
<div>
{'Text1'}
{'Text2'}
</div>,
<div>
{'Text1'}
{'Text3'}
</div>,
));
it('can explicitly ignore reconnecting different text', () =>
expectMarkupMatch(
<div>Text</div>,
<div suppressHydrationWarning={true}>Other Text</div>,
));
it('can explicitly ignore reconnecting different text in two code blocks', () =>
expectMarkupMatch(
<div suppressHydrationWarning={true}>
{'Text1'}
{'Text2'}
</div>,
<div suppressHydrationWarning={true}>
{'Text1'}
{'Text3'}
</div>,
));
});
describe('element trees and children', function() {
it('should error reconnecting missing children', () =>
expectMarkupMismatch(
<div>
<div />
</div>,
<div />,
));
it('should error reconnecting added children', () =>
expectMarkupMismatch(
<div />,
<div>
<div />
</div>,
));
it('should error reconnecting more children', () =>
expectMarkupMismatch(
<div>
<div />
</div>,
<div>
<div />
<div />
</div>,
));
it('should error reconnecting fewer children', () =>
expectMarkupMismatch(
<div>
<div />
<div />
</div>,
<div>
<div />
</div>,
));
it('should error reconnecting reordered children', () =>
expectMarkupMismatch(
<div>
<div />
<span />
</div>,
<div>
<span />
<div />
</div>,
));
it('should error reconnecting a div with children separated by whitespace on the client', () =>
expectMarkupMismatch(
<div id="parent">
<div id="child1" />
<div id="child2" />
</div>,
// prettier-ignore
<div id="parent"><div id="child1" /> <div id="child2" /></div>, // eslint-disable-line no-multi-spaces
));
it('should error reconnecting a div with children separated by different whitespace on the server', () =>
expectMarkupMismatch(
// prettier-ignore
<div id="parent"><div id="child1" /> <div id="child2" /></div>, // eslint-disable-line no-multi-spaces
<div id="parent">
<div id="child1" />
<div id="child2" />
</div>,
));
it('should error reconnecting a div with children separated by different whitespace', () =>
expectMarkupMismatch(
<div id="parent">
<div id="child1" /> <div id="child2" />
</div>,
// prettier-ignore
<div id="parent"><div id="child1" /> <div id="child2" /></div>, // eslint-disable-line no-multi-spaces
));
it('can distinguish an empty component from a dom node', () =>
expectMarkupMismatch(
<div>
<span />
</div>,
<div>
<EmptyComponent />
</div>,
));
it('can distinguish an empty component from an empty text component', () =>
expectMarkupMatch(
<div>
<EmptyComponent />
</div>,
<div>{''}</div>,
));
it('can explicitly ignore reconnecting more children', () =>
expectMarkupMatch(
<div>
<div />
</div>,
<div suppressHydrationWarning={true}>
<div />
<div />
</div>,
));
it('can explicitly ignore reconnecting fewer children', () =>
expectMarkupMatch(
<div>
<div />
<div />
</div>,
<div suppressHydrationWarning={true}>
<div />
</div>,
));
it('can explicitly ignore reconnecting reordered children', () =>
expectMarkupMatch(
<div suppressHydrationWarning={true}>
<div />
<span />
</div>,
<div suppressHydrationWarning={true}>
<span />
<div />
</div>,
));
it('can not deeply ignore reconnecting reordered children', () =>
expectMarkupMismatch(
<div suppressHydrationWarning={true}>
<div>
<div />
<span />
</div>
</div>,
<div suppressHydrationWarning={true}>
<div>
<span />
<div />
</div>
</div>,
));
});
// Markup Mismatches: misc
it('should error reconnecting a div with different dangerouslySetInnerHTML', () =>
expectMarkupMismatch(
<div dangerouslySetInnerHTML={{__html: "<span id='child1'/>"}} />,
<div dangerouslySetInnerHTML={{__html: "<span id='child2'/>"}} />,
));
it('should error reconnecting a div with different text dangerouslySetInnerHTML', () =>
expectMarkupMismatch(
<div dangerouslySetInnerHTML={{__html: 'foo'}} />,
<div dangerouslySetInnerHTML={{__html: 'bar'}} />,
));
it('should error reconnecting a div with different number dangerouslySetInnerHTML', () =>
expectMarkupMismatch(
<div dangerouslySetInnerHTML={{__html: 10}} />,
<div dangerouslySetInnerHTML={{__html: 20}} />,
));
it('should error reconnecting a div with different object dangerouslySetInnerHTML', () =>
expectMarkupMismatch(
<div
dangerouslySetInnerHTML={{
__html: {
toString() {
return 'hi';
},
},
}}
/>,
<div
dangerouslySetInnerHTML={{
__html: {
toString() {
return 'bye';
},
},
}}
/>,
));
it('can explicitly ignore reconnecting a div with different dangerouslySetInnerHTML', () =>
expectMarkupMatch(
<div dangerouslySetInnerHTML={{__html: "<span id='child1'/>"}} />,
<div
dangerouslySetInnerHTML={{__html: "<span id='child2'/>"}}
suppressHydrationWarning={true}
/>,
));
});
});