@samitouri / QOS-React / commits / fcf41e7ca2

Add async/await to unit tests; modify server rendering tests to use async/await. (#9089)

Sasha Aickin committed Mar 3, 2017 at 10:34 UTC fcf41e7ca2ab902d3058016aac6fb9b1e0ab46f8
3 files changed +63 -52
package.json
+1
@@ -12,6 +12,7 @@
12 "babel-jest": "^19.0.0",
13 "babel-plugin-check-es2015-constants": "^6.5.0",
14 "babel-plugin-syntax-trailing-function-commas": "^6.5.0",
15 + "babel-plugin-transform-async-to-generator": "^6.22.0",
16 "babel-plugin-transform-class-properties": "^6.11.5",
17 "babel-plugin-transform-es2015-arrow-functions": "^6.5.2",
18 "babel-plugin-transform-es2015-block-scoped-functions": "^6.5.0",
scripts/jest/preprocessor.js
+8 -1
@@ -22,6 +22,7 @@ var pathToBabel = path.join(require.resolve('babel-core'), '..', 'package.json')
22 var pathToModuleMap = require.resolve('fbjs/module-map');
23 var pathToBabelPluginDevWithCode = require.resolve('../error-codes/dev-expression-with-codes');
24 var pathToBabelPluginModules = require.resolve('fbjs-scripts/babel-6/rewrite-modules');
25 +var pathToBabelPluginAsyncToGenerator = require.resolve('babel-plugin-transform-async-to-generator');
26 var pathToBabelrc = path.join(__dirname, '..', '..', '.babelrc');
27 var pathToErrorCodes = require.resolve('../error-codes/codes.json');
28
@@ -54,11 +55,17 @@ module.exports = {
55 !filePath.match(/\/node_modules\//) &&
56 !filePath.match(/\/third_party\//)
57 ) {
58 + // for test files, we also apply the async-await transform, but we want to
59 + // make sure we don't accidentally apply that transform to product code.
60 + var isTestFile = !!filePath.match(/\/__tests__\//);
61 return babel.transform(
62 src,
63 Object.assign(
64 {filename: path.relative(process.cwd(), filePath)},
61 - babelOptions
65 + babelOptions,
66 + isTestFile ? {
67 + plugins: [pathToBabelPluginAsyncToGenerator].concat(babelOptions.plugins),
68 + } : {}
69 )
70 ).code;
71 }
src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
+54 -51
@@ -19,41 +19,44 @@ let ReactDOMServer;
19 // Helper functions for rendering tests
20 // ====================================
21
22 +// promisified version of ReactDOM.render()
23 +function asyncReactDOMRender(reactElement, domElement) {
24 + return new Promise(resolve =>
25 + ReactDOM.render(reactElement, domElement, resolve));
26 +}
27 // performs fn asynchronously and expects count errors logged to console.error.
28 // will fail the test if the count of errors logged is not equal to count.
24 -function expectErrors(fn, count) {
29 +async function expectErrors(fn, count) {
30 if (console.error.calls && console.error.calls.reset) {
31 console.error.calls.reset();
32 } else {
33 spyOn(console, 'error');
34 }
35
31 - return fn().then((result) => {
32 - if (console.error.calls.count() !== count) {
33 - console.log(`We expected ${count} warning(s), but saw ${console.error.calls.count()} warning(s).`);
34 - if (console.error.calls.count() > 0) {
35 - console.log(`We saw these warnings:`);
36 - for (var i = 0; i < console.error.calls.count(); i++) {
37 - console.log(console.error.calls.argsFor(i)[0]);
38 - }
36 + const result = await fn();
37 + if (console.error.calls.count() !== count && console.error.calls.count() !== 0) {
38 + console.log(`We expected ${count} warning(s), but saw ${console.error.calls.count()} warning(s).`);
39 + if (console.error.calls.count() > 0) {
40 + console.log(`We saw these warnings:`);
41 + for (var i = 0; i < console.error.calls.count(); i++) {
42 + console.log(console.error.calls.argsFor(i)[0]);
43 }
44 }
41 - expectDev(console.error.calls.count()).toBe(count);
42 - return result;
43 - });
45 + }
46 + expectDev(console.error.calls.count()).toBe(count);
47 + return result;
48 }
49
50 // renders the reactElement into domElement, and expects a certain number of errors.
51 // returns a Promise that resolves when the render is complete.
52 function renderIntoDom(reactElement, domElement, errorCount = 0) {
53 return expectErrors(
50 - () => new Promise((resolve) => {
54 + async () => {
55 ExecutionEnvironment.canUseDOM = true;
52 - ReactDOM.render(reactElement, domElement, () => {
53 - ExecutionEnvironment.canUseDOM = false;
54 - resolve(domElement.firstChild);
55 - });
56 - }),
56 + await asyncReactDOMRender(reactElement, domElement);
57 + ExecutionEnvironment.canUseDOM = false;
58 + return domElement.firstChild;
59 + },
60 errorCount
61 );
62 }
@@ -61,15 +64,14 @@ function renderIntoDom(reactElement, domElement, errorCount = 0) {
64 // Renders text using SSR and then stuffs it into a DOM node; returns the DOM
65 // element that corresponds with the reactElement.
66 // Does not render on client or perform client-side revival.
64 -function serverRender(reactElement, errorCount = 0) {
65 - return expectErrors(
67 +async function serverRender(reactElement, errorCount = 0) {
68 + const markup = await expectErrors(
69 () => Promise.resolve(ReactDOMServer.renderToString(reactElement)),
67 - errorCount)
68 - .then((markup) => {
69 - var domElement = document.createElement('div');
70 - domElement.innerHTML = markup;
71 - return domElement.firstChild;
72 - });
70 + errorCount
71 + );
72 + var domElement = document.createElement('div');
73 + domElement.innerHTML = markup;
74 + return domElement.firstChild;
75 }
76
77 const clientCleanRender = (element, errorCount = 0) => {
@@ -77,12 +79,11 @@ const clientCleanRender = (element, errorCount = 0) => {
79 return renderIntoDom(element, div, errorCount);
80 };
81
80 -const clientRenderOnServerString = (element, errorCount = 0) => {
81 - return serverRender(element, errorCount).then((markup) => {
82 - var domElement = document.createElement('div');
83 - domElement.innerHTML = markup;
84 - return renderIntoDom(element, domElement, errorCount);
85 - });
82 +const clientRenderOnServerString = async (element, errorCount = 0) => {
83 + const markup = await serverRender(element, errorCount);
84 + var domElement = document.createElement('div');
85 + domElement.innerHTML = markup;
86 + return renderIntoDom(element, domElement, errorCount);
87 };
88
89 const clientRenderOnBadMarkup = (element, errorCount = 0) => {
@@ -143,24 +144,26 @@ describe('ReactDOMServerIntegration', () => {
144 });
145
146 describe('basic rendering', function() {
146 - itRenders('a blank div', render =>
147 - render(<div />).then(e => expect(e.tagName).toBe('DIV')));
148 -
149 - itRenders('a div with inline styles', render =>
150 - render(<div style={{color:'red', width:'30px'}} />).then(e => {
151 - expect(e.style.color).toBe('red');
152 - expect(e.style.width).toBe('30px');
153 - })
154 - );
155 -
156 - itRenders('a self-closing tag', render =>
157 - render(<br />).then(e => expect(e.tagName).toBe('BR')));
158 -
159 - itRenders('a self-closing tag as a child', render =>
160 - render(<div><br /></div>).then(e => {
161 - expect(e.childNodes.length).toBe(1);
162 - expect(e.firstChild.tagName).toBe('BR');
163 - })
164 - );
147 + itRenders('a blank div', async render => {
148 + const e = await render(<div />);
149 + expect(e.tagName).toBe('DIV');
150 + });
151 +
152 + itRenders('a div with inline styles', async render => {
153 + const e = await render(<div style={{color:'red', width:'30px'}} />);
154 + expect(e.style.color).toBe('red');
155 + expect(e.style.width).toBe('30px');
156 + });
157 +
158 + itRenders('a self-closing tag', async render => {
159 + const e = await render(<br />);
160 + expect(e.tagName).toBe('BR');
161 + });
162 +
163 + itRenders('a self-closing tag as a child', async render => {
164 + const e = await render(<div><br /></div>);
165 + expect(e.childNodes.length).toBe(1);
166 + expect(e.firstChild.tagName).toBe('BR');
167 + });
168 });
169 });