diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7e2498b..4064233 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -118,3 +118,16 @@ jobs: # 前置 dist 与 stub companion binary 已由上方步骤就位。 - name: Desktop app tests run: cargo test -p wb-switch-rust + + # 前端行为测试:纯逻辑单测(node 环境),不依赖 Rust 工具链。 + frontend-tests: + name: frontend-tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + - run: npm test diff --git a/package-lock.json b/package-lock.json index bbf2493..0965050 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,8 @@ "@vitejs/plugin-react": "^4.6.0", "tailwindcss": "^4.3.3", "typescript": "~5.8.3", - "vite": "^7.0.4" + "vite": "^7.0.4", + "vitest": "^5.0.2" } }, "node_modules/@babel/code-frame": { @@ -865,9 +866,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, @@ -2905,6 +2906,17 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmmirror.com/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/d3-array": { "version": "3.2.2", "resolved": "https://registry.npmmirror.com/@types/d3-array/-/d3-array-3.2.2.tgz", @@ -2968,6 +2980,13 @@ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "license": "MIT" }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.9.tgz", @@ -3016,6 +3035,54 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, + "node_modules/@vitest/mocker": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-5.0.2.tgz", + "integrity": "sha512-Z5FS00Q1SJHkB35xATsmWGdQ5WA1/0MV3CDjqyv7GavHv1OfOj145MNfHOlHk7QLes21dKFDHr8EO2zvL+9WGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.31", + "@vitest/spy": "5.0.2", + "estree-walker": "^3.0.3", + "magic-string": "^1.2.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/magic-string": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-1.4.2.tgz", + "integrity": "sha512-vG+rjFRj1PqdIBozIxAGMjPlOhaVe+GXpbttY/iSK7rGcJRMlwNJO7dcUwmUqkymsFLJiNGI06t4D7Fr7yRC9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/@vitest/spy": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-5.0.2.tgz", + "integrity": "sha512-Ijc7T1nT9efNb5LxvjaBrEqw3f/QwUv5EE0nKqZxgqsaV/FxAAZ8baGylA8X/Z2oS4Lp+K74Jr6dTJsDKxJDeg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/aria-hidden": { "version": "1.2.6", "resolved": "https://registry.npmmirror.com/aria-hidden/-/aria-hidden-1.2.6.tgz", @@ -3028,6 +3095,16 @@ "node": ">=10" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/baseline-browser-mapping": { "version": "2.11.14", "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.11.14.tgz", @@ -3096,6 +3173,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/class-variance-authority": { "version": "0.7.1", "resolved": "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz", @@ -3335,6 +3422,13 @@ "node": ">=10.13.0" } }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { "version": "0.28.2", "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.28.2.tgz", @@ -3387,12 +3481,32 @@ "node": ">=6" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-equals": { "version": "5.4.1", "resolved": "https://registry.npmmirror.com/fast-equals/-/fast-equals-5.4.1.tgz", @@ -3877,6 +3991,20 @@ "node": ">=0.10.0" } }, + "node_modules/obug": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/obug/-/obug-2.2.1.tgz", + "integrity": "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", @@ -3885,9 +4013,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -4244,6 +4372,13 @@ "node": ">=0.10.0" } }, + "node_modules/std-env": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/std-env/-/std-env-4.3.0.tgz", + "integrity": "sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==", + "dev": true, + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "3.6.0", "resolved": "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-3.6.0.tgz", @@ -4281,6 +4416,26 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, + "node_modules/tinybench": { + "version": "6.2.0", + "resolved": "https://registry.npmmirror.com/tinybench/-/tinybench-6.2.0.tgz", + "integrity": "sha512-78U2TlB2CnVenajOFzf3BKSm0J6oz5L0NV7g32LCPccvYc0lbWvys4d3uUUCS2B1N8PAf2+aekR8i1KbC3HO7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -4509,6 +4664,112 @@ } } }, + "node_modules/vitest": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/vitest/-/vitest-5.0.2.tgz", + "integrity": "sha512-7MQrx9pDv5aHiUcovIb/70Ys3tgtkUVgCtledvKdCmEO+/1Dicq5ZqoSxOW034m03oqC+oHOKui2dM6qtMLoJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/mocker": "5.0.2", + "chai": "^6.2.2", + "es-module-lexer": "^2.3.2", + "expect-type": "^1.4.0", + "magic-string": "^1.2.3", + "obug": "^2.1.4", + "picomatch": "^4.0.7", + "std-env": "^4.2.0", + "tinybench": "^6.1.4", + "tinyexec": "^1.3.0", + "tinyglobby": "^0.2.17", + "why-is-node-running": "^3.2.1" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^22.12.0 || ^24.0.0 || >=26.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "5.0.2", + "@vitest/browser-preview": "5.0.2", + "@vitest/browser-webdriverio": "^5.0.0-beta.5 || >=5.0.0", + "@vitest/coverage-istanbul": "5.0.2", + "@vitest/coverage-v8": "5.0.2", + "@vitest/ui": "5.0.2", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.4.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/vitest/node_modules/magic-string": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-1.4.2.tgz", + "integrity": "sha512-vG+rjFRj1PqdIBozIxAGMjPlOhaVe+GXpbttY/iSK7rGcJRMlwNJO7dcUwmUqkymsFLJiNGI06t4D7Fr7yRC9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/why-is-node-running": { + "version": "3.2.2", + "resolved": "https://registry.npmmirror.com/why-is-node-running/-/why-is-node-running-3.2.2.tgz", + "integrity": "sha512-NKUzAelcoCXhXL4dJzKIwXeR8iEVqsA0Lq6Vnd0UXvgaKbzVo4ZTHROF2Jidrv+SgxOQ03fMinnNhzZATxOD3A==", + "dev": true, + "license": "MIT", + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=20.11" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index ad7a5c6..60131be 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "build": "node scripts/prepare-companion-demo.mjs clean && tsc && vite build", "build:desktop": "node scripts/prepare-agent-companion.mjs build && npm run build && node scripts/prepare-agent-companion.mjs copy", "build:demo": "node scripts/prepare-companion-demo.mjs build && tsc && VITE_DEMO_MODE=1 VITE_PAGES_DEMO=1 vite build && node scripts/prepare-companion-demo.mjs copy", + "test": "vitest run", "preview": "vite preview", "tauri": "tauri", "build:app": "TAURI_SIGNING_PRIVATE_KEY=\"$(cat \"$HOME/.wb-switch/wb-switch-updater.key\")\" TAURI_SIGNING_PRIVATE_KEY_PASSWORD=wb-switch-dev npm run tauri build -- --debug --bundles app; sh scripts/fix-app.sh", @@ -59,6 +60,7 @@ "@vitejs/plugin-react": "^4.6.0", "tailwindcss": "^4.3.3", "typescript": "~5.8.3", - "vite": "^7.0.4" + "vite": "^7.0.4", + "vitest": "^5.0.2" } } diff --git a/src/lib/credit-package-names.test.ts b/src/lib/credit-package-names.test.ts new file mode 100644 index 0000000..fc3e7f0 --- /dev/null +++ b/src/lib/credit-package-names.test.ts @@ -0,0 +1,73 @@ +import { describe, expect, it } from "vitest"; + +import { creditResourceName } from "./credit-package-names"; + +const FALLBACK = "积分包"; + +describe("creditResourceName 命中官方商品码映射", () => { + it("个人标准版取官方中文名", () => { + expect( + creditResourceName( + { packageCode: "TCACA_code_003_FAnt7lcmRT", packageName: "运营原文" }, + FALLBACK, + ), + ).toBe("CodeBuddy 个人标准版"); + }); + + it("购买积分取官方中文名", () => { + expect( + creditResourceName({ packageCode: "TCACA_code_009_0XmEQc2xOf", packageName: null }, FALLBACK), + ).toBe("购买积分"); + }); + + it("平台奖励积分取官方中文名", () => { + expect( + creditResourceName({ packageCode: "TCACA_code_007_nzdH5h4Nl0", packageName: null }, FALLBACK), + ).toBe("平台奖励积分"); + }); + + it("命中映射时忽略后端下发的 PackageName", () => { + expect( + creditResourceName( + { packageCode: "TCACA_code_028_NtpWi0jzXs", packageName: "运营原文" }, + FALLBACK, + ), + ).toBe("版本赠送用量"); + }); +}); + +describe("creditResourceName 未命中回落链", () => { + it("未登记商品码回落到 packageName", () => { + expect( + creditResourceName( + { packageCode: "TCACA_code_999_unregistered", packageName: "运营名称" }, + FALLBACK, + ), + ).toBe("运营名称"); + }); + + it("未登记商品码且无 packageName 时回落到 packageCode", () => { + expect( + creditResourceName({ packageCode: "TCACA_code_999_unregistered", packageName: null }, FALLBACK), + ).toBe("TCACA_code_999_unregistered"); + }); + + it("两个字段都为 null 时回落到调用点文案", () => { + expect(creditResourceName({ packageCode: null, packageName: null }, FALLBACK)).toBe(FALLBACK); + }); + + it("空字符串与 null 等价处理", () => { + expect(creditResourceName({ packageCode: "", packageName: "" }, FALLBACK)).toBe(FALLBACK); + expect(creditResourceName({ packageCode: "", packageName: "运营名称" }, FALLBACK)).toBe( + "运营名称", + ); + }); + + it("packageCode 为空时不因 packageName 为空串而漏掉兜底", () => { + expect(creditResourceName({ packageCode: null, packageName: "" }, FALLBACK)).toBe(FALLBACK); + }); + + it("fallback 为空串时原样返回", () => { + expect(creditResourceName({ packageCode: null, packageName: null }, "")).toBe(""); + }); +}); diff --git a/src/lib/variant.test.ts b/src/lib/variant.test.ts new file mode 100644 index 0000000..5e9dee4 --- /dev/null +++ b/src/lib/variant.test.ts @@ -0,0 +1,97 @@ +import { describe, expect, it } from "vitest"; + +import { + DEFAULT_VARIANT, + accountVariant, + normalizeVariant, + variantAppName, + variantCodebuddyIdeName, + variantDownloadDomain, + variantIsIntl, + variantLabel, + variantSupportsCheckin, + variantSupportsTravel, + variantUsesIntlCodebuddyIde, +} from "./variant"; + +describe("normalizeVariant", () => { + it("保留已知档位 cn 与 ai", () => { + expect(normalizeVariant("cn")).toBe("cn"); + expect(normalizeVariant("ai")).toBe("ai"); + }); + + it("未知字符串一律回落国内版", () => { + expect(normalizeVariant("intl")).toBe("cn"); + expect(normalizeVariant("AI")).toBe("cn"); + expect(normalizeVariant("cn ")).toBe("cn"); + }); + + it("缺省、空值与非法类型回落国内版", () => { + expect(normalizeVariant(undefined)).toBe("cn"); + expect(normalizeVariant(null)).toBe("cn"); + expect(normalizeVariant("")).toBe("cn"); + expect(normalizeVariant(0)).toBe("cn"); + expect(normalizeVariant({ variant: "ai" })).toBe("cn"); + }); + + it("缺省常量本身是国内版", () => { + expect(DEFAULT_VARIANT).toBe("cn"); + }); +}); + +describe("档位文案映射", () => { + it("档位名:国内版 / 国际版", () => { + expect(variantLabel("cn")).toBe("国内版"); + expect(variantLabel("ai")).toBe("国际版"); + }); + + it("客户端名:国际版带后缀", () => { + expect(variantAppName("cn")).toBe("WorkBuddy"); + expect(variantAppName("ai")).toBe("WorkBuddy 国际版"); + }); + + it("CodeBuddy IDE 名:国际版带后缀", () => { + expect(variantCodebuddyIdeName("cn")).toBe("CodeBuddy IDE"); + expect(variantCodebuddyIdeName("ai")).toBe("CodeBuddy IDE 国际版"); + }); + + it("下载域名:国内版 codebuddy.cn / 国际版 workbuddy.ai", () => { + expect(variantDownloadDomain("cn")).toBe("codebuddy.cn"); + expect(variantDownloadDomain("ai")).toBe("workbuddy.ai"); + }); +}); + +describe("accountVariant", () => { + it("账号为 null / undefined / 无档位字段时按国内版", () => { + expect(accountVariant(null)).toBe("cn"); + expect(accountVariant(undefined)).toBe("cn"); + expect(accountVariant({})).toBe("cn"); + }); + + it("读取账号自身档位", () => { + expect(accountVariant({ variant: "ai" })).toBe("ai"); + expect(accountVariant({ variant: "cn" })).toBe("cn"); + }); +}); + +describe("档位能力开关", () => { + it("成长中心仅国内版开放", () => { + expect(variantSupportsTravel("cn")).toBe(true); + expect(variantSupportsTravel("ai")).toBe(false); + }); + + it("自动签到仅国内版开放", () => { + expect(variantSupportsCheckin("cn")).toBe(true); + expect(variantSupportsCheckin("ai")).toBe(false); + }); + + it("只有国际版切 CodeBuddy.app", () => { + expect(variantUsesIntlCodebuddyIde("cn")).toBe(false); + expect(variantUsesIntlCodebuddyIde("ai")).toBe(true); + }); + + it("档位标记:只有国际版算 INTL", () => { + expect(variantIsIntl("cn")).toBe(false); + expect(variantIsIntl("ai")).toBe(true); + }); +}); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..82af464 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from "vitest/config"; +import path from "node:path"; + +// 独立于 vite.config.ts:那份是异步函数式 defineConfig,且带 Tauri 专用的 +// server / base 配置,测试用不上。这里只保留测试真正需要的两件事: +// @ 别名(与 vite.config.ts 保持一致)与测试文件匹配规则。 +export default defineConfig({ + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, + test: { + // 首批只覆盖纯逻辑模块(无 DOM 依赖),node 环境足够且启动最快。 + environment: "node", + include: ["src/**/*.test.ts"], + }, +});