vue3-test-config
Version:
Vue3项目测试环境自动配置工具
949 lines (811 loc) • 28.2 kB
JavaScript
/*
* @Author: wangchao67 wangchao67@mychery.com
* @Date: 2025-06-09 14:08:14
* @LastEditors: wangchao67
* @LastEditTime: 2025-06-09 18:51:55
* @Description: file content
*/
import fs from "fs";
import path from "path";
import { execSync } from "child_process";
import readline from "readline";
import { fileURLToPath } from "url";
// 获取当前文件的目录路径(ES模块中没有__dirname)
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
class TestSetup {
constructor() {
// 支持指定项目路径或使用当前工作目录
this.projectRoot = process.argv[2] || process.cwd();
this.packageJsonPath = path.join(this.projectRoot, "package.json");
// 检查项目目录是否存在
if (!fs.existsSync(this.projectRoot)) {
console.error(`❌ 项目目录不存在: ${this.projectRoot}`);
process.exit(1);
}
// 检查是否为有效的Vue项目
if (!fs.existsSync(this.packageJsonPath)) {
console.error(`❌ 未找到package.json文件: ${this.packageJsonPath}`);
process.exit(1);
}
this.packageJson = this.readPackageJson();
this.isTypeScript = this.detectTypeScript();
this.scriptLanguage = null; // 用户选择的脚本语言
this.supportBoth = false; // 是否支持两种语言
console.log(`📍 项目路径: ${this.projectRoot}`);
}
// 创建readline接口
createReadlineInterface() {
return readline.createInterface({
input: process.stdin,
output: process.stdout,
});
}
// 询问用户选择脚本语言
async askScriptLanguage() {
const rl = this.createReadlineInterface();
console.log("\n🤔 请选择测试脚本的语言支持:");
console.log("1. JavaScript 脚本");
console.log("2. TypeScript 脚本");
console.log("3. 同时支持 JavaScript 和 TypeScript");
const answer = await new Promise((resolve) => {
rl.question("\n请选择 (1/2/3): ", (answer) => {
resolve(answer.trim());
});
});
rl.close();
switch (answer) {
case "1":
this.scriptLanguage = "js";
this.supportBoth = false;
console.log("✅ 选择:JavaScript 脚本");
break;
case "2":
this.scriptLanguage = "ts";
this.supportBoth = false;
console.log("✅ 选择:TypeScript 脚本");
break;
case "3":
this.scriptLanguage = "both";
this.supportBoth = true;
console.log("✅ 选择:同时支持 JavaScript 和 TypeScript");
break;
default:
console.log("⚠️ 无效选择,默认使用项目检测结果");
this.scriptLanguage = this.isTypeScript ? "ts" : "js";
this.supportBoth = false;
}
}
// 获取文件扩展名数组
getFileExtensions() {
if (this.supportBoth) {
return ["js", "ts"];
}
return [this.scriptLanguage || (this.isTypeScript ? "ts" : "js")];
}
// 读取package.json
readPackageJson() {
try {
const content = fs.readFileSync(this.packageJsonPath, "utf8");
return JSON.parse(content);
} catch (error) {
console.error("❌ 无法读取package.json文件:", error.message);
process.exit(1);
}
}
// 检测是否使用TypeScript
detectTypeScript() {
const hasTypeScript =
this.packageJson.dependencies?.typescript ||
this.packageJson.devDependencies?.typescript ||
fs.existsSync(path.join(this.projectRoot, "tsconfig.json"));
console.log(
`🔍 检测到项目使用: ${hasTypeScript ? "TypeScript" : "JavaScript"}`
);
return hasTypeScript;
}
// 检查包是否已安装
isPackageInstalled(packageName) {
return !!(
this.packageJson.dependencies?.[packageName] ||
this.packageJson.devDependencies?.[packageName]
);
}
// 检查vitest版本冲突,避免parseAstAsync错误
checkVitestVersionConflicts() {
const vitestVersion =
this.packageJson.devDependencies?.vitest ||
this.packageJson.dependencies?.vitest;
if (vitestVersion) {
console.log(`🔍 当前vitest版本: ${vitestVersion}`);
if (vitestVersion.includes("1.") || vitestVersion.includes("2.")) {
console.log("⚠️ 检测到旧版本vitest,可能导致parseAstAsync错误");
}
}
}
// 检查版本冲突的包
checkForVersionConflicts(targetPackages) {
const conflictingPackages = [];
targetPackages.forEach((pkg) => {
const [packageName, targetVersion] = pkg.split("@");
const actualPkgName =
packageName === "" ? "@" + pkg.split("@")[1] : packageName;
const installedVersion =
this.packageJson.devDependencies?.[actualPkgName] ||
this.packageJson.dependencies?.[actualPkgName];
if (installedVersion) {
// 检查是否是低版本的vitest相关包
if (
actualPkgName.includes("vitest") &&
(installedVersion.includes("1.") || installedVersion.includes("2."))
) {
conflictingPackages.push(actualPkgName);
}
}
});
return conflictingPackages;
}
// 卸载冲突的包
uninstallConflictingPackages(packages) {
try {
const packageList = packages.join(" ");
console.log(`🗑️ 正在卸载冲突包: ${packageList}`);
execSync(`npm uninstall ${packageList}`, {
stdio: "inherit",
cwd: this.projectRoot,
});
console.log(`✅ 卸载完成: ${packageList}`);
// 重新读取package.json
this.packageJson = this.readPackageJson();
} catch (error) {
console.error(`❌ 卸载失败: ${packages}`, error.message);
throw error;
}
}
// 安装包
installPackage(packages, isDev = true) {
const devFlag = isDev ? "--save-dev" : "--save";
const packageList = Array.isArray(packages) ? packages.join(" ") : packages;
try {
console.log(`📦 正在安装: ${packageList}`);
// 确保在正确的项目目录中执行npm命令
execSync(`npm install ${devFlag} ${packageList}`, {
stdio: "inherit",
cwd: this.projectRoot,
});
console.log(`✅ 安装完成: ${packageList}`);
} catch (error) {
console.error(`❌ 安装失败: ${packageList}`, error.message);
throw error;
}
}
// 创建目录
createDirectory(dirPath) {
const fullPath = path.isAbsolute(dirPath)
? dirPath
: path.join(this.projectRoot, dirPath);
if (!fs.existsSync(fullPath)) {
fs.mkdirSync(fullPath, { recursive: true });
console.log(`📁 创建目录: ${path.relative(this.projectRoot, fullPath)}`);
return true;
} else {
console.log(
`📁 目录已存在: ${path.relative(this.projectRoot, fullPath)}`
);
return false;
}
}
// 创建文件
createFile(filePath, content, overwrite = false) {
const fullPath = path.isAbsolute(filePath)
? filePath
: path.join(this.projectRoot, filePath);
if (!fs.existsSync(fullPath) || overwrite) {
fs.writeFileSync(fullPath, content);
console.log(`📄 创建文件: ${path.relative(this.projectRoot, fullPath)}`);
return true;
} else {
console.log(
`📄 文件已存在: ${path.relative(this.projectRoot, fullPath)}`
);
return false;
}
}
// 配置Vitest
setupVitest() {
console.log("\n🧪 配置Vitest...");
// 检查现有vitest版本,避免parseAstAsync错误
this.checkVitestVersionConflicts();
// 检查并安装vitest - 使用3.2.2版本
const vitestPackages = [
"vitest@^3.2.2",
"@vue/test-utils@^2.4.0",
"happy-dom@^12.0.0",
"@vitest/coverage-v8@^3.2.2",
"@vitest/ui@^3.2.2",
];
const missingPackages = vitestPackages.filter((pkg) => {
// 提取包名(去掉版本号)进行检查
const packageName =
pkg.split("@")[0] === "" ? "@" + pkg.split("@")[1] : pkg.split("@")[0];
return !this.isPackageInstalled(packageName);
});
// 检查是否存在版本冲突的包
const conflictingPackages = this.checkForVersionConflicts(vitestPackages);
if (conflictingPackages.length > 0) {
console.log("⚠️ 检测到版本冲突的包,需要先卸载:");
conflictingPackages.forEach((pkg) => console.log(` - ${pkg}`));
this.uninstallConflictingPackages(conflictingPackages);
}
if (missingPackages.length > 0 || conflictingPackages.length > 0) {
console.log(
"📋 将安装以下Vitest相关包(3.2.2版本,避免parseAstAsync错误):"
);
vitestPackages.forEach((pkg) => console.log(` - ${pkg}`));
this.installPackage(vitestPackages);
// 重新读取package.json以获取最新的依赖信息
this.packageJson = this.readPackageJson();
} else {
console.log("✅ Vitest相关包已安装且版本兼容");
}
// 创建vitest配置文件
const extensions = this.getFileExtensions();
extensions.forEach((ext) => {
const vitestConfig =
ext === "ts" ? this.getVitestConfigTS() : this.getVitestConfigJS();
const configFileName = `vitest.config.${ext}`;
this.createFile(configFileName, vitestConfig);
});
// 验证安装是否成功,预防parseAstAsync错误
this.verifyVitestInstallation();
}
// 验证vitest安装是否成功
verifyVitestInstallation() {
try {
console.log("\n🔍 验证Vitest安装...");
// 检查关键包的版本
const packageJson = this.readPackageJson();
const vitestVersion =
packageJson.devDependencies?.vitest || packageJson.dependencies?.vitest;
const coverageVersion =
packageJson.devDependencies?.["@vitest/coverage-v8"] ||
packageJson.dependencies?.["@vitest/coverage-v8"];
const uiVersion =
packageJson.devDependencies?.["@vitest/ui"] ||
packageJson.dependencies?.["@vitest/ui"];
if (vitestVersion && vitestVersion.includes("3.2")) {
console.log("✅ Vitest 3.2.x 版本安装成功,已避免parseAstAsync错误");
console.log(` vitest: ${vitestVersion}`);
if (coverageVersion)
console.log(` /coverage-v8: ${coverageVersion}`);
if (uiVersion) console.log(` /ui: ${uiVersion}`);
} else {
console.log("⚠️ 警告:Vitest版本可能不兼容,建议手动检查");
}
} catch (error) {
console.log("⚠️ 验证过程中出现问题,请手动检查安装结果");
}
}
// 配置Cypress
setupCypress() {
console.log("\n🚀 配置Cypress...");
// 检查并安装cypress
if (!this.isPackageInstalled("cypress")) {
this.installPackage("cypress");
// 重新读取package.json
this.packageJson = this.readPackageJson();
} else {
console.log("✅ Cypress已安装");
}
// 创建cypress配置文件
const extensions = this.getFileExtensions();
extensions.forEach((ext) => {
const cypressConfig = this.getCypressConfig(ext);
const configFileName = `cypress.config.${ext}`;
this.createFile(configFileName, cypressConfig);
});
// 创建cypress支持文件目录 - 修改为test/e2e/support
const cypressSupportDir = "test/e2e/support";
this.createDirectory(cypressSupportDir);
// 为每种语言创建支持文件
extensions.forEach((ext) => {
const supportFile =
ext === "ts" ? this.getCypressSupportTS() : this.getCypressSupportJS();
const supportFileName = `e2e.${ext}`;
this.createFile(
path.join(cypressSupportDir, supportFileName),
supportFile
);
// 创建cypress commands文件
const commandsFile = this.getCypressCommands();
const commandsFileName = `commands.${ext}`;
this.createFile(
path.join(cypressSupportDir, commandsFileName),
commandsFile
);
});
}
// 创建目录结构
createDirectoryStructure() {
console.log("\n📁 创建测试目录结构...");
this.createDirectory("test");
this.createDirectory("test/unit");
this.createDirectory("test/e2e");
this.createDirectory("test/e2e/support"); // 添加support目录
}
// 更新package.json脚本
updatePackageJsonScripts() {
console.log("\n📝 更新package.json脚本...");
const scripts = this.packageJson.scripts || {};
const newScripts = {
test: "vitest",
"test:ui": "vitest --ui",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage",
"cypress:open": "cypress open",
"cypress:run": "cypress run",
"test:e2e": "cypress run",
"test:e2e:open": "cypress open",
};
let hasChanges = false;
Object.entries(newScripts).forEach(([key, value]) => {
if (!scripts[key]) {
scripts[key] = value;
hasChanges = true;
console.log(`✅ 添加脚本: ${key}`);
} else {
console.log(`📄 脚本已存在: ${key}`);
}
});
if (hasChanges) {
this.packageJson.scripts = scripts;
fs.writeFileSync(
this.packageJsonPath,
JSON.stringify(this.packageJson, null, 2)
);
console.log("✅ package.json脚本更新完成");
}
}
// 创建示例测试文件
createDemoTests() {
console.log("\n📋 创建示例测试文件...");
const extensions = this.getFileExtensions();
extensions.forEach((ext) => {
// 创建单元测试示例
const unitTestContent =
ext === "ts" ? this.getUnitTestDemoTS() : this.getUnitTestDemoJS();
const unitTestPath = `test/unit/example.test.${ext}`;
this.createFile(unitTestPath, unitTestContent);
// 创建e2e测试示例
const e2eTestContent =
ext === "ts" ? this.getE2ETestDemoTS() : this.getE2ETestDemoJS();
const e2eTestPath = `test/e2e/example.cy.${ext}`;
this.createFile(e2eTestPath, e2eTestContent);
});
}
// 获取Vitest配置内容
getVitestConfigTS() {
// 始终支持.js和.ts文件,因为项目中可能混合使用
const includePattern = "test/unit/**/*.test.{js,ts}";
return `import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'
export default defineConfig({
plugins: [vue()],
test: {
globals: true,
environment: 'jsdom',
include: ['${includePattern}'],
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
exclude: [
'node_modules/',
'test/',
'cypress/',
'**/*.d.ts'
]
}
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
`;
}
getVitestConfigJS() {
// 始终支持.js和.ts文件,因为项目中可能混合使用
const includePattern = "test/unit/**/*.test.{js,ts}";
return `import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'
export default defineConfig({
plugins: [vue()],
test: {
globals: true,
environment: 'jsdom',
include: ['${includePattern}'],
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
exclude: [
'node_modules/',
'test/',
'cypress/',
'**/*.d.ts'
]
}
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
`;
}
// 获取Cypress配置内容 - 修复:统一使用ES模块语法
getCypressConfig(extension) {
const specPattern = this.supportBoth
? "test/e2e/**/*.cy.{js,ts}"
: `test/e2e/**/*.cy.${extension}`;
const supportFile = `test/e2e/support/e2e.${extension}`;
// 统一使用ES模块语法,适配Vue3+Vite项目
const config = `import { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
baseUrl: 'http://localhost:5173',
specPattern: '${specPattern}',
supportFile: '${supportFile}',
video: true,
screenshotOnRunFailure: true,
viewportWidth: 1280,
viewportHeight: 720,
defaultCommandTimeout: 8000,
setupNodeEvents(on, config) {
// 这里可以添加插件配置
},
},
})
`;
return config;
}
// 获取Cypress支持文件内容 - 确保使用ES模块语法
getCypressSupportTS() {
return `// Cypress支持文件
import './commands'
// 全局配置
Cypress.on('uncaught:exception', (err, runnable) => {
// 返回false来阻止Cypress失败测试
console.warn('Uncaught exception:', err.message)
return false
})
// 在每个测试前的全局配置
beforeEach(() => {
// 可以在这里添加全局的前置操作
})
`;
}
getCypressSupportJS() {
return `// Cypress支持文件
import './commands'
// 全局配置
Cypress.on('uncaught:exception', (err, runnable) => {
// 返回false来阻止Cypress失败测试
console.warn('Uncaught exception:', err.message)
return false
})
// 在每个测试前的全局配置
beforeEach(() => {
// 可以在这里添加全局的前置操作
})
`;
}
// 获取Cypress commands文件内容
getCypressCommands() {
return `// Cypress自定义命令
// 您可以在这里添加自定义的Cypress命令
// 示例:添加一个登录命令
// Cypress.Commands.add('login', (username, password) => {
// cy.visit('/login')
// cy.get('[data-testid="username"]').type(username)
// cy.get('[data-testid="password"]').type(password)
// cy.get('[data-testid="login-button"]').click()
// })
// 示例:检查元素是否可见
Cypress.Commands.add('checkVisible', (selector) => {
cy.get(selector).should('be.visible')
})
// 示例:等待元素出现
Cypress.Commands.add('waitForElement', (selector, timeout = 10000) => {
cy.get(selector, { timeout }).should('exist')
})
`;
}
// 获取单元测试示例
getUnitTestDemoTS() {
return `import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
// 示例测试:测试一个简单的Vue组件
describe('示例单元测试 (TypeScript)', () => {
it('应该进行基础的数学运算', () => {
expect(1 + 1).toBe(2)
})
it('应该测试字符串操作', () => {
const message: string = 'Hello Vue3'
expect(message).toContain('Vue3')
expect(message.length).toBe(10)
})
it('应该测试数组操作', () => {
const list: string[] = ['vue3', 'ant-design-vue', 'pinia', 'vue-router', 'vite']
expect(list).toHaveLength(5)
expect(list).toContain('vue3')
})
it('应该测试对象操作', () => {
interface User {
name: string
age: number
skills: string[]
}
const user: User = {
name: '张三',
age: 25,
skills: ['Vue3', 'TypeScript']
}
expect(user).toHaveProperty('name', '张三')
expect(user.skills).toContain('Vue3')
})
it('应该测试异步操作', async () => {
const promise = Promise.resolve('success')
await expect(promise).resolves.toBe('success')
})
})
// Vue组件测试示例(需要实际组件时启用)
/*
import YourComponent from '@/components/YourComponent.vue'
describe('Vue组件测试', () => {
it('应该渲染组件', () => {
const wrapper = mount(YourComponent, {
props: {
// 组件props
}
})
expect(wrapper.exists()).toBe(true)
expect(wrapper.find('[data-testid="component"]').exists()).toBe(true)
})
it('应该响应用户交互', async () => {
const wrapper = mount(YourComponent)
await wrapper.find('[data-testid="button"]').trigger('click')
expect(wrapper.emitted()).toHaveProperty('click')
})
})
*/
`;
}
getUnitTestDemoJS() {
return `import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
// 示例测试:基础功能测试
describe('示例单元测试 (JavaScript)', () => {
it('应该进行基础的数学运算', () => {
expect(1 + 1).toBe(2)
})
it('应该测试字符串操作', () => {
const message = 'Hello Vue3'
expect(message).toContain('Vue3')
expect(message.length).toBe(10)
})
it('应该测试数组操作', () => {
const list = ['vue3', 'ant-design-vue', 'pinia', 'vue-router', 'vite']
expect(list).toHaveLength(5)
expect(list).toContain('vue3')
})
it('应该测试对象操作', () => {
const user = {
name: '张三',
age: 25,
skills: ['Vue3', 'JavaScript']
}
expect(user).toHaveProperty('name', '张三')
expect(user.skills).toContain('Vue3')
})
it('应该测试异步操作', async () => {
const promise = Promise.resolve('success')
await expect(promise).resolves.toBe('success')
})
})
// Vue组件测试示例(需要实际组件时启用)
/*
import YourComponent from '@/components/YourComponent.vue'
describe('Vue组件测试', () => {
it('应该渲染组件', () => {
const wrapper = mount(YourComponent, {
props: {
// 组件props
}
})
expect(wrapper.exists()).toBe(true)
expect(wrapper.find('[data-testid="component"]').exists()).toBe(true)
})
it('应该响应用户交互', async () => {
const wrapper = mount(YourComponent)
await wrapper.find('[data-testid="button"]').trigger('click')
expect(wrapper.emitted()).toHaveProperty('click')
})
})
*/
`;
}
// 获取E2E测试示例
getE2ETestDemoTS() {
return `describe('vueDemo项目E2E测试 (TypeScript)', () => {
beforeEach(() => {
// 访问应用首页
cy.visit('/')
})
it('应该显示页面标题', () => {
cy.title().should('not.be.empty')
})
it('应该包含基本页面元素', () => {
// 检查页面是否包含某些基本元素
cy.get('body').should('be.visible')
})
it('应该能够进行基本的页面交互', () => {
// 示例:点击操作(根据您的实际页面调整选择器)
// cy.get('[data-testid="button"]').click()
// 示例:输入操作
// cy.get('[data-testid="input"]').type('测试文本')
// 示例:检查URL变化
// cy.url().should('include', '/expected-path')
// 当前示例:检查页面加载
cy.get('body').should('exist')
})
it('应该测试页面导航', () => {
// 示例:测试路由导航
// cy.get('[data-testid="nav-about"]').click()
// cy.url().should('include', '/about')
// 当前示例:检查页面标题
cy.get('head title').should('exist')
})
it('应该测试响应式设计', () => {
// 测试不同视口尺寸
cy.viewport(375, 667) // iPhone 6/7/8
cy.get('body').should('be.visible')
cy.viewport(1280, 720) // Desktop
cy.get('body').should('be.visible')
})
it('应该测试页面性能', () => {
// 检查页面加载时间
cy.window().its('performance').invoke('now').should('be.lessThan', 5000)
})
})
// 注意:这是一个基础示例
// 实际使用时,请根据您的应用页面结构调整测试选择器和操作
`;
}
getE2ETestDemoJS() {
return `describe('vueDemo项目E2E测试 (JavaScript)', () => {
beforeEach(() => {
// 访问应用首页
cy.visit('/')
})
it('应该显示页面标题', () => {
cy.title().should('not.be.empty')
})
it('应该包含基本页面元素', () => {
// 检查页面是否包含某些基本元素
cy.get('body').should('be.visible')
})
it('应该能够进行基本的页面交互', () => {
// 示例:点击操作(根据您的实际页面调整选择器)
// cy.get('[data-testid="button"]').click()
// 示例:输入操作
// cy.get('[data-testid="input"]').type('测试文本')
// 示例:检查URL变化
// cy.url().should('include', '/expected-path')
// 当前示例:检查页面加载
cy.get('body').should('exist')
})
it('应该测试页面导航', () => {
// 示例:测试路由导航
// cy.get('[data-testid="nav-about"]').click()
// cy.url().should('include', '/about')
// 当前示例:检查页面标题
cy.get('head title').should('exist')
})
it('应该测试响应式设计', () => {
// 测试不同视口尺寸
cy.viewport(375, 667) // iPhone 6/7/8
cy.get('body').should('be.visible')
cy.viewport(1280, 720) // Desktop
cy.get('body').should('be.visible')
})
it('应该测试页面性能', () => {
// 检查页面加载时间
cy.window().its('performance').invoke('now').should('be.lessThan', 5000)
})
})
// 注意:这是一个基础示例
// 实际使用时,请根据您的应用页面结构调整测试选择器和操作
`;
}
// 主要执行方法
async run() {
console.log("🚀 开始配置测试环境...\n");
console.log(`📁 目标项目: ${this.projectRoot}\n`);
try {
// 询问用户选择脚本语言
await this.askScriptLanguage();
// 检查是否为Vue项目
const isVueProject =
this.packageJson.dependencies?.vue ||
this.packageJson.devDependencies?.vue ||
this.packageJson.dependencies?.["@vitejs/plugin-vue"];
if (!isVueProject) {
console.warn("⚠️ 警告:这似乎不是一个Vue项目,但会继续配置测试环境");
}
// 1. 配置Vitest
this.setupVitest();
// 2. 配置Cypress
this.setupCypress();
// 3. 创建目录结构
this.createDirectoryStructure();
// 4. 更新package.json脚本
this.updatePackageJsonScripts();
// 5. 创建示例测试文件
this.createDemoTests();
console.log("\n✅ 测试环境配置完成!");
// 显示生成的文件
console.log("\n📄 生成的配置文件:");
const extensions = this.getFileExtensions();
extensions.forEach((ext) => {
console.log(` - vitest.config.${ext}`);
console.log(` - cypress.config.${ext}`);
});
console.log("\n📋 可用的测试命令:");
console.log(" npm run test # 运行单元测试(监听模式)");
console.log(" npm run test:ui # 打开Vitest UI界面");
console.log(" npm run test:run # 运行单元测试(单次)");
console.log(" npm run test:coverage # 运行单元测试并生成覆盖率报告");
console.log(" npm run cypress:open # 打开Cypress测试界面");
console.log(" npm run cypress:run # 运行E2E测试(无头模式)");
console.log(" npm run test:e2e # 运行E2E测试");
console.log(" npm run test:e2e:open # 打开E2E测试界面");
console.log("\n📁 目录结构:");
console.log(" test/");
console.log(" ├── unit/ # 单元测试文件");
console.log(" └── e2e/ # E2E测试文件");
console.log(" ├── support/ # Cypress支持文件");
if (this.supportBoth) {
console.log(" ├── *.cy.js # E2E测试用例(JS)");
console.log(" └── *.cy.ts # E2E测试用例(TS)");
} else {
console.log(
` └── *.cy.${this.scriptLanguage} # E2E测试用例`
);
}
console.log("\n💡 使用提示:");
console.log(" - 确保您的开发服务器运行在 http://localhost:5173");
console.log(" - 可以根据需要调整配置文件中的设置");
console.log(" - 已自动安装 @vue/test-utils 用于Vue组件测试");
console.log(" - 使用 data-testid 属性来为测试选择元素");
console.log(" - 运行 'npm run dev' 启动开发服务器后再进行E2E测试");
console.log(" - 所有测试文件统一放在 test/ 目录下");
if (this.supportBoth) {
console.log(" - 支持 JavaScript 和 TypeScript 两种测试脚本");
} else {
console.log(` - 使用 ${this.scriptLanguage.toUpperCase()} 测试脚本`);
}
} catch (error) {
console.error("\n❌ 配置过程中发生错误:", error.message);
console.error("堆栈信息:", error.stack);
process.exit(1);
}
}
}
// 执行配置
const setup = new TestSetup();
setup.run();