Skip to content

claude-code-chat-browser: Add windows-latest to CI test matrix #61

@clean6378-max-it

Description

@clean6378-max-it

Planned Effort

5 story points — sprint item #2 (Medium): Windows CI coverage — add windows-latest to .github/workflows matrix

Depends on: Ubuntu CI green on master (or Tuesday PR branch rebased on green baseline). Tuesday dispatch registry (#1) can be in review in parallel; finish review fixes before merging CI if both PRs are open.

Problem

All five jobs in .github/workflows/ci.yml run on ubuntu-latest only. Two production code paths diverge on Windows but are never exercised on a real Windows runner:

  1. Cross-process export state locking (utils/export_state_store.py) — Unix uses fcntl.flock; Windows uses msvcrt.locking on a sidecar *.lock file. tests/test_export_state_store.py mocks msvcrt when fcntl is patched away on Linux; the real msvcrt path never runs in CI.

  2. Claude projects home directory (utils/session_path.py) — get_claude_projects_dir() prefers USERPROFILE on Windows vs HOME on Unix. Tests set both vars in _isolated_home_env() for subprocess CLI runs, but platform.system() == "Windows" branch is not validated on a Windows runner.

Goal

Run the same pytest, integration + coverage, and Vitest suites on windows-latest and ubuntu-latest, with targeted tests that prove the Windows-specific branches work on native Windows.

Scope

1. CI workflow matrix

Update .github/workflows/ci.yml:

Job Change
pytest strategy.matrix.os: [ubuntu-latest, windows-latest]
integration-tests Same matrix; use distinct coverage artifact name per OS (e.g. coverage-report-${{ matrix.os }})
js-tests Same matrix (npm ci + npm test)
prod-install-smoke Keep ubuntu-latest only (bash heredoc boot script; no Windows value)
mypy Keep ubuntu-latest only (type-check is OS-agnostic; avoids duplicate slow job)

Use Python 3.12 and Node 20 on both OSes (match current Ubuntu pins).

Windows workflow notes:

  • GitHub windows-latest uses PowerShell by default — keep run: steps as single-line pip / pytest / npm commands (no bash-only heredocs in matrix jobs).
  • Set fail-fast: false on matrix so one OS failure does not cancel the other.
  • If a test is genuinely Unix-only (rare), gate with @pytest.mark.skipif(sys.platform == "win32", ...) and document why — do not skip the whole suite.

2. Platform-specific tests (add or extend)

A — Real msvcrt on Windows (new test in tests/test_export_state_store.py or tests/test_export_state_lock_windows.py):

@pytest.mark.skipif(sys.platform != "win32", reason="requires Windows msvcrt")
def test_export_state_lock_uses_real_msvcrt(tmp_path: Path) -> None:
    ...
  • Call export_state_lock() without monkeypatching fcntl / msvcrt.
  • On win32, fcntl is absent and real msvcrt.locking must acquire and release — e.g. with export_state_lock(path): atomic_write_export_state(...) then load_export_state_from_disk(path).

B — USERPROFILE resolution (new test in tests/test_session_path.py):

  • Option 1 (portable): monkeypatch.setattr(platform, "system", lambda: "Windows"), set USERPROFILE to a temp path, unset or ignore HOME, assert get_claude_projects_dir() ends with .claude\projects under that profile.
  • Option 2 (runner-native): @pytest.mark.skipif(sys.platform != "win32") set USERPROFILE to tmp_path and assert path on real Windows job.

At least one test must satisfy acceptance: USERPROFILE path resolution tested on Windows runner (Option 2 strongest; Option 1 + green Windows matrix also acceptable if Option 2 is included).

3. Documentation

  • README.md or CONTRIBUTING.md: CI badge or one line — tests run on Ubuntu + Windows.
  • Optional: docs/architecture.md or export-state section — one sentence that export locking uses fcntl (POSIX) / msvcrt (Windows).

4. Fix failures discovered on Windows

Common fixes when matrix first goes green locally on Windows:

Area Typical fix
Path separators Prefer pathlib.Path or os.path.join in test fixtures
Line endings .gitattributes / core.autocrlf — ensure tests open files with encoding="utf-8"
Subprocess CLI Already uses PYTHONUTF8=1 in test_cli_e2e._cli_env() — extend to any new subprocess tests
Lock file Ensure export_state_lock creates non-empty lock file before msvcrt.locking (see utils/export_state_store.py lines 71–79)

Acceptance Criteria

  • windows-latest added to CI matrix for pytest, integration-tests, and js-tests
  • Platform-specific locking tests exercise real msvcrt path on Windows (not only FakeMsvcrt monkeypatch)
  • USERPROFILE path resolution tested on Windows runner (native and/or explicit Windows branch test)
  • All existing tests pass on both ubuntu-latest and windows-latest
  • README or CONTRIBUTING notes cross-platform CI

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions