build / task (16.x, npm, macOS-latest) (push) Canceled after 0s
build / task (16.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, npm, windows-latest) (push) Canceled after 0s
build / task (16.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (16.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (16.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (16.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, yarn, windows-latest) (push) Canceled after 0s
build / task (18.x, npm, macOS-latest) (push) Canceled after 0s
build / task (18.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, npm, windows-latest) (push) Canceled after 0s
build / task (18.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (18.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (18.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (18.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, yarn, windows-latest) (push) Canceled after 0s
build / task (20.x, npm, macOS-latest) (push) Canceled after 0s
build / task (20.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, npm, windows-latest) (push) Canceled after 0s
build / task (20.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (20.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (20.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (20.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, yarn, windows-latest) (push) Canceled after 0s
132 lines
8.1 KiB
JavaScript
132 lines
8.1 KiB
JavaScript
const { test } = require("node:test")
|
|
const assert = require("node:assert/strict")
|
|
const fs = require("node:fs")
|
|
const path = require("node:path")
|
|
const ts = require("typescript")
|
|
const vue = require("vue")
|
|
const { parse, compileScript, compileTemplate } = require("@vue/compiler-sfc")
|
|
const root = path.join(__dirname, "../src")
|
|
|
|
function load(source, mocks, globals = {}) {
|
|
const compiled = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2021 } }).outputText
|
|
const mod = { exports: {} }
|
|
new Function("module", "exports", "require", ...Object.keys(globals), compiled)(mod, mod.exports,
|
|
key => key in mocks ? mocks[key] : require(key), ...Object.values(globals))
|
|
return mod.exports
|
|
}
|
|
|
|
for (const scene of ["cz", "jz"]) {
|
|
test(`${scene} 页面提交对应后台任务,固定筛选并保留进度和下载流程`, async () => {
|
|
const requests = [], progress = [], downloads = []
|
|
const submitted = { taskId: "a".repeat(32), redisKey: `wallet:export:${scene}`, status: "PENDING" }
|
|
const request = options => { requests.push(options); return Promise.resolve({ data: submitted }) }
|
|
const tasks = load(fs.readFileSync(path.join(root, "api/asyncTask.ts"), "utf8"), { "/@/utils/request": { default: request } })
|
|
const apis = {}
|
|
for (const api of ["wallet-manage", "wallet-transaction"]) {
|
|
apis[`/@/api/wallet/${api}`] = load(fs.readFileSync(path.join(root, `api/wallet/${api}.ts`), "utf8"), {
|
|
"/@/utils/request": { default: request }, "/@/api/asyncTask": tasks,
|
|
})
|
|
}
|
|
const hook = load(fs.readFileSync(path.join(root, "hooks/batchExport.ts"), "utf8"), {
|
|
vue, "/@/components/AsyncTaskProgress.vue": {},
|
|
"/@/hooks/message": { useMessage: () => ({ error: message => assert.fail(message) }) },
|
|
"/@/utils/exportDownload": { downloadExportFile: (...args) => downloads.push(args) },
|
|
})
|
|
const descriptor = parse(fs.readFileSync(path.join(root, `views/wallet/wallet-${scene}/index.vue`), "utf8")).descriptor
|
|
assert.deepEqual(compileTemplate({ source: descriptor.template.content, filename: `${scene}.vue`, id: scene }).errors, [])
|
|
const page = load(compileScript(descriptor, { id: scene }).content, {
|
|
...apis, vue, dayjs: { default: require("dayjs") },
|
|
"/@/components/AsyncTaskProgress.vue": {}, "/@/hooks/batchExport": hook,
|
|
"/@/hooks/table": { useTable: state => {
|
|
state.pagination = { current: 8, size: 10 }
|
|
return { getDataList() {}, tableStyle: {} }
|
|
} },
|
|
"/@/hooks/message": {}, "/@/hooks/dict": { useDict: () => ({}) },
|
|
"/@/utils/formatMoney": {}, "/@/api/admin/dept": {},
|
|
"/@/utils/formatTime": { formatDate: () => "2026-09" },
|
|
}, { ref: vue.ref, reactive: vue.reactive, defineAsyncComponent: vue.defineAsyncComponent, useRouter: () => ({ push() {} }) })
|
|
const state = page.default.setup({}, { expose() {} })
|
|
state.exportProgressRef.value = { startSubmitting: name => progress.push(name), start: value => progress.push(value), submissionFailed: message => assert.fail(message) }
|
|
Object.assign(state.state.queryForm, { current: 8, size: 10, userId: "123", deptIds: ["456"], walletTypeIdList: ["789"], isInclude: false })
|
|
Object.assign(state.state.queryForm, { bizType: "3", createTimeList: ["2026-09-01", "2026-09-30"], tagList: ["7"] })
|
|
const before = JSON.parse(JSON.stringify(state.state.queryForm))
|
|
const expected = { ...before }; delete expected.current; delete expected.size
|
|
await state.exportExcel()
|
|
assert.equal(requests.length, 1)
|
|
assert.equal(requests[0].url, `/wallet/wallet-transaction/export-${scene}-async`)
|
|
assert.equal(requests[0].method, "post")
|
|
assert.deepEqual(requests[0].data, expected)
|
|
assert.deepEqual(JSON.parse(JSON.stringify(state.state.queryForm)), before)
|
|
assert.equal(state.exportTaskConfig.progressUrl, "/wallet/async-task/progress")
|
|
assert.equal(state.exportTaskConfig.redisKey, submitted.redisKey)
|
|
assert.deepEqual(progress[1], submitted)
|
|
state.state.queryForm.deptIds.push("999")
|
|
assert.deepEqual(requests[0].data.deptIds, ["456"])
|
|
state.handleExportSuccess({ ...submitted, status: "SUCCESS", resultFileUrl: "https://files.example.com/export.xlsx", resultFileName: "原导出文件.xlsx" })
|
|
assert.deepEqual(downloads, [["https://files.example.com/export.xlsx", "原导出文件.xlsx"]])
|
|
})
|
|
}
|
|
|
|
test("用户钱包汇总导出沿用已应用的区间和筛选,分页和未提交的表单不进入后台任务", async () => {
|
|
const requests = [], progress = [], downloads = []
|
|
const submitted = { taskId: "b".repeat(32), redisKey: "wallet:export:qb-users", status: "PENDING" }
|
|
const request = options => {
|
|
requests.push(options)
|
|
return Promise.resolve(options.url.endsWith("/page-qb-users")
|
|
? { code: 0, data: { records: [], total: 100 } } : { data: submitted })
|
|
}
|
|
const tasks = load(fs.readFileSync(path.join(root, "api/asyncTask.ts"), "utf8"), { "/@/utils/request": { default: request } })
|
|
const api = load(fs.readFileSync(path.join(root, "api/wallet/wallet-manage.ts"), "utf8"), {
|
|
"/@/utils/request": { default: request }, "/@/api/asyncTask": tasks,
|
|
})
|
|
const message = { useMessage: () => ({ error: message => assert.fail(message) }) }
|
|
const users = load(fs.readFileSync(path.join(root, "views/wallet/wallet-qb/useWalletQbUsers.ts"), "utf8"), {
|
|
vue, "/@/api/wallet/wallet-manage": api, "/@/hooks/message": message,
|
|
"/@/utils/formatTime": { formatDate: () => "2026-11" },
|
|
})
|
|
const batch = load(fs.readFileSync(path.join(root, "hooks/batchExport.ts"), "utf8"), {
|
|
vue, "/@/components/AsyncTaskProgress.vue": {}, "/@/hooks/message": message,
|
|
"/@/utils/exportDownload": { downloadExportFile: (...args) => downloads.push(args) },
|
|
})
|
|
const descriptor = parse(fs.readFileSync(path.join(root, "views/wallet/wallet-qb/index.vue"), "utf8")).descriptor
|
|
const page = load(compileScript(descriptor, { id: "qb-users-export" }).content, {
|
|
vue, "./useWalletQbUsers": users, "/@/api/wallet/wallet-manage": api,
|
|
"/@/hooks/batchExport": batch, "/@/components/AsyncTaskProgress.vue": {},
|
|
"/@/hooks/message": message, "/@/hooks/dict": { useDict: () => ({}) },
|
|
"/@/utils/formatMoney": {}, "/@/utils/formatTime": { formatDate: () => "2026-11" },
|
|
}, { ref: vue.ref, reactive: vue.reactive, computed: vue.computed })
|
|
const renderer = vue.createRenderer({
|
|
createElement: () => ({}), createText: () => ({}), createComment: () => ({}),
|
|
setText() {}, setElementText() {}, patchProp() {}, insert() {}, remove() {}, parentNode: () => null, nextSibling: () => null,
|
|
})
|
|
let state
|
|
const app = renderer.createApp({ setup() { state = page.default.setup({}, { expose() {} }); return () => null } })
|
|
app.mount({})
|
|
try {
|
|
await new Promise(resolve => setImmediate(resolve))
|
|
state.exportProgressRef.value = { startSubmitting: name => progress.push(name), start: value => progress.push(value), submissionFailed: message => assert.fail(message) }
|
|
Object.assign(state.state.queryForm, { userId: "123", deptIds: ["456"], walletTypeIdList: ["789"], isInclude: false,
|
|
minBalanceYuan: "1000.01", maxBalanceYuan: "2000" })
|
|
await state.getDataList()
|
|
const expected = state.getAppliedQuery()
|
|
state.currentChangeHandle(8)
|
|
await new Promise(resolve => setImmediate(resolve))
|
|
Object.assign(state.state.queryForm, { minBalanceYuan: "0", walletRecordMonth: "2026-10" })
|
|
state.state.queryForm.deptIds.push("999")
|
|
await state.exportExcel()
|
|
const exported = requests.filter(request => request.url.endsWith("/export-qb-users-async"))
|
|
assert.equal(exported.length, 1)
|
|
assert.equal(exported[0].method, "post")
|
|
assert.deepEqual(exported[0].data, expected)
|
|
assert.equal(exported[0].data.minBalance, 100001)
|
|
assert.equal(exported[0].data.maxBalance, 200000)
|
|
assert.equal(exported[0].data.current, undefined)
|
|
assert.equal(exported[0].data.size, undefined)
|
|
assert.equal(state.exportTaskConfig.progressUrl, "/wallet/async-task/progress")
|
|
assert.equal(state.exportTaskConfig.redisKey, submitted.redisKey)
|
|
assert.deepEqual(progress[1], submitted)
|
|
state.handleExportSuccess({ ...submitted, status: "SUCCESS", resultFileUrl: "https://files.example.com/users.xlsx", resultFileName: "用户钱包余额.xlsx" })
|
|
assert.deepEqual(downloads, [["https://files.example.com/users.xlsx", "用户钱包余额.xlsx"]])
|
|
} finally { app.unmount() }
|
|
})
|