Adding some server rendering unit tests. (#9055)
* Added a handful of SSR unit tests, ported from a previous pull request. * Fixing linting errors * Fixed a test helper function to properly report errors. * Un-nested the new rendering tests. Updated the fiber test passing/not passing lists. * Edited to comply with the react/jsx-space-before-closing eslint rule, which will soon be merged into master. * Response to code review from @spicyj. Moved tests to separate file, reworked wording of test names, corrected use of canUseDom, and simplified tests against tagName. Thanks for the help, @spicyj!
This commit is contained in:
parent
d1ee199492
commit
3788654d57
|
@ -134,6 +134,12 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
|
|||
* should warn about class (ssr)
|
||||
* should suggest property name if available (ssr)
|
||||
|
||||
src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
|
||||
* renders a blank div with client render on top of bad server markup
|
||||
* renders a div with inline styles with client render on top of bad server markup
|
||||
* renders a self-closing tag with client render on top of bad server markup
|
||||
* renders a self-closing tag as a child with client render on top of bad server markup
|
||||
|
||||
src/renderers/dom/shared/__tests__/ReactMount-test.js
|
||||
* should warn if mounting into dirty rendered markup
|
||||
* should account for escaping on a checksum mismatch
|
||||
|
|
|
@ -1116,6 +1116,20 @@ src/renderers/dom/shared/__tests__/ReactDOMSVG-test.js
|
|||
* can render SVG into a non-React SVG tree
|
||||
* can render HTML into a foreignObject in non-React SVG tree
|
||||
|
||||
src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
|
||||
* renders a blank div with server string render
|
||||
* renders a blank div with clean client render
|
||||
* renders a blank div with client render on top of good server markup
|
||||
* renders a div with inline styles with server string render
|
||||
* renders a div with inline styles with clean client render
|
||||
* renders a div with inline styles with client render on top of good server markup
|
||||
* renders a self-closing tag with server string render
|
||||
* renders a self-closing tag with clean client render
|
||||
* renders a self-closing tag with client render on top of good server markup
|
||||
* renders a self-closing tag as a child with server string render
|
||||
* renders a self-closing tag as a child with clean client render
|
||||
* renders a self-closing tag as a child with client render on top of good server markup
|
||||
|
||||
src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
|
||||
* updates a mounted text component in place
|
||||
* can be toggled in and out of the markup
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
let ExecutionEnvironment;
|
||||
let React;
|
||||
let ReactDOM;
|
||||
let ReactDOMServer;
|
||||
|
||||
// Helper functions for rendering tests
|
||||
// ====================================
|
||||
|
||||
// performs fn asynchronously and expects count errors logged to console.error.
|
||||
// will fail the test if the count of errors logged is not equal to count.
|
||||
function expectErrors(fn, count) {
|
||||
if (console.error.calls && console.error.calls.reset) {
|
||||
console.error.calls.reset();
|
||||
} else {
|
||||
spyOn(console, 'error');
|
||||
}
|
||||
|
||||
return fn().then((result) => {
|
||||
if (console.error.calls.count() !== count) {
|
||||
console.log(`We expected ${count} warning(s), but saw ${console.error.calls.count()} warning(s).`);
|
||||
if (console.error.calls.count() > 0) {
|
||||
console.log(`We saw these warnings:`);
|
||||
for (var i = 0; i < console.error.calls.count(); i++) {
|
||||
console.log(console.error.calls.argsFor(i)[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
expectDev(console.error.calls.count()).toBe(count);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
// renders the reactElement into domElement, and expects a certain number of errors.
|
||||
// returns a Promise that resolves when the render is complete.
|
||||
function renderIntoDom(reactElement, domElement, errorCount = 0) {
|
||||
return expectErrors(
|
||||
() => new Promise((resolve) => {
|
||||
ExecutionEnvironment.canUseDOM = true;
|
||||
ReactDOM.render(reactElement, domElement, () => {
|
||||
ExecutionEnvironment.canUseDOM = false;
|
||||
resolve(domElement.firstChild);
|
||||
});
|
||||
}),
|
||||
errorCount
|
||||
);
|
||||
}
|
||||
|
||||
// Renders text using SSR and then stuffs it into a DOM node; returns the DOM
|
||||
// element that corresponds with the reactElement.
|
||||
// Does not render on client or perform client-side revival.
|
||||
function serverRender(reactElement, errorCount = 0) {
|
||||
return expectErrors(
|
||||
() => Promise.resolve(ReactDOMServer.renderToString(reactElement)),
|
||||
errorCount)
|
||||
.then((markup) => {
|
||||
var domElement = document.createElement('div');
|
||||
domElement.innerHTML = markup;
|
||||
return domElement.firstChild;
|
||||
});
|
||||
}
|
||||
|
||||
const clientCleanRender = (element, errorCount = 0) => {
|
||||
const div = document.createElement('div');
|
||||
return renderIntoDom(element, div, errorCount);
|
||||
};
|
||||
|
||||
const clientRenderOnServerString = (element, errorCount = 0) => {
|
||||
return serverRender(element, errorCount).then((markup) => {
|
||||
var domElement = document.createElement('div');
|
||||
domElement.innerHTML = markup;
|
||||
return renderIntoDom(element, domElement, errorCount);
|
||||
});
|
||||
};
|
||||
|
||||
const clientRenderOnBadMarkup = (element, errorCount = 0) => {
|
||||
var domElement = document.createElement('div');
|
||||
domElement.innerHTML = '<div id="badIdWhichWillCauseMismatch" data-reactroot="" data-reactid="1"></div>';
|
||||
return renderIntoDom(element, domElement, errorCount + 1);
|
||||
};
|
||||
|
||||
// runs a DOM rendering test as four different tests, with four different rendering
|
||||
// scenarios:
|
||||
// -- render to string on server
|
||||
// -- render on client without any server markup "clean client render"
|
||||
// -- render on client on top of good server-generated string markup
|
||||
// -- render on client on top of bad server-generated markup
|
||||
//
|
||||
// testFn is a test that has one arg, which is a render function. the render
|
||||
// function takes in a ReactElement and an optional expected error count and
|
||||
// returns a promise of a DOM Element.
|
||||
//
|
||||
// You should only perform tests that examine the DOM of the results of
|
||||
// render; you should not depend on the interactivity of the returned DOM element,
|
||||
// as that will not work in the server string scenario.
|
||||
function itRenders(desc, testFn) {
|
||||
it(`renders ${desc} with server string render`,
|
||||
() => testFn(serverRender));
|
||||
itClientRenders(desc, testFn);
|
||||
}
|
||||
|
||||
// run testFn in three different rendering scenarios:
|
||||
// -- render on client without any server markup "clean client render"
|
||||
// -- render on client on top of good server-generated string markup
|
||||
// -- render on client on top of bad server-generated markup
|
||||
//
|
||||
// testFn is a test that has one arg, which is a render function. the render
|
||||
// function takes in a ReactElement and an optional expected error count and
|
||||
// returns a promise of a DOM Element.
|
||||
//
|
||||
// Since all of the renders in this function are on the client, you can test interactivity,
|
||||
// unlike with itRenders.
|
||||
function itClientRenders(desc, testFn) {
|
||||
it(`renders ${desc} with clean client render`,
|
||||
() => testFn(clientCleanRender));
|
||||
it(`renders ${desc} with client render on top of good server markup`,
|
||||
() => testFn(clientRenderOnServerString));
|
||||
it(`renders ${desc} with client render on top of bad server markup`,
|
||||
() => testFn(clientRenderOnBadMarkup));
|
||||
}
|
||||
|
||||
describe('ReactDOMServerIntegration', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModuleRegistry();
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactDOMServer = require('ReactDOMServer');
|
||||
|
||||
ExecutionEnvironment = require('ExecutionEnvironment');
|
||||
ExecutionEnvironment.canUseDOM = false;
|
||||
});
|
||||
|
||||
describe('basic rendering', function() {
|
||||
itRenders('a blank div', render =>
|
||||
render(<div />).then(e => expect(e.tagName).toBe('DIV')));
|
||||
|
||||
itRenders('a div with inline styles', render =>
|
||||
render(<div style={{color:'red', width:'30px'}} />).then(e => {
|
||||
expect(e.style.color).toBe('red');
|
||||
expect(e.style.width).toBe('30px');
|
||||
})
|
||||
);
|
||||
|
||||
itRenders('a self-closing tag', render =>
|
||||
render(<br />).then(e => expect(e.tagName).toBe('BR')));
|
||||
|
||||
itRenders('a self-closing tag as a child', render =>
|
||||
render(<div><br /></div>).then(e => {
|
||||
expect(e.childNodes.length).toBe(1);
|
||||
expect(e.firstChild.tagName).toBe('BR');
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue