组件测试及发布

单元测试

在组件开发完成并发布之前,需要对组件进行单元测试,单元测试是使用断言的方式判断实际的输出与预测的输出是否相同,目的是发现可能存在的问题;组件的单元测试是指使用单元测试工具对组件的各种状态及行为进行测试,确保组件发布后在使用过程中不会出现错误。

Vue组件的单元测试

  • 组件的单元测试有很多好处:

    • 提供描述组件行为的文档
    • 节省手动测试的时间
    • 减少研发新特性时产生的 bug
    • 改进设计
    • 促进重构
  • 用 Jest 测试单文件组件

    官方文档

    首先需要安装 Jest 和 Vue Test Utils

    yarn add jest @vue/test-utils -D -W
    

    然后需要在 package.json 中定义一个单元测试的脚本

    // package.json
    {
      "scripts": {
        "test": "jest" // 修改test为jest
      }
    }
    

    为了告诉 Jest 如何处理 *.vue 文件,需要安装和配置 vue-jest 预处理器:

    yarn add vue-jest -D -W
    

    创建jext.config.js配置文件

    module.exports = {
      "testMatch": ["**/__tests__/**/*.[jt]s?(x)"],
      "moduleFileExtensions": [
        "js",
        "json",
        // 告诉 Jest 处理 `*.vue` 文件
        "vue"
      ],
      "transform": {
        // 用 `vue-jest` 处理 `*.vue` 文件
        ".*\\.(vue)$": "vue-jest",
        // 用 `babel-jest` 处理 js
        ".*\\.(js)$": "babel-jest" 
      }
    }
    

    需要安装 babel-jest处理es6语法

    yarn add babel-jest -D -W
    

    babel配置文件

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

    Babel 的桥接

    yarn add babel-core@bridge -D -W
    
  • Jest常用API

    中文文档

    • 全局函数

      describe(name, fn) 把相关测试组合在一起

      test(name, fn) 测试方法

      expect(value) 断言

    • 匹配器

      toBe(value) 判断值是否相等

      toEqual(obj) 判断对象是否相等

      toContain(value) 判断数组或字符串是否包含

    • 快照

      toMatchSnapshot()

  • vue-jest常用API

    中文文档

    • mount() 创建一个包含被挂载和渲染的Vue组件的Wrapper
    • Wrapper
      • vm wrapper包裹的组件实例
      • props() 返回Vue实例选项中的props对象
      • html() 组件生成的HTML标签
      • find() 通过选择器返回匹配的组件中的DOM元素
      • trigger() 触发DOM原生事件,自定义事件wrapper.vm.$emit()
      • ...
  • 创建packages/input/__tests__/input.test.js文件

    @vue/test-utils提供API用于挂载组件,Jest不需要导入因为测试文件是被jest加载执行的

    import input from '../src/input.vue'
    import { mount } from '@vue/test-utils'
    
    // 创建代码块 将input相关测试都添加到这里
    describe('wang-input', () => {
      test('input-text', () => {
        // 挂载组件 只是内存中的挂载 返回一个包裹器
        const wrapper = mount(input)
        // 测试生成的html中是否包含type=text
        expect(wrapper.html()).toContain('input type="text"')
      })
    })
    
    
  • 使用yarn test测试

    image-20210412082210659.png
  • 添加更多测试

    ...
    test('input-password', () => {
        const wrapper = mount(input, {
          propsData: {
            type: 'password',
          },
        })
        expect(wrapper.html()).toContain('input type="password"')
      })
    
      test('input-password', () => {
        const wrapper = mount(input, {
          propsData: {
            type: 'password',
            value: 'admin',
          },
        })
        expect(wrapper.props('value')).toBe('admin')
      })
    
      // 快照
      test('input-snapshot', () => {
        const wrapper = mount(input, {
          propsData: {
            type: 'password',
            value: 'admin',
          },
        })
        // 快照 第一次运行会将wrapper.vm.$el的内容存储在./__snapshots__/input.test.js.snap中
        expect(wrapper.vm.$el).toMatchSnapshot()
      })
    ...
    

    如果以后生成的快照和第一次生成的不同,会测试失败,如下所示:

    image-20210412082559674.png

可以通过yarn test -u删除旧的快照文件,并重新生成

Rollup打包
  • 特点

    • Rollup是一个模块打包器
    • Rollup支持Tree-shaking
    • 打包结果比webpack小
    • 开发框架/组件库使用Rollup更合适,如Vue、React等
  • 安装

    • Rollup
    • rollup-plugin-terser 对代码进行压缩
    • [email protected] 将单文件组件编译成js代码,最新版本适用于vue3.x,内部需要使用到vue-template-compiler
    • vue-template-compiler
  • 设置Rollup配置文件

    import { terser } from 'rollup-plugin-terser'
    import vue from 'rollup-plugin-vue'
    
    module.exports = [
      {
        input: 'index.js',
        output: [
          {
            file: 'dist/index.js',
            format: 'es'
          }
        ],
        plugins: [
          vue({
            // Dynamically inject css as a