mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
* Move files and tests to more meaningful places * Fix the build Now that we import reconciler via react-reconciler, I needed to make a few tweaks. * Update sizes * Move @preventMunge directive to FB header * Revert unintentional change * Fix Flow coverage I forgot to @flow-ify those files. This uncovered some issues. * Prettier, I love you but you're bringing me down Prettier, I love you but you're bringing me down Like a rat in a cage Pulling minimum wage Prettier, I love you but you're bringing me down Prettier, you're safer and you're wasting my time Our records all show you were filthy but fine But they shuttered your stores When you opened the doors To the cops who were bored once they'd run out of crime Prettier, you're perfect, oh, please don't change a thing Your mild billionaire mayor's now convinced he's a king So the boring collect I mean all disrespect In the neighborhood bars I'd once dreamt I would drink Prettier, I love you but you're freaking me out There's a ton of the twist but we're fresh out of shout Like a death in the hall That you hear through your wall Prettier, I love you but you're freaking me out Prettier, I love you but you're bringing me down Prettier, I love you but you're bringing me down Like a death of the heart Jesus, where do I start? But you're still the one pool where I'd happily drown And oh! Take me off your mailing list For kids who think it still exists Yes, for those who think it still exists Maybe I'm wrong and maybe you're right Maybe I'm wrong and maybe you're right Maybe you're right, maybe I'm wrong And just maybe you're right And oh! Maybe mother told you true And there'll always be somebody there for you And you'll never be alone But maybe she's wrong and maybe I'm right And just maybe she's wrong Maybe she's wrong and maybe I'm right And if so, here's this song!
489 lines
14 KiB
JavaScript
489 lines
14 KiB
JavaScript
/**
|
|
* Copyright (c) 2013-present, Facebook, Inc.
|
|
*
|
|
* 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';
|
|
|
|
var React;
|
|
var ReactDOM;
|
|
var ReactDOMServer;
|
|
|
|
function getTestDocument(markup) {
|
|
var doc = document.implementation.createHTMLDocument('');
|
|
doc.open();
|
|
doc.write(
|
|
markup ||
|
|
'<!doctype html><html><meta charset=utf-8><title>test doc</title>',
|
|
);
|
|
doc.close();
|
|
return doc;
|
|
}
|
|
|
|
describe('rendering React components at document', () => {
|
|
beforeEach(() => {
|
|
jest.resetModules();
|
|
|
|
React = require('react');
|
|
ReactDOM = require('react-dom');
|
|
ReactDOMServer = require('react-dom/server');
|
|
});
|
|
|
|
describe('with old implicit hydration API', () => {
|
|
function expectDeprecationWarningWithFiber() {
|
|
expectDev(console.warn.calls.count()).toBe(1);
|
|
expectDev(console.warn.calls.argsFor(0)[0]).toContain(
|
|
'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
|
|
'will stop working in React v17. Replace the ReactDOM.render() call ' +
|
|
'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
|
|
);
|
|
}
|
|
|
|
it('should be able to adopt server markup', () => {
|
|
spyOn(console, 'warn');
|
|
class Root extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
{'Hello ' + this.props.hello}
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
var markup = ReactDOMServer.renderToString(<Root hello="world" />);
|
|
var testDocument = getTestDocument(markup);
|
|
var body = testDocument.body;
|
|
|
|
ReactDOM.render(<Root hello="world" />, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
|
|
ReactDOM.render(<Root hello="moon" />, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello moon');
|
|
|
|
expect(body === testDocument.body).toBe(true);
|
|
expectDeprecationWarningWithFiber();
|
|
});
|
|
|
|
it('should not be able to unmount component from document node', () => {
|
|
spyOn(console, 'warn');
|
|
class Root extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
Hello world
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
var markup = ReactDOMServer.renderToString(<Root />);
|
|
var testDocument = getTestDocument(markup);
|
|
ReactDOM.render(<Root />, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
|
|
// In Fiber this actually works. It might not be a good idea though.
|
|
ReactDOM.unmountComponentAtNode(testDocument);
|
|
expect(testDocument.firstChild).toBe(null);
|
|
|
|
expectDeprecationWarningWithFiber();
|
|
});
|
|
|
|
it('should not be able to switch root constructors', () => {
|
|
spyOn(console, 'warn');
|
|
class Component extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
Hello world
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
class Component2 extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
Goodbye world
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
var markup = ReactDOMServer.renderToString(<Component />);
|
|
var testDocument = getTestDocument(markup);
|
|
|
|
ReactDOM.render(<Component />, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
|
|
// This works but is probably a bad idea.
|
|
ReactDOM.render(<Component2 />, testDocument);
|
|
|
|
expect(testDocument.body.innerHTML).toBe('Goodbye world');
|
|
expectDeprecationWarningWithFiber();
|
|
});
|
|
|
|
it('should be able to mount into document', () => {
|
|
spyOn(console, 'warn');
|
|
class Component extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
{this.props.text}
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
var markup = ReactDOMServer.renderToString(
|
|
<Component text="Hello world" />,
|
|
);
|
|
var testDocument = getTestDocument(markup);
|
|
|
|
ReactDOM.render(<Component text="Hello world" />, testDocument);
|
|
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
expectDeprecationWarningWithFiber();
|
|
});
|
|
|
|
it('renders over an existing text child without throwing', () => {
|
|
const container = document.createElement('div');
|
|
container.textContent = 'potato';
|
|
ReactDOM.render(<div>parsnip</div>, container);
|
|
expect(container.textContent).toBe('parsnip');
|
|
// We don't expect a warning about new hydration API here because
|
|
// we aren't sure if the user meant to hydrate or replace a stub node.
|
|
// We would see a warning if the container had React-rendered HTML in it.
|
|
});
|
|
|
|
it('should give helpful errors on state desync', () => {
|
|
class Component extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
{this.props.text}
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
var markup = ReactDOMServer.renderToString(
|
|
<Component text="Goodbye world" />,
|
|
);
|
|
var testDocument = getTestDocument(markup);
|
|
|
|
spyOn(console, 'warn');
|
|
spyOn(console, 'error');
|
|
ReactDOM.render(<Component text="Hello world" />, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
expectDev(console.warn.calls.count()).toBe(1);
|
|
expectDev(console.warn.calls.argsFor(0)[0]).toContain(
|
|
'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
|
|
'will stop working in React v17. Replace the ReactDOM.render() call ' +
|
|
'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
|
|
);
|
|
expectDev(console.error.calls.count()).toBe(1);
|
|
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
|
'Warning: Text content did not match.',
|
|
);
|
|
});
|
|
|
|
it('should throw on full document render w/ no markup', () => {
|
|
var testDocument = getTestDocument();
|
|
|
|
class Component extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
{this.props.text}
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
ReactDOM.render(<Component text="Hello world" />, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
// We don't expect a warning about new hydration API here because
|
|
// we aren't sure if the user meant to hydrate or replace the document.
|
|
// We would see a warning if the document had React-rendered HTML in it.
|
|
});
|
|
|
|
it('supports findDOMNode on full-page components', () => {
|
|
spyOn(console, 'warn');
|
|
var tree = (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
Hello world
|
|
</body>
|
|
</html>
|
|
);
|
|
|
|
var markup = ReactDOMServer.renderToString(tree);
|
|
var testDocument = getTestDocument(markup);
|
|
var component = ReactDOM.render(tree, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
expect(ReactDOM.findDOMNode(component).tagName).toBe('HTML');
|
|
expectDeprecationWarningWithFiber();
|
|
});
|
|
});
|
|
|
|
describe('with new explicit hydration API', () => {
|
|
it('should be able to adopt server markup', () => {
|
|
class Root extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
{'Hello ' + this.props.hello}
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
var markup = ReactDOMServer.renderToString(<Root hello="world" />);
|
|
var testDocument = getTestDocument(markup);
|
|
var body = testDocument.body;
|
|
|
|
ReactDOM.hydrate(<Root hello="world" />, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
|
|
ReactDOM.hydrate(<Root hello="moon" />, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello moon');
|
|
|
|
expect(body === testDocument.body).toBe(true);
|
|
});
|
|
|
|
it('should not be able to unmount component from document node', () => {
|
|
class Root extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
Hello world
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
var markup = ReactDOMServer.renderToString(<Root />);
|
|
var testDocument = getTestDocument(markup);
|
|
ReactDOM.hydrate(<Root />, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
|
|
// In Fiber this actually works. It might not be a good idea though.
|
|
ReactDOM.unmountComponentAtNode(testDocument);
|
|
expect(testDocument.firstChild).toBe(null);
|
|
});
|
|
|
|
it('should not be able to switch root constructors', () => {
|
|
class Component extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
Hello world
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
class Component2 extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
Goodbye world
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
var markup = ReactDOMServer.renderToString(<Component />);
|
|
var testDocument = getTestDocument(markup);
|
|
|
|
ReactDOM.hydrate(<Component />, testDocument);
|
|
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
|
|
// This works but is probably a bad idea.
|
|
ReactDOM.hydrate(<Component2 />, testDocument);
|
|
|
|
expect(testDocument.body.innerHTML).toBe('Goodbye world');
|
|
});
|
|
|
|
it('should be able to mount into document', () => {
|
|
class Component extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
{this.props.text}
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
var markup = ReactDOMServer.renderToString(
|
|
<Component text="Hello world" />,
|
|
);
|
|
var testDocument = getTestDocument(markup);
|
|
|
|
ReactDOM.hydrate(<Component text="Hello world" />, testDocument);
|
|
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
});
|
|
|
|
it('renders over an existing text child without throwing', () => {
|
|
spyOn(console, 'error');
|
|
const container = document.createElement('div');
|
|
container.textContent = 'potato';
|
|
ReactDOM.hydrate(<div>parsnip</div>, container);
|
|
expect(container.textContent).toBe('parsnip');
|
|
expectDev(console.error.calls.count()).toBe(1);
|
|
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
|
'Expected server HTML to contain a matching <div> in <div>.',
|
|
);
|
|
});
|
|
|
|
it('should give helpful errors on state desync', () => {
|
|
class Component extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
{this.props.text}
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
var markup = ReactDOMServer.renderToString(
|
|
<Component text="Goodbye world" />,
|
|
);
|
|
var testDocument = getTestDocument(markup);
|
|
|
|
spyOn(console, 'error');
|
|
ReactDOM.hydrate(<Component text="Hello world" />, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
expectDev(console.error.calls.count()).toBe(1);
|
|
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
|
'Warning: Text content did not match.',
|
|
);
|
|
});
|
|
|
|
it('should render w/ no markup to full document', () => {
|
|
spyOn(console, 'error');
|
|
var testDocument = getTestDocument();
|
|
|
|
class Component extends React.Component {
|
|
render() {
|
|
return (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
{this.props.text}
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
}
|
|
|
|
ReactDOM.hydrate(<Component text="Hello world" />, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
expectDev(console.error.calls.count()).toBe(1);
|
|
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
|
// getTestDocument() has an extra <meta> that we didn't render.
|
|
'Did not expect server HTML to contain a <meta> in <head>.',
|
|
);
|
|
});
|
|
|
|
it('supports findDOMNode on full-page components', () => {
|
|
var tree = (
|
|
<html>
|
|
<head>
|
|
<title>Hello World</title>
|
|
</head>
|
|
<body>
|
|
Hello world
|
|
</body>
|
|
</html>
|
|
);
|
|
|
|
var markup = ReactDOMServer.renderToString(tree);
|
|
var testDocument = getTestDocument(markup);
|
|
var component = ReactDOM.hydrate(tree, testDocument);
|
|
expect(testDocument.body.innerHTML).toBe('Hello world');
|
|
expect(ReactDOM.findDOMNode(component).tagName).toBe('HTML');
|
|
});
|
|
});
|
|
});
|