diff --git a/package.json b/package.json index 32e05560eef11..df17e49d0d7ca 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "babel-jest": "^19.0.0", "babel-plugin-check-es2015-constants": "^6.5.0", "babel-plugin-syntax-trailing-function-commas": "^6.5.0", + "babel-plugin-transform-async-to-generator": "^6.22.0", "babel-plugin-transform-class-properties": "^6.11.5", "babel-plugin-transform-es2015-arrow-functions": "^6.5.2", "babel-plugin-transform-es2015-block-scoped-functions": "^6.5.0", diff --git a/scripts/jest/preprocessor.js b/scripts/jest/preprocessor.js index 20f372dc57946..4a48cfe9e5554 100644 --- a/scripts/jest/preprocessor.js +++ b/scripts/jest/preprocessor.js @@ -22,6 +22,7 @@ var pathToBabel = path.join(require.resolve('babel-core'), '..', 'package.json') var pathToModuleMap = require.resolve('fbjs/module-map'); var pathToBabelPluginDevWithCode = require.resolve('../error-codes/dev-expression-with-codes'); var pathToBabelPluginModules = require.resolve('fbjs-scripts/babel-6/rewrite-modules'); +var pathToBabelPluginAsyncToGenerator = require.resolve('babel-plugin-transform-async-to-generator'); var pathToBabelrc = path.join(__dirname, '..', '..', '.babelrc'); var pathToErrorCodes = require.resolve('../error-codes/codes.json'); @@ -54,11 +55,17 @@ module.exports = { !filePath.match(/\/node_modules\//) && !filePath.match(/\/third_party\//) ) { + // for test files, we also apply the async-await transform, but we want to + // make sure we don't accidentally apply that transform to product code. + var isTestFile = !!filePath.match(/\/__tests__\//); return babel.transform( src, Object.assign( {filename: path.relative(process.cwd(), filePath)}, - babelOptions + babelOptions, + isTestFile ? { + plugins: [pathToBabelPluginAsyncToGenerator].concat(babelOptions.plugins), + } : {} ) ).code; } diff --git a/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js b/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js index daf84a2f219a4..afe70f87cce37 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js +++ b/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js @@ -19,41 +19,44 @@ let ReactDOMServer; // Helper functions for rendering tests // ==================================== +// promisified version of ReactDOM.render() +function asyncReactDOMRender(reactElement, domElement) { + return new Promise(resolve => + ReactDOM.render(reactElement, domElement, resolve)); +} // 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) { +async 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]); - } + const result = await fn(); + if (console.error.calls.count() !== count && console.error.calls.count() !== 0) { + 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; - }); + } + 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) => { + async () => { ExecutionEnvironment.canUseDOM = true; - ReactDOM.render(reactElement, domElement, () => { - ExecutionEnvironment.canUseDOM = false; - resolve(domElement.firstChild); - }); - }), + await asyncReactDOMRender(reactElement, domElement); + ExecutionEnvironment.canUseDOM = false; + return domElement.firstChild; + }, errorCount ); } @@ -61,15 +64,14 @@ function renderIntoDom(reactElement, domElement, errorCount = 0) { // 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( +async function serverRender(reactElement, errorCount = 0) { + const markup = await expectErrors( () => Promise.resolve(ReactDOMServer.renderToString(reactElement)), - errorCount) - .then((markup) => { - var domElement = document.createElement('div'); - domElement.innerHTML = markup; - return domElement.firstChild; - }); + errorCount + ); + var domElement = document.createElement('div'); + domElement.innerHTML = markup; + return domElement.firstChild; } const clientCleanRender = (element, errorCount = 0) => { @@ -77,12 +79,11 @@ const clientCleanRender = (element, errorCount = 0) => { 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 clientRenderOnServerString = async (element, errorCount = 0) => { + const markup = await serverRender(element, errorCount); + var domElement = document.createElement('div'); + domElement.innerHTML = markup; + return renderIntoDom(element, domElement, errorCount); }; const clientRenderOnBadMarkup = (element, errorCount = 0) => { @@ -143,24 +144,26 @@ describe('ReactDOMServerIntegration', () => { }); describe('basic rendering', function() { - itRenders('a blank div', render => - render(
).then(e => expect(e.tagName).toBe('DIV'))); - - itRenders('a div with inline styles', render => - render().then(e => { - expect(e.style.color).toBe('red'); - expect(e.style.width).toBe('30px'); - }) - ); - - itRenders('a self-closing tag', render => - render(