Skip to content

Conversation

@paul-sachs
Copy link
Contributor

@paul-sachs paul-sachs commented Oct 17, 2025

When expanding a splat, undefined should be handled exactly like if the _splat param didn't exist at all. This allows consistent handling of _splat routes to ensure that trailing slashes are kept or dropped according to the spec.

Fixes #5385

Summary by CodeRabbit

  • Bug Fixes

    • Consistent handling of empty, undefined, or omitted "splat" segments so routes, links, and navigation resolve predictably across trailing-slash settings.
  • New Features

    • Trailing-slash behavior is now exposed and configurable, making URL trailing-slash handling explicit.
  • Tests

    • Added end-to-end tests covering splat-route link generation and navigation for empty, undefined, and missing splat values across trailing-slash modes.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 17, 2025

Warning

Rate limit exceeded

@nlynzaad has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 5 minutes and 7 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between b26e9b7 and d55f44c.

📒 Files selected for processing (1)
  • packages/solid-router/tests/navigate.test.tsx (2 hunks)

Walkthrough

Treats empty or falsy _splat as missing during path interpolation, adds a trailingSlashOptions const and derived TrailingSlashOption type (exported), re-exports it, and adds parameterized tests across router-core, react-router, and solid-router validating behavior for empty/undefined/missing splat with trailingSlash options.

Changes

Cohort / File(s) Summary
Core path logic & exports
packages/router-core/src/path.ts, packages/router-core/src/router.ts, packages/router-core/src/index.ts
interpolatePath now treats falsy _splat values as missing (changes wildcard insertion logic); added trailingSlashOptions const and derived TrailingSlashOption type; re-exported trailingSlashOptions from package index.
Core tests
packages/router-core/tests/path.test.ts
Added tests asserting interpolatePath omits splat and marks params missing when _splat is "" or undefined.
React Router tests
packages/react-router/tests/link.test.tsx, packages/react-router/tests/navigate.test.tsx, packages/react-router/tests/useNavigate.test.tsx
Added parameterized "splat routes with empty splat" suites using trailingSlashOptions that check href/pathname generation, navigation, and active-route behavior for _splat values "", undefined, and omitted across trailing-slash options. (Duplicate suites appear in diff.)
Solid Router tests
packages/solid-router/tests/link.test.tsx, packages/solid-router/tests/navigate.test.tsx, packages/solid-router/tests/useNavigate.test.tsx
Added parameterized "splat routes with empty splat" suites using trailingSlashOptions validating href/pathname generation and navigation for _splat values "", undefined, and omitted across trailing-slash options. (Duplicate suites appear in diff.)

Sequence Diagram(s)

sequenceDiagram
  participant Caller as Link / Navigate / Router
  participant Interpolator as interpolatePath()
  participant Config as trailingSlashOptions

  Note over Caller,Interpolator: Build path for a splat route (template contains `$`)
  Caller->>Interpolator: interpolate(pathTemplate, params, leaveWildcards?)
  alt params._splat is truthy
    Interpolator->>Interpolator: encode & insert splat segment
    Interpolator-->>Caller: path including encoded splat
  else params._splat is missing or falsy
    Interpolator->>Interpolator: treat splat as missing -> omit wildcard segment/prefix
    Interpolator-->>Caller: base path without splat
  end
  Caller->>Config: read trailingSlash option
  Config-->>Caller: append or omit trailing slash according to option
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • schiller-manuel

Poem

🐰 A little splat, now gently missed,
Empty hops where pathways twist,
Trailing slashes checked and neat,
Tests hop in on nimble feet,
The rabbit grins — no "undefined" to greet. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "fix(router-core): add support for handling any kind of empty _splat consistently" is clear, concise, and accurately summarizes the primary change. It directly identifies both the package being modified (router-core) and the core objective (consistent handling of empty _splat values). The title is specific enough that teammates scanning the history would understand that this PR addresses splat parameter handling rather than using vague terminology.
Linked Issues Check ✅ Passed The code changes comprehensively address the requirements from issue #5385. The core fix in packages/router-core/src/path.ts changes the _splat validation from a property existence check to a truthy check, ensuring that empty strings and undefined values are treated as missing parameters and do not render the literal string "undefined" or generate incorrect trailing slashes. The PR introduces the trailingSlashOptions constant to enable consistent parameterized testing across all trailingSlash configurations (always, never, preserve), and includes extensive test coverage across all three frameworks (react-router, solid-router) and all navigation methods (Link, navigate, useNavigate) as requested by reviewers. This directly satisfies the requirement that splat routes respect the configured trailingSlash specification.
Out of Scope Changes Check ✅ Passed All changes in the pull request are directly scoped to addressing issue #5385. The core logic fix in path.ts, the supporting type and constant definitions in router.ts and index.ts, and the comprehensive test suites across react-router and solid-router test files are all essential to implementing and validating the consistent handling of empty _splat parameters across different trailingSlash configurations. No changes appear to introduce functionality, features, or modifications unrelated to fixing the splat route handling behavior described in the linked issue.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

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 and usage tips.

@paul-sachs paul-sachs changed the title Add support for handling any kind of empty _splat consistently fix(router-core): add support for handling any kind of empty _splat consistently Oct 17, 2025
@schiller-manuel
Copy link
Contributor

for which scenarios is this relevant? navigating an setting _splat to e.g. undefined?
we should add tests for those scenarios as well

@nlynzaad
Copy link
Contributor

nlynzaad commented Oct 19, 2025

thanks for the unit tests on path and Link, as Manuel mentioned please add tests for navigate as well, both useNavigate and navigate, just to ensure consistency.

Apart from that it's a go from me.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/react-router/tests/navigate.test.tsx (3)

1250-1250: Keep createRootRoute usage consistent.

Elsewhere in this file you call createRootRoute({}). Mirror that here to avoid accidental reliance on defaulted options.

Apply:

-      const rootRoute = createRootRoute()
+      const rootRoute = createRootRoute({})

1270-1287: Add a case that clears an existing non-empty splat.

Also verify that navigating from "/splat/foo" (or deeper) to an empty/omitted _splat lands on "/splat" (or "/splat/") per trailingSlash. This guards interpolation when removing segments, not just building from root.

Append inside this describe('splat routes with empty splat', ...):

+  it.each([{ trailingSlash: true }, { trailingSlash: false }])(
+    'clears a non-empty _splat with trailingSlash: $trailingSlash',
+    async ({ trailingSlash }) => {
+      const tail = trailingSlash ? '/' : ''
+      const history = createMemoryHistory({ initialEntries: ['/splat/foo/bar'] })
+      const rootRoute = createRootRoute({})
+      const indexRoute = createRoute({ getParentRoute: () => rootRoute, path: '/' })
+      const splatRoute = createRoute({ getParentRoute: () => rootRoute, path: 'splat/$' })
+      const router = createRouter({
+        routeTree: rootRoute.addChildren([indexRoute, splatRoute]),
+        history,
+        trailingSlash: trailingSlash ? 'always' : 'never',
+      })
+      await router.load()
+      // Clear via '', undefined, and omission
+      for (const params of [{ _splat: '' }, { _splat: undefined }, {}]) {
+        await router.navigate({ to: '/splat/$', params })
+        await router.invalidate()
+        expect(router.state.location.pathname).toBe(`/splat${tail}`)
+      }
+    },
+  )

1242-1290: Add a useNavigate parity test.

Reviewers asked for both programmatic navigate and hook-based navigation. Please add a React-level test that calls useNavigate() with { to: '/splat/$', params: { _splat: undefined } } and asserts the same pathname outcomes for 'always'/'never'. I can help wire a minimal render harness if you don’t have one handy.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c35c88c and 3e11ca1.

📒 Files selected for processing (1)
  • packages/react-router/tests/navigate.test.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/react-router/tests/navigate.test.tsx
packages/{react-router,solid-router}/**

📄 CodeRabbit inference engine (AGENTS.md)

Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Files:

  • packages/react-router/tests/navigate.test.tsx
🧠 Learnings (1)
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
PR: TanStack/router#5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/react-router/tests/navigate.test.tsx
🧬 Code graph analysis (1)
packages/react-router/tests/navigate.test.tsx (2)
packages/history/src/index.ts (1)
  • createMemoryHistory (568-614)
packages/react-router/src/router.ts (1)
  • createRouter (80-82)
🔇 Additional comments (1)
packages/react-router/tests/navigate.test.tsx (1)

1242-1290: Good coverage for empty/undefined/omitted _splat across trailingSlash policies.

Scenario matrix and back-to-index reset make the assertions robust. This directly guards against "/undefined" regressions and enforces 'always' vs 'never'.

@paul-sachs
Copy link
Contributor Author

@schiller-manuel Added additional test coverage. I followed the suggestions of CodeRabbit as well, to better cover trailingSlash potential options even though I know preserve doesn't really make that much of a difference but it was easy enough to modify so might as well test it.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/react-router/tests/navigate.test.tsx (1)

1242-1290: Great coverage for empty/undefined/omitted _splat across all trailingSlash modes.

Behavior matches the spec and prevents /undefined regressions. Optional: factor the matrix into a typed constant to drop the casts and reuse across files:

const trailingSlashCases = (['preserve','always','never'] as const).map((t) => ({ trailingSlash: t }))
packages/react-router/tests/useNavigate.test.tsx (1)

2559-2680: Solid navigate-path coverage for empty _splat via useNavigate.

Asserts match expectations for 'preserve'/'always'/'never' and properly reset between runs. Consider extracting a shared typed matrix to remove repeated casts, mirroring the navigate and link tests.

packages/react-router/tests/link.test.tsx (1)

5552-5643: Href + active-state assertions for splat links are on point.

This closes the loop on Link behavior for empty/undefined/omitted _splat. If you want to DRY the three files, consider a small helper to supply the trailingSlash cases and expected tail.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cc7d00 and 3ec9c9d.

📒 Files selected for processing (3)
  • packages/react-router/tests/link.test.tsx (2 hunks)
  • packages/react-router/tests/navigate.test.tsx (2 hunks)
  • packages/react-router/tests/useNavigate.test.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/react-router/tests/useNavigate.test.tsx
  • packages/react-router/tests/navigate.test.tsx
  • packages/react-router/tests/link.test.tsx
packages/{react-router,solid-router}/**

📄 CodeRabbit inference engine (AGENTS.md)

Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Files:

  • packages/react-router/tests/useNavigate.test.tsx
  • packages/react-router/tests/navigate.test.tsx
  • packages/react-router/tests/link.test.tsx
🧠 Learnings (2)
📚 Learning: 2025-09-28T21:41:45.233Z
Learnt from: nlynzaad
PR: TanStack/router#5284
File: e2e/react-start/basic/server.js:50-0
Timestamp: 2025-09-28T21:41:45.233Z
Learning: In Express v5, catch-all routes must use named wildcards. Use `/*splat` to match everything except root path, or `/{*splat}` (with braces) to match including root path. The old `*` syntax is not allowed and will cause "Missing parameter name" errors. This breaking change requires explicit naming of wildcard parameters.

Applied to files:

  • packages/react-router/tests/useNavigate.test.tsx
  • packages/react-router/tests/navigate.test.tsx
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
PR: TanStack/router#5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/react-router/tests/navigate.test.tsx
  • packages/react-router/tests/link.test.tsx
🧬 Code graph analysis (3)
packages/react-router/tests/useNavigate.test.tsx (1)
packages/router-core/src/router.ts (1)
  • TrailingSlashOption (800-800)
packages/react-router/tests/navigate.test.tsx (3)
packages/router-core/src/router.ts (1)
  • TrailingSlashOption (800-800)
packages/react-router/src/index.tsx (5)
  • TrailingSlashOption (80-80)
  • createMemoryHistory (118-118)
  • createRootRoute (258-258)
  • createRoute (255-255)
  • createRouter (273-273)
packages/history/src/index.ts (1)
  • createMemoryHistory (568-614)
packages/react-router/tests/link.test.tsx (2)
packages/router-core/src/router.ts (1)
  • TrailingSlashOption (800-800)
packages/react-router/src/router.ts (1)
  • createRouter (80-82)
🔇 Additional comments (3)
packages/react-router/tests/navigate.test.tsx (1)

9-9: Type import looks good.

Importing TrailingSlashOption from the public surface is correct and keeps tests strongly typed.

packages/react-router/tests/useNavigate.test.tsx (1)

26-26: Type import is appropriate.

Using TrailingSlashOption here keeps the parameterized tests precise.

packages/react-router/tests/link.test.tsx (1)

44-44: Type import is fine.

Keeps tests aligned with the public API surface.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/react-router/tests/link.test.tsx (1)

5553-5644: LGTM: Thorough Link component test for empty splat handling.

This test validates that the Link component generates consistent hrefs for empty, undefined, and omitted _splat parameters across all trailingSlash configurations. The activation check (lines 5637-5639) confirms the router correctly recognizes all three link variants as pointing to the same route.

Potential duplication concern: The AI summary indicates this test suite may be duplicated in the file. If so, please remove the duplicate to avoid redundant test execution and maintenance overhead.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ec9c9d and 1b5b17c.

📒 Files selected for processing (4)
  • packages/react-router/tests/link.test.tsx (2 hunks)
  • packages/react-router/tests/navigate.test.tsx (2 hunks)
  • packages/react-router/tests/useNavigate.test.tsx (3 hunks)
  • packages/react-router/tests/utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/react-router/tests/useNavigate.test.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/react-router/tests/utils.ts
  • packages/react-router/tests/navigate.test.tsx
  • packages/react-router/tests/link.test.tsx
packages/{react-router,solid-router}/**

📄 CodeRabbit inference engine (AGENTS.md)

Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Files:

  • packages/react-router/tests/utils.ts
  • packages/react-router/tests/navigate.test.tsx
  • packages/react-router/tests/link.test.tsx
🧠 Learnings (1)
📓 Common learnings
Learnt from: nlynzaad
PR: TanStack/router#5284
File: e2e/react-start/basic/server.js:50-0
Timestamp: 2025-09-28T21:41:45.233Z
Learning: In Express v5, catch-all routes must use named wildcards. Use `/*splat` to match everything except root path, or `/{*splat}` (with braces) to match including root path. The old `*` syntax is not allowed and will cause "Missing parameter name" errors. This breaking change requires explicit naming of wildcard parameters.
🧬 Code graph analysis (2)
packages/react-router/tests/navigate.test.tsx (2)
packages/react-router/tests/utils.ts (1)
  • trailingSlashCases (58-58)
packages/history/src/index.ts (1)
  • createMemoryHistory (568-614)
packages/react-router/tests/link.test.tsx (1)
packages/react-router/tests/utils.ts (1)
  • trailingSlashCases (58-58)
🔇 Additional comments (2)
packages/react-router/tests/utils.ts (1)

57-58: LGTM: Clean test utility for trailing slash parameterization.

This provides a single source of truth for testing all three trailing slash modes across the test suites. The const assertion ensures proper type inference.

packages/react-router/tests/navigate.test.tsx (1)

1243-1291: LGTM: Comprehensive test coverage for empty splat navigation.

This test validates that empty string, undefined, and omitted _splat parameters all produce consistent navigation behavior across all trailingSlash configurations. The iteration through param sets with cleanup (navigating back to index) ensures test isolation.

Note on preserve mode (line 1247): The test treats 'preserve' the same as 'never' (no trailing slash). This is likely correct for programmatic navigation where there's no "user-typed" URL to preserve, but worth confirming this aligns with the router's intended behavior for the preserve mode.

@nlynzaad
Copy link
Contributor

@paul-sachs thanks a lot for this.

I made some minor updates:

  1. exported the constant from router-core so it can be reused more globally
  2. replicated the tests for solid js

@nx-cloud
Copy link

nx-cloud bot commented Oct 20, 2025

View your CI Pipeline Execution ↗ for commit d55f44c

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 1m 44s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 35s View ↗

☁️ Nx Cloud last updated this comment at 2025-10-20 23:12:49 UTC

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/solid-router/tests/useNavigate.test.tsx (1)

2528-2647: Stabilize event timing; add defensive assertion

  • Don’t wrap fireEvent.click/history.push inside waitFor. Click/push first, then waitFor on resulting state to reduce flakes.
  • Also assert pathname never contains "undefined" to lock the regression.

Apply this representative diff to the three interactions:

- await waitFor(() => {
-   fireEvent.click(splatBtnWithEmptySplat)
- })
+ fireEvent.click(splatBtnWithEmptySplat)
+ await waitFor(() => expect(window.location.pathname).toBe(`/splat${tail}`))
+ expect(window.location.pathname).not.toContain('undefined')

- await waitFor(() => {
-   history.push('/')
- })
+ history.push('/')
+ await waitFor(() => expect(window.location.pathname).toBe('/'))
packages/solid-router/tests/navigate.test.tsx (1)

572-624: Harden expectations for the splat permutations

Current checks are solid. Consider adding:

  • A negative assertion against “undefined” in the path.
  • Optional: type paramSets to make intent explicit.

Example tweak:

- const paramSets = [
+ const paramSets: Array<Partial<{ _splat: string }>> = [
   { _splat: '' },
   { _splat: undefined },
   {},
 ]
 ...
 expect(router.state.location.pathname).toBe(`/splat${tail}`)
+expect(router.state.location.pathname).not.toContain('undefined')
packages/react-router/tests/link.test.tsx (1)

5553-5641: Strengthen assertions; minor readability

  • Add a negative assertion to ensure no “undefined” leaks into href/path.
  • Optional: factor expectedHref = /splat${tail} to avoid repetition.

Example additions:

expect(splatLinkWithEmptySplat.getAttribute('href')).toBe(`/splat${tail}`)
+expect(splatLinkWithEmptySplat.getAttribute('href')).not.toMatch(/undefined/)
...
expect(window.location.pathname).toBe(`/splat${tail}`)
+expect(window.location.pathname).not.toMatch(/undefined/)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b5b17c and 92a1269.

📒 Files selected for processing (8)
  • packages/react-router/tests/link.test.tsx (2 hunks)
  • packages/react-router/tests/navigate.test.tsx (2 hunks)
  • packages/react-router/tests/useNavigate.test.tsx (2 hunks)
  • packages/router-core/src/index.ts (1 hunks)
  • packages/router-core/src/router.ts (1 hunks)
  • packages/solid-router/tests/link.test.tsx (2 hunks)
  • packages/solid-router/tests/navigate.test.tsx (2 hunks)
  • packages/solid-router/tests/useNavigate.test.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-core/src/index.ts
  • packages/solid-router/tests/useNavigate.test.tsx
  • packages/react-router/tests/navigate.test.tsx
  • packages/router-core/src/router.ts
  • packages/solid-router/tests/navigate.test.tsx
  • packages/react-router/tests/useNavigate.test.tsx
  • packages/solid-router/tests/link.test.tsx
  • packages/react-router/tests/link.test.tsx
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep framework-agnostic core router logic in packages/router-core/

Files:

  • packages/router-core/src/index.ts
  • packages/router-core/src/router.ts
packages/{react-router,solid-router}/**

📄 CodeRabbit inference engine (AGENTS.md)

Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Files:

  • packages/solid-router/tests/useNavigate.test.tsx
  • packages/react-router/tests/navigate.test.tsx
  • packages/solid-router/tests/navigate.test.tsx
  • packages/react-router/tests/useNavigate.test.tsx
  • packages/solid-router/tests/link.test.tsx
  • packages/react-router/tests/link.test.tsx
🧠 Learnings (1)
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
PR: TanStack/router#5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/solid-router/tests/useNavigate.test.tsx
  • packages/react-router/tests/navigate.test.tsx
  • packages/solid-router/tests/navigate.test.tsx
  • packages/solid-router/tests/link.test.tsx
🧬 Code graph analysis (7)
packages/solid-router/tests/useNavigate.test.tsx (2)
packages/router-core/src/router.ts (1)
  • trailingSlashOptions (800-804)
packages/solid-router/src/useNavigate.tsx (1)
  • useNavigate (11-25)
packages/react-router/tests/navigate.test.tsx (3)
packages/router-core/src/router.ts (1)
  • trailingSlashOptions (800-804)
packages/history/src/index.ts (1)
  • createMemoryHistory (568-614)
packages/react-router/src/router.ts (1)
  • createRouter (91-93)
packages/router-core/src/router.ts (3)
packages/router-core/src/index.ts (2)
  • trailingSlashOptions (207-207)
  • TrailingSlashOption (212-212)
packages/react-router/src/index.tsx (1)
  • TrailingSlashOption (80-80)
packages/solid-router/src/index.tsx (1)
  • TrailingSlashOption (79-79)
packages/solid-router/tests/navigate.test.tsx (1)
packages/solid-router/src/router.ts (1)
  • createRouter (76-78)
packages/react-router/tests/useNavigate.test.tsx (1)
packages/router-core/src/router.ts (1)
  • trailingSlashOptions (800-804)
packages/solid-router/tests/link.test.tsx (1)
packages/router-core/src/router.ts (1)
  • trailingSlashOptions (800-804)
packages/react-router/tests/link.test.tsx (2)
packages/router-core/src/router.ts (1)
  • trailingSlashOptions (800-804)
packages/react-router/src/router.ts (1)
  • createRouter (91-93)
🔇 Additional comments (9)
packages/router-core/src/index.ts (1)

199-209: Expose trailingSlashOptions in public API — good addition

Matches router.ts const and unblocks cross-package tests/imports. No issues.

packages/solid-router/tests/useNavigate.test.tsx (1)

13-13: Import source for trailingSlashOptions — OK

Public export is available; import looks correct.

packages/solid-router/tests/navigate.test.tsx (1)

3-3: Import of trailingSlashOptions — OK

Consistent with router-core export.

packages/react-router/tests/link.test.tsx (1)

15-15: Import of trailingSlashOptions — OK

Matches new public export.

packages/react-router/tests/navigate.test.tsx (1)

1243-1294: Great coverage for splat edge cases

Exercising empty/undefined/missing _splat across every trailingSlash mode (via Object.values(trailingSlashOptions)) is a nice way to lock the regression fix and guard future modes automatically.

packages/solid-router/tests/link.test.tsx (1)

5089-5177: Solid link parity looks solid

Thanks for mirroring the React coverage here—asserting both the generated hrefs and active-state behaviour across the three _splat permutations gives us end-to-end confidence that the Solid bindings respect the core fix.

packages/router-core/src/router.ts (1)

800-808: Nice single source for trailingSlash values

Deriving TrailingSlashOption from the trailingSlashOptions const keeps the runtime export and type union in lockstep, which makes the downstream Object.values(...) usage in tests both ergonomic and type-safe.

packages/react-router/tests/useNavigate.test.tsx (2)

13-14: LGTM!

The import of trailingSlashOptions is correct and enables parameterized testing across all trailing slash configurations.


2565-2679: LGTM!

The test implementation comprehensively covers the empty splat scenarios. The logic correctly handles all three edge cases (empty string, undefined, and missing _splat), verifies the pathname respects the trailingSlash option, and properly resets state between test cases for isolation.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 20, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@5510

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@5510

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@5510

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@5510

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@5510

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@5510

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@5510

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@5510

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@5510

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@5510

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@5510

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@5510

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@5510

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@5510

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@5510

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@5510

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@5510

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@5510

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@5510

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@5510

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@5510

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@5510

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@5510

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@5510

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@5510

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@5510

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@5510

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@5510

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@5510

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@5510

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@5510

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@5510

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@5510

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@5510

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@5510

commit: d55f44c

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/solid-router/tests/useNavigate.test.tsx (1)

2528-2643: Good end‑to‑end coverage; consider simplifying waitFor usage.

Current pattern awaits findByText inside an async waitFor callback. Prefer either:

  • waitFor pathname, then a standalone findByText, or
  • use synchronous getByText inside waitFor.

Example:

await waitFor(() => expect(window.location.pathname).toBe(`/splat${tail}`))
expect(await screen.findByText('Splat Route')).toBeInTheDocument()
packages/solid-router/tests/link.test.tsx (1)

5089-5181: Thorough Link-level validation for empty/undefined/missing _splat.

Href generation and active state checks look correct across all trailingSlash modes; route render assertion completes the flow.

Minor: the inline comment “When _splat has a value...” could say “When navigating with empty/undefined/missing _splat...” for precision.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 25fa686 and b26e9b7.

📒 Files selected for processing (3)
  • packages/solid-router/tests/link.test.tsx (2 hunks)
  • packages/solid-router/tests/navigate.test.tsx (2 hunks)
  • packages/solid-router/tests/useNavigate.test.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/solid-router/tests/link.test.tsx
  • packages/solid-router/tests/useNavigate.test.tsx
  • packages/solid-router/tests/navigate.test.tsx
packages/{react-router,solid-router}/**

📄 CodeRabbit inference engine (AGENTS.md)

Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Files:

  • packages/solid-router/tests/link.test.tsx
  • packages/solid-router/tests/useNavigate.test.tsx
  • packages/solid-router/tests/navigate.test.tsx
🧠 Learnings (1)
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
PR: TanStack/router#5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/solid-router/tests/link.test.tsx
  • packages/solid-router/tests/useNavigate.test.tsx
  • packages/solid-router/tests/navigate.test.tsx
🧬 Code graph analysis (3)
packages/solid-router/tests/link.test.tsx (1)
packages/router-core/src/router.ts (1)
  • trailingSlashOptions (800-804)
packages/solid-router/tests/useNavigate.test.tsx (2)
packages/router-core/src/router.ts (1)
  • trailingSlashOptions (800-804)
packages/solid-router/src/useNavigate.tsx (1)
  • useNavigate (11-25)
packages/solid-router/tests/navigate.test.tsx (1)
packages/solid-router/src/router.ts (1)
  • createRouter (76-78)
🪛 ESLint
packages/solid-router/tests/navigate.test.tsx

[error] 11-11: @solidjs/testing-library import should occur before import of ../src

(import/order)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Preview
  • GitHub Check: Test
🔇 Additional comments (3)
packages/solid-router/tests/navigate.test.tsx (1)

573-628: Solid coverage for empty/undefined/missing _splat across trailingSlash modes.

Exercises navigate() + history reset and asserts path normalization. Matches the intended behavior.

packages/solid-router/tests/useNavigate.test.tsx (1)

13-13: LGTM import.

Public trailingSlashOptions usage is appropriate here.

packages/solid-router/tests/link.test.tsx (1)

13-13: LGTM import.

Using the exported trailingSlashOptions keeps tests in sync with core.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trailing slash options isn't enforced with splat route

3 participants