Commit 1d586aaf authored by Fabrizio Castellarin's avatar Fabrizio Castellarin Committed by Dan Abramov
Browse files

E2e jsdom fix (#1470)

* E2E: run tests when react is ready

* Entangle e2e with callbacks

* Remove unused e2e lines
parent bc2fc808
No related merge requests found
Showing with 124 additions and 72 deletions
+124 -72
{
"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",
......
......@@ -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()
})
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 <div>{feature}</div>;
}
}
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 ? <Feature /> : null;
return Feature ? <BuiltEmitter><Feature /></BuiltEmitter> : null;
}
}
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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());
});
}
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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.
......
......@@ -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
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment