Commit d14afcfe authored by liguangyu06's avatar liguangyu06
Browse files

将 spd-ui-verify 默认套件扩为完整基础管理,并改拉 temp。

parent 694b2f03
......@@ -112,7 +112,7 @@ pipeline {
parameters {
choice(
name: 'SUITE',
choices: ['full', 'nightly', 'smoke', 'login', 'center', 'dept', 'invoice', 'trace', 'consume', 'recon', 'cost', 'warn', 'pol', 'exc', 'ana', 'ops', 'reag', 'invoice-trace', 'recon-cost', 'vendor', 'admit', 'basic', 'surgery', 'warehouse', 'flow', 'extended', 'quarantine'],
choices: ['full', 'nightly', 'smoke', 'login', 'center', 'dept', 'invoice', 'trace', 'consume', 'recon', 'cost', 'warn', 'pol', 'exc', 'ana', 'ops', 'reag', 'invoice-trace', 'recon-cost', 'vendor', 'admit', 'basic', 'basic-core', 'surgery', 'warehouse', 'flow', 'deptm', 'iface', 'extended', 'quarantine'],
description: '执行方式(默认 full 全量回归,含 @full 全列排序)'
)
string(name: 'WORKERS', defaultValue: '3', description: '单进程内并行文件数(同一 spec 不拆开)')
......
// 日常验证专用流水线:默认 full 全量、WORKERS=2,超时 6 小时,不设定时、不发邮件;与夜间 SPD 任务分离。
// 日常验证专用流水线:默认 basic(基础管理)、WORKERS=2,超时 6 小时,不设定时、不发邮件;与夜间 SPD 任务分离。
// Jenkins 任务 Script Path 填 Jenkinsfile.verify
def runCi() {
......@@ -25,8 +25,8 @@ pipeline {
parameters {
choice(
name: 'SUITE',
choices: ['full', 'nightly', 'smoke', 'login', 'vendor', 'admit', 'basic', 'surgery', 'warehouse', 'flow', 'center', 'dept', 'invoice', 'trace', 'consume', 'recon', 'cost', 'warn', 'pol', 'exc', 'ana', 'ops', 'reag', 'invoice-trace', 'recon-cost', 'extended', 'quarantine'],
description: '默认 full 全量回归;可改 smoke / 单模块等'
choices: ['basic', 'basic-core', 'full', 'nightly', 'smoke', 'login', 'vendor', 'admit', 'surgery', 'warehouse', 'flow', 'deptm', 'iface', 'center', 'dept', 'invoice', 'trace', 'consume', 'recon', 'cost', 'warn', 'pol', 'exc', 'ana', 'ops', 'reag', 'invoice-trace', 'recon-cost', 'extended', 'quarantine'],
description: '默认 basic(基础管理全量);basic-core 仅用户/医院资料;可改 full / smoke / 其他单模块'
)
string(name: 'WORKERS', defaultValue: '2', description: '并行文件数,验证任务默认 2')
string(name: 'SHARDS', defaultValue: '1', description: '分片数,日常验证保持 1')
......
......@@ -38,7 +38,7 @@ Chromium 缓存在项目内 `.playwright-browsers/`(已 gitignore),与 `@p
| `smoke` | `npm run test:ci:smoke` | 报表与基础设置中已打 `@smoke` 的用例(含厂商、准入、基础管理、手术、库房、流程) |
| `nightly` | `npm run test:ci:nightly` | 主 spec 回归,排除 `@full` 全列排序 |
| `full` | `npm run test:ci:full` | 含全列排序,建议周末 |
| 模块 | `SUITE=center npm run test:ci` | `center` / `dept` / `vendor` / `admit` / `basic` / `surgery` / `warehouse` / `flow` 等 |
| 模块 | `SUITE=basic npm run test:ci` | `basic`(基础管理全量)/ `basic-core` / `vendor` / `admit` / `deptm` / `iface` / `center` 等 |
| 夜间分片 | `npm run test:spd:shard` | 先登录一次,再 2 进程分片并合并报告 |
并行默认按 **文件**(`PW_WORKERS`)。配置 `TEST_USER_2` / `TEST_PASS_2` 后 worker 在双账号间轮换,可在不加大单账号并发的前提下提高并行度。不要开 `PW_FULLY_PARALLEL=1`:本仓库大量同页 serial,拆开后仍易互踩。总浏览器约 `SHARDS × WORKERS`,单机建议不超过 6。详见 [docs/jenkins.md](docs/jenkins.md)。
......
......@@ -133,6 +133,38 @@ export const PAGE_GROUPS = {
'tests/spd/flow-def.spec.ts',
'tests/spd/flow-inst.spec.ts',
],
deptm: [
'tests/spd/deptm-register.spec.ts',
'tests/spd/deptm-category.spec.ts',
'tests/spd/deptm-product-alloc.spec.ts',
'tests/spd/deptm-zone-product.spec.ts',
'tests/spd/deptm-follow-limit.spec.ts',
'tests/spd/deptm-req-template.spec.ts',
'tests/spd/deptm-auto-req.spec.ts',
'tests/spd/deptm-staff.spec.ts',
'tests/spd/deptm-minmax.spec.ts',
'tests/spd/deptm-budget.spec.ts',
'tests/spd/deptm-lab-machine.spec.ts',
'tests/spd/deptm-delivery.spec.ts',
],
iface: [
'tests/spd/iface-his-price.spec.ts',
'tests/spd/iface-dept-req-ok.spec.ts',
'tests/spd/iface-subdept-req.spec.ts',
'tests/spd/iface-low-billing.spec.ts',
'tests/spd/iface-insurance.spec.ts',
'tests/spd/iface-vendor-code.spec.ts',
'tests/spd/iface-peripheral.spec.ts',
'tests/spd/iface-ext-detail.spec.ts',
'tests/spd/iface-platform-diff.spec.ts',
'tests/spd/iface-api-log.spec.ts',
'tests/spd/iface-push-price.spec.ts',
'tests/spd/iface-charge-code.spec.ts',
'tests/spd/iface-cabinet-zone.spec.ts',
'tests/spd/iface-mat-push.spec.ts',
'tests/spd/iface-req-query.spec.ts',
'tests/spd/iface-campus-code.spec.ts',
],
};
/** @typedef {{ description: string, files: string[], grep?: string, runFull?: boolean, runQuarantine?: boolean, workers?: number, retries?: number }} SuiteDef */
......@@ -148,7 +180,7 @@ export const SUITES = {
retries: 0,
},
smoke: {
description: '冒烟:报表与基础设置中已打 @smoke 的用例(登录/首页、报表、厂商、准入、基础管理、手术、库房、流程)',
description: '冒烟:报表与基础设置中已打 @smoke 的用例(登录/首页、报表、厂商、准入、用户医院资料、手术、库房、流程、科室、接口)',
files: [
...PAGE_GROUPS.auth,
...PAGE_GROUPS.cost,
......@@ -170,6 +202,8 @@ export const SUITES = {
...PAGE_GROUPS.surgery,
...PAGE_GROUPS.warehouse,
...PAGE_GROUPS.flow,
...PAGE_GROUPS.deptm,
...PAGE_GROUPS.iface,
],
grep: '@smoke',
workers: 3,
......@@ -273,7 +307,22 @@ export const SUITES = {
retries: 0,
},
basic: {
description: '基础管理(用户/角色/院区等)',
description: '基础管理全量(用户/医院资料/厂商/准入/手术/库房/流程/科室/接口)',
files: [
...PAGE_GROUPS.basic,
...PAGE_GROUPS.vendor,
...PAGE_GROUPS.admit,
...PAGE_GROUPS.surgery,
...PAGE_GROUPS.warehouse,
...PAGE_GROUPS.flow,
...PAGE_GROUPS.deptm,
...PAGE_GROUPS.iface,
],
workers: 2,
retries: 0,
},
'basic-core': {
description: '基础管理-用户与医院资料(窄范围)',
files: PAGE_GROUPS.basic,
workers: 1,
retries: 0,
......@@ -296,6 +345,18 @@ export const SUITES = {
workers: 1,
retries: 0,
},
deptm: {
description: '科室管理',
files: PAGE_GROUPS.deptm,
workers: 1,
retries: 0,
},
iface: {
description: '接口管理',
files: PAGE_GROUPS.iface,
workers: 1,
retries: 0,
},
extended: {
description: '扩展报表:预警/运维/异常/政策/财务分析/试剂',
files: [
......
......@@ -33,7 +33,7 @@
| SCM | Git |
| Repository URL | `http://10.17.65.20/gitlab/test/autotest-playwright-web-spd.git` |
| Credentials | `gitlab-spd-ui`(与现有 SPD 任务相同) |
| Branch | `*/main` |
| Branch | **`*/temp`**(日常验证拉开发分支;夜间 `SPD` 仍用 `*/main`) |
| Script Path | **`Jenkinsfile.verify`**(不是 `Jenkinsfile`) |
5. **不要**勾选 Build periodically
......@@ -44,7 +44,7 @@
1. 点 **Build with Parameters**
2. 默认即可:
- **SUITE** = `full`(全量回归,与 SPD 夜间套件一致)
- **SUITE** = `basic`(基础管理全量:用户/医院资料/厂商/准入/手术/库房/流程/科室/接口)
- **WORKERS** = `2`
- **SHARDS** = `1`
- **RUN_FULL** = 不勾
......@@ -55,18 +55,21 @@
| 场景 | 参数 |
|------|------|
| 只跑基础管理全量(默认) | `SUITE=basic` |
| 仅用户/医院资料 | `SUITE=basic-core` |
| 改完框架/公共 PO 后快速回归 | `SUITE=smoke` |
| 全量回归(含报表) | `SUITE=full` |
| 只验证登录 | `SUITE=login` |
| 只验证厂商模块 | `SUITE=vendor` |
| 只跑某条用例标题 | `GREP=STAT-IES-001` 或 `GREP=@smoke` |
| 本地改 spec 已 push 到 main | 直接 Build,拉最新 main |
| 本地改 spec 已 push 到 temp | 直接 Build,拉最新 temp |
本地等价:
```bash
npm run test:ci:smoke
SUITE=basic PW_WORKERS=2 npm run test:ci
# 或
SUITE=vendor PW_WORKERS=2 npm run test:ci
npm run test:ci:smoke
```
## 4. 凭据与节点
......@@ -79,8 +82,8 @@ SUITE=vendor PW_WORKERS=2 npm run test:ci
## 5. 与 temp / main 的关系
- Jenkins **只拉 `main`**(正式自动化仓库)
- 在 `temp` 开发时:先合 selective 到 `main`,或临时把 Branch 改成 `*/temp` 做试验(勿长期这样)
- **`spd-ui-verify` 拉 `temp`**(日常验证开发分支)
- 夜间 **`SPD`** 仍拉 **`main`**;稳定后再合入 `main` 供正式回归
## 6. 与 `SPD` / `spd-ui-smoke` 的关系(同一 Jenkins)
......
......@@ -8,7 +8,7 @@
| 任务 | 套件 | 建议 cron | 说明 |
|------|------|-----------|------|
| **`spd-ui-verify`** | **`full`(默认)** | **无(仅手工)** | **平时验证脚本**:Script Path 用 `Jenkinsfile.verify`,默认 WORKERS=2,见 [jenkins-job-spd-ui-verify.md](./jenkins-job-spd-ui-verify.md) |
| **`spd-ui-verify`** | **`basic`(默认)** | **无(仅手工)** | **平时验证脚本**:只跑基础管理全量(不含报表);Script Path 用 `Jenkinsfile.verify`,默认 WORKERS=2,见 [jenkins-job-spd-ui-verify.md](./jenkins-job-spd-ui-verify.md) |
| `spd-ui-smoke` | `smoke` | `H 8-18 * * 1-5` | 工作时段冒烟:报表与基础设置中已打 `@smoke` 的用例(含厂商、准入、基础管理、手术、库房、流程) |
| `spd-ui-nightly` / `SPD` | `nightly` / `full` | `H 23 * * 1,3,5` | 周一、三、五 **23 点** 回归(Jenkins 任务 `SPD` 当前按此时段跑 full) |
| `spd-ui-full` | `full` | `H 3 * * 0` | 周末含全列排序,最慢 |
......
......@@ -18,6 +18,10 @@ const TOKEN = process.env.JENKINS_TOKEN || process.env.JENKINS_API_TOKEN || proc
const SOURCE = process.env.JENKINS_COPY_FROM || 'SPD';
const TARGET = process.env.JENKINS_VERIFY_JOB || 'spd-ui-verify';
const SCRIPT_PATH = process.env.JENKINS_VERIFY_SCRIPT || 'Jenkinsfile.verify';
const BRANCH = process.env.JENKINS_VERIFY_BRANCH || '*/temp';
/** Jenkins CSRF crumb 需与会话 Cookie 同用,否则 POST config.xml 会 403。 */
const cookieJar = new Map();
function authHeader() {
if (!USER || !TOKEN) {
......@@ -28,16 +32,29 @@ function authHeader() {
return `Basic ${basic}`;
}
function rememberCookies(res) {
const raw = typeof res.headers.getSetCookie === 'function' ? res.headers.getSetCookie() : [];
const list = raw.length ? raw : [res.headers.get('set-cookie')].filter(Boolean);
for (const line of list) {
const part = String(line).split(';')[0];
const eq = part.indexOf('=');
if (eq > 0) cookieJar.set(part.slice(0, eq), part.slice(eq + 1));
}
}
async function jenkinsFetch(path, { method = 'GET', headers = {}, body } = {}) {
const url = `${JENKINS_URL}${path.startsWith('/') ? path : `/${path}`}`;
const cookie = [...cookieJar.entries()].map(([k, v]) => `${k}=${v}`).join('; ');
const res = await fetch(url, {
method,
headers: {
Authorization: authHeader(),
...(cookie ? { Cookie: cookie } : {}),
...headers,
},
body,
});
rememberCookies(res);
const text = await res.text();
return { res, text };
}
......@@ -64,16 +81,21 @@ function patchConfigXml(xml) {
let out = xml;
out = out.replace(/<scriptPath>Jenkinsfile<\/scriptPath>/, `<scriptPath>${SCRIPT_PATH}</scriptPath>`);
out = out.replace(/<scriptPath>.*?<\/scriptPath>/, `<scriptPath>${SCRIPT_PATH}</scriptPath>`);
// Pipeline from SCM:把分支说明符改成 temp(默认 */temp)
out = out.replace(
/(<hudson\.plugins\.git\.BranchSpec>[\s\S]*?<name>)[^<]*(<\/name>)/,
`$1${BRANCH}$2`,
);
out = out.replace(/<triggers>[\s\S]*?<\/triggers>\s*/g, '');
out = out.replace(/<hudson\.tasks\.Mailer[\s\S]*?<\/hudson\.tasks\.Mailer>/g, '');
out = out.replace(
/<hudson\.plugins\.emailext[\s\S]*?<\/hudson\.plugins\.emailext>/g,
'',
);
if (!out.includes('<description>')) {
if (!out.includes('<description>') || out.includes('<description/>')) {
out = out.replace(
/<description\/>/,
'<description>日常验证(smoke/单模块),手工触发,不发邮件。Script: Jenkinsfile.verify</description>',
`<description>日常验证(基础管理),拉 ${BRANCH},手工触发,不发邮件。Script: Jenkinsfile.verify</description>`,
);
}
return out;
......@@ -122,7 +144,7 @@ async function updateConfig(crumb) {
}
async function main() {
console.log(`[jenkins] ${JENKINS_URL} source=${SOURCE} target=${TARGET} script=${SCRIPT_PATH}`);
console.log(`[jenkins] ${JENKINS_URL} source=${SOURCE} target=${TARGET} script=${SCRIPT_PATH} branch=${BRANCH}`);
const me = await jenkinsFetch('/me/api/json');
if (!me.res.ok) {
......@@ -144,7 +166,7 @@ async function main() {
await updateConfig(crumb);
console.log(`[jenkins] 完成:${JENKINS_URL}/job/${TARGET}/`);
console.log('[jenkins] 请在 Jenkins 点 Build with Parameters(默认 SUITE=smoke)试跑。');
console.log('[jenkins] 请在 Jenkins 点 Build with Parameters(默认 SUITE=basic)试跑。');
}
main().catch((err) => {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment