Vite2 自动化测试-e2e

Vite2 自动化测试-e2e

1 初始化

1.1 安装

js 复制代码
mkdir vite-test-e2e
cd vite-test-e2e
npm init -y

pnpm install vue
pnpm i vite @vitejs/plugin-vue -D
pnpm install @babel/core @babel/preset-env  typescript @babel/preset-typescript  -D
pnpm install jest ts-jest ts-node @types/node @types/jest babel-jest @vue/vue3-jest -D
pnpm install  @vue/test-utils@next jest-transform-stub -D
echo done

1.2 tsconfig.node.json

json 复制代码
{
  "compilerOptions": {
    "composite": true,
    "module": "esnext",
    "moduleResolution": "node",
    "skipLibCheck": true
  },
  "include": ["vite.config.ts"]
}

2.3 tsconfig.json

tsconfig.json

json 复制代码
{
  "compilerOptions": {
    "target": "esnext",
    "useDefineForClassFields": true,
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "skipLibCheck": true,
    "strictNullChecks": true,
    "noEmit": true,
    "noEmitOnError": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

1.4 vite.config.ts

vite.config.ts

js 复制代码
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { resolve } from "path";
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      "@": resolve("src"),
    },
  },
});

1.5 package.json

package.json

json 复制代码
{
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  }
}

1.6 index.html

index.html

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>

  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

1.7 .gitignore

.gitignore

js 复制代码
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

1.8 src/main.ts

src/main.ts

js 复制代码
import { createApp } from "vue";
import App from "./App.vue";

createApp(App).mount("#app");

1.9 src/env.d.ts

src/env.d.ts

js 复制代码
/// <reference types="vite/client" />

declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
  const component: DefineComponent<{}, {}, any>
  export default component
}

1.10 src/App.vue

src/App.vue

js 复制代码
<script setup lang="ts">
import TodoApp from './components/TodoApp.vue'
</script>

<template>
  <TodoApp/>
</template>

<style></style>

1.11 TodoApp.vue

src/components/TodoApp.vue

js 复制代码
<template>
  <img :src="logoUrl"/>
  <input data-test="newTodo" />
  <button data-test="addTodo">addTodo</button>
</template>
<script setup lang="ts">
import logoUrl from "@/assets/logo.png"
</script>
<style scoped>
img{
  width:50px;
}
</style>

2 添加单元测试

2.1 package.json

package.json

diff 复制代码
{
    "scripts": {
    "dev": "vite",
    "build": "vite build",
+   "test": "jest"
  },
}

2.2 src/sum.ts

src/sum.ts

js 复制代码
export default function (a: number, b: number) {
  return a + b;
}

2.3 添加sum方法的测试用例

src/sum.spec.ts

js 复制代码
import sum from "./sum";
it("test sum", () => {
  expect(sum(1, 2)).toBe(3);
});

2.4 babel.config.ts

babel.config.ts

js 复制代码
export default {
  presets: ["@babel/preset-env", "@babel/preset-typescript"],
};

2.5 jest.config.ts

jest.config.ts

js 复制代码
import type { Config } from "@jest/types";
const config: Config.InitialOptions = {
  transform: {
    "^.+\\.js$": "babel-jest",
    "^.+\\.ts$": "ts-jest",
  },
  testMatch: ["<rootDir>/src/**/*.spec.(t|j)s"],
  testEnvironment: "jsdom",
  transformIgnorePatterns: ["/node_modules/"],
};
export default config;

3 测试组件

3.1 添加 TodoApp组件的测试用例

src/components/TodoApp.spec.ts

js 复制代码
import { mount } from "@vue/test-utils";
import TodoApp from "./TodoApp.vue";

test("render todoApp", () => {
  const wrapper = mount(TodoApp);
  const addTodo = wrapper.get('[data-test="addTodo"]');
  expect(addTodo.text()).toBe("addTodo");
});

3.1 jest.config.ts

jest.config.ts

diff 复制代码
import type { Config } from '@jest/types';
const config: Config.InitialOptions = {
   transform: {
    "^.+\\.js$": "babel-jest",
    "^.+\\.ts$": "ts-jest",
+   // 配置.vue结尾的文件使用的测试库
+   "^.+\\.vue$": "@vue/vue3-jest",
+   // 其他文件类型的转换
+   ".+\\.(css|scss|png|jpg|svg)$": "jest-transform-stub"
  },
+ moduleNameMapper: {
+   "^@/(.*)$": "<rootDir>/src/$1"
+ },
  testMatch: ["<rootDir>/src/**/*.spec.(t|j)s"],
  testEnvironment: "jsdom",
  transformIgnorePatterns: ["/node_modules/"]
};
export default config;

4 代码覆盖率

4.1 package.json 添加代码覆盖率

diff 复制代码
{
    "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test": "jest",
+   "test:coverage": "jest --coverage"
  },
}

4.2 jest 配置添加代码覆盖率统计

jest.config.ts

diff 复制代码
import type { Config } from '@jest/types';
const config: Config.InitialOptions = {
  transform: {
    "^.+\\.js$": "babel-jest",
    "^.+\\.ts$": "ts-jest",
    "^.+\\.vue$": "@vue/vue3-jest",
    ".+\\.(css|scss|png|jpg|svg)$": "jest-transform-stub"
  },
  moduleNameMapper: {
    "^@/(.*)$": "<rootDir>/src/$1"
  },
  testMatch: ["<rootDir>/src/**/*.spec.(t|j)s"],
  testEnvironment: "jsdom",
+ transformIgnorePatterns: ["/node_modules/"],
+ coverageDirectory: "coverage",
+ coverageProvider: "v8",
+ collectCoverageFrom: ["src/**/*.{js,vue}", "!src/main.ts", "!src/App.vue"],
+ coverageThreshold: {
+   global: {
+     branches: 40,
+     functions: 80,
+     lines: 90,
+     statements: 80
+   }
+ }
};
export default config;

5 E2E 测试

5.1 安装

js 复制代码
pnpm install cypress -D
pnpm install @cypress/vue@next @cypress/vite-dev-server -D
echo done

5.2 TodoApp.vue

src/components/TodoApp.vue

diff 复制代码
<template>
+ <input data-test="newTodo" v-model="newTodo" />
+ <button data-test="addTodo" @click="addTodo">addTodo</button>
+ <ul class="todo-list">
+   <li v-for="todo in todoList">{{ todo.text }}</li>
+ </ul>
</template>
<script setup lang="ts">
+import { ref, reactive } from 'vue';
+interface Todo {
+  text: string;
+}
+const newTodo = ref('');
+const todoList = reactive<Array<Todo>>([]);
+const addTodo = () => {
+  todoList.push({ text: newTodo.value });
+  newTodo.value = '';
+}
</script>

5.3 添加TodoApp组件的 cypress 测试文件

src/components/TodoApp.cy.ts

js 复制代码
import { mount } from "@cypress/vue";
import TodoApp from "./TodoApp.vue";
describe("TodoApp", () => {
  it("render TodoApp", () => {
    mount(TodoApp);
    const text = "play";
    cy.get('[data-test="newTodo"]').type(text);
    cy.get('[data-test="addTodo"]').click();
    cy.get(".todo-list li")
      .should("have.length", 1)
      .last()
      .should("have.text", text);
  });
});

5.4 todoApp.spec.js

cypress/integration/1-getting-started/todoApp.spec.js

js 复制代码
/// <reference types="cypress" />
describe("TodoApp", () => {
  beforeEach(() => {
    cy.visit("http://127.0.0.1:3000");
  });
  it("can add new todo items", () => {
    const text = "play";
    cy.get('[data-test="newTodo"]').type(text);
    cy.get('[data-test="addTodo"]').click();
    cy.get(".todo-list li")
      .should("have.length", 1)
      .last()
      .should("have.text", text);
  });
});

5.5 plugins/index.js

cypress/plugins/index.js

js 复制代码
const { startDevServer } = require("@cypress/vite-dev-server");
module.exports = (on, config) => {
  on("dev-server:start", async (options) => startDevServer({ options }));
};

5.6 添加 cypress 配置文件

cypress.json

json 复制代码
{
  "component": {
    "testFiles": "**/*.cy.{js,ts,jsx,tsx}",
    "componentFolder": "src"
  }
}

5.7 package.json添加cypress e2e测试命令

package.json

diff 复制代码
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test": "jest",
    "test:coverage": "jest --coverage",
+   "test:e2e": "cypress open",
+   "test:ct": "cypress open-ct"
  },
}

执行下看看e2e测试结果:

bash 复制代码
yarn test:e2e

# npm run test:e2e

可以看到启动Cypress打开了一个新的无头浏览器窗口,这个窗其实是 Cypress Test Runner 开发的一个视窗,一般开发时我们会使用 cypress open 命令来启动 这个Test Runner 的窗口便于开发。

第二个命令 test:ct 表示支持开发过程热重启

5.8 index.d.ts

node_modules/cypress/types/index.d.ts

js 复制代码
// <reference path="./cypress-expect.d.ts" />

5.9 cypress-expect.d.ts 去除声明 expectassert

node_modules/cypress/types/cypress-expect.d.ts

js 复制代码
//declare const expect: Chai.ExpectStatic
//declare const assert: Chai.AssertStatic

6 组件测试的流程

  • 整个 e2e 测试 的过程包含 组件测试(component test) ,然后组件测试(component test) 包含 单元测试(unit test);
  • 单元测试(unit test) 通过后,再通过组件测试,最后通过 e2e test (端到端测试)

如下所示:

代码仓库

7.参考链接

相关推荐
耶啵奶膘28 分钟前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^2 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie3 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic3 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿3 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具4 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
qq_390161774 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test5 小时前
js下载excel示例demo
前端·javascript·excel
Yaml45 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事5 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro