|
|
|
|
@ -0,0 +1,162 @@
|
|
|
|
|
/**
|
|
|
|
|
* 生成紫云智能导税 PAD 客户端测试用例 Excel
|
|
|
|
|
* 运行: npx --yes --package=xlsx node scripts/generate-testcases.mjs
|
|
|
|
|
*/
|
|
|
|
|
import { createRequire } from 'module'
|
|
|
|
|
import { writeFileSync } from 'fs'
|
|
|
|
|
import { dirname, join } from 'path'
|
|
|
|
|
import { fileURLToPath } from 'url'
|
|
|
|
|
|
|
|
|
|
const require = createRequire(import.meta.url)
|
|
|
|
|
const XLSX = require('xlsx')
|
|
|
|
|
|
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
|
|
|
const rootDir = join(__dirname, '..')
|
|
|
|
|
|
|
|
|
|
const HEADERS = [
|
|
|
|
|
'用例编号',
|
|
|
|
|
'模块',
|
|
|
|
|
'功能点',
|
|
|
|
|
'用例标题',
|
|
|
|
|
'前置条件',
|
|
|
|
|
'测试步骤',
|
|
|
|
|
'预期结果',
|
|
|
|
|
'优先级',
|
|
|
|
|
'用例类型',
|
|
|
|
|
'关联接口/页面',
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
/** @type {string[][]} */
|
|
|
|
|
const cases = [
|
|
|
|
|
// ========== 登录与认证 ==========
|
|
|
|
|
['TC-001', '登录', '账号登录', '正确账号密码登录成功', '网络正常;后端 pad.auth 可用', '1. 打开应用进入登录页\n2. 输入有效用户名和密码\n3. 点击「登录」', '登录成功;Token 与用户信息写入本地;跳转智能导税首页', 'P0', '功能', 'pages/login/login.vue / pad.auth /login'],
|
|
|
|
|
['TC-002', '登录', '账号登录', '错误密码登录失败', '网络正常', '1. 输入正确用户名、错误密码\n2. 点击「登录」', '登录失败;Toast 提示错误信息;停留在登录页', 'P0', '功能', 'pad.auth /login'],
|
|
|
|
|
['TC-003', '登录', '账号登录', '用户名为空时无法登录', '在登录页', '1. 用户名留空,输入密码\n2. 点击「登录」', '提示校验失败或接口返回错误;不跳转首页', 'P1', '边界', 'pages/login/login.vue'],
|
|
|
|
|
['TC-004', '登录', '自动回填', '再次进入登录页自动回填账号密码', '曾成功登录过', '1. 退出登录\n2. 重新进入登录页', '用户名、密码自动回填上次登录信息', 'P2', '功能', 'login_username / login_password 本地存储'],
|
|
|
|
|
['TC-005', '登录', 'Token', '业务请求携带 Bearer Token', '已登录', '1. 进入任意需鉴权页面触发请求\n2. 抓包或查看网络日志', '请求头含 Authorization: Bearer {token};除登录外均走签名', 'P0', '安全', 'utils/request.js'],
|
|
|
|
|
['TC-006', '登录', 'Token 刷新', 'Token 过期后自动刷新', '已登录;access_token 过期', '1. 触发需鉴权接口\n2. 观察 401 处理', '自动用 refresh_token 刷新;刷新成功后重试原请求', 'P1', '功能', 'utils/request.js'],
|
|
|
|
|
|
|
|
|
|
// ========== 首页 ==========
|
|
|
|
|
['TC-010', '首页', '大厅概况', '首页指标正常展示', '已登录;pad.hallSystem 可用', '1. 进入智能导税首页\n2. 查看左侧指标卡片', '显示当前等候人数、今日预约、空闲窗口、空闲自助机等数据', 'P0', '功能', 'pages/index/index.vue / pad.hallSystem /overview/metrics'],
|
|
|
|
|
['TC-011', '首页', '大厅概况', '指标约 30 秒自动刷新', '停留在首页', '1. 记录当前指标值\n2. 等待约 30 秒', '指标数据自动重新拉取并更新', 'P2', '功能', 'pages/index/index.vue'],
|
|
|
|
|
['TC-012', '首页', '导航', '点击指标跳转大厅详情', '在首页', '1. 点击任意概况指标卡片', '跳转至大厅详情页 hallInfo', 'P1', '功能', 'pages/mod/hallInfo.vue'],
|
|
|
|
|
['TC-013', '首页', '功能入口', '预检取号入口跳转', '在首页', '1. 点击「预检取号」', '进入 pages/queue/index', 'P0', '功能', 'pages/queue/index.vue'],
|
|
|
|
|
['TC-014', '首页', '功能入口', '票号管理入口跳转', '在首页', '1. 点击「票号管理」', '进入 pages/table/ticket', 'P0', '功能', 'pages/table/ticket.vue'],
|
|
|
|
|
['TC-015', '首页', '功能入口', '信息推送入口跳转', '在首页', '1. 点击「信息推送」', '进入 pages/mod/pushMessage', 'P1', '功能', 'pages/mod/pushMessage.vue'],
|
|
|
|
|
['TC-016', '首页', '功能入口', '回签优先入口跳转', '在首页', '1. 点击「回签优先」', '进入 pages/mod/sign-priority', 'P1', '功能', 'pages/mod/sign-priority.vue'],
|
|
|
|
|
['TC-017', '首页', '用户区', '退出登录', '已登录', '1. 点击右上角用户头像\n2. 选择退出登录', '清除登录态;跳转登录页', 'P0', '功能', 'pages/index/index.vue'],
|
|
|
|
|
|
|
|
|
|
// ========== 预检取号 ==========
|
|
|
|
|
['TC-020', '预检取号', '列表查询', '默认加载核验记录', '已登录;有核验数据', '1. 进入预检取号页', '自动请求 verify/search;列表展示姓名、身份证(脱敏)、手机号(脱敏)、核验结果、核验时间', 'P0', '功能', 'pad.ticket /verify/search'],
|
|
|
|
|
['TC-021', '预检取号', '列表查询', '按姓名模糊查询', '在预检取号页', '1. 输入姓名关键字\n2. 点击「查询」', '返回匹配记录;分页信息正确', 'P0', '功能', 'searchTicketVerify'],
|
|
|
|
|
['TC-022', '预检取号', '列表查询', '按身份证模糊查询', '在预检取号页', '1. 输入身份证号片段\n2. 点击「查询」', '返回匹配记录', 'P1', '功能', 'searchTicketVerify'],
|
|
|
|
|
['TC-023', '预检取号', '列表查询', '按手机号模糊查询', '在预检取号页', '1. 输入手机号片段\n2. 点击「查询」', '返回匹配记录', 'P1', '功能', 'searchTicketVerify'],
|
|
|
|
|
['TC-024', '预检取号', '列表查询', '重置查询条件', '已填写查询条件', '1. 点击「重置」', '清空姓名/身份证/手机号;重新加载默认列表', 'P1', '功能', 'pages/queue/index.vue'],
|
|
|
|
|
['TC-025', '预检取号', '轮询刷新', '页面停留 15 秒自动刷新', '停留在预检取号页', '1. 进入页面后等待 15 秒', '列表自动重新请求;数据更新', 'P2', '功能', 'pages/queue/index.vue'],
|
|
|
|
|
['TC-026', '预检取号', '日期范围', '查询固定为当天至过去 3 天', '抓包或查看请求体', '1. 触发查询\n2. 检查 startDate/endDate', 'startDate 为 3 天前;endDate 为当天', 'P2', '功能', 'searchTicketVerify body'],
|
|
|
|
|
['TC-027', '预检取号', '分页', '翻页加载数据', '总记录数大于每页条数', '1. 点击分页下一页', '展示对应页数据;当前页码与总数正确', 'P1', '功能', 'uni-pagination'],
|
|
|
|
|
['TC-028', '预检取号', '脱敏展示', '身份证手机号脱敏', '列表有数据', '1. 查看列表身份证、手机号列', '中间位以 * 脱敏显示', 'P1', '安全', 'maskIdCard / maskPhone'],
|
|
|
|
|
['TC-029', '预检取号', '核验结果', '展示 baishuiResp 文案', '记录含核验说明', '1. 查看核验结果列', '显示后端返回的人脸比对等说明文字', 'P1', '功能', 'baishuiResp'],
|
|
|
|
|
['TC-030', '预检取号', '人脸照片', '有 faceImg 时显示查看照片按钮', '记录 faceImg 有值', '1. 查看核验结果列', '显示「查看照片」按钮;与文案同一行不换行', 'P1', 'UI', 'pages/queue/index.vue .face-cell'],
|
|
|
|
|
['TC-031', '预检取号', '人脸照片', '无 faceImg 时不显示按钮', '记录 faceImg 为空', '1. 查看该行', '仅显示核验文案;无查看照片按钮', 'P2', '边界', 'hasFaceImg'],
|
|
|
|
|
['TC-032', '预检取号', '人脸照片', '点击查看照片弹窗展示', '记录有 uid 且后端有照片', '1. 点击「查看照片」\n2. 等待加载', '弹窗展示人脸图;GET pad.ticket /face/image/{uid};使用 imageBase64', 'P0', '功能', 'getFaceImage'],
|
|
|
|
|
['TC-033', '预检取号', '人脸照片', '照片加载失败提示', '接口异常或无数据', '1. 点击「查看照片」', '显示加载失败或暂无照片;控制台有 face-image 日志', 'P1', '异常', 'utils/faceImage.js'],
|
|
|
|
|
['TC-034', '预检取号', '健康报告', '打开健康报告弹窗', '记录有身份证', '1. 点击「健康报告」', '请求 health-reopt/url;弹窗内嵌展示报告页面', 'P0', '功能', 'pad.business /health-reopt/url'],
|
|
|
|
|
['TC-035', '预检取号', '健康报告', '无身份证时健康报告按钮禁用', '记录 idCard 为空', '1. 查看操作列', '健康报告按钮 disabled', 'P2', '边界', 'pages/queue/index.vue'],
|
|
|
|
|
['TC-036', '预检取号', '取号', '选择业务类型取号成功', '有效核验记录', '1. 点击「取号」\n2. 选择业务类型', '调用 take 接口;提示票号、等候、窗口等信息;列表刷新', 'P0', '功能', 'pad.ticket /take'],
|
|
|
|
|
['TC-037', '预检取号', '取号', '无手机号时先补录再取号', '记录 phone 为空', '1. 点击「取号」\n2. 在弹窗输入手机号并确定\n3. 选择业务', '先弹出手机号补录;补录后正常取号', 'P0', '功能', 'confirmPhoneForTakeTicket'],
|
|
|
|
|
['TC-038', '预检取号', '预约签到', '预约签到确认', '记录有预约信息', '1. 点击「预约签到」\n2. 查看预约信息\n3. 确认签到', '展示姓名/身份证/手机号/时间段;签到成功提示', 'P1', '功能', 'pages/queue/index.vue'],
|
|
|
|
|
['TC-039', '预检取号', '空数据', '无记录时空状态', '查询无结果', '1. 输入不存在条件查询', '表格显示「暂无更多数据」', 'P2', '边界', 'uni-table emptyText'],
|
|
|
|
|
|
|
|
|
|
// ========== 业务选择取号 ==========
|
|
|
|
|
['TC-040', '业务选择', '业务列表', '展示可办业务网格', '从录入流程进入 business-select', '1. 进入业务选择页', '动态加载 pad.business /enabled 业务列表;展示图标与名称', 'P1', '功能', 'pages/queue/business-select.vue'],
|
|
|
|
|
['TC-041', '业务选择', '取号', '选择业务确认取号', '已录入纳税人信息', '1. 点击某业务\n2. 点击确认取号', '取号成功弹窗展示排队号、业务、等候、窗口等', 'P1', '功能', 'takeTicket'],
|
|
|
|
|
['TC-042', '业务选择', '导航', '返回修改', '在业务选择页', '1. 点击「返回修改」', '返回上一页修改信息', 'P2', '功能', 'business-select.vue'],
|
|
|
|
|
|
|
|
|
|
// ========== 票号管理 ==========
|
|
|
|
|
['TC-050', '票号管理', 'Tab 筛选', '企业/个人 Tab 切换', '进入票号管理', '1. 切换一级 Tab\n2. 切换二级状态 Tab', '列表按 Tab 条件刷新', 'P0', '功能', 'pages/table/ticket.vue'],
|
|
|
|
|
['TC-051', '票号管理', '筛选', '按日期时间筛选', '在票号管理页', '1. 选择日期时间范围\n2. 点击查询', '返回对应时间段票号', 'P1', '功能', 'pad.ticket /list'],
|
|
|
|
|
['TC-052', '票号管理', '筛选', '按业务类型/票号关键字筛选', '在票号管理页', '1. 设置筛选条件\n2. 查询', '列表符合筛选条件', 'P1', '功能', 'getTicket'],
|
|
|
|
|
['TC-053', '票号管理', '详情', '点击票号查看详情', '列表有数据', '1. 点击票号链接', '弹出票号详情', 'P1', '功能', 'showDetail'],
|
|
|
|
|
['TC-054', '票号管理', '导税', '导税操作', '等候中票号', '1. 执行导税相关操作', '跳转导税模块或完成导税流程', 'P1', '功能', 'pages/mod/guidance.vue'],
|
|
|
|
|
['TC-055', '票号管理', '优先呼叫', '优先呼叫确认', '支持优先呼叫的票号', '1. 点击优先呼叫\n2. 确认', '操作成功并刷新列表', 'P2', '功能', 'confirmPriorityCall'],
|
|
|
|
|
['TC-056', '票号管理', '健康报告', '票号管理查看健康报告', '票号关联纳税人', '1. 打开健康报告入口', '正常展示税务健康检查报告', 'P2', '功能', 'TaxHealthReport 组件'],
|
|
|
|
|
|
|
|
|
|
// ========== 今日进厅 / 今日预约 ==========
|
|
|
|
|
['TC-060', '今日进厅', '列表', '进厅数据查询与 Tab 筛选', '从入口进入 dailyEntry', '1. 切换状态 Tab\n2. 点击查询', '展示进厅统计数据列表', 'P2', '功能', 'pages/table/dailyEntry.vue / pad.hallSystem /list'],
|
|
|
|
|
['TC-061', '今日预约', '列表', '预约数据查询', '从入口进入 appointment', '1. 切换状态 Tab\n2. 查询', '展示预约列表;支持筛选', 'P2', '功能', 'pages/table/appointment.vue / pad.appointment /time-slots'],
|
|
|
|
|
|
|
|
|
|
// ========== 大厅详情 ==========
|
|
|
|
|
['TC-070', '大厅详情', '窗口监控', '窗口状态列表展示', '进入 hallInfo', '1. 查看人工窗口列表', '展示窗口名称、业务、当前票号、状态、等候人数', 'P0', '功能', 'pad.window /monitor/list'],
|
|
|
|
|
['TC-071', '大厅详情', '设备监控', '自助设备状态展示', '进入 hallInfo', '1. 查看自助办税设备区', '展示设备名称与状态(空闲/使用中/维护中)', 'P1', '功能', 'hallInfo.vue'],
|
|
|
|
|
['TC-072', '大厅详情', '刷新', '手动刷新监控数据', '在大厅详情页', '1. 点击刷新按钮', '重新拉取 monitor 数据并更新界面', 'P1', '功能', 'refreshMonitorList'],
|
|
|
|
|
['TC-073', '大厅详情', '窗口操作', '点击窗口弹窗与操作', '有窗口数据', '1. 点击某窗口\n2. 在弹窗执行操作', '弹出窗口详情;操作符合后端能力', 'P2', '功能', 'handleWindowClick'],
|
|
|
|
|
|
|
|
|
|
// ========== 大厅控制 ==========
|
|
|
|
|
['TC-080', '大厅控制', '参数列表', '系统参数表格展示', '进入 hallManagment', '1. 查看参数表格', '展示参数名称、Key、当前值', 'P0', '功能', 'pad.hallSystem /list'],
|
|
|
|
|
['TC-081', '大厅控制', '参数编辑', '修改参数值成功', '有可编辑参数', '1. 点击编辑\n2. 修改值\n3. 确认保存', '二次确认后 POST /value;列表自动刷新', 'P0', '功能', 'updateSysValue'],
|
|
|
|
|
['TC-082', '大厅控制', '参数编辑', 'Key 与名称只读', '打开编辑弹窗', '1. 查看编辑表单', 'Key、参数名称不可编辑;仅值可改', 'P2', 'UI', 'hallManagment.vue'],
|
|
|
|
|
['TC-083', '大厅控制', '参数编辑', '取消编辑不保存', '编辑弹窗打开', '1. 修改值后关闭弹窗', '不调用保存接口;列表不变', 'P2', '功能', 'closeEditPopup'],
|
|
|
|
|
|
|
|
|
|
// ========== 回签优先 ==========
|
|
|
|
|
['TC-090', '回签优先', '回签', '输入票号回签成功', '有效等候票号', '1. 输入票号\n2. 确认回签', '二次确认后调用 resume;成功提示', 'P0', '功能', 'pad.ticket /resume'],
|
|
|
|
|
['TC-091', '回签优先', '回签', '票号为空提示', '在回签 Tab', '1. 不输入票号点击回签', 'Toast「请输入票号」', 'P1', '边界', 'sign-priority.vue'],
|
|
|
|
|
['TC-092', '回签优先', '扫码', '扫码填充票号', '设备支持扫码', '1. 点击扫码\n2. 扫描有效二维码', '票号输入框自动填入扫描结果', 'P1', '功能', 'uni.scanCode'],
|
|
|
|
|
['TC-093', '回签优先', '优先取号', '选择业务优先取号', '在优先 Tab;业务列表已加载', '1. 点击某业务类型', '调用 create-jump;返回优先票号信息', 'P0', '功能', 'pad.ticket /create-jump'],
|
|
|
|
|
|
|
|
|
|
// ========== 信息推送 ==========
|
|
|
|
|
['TC-100', '信息推送', '语音呼叫', '发送语音呼叫', '在语音 Tab', '1. 输入票号与窗口\n2. 点击发送呼叫', '请求成功;Toast 提示', 'P1', '功能', 'pushMessage Tab0'],
|
|
|
|
|
['TC-101', '信息推送', '信息屏', '推送至同步屏/综合屏', '在信息屏 Tab', '1. 勾选目标屏\n2. 输入内容\n3. 推送', '推送成功;内容不超过 500 字', 'P1', '功能', 'pushMessage Tab1'],
|
|
|
|
|
['TC-102', '信息推送', '短信', '发送短信', '在短信 Tab', '1. 输入 11 位手机号与内容\n2. 发送', '发送成功或后端返回明确结果', 'P1', '功能', 'pushMessage Tab2'],
|
|
|
|
|
['TC-103', '信息推送', '短信', '手机号格式校验', '在短信 Tab', '1. 输入非法手机号\n2. 发送', '前端校验或后端拒绝并提示', 'P2', '边界', 'smsForm.phone maxlength=11'],
|
|
|
|
|
|
|
|
|
|
// ========== 小票模板 ==========
|
|
|
|
|
['TC-110', '小票模板', '加载', '进入 Tab 自动加载模板', '进入信息推送-小票模板 Tab', '1. 切换到第 4 个 Tab', 'GET pad.print /template;解析 sections 展示', 'P0', '功能', 'getPrintTemplate / parsePrintTemplate'],
|
|
|
|
|
['TC-111', '小票模板', '编辑', '修改 section 样式', '模板已加载', '1. 修改字号、对齐等样式\n2. 占位符 {{title}}/{{ticketNo}} 不可改文本', '样式可改;占位文本只读', 'P1', '功能', 'pushMessage.vue sections'],
|
|
|
|
|
['TC-112', '小票模板', '保存', '保存模板成功', '已修改模板', '1. 点击保存\n2. 确认', 'POST pad.print /template;body 含 cutPaper 与 sections;提示成功', 'P0', '功能', 'savePrintTemplate / buildPrintTemplateSaveBody'],
|
|
|
|
|
['TC-113', '小票模板', '保存', '保存失败签名或网关错误', '后端未注册或签名异常', '1. 点击保存', 'Toast 提示失败;控制台可见 traceId 与错误码', 'P1', '异常', 'pad.print POST /template'],
|
|
|
|
|
['TC-114', '小票模板', '刷新', '手动重新加载模板', '在小票模板 Tab', '1. 点击重新加载', '重新请求并覆盖当前编辑内容', 'P2', '功能', 'loadPrintTemplate'],
|
|
|
|
|
|
|
|
|
|
// ========== HTTP / 签名 / 通用 ==========
|
|
|
|
|
['TC-120', '请求层', '网关', '统一 POST /public 入口', '已登录业务请求', '1. 触发任意业务 API', '请求 URL 为公网 /public;body 含 tag、map、signature 等', 'P0', '接口', 'utils/request.js'],
|
|
|
|
|
['TC-121', '请求层', '签名', 'HMAC-SHA256 签名流程', '非 skipSign 请求', '1. 先调 pad.sign\n2. 再发业务请求', 'query/body 深拷贝排序后参与签名;含 timestamp、nonce', 'P0', '安全', 'sortKeysDeep / pad.sign'],
|
|
|
|
|
['TC-122', '请求层', '响应', 'code=200 视为成功', '接口正常', '1. 调用成功接口', 'resolve data;Toast 不报错', 'P0', '接口', 'handleResponse'],
|
|
|
|
|
['TC-123', '请求层', '响应', '业务失败 Toast 提示', '接口返回 code!=200', '1. 触发失败场景', 'uni.showToast 显示 msg;Promise reject', 'P1', '异常', 'handleResponse'],
|
|
|
|
|
['TC-124', '请求层', '响应', 'data 为 null 返回完整响应', '特定接口 data=null', '1. 调用该接口', '返回完整 response 对象而非 null', 'P2', '接口', 'handleResponse'],
|
|
|
|
|
['TC-125', '请求层', '追踪', '每次请求含 traceId', '任意请求', '1. 查看请求日志', '每次请求生成唯一 traceId 便于排查', 'P2', '可维护', 'utils/request.js'],
|
|
|
|
|
|
|
|
|
|
// ========== UI / 兼容 ==========
|
|
|
|
|
['TC-130', 'UI', '横屏', '页面横屏布局正常', 'PAD 横屏模式', '1. 浏览各主要页面', '布局无严重错位;globalStyle pageOrientation=landscape', 'P1', 'UI', 'pages.json'],
|
|
|
|
|
['TC-131', 'UI', '导航', 'TopDivBar 返回', '子页面', '1. 点击返回', '返回上一页或首页', 'P1', 'UI', 'TopDivBar.vue'],
|
|
|
|
|
['TC-132', '兼容', '多端', 'H5/Electron 人脸照片展示', 'Electron 或 H5 环境', '1. 查看人脸照片', '优先使用原生 img + Blob/dataUrl;图片正常显示', 'P1', '兼容', 'faceImage.js useNativeImg'],
|
|
|
|
|
['TC-133', '兼容', '多端', 'App 端人脸照片展示', 'Android/iOS App', '1. 查看人脸照片', 'base64ToTempFilePath 转本地路径后 image 组件展示', 'P1', '兼容', 'utils/faceImage.js'],
|
|
|
|
|
|
|
|
|
|
// ========== 网格员 / 预留 ==========
|
|
|
|
|
['TC-140', '网格员', '入口', '网格员入口可进入', '首页有网格员入口', '1. 点击网格员', '进入 manager 页面或预留提示', 'P3', '功能', 'pages/mod/manager.vue'],
|
|
|
|
|
['TC-141', '多合一', '预留', '多合一模块可访问', '有入口时', '1. 进入 multiInOne', '页面正常加载;查询等功能可用', 'P3', '功能', 'pages/mod/multiInOne.vue'],
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const sheetData = [HEADERS, ...cases]
|
|
|
|
|
const wb = XLSX.utils.book_new()
|
|
|
|
|
const ws = XLSX.utils.aoa_to_sheet(sheetData)
|
|
|
|
|
|
|
|
|
|
// 列宽
|
|
|
|
|
ws['!cols'] = [
|
|
|
|
|
{ wch: 10 },
|
|
|
|
|
{ wch: 12 },
|
|
|
|
|
{ wch: 12 },
|
|
|
|
|
{ wch: 28 },
|
|
|
|
|
{ wch: 24 },
|
|
|
|
|
{ wch: 40 },
|
|
|
|
|
{ wch: 36 },
|
|
|
|
|
{ wch: 8 },
|
|
|
|
|
{ wch: 10 },
|
|
|
|
|
{ wch: 32 },
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
XLSX.utils.book_append_sheet(wb, ws, '测试用例')
|
|
|
|
|
|
|
|
|
|
const outPath = join(rootDir, '测试用例-紫云智能导税.xlsx')
|
|
|
|
|
XLSX.writeFile(wb, outPath)
|
|
|
|
|
console.log('已生成:', outPath)
|
|
|
|
|
console.log('用例总数:', cases.length)
|