test(admin): 审核台 review api 单测(7)——链路②关键门回归基线 + game-admin 测基建

game-admin 深查=功能已成(5 wanxiang 视图+客户端全建、贴契约零缺口),唯缺测。补关键门(发布→审核→入 feed)回归:
- src/api/wanxiang/project.spec.ts(7 测):mock 兜底两端不打真接口;真实模式 GET /project/review/page + POST /project/review 的 url/method/data 贴 frozen project.yaml;**审核决策码 1通过/2拒绝/3下架 钉死契约 ReviewReqVO.decision**(最易错处)
- 引入 vitest 2(Vite5 兼容)+ vitest.config(env node,@别名)+ npm test 脚本;tsconfig exclude *.spec.ts(不入 ts:check/build)
- 锁:本仓 pnpm 为准(build 脚本走 pnpm)→ 同步 pnpm-lock.yaml(加 vitest 子树);package-lock.json 为残留次级锁,回退不引入 npm churn/意外版本漂移

验证:`npm test` 7/7 绿(vitest 2.1.9,pnpm node_modules)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
lili 2026-06-17 17:02:50 -07:00
parent d44071408f
commit 349cd8292c
5 changed files with 345 additions and 28 deletions

View File

@ -22,7 +22,8 @@
"lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src",
"lint:format": "prettier --write --loglevel warn \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"",
"lint:style": "stylelint --fix \"./src/**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
"lint:lint-staged": "lint-staged -c "
"lint:lint-staged": "lint-staged -c ",
"test": "vitest run"
},
"dependencies": {
"@element-plus/icons-vue": "2.3.2",
@ -139,6 +140,7 @@
"vite-plugin-purge-icons": "^0.10.0",
"vite-plugin-svg-icons-ng": "^1.3.1",
"vite-plugin-top-level-await": "^1.4.4",
"vitest": "^2.1.9",
"vue-eslint-parser": "^9.3.2",
"vue-tsc": "^1.8.27"
},

View File

@ -345,6 +345,9 @@ importers:
vite-plugin-top-level-await:
specifier: ^1.4.4
version: 1.4.4(rollup@4.27.4)(vite@5.1.4(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0))
vitest:
specifier: ^2.1.9
version: 2.1.9(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0)
vue-eslint-parser:
specifier: ^9.3.2
version: 9.4.3(eslint@8.57.1)
@ -1406,42 +1409,36 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.0':
resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.0':
resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.0':
resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.0':
resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.0':
resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.0':
resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==}
@ -1545,55 +1542,46 @@ packages:
resolution: {integrity: sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.27.4':
resolution: {integrity: sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.27.4':
resolution: {integrity: sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.27.4':
resolution: {integrity: sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-powerpc64le-gnu@4.27.4':
resolution: {integrity: sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.27.4':
resolution: {integrity: sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-s390x-gnu@4.27.4':
resolution: {integrity: sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.27.4':
resolution: {integrity: sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.27.4':
resolution: {integrity: sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.27.4':
resolution: {integrity: sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==}
@ -1639,28 +1627,24 @@ packages:
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@swc/core-linux-arm64-musl@1.9.3':
resolution: {integrity: sha512-tzVH480RY6RbMl/QRgh5HK3zn1ZTFsThuxDGo6Iuk1MdwIbdFYUY034heWUTI4u3Db97ArKh0hNL0xhO3+PZdg==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@swc/core-linux-x64-gnu@1.9.3':
resolution: {integrity: sha512-ivXXBRDXDc9k4cdv10R21ccBmGebVOwKXT/UdH1PhxUn9m/h8erAWjz5pcELwjiMf27WokqPgaWVfaclDbgE+w==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@swc/core-linux-x64-musl@1.9.3':
resolution: {integrity: sha512-ILsGMgfnOz1HwdDz+ZgEuomIwkP1PHT6maigZxaCIuC6OPEhKE8uYna22uU63XvYcLQvZYDzpR3ms47WQPuNEg==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@swc/core-win32-arm64-msvc@1.9.3':
resolution: {integrity: sha512-e+XmltDVIHieUnNJHtspn6B+PCcFOMYXNJB1GqoCcyinkEIQNwC8KtWgMqUucUbEWJkPc35NHy9k8aCXRmw9Kg==}
@ -2155,6 +2139,35 @@ packages:
vite: ^5.0.0 || ^6.0.0
vue: ^3.2.25
'@vitest/expect@2.1.9':
resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==}
'@vitest/mocker@2.1.9':
resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==}
peerDependencies:
msw: ^2.4.9
vite: ^5.0.0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
'@vitest/pretty-format@2.1.9':
resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==}
'@vitest/runner@2.1.9':
resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==}
'@vitest/snapshot@2.1.9':
resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==}
'@vitest/spy@2.1.9':
resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==}
'@vitest/utils@2.1.9':
resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==}
'@volar/language-core@1.11.1':
resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==}
@ -2434,6 +2447,10 @@ packages:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
assertion-error@2.0.1:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
astral-regex@2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
@ -2569,6 +2586,10 @@ packages:
caniuse-lite@1.0.30001684:
resolution: {integrity: sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==}
chai@5.3.3:
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
engines: {node: '>=18'}
chalk@1.1.3:
resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==}
engines: {node: '>=0.10.0'}
@ -2581,6 +2602,10 @@ packages:
resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
check-error@2.1.3:
resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==}
engines: {node: '>= 16'}
cheerio-select@2.1.0:
resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
@ -2933,6 +2958,10 @@ packages:
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'}
deep-eql@5.0.2:
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'}
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@ -3224,6 +3253,10 @@ packages:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
expect-type@1.3.0:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
ext@1.7.0:
resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
@ -3841,6 +3874,9 @@ packages:
resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
engines: {node: '>= 0.6.0'}
loupe@3.2.1:
resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
@ -4195,6 +4231,10 @@ packages:
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
pathval@2.0.1:
resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
engines: {node: '>= 14.16'}
perfect-debounce@1.0.0:
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
@ -4535,6 +4575,9 @@ packages:
resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
engines: {node: '>= 0.4'}
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
@ -4601,6 +4644,12 @@ packages:
ssr-window@4.0.2:
resolution: {integrity: sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==}
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
std-env@3.10.0:
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
steady-xml@0.1.0:
resolution: {integrity: sha512-5sk17qO2wWRtonTNoBhoKAB35OSsGJOa3+NEa6D+1GS+de+ujDWxnflMkXBrviOfkNrPTUqduAdXhrMJs89nAw==}
engines: {node: '>=12.0.0'}
@ -4742,6 +4791,9 @@ packages:
tiny-warning@1.0.3:
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
tinyexec@0.3.1:
resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==}
@ -4749,6 +4801,18 @@ packages:
resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==}
engines: {node: '>=12.0.0'}
tinypool@1.1.1:
resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
engines: {node: ^18.0.0 || >=20.0.0}
tinyrainbow@1.2.0:
resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
engines: {node: '>=14.0.0'}
tinyspy@3.0.2:
resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
engines: {node: '>=14.0.0'}
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@ -4916,6 +4980,11 @@ packages:
videojs-vtt.js@0.15.5:
resolution: {integrity: sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==}
vite-node@2.1.9:
resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
vite-plugin-compression@0.5.1:
resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
peerDependencies:
@ -4983,6 +5052,31 @@ packages:
terser:
optional: true
vitest@2.1.9:
resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@types/node': ^18.0.0 || >=20.0.0
'@vitest/browser': 2.1.9
'@vitest/ui': 2.1.9
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
'@types/node':
optional: true
'@vitest/browser':
optional: true
'@vitest/ui':
optional: true
happy-dom:
optional: true
jsdom:
optional: true
vue-demi@0.14.10:
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
engines: {node: '>=12'}
@ -5085,6 +5179,11 @@ packages:
engines: {node: '>= 8'}
hasBin: true
why-is-node-running@2.3.0:
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
engines: {node: '>=8'}
hasBin: true
wildcard@1.1.2:
resolution: {integrity: sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==}
@ -6325,7 +6424,7 @@ snapshots:
escodegen: 2.1.0
estree-walker: 2.0.2
jsonc-eslint-parser: 2.4.0
magic-string: 0.30.14
magic-string: 0.30.17
mlly: 1.7.3
source-map-js: 1.2.1
yaml-eslint-parser: 1.2.3
@ -7027,7 +7126,7 @@ snapshots:
colorette: 2.0.20
consola: 3.2.3
fast-glob: 3.3.2
magic-string: 0.30.14
magic-string: 0.30.17
pathe: 1.1.2
perfect-debounce: 1.0.0
transitivePeerDependencies:
@ -7105,7 +7204,7 @@ snapshots:
'@unocss/rule-utils': 0.58.9
css-tree: 2.3.1
fast-glob: 3.3.2
magic-string: 0.30.14
magic-string: 0.30.17
postcss: 8.4.49
'@unocss/preset-attributify@0.58.9':
@ -7158,7 +7257,7 @@ snapshots:
'@unocss/rule-utils@0.58.9':
dependencies:
'@unocss/core': 0.58.9
magic-string: 0.30.14
magic-string: 0.30.17
'@unocss/rule-utils@66.1.0-beta.5':
dependencies:
@ -7205,7 +7304,7 @@ snapshots:
'@unocss/transformer-directives': 0.58.9
chokidar: 3.6.0
fast-glob: 3.3.2
magic-string: 0.30.14
magic-string: 0.30.17
vite: 5.1.4(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0)
transitivePeerDependencies:
- rollup
@ -7298,6 +7397,46 @@ snapshots:
vite: 5.1.4(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0)
vue: 3.5.12(typescript@5.3.3)
'@vitest/expect@2.1.9':
dependencies:
'@vitest/spy': 2.1.9
'@vitest/utils': 2.1.9
chai: 5.3.3
tinyrainbow: 1.2.0
'@vitest/mocker@2.1.9(vite@5.1.4(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0))':
dependencies:
'@vitest/spy': 2.1.9
estree-walker: 3.0.3
magic-string: 0.30.17
optionalDependencies:
vite: 5.1.4(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0)
'@vitest/pretty-format@2.1.9':
dependencies:
tinyrainbow: 1.2.0
'@vitest/runner@2.1.9':
dependencies:
'@vitest/utils': 2.1.9
pathe: 1.1.2
'@vitest/snapshot@2.1.9':
dependencies:
'@vitest/pretty-format': 2.1.9
magic-string: 0.30.17
pathe: 1.1.2
'@vitest/spy@2.1.9':
dependencies:
tinyspy: 3.0.2
'@vitest/utils@2.1.9':
dependencies:
'@vitest/pretty-format': 2.1.9
loupe: 3.2.1
tinyrainbow: 1.2.0
'@volar/language-core@1.11.1':
dependencies:
'@volar/source-map': 1.11.1
@ -7387,7 +7526,7 @@ snapshots:
'@vue/compiler-ssr': 3.5.13
'@vue/shared': 3.5.13
estree-walker: 2.0.2
magic-string: 0.30.14
magic-string: 0.30.17
postcss: 8.4.49
source-map-js: 1.2.1
@ -7671,6 +7810,8 @@ snapshots:
array-union@2.1.0: {}
assertion-error@2.0.1: {}
astral-regex@2.0.0: {}
async-validator@4.2.5: {}
@ -7834,6 +7975,14 @@ snapshots:
caniuse-lite@1.0.30001684: {}
chai@5.3.3:
dependencies:
assertion-error: 2.0.1
check-error: 2.1.3
deep-eql: 5.0.2
loupe: 3.2.1
pathval: 2.0.1
chalk@1.1.3:
dependencies:
ansi-styles: 2.2.1
@ -7849,6 +7998,8 @@ snapshots:
chalk@5.3.0: {}
check-error@2.1.3: {}
cheerio-select@2.1.0:
dependencies:
boolbase: 1.0.0
@ -8221,6 +8372,8 @@ snapshots:
decamelize@1.2.0: {}
deep-eql@5.0.2: {}
deep-is@0.1.4: {}
default-passive-events@2.0.0: {}
@ -8589,6 +8742,8 @@ snapshots:
signal-exit: 4.1.0
strip-final-newline: 3.0.0
expect-type@1.3.0: {}
ext@1.7.0:
dependencies:
type: 2.7.3
@ -9186,6 +9341,8 @@ snapshots:
loglevel@1.9.2: {}
loupe@3.2.1: {}
lru-cache@10.4.3: {}
lru-cache@5.1.1:
@ -9526,6 +9683,8 @@ snapshots:
pathe@2.0.3: {}
pathval@2.0.1: {}
perfect-debounce@1.0.0: {}
picocolors@1.1.1: {}
@ -9849,6 +10008,8 @@ snapshots:
get-intrinsic: 1.2.4
object-inspect: 1.13.3
siginfo@2.0.0: {}
signal-exit@4.1.0: {}
signature_pad@3.0.0-beta.4: {}
@ -9909,6 +10070,10 @@ snapshots:
ssr-window@4.0.2: {}
stackback@0.0.2: {}
std-env@3.10.0: {}
steady-xml@0.1.0: {}
string-argv@0.3.2: {}
@ -10083,6 +10248,8 @@ snapshots:
tiny-warning@1.0.3: {}
tinybench@2.9.0: {}
tinyexec@0.3.1: {}
tinyglobby@0.2.10:
@ -10090,6 +10257,12 @@ snapshots:
fdir: 6.4.2(picomatch@4.0.2)
picomatch: 4.0.2
tinypool@1.1.1: {}
tinyrainbow@1.2.0: {}
tinyspy@3.0.2: {}
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@ -10159,7 +10332,7 @@ snapshots:
escape-string-regexp: 5.0.0
estree-walker: 3.0.3
local-pkg: 0.5.1
magic-string: 0.30.14
magic-string: 0.30.17
mlly: 1.7.3
pathe: 1.1.2
picomatch: 4.0.2
@ -10297,6 +10470,23 @@ snapshots:
dependencies:
global: 4.4.0
vite-node@2.1.9(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0):
dependencies:
cac: 6.7.14
debug: 4.3.7
es-module-lexer: 1.5.4
pathe: 1.1.2
vite: 5.1.4(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0)
transitivePeerDependencies:
- '@types/node'
- less
- lightningcss
- sass
- stylus
- sugarss
- supports-color
- terser
vite-plugin-compression@0.5.1(vite@5.1.4(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0)):
dependencies:
chalk: 4.1.2
@ -10366,6 +10556,40 @@ snapshots:
sass: 1.81.0
terser: 5.36.0
vitest@2.1.9(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0):
dependencies:
'@vitest/expect': 2.1.9
'@vitest/mocker': 2.1.9(vite@5.1.4(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0))
'@vitest/pretty-format': 2.1.9
'@vitest/runner': 2.1.9
'@vitest/snapshot': 2.1.9
'@vitest/spy': 2.1.9
'@vitest/utils': 2.1.9
chai: 5.3.3
debug: 4.3.7
expect-type: 1.3.0
magic-string: 0.30.17
pathe: 1.1.2
std-env: 3.10.0
tinybench: 2.9.0
tinyexec: 0.3.1
tinypool: 1.1.1
tinyrainbow: 1.2.0
vite: 5.1.4(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0)
vite-node: 2.1.9(@types/node@20.17.9)(sass@1.81.0)(terser@5.36.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 20.17.9
transitivePeerDependencies:
- less
- lightningcss
- msw
- sass
- stylus
- sugarss
- supports-color
- terser
vue-demi@0.14.10(vue@3.5.12(typescript@5.3.3)):
dependencies:
vue: 3.5.12(typescript@5.3.3)
@ -10477,6 +10701,11 @@ snapshots:
dependencies:
isexe: 2.0.0
why-is-node-running@2.3.0:
dependencies:
siginfo: 2.0.0
stackback: 0.0.2
wildcard@1.1.2: {}
word-wrap@1.2.5: {}

View File

@ -0,0 +1,70 @@
/**
* project.spec.ts —— 造梦运营·项目审核 api 单测(链路②关键门:发布→审核→入 feed)。
* 验:① mock 兜底(VITE_APP_WANXIANG_MOCK=true)两端均不打真实接口;② 真实模式 url/method/data 贴 frozen project.yaml;
* ③ 审核决策码 1通过/2拒绝/3下架 对齐契约 ReviewReqVO.decision(钉死最易错的决策映射)。跑 `npm test`。
*/
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
// mock 请求包络(project.ts: `import request from '@/config/axios'`,默认导出 {get,post,...})
vi.mock('@/config/axios', () => ({ default: { get: vi.fn(), post: vi.fn() } }))
import request from '@/config/axios'
import { getProjectReviewPage, reviewProject, ReviewDecisionEnum, ProjectStatusEnum } from './project'
const req = request as unknown as { get: ReturnType<typeof vi.fn>; post: ReturnType<typeof vi.fn> }
describe('wanxiang/project 审核 api', () => {
beforeEach(() => vi.clearAllMocks())
afterEach(() => vi.unstubAllEnvs())
describe('mock 兜底(VITE_APP_WANXIANG_MOCK=true)', () => {
beforeEach(() => vi.stubEnv('VITE_APP_WANXIANG_MOCK', 'true'))
it('getProjectReviewPage → 本地 mock 分页{list,total},不打真实接口', async () => {
const r = await getProjectReviewPage({ pageNo: 1, pageSize: 10 })
expect(r.total).toBeGreaterThan(0)
expect(r.list.every((p) => p.status === ProjectStatusEnum.REVIEWING)).toBe(true)
expect(req.get).not.toHaveBeenCalled()
})
it('reviewProject → mock 返 true,不打真实接口', async () => {
const r = await reviewProject({ gameId: 1001, versionId: 5001, decision: ReviewDecisionEnum.PASS })
expect(r).toBe(true)
expect(req.post).not.toHaveBeenCalled()
})
})
describe('真实模式(VITE_APP_WANXIANG_MOCK!=true)', () => {
beforeEach(() => vi.stubEnv('VITE_APP_WANXIANG_MOCK', 'false'))
it('getProjectReviewPage → GET /project/review/page + params', async () => {
req.get.mockResolvedValue({ list: [], total: 0 })
await getProjectReviewPage({ pageNo: 2, pageSize: 5, status: 1 })
expect(req.get).toHaveBeenCalledWith({ url: '/project/review/page', params: { pageNo: 2, pageSize: 5, status: 1 } })
})
it('reviewProject(通过) → POST /project/review {decision:1}', async () => {
req.post.mockResolvedValue(true)
await reviewProject({ gameId: 1001, versionId: 5001, decision: ReviewDecisionEnum.PASS })
expect(req.post).toHaveBeenCalledWith({ url: '/project/review', data: { gameId: 1001, versionId: 5001, decision: 1 } })
})
it('reviewProject(拒绝) → POST {decision:2} + reason', async () => {
req.post.mockResolvedValue(true)
await reviewProject({ gameId: 1002, versionId: 5002, decision: ReviewDecisionEnum.REJECT, reason: '内容不当' })
expect(req.post).toHaveBeenCalledWith({ url: '/project/review', data: { gameId: 1002, versionId: 5002, decision: 2, reason: '内容不当' } })
})
it('reviewProject(下架) → POST {decision:3} + reason', async () => {
req.post.mockResolvedValue(true)
await reviewProject({ gameId: 1003, versionId: 5003, decision: ReviewDecisionEnum.OFFLINE, reason: '违规下架' })
expect(req.post).toHaveBeenCalledWith({ url: '/project/review', data: { gameId: 1003, versionId: 5003, decision: 3, reason: '违规下架' } })
})
})
it('决策枚举钉死契约 ReviewReqVO.decision(1通过/2拒绝/3下架)', () => {
expect(ReviewDecisionEnum.PASS).toBe(1)
expect(ReviewDecisionEnum.REJECT).toBe(2)
expect(ReviewDecisionEnum.OFFLINE).toBe(3)
})
})

View File

@ -39,5 +39,5 @@
"src/types/auto-imports.d.ts",
"src/types/auto-components.d.ts"
],
"exclude": ["dist", "target", "node_modules"]
"exclude": ["dist", "target", "node_modules", "src/**/*.spec.ts"]
}

View File

@ -0,0 +1,16 @@
/**
* vitest 配置(game-admin)。环境 node(api 层测无需 DOM);@ 别名→src(对齐 vite.config)。
* 用途:wanxiang 运营 api 单测(审核台 review 等);跑 `npm test`。
*/
import { defineConfig } from 'vitest/config'
import { fileURLToPath } from 'node:url'
export default defineConfig({
resolve: {
alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) },
},
test: {
environment: 'node',
include: ['src/**/*.spec.ts'],
},
})