The goal of this instruction is to quickly setup a React development environment with Unit Test in place. This assumes that you have Node.Js installed on your machine.
Here are the list of web development tools needed:
To demonstrate clearly, we’re going to use this simple Password Strength source code ( password-strength-react ) I wrote. The plan is to create a React development setup with unit test and live reload for a seamless developer experience.
If you don’t have time following the steps, you can also get the whole setup here - https://github.com/hunyoboy/password-strength-react/tree/unit-test
If you want to follow the steps here, let’s go ahead and clone the Password Strength repository from https://github.com/hunyoboy/password-strength-react using this command:
git clone https://github.com/hunyoboy/password-strength-react.git password-strength
The command will create a folder named “password-strength” with source code inside.
Folder structure of the cloned source code on my IDE.
Opening the package.json, we’ll see the list of dependencies needed to setup the React web development.
Take note of the values for “start” and “test” properties of scripts inside package.json. These are the commands to start our web development server ( Webpack Dev Server ) . You’ll see how we’re going to use them later.
Here are the steps:
Install dependencies listed inside package.json using NPM.
Using the command line, go inside the “password-strength” folder and run the command npm install
:
Once the command is finished, you’ll see a folder named npm_modules.
Create a root folder and name it “test”.
Inside test folder, create a new html file and name it “index.html”.
Copy/paste the code below into index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Password Strength Test</title>
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.min.css">
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine-html.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/boot.min.js"></script>
<!-- bundled test script and dependencies by Webpack -->
<script src="../build/test.js"></script>
</head>
<body>
</body>
</html>
File index.html will be responsible for displaying our test results from Jasmine thru url, http://localhost:8080/test. Some people will name this file “SpecRunner.html” or “Spec.html”.
Move code for each React component to its own separate javascript file.
If you open “components/PasswordStrength.js”, you’ll notice that all our React components are inside here. For maintainability and ease in unit testing, we need to separate each component by creating a new js file per component.
Delete PasswordStrength.js and copy all the files from here and its content inside the components folder.
Your components folder will look like this:
Inside “components” folder, create a new folder named “tests”.
Folder tests will hold our actual Jasmine test scripts for unit testing our React components.
a. Inside tests folder, create a js file and name it “PasswordStrength-spec.js”. This is the unit test for the PasswordStrength component.
Copy/paste the code below:
import React from 'react/lib/ReactWithAddOns'
import PasswordStrength from '../PasswordStrength'
describe("PasswordStrength Component", () => {
beforeEach(function() {
this.TestUtils = React.addons.TestUtils
this.component = this.TestUtils.renderIntoDocument(<PasswordStrength/>)
});
it("Renders a div with class danger.", function() {
var box = this.TestUtils.scryRenderedDOMComponentsWithClass(this.component, "danger");
expect(box.length).toEqual(1);
});
});
b. Create another js file inside tests folder and name it “CheckBox-spec.js”. This targets the CheckBox component for unit testing.
Copy/paste the code below:
import React from 'react/lib/ReactWithAddOns'
import CheckBox from '../CheckBox'
describe("CheckBox Component", () => {
beforeEach(function() {
this.TestUtils = React.addons.TestUtils
this.component = this.TestUtils.renderIntoDocument(<CheckBox checked={false} />)
});
it("Input tag is rendered and props is false.", function() {
var input = this.TestUtils.scryRenderedDOMComponentsWithTag(this.component, "input");
expect(input.length).toEqual(1);
expect(this.component.props.checked).toEqual(false);
});
});
For demo purposes, we only have 2 components with unit test scripts. Feel free to write unit test scripts for the rest of the components.
At this point, your components folder should look like this:
Create a root folder called “client” and its content.
We will be serving our Single Page Application ( SPA ) through this folder, http://localhost:8080/client.
a. Create an index html file and copy/paste code below:
<!DOCTYPE html>
<html>
<head>
<title>React</title>
<link rel="stylesheet" href="http://joecaps.com/blog/css/trio.css">
<link rel="stylesheet" href="http://joecaps.com/blog/demo/css/password-strength-widget.css">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="container">
<div class="title">
<h2>Demo - Password Strength Component In React</h2>
</div>
<div id="app"></div>
</div>
<script src="../build/build.js"></script>
</body>
</html>
b. Create our React entry js file called “client.js”. Copy/paste the code below:
import React from 'react'
import { render } from 'react-dom'
import PasswordStrength from '../components/PasswordStrength'
render(
<PasswordStrength/>,
document.getElementById('app')
)
At this point your folder structure will look like below:
Create Webpack’s configuration file
Create a js file on the root and name it “webpack.config.js”. Copy/paste the code below:
var path = require("path"),
webpack = require("webpack"),
glob = require("glob"),
minimize = process.argv.indexOf('--minimize') !== -1,
plugins = [];
if (minimize) {
plugins.push(new webpack.optimize.UglifyJsPlugin());
}
module.exports = {
devtool: 'inline-source-map',
entry: {
test: glob.sync("./components/tests/*spec.js"),
build: ["./client/client.js"]
},
output: {
path: path.resolve(__dirname, "build"),
filename: '[name].js',
publicPath: '/build'
},
plugins: plugins,
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['react','es2015']
}
}
]
}
}
Based from the “entry” property above, we will have 2 bundled files named “test.js” and “build.js”. The test.js will be reference by the html file test/index.html for displaying and running unit tests. However, build.js will be referenced by client/index.html for running the React application.
Also if you notice this line glob.sync("./components/tests/*spec.js")
. This line of code will return an array of file names inside “components/tests/” folder to be
bundled-up by Webpack for running our unit tests. It is important to name your unit test file with something like **spec.js so it will be bundled by Webpack.
Test our setup by running npm test
on the command line.
Remember the scripts properties inside package.json file before? This is how we used them.
Go to your terminal and inside password-strength directory, run npm test
:
Webpack will run and bundle all our applications dependencies.
Once the command is finished, you’ll see something like this:
To see the test bundled file in the browser, go to http://localhost:8080/build/test.js. For the app’s bundled file, go to http://localhost:8080/build/build.js.
Take note that the webpack dev server is serving these files from memory. However, if you want to see the bundled files on your local directory, run this command instead:
webpack
Webpack will create a folder named “build” with the bundled files inside:
Run unit test with live page reload.
On your browser go to, http://localhost:8080/test. You’re running the unit test and see something like this:
Test the live reload feature by making one of the test fail. Open components/tests/PasswordStrength-spec.js and change the expected value from 1 to 2.
You should see that your browser will reload automatically displaying a big red failed Unit test:
Pretty cool eh. Now you can continue writing unit test for the rest of components and see in almost real-time the result.
To see the Password Strength app running, go to http://localhost:8080/client
Also take note that running npm start
instead of npm test
will minify the bundled js files using the Uglify plugin.