[Testing] Config jest to test Javascript Application -- Part 1
Transpile Modules with Babel in Jest Tests
Jest automatically loads and applies our babel configuration. However, because our project takes advantage of tree shaking with webpack, our babel configuration disables transpiling modules. For Jest to work on our code, we need to make sure that our babel configuration transpiles modules during our tests. We’ll use the NODE_ENV environment variable to generate the proper configuration.
For tree shaking with Webpack, need to disable transpile modules, for jest testing, we need to use commonjs
const isTest = String(process.env.NODE_ENV) === 'test'
module.exports = {
presets: [['@babel/preset-env', {modules: isTest ? 'commonjs' : false}], '@babel/preset-react'],
...
}
Configure Jest’s test environment for testing node or browser code
In our application we’re testing code that should run in the browser, but Jest is intended to test JavaScript that runs in the browser or in node. Let’s create a custom jest config file so we can customize the test environment.
If jest in your app is mean for Node application, then config jest environment to 'node', otherwise, it is mean for broswer, then 'jsdom'
Create 'jest.config.js':
module.exports = {
testEnvironment: 'jest-environment-jsdom', //'jest-environment-node',
}
If you use 'node' env, then in the test, you cannot access window object.
Support importing CSS files with Jest’s moduleNameMapper
In most real-world applications using webpack, you’re likely using a few loaders. In this lesson we’ll see how to make Jest load our modules properly with a moduleNameMapper so we can test our code that makes use of these loaders.
If you use loader in webpack to css files or graphql files which jest don't understand, you can use this trick to make it work.
Install:
npm i -D react-testing-library
In jest.config.js file:
module.exports = {
testEnvironment: 'jest-environment-jsdom', //'jest-environment-node',
moduleNameMapper: {
'\\.css$': require.resolve('./test/style-mock.js')
}
}
test/style-mock.js:
module.exports = {}
test file:
import 'react-testing-library/cleanup-after-each'
import React from 'react'
import {render} from 'react-testing-library'
import AutoScalingText from '../auto-scaling-text' test('renders', () => {
render(<AutoScalingText />)
})
component file:
...
import styles from './auto-scaling-text.module.css' class AutoScalingText extends React.Component { ... return (
<div
className={styles.autoScalingText}
...
Support using webpack CSS modules with Jest
If you’re using CSS modules with webpack, then we can improve our moduleNameMapper to improve our experience and capabilities testing our components by including the css module property name in our tests using identity-obj-proxy.
If we log out the html inside our test:
import 'react-testing-library/cleanup-after-each'
import React from 'react'
import {render} from 'react-testing-library'
import AutoScalingText from '../auto-scaling-text' test('renders', () => {
const {container} = render(<AutoScalingText />)
console.log(container.innerHTML)
})
We can see:
console.log src/shared/__tests__/auto-scaling-text.js:
<div style="transform: scale(1,1);"></div>
There is no information about the component class, which should be:
<div className={styles.autoScalingText}
Install:
npm i -D identity-obj-proxy
in jest.config.js:
module.exports = {
testEnvironment: 'jest-environment-jsdom', //'jest-environment-node',
moduleNameMapper: {
'\\.module\\.css$': 'identity-obj-proxy',
'\\.css$': require.resolve('./test/style-mock.js')
}
}
Run:
jest
We can see:
console.log src/shared/__tests__/auto-scaling-text.js:
<div class="autoScalingText" style="transform: scale(1,1);"></div>
Which include the class name can be a better debug / testing experience.
Generate a Serializable Value with Jest Snapshots
Snapshot testing is a way to simplify writing and maintaining assertions. As noted in the Jest documentation: “The snapshot artifact should be committed alongside code changes, and reviewed as part of your code review process. Jest uses pretty-format to make snapshots human-readable during code review. On subsequent test runs Jest will simply compare the rendered output with the previous snapshot. If they match, the test will pass. If they don't match, either the test runner found a bug in your code that should be fixed, or the implementation has changed and the snapshot needs to be updated.” Let’s see how these work and in what situations we can and should use them.
it is really easy to use snapshot in jest, just remember to update the snaphost when it is necessary by: 'npm t -- --u'
Javascript:
const superHeros = [
{name: 'Dynaguy', powers: ['disintegration ray', 'fly']},
{name: 'Apogee', powers: ['gravity control', 'fly']},
{name: 'Blazestone', powers: ['control of fire', 'pyrotechnic discharges']},
{name: 'Froozone', powers: ['freeze water']},
{name: 'Mr. Incredible', powers: ['physical strength']},
{name: 'Elastigirl', powers: ['physical stretch']},
{name: 'Violet', powers: ['invisibility', 'force fields']},
{name: 'Dash', powers: ['speed']},
{name: 'Jack-Jack', powers: ['shapeshifting', 'fly']}
] export function getFlyingSuperHeros() {
return superHeros.filter(hero => {
return hero.powers.includes('fly')
})
}
import {getFlyingSuperHeros} from '../super-heros';
test('returns super heros that can fly', () => {
const flyingHeros = getFlyingSuperHeros()
expect(flyingHeros).toMatchSnapshot();
})
snapshot:
// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`returns super heros that can fly 1`] = `
Array [
Object {
"name": "Dynaguy",
"powers": Array [
"disintegration ray",
"fly",
],
},
Object {
"name": "Apogee",
"powers": Array [
"gravity control",
"fly",
],
},
Object {
"name": "Jack-Jack",
"powers": Array [
"shapeshifting",
"fly",
],
},
]
`;
React Component:
import React from 'react'
import PropTypes from 'prop-types'
import AutoScalingText from './auto-scaling-text'
import {getFormattedValue} from './utils' class CalculatorDisplay extends React.Component {
static propTypes = {
value: PropTypes.string.isRequired,
}
render() {
const {value, ...props} = this.props
const formattedValue = getFormattedValue(
value,
typeof window === 'undefined' ? 'en-US' : window.navigator.language,
) return (
<div
{...props}
css={{
color: 'white',
background: '#1c191c',
lineHeight: '130px',
fontSize: '6em',
flex: '1',
}}
>
<AutoScalingText>{formattedValue}</AutoScalingText>
</div>
)
}
} export default CalculatorDisplay
import 'react-testing-library/cleanup-after-each'
import React from 'react'
import {render} from 'react-testing-library'
import CalculatorDisplay from '../calculator-display' test('mounts', () => {
const {container} = render(<CalculatorDisplay value="0" />)
expect(container.firstChild).toMatchSnapshot()
})
Snapshot:
// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`mounts 1`] = `
<div
class="css-12149uf"
>
<div
class="autoScalingText"
style="transform: scale(1,1);"
>
0
</div>
</div>
`;
Test an Emotion Styled UI with Custom Jest Snapshot Serializers
Part of the power of snapshots is the ability to provide custom serializers. Let’s check out how to use jest-emotion to include our emotion CSS styles in our React component snapshots so we can be made aware of the impact of our CSS changes on our components.
If we look at the implementation of our component, we're getting that className from the css prop, because we're using emotion's babel plugin that will take the css prop and turn it into a className that's generated with a hash.
Snapshot:
// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`mounts 1`] = `
<div
class="css-12149uf"
>
<div
class="autoScalingText"
style="transform: scale(1,1);"
>
0
</div>
</div>
`;
Using serializer to solve the problem:
Install:
npm install --save-dev jest-emotion
import {createSerializer} from 'jest-emotion';
import * as emotion from 'emotion';
expect.addSnapshotSerializer(createSerializer(emotion));
Snapshot:
exports[`mounts 1`] = `
.emotion-0 {
color: white;
background: #1c191c;
line-height: 130px;
font-size: 6em;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
} <div
class="emotion-0"
>
Now it shows the class and styles, it is much clear to see what has been changed.
It is also possible to add global serializer:
jest.config.js:
module.exports = {
testEnvironment: 'jest-environment-jsdom', //'jest-environment-node',
moduleNameMapper: {
'\\.module\\.css$': 'identity-obj-proxy',
'\\.css$': require.resolve('./test/style-mock.js')
},
snapshotSerializers: ['jest-serializer-path']
}
Handle Dynamic Imports using Babel with Jest
If your application is of any significant size, you will want to make use of dynamic imports to for code splitting with webpack. However, dynamic imports are not supported in node. Let’s see how this problem manifests itself and update our babel config to use babel-plugin-dynamic-import-node to simulate this in our test environment.
dynamic import:
import loadable from 'react-loadable'
const CalculatorDisplay = loadable({
loader: () => import('calculator-display').then(mod => mod.default),
loading: () => <div style={{height: 120}}>Loading display...</div>,
})
Install:
npm i -D babel-plugin-dynamic-import-node
Config babel:
plugins: [
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-object-rest-spread',
[
'babel-plugin-emotion',
{
hoist: isProd,
sourceMap: !isProd,
autoLabel: !isProd,
labelFormat: '[filename]--[local]',
},
],
'react-loadable/babel',
isTest ? 'babel-plugin-dynamic-import-node': null
].filter(Boolean),
[Testing] Config jest to test Javascript Application -- Part 1的更多相关文章
- [Testing] Config jest to test Javascript Application -- Part 2
Setup an afterEach Test Hook for all tests with Jest setupTestFrameworkScriptFile With our current t ...
- [Testing] Config jest to test Javascript Application -- Part 3
Run Jest Watch Mode by default locally with is-ci-cli In CI, we don’t want to start the tests in wat ...
- Web.config Transformation Syntax for Web Application Project Deployment
Web.config Transformation Syntax for Web Application Project Deployment Other Versions Updated: Ma ...
- JavaScript Application Architecture On The Road To 2015
JavaScript Application Architecture On The Road To 2015 I once told someone I was an architect. It’s ...
- 转:Transform Web.Config when Deploying a Web Application Project
Introduction One of the really cool features that are integrated with Visual Studio 2010 is Web.Conf ...
- spring cloud config的bootstrap.yml与application.proterties的区别
bootstrap.yml 和application.yml 都可以用来配置参数 bootstrap.yml可以理解成系统级别的一些参数配置,这些参数一般是不会变动的 application.ym ...
- Unit Testing a zend-mvc application
Unit Testing a zend-mvc application A solid unit test suite is essential for ongoing development in ...
- JavaScript Web Application summary
Widget/ HTML DOM (CORE) (local dom) DOM, BOM, Event(Framework, UI, Widget) function(closure) DATA (c ...
- JavaScript Libraries In A TypeScript Application, Revisited
If you haven’t already gotten involved with it, you’ll probably know that TypeScript is becoming inc ...
随机推荐
- perl学习之正则表达式
9 Perl 中的正则表达式 正则表达式的三种形式 正则表达式中的常用模式 正则表达式的 8 大原则 正则表达式是 Perl 语言的一大特色,也是 Perl 程序中的一点难点,不过如果大家能够很 ...
- 安装tesserocr的步骤和报错RuntimeError: Failed to init API, possibly an invalid tessdata path解决办法
1,首先下载合适的tesseract-ocr的版本 2,然后安装到这一步注意要勾选这一项来安装OCR识别支持的语言包,这样OCR就可以识别多国语言,然后就可以一直点击下一步完成安装. 3,安装tess ...
- 03007_HttpServlet
1.创建 new---Servlet package com.gzdlh.servlet; import java.io.IOException; import javax.servlet.Servl ...
- js-dom-EventUtil
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- TOJ 5021: Exchange Puzzle
5021: Exchange Puzzle Time Limit(Common/Java):1000MS/3000MS Memory Limit:65536KByteTotal Submit ...
- 九度oj 题目1160:放苹果
题目描述: 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法. 输入: 第一行是测试数据的数目t(0 <= t ...
- 九度oj 题目1114:神奇的口袋
题目描述: 有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40.John现在有n个想要得到的物品,每个物品的体积分别是a1,a2……an.John可以从这些物品中 ...
- 【Luogu】P2059卡牌游戏(概率DP)
题目链接 这绝壁是道紫难度的题 请移步xyz32678的题解. 设f[i][j]是有i个人参加了游戏,1是庄家,最后j胜出的概率. 我们可以发现,这个游戏影响胜出的概率的只有庄家的相对位置和人数,跟玩 ...
- 洛谷P3760 - [TJOI2017]异或和
Portal Description 给出一个\(n(n\leq10^5)\)的序列\(\{a_n\}(\Sigma a_i\leq10^6)\),求该数列所有连续和的异或和. Solution 线段 ...
- [ZJOI2005]午餐 (贪心,动态规划)
题目描述 上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂.这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭.由于每个人的口味(以及胃口)不同,所以他们要吃的菜各 ...