Vue3最佳实践 第八章 ESLint 与 测试 ( Jest )

news2024/11/15 17:31:44

在这里插入图片描述

Jest 测试 Vue 组件

  ​在前端项目开发过程中,有很多时候也会要进行测试工作。本文将重点介绍如何利用 JavaScript 测试框架 Jest 进行高效的测试。Jest 是由 FaceBook 开发的顶级测试框架之一,广受开发者们的欢迎和信赖。在接下来的内容中,我们将通过简明扼要的解释和代码示例,向大家展示如何使用 Jest 这个强大的测试工具。无论你是初学者还是有经验的开发者,都能从下面的内容中获得深入的理解和实践的启发。

目录

  • Jest 测试 Vue 组件
    • 1 Vue项目导入Jest
    • 2 Jest 测试 Vue组件
    • 3 Jest 中测试 Vue 应用组件
    • 4 Jest 中 describe 函数
    • 5 Jest 测试 Vue 中的元素
    • 6 Jest事件测试
    • 7 Jest 测试emit 事件

第一章 Vue3项目创建 1 Vue CLI 创建vue项目
第一章 Vue3项目创建 2 使用 Webpack 5 搭建 vue项目
第一章 Vue3项目创建 3 Vite 创建 vue项目
第二章 Vue3 基础语法指令
第三章 Vue Router路由器的使用
第四章 VUE常用 UI 库 1 ( element-plus,Ant ,naiveui,ArcoDesign)
第四章 VUE常用 UI 库 2 ( ailwind 后台框架)
第五章 Vue 组件应用 1( Props )
第五章 Vue 组件应用 2 ( Emit )
第五章 Vue 组件应用 3( Slots )
第五章 Vue 组件应用 4 ( provide 和 inject )
第五章 Vue 组件应用 5 (Vue 插件)
第六章 Pinia,Vuex与axios,VueUse 1(Pinia)
第六章 Pinia,Vuex与axios,VueUse 2(Vuex)
第六章 Pinia,Vuex与axios,VueUse 3(VueUse)
第六章 Pinia,Vuex与axios,VueUse 4(axios)
第七章 TypeScript 上
第七章 TypeScript 中
第七章 TypeScript 下 创建Trello 任务管理器
第八章 ESLint 与 测试 ( ESLint )
第八章 ESLint 与 测试 ( Jest )
第八章 ESLint 与 测试 (TypeScript 中Jest与检测环境集成)

1 Vue项目导入Jest

  ​在开发过程中,我们常常面临这样的困扰:为已经运行良好的应用程序添加新功能,却担心新加入的代码可能会对原有功能产生破坏。虽然测试不能完全消除这种焦虑,但它能有效地降低我们的担忧。

  ​通过编写可测试的代码并进行测试,我们可以把代码切分成独立的组件。大部分难以测试的代码往往功能复杂或者各部分相互交织,难以将其作为独立的组件进行隔离。但如果我们能将代码切割成一个个独立、可测试的组件,那么代码复用的可能性就会大大增加,重构和调试也会变得更加容易。而且,通过检查测试结果,我们可以更好地了解被测试组件的行为,从而利用这些信息来编写设计文档。

  ​然而,有些人可能不清楚如何对 Vue.js 进行测试。本文主要介绍的是对 Vue.js 组件进行单元测试,确保每个组件都能按照预期正确运行。具体来说,我们会检查组件是否能正确处理 props,比如传递的 props 是否能按预期显示在浏览器上。同时,我们还会测试事件处理,例如点击事件是否能在浏览器上产生预期的效果。

1 创建测试环境

https://jestjs.io/zh-Hans/docs/getting-started

导入@vue/test-utils与jest需要的组件。

npm init vite@latest vue-jest
npm install --save-dev @vue/test-utils
npm install --save-dev jest
npm install --save-dev @vue/vue3-jest

npm install --save-dev babel-jest
npm install --save-dev @babel/core
npm install --save-dev @babel/preset-env
npm install --save-dev @vue/babel-preset-app or @vue/cli-plugin-babel
npm install --save-dev jest-environment-jsdom
package.json 文件中
```
"scripts": {
    "test": "jest"
}
```
最后,运行测试:
```
npm run test

Vue测试功能需要使用的以下几种基础组件

1 @vue/test-utils Vue.js 的官方测试实用程序库,用于vue脚本测试。官网地址https://test-utils.vuejs.org/

2 jest 是现在主流的JavaScript 测试框架。 https://jestjs.io

3 vue/vue3-jest Vue 单文件组件的 Jest 转换器。是一个基于jest的Vue.js测试框架,它可以帮助开发者简化Vue单元测试的操作,它提供了一系列的Vue特定的模拟器和matchers,可以帮助开发者更加容易地测试Vue组件,并且可以更好地支持Vue3的特性。

2 创建第一个测试程序
  ​安装完成后,test.spec.js 文件会自动保存在 tests/unit 文件夹中。这意味着您可以立即进行测试,无需等待安装完成。虽然在本文档中,我们不会使用默认编写的 test.spec.js 文件中的代码,但为了逐步加深对测试的理解,我们将首先使用 test.spec.js 进行测试。

Jest 会自动检测和测试以 .spec.js.test.js 结尾的文件。这两种文件都是 Jest 的测试文件,用于编写测试用例。

  • .spec.js

  • .test.js

test('2+2=4', () => {
    expect(2 + 2).toBe(4);
});

  ​在编写测试用例时,我们通常会在测试函数的第一个参数中描述测试的目标。这样做可以帮助我们更好地理解测试的内容,即使在未来回顾这些测试时也是如此。测试实际上将在第二个参数的函数中进行。

在测试过程中,我们需要进行断言以确保代码的行为符合预期。断言通过使用 expect 函数并为其参数指定一个值来进行。例如,如果我们想要测试 2+2 的结果是否为 4,我们就可以在 toBe 函数中指定值 4,并将其与 expect 函数中的加法运算结果进行比较。

toBe 函数是 Jest 提供的匹配器函数之一,它用于检查 expect 函数中指定的值是否与 toBe 函数中指定的值相匹配。在大多数常规测试中,我们会使用 expecttoBe 来验证两个值是否一致。

如果你想了解 Jest 中其他匹配器的使用方法,可以访问 Jest 的官方文档:https://jestjs.io/zh-Hans/docs/using-matchers

npm run test

> vue-jest@0.0.0 test
> jest

 PASS  src/test.spec.js
  √ 2+2=4 (7 ms)
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.973 s
Ran all test suites.

Jest中还存在各种其他匹配器功能。稍后我们可以更改条件以将 expect 的值与 matchers 函数相匹配,使用 matchers 函数而不是 toBe 函数来进行对比。

它是使用 test 函数编写的,但我们也可以使用 it 函数代替 test 函数。使用哪一个都没有关系。

it('2+2=4', () => {
    expect(2 + 2).toBe(4);
});

更新 test.spec.js 文件后,可以通过在命令行上运行 npm run test:unit 来运行测试。

查看npm run test:unit的执行消息,可以看到消息中对测试函数第一个参数二加二等于四的测试内容的描述。如果显示PASS,则表示本次测试成功。

如果在更改后执行 npm run test:unit ,则可以检查执行消息为 FAIL 而不是 PASS。您还可以从执行消息中看到,预期为 4 (Expected: 4) 的值包含 3 (Received: 3)。它还会提示测试的哪一部分有错误,而不仅仅是测试的通过或失败。

it('2+2=4', () => {
    expect(2 + 2).toBe(5);
});
npm run test      
> vue_typescript_lint@0.0.0 test
> jest
 FAIL  src/tests/test.spec.js
  × 2+2=4 (7 ms)2+2=4
    expect(received).toBe(expected) // Object.is equality
    Expected: 5
    Received: 4
      1 |
      2 | it('2+2=4', () => {
    > 3 |     expect(2 + 2).toBe(5);
        |                   ^
      4 | });

      at Object.toBe (src/tests/test.spec.js:3:19)
Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        1.102 s
Ran all test suites.

2 Jest 测试 Vue组件

  ​通过前面的学习,我们已经掌握了如何在项目中安装和使用 Jest。但是,我们的目标是测试 Vue.js 组件,这才是我们使用 Jest 的初衷。因此,接下来我们将利用 test.spec.js 文件来编写测试代码。

为了完成 Vue 组件的测试,我们需要引入 Vue Test Utils 组件库中的 mount 测试函数。Vue Test Utils 是 Vue 官方提供的一套测试工具库,其中包含了所有用于测试 Vue.js 所需的函数。

通过使用 Vue Test Utils,我们可以更高效、更深入地测试 Vue.js 组件的行为和状态,从而确保它们能够按照我们的预期正确运行。

import { mount } from '@vue/test-utils';
test('2+2=4', () => {
    expect(2 + 2).toBe(4);
});

运行npm run test 命令,这个时候并没有出现测试成功的提示,而是出现了下面的解析错误提示。
在这里插入图片描述

  ​​ 这是因为 Jest 在 Node.js 环境中运行测试,默认不支持使用 import 语句。相反,它建议使用 require 语句来导入模块。为了解决这个问题,我们可以使用像 Babel 这样的工具来转译我们的 JavaScript 代码,将其中的 import 语句转换为 Node.js 可以理解的 require() 语句。这样,我们就可以在 Jest 测试代码中使用 import 语句了。

为了实现这个转换,我们需要引入 babel-jest 这个包,并将其配置为 Jest 的转译器。babel-jest 会将测试代码中的 import 语句转换成 Node.js 可以执行的代码。这样,我们就可以在测试中使用 import 语句来导入需要的模块了。

Babel官网地址 https://babeljs.io/

  • 安装babel-jest包 是一个用于在 Vue 3 中使用 Babel 的 Jest 测试框架。它可以帮助开发人员在 Vue 3 中使用 Babel 来编写测试代码,并且可以使用 Babel 来将测试代码转换为 JavaScript 代码。
  • 安装@babel/preset-env Babel解析编辑工具插件。
npm install --save-dev babel-jest
npm install --save-dev @babel/core
npm install --save-dev @babel/preset-env

在项目根目录中创建**.babelrc**文件,在文件中配置@babel/preset-env插件到测试环境中。

// .babelrc 
{ 
    "presets" :  [ "@babel/preset-env" ] 
}

我们在执行测试命令,可以看到我们测试通过,证明babel-jest组件将import语句转录成功。

npm run test
> vue-jest@0.0.0 test
> jest
 PASS  src/test.spec.js
  √ 2+2=4 (4 ms)
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.168 s
Ran all test suites.

  ​​ 上面我们导入Vue Test Utils中的测试函数mount成功,现在我们要使用mount函数来测试一下正式的vue模板是否能正常运行。我们在test.spec.js 文件中加入以Vue模板字符串,在使用mount函数验证这个Vue模板字符是否是一个标准的Vue组件。

import { mount } from '@vue/test-utils';
const App = {
  template:`<div>欢迎使用vue/jest</div> `
}
test("测试 Vue3 Component",function(){
  const wrapper = mount(App);
  console.log(wrapper.text())
})

运行npm run test 后会看到编辑器又出现了错误提示。
在这里插入图片描述

这个错误的原因是mount函数无法理解Vue组件中的template模板的 HTML 代码,解决这个错误关键是要样Jest能够理解Vue模板中的语法 。

上述错误背后的原因是,jest 无法理解和处理 .vue 文件!

  ​​ 在前面,我们已经导入了 @vue/vue3-jest 组件,现在是时候使用它了。我们需要在 Jest 测试框架中添加这个组件,并使用 @vue/vue3-jest 组件中的 .vue 文件转换器来解析 Vue 模板,以便 Jest 程序能够理解 .vue 文件中的代码。

为了实现这个目标,我们需要在 jest.config.js 文件中添加对 @vue/vue3-jest 组件的解析配置。通过配置 Jest 的转换器,我们可以让 Jest 理解和处理 .vue 文件中的代码。

// jest.config.js
module.exports = {
    transform: {
      "^.+\\.jsx?$": "babel-jest",
      '^.+\\.vue$' : '@vue/vue3-jest' , 
    },
 };

配置完成后,我们再次运行测试 npm run test 还是又新的错误出现。
在这里插入图片描述

  ​​ 这个错误信息是因为当前执行的代码上下文中未定义 document 对象。在 Web 浏览器中,通常会提供这个 DOM 对象树,但是在 Node.js 环境中运行的 Jest 测试程序中是没有这个 DOM 对象的。因此,我们需要在 Node.js 环境中模拟一个 DOM 对象,以便在 Jest 程序中进行测试使用。

为了解决这个问题,我们可以使用 jsdom 这个库来模拟一个 DOM 环境。jsdom 可以在 Node.js 环境中创建一个虚拟的 DOM 对象树,使得我们可以在 Jest 测试中使用类似于浏览器环境的 API,比如 document 对象。

下面我们通过安装 jsdom 包,并在 Jest 的配置文件中进行相应的配置,来实现在 Jest 中使用模拟的 DOM 环境进行测试。

jest-environment-jsdom 包是一个 Jest 测试环境,它使用 jsdom 模拟浏览器环境,使Jest 测试代码在运行时,可以引用到浏览器的 API 和 DOM 对象。

npm install --save-dev jest-environment-jsdom

安装完jest-environment-jsdom 包,后在jest.config.js文件中配置 jsdom 模拟浏览器到node运行环境中来。配置文件中testEnvironment属性设置jsdom在,表示jest以 js 语法进行测试。

module.exports = {
    testEnvironment: 'jsdom',
    testEnvironmentOptions: {
        customExportConditions: ["node", "node-addons"],
     },
    transform: {
        "^.+\\.jsx?$": "babel-jest",
        '^.+\\.vue$' : '@vue/vue3-jest' , 
      },
  };

配置成功后运行测试指令,这回终于看到vue组件模板测试通过。

npm run test
> vue-jest@0.0.0 test
> test
> jest
  console.log       
    欢迎使用vue/jest
      at Object.log (src/test.spec.js:7:11)
 PASS  src/test.spec.js
  √ 测试 Vue3 Component (78 ms)
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.796 s
Ran all test suites.

package.json文件中记录了vue使用jest测试所需要的组件。

  "devDependencies": {
    "@babel/preset-env": "^7.20.2",
    "@vitejs/plugin-vue": "^4.0.0",
    "@vue/test-utils": "^2.2.9",
    "@vue/vue3-jest": "^29.2.2",
    "babel-jest": "^29.4.1",
    "jest": "^29.4.1",
    "jest-environment-jsdom": "^29.4.1",
    "vite": "^4.0.0"
  }

vue组件导入测试

  ​​ 接下来,让我们使用vue文件组件而不是vue模板字符串进行测试。在src文件夹下中的App.vue文件里写入以下代码。

<script setup>
</script>
<div>欢迎使用vue/jest</div> 
<style scoped>
</style>

在 test.spec.js 文件中,导入 App.vue组件使用mount函数装入App.vue组件的对象。

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
test("测试 Vue3 Component",function(){
  const wrapper = mount(app);
  console.log(wrapper.text())
})

运行jest测试命令,看到运行测试成功并且测试通过。

npm run test
> vue-jest@0.0.0 test
> jest
  console.log
    欢迎使用vue/jest
      at Object.log (src/test.spec.js:6:11)
 PASS  src/test.spec.js
  √ 测试 Vue3 Component (58 ms)
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.263 s
Ran all test suites.

  ​​ 到目前为止,大家已经能够理解如何使用Jest测试文件进行测试了。对于第一次使用Jest测试Vue.js组件的人来说,应该能轻松掌握了Jest与Vue测试环境的搭建了,也知道如何测试Vue组件的单元测试。在实际的开发过程中会发现不同Vue版本中测试环境的搭建是有所不同的,大家要根据以后组件的升级自己就调整他们对应的组件兼容性。

3 Jest 中测试 Vue 应用组件

  ​​vue组件中不仅有模板标签中的 HTML,还会有各种元素属性,props、emit,slort,provide 和 inject ,数据与计算属性,反应函数等等内容,他们都可以成为我们测试的对象。

1 props 传递值测试

  ​​我们将进行一个示例来演示如何在测试代码中将 props 传递给 App 组件,并且让大家更好地理解 App 组件如何根据传入的 props 值生成相应的 HTML 字符串。我们需要修改 App.vue 中的代码。在脚本部分,我们可以设置一个名为 name 的属性,并将其类型设置为字符串(String),并传入我们想要测试的 props 值。

<script setup>
const props =defineProps({
  name: {
    type: String,
  }
});
</script>
<template>
<div>欢迎你 {{name}}</div> 
</template>
<style>
</style>

单元测试是用来测试每个组件的,因此需要在测试中传递 props,而不是从其他组件传递 props。

  ​​在 Vue Test Utils 文档中,对 mount 函数有详细的描述。您可以在第二个参数中,将除了 props 之外的内容作为挂载选项传递给组件。下面是一个示例,使用 mount 函数的第二个参数来传递字符串 ‘World’ 给 props 的 msg 属性.

  • props() 方法查询测试test对象中设置的 props 值。
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';

test("测试 Vue3 Component",function(){
  const test = mount(app,{
    props:{
      name: "韬哥"
    }
  });
  console.log(test.props());
  expect(test.text()).toBe('欢迎你 韬哥')
})

当运行测试时,World 字符串在 props 中传递,所以 App 组件的内容将是 Hello World。所以你可以通过考试。

 npm run test
> vue-jest@0.0.0 test
> jest
  console.log       
    { name: '韬哥' }
      at Object.log (src/test.spec.js:10:11)
 PASS  src/test.spec.js
  √ 测试 Vue3 Component (74 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.331 s
Ran all test suites.

2 数据对象值测试
  ​​在Vue组件中设置数据对象内容,我们可以在测试文件中tset.vm 属性获得到vue组件中设置的数据对象内容。在通过 expect().toBe() 方法进行测试。

  • Vue组件中的数据对象 使用 .vm获得

在 App.vue组件中设置一个dpetname 数据属性。

<script setup>
const props =defineProps({
  name: {
    type: String,
  }
});
let dpetname="部门一";
</script>
<template>
<div>欢迎你 {{name}}</div> 
</template>
<style>
</style>

测试文件内容

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
test("测试 Vue3 Component",function(){
  const test = mount(app,{
    props:{
      name: "韬哥"
    }
  });
expect(test.text()).toMatch('欢迎你');
expect(test.vm.dpetname).toMatch('部门一');
})

运行测试内容

npm run test
> vue-jest@0.0.0 test
> jest

  console.log       
    { name: '韬哥' }
      at Object.log (src/test.spec.js:10:11)
  console.log
    部门一
      at Object.log (src/test.spec.js:11:11)
 PASS  src/test.spec.js
 
  √ 测试 Vue3 Component (77 ms)
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.166 s
Ran all test suites.

3 computed计算属性

  ​​我们可以测试计算属性是否按预期工作。例如,您可以测试设置数据属性 name 的值是否由计算属性 upperCaseName 转换为大写。

<script setup>
import {computed} from "vue";
const props =defineProps({
  name: {
    type: String,
  }
});
//计算函数设置name 字符大写
const upperCaseName=computed(() => {
  return props.name.toUpperCase()
});
</script>
<template>
<div>欢迎你 {{upperCaseName}}</div> 
</template>
<style>
</style>
import { mount } from '@vue/test-utils';
import app from '../src/App.vue';

test("测试 Vue3 Component",function(){
  const test = mount(app,{
    props:{
      name: "zht"
    }
  });
  expect(test.text()).toMatch('欢迎你 ZHT');
})
npm run test
> vue-jest@0.0.0 test
> jest
 PASS  src/test.spec.js
  √ 测试 Vue3 Component (26 ms)
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.086 s
Ran all test suites.

4 Jest 中 describe 函数

  在编写测试代码时,我们可以在测试或 it 函数之外编写 describe 函数,用于组织多个测试函数。这样可以使测试代码更加清晰和易读。如果只有一个测试函数,describe 函数不是必需的,但如果要运行多个测试函数,可以将它们组合在一起。

在 describe 函数中,我们可以设置组件的名称作为第一个参数,用于描述要测试的内容。通过这样的设置,我们可以更好地理解每个测试函数的目的和作用。

举个例子,假设我们要测试一个名为 app 的组件。我们可以使用 describe 函数来描述该组件的测试内容。

在 describe 函数中,我们可以编写多个测试函数,比如一个 test 函数和一个 it 函数。每个测试函数都有自己的描述和测试逻辑。通过这样的组织方式,我们可以更好地管理和执行多个测试函数,并保持代码的简洁性和可读性。

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';

describe('app', () => {
  it("测试 Vue3 Component",function(){
    const test = mount(app,{
      props:{
        name: "zht"
      }
    });
    expect(test.text()).toMatch('欢迎你 ZHT');
  })
  test("测试 Vue3 Component",function(){
    const test = mount(app,{
      props:{
        name: "zht"
      }
    });
    expect(test.text()).toMatch('欢迎你 ZHT');
  })
});

如果任何一个测试用例失败,将显示以下内容。可以看到测试套件失败,因为 2 个测试用例中的 1 个用例失败。

npm run test
> vue-jest@0.0.0 test
> jest
 FAIL  src/test.spec.js
  app
    √ 测试 Vue3 Component (26 ms)
    × 测试 Vue3 Component (16 ms)
  ● app › 测试 Vue3 Component
    expect(received).toMatch(expected)
    Expected substring: "欢迎你 zht"
    Received string:    "欢迎你 ZHT"
      18 |       }
      19 |     });
    > 20 |     expect(test.text()).toMatch('欢迎你 zht');
         |                         ^
      21 |   })
      22 | });
      23 |
      at Object.toMatch (src/test.spec.js:20:25)
Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        3.136 s
Ran all test suites.
describe('app', () => {
  it("测试 Vue3 Component",function(){
    ......
    expect(test.text()).toMatch('欢迎你 ZHT');
  })
  test("测试 Vue3 Component",function(){
    ......
    expect(test.text()).toMatch('欢迎你 ZHT');
  })
});

当我运行测试时,我看到已经运行了两个测试并且两个测试都通过了。describe 函数也称为 Tes Suites,它也是执行消息中显示的测试单元。这次有两个测试成功了,所以一个Test Suite成功了,就代表两个测试用例Tests成功了。

npm run test
> vue-jest@0.0.0 test
> jest
 PASS  src/test.spec.js
  app
    √ 测试 Vue3 Component (25 ms)
    √ 测试 Vue3 Component (7 ms)
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        3 s
Ran all test suites.

describe only 只允行函数

如果只想运行describe中设置的一个测试函数(it function),可以在test后加上only,跳过其他测试函数,只运行指定的测试函数。

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
  it.only("测试 Vue3 Component",function(){
    const test = mount(app,{
      props:{
        name: "zht"
      }
    });
    expect(test.text()).toMatch('欢迎你 ZHT');
  })
  test("测试 Vue3 Component",function(){
    const test = mount(app,{
      props:{
        name: "zht"
      }
    });
    expect(test.text()).toMatch('欢迎你 ZHT');
  })
});

运行测试命令,可以看到describe函数中只运行了only方法。

npm run test
> vue-jest@0.0.0 test
> jest
 PASS  src/test.spec.js
  app
    √ 测试 Vue3 Component (25 ms)
    ○ skipped 测试 Vue3 Component
Test Suites: 1 passed, 1 total
Tests:       1 skipped, 1 passed, 2 total
Snapshots:   0 total
Time:        2.999 s
Ran all test suites.

5 Jest 测试 Vue 中的元素

  我们将了解如何使用 Wrapper 对象的 get、find、exists、isVisible 和 setData 方法来获得和设置Vue组件中的元素属性值,在操作这些属性值进行测试,也可以对Vue模板中的 v-if 条件指令进行测试。
  在 App.vue 文件中写入以下代码。在脚本中创建isname属性,在模板中的创建一个a元素,a元素中设置v-if指令将isname与它绑定,isname为true时显示”大家好“,为false时不显示”大家好“。在设置一个id为profile的a元素,我们在下面的测试中将获得这元素的内容。

<script setup>
let isname=true;
</script>
<template>
  <nav>
    <a id="profile" href="/profile">我是一个a属性</a>
    <a v-if="isname" id="isname" href="/isname">大家好</a>
  </nav>
</template>
<style>
</style>

  在test.spec.js测试文件中我们使用 mount 函数获取 Wapper 对象,在使用 Wrpper 对象的 get 方法获取指定ID元素的 DOMWrapper 对象,最后通过text 方法将DOMWrapper 元素的内容信息打印出来。

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';

describe('app', () => {
  it("测试 app Component",function(){
    const wrapper = mount(app);
    const profile = wrapper.get('#profile'); //DOMWrapper
    console.log(profile.text());
    const isname = wrapper.get('#isname'); //DOMWrapper
    console.log(isname.text());
  })
})

运行npm run test命令,看到控制台打印出来模板中profile与isname元素内容。

npm run test

> vue-jest@0.0.0 test
> jest

  console.log    
    我是一个a属性

      at Object.log (src/test.spec.js:8:13)

  console.log
    大家好

      at Object.log (src/test.spec.js:10:13)

 PASS  src/test.spec.js
  app
    √ 测试 app Component (189 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        8.622 s, estimated 9 s
Ran all test suites.

  不仅 get 方法可以获得指定ID元素的内容,find 方法也具有相同的功能可以获得元素的内容,两者都返回相同的 DOMWrapper。但是唯一不同的地方时,如果元素不存在get 方法会抛出错误,find方法会返回空值。

get 方法 与 find方法区别

  • get 如果元素不存在会抛出错误。
  • find 如果元素不存在不会抛出错误。

在App.vue文件代码中将isname设置为false,这样会使 v-if 指令将元素隐藏起来。然后我们在这种情况下进行测试看看会发生什么。

运行测试,get方法出现错误提示测试失败。

npm run test

> vue-jest@0.0.0 test
> jest

  console.log    
    我是一个a属性

      at Object.log (src/test.spec.js:8:13)

 FAIL  src/test.spec.js
  app
    × 测试 app Component (112 ms)

  ● app › 测试 app Component

    Unable to get #isname within: <nav><a id="profile" href="/profile">我是一个a属性</a>
      <!--v-if-->
    </nav>

       7 |     const profile = wrapper.find('#profile'); //DOMWrapper
       8 |     console.log(profile.text());
    >  9 |     const isname = wrapper.get('#isname'); //DOMWrapper
         |                            ^
      10 |     console.log(isname.text());
      11 |   })
      12 | })

      at VueWrapper.Object.<anonymous>.BaseWrapper.get (node_modules/@vue/test-utils/dist/vue-test-utils.cjs.js:7212:15)
      at Object.get (src/test.spec.js:9:28)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        10.196 s

1 setData方法

  setData 方法用于测试中设置vue组件中脚本里的变量属性值。如果在上面的测试代码中你使用 setData重新覆盖了 isname值,运行测试后get方法也会出现错误。

2 exists 方法
​  exists 方法的返回值只有 true 或 false。所有它需要配合toBe 方法一起使用来进行测试。在测试代码中使用find方法获得元素值,在使用exists对值内容进行判断。

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
  it("测试 app Component",function(){
    const wrapper = mount(app);
    const isname = wrapper.find('#isname');
    expect(isname.exists()).toBe(false)
  })
})

3 v-show
  让我们先重新回忆一下 v-show 和 v-if 指令的区别。在v-if中除了可以使用v-else之外,还有一个显示上的区别,v-if中的元素显示是使用javascript脚本控制的。在v-show的情况下,显示或不显示是由style属性的显示值控制的,当显示值为block表示显示,none表示隐藏。另一方面,v-if 只有在元素可见时才添加元素,如果隐藏则元素不存在。所以在v-show的隐藏模式下,测试wrapper对象使用get方法,也可以通过get方法获取元素并且不会报错。因为无论显示还是隐藏,元素本身都是存在于dom树中。

将 App.vue 文件中的 v-if 指令更改为 v-show 指令。

<script setup>
let isname=false;
</script>
<template>
  <nav>
    <a id="profile" href="/profile">我是一个a属性</a>
    <a v-show="isname" id="isname" href="/isname">大家好</a>
  </nav>
</template>
<style>
</style>

测试类中使用get方法,运行测试命令,控制台没有出现错误。

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app', () => {
  it("测试 app Component",function(){
    const wrapper = mount(app);
    const isname = wrapper.get('#isname');r
    expect(isname.exists()).toBe(true)
  })
})

6 Jest事件测试

  在Vue.js中,通过在各个地方设置事件来实现与用户的交互。我们将检查如何在事件中设置频繁使用的点击事件时进行测试。

如下更新 App.vue 文件。设置数据属性计数并将初始值设置为 0。给button元素添加点击事件,点击按钮时执行increment方法,将count的值加1。s

<script setup>
import { ref } from 'vue';//从 vue 中引入 ref 函数
const count = ref(0);
const oncount=()=>{
  count.value++;
}
</script>
<template>
    <p>数据 : {{ count }}</p>
    <button @click="oncount"></button>
</template>
<style>
</style>

1 trigger 触发方式

  在测试代码中,如果你第一次测试点击事件,可能不知道如何模拟按钮点击。下面是一种方法来模拟点击按钮。

首先,使用 get 方法(或 find 方法)获取按钮元素,并触发 DOM 元素的点击事件,这个里我们使用DOMwrapper函数获取按钮元素并触发事件 。例如:

const wrapper = mount(app);
wrapper.get('button').trigger('click');

接下来,通过检查包含特定文本的组件内容来验证点击后是否正确更新了状态。例如,如果希望验证组件内容包含 “Count is: 1”,可以使用 toContain 函数进行断言。

expect(wrapper.text()).toContain('Count is: 1');

  原因是在测试期间,当单击按钮时,DOM 不会立即更新。这就是为什么在使用 setData 方法时,如果没有使用异步函数(如 async/await),测试将失败。同样,在模拟点击按钮时,也需要使用异步函数。通过在测试函数前添加 async 关键字,并在触发按钮点击后使用 await 关键字,可以解决这个问题。

it('should update count when button is clicked', async () => {
  const wrapper = mount(app);
  await wrapper.get('button').trigger('click');
  expect(wrapper.text()).toContain('Count is: 1');
});

trigger 方法不仅适用于 click 事件,还适用于其他事件,如 submitkeyup。稍后我们将在表单测试中使用 submit 事件。虽然官方文档中描述了使用 nextTick 方法的两种方法,但建议不使用 nextTick,因为这样代码会更加简洁和清晰。

2 nextTick 更新 DOM

  NextTick 是从 vue 导入的,但是由于可以从 wrapper 对象的 vm 属性访问 Vue 实例,因此也可以使用 wrapper.vm 执行 nextTick。在这种情况下, 我们不需要从 vue 导入 nextTick

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app',  () => {
  it("测试 app Component", async function(){
    const wrapper = mount(app);
     wrapper.get('button').trigger('click');
     await wrapper.vm.$nextTick()
    console.log(wrapper.text());
    expect(wrapper.text()).toContain('数据 : 1')
  })
})

在编辑器中运行测试指令看到以下结果。

npm run test

> vue-jest@0.0.0 test
> jest

  console.log
    数据 : 1 

      at log (src/test.spec.js:9:13)

 PASS  src/test.spec.js
  app
    √ 测试 app Component (85 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.183 s
Ran all test suites.

3 beforeEach

  在测试代码中,可以使用 beforeEach 函数来初始化每个测试处理。这样,在每个测试运行之前,都会执行 beforeEach 中的代码。这对于在多个测试中共享相同的设置非常有用。

举个例子,假设在 Countup 测试中运行了两个测试函数。这两个测试函数都需要先运行 mount(App) 来创建组件的包装器。如果将 mount(App) 放在每个测试函数内部,代码会重复出现,不够简洁。为了避免重复代码,可以使用 beforeEach 函数,在每个测试运行之前,先运行一次 mount(App)

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app',  () => {
  let wrapper;
  beforeEach(() => {
    wrapper = mount(app)
  })
  it("click button count up", async () => {
    await wrapper.get('button').trigger('click')
    console.log(wrapper.text());
    expect(wrapper.text()).toContain('数据 : 1')
  })
  it("click button count up", async () => {
    await wrapper.get('button').trigger('click')
    expect(wrapper.text()).toContain('数据 : 1')
  })
})

在上面的示例中,我们使用 beforeEach 函数来初始化 wrapper 变量,然后在每个测试函数中使用该变量。这样可以避免重复代码,并确保每个测试都有一个新的包装器。

请注意,在定义 wrapper 变量时使用 let 而不是 const。如果使用 const,会导致错误,因为 const 值无法被覆盖。

除了 beforeEach 函数外,还有其他一些类似的函数可用于在测试运行之前或之后执行常见的处理。例如,如果您希望在每个测试之后执行一些常见的处理,可以使用 afterEach(() => {})。如果您有一些希望在每次测试之前只运行一次的共同操作,可以使用 beforeAll(() => {})

7 Jest 测试emit 事件

  我刚刚检查了如何测试 props,但与 props 相反,Vue.js 在将数据从子组件传递到父组件时使用 emit 事件。检查 emit 事件是如何测试的

<script setup>
const count = 0;
const oncount=()=>{
   this.count += 1;
   this.$emit('initCount',this.count)
}
</script>
<template>
    <p>数据 : {{ count }}</p>
    <button @click="oncount"></button>
</template>
<style>
</style>

当按钮被点击时,click事件执行increment方法,emit方法将事件名称为incrementCount的payload中设置的this.count值传递给父组件。

测试应该获得由 emit 触发的事件 incrementCount。可以通过包装对象的 emitted 方法获取 Emit 事件。将 App 组件的事件名称 incrementCount 指定为发出的参数。

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app',  () => {
  it("click button count up", async () => {
    const wrapper = mount(app);
    wrapper.get('button').trigger('click')
    console.log(wrapper.emitted('initCount'))
  })
})

测试

npm run test
> vue-jest@0.0.0 test
> jest
  console.log
    [ [ 0 ] ]

      at log (src/test.spec.js:8:13)

 PASS  src/test.spec.js
  app
    √ click button count up (79 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.031 s

this.count 的值存储在一个数组中,可以使用wrapper.emitted('incrementCount')[0][0]访问。

您可以使用 toBe 函数来检查从 emit 事件中获取的值。当我运行测试时,它通过了。

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app',  () => {
  it("click button count up", async () => {
    const wrapper = mount(app);
    wrapper.get('button').trigger('click')
    console.log(wrapper.emitted('initCount'))
    expect(wrapper.emitted('initCount')[0][0]).toBe(0)
  })
})

测试通过 count 变量测试成功。

npm run test

> vue-jest@0.0.0 test
> jest

  console.log
    [ [ 0 ] ]

      at log (src/test.spec.js:8:13)

 PASS  src/test.spec.js
  app
    √ click button count up (96 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.289 s

我们在App组件中emit传入多个值。

<script setup>
import { ref } from 'vue';//从 vue 中引入 ref 函数
const count = ref(0);
const emit = defineEmits();
const oncount=()=>{
      emit('initCount',count.value++,'测试字符串');
}
</script>
<template>
    <p>数据 : {{ count }}</p>
    <button @click="oncount"></button>
</template>
<style>
</style>

在那种情况下,在测试端,您可以像下面这样在数组中获取它。还要检查多次执行点击事件时的数据

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app',  () => {
  it("click button count up", async () => {
    const wrapper = mount(app);
    wrapper.get('button').trigger('click')
    wrapper.get('button').trigger('click')
    console.log(wrapper.emitted('initCount'))
    expect(wrapper.emitted('initCount')[0][0]).toBe(0)
  })
})

运行测试我们可以看到我们通过测试组件获得测试结果。

npm run test

> vue-jest@0.0.0 test
> jest

  console.log
    [ [ 0, '测试字符串' ], [ 1, '测试字符串' ] ]

      at log (src/test.spec.js:9:13)

 PASS  src/test.spec.js
  app
    √ click button count up (91 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total

  如下更新 App.vue 文件以查看如何测试输入表单。当您在只有一个输入元素的简单表单中单击“提交”按钮时,submitForm 方法由表单标记中设置的提交事件执行。在 submitForm 方法中,将保存在 input 元素中输入的值的数据属性的名称与 emit 事件提交的事件名称一起传递给父组件。

<script setup>
import { ref } from 'vue';//从 vue 中引入 ref 函数
const name = ref("");
const dept = ref("");
const emit = defineEmits();
const OnForm=()=>{
      emit('Onsubmit',{"name":name,"dept":dept});
}
</script>
<template>

<form @submit.prevent="OnForm">
    <input type="text" v-model="name" />
    <input type="text" v-model="dept" />
    <button type="submit">Submit</button>
  </form>
</template>
<style>
</style>

** 1 from表单提交验证**

  对于提交事件,可以像点击事件一样使用触发方法。这次我们同样使用emit事件,但与上次不同的是,我们为payload指定了一个对象。

通常,输入元素是由用户在浏览器上输入的。我不知道如何在测试代码中将值设置为 input 元素,所以我将首先检查该方法。

使用 setValue 方法将值设置为输入元素。由于这里只有一个input元素,所以在get方法中只指定了input,但是如果有多个input,则需要给input元素设置一个可以识别的属性,比如id。

import { mount } from '@vue/test-utils';
import app from '../src/App.vue';
describe('app',  () => {
  it("测试 from",() => {
    const wrapper = mount(app);
    const input = wrapper.get('input')
    input.setValue('zht')
    const input1 = wrapper.get('#dept').setValue('部门一')
    wrapper.trigger('submit')
    console.log(wrapper.emitted('Onsubmit'))
    expect(wrapper.emitted('Onsubmit')[0][0]).toEqual({
      name:"zht",dept:"部门一"
    })
  })
})

  当我运行测试时,console.log 显示在提交的事件中收到的有效负载。可以看到数组中有对象。使用匹配器函数的 toEqual 函数进行断言。您可以使用 toEqual 函数来检查数组数据是否匹配。当您运行测试时,您可以确认它通过(成功)。这是一个只有输入元素的简单表单,但我能够检查如何测试表单。

npm run test

> vue-jest@0.0.0 test
> jest

  console.log
    [ [ { name: 'zht', dept: '部门一' } ] ]

      at Object.log (src/test.spec.js:11:13)

 PASS  src/test.spec.js
  app
    √ 测试 from (101 ms)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1152636.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Ubuntu 系统使用进入,自动进入base虚拟环境解决最全】

项目场景&#xff1a; 在Ubuntu上安装完anaconda后&#xff0c;发现每次打开终端后都会自动进入到base的虚拟环境中去&#xff0c;虽然在这些环境下使用问题不大&#xff0c;但一些软件的安装在虚拟环境下有影响。每次使用conda deactivate退出也很麻烦。 问题描述 安装玩之…

软件测试这些基本类型你知道吗

关于软件测试的类型&#xff0c;从不同角度来讲&#xff0c;可以分很多种&#xff0c;有时候甚至觉得软件测试是人类创造出来的最复杂的职业。。。 对一些常见的测试类型做了一个基本的文档总结&#xff0c;有些测试类型在之前的基础知识里面已经有所介绍&#xff0c;这里就没…

【Python爬虫+可视化】解析小破站热门视频,看看播放量为啥会这么高!评论、弹幕主要围绕什么展开

大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 环境使用 Python 3.8 Pycharm 模块使用 import requests import csv import datetime import hashlib import time 一. 数据来源分析 明确需求 明确采集网站以及数…

Linux Spug自动化运维平台公网远程访问

文章目录 前言1. Docker安装Spug2 . 本地访问测试3. Linux 安装cpolar4. 配置Spug公网访问地址5. 公网远程访问Spug管理界面6. 固定Spug公网地址 前言 Spug 面向中小型企业设计的轻量级无 Agent 的自动化运维平台&#xff0c;整合了主机管理、主机批量执行、主机在线终端、文件…

Unity HoloLens 2 应用程序发布

设置3D 启动器画面&#xff0c;glb格式的模型 VS中可以直接生成所有大小的图标

C++:快速入门篇

C:.cpp(面向对象) C语音&#xff1a;.c(面向过程)是为了弥补C的不足 命名冲突&#xff1a; 1.写的跟库冲突 2.自己写的互相冲突 1.命名空间 在C/C中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存在于全局作用域中&#xff…

mysql扩展语句

&#xff08;一&#xff09;复制表和删除表 &#xff08;二&#xff09;临时表 &#xff08;三&#xff09;mysql的六种约束方式 主键约束 primary key 用于唯一标识表中的每一行&#xff0c;主键列的值必须是唯一而且不能为空&#xff0c;一个表只能有一个主键 外键约束 for…

mysql之语句

1、mysql的扩展语句 &#xff08;1&#xff09;创建表 if not exists yyy&#xff1a;这个表不存在才会创建 zerofill&#xff1a;自动补齐位置 primary key&#xff1a;当前表的主键&#xff0c;主键只能有一个&#xff0c;唯一且不能为空 auto_increment&#xff1a;表示…

Allegro172版本不显示Microvia间距规则的解决办法

Allegro172版本不显示Microvia间距规则的解决办法 在用Allegro进行PCB设计的时候,进行盲埋孔单板设计的时候,有时会使用到Microvia,当然就要对Microvia进行规则设置,如下图 Allegro166版本的时候,Microvia规则是一直存在的 但是当版本升级到了172的时候,会发现Microvia的…

【面试专题】并发编程篇①

&#x1f4c3;个人主页&#xff1a;个人主页 &#x1f525;系列专栏&#xff1a;Java面试专题 1.线程和进程的区别 线程和进程都是操作系统中的概念&#xff0c;它们的主要区别如下&#xff1a; 资源分配&#xff1a;进程是操作系统中的资源分配的基本单位&#xff0c;每个进程…

IDEA优雅自动生成类注释和快捷键生成方法注释

生成类注释 Preferences->Editor->File and Code Templates-> Includes ->File Header 注释模板&#xff1a; /*** Classname ${NAME}* Description ${description}* Date ${DATE} ${TIME}* Created by ZouLiPing*/生成方法和字段注释 查看IDEA自动配置java快捷…

Istio实战(十)-Envoy 请求解析(上)

前言 Envoy 是一款面向 Service Mesh 的高性能网络代理服务。它与应用程序并行运行,通过以平台无关的方式提供通用功能来抽象网络。当基础架构中的所有服务流量都通过 Envoy 网格时,通过一致的可观测性,很容易地查看问题区域,调整整体性能。 Envoy也是istio的核心组件之一…

使用cpufrequtils查看调整cpu频率及模式

使用cpufrequtils查看调整cpu频率及模式 cpufrequtils是一个查看和修改CPU频率GHz的工具 有些物理服务器使用默认频率进行运行&#xff0c;这时可以使用该工具进行就该CPU的核心频率 安装: apt install cpufrequtils yum install cpufrequtils 使用: # 查看全部核心详细信息…

1111111111111

一、集合 1.1 简介 集合主要分为两组&#xff08;单列集合、双列集合&#xff09;&#xff0c;Collection 接口有两个重要的子接口 List 和Set&#xff0c;它们的实现子类都是单列集合。Map 接口的实现子类是双列集合&#xff0c;存放的是 K-V 1.2 关系图 二、Collection 接口…

Shadow DOM API 的 ShadowRoot 接口支持挂载的 shadow DOM 元素仅有18个:

<article, aside, blockquote, body, div, footer, h1-h6, header, main, nav, p, section, span> 浏览器兼容性 Browser compatibility

配置OSPF的多区域

实验6&#xff1a;配置多区域OSPF 实验需求 实现OSPF多区域配置阐明OSPF的LSA的类型阐明OSPF引入外部路由的配置方法阐明向OSPF引入缺省路由的方法 实验拓扑 配置多区域OSPF如图1-16所示。 图1-16 配置多区域OSPF 实验步骤 [1] IP地址配置 R1的配置 <Huawei>system…

Apache Doris (四十九): Doris表结构变更-动态分区(1)

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录

动态规划14:一和零

动态规划14&#xff1a;一和零 题目 474. 一和零 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素&#xff0c;集合 x 是集合 y 的 子集 。 …

计算机网络 第五章传输层

文章目录 1 传输层的功能2 传输层两种协议&#xff1a;UDP和TCP3 端口和端口号4 UDP数据报特点和首部格式5 UDP校验6 TCP协议的特点7 TCP报文段首部格式 1 传输层的功能 2 传输层两种协议&#xff1a;UDP和TCP 3 端口和端口号 4 UDP数据报特点和首部格式 5 UDP校验 6 TCP协议的…

机器人的触发条件有什么区别,如何巧妙的使用

简介​ 维格机器人触发条件,分为3个,分别是: 有新表单提交时、有记录满足条件时、有新的记录创建时 。 看似3个,其实是能够满足我们非常多的使用场景。 本篇将先介绍3个条件的触发条件,然后再列举一些复杂的触发条件如何用现有的触发条件来满足 注意: 维格机器人所有的…