From dc9c7123e6eceab3859e1d976effffbffb3b77fb Mon Sep 17 00:00:00 2001 From: Fabrizio Castellarin Date: Mon, 30 Jan 2017 20:24:12 +0100 Subject: [PATCH] E2e jsdom fix (#1470) * E2E: run tests when react is ready * Entangle e2e with callbacks * Remove unused e2e lines --- .../kitchensink/.template.dependencies.json | 2 +- .../kitchensink/integration/initDOM.js | 23 ++++--------- .../fixtures/kitchensink/src/App.js | 24 +++++++++++++- .../kitchensink/src/features/env/NodePath.js | 7 +++- .../src/features/syntax/ArrayDestructuring.js | 7 +++- .../src/features/syntax/ArraySpread.js | 7 +++- .../src/features/syntax/AsyncAwait.js | 7 +++- .../src/features/syntax/ComputedProperties.js | 7 +++- .../features/syntax/CustomInterpolation.js | 7 +++- .../src/features/syntax/DefaultParameters.js | 7 +++- .../features/syntax/DestructuringAndAwait.js | 7 +++- .../src/features/syntax/Generators.js | 7 +++- .../features/syntax/ObjectDestructuring.js | 7 +++- .../src/features/syntax/ObjectSpread.js | 7 +++- .../src/features/syntax/Promises.js | 7 +++- .../src/features/syntax/RestAndDefault.js | 7 +++- .../src/features/syntax/RestParameters.js | 7 +++- .../features/syntax/TemplateInterpolation.js | 7 +++- tasks/e2e-installs.sh | 10 ------ tasks/e2e-kitchensink.sh | 32 ++----------------- 20 files changed, 124 insertions(+), 72 deletions(-) diff --git a/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json b/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json index 8adac45708d..62e0d34a35c 100644 --- a/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json +++ b/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json @@ -1,7 +1,7 @@ { "dependencies": { "babel-preset-latest": "6.16.0", - "babel-register": "6.18.0", + "babel-register": "6.22.0", "babel-polyfill": "6.20.0", "chai": "3.5.0", "jsdom": "9.8.3", diff --git a/packages/react-scripts/fixtures/kitchensink/integration/initDOM.js b/packages/react-scripts/fixtures/kitchensink/integration/initDOM.js index c04e60d4c87..21e9c701a47 100644 --- a/packages/react-scripts/fixtures/kitchensink/integration/initDOM.js +++ b/packages/react-scripts/fixtures/kitchensink/integration/initDOM.js @@ -5,9 +5,6 @@ const path = require('path') let getMarkup let resourceLoader -// this value could be tweaked in order to let the resource -// retriever get every file and jsdom execute react -let timeToWaitForJsToExecute if (process.env.E2E_FILE) { const file = path.isAbsolute(process.env.E2E_FILE) @@ -21,8 +18,6 @@ if (process.env.E2E_FILE) { null, fs.readFileSync(path.join(path.dirname(file), resource.url.pathname), 'utf8') ) - - timeToWaitForJsToExecute = 0 } else if (process.env.E2E_URL) { getMarkup = () => new Promise(resolve => { http.get(process.env.E2E_URL, (res) => { @@ -32,11 +27,7 @@ if (process.env.E2E_FILE) { }) }) - resourceLoader = (resource, callback) => { - return resource.defaultFetch(callback) - } - - timeToWaitForJsToExecute = 100 + resourceLoader = (resource, callback) => resource.defaultFetch(callback) } else { it.only('can run jsdom (at least one of "E2E_FILE" or "E2E_URL" environment variables must be provided)', () => { expect(new Error('This isn\'t the error you are looking for.')).toBeUndefined() @@ -47,16 +38,16 @@ export default feature => new Promise(async resolve => { const markup = await getMarkup() const host = process.env.E2E_URL || 'http://localhost:3000' const doc = jsdom.jsdom(markup, { - features : { - FetchExternalResources : ['script', 'css'], - ProcessExternalResources : ['script'], + features: { + FetchExternalResources: ['script', 'css'], + ProcessExternalResources: ['script'], }, + created: (_, win) => win.addEventListener('ReactFeatureDidMount', () => resolve(doc), true), + deferClose: true, resourceLoader, url: `${host}#${feature}`, virtualConsole: jsdom.createVirtualConsole().sendTo(console), }) - doc.defaultView.addEventListener('load', () => { - setTimeout(() => resolve(doc), timeToWaitForJsToExecute) - }, false) + doc.close() }) diff --git a/packages/react-scripts/fixtures/kitchensink/src/App.js b/packages/react-scripts/fixtures/kitchensink/src/App.js index 66cd45541f7..04641535ac7 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/App.js +++ b/packages/react-scripts/fixtures/kitchensink/src/App.js @@ -1,5 +1,27 @@ import React from 'react'; +class BuiltEmitter extends React.Component { + constructor(props) { + super(props) + + this.callWhenDone = done => done(); + } + + componentDidMount() { + this.callWhenDone(() => document.dispatchEvent(new Event('ReactFeatureDidMount'))); + } + + render() { + const feature = React.cloneElement(React.Children.only(this.props.children), { + setCallWhenDone: done => { + this.callWhenDone = done; + } + }); + + return
{feature}
; + } +} + class App extends React.Component { constructor(props) { super(props); @@ -96,7 +118,7 @@ class App extends React.Component { render() { const Feature = this.state.feature; - return Feature ? : null; + return Feature ? : null; } } diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/env/NodePath.js b/packages/react-scripts/fixtures/kitchensink/src/features/env/NodePath.js index 2d2f474f19e..1644b49ca04 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/env/NodePath.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/env/NodePath.js @@ -5,12 +5,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = load(); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ArrayDestructuring.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ArrayDestructuring.js index 38e35120960..1ee751af71f 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ArrayDestructuring.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ArrayDestructuring.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = load(); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ArraySpread.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ArraySpread.js index d7d9a459133..be6311980d7 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ArraySpread.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ArraySpread.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = load([{ id: 42, name: '42' }]); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/AsyncAwait.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/AsyncAwait.js index 01c68640575..84dd42e0a9b 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/AsyncAwait.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/AsyncAwait.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = await load(); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ComputedProperties.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ComputedProperties.js index c7a24cb7f3d..b6111a149d9 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ComputedProperties.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ComputedProperties.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = load('user_'); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/CustomInterpolation.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/CustomInterpolation.js index 03298968375..8184d3bd4ba 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/CustomInterpolation.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/CustomInterpolation.js @@ -18,12 +18,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = load(); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/DefaultParameters.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/DefaultParameters.js index 3a676358a92..637a239d7a4 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/DefaultParameters.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/DefaultParameters.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = load(); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/DestructuringAndAwait.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/DestructuringAndAwait.js index 291ed3bccc4..e28e0bb3643 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/DestructuringAndAwait.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/DestructuringAndAwait.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const { users } = await load(); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/Generators.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/Generators.js index 4f2fc95ca6f..a20fc19b75f 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/Generators.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/Generators.js @@ -12,6 +12,11 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } @@ -20,7 +25,7 @@ export default class extends React.Component { for (let user of load(4)) { users.push(user); } - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ObjectDestructuring.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ObjectDestructuring.js index c6edbee2702..db377cee5e6 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ObjectDestructuring.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ObjectDestructuring.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = load(); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ObjectSpread.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ObjectSpread.js index ca41004f9f6..72356fb9404 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ObjectSpread.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/ObjectSpread.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = load({ age: 42 }); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/Promises.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/Promises.js index c0e13c81ebf..9eb8c20f790 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/Promises.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/Promises.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } componentDidMount() { load().then(users => { - this.setState({ users }); + this.setState({ users }, () => this.done()); }); } diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/RestAndDefault.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/RestAndDefault.js index a977e8c8340..94b75980835 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/RestAndDefault.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/RestAndDefault.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = load(); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/RestParameters.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/RestParameters.js index 9dcc33fa00e..c1cd63e887e 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/RestParameters.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/RestParameters.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = load({ id: 0, user: { id: 42, name: '42' } }); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/TemplateInterpolation.js b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/TemplateInterpolation.js index 505ee6173d5..33b004722d8 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/syntax/TemplateInterpolation.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/syntax/TemplateInterpolation.js @@ -13,12 +13,17 @@ export default class extends React.Component { constructor(props) { super(props); + this.done = () => {}; + this.props.setCallWhenDone && this.props.setCallWhenDone((done) => { + this.done = done; + }); + this.state = { users: [] }; } async componentDidMount() { const users = load('user_'); - this.setState({ users }); + this.setState({ users }, () => this.done()); } render() { diff --git a/tasks/e2e-installs.sh b/tasks/e2e-installs.sh index f3c1d8d3bd0..7bb4c0392f2 100755 --- a/tasks/e2e-installs.sh +++ b/tasks/e2e-installs.sh @@ -22,8 +22,6 @@ temp_app_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_app_path'` function cleanup { echo 'Cleaning up.' cd $root_path - # Uncomment when snapshot testing is enabled by default: - # rm ./packages/react-scripts/template/src/__snapshots__/App.test.js.snap rm -rf $temp_cli_path $temp_app_path } @@ -60,14 +58,6 @@ root_path=$PWD npm install -# If the node version is < 4, the script should just give an error. -if [ `node --version | sed -e 's/^v//' -e 's/\..\+//g'` -lt 4 ] -then - cd $temp_app_path - err_output=`node "$root_path"/packages/create-react-app/index.js test-node-version 2>&1 > /dev/null || echo ''` - [[ $err_output =~ You\ are\ running\ Node ]] && exit 0 || exit 1 -fi - if [ "$USE_YARN" = "yes" ] then # Install Yarn so that the test can use it to install packages. diff --git a/tasks/e2e-kitchensink.sh b/tasks/e2e-kitchensink.sh index eecd6ed62a7..892230ab747 100755 --- a/tasks/e2e-kitchensink.sh +++ b/tasks/e2e-kitchensink.sh @@ -22,8 +22,6 @@ temp_app_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_app_path'` function cleanup { echo 'Cleaning up.' cd $root_path - # Uncomment when snapshot testing is enabled by default: - # rm ./packages/react-scripts/template/src/__snapshots__/App.test.js.snap rm -rf $temp_cli_path $temp_app_path } @@ -60,14 +58,6 @@ root_path=$PWD npm install -# If the node version is < 4, the script should just give an error. -if [ `node --version | sed -e 's/^v//' -e 's/\..\+//g'` -lt 4 ] -then - cd $temp_app_path - err_output=`node "$root_path"/packages/create-react-app/index.js test-node-version 2>&1 > /dev/null || echo ''` - [[ $err_output =~ You\ are\ running\ Node ]] && exit 0 || exit 1 -fi - if [ "$USE_YARN" = "yes" ] then # Install Yarn so that the test can use it to install packages. @@ -93,9 +83,6 @@ cp package.json package.json.orig # of those packages. node $root_path/tasks/replace-own-deps.js -# Remove .npmignore so the test template is added -rm $root_path/packages/react-scripts/.npmignore - # Finally, pack react-scripts scripts_path=$root_path/packages/react-scripts/`npm pack` @@ -151,14 +138,7 @@ E2E_URL="http://localhost:3001" \ E2E_FILE=./build/index.html \ CI=true \ NODE_PATH=src \ - node_modules/.bin/mocha --require babel-register --require babel-polyfill integration/*.js - -# Uncomment when snapshot testing is enabled by default: -# test -e src/__snapshots__/App.test.js.snap - -# Test the server -REACT_APP_SHELL_ENV_MESSAGE=fromtheshell NODE_PATH=src npm start -- --smoke-test -REACT_APP_SHELL_ENV_MESSAGE=fromtheshell HTTPS=true NODE_PATH=src npm start -- --smoke-test + node_modules/.bin/mocha --require babel-register --require babel-polyfill integration/*.test.js # ****************************************************************************** # Finally, let's check that everything still works after ejecting. @@ -199,20 +179,14 @@ E2E_URL="http://localhost:3002" \ REACT_APP_SHELL_ENV_MESSAGE=fromtheshell \ CI=true NODE_PATH=src \ NODE_ENV=production \ - node_modules/.bin/mocha --require babel-register --require babel-polyfill integration/*.js + node_modules/.bin/mocha --require babel-register --require babel-polyfill integration/*.test.js # Test "production" environment E2E_FILE=./build/index.html \ CI=true \ NODE_ENV=production \ NODE_PATH=src \ - node_modules/.bin/mocha --require babel-register --require babel-polyfill integration/*.js - -# Uncomment when snapshot testing is enabled by default: -# test -e src/__snapshots__/App.test.js.snap - -# Test the server -REACT_APP_SHELL_ENV_MESSAGE=fromtheshell NODE_PATH=src npm start -- --smoke-test + node_modules/.bin/mocha --require babel-register --require babel-polyfill integration/*.test.js # Cleanup cleanup