ci(test): add test:packages script and wire packages/pi-coding-agent tests into CI

The 13 test files in packages/pi-coding-agent/src/core/ were never executed
in CI or by `npm test`. The test:unit glob only covers src/resources/extensions/gsd/tests/
and src/tests/, leaving lifecycle-hooks, model-registry-auth-mode, auth-storage,
and 10 other suites with zero enforcement.

- Add `test:packages` script that runs compiled dist tests after build
- Wire into both the linux build job and windows-portability job in CI
- Fix two env-isolation bugs in auth-storage.test.ts: the "returns undefined"
  and "falls through to fallback resolver" tests were not clearing
  OPENROUTER_API_KEY before calling getApiKey, causing failures when the
  env var is set in the caller's environment
This commit is contained in:
Jeremy McSpadden 2026-03-25 12:14:17 -05:00
parent ab5444fec8
commit d6bd17298f
3 changed files with 34 additions and 2 deletions

View file

@ -139,6 +139,9 @@ jobs:
- name: Run unit tests
run: npm run test:unit
- name: Run package tests
run: npm run test:packages
- name: Run integration tests
run: npm run test:integration
@ -171,3 +174,6 @@ jobs:
- name: Run unit tests
run: npm run test:unit
- name: Run package tests
run: npm run test:packages

View file

@ -54,6 +54,7 @@
"copy-themes": "node scripts/copy-themes.cjs",
"copy-export-html": "node scripts/copy-export-html.cjs",
"test:unit": "node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --experimental-test-isolation=process --test src/resources/extensions/gsd/tests/*.test.ts src/resources/extensions/gsd/tests/*.test.mjs src/tests/*.test.ts",
"test:packages": "node --test packages/pi-coding-agent/dist/core/*.test.js",
"test:marketplace": "GSD_TEST_CLONE_MARKETPLACES=1 node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/claude-import-tui.test.ts src/resources/extensions/gsd/tests/plugin-importer-live.test.ts src/tests/marketplace-discovery.test.ts",
"test:coverage": "c8 --reporter=text --reporter=lcov --exclude='src/resources/extensions/gsd/tests/**' --exclude='src/tests/**' --exclude='scripts/**' --exclude='native/**' --exclude='node_modules/**' --check-coverage --statements=50 --lines=50 --branches=20 --functions=20 node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --experimental-test-isolation=process --test src/resources/extensions/gsd/tests/*.test.ts src/resources/extensions/gsd/tests/*.test.mjs src/tests/*.test.ts",
"test:integration": "node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --experimental-test-isolation=process --test src/resources/extensions/gsd/tests/*integration*.test.ts src/tests/integration/*.test.ts",

View file

@ -266,7 +266,7 @@ describe("AuthStorage — areAllCredentialsBackedOff", () => {
// ─── mismatched oauth credential for non-OAuth provider (#2083) ───────────────
describe("AuthStorage — oauth credential for non-OAuth provider (#2083)", () => {
it("returns undefined when openrouter has type:oauth (no registered OAuth provider)", async () => {
it("returns undefined when openrouter has type:oauth (no registered OAuth provider)", async (t) => {
// Simulates the bug: OpenRouter credential stored as type:"oauth"
// but OpenRouter is not a registered OAuth provider.
const storage = inMemory({
@ -278,12 +278,25 @@ describe("AuthStorage — oauth credential for non-OAuth provider (#2083)", () =
},
});
// Isolate from any real OPENROUTER_API_KEY in the environment so the
// fall-through to env / fallback finds nothing and returns undefined.
const origEnv = process.env.OPENROUTER_API_KEY;
delete process.env.OPENROUTER_API_KEY;
t.after(() => {
if (origEnv === undefined) {
delete process.env.OPENROUTER_API_KEY;
} else {
process.env.OPENROUTER_API_KEY = origEnv;
}
});
// Before the fix, getApiKey returns undefined because
// resolveCredentialApiKey calls getOAuthProvider("openrouter") → null → undefined.
// The key in the oauth credential is never extracted.
const key = await storage.getApiKey("openrouter");
// After the fix, the oauth credential with an unrecognised provider
// should be skipped, and getApiKey should fall through to env / fallback.
// With no env var and no fallback resolver configured, the result is undefined.
assert.equal(key, undefined);
});
@ -312,7 +325,7 @@ describe("AuthStorage — oauth credential for non-OAuth provider (#2083)", () =
assert.equal(key, "sk-or-v1-env-key");
});
it("falls through to fallback resolver when openrouter has type:oauth credential", async () => {
it("falls through to fallback resolver when openrouter has type:oauth credential", async (t) => {
const storage = inMemory({
openrouter: {
type: "oauth",
@ -322,6 +335,18 @@ describe("AuthStorage — oauth credential for non-OAuth provider (#2083)", () =
},
});
// Isolate from any real OPENROUTER_API_KEY so env fallback is skipped
// and the fallback resolver is reached.
const origEnv = process.env.OPENROUTER_API_KEY;
delete process.env.OPENROUTER_API_KEY;
t.after(() => {
if (origEnv === undefined) {
delete process.env.OPENROUTER_API_KEY;
} else {
process.env.OPENROUTER_API_KEY = origEnv;
}
});
storage.setFallbackResolver((provider) =>
provider === "openrouter" ? "sk-or-v1-fallback" : undefined,
);