Skip to content

fix: make test suite pass on Windows (path separators + URL.pathname)#3234

Open
GeekLuffy wants to merge 2 commits into
facebook:mainfrom
GeekLuffy:fix/windows-test-compat
Open

fix: make test suite pass on Windows (path separators + URL.pathname)#3234
GeekLuffy wants to merge 2 commits into
facebook:mainfrom
GeekLuffy:fix/windows-test-compat

Conversation

@GeekLuffy

Copy link
Copy Markdown

What

Fixes test suite failures when running on Windows. All affected tests
pass on macOS/Linux but fail on Windows due to OS-specific path handling.

Fixes #3233

Root Causes & Fixes

1. Snapshot serializer stack overflow (internal/test-utils/src/setup.ts)

The custom Vitest snapshot serializer's test() matched every DOM node.
When printer() serialized child nodes it called test() recursively,
causing Maximum call stack size exceeded. Fixed with an isNormalizing
re-entrance guard.

2. NTFS case-insensitive false match (derivedVarRegistry.test.ts)

existsSync('theme/Theme.doc.mjs') returned true on Windows because
NTFS is case-insensitive, so the theme/ utility directory was scanned
as a component, producing false --border-width undocumented-var failures.
Fixed using readdirSync().includes() for a case-sensitive check.

3. URL.pathname leading slash on Windows (doctor.test.mjs)

new URL(import.meta.url).pathname returns /C:/Users/... on Windows
with a spurious leading /, causing fs.mkdtempSync to fail with ENOENT.
Replaced with fileURLToPath(import.meta.url) from node:url.

4. Backslash path separators (CLI source + tests)

path.join() uses \ on Windows. Category strings and regex assertions
failed. Normalized separators to / in source files; updated test regexes
to accept both [/\\].

Testing

Test file Before After
FormLayout.test.tsx ❌ 3 failed (stack overflow) ✅ 17/17
derivedVarRegistry.test.ts ❌ failed (--border-width) ✅ 8/8
component-resolution.test.mjs ❌ path regex failures ✅ 21/21
doctor.test.mjs ❌ ENOENT mkdtemp ✅ 24/24

Four categories of Windows-specific failures fixed:

1. Snapshot serializer (setup.ts): add isNormalizing re-entrance guard
   to prevent infinite recursion when printer calls test on child DOM nodes.

2. derivedVarRegistry.test.ts: replace existsSync with case-sensitive
   readdirSync().includes() so the NTFS case-insensitive filesystem does
   not match theme/Theme.doc.mjs for the lowercase theme directory,
   causing false --border-width undocumented-var failures.

3. doctor.test.mjs: replace new URL(import.meta.url).pathname with
   fileURLToPath(import.meta.url) so mkdtemp receives a valid Windows
   path instead of /C:/... with a spurious leading slash.

4. component-discovery.mjs / component.mjs / template.mjs: normalize
   path separators to forward slashes so category strings and file-path
   logic work cross-platform. component-resolution.test.mjs and
   swizzle-gap-safety.test.mjs: update path regex assertions to accept
   both / and \ separators.
@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

@GeekLuffy is attempting to deploy a commit to the Meta Open Source Team on Vercel.

A member of the Team first needs to authorize it.

@meta-cla

meta-cla Bot commented Jun 29, 2026

Copy link
Copy Markdown

Hi @GeekLuffy!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks!

@meta-cla

meta-cla Bot commented Jun 29, 2026

Copy link
Copy Markdown

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Jun 29, 2026
@GeekLuffy

Copy link
Copy Markdown
Author

@cixzhang @thedjpetersen I have pushed a fix for the ESLint error in swizzle-gap-safety.test.mjs.

The template literal escape sequence has been updated to remove the unnecessary escape character \" which was causing the linter check to fail in CI.

@cixzhang

Copy link
Copy Markdown
Contributor

Thanks for tackling this. Hmm I'm missing a windows machine to help test this but let me check around.

@GeekLuffy GeekLuffy force-pushed the fix/windows-test-compat branch from 2017c85 to ba5b71a Compare June 30, 2026 05:24
@GeekLuffy

Copy link
Copy Markdown
Author

Thanks for tackling this. Hmm I'm missing a windows machine to help test this but let me check around.

No worries! I am running this on a Windows machine locally and have verified that the changes fix the path resolution issues. The entire vitest CLI test suite now compiles and passes successfully without any failures.

@nynexman4464 nynexman4464 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for tackling this — the four diagnoses are well-described and the fixes look clean. The snapshot recursion guard in particular is a nice approach.

A few findings worth raising before merge (I verified the Windows behavior together with my agent — commands shown so you can repro):

  1. agent-docs.test.mjs (6 failures) — same family of path-separator bug this PR is fixing, missed at one site. Ran in isolation on Windows:

    pnpm vitest run packages/cli/src/commands/agent-docs.test.mjs --reporter=default

    All 6 fail in single-digit ms (not timeouts) with assertions like expected [ '.claude\CLAUDE.md' ] to deeply equal [ '.claude/CLAUDE.md' ]. Traces to packages/cli/src/commands/agent-docs.mjs:32:

    const CLAUDE_DIR_MD = path.join('.claude', 'CLAUDE.md');  // → ".claude\CLAUDE.md" on Windows

    Same fix pattern as template.mjs — either a literal '.claude/CLAUDE.md' or .replace(/\\/g, '/') drops all 6.

  2. component-package.test.mjs + external-showcase.test.mjs (12 failures) — same class of cross-platform fs issue, different mechanism. Verified with:

    pnpm vitest run packages/cli/src/commands/component-package.test.mjs --reporter=default

    All fail in single-digit ms with Error: EPERM: operation not permitted, symlink from fs.symlinkSync(). Windows requires Developer Mode (or admin) for symlinks; on a default install they EPERM. Fix is typically fs.symlinkSync(target, path, 'junction') for directory symlinks, which doesn't need elevation. I'll follow up on this separately unless you'd prefer to include it in this PR.

  3. component-resolution > Badge resolves to Badge dir from the after-patch run is a timing flake, not a real failure. Reproduced with:

    pnpm vitest run packages/cli/src/commands/component-resolution.test.mjs --reporter=default     # passes 21/21, Badge at ~4.7s
    pnpm vitest run packages/cli/src/commands --reporter=default                                    # Badge fails at 5055ms — 5s timeout overshoot

    The PR's path-separator fix for this test is correct; the remaining failure is hardware/parallel-load sensitive. Worth either raising vitest's default testTimeout for these heavier tests or removing it from the "still failing" count.

  4. Minor PR description note: the resolveImportPath case-insensitive lookup is a behavior change on every platform, not just Windows — astryx component Theme@astryxdesign/core/theme now works on Linux too. It's the right behavior (there's a test that expects it), just scoped broader than the PR title implies. A line in the description would help reviewers.

One inline note on the csc.exe shim too. The agent-docs fix is the only one that's the same class as what this PR is doing — the rest can be follow-ups.

`;
const csPath = path.join(shimDir, 'gh.cs');
fs.writeFileSync(csPath, csCode);
const compileResult = spawnSync('C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\csc.exe', [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Small portability tweak — %WINDIR% is the documented way to reference the Windows directory, since users can install Windows on D: or elsewhere:

const cscPath = path.join(
  process.env.WINDIR || 'C:\\Windows',
  'Microsoft.NET\\Framework\\v4.0.30319\\csc.exe',
);

The v4.0.30319 version itself isn't really brittle — that path has been frozen since 2010 across all .NET Framework 4.x in-place upgrades, and Microsoft's own docs reference it directly (ref). A short code comment noting that would help future readers know the magic number is intentional. Not blocking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Test suite fails on Windows due to path separator and URL.pathname issues

3 participants