Skip to content

Recovered: test: make the Windows CLI test harness portable (#207 by @Yazan-O)#250

Open
jangjos-128 wants to merge 2 commits into
TestSprite:mainfrom
Yazan-O:fix/windows-credentials-tests
Open

Recovered: test: make the Windows CLI test harness portable (#207 by @Yazan-O)#250
jangjos-128 wants to merge 2 commits into
TestSprite:mainfrom
Yazan-O:fix/windows-credentials-tests

Conversation

@jangjos-128

@jangjos-128 jangjos-128 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Running npm test on a Windows workstation currently fails in several suites, which blocks the documented contributor loop (CONTRIBUTING.md) for Windows users. This PR makes the test harness portable without changing any CLI behavior — the diff is tests + one test helper only.

  • Make path- and CRLF-sensitive assertions separator/line-ending neutral.
  • Make POSIX permission-bit assertions (0o600) POSIX-only — Node on Windows cannot represent them, so they asserted 0o666 and failed.
  • Isolate subprocess tests from the real user profile by setting both HOME and USERPROFILE, and remove inherited TESTSPRITE_* env vars case-insensitively.
  • Run subprocess build setup through the active npm entrypoint (with a Windows .cmd fallback) instead of assuming npm is directly spawnable.

Why the isolation fix matters beyond CI

While validating this patch we hit the failure mode in the wild: running the unpatched suite on a Windows machine with a real TestSprite profile overwrote ~/.testsprite/credentials with the test fixture (sk-keep-me @ http://127.0.0.1:14979), silently breaking every subsequent real CLI call with UNAVAILABLE: fetch failed until the file was restored by hand. The HOME/USERPROFILE isolation in this PR prevents that.

Tests

  • npm test — 50 files / 1846 tests pass on Windows 11 (Node 23) and under npx -p node@22.
  • npm run lint:fix, npm run typecheck, npm run build — all pass.

Summary by CodeRabbit

  • Tests
    • Improved test reliability when running build commands across different npm environments and operating systems.
    • Updated subprocess and help-output tests to use a shared npm execution approach.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b7770984-31cb-497d-a6d5-f32d093e3beb

📥 Commits

Reviewing files that changed from the base of the PR and between 5be8ecd and 8c53e78.

📒 Files selected for processing (1)
  • test/cli.subprocess.test.ts

Walkthrough

Adds a shared, platform-aware npm script runner and replaces direct npm build invocations in the CLI subprocess and help snapshot tests.

Changes

Npm test portability

Layer / File(s) Summary
Shared npm runner
test/helpers/npm.ts
Adds runNpmScript with environment- and platform-specific npm invocation.
Build setup migration
test/cli.subprocess.test.ts, test/help.snapshot.test.ts
Updates test setup to build the CLI through runNpmScript.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

Suggested reviewers: ruili-testsprite, zeshi-du

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly states the main change: making the Windows CLI test harness portable.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/agent-targets.test.ts`:
- Around line 39-40: Add a deterministic offline regression assertion in the
parser tests around the rawLine normalization loop, using frontmatter input with
explicit CRLF sequences such as "---\r\ndescription: ...\r\n---\r\n". Verify the
parsed result handles CRLF correctly, without relying on fixture files whose
line endings may vary.

In `@test/cli.subprocess.test.ts`:
- Line 371: Update childEnv used by the subprocess tests to remove all inherited
TESTSPRITE_* variables case-insensitively, including TESTSPRITE_PROFILE and any
future matching names. Apply explicit envOverrides afterward so test-provided
values are preserved, and keep the existing subprocess environment behavior
unchanged otherwise.

In `@test/helpers/npm.ts`:
- Around line 9-12: Update the Windows command selection in the execFileSync
invocation to run npm.cmd through cmd.exe with /d /s /c and preserve the
existing npm run script arguments; keep the non-Windows npm command path
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c87dc992-69cd-4ce7-b035-c6baa1e4b4a9

📥 Commits

Reviewing files that changed from the base of the PR and between 60d55e4 and 5be8ecd.

📒 Files selected for processing (8)
  • CANDIDATES.md
  • src/lib/agent-targets.test.ts
  • src/lib/bundle.test.ts
  • src/lib/credentials.test.ts
  • src/lib/skill-nudge.test.ts
  • test/cli.subprocess.test.ts
  • test/help.snapshot.test.ts
  • test/helpers/npm.ts

Comment thread src/lib/agent-targets.test.ts Outdated
Comment on lines +39 to +40
for (const rawLine of lines) {
const line = rawLine.replace(/\r$/, '');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add a deterministic CRLF regression case.

The parser change is correct, but the current fixture-based coverage may use LF files and never prove CRLF handling. Add an assertion using input such as ---\r\ndescription: ...\r\n---\r\n.

As per path instructions, tests must cover new behavior deterministically and offline.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/agent-targets.test.ts` around lines 39 - 40, Add a deterministic
offline regression assertion in the parser tests around the rawLine
normalization loop, using frontmatter input with explicit CRLF sequences such as
"---\r\ndescription: ...\r\n---\r\n". Verify the parsed result handles CRLF
correctly, without relying on fixture files whose line endings may vary.

Source: Path instructions

Comment thread test/cli.subprocess.test.ts Outdated
TESTSPRITE_API_URL: undefined,
...envOverrides,
} as NodeJS.ProcessEnv,
env: childEnv(envOverrides),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Scrub every inherited TESTSPRITE_* variable.

This loop removes only TESTSPRITE_API_KEY and TESTSPRITE_API_URL; an inherited TESTSPRITE_PROFILE can still alter profile resolution and make subprocess results depend on the host environment.

   const env = { ...process.env };
   for (const key of Object.keys(env)) {
-    if (key.toUpperCase() === 'TESTSPRITE_API_KEY' || key.toUpperCase() === 'TESTSPRITE_API_URL') {
+    if (key.toUpperCase().startsWith('TESTSPRITE_')) {
       delete env[key];
     }
   }

As per path instructions, subprocess tests must remove inherited TESTSPRITE_* environment variables case-insensitively while preserving explicit test overrides.

Also applies to: 382-388

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/cli.subprocess.test.ts` at line 371, Update childEnv used by the
subprocess tests to remove all inherited TESTSPRITE_* variables
case-insensitively, including TESTSPRITE_PROFILE and any future matching names.
Apply explicit envOverrides afterward so test-provided values are preserved, and
keep the existing subprocess environment behavior unchanged otherwise.

Source: Path instructions

Comment thread test/helpers/npm.ts
Comment on lines +9 to +12
execFileSync(process.platform === 'win32' ? 'npm.cmd' : 'npm', ['run', script], {
cwd,
stdio: 'pipe',
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
node <<'NODE'
const { execFileSync } = require('node:child_process');

if (process.platform === 'win32') {
  execFileSync(process.env.ComSpec || 'cmd.exe', ['/d', '/s', '/c', 'npm.cmd', '--version'], {
    stdio: 'inherit',
  });
}
NODE

Repository: TestSprite/testsprite-cli

Length of output: 163


Use cmd.exe for the Windows fallback

execFileSync('npm.cmd', ...) won’t launch the batch shim directly on Windows. If npm_execpath is unset here, this branch fails; use cmd.exe /d /s /c npm.cmd run <script> instead.

🧰 Tools
🪛 ast-grep (0.44.1)

[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { execFileSync } from 'node:child_process';
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/helpers/npm.ts` around lines 9 - 12, Update the Windows command
selection in the execFileSync invocation to run npm.cmd through cmd.exe with /d
/s /c and preserve the existing npm run script arguments; keep the non-Windows
npm command path unchanged.

Source: MCP tools

@jangjos-128

Copy link
Copy Markdown
Contributor Author

Hi @Yazan-O 👋 — this is the recovery of your PR #207 , which was auto-closed by an error in our 2026-07-09 release process. Your commits are intact — thank you for the contribution!

It currently shows merge conflicts because main has moved on since your branch was cut. To clear them, update your PR branch (BRANCH) against the latest main — either option works and both update this PR in place:

Option A — merge (no force-push):

git checkout BRANCH
git fetch upstream          # your remote for TestSprite/testsprite-cli (may be "origin")
git merge upstream/main     # resolve conflicts, commit
git push

Option B — rebase (cleaner history, needs force):

git checkout BRANCH
git fetch upstream
git rebase upstream/main    # resolve conflicts
git push --force-with-lease

Once you push, the conflicts here resolve automatically and we'll take it into review.

Sorry again for the extra step!

v0.3.0 independently landed most of this branch's Windows work, so the
overlapping parts are dropped in favour of upstream's versions:

- credentials.test.ts / cli.subprocess.test.ts: upstream's inline
  process.platform guards and HOME+USERPROFILE child env supersede the
  expectPosixMode()/childEnv() helpers here.
- skill-nudge.test.ts: upstream's toPosix() supersedes posixPath().
- agent-targets.test.ts: upstream's split(/\r?\n/) already drops the CRLF,
  which makes the per-line \r strip here a no-op.
- bundle.test.ts: upstream's resolveBundleDir assertion is stricter
  (adds isAbsolute); taken as-is.

What is left is the one thing v0.3.0 does not fix, which still stops the
suite from running on Windows at all:

  execFileSync('npm', ['run', 'build'], ...) throws "spawnSync npm ENOENT"
  on Windows, because npm is npm.cmd and execFileSync does not go through
  a shell. It fails the beforeAll() in both cli.subprocess.test.ts and
  help.snapshot.test.ts, so neither file can run.

test/helpers/npm.ts routes the build through process.env.npm_execpath with
the current node binary, falling back to npm.cmd / npm.

CANDIDATES.md is dropped; it was a working note, not part of the fix.

Verified on Windows: 50 files / 1859 passed, 1 skipped; typecheck + lint clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants