Testing Web Frameworks with Jest: Vue, Redux, and Express
Jest is actually a universal testing platform, although it is often considered to be a React-specific test runner. Jest has the ability to adapt to any JavaScript library or framework. In this tutorial we will teach you how to integrate Jest into other popular JS libraries other than React.
Vue.js
Note: we assume that you have a Vue project already created if not please run:
npm install -g vue-cli
vue init webpack vue-test
cd vue-test
To run Jest in this Vue project you have to install some dependencies:
npm i -D jest vue-jest babel-jest
You need jest-vue-preprocessor to make Jest understand your .vue files, and you need babel-jest for the integration with Babel.
Also you will need to install vue-test-utils:
npm i -D vue-test-utils
Once you are done with installing the dependencies, you have to add the following configuration in the package.json
"jest": {
"moduleNameMapper": {
"^vue$": "vue/dist/vue.common.js"
},
"moduleFileExtensions": [
"js",
"vue"
],
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
".*\\.(vue)$": "/node_modules/vue-jest"
}
}
The moduleFileExtensions tells Jest which extensions to look for, and transform tells Jewhich preprocessor to use for a file extension.
Finally, you have to add a test script to the package.json:
{
"scripts": {
"test": "jest",
...
},
...
}
Testing a Component
Let us consider a test for a single file Component (a file that contains its html, css and js in one component).
To do this, you need to first create a ChatList.vue component in src/components:
<template>
<ul>
<li v-for="chat in chats">
{{ chat }}
</li>
</ul>
</template>
<script>
export default {
name: 'list',
props: ['chats']
}
</script>
Then you need to update your App.Vue as shown below:
<template>
<div id="app">
<ChatList :chats="chats"/>
</div>
</template>
<script>
import ChatList from './components/ChatList'
export default {
name: 'app',
data: () => ({ messages: ['Hey John', 'Howdy Paco'] }),
components: {
ChatList
}
}
</script>
So far we have created a couple of components that we can use for our testing. Next we will create a folder under the project root, and an App.test.js file:
import Vue from "vue";
import App from "../src/App";
describe("App.test.js", () => {
let cmp, vm;
beforeEach(() => {
cmp = Vue.extend(App); // Create a copy of the original component
vm = new cmp({
data: {
// Replaces data value with this fake data
chats: ["Aryan"]
}
}).$mount(); // Instances and mounts the component
});
it('equals chats to ["Aryan"]', () => {
expect(vm.chats).toEqual(["Aryan"]);
});
});
Now when we run npm test, the test runs and passes. In the case where you are modifying tests you have to run the above command in watch mode:
npm test -- --watch
Redux
Follow this steps to write tests for a Redux code.
Setup
Install jest and babel-jest:
npm install --save-dev jest```
```npm install --save-dev babel-jest
Then you configure your code to use babel-preset-env features in .babelrc:
{
"presets": ["@babel/preset-env"]
}
You should add this to the scripts in your package.json
{
...
"scripts": {
...
"test": "jest",
"test:watch": "npm test -- --watch"
},
...
}
Finally, you can run npm test to run it once, or you can run npm run test:watch to test every file change.
Express.js
Follow the steps below to find out how to test an Express with Jest.
1. Install
The first thing that you need to do is to install babel-cli, babel-preset-env, jest, supertest and superagent.
npm install --save-dev babel-cli babel-preset-env jest supertest superagent
2. Separate your app and sever
This is so that Jest won't be listening to your port after testing
//app.js
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.status(200).send('Hello World!')
})
module.exports = app
//server.js
const app = require('./app')
app.listen(5678, () => {
console.log('Your Example app listening on port 5678!');
})
3. Use done to notify that it endsM
Jest test ends when it hits the last line of the test function, so you will need to use a done() to make it right.
const request = require('supertest');
const app = require('../../src/app')
describe('It should test the root path', () => {
test('It has to response the GET method', (done) => {
request(app).get('/').then((response) => {
expect(response.statusCode).toBe(200);
done();
});
});
});
4. Promise way
const request = require('supertest');
const app = require('../../src/app')
describe('Test the root path', () => {
test('It should response the GET method', () => {
return request(app).get("/").then(response => {
expect(response.statusCode).toBe(200)
})
});
})
5. Async, await way to test
const request = require('supertest');
const app = require('../../src/app')
describe('It should test the root path', () => {
test('It has to response the GET method', async () => {
const response = await request(app).get('/');
expect(response.statusCode).toBe(200);
});
})
6. Using Supertest
You can also use the supertest way. All you need to do is to return the statement and remember not use .end() and the end.
A working example is as shown below:
const request = require('supertest');
const app = require('../../src/app')
describe('It should test the root path', () => {
test('It has to response the GET method', () => {
return request(app).get('/').expect(200);
});
})
7. Database connection
You have to handle database connection during the tests, this is done using this pattern:
describe('It has to test the addLike method', () => {
beforeAll(() => {
mongoDB.connect();
});```
afterAll((done) => {
mongoDB.disconnect(done);
});
}
Here we used mongoDB. We will connect at the beginning of this test suite, and disconnect at the end. And the mongoDB is just a wrapper class.
You can consider using beforeEach and afterEach to manage the database connection so as to prevent race condition.
module.exports = {
mongoose,
connect: () => {
mongoose.Promise = Promise;
mongoose.connect(config.database[process.env.NODE_ENV]);
},
disconnect: (done) => {
mongoose.disconnect(done);
},
};
Notice that done? It is a variable used to indicate that an async operation is finished. Jest will give that as a parameter for that afterAll.
8. Running the Tests
You may want to use jest --runInBand to run the tests depending on how you structure your tests. Otherwise, multiple tests access same collection causes random failing for your tests. In order not to use -runInBand, you can open and close database connection with beforeEach and afterEach instead of beforeAll and afterAll.
GatsbyJS
To run jest in Gatsby follow the steps below:
1. Install the dependencies
npm install --save-dev jest babel-jest react-test-renderer babel-preset-gatsby identity-obj-proxy
2. Create a Jest configuration file
jest.config.js
module.exports = {
transform: {
"^.+\\.jsx?$": `<rootDir>/jest-preprocess.js`,
},
moduleNameMapper: {
".+\\.(css|styl|less|sass|scss)$": `identity-obj-proxy`,
".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": `<rootDir>/__mocks__/file-mock.js`,
},
testPathIgnorePatterns: [`node_modules`, `.cache`, `public`],
transformIgnorePatterns: [`node_modules/(?!(gatsby)/)`],
globals: {
__PATH_PREFIX__: ``,
},
testURL: `http://localhost`,
setupFiles: [`<rootDir>/loadershim.js`],
}
3. Use mocks to complete your testing environment
Mocking the gatsby module is recommended. Though it is not needed at first, however, it will make things easier when you want to test components that makes use of Link or GraphQL
__mocks__/gatsby.js
```const React = require("react")
const gatsby = jest.requireActual("gatsby")
module.exports = {
...gatsby,
graphql: jest.fn(),
Link: jest.fn().mockImplementation(
// these props are invalid for an `a` tag
({
activeClassName,
activeStyle,
getProps,
innerRef,
partiallyActive,
ref,
replace,
to,
...rest
}) =>
React.createElement("a", {
...rest,
href: to,
})
),
StaticQuery: jest.fn(),
useStaticQuery: jest.fn(),
}
4. Write the test
Create a test file and add it to a __tests__ directory, or you put them elsewhere, it should have the extension .spec.js or.test.js. for instance:
src/components/__tests__/header.js
```import React from "react"
import renderer from "react-test-renderer"
import Header from "../header"
describe("Header", () => {
it("renders correctly", () => {
const tree = renderer
.create(<Header siteTitle="Default Starter" />)
.toJSON()
expect(tree).toMatchSnapshot()
})
})
5. Running the tests
Inside your package.json there is already a script for test, this currently outputs an error message. Change this to use the jest executable that we now have available, like so:
"scripts": {
"test": "jest"
}
Previous:
Troubleshooting Jest: Fixes for Common Testing Issues.
Next:
Jest Expect: Comprehensive Guide to Matchers and Extensions.
It will be nice if you may share this link in any developer community or anywhere else, from where other developers may find this content. Thanks.
https://www.w3resource.com/jest/testing-web-frameworks-with-jest.php
- Weekly Trends and Language Statistics
- Weekly Trends and Language Statistics