test(ui): 添加模型参数配置端到端测试
- 创建完整的端到端测试套件 - 添加4个测试场景,15个测试用例 - 创建测试计划和验证脚本 - 包含快速验证脚本,通过19项检查 测试覆盖: - 页面加载和显示 - 参数修改追踪 - 保存功能 - 边界情况
This commit is contained in:
18
ruoyi-ui/package.test.json
Normal file
18
ruoyi-ui/package.test.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "ruoyi-ui",
|
||||
"version": "3.9.1",
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service serve",
|
||||
"build:prod": "vue-cli-service build",
|
||||
"test:e2e": "mocha tests/e2e/**/*.test.js --require @babel/register --timeout 10000",
|
||||
"test:e2e:coverage": "nyc npm run test:e2e"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/register": "^7.22.15",
|
||||
"@vue/test-utils": "^1.3.6",
|
||||
"chai": "^4.3.7",
|
||||
"mocha": "^10.2.0",
|
||||
"nyc": "^15.1.0",
|
||||
"sinon": "^15.2.0"
|
||||
}
|
||||
}
|
||||
382
ruoyi-ui/tests/e2e/model-param-config.test.js
Normal file
382
ruoyi-ui/tests/e2e/model-param-config.test.js
Normal file
@@ -0,0 +1,382 @@
|
||||
/**
|
||||
* 模型参数配置端到端测试
|
||||
* 测试完整的用户操作流程:加载 → 修改 → 保存
|
||||
*/
|
||||
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { expect } from 'chai'
|
||||
import sinon from 'sinon'
|
||||
import ModelParam from '@/views/ccdi/modelParam/index.vue'
|
||||
import * as modelParamApi from '@/api/ccdi/modelParam'
|
||||
|
||||
describe('模型参数配置 - 端到端测试', () => {
|
||||
let wrapper
|
||||
let sandbox
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore()
|
||||
if (wrapper) {
|
||||
wrapper.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
describe('场景1: 页面加载和显示', () => {
|
||||
it('应该显示加载状态', async () => {
|
||||
// 模拟API延迟
|
||||
const loadStub = sandbox.stub(modelParamApi, 'listAllParams')
|
||||
.returns(new Promise(resolve => setTimeout(resolve, 100)))
|
||||
|
||||
wrapper = mount(ModelParam)
|
||||
|
||||
// 验证loading状态
|
||||
expect(wrapper.vm.loading).to.be.true
|
||||
expect(wrapper.find('.el-loading-mask').exists()).to.be.true
|
||||
})
|
||||
|
||||
it('应该成功加载所有模型参数', async () => {
|
||||
// Mock数据
|
||||
const mockData = {
|
||||
code: 200,
|
||||
data: {
|
||||
models: [
|
||||
{
|
||||
modelCode: 'LARGE_TRANSACTION',
|
||||
modelName: '大额交易模型',
|
||||
params: [
|
||||
{
|
||||
paramCode: 'THRESHOLD_AMOUNT',
|
||||
paramName: '单笔交易金额阈值',
|
||||
paramDesc: '单笔交易金额超过此值触发预警',
|
||||
paramValue: '50000',
|
||||
paramUnit: '元'
|
||||
},
|
||||
{
|
||||
paramCode: 'DAILY_LIMIT',
|
||||
paramName: '日累计金额阈值',
|
||||
paramDesc: '单日累计金额超过此值触发预警',
|
||||
paramValue: '100000',
|
||||
paramUnit: '元'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
modelCode: 'SUSPICIOUS_FOREIGN_EXCHANGE',
|
||||
modelName: '可疑外汇交易模型',
|
||||
params: [
|
||||
{
|
||||
paramCode: 'FOREIGN_AMOUNT',
|
||||
paramName: '外汇交易金额阈值',
|
||||
paramDesc: '外汇交易金额超过此值触发预警',
|
||||
paramValue: '10000',
|
||||
paramUnit: '美元'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
sandbox.stub(modelParamApi, 'listAllParams')
|
||||
.resolves(mockData)
|
||||
|
||||
wrapper = mount(ModelParam)
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
// 等待加载完成
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
|
||||
// 验证数据加载
|
||||
expect(wrapper.vm.loading).to.be.false
|
||||
expect(wrapper.vm.modelGroups).to.have.lengthOf(2)
|
||||
expect(wrapper.vm.modelGroups[0].modelCode).to.equal('LARGE_TRANSACTION')
|
||||
expect(wrapper.vm.modelGroups[1].modelCode).to.equal('SUSPICIOUS_FOREIGN_EXCHANGE')
|
||||
})
|
||||
|
||||
it('应该显示空状态提示当无数据时', async () => {
|
||||
sandbox.stub(modelParamApi, 'listAllParams')
|
||||
.resolves({ code: 200, data: { models: [] } })
|
||||
|
||||
wrapper = mount(ModelParam)
|
||||
await wrapper.vm.$nextTick()
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
|
||||
// 验证空状态
|
||||
expect(wrapper.vm.modelGroups).to.have.lengthOf(0)
|
||||
expect(wrapper.find('.empty-state').exists()).to.be.true
|
||||
expect(wrapper.text()).to.include('暂无参数配置数据')
|
||||
})
|
||||
|
||||
it('应该显示错误信息当加载失败时', async () => {
|
||||
const errorMsg = '网络请求失败'
|
||||
sandbox.stub(modelParamApi, 'listAllParams')
|
||||
.rejects(new Error(errorMsg))
|
||||
|
||||
const messageSpy = sandbox.spy()
|
||||
|
||||
wrapper = mount(ModelParam, {
|
||||
mocks: {
|
||||
$message: {
|
||||
error: messageSpy
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await wrapper.vm.$nextTick()
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
|
||||
// 验证错误处理
|
||||
expect(messageSpy.calledOnce).to.be.true
|
||||
expect(messageSpy.firstCall.args[0]).to.include('加载参数失败')
|
||||
})
|
||||
})
|
||||
|
||||
describe('场景2: 参数修改追踪', () => {
|
||||
beforeEach(async () => {
|
||||
const mockData = {
|
||||
code: 200,
|
||||
data: {
|
||||
models: [
|
||||
{
|
||||
modelCode: 'LARGE_TRANSACTION',
|
||||
modelName: '大额交易模型',
|
||||
params: [
|
||||
{
|
||||
paramCode: 'THRESHOLD_AMOUNT',
|
||||
paramName: '单笔交易金额阈值',
|
||||
paramValue: '50000',
|
||||
paramUnit: '元'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
sandbox.stub(modelParamApi, 'listAllParams')
|
||||
.resolves(mockData)
|
||||
|
||||
wrapper = mount(ModelParam)
|
||||
await wrapper.vm.$nextTick()
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
})
|
||||
|
||||
it('应该正确追踪单个参数修改', () => {
|
||||
const row = wrapper.vm.modelGroups[0].params[0]
|
||||
|
||||
// 修改参数
|
||||
wrapper.vm.markAsModified('LARGE_TRANSACTION', row)
|
||||
|
||||
// 验证修改记录
|
||||
expect(wrapper.vm.modifiedParams['LARGE_TRANSACTION']).to.exist
|
||||
expect(wrapper.vm.modifiedParams['LARGE_TRANSACTION'].has('THRESHOLD_AMOUNT')).to.be.true
|
||||
expect(wrapper.vm.modifiedCount).to.equal(1)
|
||||
})
|
||||
|
||||
it('应该正确追踪多个参数修改', () => {
|
||||
const row1 = wrapper.vm.modelGroups[0].params[0]
|
||||
|
||||
// 修改参数多次
|
||||
wrapper.vm.markAsModified('LARGE_TRANSACTION', row1)
|
||||
wrapper.vm.markAsModified('LARGE_TRANSACTION', row1) // 重复修改
|
||||
|
||||
// 验证只记录一次
|
||||
expect(wrapper.vm.modifiedCount).to.equal(1)
|
||||
})
|
||||
|
||||
it('应该正确计算修改数量', async () => {
|
||||
// 添加第二个参数
|
||||
wrapper.vm.modelGroups[0].params.push({
|
||||
paramCode: 'DAILY_LIMIT',
|
||||
paramName: '日累计金额阈值',
|
||||
paramValue: '100000',
|
||||
paramUnit: '元'
|
||||
})
|
||||
|
||||
const row1 = wrapper.vm.modelGroups[0].params[0]
|
||||
const row2 = wrapper.vm.modelGroups[0].params[1]
|
||||
|
||||
// 修改两个不同参数
|
||||
wrapper.vm.markAsModified('LARGE_TRANSACTION', row1)
|
||||
wrapper.vm.markAsModified('LARGE_TRANSACTION', row2)
|
||||
|
||||
// 验证修改数量
|
||||
expect(wrapper.vm.modifiedCount).to.equal(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('场景3: 保存功能', () => {
|
||||
beforeEach(async () => {
|
||||
const mockData = {
|
||||
code: 200,
|
||||
data: {
|
||||
models: [
|
||||
{
|
||||
modelCode: 'LARGE_TRANSACTION',
|
||||
modelName: '大额交易模型',
|
||||
params: [
|
||||
{
|
||||
paramCode: 'THRESHOLD_AMOUNT',
|
||||
paramName: '单笔交易金额阈值',
|
||||
paramValue: '50000',
|
||||
paramUnit: '元'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
sandbox.stub(modelParamApi, 'listAllParams')
|
||||
.resolves(mockData)
|
||||
|
||||
wrapper = mount(ModelParam)
|
||||
await wrapper.vm.$nextTick()
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
})
|
||||
|
||||
it('应该拒绝保存当无修改时', async () => {
|
||||
const messageSpy = sandbox.spy()
|
||||
|
||||
wrapper.vm.$message = {
|
||||
info: messageSpy
|
||||
}
|
||||
|
||||
// 尝试保存(未修改)
|
||||
await wrapper.vm.handleSaveAll()
|
||||
|
||||
// 验证提示
|
||||
expect(messageSpy.calledOnce).to.be.true
|
||||
expect(messageSpy.firstCall.args[0]).to.include('没有需要保存的修改')
|
||||
})
|
||||
|
||||
it('应该成功保存修改', async () => {
|
||||
// Mock保存接口
|
||||
sandbox.stub(modelParamApi, 'saveAllParams')
|
||||
.resolves({ code: 200, msg: '操作成功' })
|
||||
|
||||
const messageSpy = sandbox.spy()
|
||||
wrapper.vm.$message = { success: messageSpy }
|
||||
wrapper.vm.$modal = { msgSuccess: messageSpy }
|
||||
|
||||
// 修改参数
|
||||
const row = wrapper.vm.modelGroups[0].params[0]
|
||||
row.paramValue = '60000'
|
||||
wrapper.vm.markAsModified('LARGE_TRANSACTION', row)
|
||||
|
||||
// 保存
|
||||
await wrapper.vm.handleSaveAll()
|
||||
|
||||
// 验证保存成功
|
||||
expect(messageSpy.called).to.be.true
|
||||
expect(wrapper.vm.modifiedCount).to.equal(0) // 清空修改记录
|
||||
})
|
||||
|
||||
it('应该显示错误当保存失败时', async () => {
|
||||
const errorMsg = '保存失败:参数值不能为空'
|
||||
sandbox.stub(modelParamApi, 'saveAllParams')
|
||||
.rejects({
|
||||
response: {
|
||||
data: { msg: '参数值不能为空' }
|
||||
}
|
||||
})
|
||||
|
||||
const messageSpy = sandbox.spy()
|
||||
wrapper.vm.$message = { error: messageSpy }
|
||||
|
||||
// 修改参数
|
||||
const row = wrapper.vm.modelGroups[0].params[0]
|
||||
wrapper.vm.markAsModified('LARGE_TRANSACTION', row)
|
||||
|
||||
// 尝试保存
|
||||
await wrapper.vm.handleSaveAll()
|
||||
|
||||
// 验证错误提示
|
||||
expect(messageSpy.calledOnce).to.be.true
|
||||
expect(messageSpy.firstCall.args[0]).to.include('保存失败')
|
||||
})
|
||||
|
||||
it('应该设置saving状态当保存中', async () => {
|
||||
// Mock延迟保存
|
||||
sandbox.stub(modelParamApi, 'saveAllParams')
|
||||
.returns(new Promise(resolve => setTimeout(() => resolve({ code: 200 }), 100)))
|
||||
|
||||
// 修改参数
|
||||
const row = wrapper.vm.modelGroups[0].params[0]
|
||||
wrapper.vm.markAsModified('LARGE_TRANSACTION', row)
|
||||
|
||||
// 开始保存(不等待)
|
||||
const savePromise = wrapper.vm.handleSaveAll()
|
||||
|
||||
// 验证saving状态
|
||||
expect(wrapper.vm.saving).to.be.true
|
||||
|
||||
// 等待保存完成
|
||||
await savePromise
|
||||
|
||||
// 验证saving状态恢复
|
||||
expect(wrapper.vm.saving).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
describe('场景4: 边界情况', () => {
|
||||
it('应该处理空projectId', async () => {
|
||||
const loadStub = sandbox.stub(modelParamApi, 'listAllParams')
|
||||
.resolves({ code: 200, data: { models: [] } })
|
||||
|
||||
wrapper = mount(ModelParam)
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
// 验证默认projectId为0
|
||||
expect(loadStub.firstCall.args[0]).to.deep.equal({ projectId: 0 })
|
||||
})
|
||||
|
||||
it('应该处理API返回异常数据结构', async () => {
|
||||
sandbox.stub(modelParamApi, 'listAllParams')
|
||||
.resolves({ code: 200 }) // 缺少data字段
|
||||
|
||||
wrapper = mount(ModelParam)
|
||||
await wrapper.vm.$nextTick()
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
|
||||
// 验证容错处理
|
||||
expect(wrapper.vm.modelGroups).to.deep.equal([])
|
||||
})
|
||||
|
||||
it('应该处理参数值为null或undefined', async () => {
|
||||
const mockData = {
|
||||
code: 200,
|
||||
data: {
|
||||
models: [
|
||||
{
|
||||
modelCode: 'TEST_MODEL',
|
||||
modelName: '测试模型',
|
||||
params: [
|
||||
{
|
||||
paramCode: 'TEST_PARAM',
|
||||
paramName: '测试参数',
|
||||
paramValue: null,
|
||||
paramUnit: '个'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
sandbox.stub(modelParamApi, 'listAllParams')
|
||||
.resolves(mockData)
|
||||
|
||||
wrapper = mount(ModelParam)
|
||||
await wrapper.vm.$nextTick()
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
|
||||
// 验证数据加载
|
||||
expect(wrapper.vm.modelGroups).to.have.lengthOf(1)
|
||||
expect(wrapper.vm.modelGroups[0].params[0].paramValue).to.be.null
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user