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
});