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的更多相关文章

  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 ...

  2. [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 ...

  3. Web.config Transformation Syntax for Web Application Project Deployment

    Web.config Transformation Syntax for Web Application Project Deployment Other Versions   Updated: Ma ...

  4. 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 ...

  5. 转: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 ...

  6. spring cloud config的bootstrap.yml与application.proterties的区别

    bootstrap.yml  和application.yml  都可以用来配置参数 bootstrap.yml可以理解成系统级别的一些参数配置,这些参数一般是不会变动的 application.ym ...

  7. Unit Testing a zend-mvc application

    Unit Testing a zend-mvc application A solid unit test suite is essential for ongoing development in ...

  8. JavaScript Web Application summary

    Widget/ HTML DOM (CORE) (local dom) DOM, BOM, Event(Framework, UI, Widget) function(closure) DATA (c ...

  9. 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 ...

随机推荐

  1. Python9-递归函数-day17

    # 计算方法:人脑复杂,计算机简单#查找:找数据#排序#最短路径#我们学习的算法都是过去时#要了解基础的算法,才能创造出更好的算法#不是所有的事情都能套用现成的方法解决的# 有些时候会用到学过的算法只 ...

  2. 【LeetCode】String to Integer (atoi)(字符串转换整数 (atoi))

    这道题是LeetCode里的第8道题. 题目要求: 请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止. 当我们 ...

  3. 利用pytorch复现spatial pyramid pooling层

    sppnet不讲了,懒得写...直接上代码 from math import floor, ceil import torch import torch.nn as nn import torch.n ...

  4. .NET重构(五):存储过程、触发器和函数的区别

    导读:在触发器的学习过程中,师傅讲了它的耦合性高,建议我能用存储过程,那到底什么是存储过程呢,自己也不是特别了解,还有就是,触发器也算是一种特殊的存储过程,为什么就不建议多用呢?接下来,就谈谈触发器. ...

  5. POJ-2002 Squares,哈希模板+数学公式!

                                                           Squares 题意:二维坐标轴给出n个点求有多少个正方形. 要是平时做比赛的话毫无疑问会 ...

  6. The BLOB and TEXT Types

    官网参考:https://dev.mysql.com/doc/refman/5.7/en/blob.html 字符串类型对应的存储需求 Data Type Storage Required CHAR( ...

  7. spring运行时没有问题,在单元测试时,出现java.lang.ClassFormatError错误

    Caused by: java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstrac ...

  8. [luoguP1053] 篝火晚会(贪心 + 乱搞)

    传送门 假设第一个位置是1,那么枚举它的左右两边是谁,有两种情况,然后可以递推求出序列. 然后可以贪心,两个序列有多少个不同的数,答案就是多少,具体为啥,yy一下即可 然后就是判断递推求出的序列和目标 ...

  9. [BZOJ1590] [Usaco2008 Dec]Secret Message 秘密信息(字典树)

    传送门 看到前缀就要想到字典树! 看到前缀就要想到字典树! 看到前缀就要想到字典树! #include <cstdio> #include <iostream> #define ...

  10. 【边双连通】poj 3352 Road Construction

    http://poj.org/problem?id=3352 [题意] 给定一个连通的无向图,求最少加多少条边使得这个图变成边双连通图 [AC] //#include<bits/stdc++.h ...