diff --git a/tests/bundle-route.spec.ts b/tests/bundle-route.spec.ts index 1585cd5..501585d 100644 --- a/tests/bundle-route.spec.ts +++ b/tests/bundle-route.spec.ts @@ -84,7 +84,12 @@ describe('/sidebar/bundle route', () => { try { const first = fakeRes() await handler(req('GET', '/sidebar/bundle/editor.js'), first as unknown as ServerResponse) - writeFileSync(join(dir, 'client-editor.js'), 'window.__ModuleLoader__ && 1;') + // The rewrite must change the LENGTH too: the ETag memo revalidates on + // stat (mtime+size), and Windows updates file timestamps lazily — an + // equal-size rewrite right after the first read can still look + // unchanged (stale 304). A size delta busts the memo deterministically + // on every platform. + writeFileSync(join(dir, 'client-editor.js'), 'window.__ModuleLoader__ && 1; // rotated') const second = fakeRes() await handler(req('GET', '/sidebar/bundle/editor.js', { 'if-none-match': first.headers.etag! }), second as unknown as ServerResponse) expect(second.status).toBe(200) diff --git a/tests/git-worktree.spec.ts b/tests/git-worktree.spec.ts index 2f4aca3..c0b4e2e 100644 --- a/tests/git-worktree.spec.ts +++ b/tests/git-worktree.spec.ts @@ -68,8 +68,11 @@ describe('linked Git worktrees', () => { git(main, ['worktree', 'add', '-q', '-b', 'agent', agent]) writeFileSync(join(agent, 'tracked.txt'), 'changed by agent\n') // macOS tmpdir() keeps the /var symlink while git reports the resolved - // /private/var prefix — canonicalize every path handed to git APIs. - const agentPath = realpathSync(agent) + // /private/var prefix; on Windows TEMP is often the 8.3 short form + // (C:\Users\RUNNER~1\...) while git reports the long path. The NATIVE + // realpath resolves both aliasings (libuv's GetFinalPathNameByHandle + // expands 8.3 names) — canonicalize every path handed to git APIs. + const agentPath = realpathSync.native(agent) const listed = await worktrees(main) expect(listed).toHaveLength(2) @@ -87,7 +90,7 @@ describe('linked Git worktrees', () => { rmSync(agent, { recursive: true, force: true }) const remaining = await worktrees(main) expect(remaining).toHaveLength(1) - expect(resolve(remaining[0]!.path)).toBe(resolve(realpathSync(main))) + expect(resolve(remaining[0]!.path)).toBe(resolve(realpathSync.native(main))) expect(remaining[0]!.current).toBe(true) await expect(resolveWorktree(main, agentPath)).rejects.toThrow('unknown linked worktree') } finally { diff --git a/tests/git.spec.ts b/tests/git.spec.ts index 9932d23..b5fccc6 100644 --- a/tests/git.spec.ts +++ b/tests/git.spec.ts @@ -11,8 +11,12 @@ import { parseLogLines, parsePorcelainZ, repoRoots, status } from '../src/git.ts const execFileAsync = promisify(execFile) const normalizePath = (path: string): string => path.replaceAll('\\', '/') // macOS tmpdir() is the /var symlink while git reports the resolved -// /private/var prefix — canonicalize both sides before comparing. -const canonical = (path: string): string => normalizePath(realpathSync(path)) +// /private/var prefix; on Windows TEMP is often the 8.3 short form +// (C:\Users\RUNNER~1\...) while git reports the long path. The NATIVE +// realpath resolves both aliasings (libuv canonicalizes on Windows via +// GetFinalPathNameByHandle, which expands 8.3 names) — canonicalize both +// sides before comparing. +const canonical = (path: string): string => normalizePath(realpathSync.native(path)) describe('git parsing', () => { it('discovers and selects direct child repositories under a workspace directory', async () => { diff --git a/tests/market-manifest.spec.ts b/tests/market-manifest.spec.ts index 945e459..0c30693 100644 --- a/tests/market-manifest.spec.ts +++ b/tests/market-manifest.spec.ts @@ -57,7 +57,10 @@ function packedManifest(): Record { // spawn directly (ENOENT). Run it through the shell so the same call // works on every platform; `tar` is available on all supported OSes. execFileSync('pnpm', ['pack', '--pack-destination', dir], { cwd: ROOT, stdio: 'pipe', shell: process.platform === 'win32' }) - execFileSync('tar', ['-xzf', join(dir, `${pkg.name}-${pkg.version}.tgz`), '-C', dir, 'package/package.json'], { stdio: 'pipe' }) + // Never hand tar an absolute Windows path: Git Bash's GNU tar reads the + // drive-letter colon as a remote-host spec ("Cannot connect to C:"). + // Run it from the pack dir with the bare tarball name instead. + execFileSync('tar', ['-xzf', `${pkg.name}-${pkg.version}.tgz`, 'package/package.json'], { cwd: dir, stdio: 'pipe' }) return JSON.parse(readFileSync(join(dir, 'package/package.json'), 'utf8')) as Record } finally { rmSync(dir, { recursive: true, force: true }) diff --git a/tests/smoke.spec.ts b/tests/smoke.spec.ts index 990edad..99a834d 100644 --- a/tests/smoke.spec.ts +++ b/tests/smoke.spec.ts @@ -409,6 +409,12 @@ describe('git destructive operations (scratch repository)', () => { const makeScratchRepo = (): string => { const dir = mkdtempSync(join(tmpdir(), 'dsh-sidebar-git-')) gitRun(dir, ['init', '-q']) + // Pin the eol policy: Git for Windows defaults to core.autocrlf=true + // (system gitconfig on the CI runner, and many dev machines), which + // smudges LF→CRLF on every index restore and breaks the byte-exact + // assertions below. The destructive-op behavior under test is orthogonal + // to the machine's eol policy. + gitRun(dir, ['config', 'core.autocrlf', 'false']) gitRun(dir, ['checkout', '-q', '-b', 'main']) writeFileSync(join(dir, 'a.txt'), 'one\ntwo\nthree\n') gitRun(dir, ['add', '-A'])