[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 ...
随机推荐
- SGU 149 树形DP Computer Network
这道题搜了一晚上的题解,外加自己想了半个早上,终于想得很透彻了.于是打算好好写一写这题题解,而且这种做法比网上大多数题解要简单而且代码也比较简洁. 首先要把题读懂,把输入读懂,这实际上是一颗有向树.第 ...
- js的setInterval和setTimeout的那些浅坑
setInterval和setTimeout的区别简单提一下 setInterval() :按照指定的周期(以毫秒计)来调用函数或计算表达式.方法会不停地调用函数,直到 clearInterval() ...
- 关于加号传递到后端会变为空格的c#例子
参考博客:http://blog.csdn.net/nsdnresponsibility/article/details/50965262 以前在一次传递参数的情况中遇到,特此记录一下. 之前传递的参 ...
- 16,re模块的常用方法
ret =re.findall('\d+', 'eva123egon4yuan567') print(ret)#返回满足条件的结果 ,放在一个列表里. ret2 = re.search('\d+',' ...
- 编辑器sublime(转)摘自网络
一.下载和安装 Sublime Text2是一款开源的软件,不需要注册即可使用(虽然没有注册会有弹窗,但是基本不影响使用). 下载地址:http://www.sublimetext.com/,请自行根 ...
- Configure Red Hat Enterprise Linux shared disk cluster for SQL Server
下面一步一步介绍一下如何在Red Hat Enterprise Linux系统上为SQL Server配置共享磁盘集群(Shared Disk Cluster)及其相关使用(仅供测试学习之用,基础篇) ...
- 大数据学习——Storm学习单词计数案例
需求:计算单词在文档中出现的次数,每出现一次就累加一次 遇到的问题 这个问题是<scope>provided</scope>作用域问题 https://www.cnblogs. ...
- [android 开发篇] 易白教程网址
http://www.yiibai.com/android/android_bluetooth.html
- 九度oj 题目1137:浮点数加法
题目描述: 求2个浮点数相加的和 题目中输入输出中出现浮点数都有如下的形式:P1P2...Pi.Q1Q2...Qj对于整数部分,P1P2...Pi是一个非负整数 对于小数部分,Qj不等于0 输入: 对 ...
- BZOJ 2190 [SDOI2008]仪仗队 ——Dirichlet积
[题目分析] 考虑斜率为0和斜率不存在的两条线上只能看到3人. 其余的人能被看见,当且仅当gcd(x,y)=1 ,然后拿卷积算一算 发现就是欧拉函数的前缀和的二倍. 注意2的情况要特判. [代码] # ...