Files
2026-10-16 13:07:56 +08:00

250 lines
10 KiB
JavaScript

import AccountForm from '@/views/account/accountList/components/addOrExit.vue'
import RoleForm from '@/views/account/roleList/components/addOrExit.vue'
import AccountList from '@/views/account/accountList/index.vue'
import RoleList from '@/views/account/roleList/index.vue'
import Login from '@/views/login/index.vue'
import UploadImgPaste from '@/components/UploadImgPaste/index.vue'
import UploadImages from '@/components/UploadComicsImgArrByOrder/index.vue'
import { accAdd, accUp, accSavestatus, accList } from '@/api/account/accountList'
import { roleAdd, roleUp, getRoleList } from '@/api/account/roleList'
import { login, validateQR } from '@/api/login'
import { mediaUploadImg } from '@/api/components/UploadImgPaste'
import { upLoadFile } from '@/api/common'
jest.mock('@/api/account/accountList', () => ({
accAdd: jest.fn(), accUp: jest.fn(), accSavestatus: jest.fn(), accList: jest.fn()
}))
jest.mock('@/api/account/roleList', () => ({
roleAdd: jest.fn(), roleUp: jest.fn(), getRoleList: jest.fn()
}))
jest.mock('@/api/login', () => ({ login: jest.fn(), validateQR: jest.fn() }))
jest.mock('@/api/system/systemConfig', () => ({ getSyscfg: jest.fn() }))
jest.mock('@/api/components/UploadImgPaste', () => ({ mediaUploadImg: jest.fn() }))
jest.mock('@/api/common', () => ({ upLoadFile: jest.fn() }))
function context(component, state = {}, valid = true) {
return Object.assign({
$refs: {
ruleForm: { validate: callback => callback(valid) },
loginForm: { validate: callback => callback(valid) }
},
$message: Object.assign(jest.fn(), { success: jest.fn(), error: jest.fn() })
}, component.methods, state)
}
beforeEach(() => jest.resetAllMocks())
const forms = [
['新增账号', AccountForm, accAdd, 'submitForm', 'btnLoading', 'dialogFormVisible'],
['编辑账号', AccountForm, accUp, 'submitForm', 'btnLoading', 'dialogFormVisible'],
['账号状态', AccountForm, accSavestatus, 'submitForm', 'btnLoading', 'dialogFormVisible'],
['新增角色', RoleForm, roleAdd, 'onSubmitRole', 'disabled', 'dialogVisible'],
['编辑角色', RoleForm, roleUp, 'onSubmitRole', 'disabled', 'dialogVisible']
]
forms.forEach(([title, component, request, method, flag, visible]) => {
describe(title, () => {
const makeForm = (valid = true) => context(component, {
title, rowData: { acc: 'tester', userName: '测试账号' }, params: {},
[flag]: false, [visible]: true
}, valid)
const failures = [
['业务失败', () => Promise.resolve({ code: 500 })],
['网络失败', () => Promise.reject(new Error('network error'))],
['请求同步异常', () => { throw new Error('request error') }]
]
failures.forEach(([name, fail]) => {
it(`${name}后结束加载、保留表单并支持重试`, async() => {
const vm = makeForm()
request.mockImplementationOnce(fail).mockResolvedValueOnce({ code: 200 })
await vm[method]('ruleForm')
expect(vm[flag]).toBe(false)
expect(vm[visible]).toBe(true)
expect(vm.$message.success).not.toHaveBeenCalled()
await vm[method]('ruleForm')
expect(request).toHaveBeenCalledTimes(2)
expect(vm[flag]).toBe(false)
expect(vm[visible]).toBe(false)
expect(vm.$message.success).toHaveBeenCalledTimes(1)
})
})
it('请求未结束时保持加载并阻止重复提交', async() => {
const vm = makeForm()
let finish
request.mockImplementationOnce(() => new Promise(resolve => { finish = resolve }))
const pending = vm[method]('ruleForm')
expect(vm[flag]).toBe(true)
vm[method]('ruleForm')
expect(request).toHaveBeenCalledTimes(1)
finish({ code: 200 })
await pending
expect(vm[flag]).toBe(false)
})
it('校验失败时不请求也不进入加载', async() => {
const vm = makeForm(false)
await vm[method]('ruleForm')
expect(request).not.toHaveBeenCalled()
expect(vm[flag]).toBe(false)
})
})
})
describe('账号和角色列表', () => {
[
[AccountList, accList, 'getAccountData', { code: 200, data: { accRec: [], totalCount: 0 } }, 'accountData', 'accRec'],
[RoleList, getRoleList, 'getRoleData', { code: 200, data: { roleRecs: [], totalCount: 0 } }, 'list', 'roleRecs']
].forEach(([component, request, method, success, listKey, responseKey]) => {
it(`${method}接口失败后可再次加载`, async() => {
const vm = context(component, { loading: false, searchData: {}, param: {} })
let fail
request.mockImplementationOnce(() => new Promise((resolve, reject) => { fail = reject }))
.mockResolvedValueOnce(success)
const pending = vm[method]()
expect(vm.loading).toBe(true)
fail(new Error('network error'))
await pending
expect(vm.loading).toBe(false)
await vm[method]()
expect(request).toHaveBeenCalledTimes(2)
expect(vm.loading).toBe(false)
})
it(`${method}关闭弹框后静默更新数据并保留当前分页`, async() => {
const oldRows = [{ id: 1 }]
const newRows = [{ id: 2 }]
const vm = context(component, {
loading: false, [listKey]: oldRows,
dialogVisible: true, dialogFormVisible: true,
searchData: { pageNum: 3 }, param: { pageNum: 3 }
})
let finish
request.mockImplementationOnce(() => new Promise(resolve => { finish = resolve }))
const pending = vm.close()
expect(vm.loading).toBe(false)
expect(vm[listKey]).toBe(oldRows)
finish({ ...success, data: { ...success.data, [responseKey]: newRows } })
await pending
expect(vm.loading).toBe(false)
expect(vm[listKey]).toBe(newRows)
expect(vm.searchData.pageNum).toBe(3)
expect(vm.param.pageNum).toBe(3)
})
it(`${method}静默刷新失败时保留列表且不显示遮罩`, async() => {
const oldRows = [{ id: 1 }]
const vm = context(component, {
loading: false, [listKey]: oldRows, searchData: {}, param: {}
})
request.mockRejectedValueOnce(new Error('network error'))
const pending = vm[method]({ silent: true })
expect(vm.loading).toBe(false)
await pending
expect(vm.loading).toBe(false)
expect(vm[listKey]).toBe(oldRows)
})
const outcomes = ['成功', '失败']
outcomes.forEach(outcome => {
it(`${method}静默刷新${outcome}不会提前关闭普通请求遮罩`, async() => {
const vm = context(component, { loading: false, searchData: {}, param: {} })
let finishNormal
let finishSilent
request.mockImplementationOnce(() => new Promise(resolve => { finishNormal = resolve }))
.mockImplementationOnce(() => new Promise((resolve, reject) => {
finishSilent = outcome === '成功' ? resolve : reject
}))
const normal = vm[method]()
const silent = vm[method]({ silent: true })
expect(vm.loading).toBe(true)
finishSilent(outcome === '成功' ? success : new Error('network error'))
await silent
expect(vm.loading).toBe(true)
finishNormal(success)
await normal
expect(vm.loading).toBe(false)
})
})
})
})
it('登录接口失败后复位,业务失败后同样复位', async() => {
const vm = context(Login, {
loading: false, loginForm: { username: 'tester', password: 'password' }
})
login.mockRejectedValueOnce(new Error('network error'))
.mockResolvedValueOnce({ code: 4016 })
await vm.handleLogin()
expect(vm.loading).toBe(false)
await vm.handleLogin()
expect(vm.loading).toBe(false)
expect(login).toHaveBeenCalledTimes(2)
expect(vm.$message.error).toHaveBeenCalledWith('密码错误,请重新输入')
})
it('二维码验证请求失败后复位', async() => {
const vm = context(Login, { loading: false, loginForm: { username: 'tester' } })
validateQR.mockRejectedValueOnce(new Error('network error'))
await vm.handleQrValidate()
expect(vm.loading).toBe(false)
expect(login).not.toHaveBeenCalled()
})
it('二维码验证期间修改输入导致二次校验失败时仍释放加载状态', async() => {
const vm = context(Login, { loading: false, loginForm: { username: 'tester' } })
vm.$refs.loginForm.validate = jest.fn()
.mockImplementationOnce(callback => callback(true))
.mockImplementationOnce(callback => callback(false))
let finish
validateQR.mockImplementationOnce(() => new Promise(resolve => { finish = resolve }))
const pending = vm.handleQrValidate()
expect(vm.loading).toBe(true)
finish({ code: 200 })
await pending
expect(vm.loading).toBe(false)
expect(login).not.toHaveBeenCalled()
})
it('二维码验证后由登录请求保持加载并在登录失败时释放', async() => {
const vm = context(Login, {
loading: false, loginForm: { username: 'tester', password: 'password' }
})
validateQR.mockResolvedValueOnce({ code: 200 })
let fail
login.mockImplementationOnce(() => new Promise((resolve, reject) => { fail = reject }))
await vm.handleQrValidate()
expect(vm.loading).toBe(true)
fail(new Error('network error'))
await Promise.resolve()
expect(vm.loading).toBe(false)
})
it('粘贴图片上传失败后复位', async() => {
const vm = context(UploadImgPaste, { loading: false, file: new Blob(['image']) })
mediaUploadImg.mockRejectedValueOnce(new Error('network error'))
const pending = vm.uploadPlans()
expect(vm.loading).toBe(true)
await pending
expect(vm.loading).toBe(false)
})
it('批量图片上传失败后释放本地和父组件上传状态', async() => {
const vm = context(UploadImages, {
loading: false, fileList: [{ name: 'image.png', raw: new Blob(['image']) }],
locaImg: [], source: { cancel: jest.fn() },
$notify: { error: jest.fn() }, $emit: jest.fn()
})
upLoadFile.mockRejectedValueOnce(new Error('network error'))
const pending = vm.upLoad()
expect(vm.loading).toBe(true)
expect(vm.$emit).toHaveBeenCalledWith('setIsUploadIng', true)
await pending
expect(vm.loading).toBe(false)
expect(vm.$emit).toHaveBeenCalledWith('setIsUploadIng', false)
expect(vm.$notify.error).toHaveBeenCalledTimes(1)
})