jest单元测试

npm i -D jest jest-environment-jsdom:安装依赖项
npm i -D babel-jest @babel/core @babel/preset-env:使用babel

// babel.config.js
module.exports = {
  presets: [['@babel/preset-env']]
}

npx jest --init:初始化jest.config.js
在这里插入图片描述
jest.config.js配置文件中:

// 要测试的文件
testMatch: [
    "**/__tests__/**/*.[jt]s?(x)",
    "**/?(*.)+(spec|test).[tj]s?(x)"
  ],
// demo.test.js文件
// 钩子函数
beforeEach(() => { console.log('beforeEach') })
afterEach(() => { console.log('afterEach') })
beforeAll(() => { console.log('beforeAll') })
afterAll(() => { console.log('afterAll') })
// describe(name, fn) 是一个将多个相关的测试组合在一起的块
describe('A组件', () => {
  test('方法1', () => {
    expect(1 + 2).toBe(3)
  })
  test('方法2', () => {
    expect(1 + 2).toEqual(3)
  })
})
test('demo', ()=>{
  expect({ name: 'tom' }).toEqual({ name: 'tom' })
  expect('helloworld').toMatch(/world/)
  expect(3).toBeGreaterThan(2)
  expect(3).toBeGreaterThanOrEqual(2)
  expect(3).toBeLessThan(5)
  expect(3).toBeLessThanOrEqual(5)
  expect(0.1 + 0.2).toBeCloseTo(0.3)
  const shoppingList = ['milk', 'coffee']
  expect(shoppingList).toContain('milk');
  expect(new Set(shoppingList)).toContain('milk');
  // let flag = false
  // expect(flag).toBeNull()
  // expect(flag).toBeUndefined()
  // expect(flag).toBeFalsy()
  // expect(flag).toBeTruthy
 }
 
function compileAndroidCode() {
  throw new Error('you are using the wrong JDK');
}
test('compiling android goes as expected', () => {
  expect(() => compileAndroidCode()).toThrow();
  expect(() => compileAndroidCode()).toThrow(Error);
  // You can also use the exact error message or a regexp
  expect(() => compileAndroidCode()).toThrow('you are using the wrong JDK');
  expect(() => compileAndroidCode()).toThrow(/JDK/);
});

// 异步测试1
function getData(callback) {
  setTimeout(() => {
    callback({ foo: 'bar' })
  }, 2000)
}
test('async test', (done) => {
  getData(data => {
    done()
    expect(data).toEqual({ foo: 'bar' })
  })
})
// 异步测试2
function getData() {
  return new Promise((resolve, reject) => {
    // reject('hello')
    setTimeout(() => {
      resolve({ foo: 'bar' })
    }, 2000)
  })
}
test('async test', (done) => {
  getData().then(data => {
    done()
    expect(data).toEqual({ foo: 'bar' })
  })
})
// 不用done的写法
test('async test', () => {
  // return getData().then(data => {
  //   expect(data).toEqual({ foo: 'bar' })
  // })
  //也可这样写
  return expect(getData()).resolves.toEqual({ foo: 'bar' })
  // 异常 reject('hello')
  // return expect(getData()).rejects.toMatch('hello')
})
// async await
test('async', async () => {
  try {
    const data = await getData()
    expect(data).toEqual({ foo: 'bar' })
  } catch (err) {
    expect(err).toMatch('hello')
  }
  // 或者这样写
  // await expect(getData()).resolves.toEqual({ foo: 'bar' })
  // await expect(getData()).rejects.toMatch('hello')
})

Mock定时器

// 耗时的异步测试
function getData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ foo: 'bar' })
    }, 60000)
  })
}
// mock定时器
jest.useFakeTimers()
test('demo', () => {
  expect.assertions(1)
  getData().then(data => {
    expect(data).toEqual({ foo: 'bar' })
  })
  // 快速所有定时器
  jest.runAllTimers()
})
// 循环定时器
function getData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ foo: 'bar' })
      getData()
    }, 60000)
  })
}
// mock定时器
jest.useFakeTimers()
test('demo', () => {
  expect.assertions(1)
  getData().then(data => {
    expect(data).toEqual({ foo: 'bar' })
  })
  // 快进当前的定时器家属,不等待其他的
  jest.runOnlyPendingTimers(
function getData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ foo: 'bar' })
    }, 2000)
  })
}
// mock定时器
jest.useFakeTimers()
test('demo', () => {
  expect.assertions(1)
  getData().then(data => {
    expect(data).toEqual({ foo: 'bar' })
  })
  jest.advanceTimersByTime(1000)
  console.log(1)
  jest.advanceTimersByTime(1000)
})

Mock函数

// 基本用法
function forEach(items, callbask) {
  for (let i = 0; i < items.length; i++) {
    callbask(items[i], i)
  }
}
test('Mock Function', () => {
  const items = [1, 2, 3]
  const mockFn = jest.fn((val, index) => {
    return val + 1
  })
  // 设置所有的mock函数返回值为123
  // mockFn.mockReturnValue(123)
  // 与mockFn.mockReturnValue(123)作用相同
  // mockFn.mockReturnValueOnce(123)
  // mockFn.mockReturnValueOnce(123)
  // mockFn.mockReturnValueOnce(123)
  forEach(items, mockFn)
  console.log(mockFn.mock)
  expect(mockFn.mock.calls.length).toBe(items.length)
  expect(mockFn.mock.calls[0][0]).toBe(1)
  expect(mockFn.mock.calls[0][1]).toBe(0)
})
// 模拟模块
//users.js
import axios from 'axios'
export const getAllusers = () => {
  return axios.get('/users.json').then(res => res.data)
}
// mock-function.test.js
import axios from 'axios'
import { getAllusers } from './users'
jest.mock('axios')
test('should fetch users', async () => {
  const users = [{ name: 'Bob' }]
  const res = { data: users }
  axios.get.mockResolvedValue(res)
  const data = await getAllusers()
  expect(data).toEqual(users)
})
// 模拟实现
//foo.js
export default function foo() {
  return 1
}
// mock-function.test.js
jest.mock('./foo')
import foo from './foo'
foo.mockImplementation(() => 123)
test('Mock Implementations', () => {
  expect(foo()).toBe(123)
})

DOM测试

function renderHtml() {
  const div = document.createElement('div')
  div.innerHTML = `
  <h1>Hello World</h1>
  `
  document.body.appendChild(div)
}
test('DOM Testing', () => {
  renderHtml()
  expect(document.querySelector('h1').innerHTML).toBe('Hello World')
})

function renderVueComponent() {
  document.body.innerHTML = `<div id="app"></div>`
  new Vue({
    template: `
    <div id="app"><h1>{{message}}</h1></div>
    `,
    data: {
      message: 'Hello World'
    }
  }).$mount('#app')
}
test('Vue Testing', () => {
  renderVueComponent()
  console.log(document.body.innerHTML)
  expect(document.body.innerHTML).toMatch(/Hello World/)
})

快照测试

test.only('Snapshot Testing', () => {
  renderVueComponent()
  expect(document.body.innerHTML).toMatchSnapshot()
})
// 更新快照命令:npx jest --updateSnapshot
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值