Skip to content

Commit 6129d80

Browse files
fengzhi09s39-dev
andauthored
test(tui): pin the runner locale and the update host so the suite is machine-independent (#137)
* test(vitest): pin the runner locale to the one CI uses The TUI resolves its language from the environment: sessionMutationLocale() falls back to Intl's resolved locale, which Node derives from LANG, and packages/tui/src/update/messages.ts reads LC_ALL/LC_MESSAGES/LANG directly. A developer shell running LANG=zh_CN.utf8 therefore renders Chinese copy while the suites assert the English strings they ship, and 29 capability tests fail on a host CI never exercises. Spawn the suite with LC_ALL and LANG set to en_US.UTF-8 so every group runs under one locale. Pinning the two variables together covers the Intl and the environment lookup paths, which stubbing each test would miss. Fixing it in the runner keeps the suites aligned with CI instead of teaching every translation-sensitive assertion about the developer's shell. Purely test infrastructure; no product behaviour changes. * test(tui): pin the update-service host to a published release target McodeUpdateService.check() calls resolveMcodeReleaseTarget() with no override, so it reads process.platform and process.arch. release.ts publishes only darwin-arm64, darwin-x64, linux-x64, windows-x64 and windows-arm64, and a host outside that set — linux-arm64, for example — fails every check with "Unsupported MCode update host" regardless of what the test asserts. Pin both properties with Object.defineProperty in beforeEach and restore the captured host descriptors in afterEach, so the rest of the process is untouched. The fallback is linux-x64, a real REQUIRED_V1_TARGETS entry, so the tests keep exercising a shipped target instead of an invented one. Hosts that already publish keep their own platform and arch, which leaves the win32-only install test on Windows driving the real win32 branch of resolveMcodeInstallRoot and detectMcodeInstallSource. Purely test infrastructure; release.ts TARGETS is unchanged, so whether linux-arm64 should become a published target stays a product decision. --------- Co-authored-by: s39-dev <s39-dev@local>
1 parent c1b239d commit 6129d80

2 files changed

Lines changed: 49 additions & 2 deletions

File tree

‎packages/tui/test/unit/update-service.test.ts‎

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync
44
import { createServer } from 'node:http';
55
import { tmpdir } from 'node:os';
66
import path from 'node:path';
7-
import { afterEach, describe, expect, it, vi } from 'vitest';
7+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
88
import { McodeUpdateService, type McodeUpdateDependencies } from '../../src/update/service.js';
99
import { resolveMcodeNpmDistribution } from '../../src/update/install-source.js';
10-
import type { McodeReleaseManifestV1 } from '../../src/update/release.js';
10+
import { resolveMcodeReleaseTarget, type McodeReleaseManifestV1 } from '../../src/update/release.js';
1111

1212
const temporaryRoots: string[] = [];
1313

@@ -56,6 +56,43 @@ afterEach(() => {
5656
}
5757
});
5858

59+
// McodeUpdateService.check() resolves the release target from the running
60+
// process, so this file only runs on a host release.ts actually publishes for.
61+
// A host outside that set (linux-arm64, for example) fails every check with
62+
// "Unsupported MCode update host" no matter what the test asserts. Pin the
63+
// reported platform and arch to a real required target for the duration of
64+
// each test, and restore the host descriptors afterwards so the rest of the
65+
// process is unaffected. Hosts that already publish keep their own values,
66+
// which leaves the win32-only install test exercising the real win32 branch.
67+
const hostIsRequiredTarget = (() => {
68+
try {
69+
resolveMcodeReleaseTarget();
70+
return true;
71+
} catch {
72+
return false;
73+
}
74+
})();
75+
const pinnedTarget = hostIsRequiredTarget
76+
? { platform: process.platform, arch: process.arch }
77+
: { platform: 'linux', arch: 'x64' };
78+
const hostDescriptors = {
79+
platform: Object.getOwnPropertyDescriptor(process, 'platform'),
80+
arch: Object.getOwnPropertyDescriptor(process, 'arch'),
81+
};
82+
83+
beforeEach(() => {
84+
for (const [key, value] of Object.entries(pinnedTarget)) {
85+
Object.defineProperty(process, key, { value, configurable: true });
86+
}
87+
});
88+
89+
afterEach(() => {
90+
for (const [key, descriptor] of Object.entries(hostDescriptors)) {
91+
if (!descriptor) continue;
92+
Object.defineProperty(process, key, descriptor);
93+
}
94+
});
95+
5996
describe('McodeUpdateService', () => {
6097
it
6198
.skipIf(process.platform !== 'win32')

‎scripts/run-vitest-suite.mjs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ const cli = path.resolve(path.dirname(manifestPath), require(manifestPath).bin.v
1616
// https://github.com/libuv/libuv/issues/5010. Keep real filesystem watching in
1717
// the tests, but create their temporary fixtures beneath the canonical path.
1818
const environment = { ...process.env };
19+
// Assertions compare against the English copy the suites ship, but the TUI
20+
// picks its language from the environment: sessionMutationLocale() falls back to
21+
// Intl's resolved locale, which Node derives from LANG, and
22+
// packages/tui/src/update/messages.ts reads LC_ALL/LC_MESSAGES/LANG directly.
23+
// A developer shell with LANG=zh_CN.utf8 therefore renders Chinese TUI output
24+
// and fails English-only assertions that CI never sees. Pin both variables so
25+
// the suites run under the locale CI uses, and cover the Intl and environment
26+
// lookup paths together rather than stubbing each test.
27+
environment.LC_ALL = "en_US.UTF-8";
28+
environment.LANG = "en_US.UTF-8";
1929
if (process.platform === "win32") {
2030
environment.TEMP = environment.TMP = realpathSync.native(tmpdir());
2131
}

0 commit comments

Comments
 (0)