Skip to content

Conversation

@birkskyum
Copy link
Member

@birkskyum birkskyum commented Dec 12, 2025

add vue-router suites

  • basic-vue-query
  • basic-vue-query-file-based

Summary by CodeRabbit

  • New Features
    • Added two new end-to-end example projects demonstrating Vue Router integration with data fetching capabilities, complete with Playwright testing setup and debugging tools for development workflows.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 12, 2025

Walkthrough

This PR adds two complete end-to-end test project scaffolds for TanStack Vue Router integrated with Vue Query and Playwright testing: one using file-based routing and one using traditional lazy routes. Both include full project setup (configs, dependencies, source code) and example posts/post-detail flows with error handling.

Changes

Cohort / File(s) Summary
File-based Vue Router Project Setup
e2e/vue-router/basic-vue-query-file-based/.gitignore, index.html, package.json
Project configuration with standard ignore patterns, HTML entry point, and npm dependencies including Vue 3, Tailwind, TanStack libraries, and Playwright.
File-based Build & Test Config
e2e/vue-router/basic-vue-query-file-based/playwright.config.ts, postcss.config.mjs, tsconfig.json, vite.config.js
Playwright test runner config with dynamic ports and global setup/teardown; PostCSS for Tailwind; Vite config with TanStack Router plugin (Vue target, auto code-splitting); TypeScript strict mode.
File-based Main & Route Tree
e2e/vue-router/basic-vue-query-file-based/src/main.tsx, src/routeTree.gen.ts
Vue 3 app bootstrap with QueryClient and router initialization, module augmentation for type safety; generated route tree with type definitions, nested layouts (_layout, _layout-2), and route mappings.
File-based Route Definitions
e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx, _layout.tsx, _layout-2.tsx, _layout-2/layout-a.tsx, _layout-2/layout-b.tsx, index.tsx, posts.tsx, posts.index.tsx, posts.$postId.tsx
Root route with nav and dev tools; nested layout components; home and posts-index pages; posts list with Link navigation and loader; dynamic post detail route with loader prefetch, error handling, and retry.
File-based Query & Data Helpers
e2e/vue-router/basic-vue-query-file-based/src/posts.tsx, postQueryOptions.tsx, postsQueryOptions.tsx
Post type and fetch functions (fetchPost, fetchPosts) with PostNotFoundError; Vue Query query options helpers for single post and posts list.
File-based Styling & Tests
e2e/vue-router/basic-vue-query-file-based/src/styles.css, tests/app.spec.ts, tests/setup/global.setup.ts, tests/setup/global.teardown.ts
Tailwind base layer with light/dark color scheme; Playwright e2e tests for navigation, nested layouts, error handling; dummy server setup/teardown.
Traditional Vue Router Project Setup
e2e/vue-router/basic-vue-query/.gitignore, index.html, package.json
Project configuration (same structure as file-based version) with standard dependencies for Vue 3, Tailwind, TanStack libraries, Playwright.
Traditional Build & Test Config
e2e/vue-router/basic-vue-query/playwright.config.ts, postcss.config.mjs, tsconfig.json, vite.config.js
Playwright config with dynamic ports; PostCSS Tailwind; Vite with Vue & Vue JSX plugins (no TanStack Router plugin); TypeScript strict mode.
Traditional Main & Inline Routes
e2e/vue-router/basic-vue-query/src/main.tsx
Single file with all routes, components, loader logic, error handling, QueryClient setup, and router initialization inline; module augmentation for router type safety.
Traditional Query & Data Helpers
e2e/vue-router/basic-vue-query/src/posts.ts, posts.lazy.tsx
Post types, fetch functions (fetchPost, fetchPosts), NotFoundError class; Vue Query options (postQueryOptions, postsQueryOptions); lazy posts route component with link list and error handling.
Traditional Styling & Tests
e2e/vue-router/basic-vue-query/src/styles.css, tests/app.spec.ts, tests/setup/global.setup.ts, tests/setup/global.teardown.ts
Tailwind styling (same as file-based); Playwright e2e tests for navigation, layouts, errors; dummy server setup/teardown.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Browser as Vue App<br/>(Router + Query)
    participant Router as TanStack<br/>Router
    participant QueryClient as Vue Query<br/>Client
    participant API as Dummy Server
    participant ErrorHandler as Error<br/>Boundary

    User->>Browser: Navigate to /posts/$postId
    Browser->>Router: Route match
    Router->>QueryClient: loader: ensureQueryData(postQueryOptions(postId))
    QueryClient->>QueryClient: Check cache
    alt Cache hit
        QueryClient-->>Router: Return cached data
    else Cache miss
        QueryClient->>API: fetchPost(postId)
        alt Success (200)
            API-->>QueryClient: { id, title, body }
            QueryClient-->>Router: Return fetched data
        else Not Found (404)
            API-->>QueryClient: 404 response
            QueryClient->>ErrorHandler: Throw PostNotFoundError
            ErrorHandler-->>Browser: Render PostErrorComponent
            Note over ErrorHandler: Show retry button
            Browser-->>User: Display "Post not found"
        end
    end
    
    alt Post found
        Router->>Browser: Render PostComponent
        Browser->>Browser: useQuery(postQueryOptions(postId))
        Browser->>Browser: Route.useLoaderData()
        Browser-->>User: Display post title & body
    end
    
    alt User clicks retry
        User->>Browser: Click retry
        Browser->>Router: router.invalidate()
        Router->>QueryClient: Invalidate query
        QueryClient->>API: fetchPost(postId) [again]
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Generated route tree complexity: Both versions include intricate routeTree.gen.ts with nested type definitions, FileRoutesByPath mappings, and parent-child relationships requiring careful validation.
  • Parallel structures requiring consistency checks: Two nearly identical project setups demand verification that patterns are applied consistently; variations between file-based and traditional routing approaches must align with design intent.
  • Router & Query integration points: Module augmentations, QueryClient context passing, loader prefetch logic, and error boundaries need scrutiny across both versions.
  • Test setup validation: Playwright config, dummy server orchestration, and e2e test coverage (navigation, layouts, error scenarios) span both projects.

Areas requiring extra attention:

  • src/routeTree.gen.ts (file-based) – verify generated types, FileRoutesByPath augmentation, nested layout structure
  • src/main.tsx (traditional) – ensure inline route definitions, loaders, error components, and module augmentation are complete and correct
  • Post error handling flow – PostErrorComponent retry mechanism and PostNotFoundError propagation in both versions
  • Consistency between file-based and traditional routing approaches – confirm feature parity despite implementation differences
  • Playwright config dynamic port allocation and global setup/teardown logic

Possibly related PRs

Suggested reviewers

  • birkskyum
  • schiller-manuel

Poem

🐰 Hops through routes with queries bound,
Two Vue pathways, both profound—
File-based trees and lazy flows,
Error caught where retry goes.
Tests await with Playwright's grace,
E2E examples win the race!

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'e2e(vue-router): vue-query suites' clearly and concisely describes the main change: adding Vue Query test suites for Vue Router e2e testing.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch e2e(vue-router)--vue-query-suites

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.

@nx-cloud
Copy link

nx-cloud bot commented Dec 12, 2025

View your CI Pipeline Execution ↗ for commit 72b462b

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

☁️ Nx Cloud last updated this comment at 2025-12-12 16:34:02 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 12, 2025

More templates

@tanstack/arktype-adapter

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

@tanstack/directive-functions-plugin

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

@tanstack/eslint-plugin-router

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

@tanstack/history

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

@tanstack/nitro-v2-vite-plugin

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

@tanstack/react-router

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

@tanstack/react-router-devtools

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

@tanstack/react-router-ssr-query

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

@tanstack/react-start

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

@tanstack/react-start-client

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

@tanstack/react-start-server

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

@tanstack/router-cli

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

@tanstack/router-core

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

@tanstack/router-devtools

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

@tanstack/router-devtools-core

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

@tanstack/router-generator

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

@tanstack/router-plugin

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

@tanstack/router-ssr-query-core

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

@tanstack/router-utils

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

@tanstack/router-vite-plugin

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

@tanstack/server-functions-plugin

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

@tanstack/solid-router

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

@tanstack/solid-router-devtools

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

@tanstack/solid-router-ssr-query

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

@tanstack/solid-start

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

@tanstack/solid-start-client

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

@tanstack/solid-start-server

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

@tanstack/start-client-core

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

@tanstack/start-plugin-core

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

@tanstack/start-server-core

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

@tanstack/start-static-server-functions

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

@tanstack/start-storage-context

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

@tanstack/valibot-adapter

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

@tanstack/virtual-file-routes

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

@tanstack/vue-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router@6083

@tanstack/vue-router-devtools

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

@tanstack/vue-router-ssr-query

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

@tanstack/vue-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start@6083

@tanstack/vue-start-client

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

@tanstack/vue-start-server

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

@tanstack/zod-adapter

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

commit: 72b462b

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: 6

🧹 Nitpick comments (20)
e2e/vue-router/basic-vue-query/src/posts.lazy.tsx (1)

17-17: Consider proper typing instead of type assertion.

The type assertion as Array<{ id: string; title: string }> assumes the data shape. If postsQueryOptions is properly typed with generics, this assertion could be avoided, improving type safety.

Example if using typed query options:

// In posts.ts or postsQueryOptions.tsx
type Post = { id: string; title: string }

export const postsQueryOptions = queryOptions<Post[]>({
  queryKey: ['posts'],
  queryFn: () => fetchPosts(),
})

Then the type assertion wouldn't be needed:

-  ...((posts.value ?? []) as Array<{ id: string; title: string }>),
+  ...(posts.value ?? []),
e2e/vue-router/basic-vue-query-file-based/src/postsQueryOptions.tsx (1)

1-7: Looks good; consider queryFn: fetchPosts for brevity (optional).

e2e/vue-router/basic-vue-query-file-based/package.json (1)

5-12: test:e2e script is not Windows-friendly (rm -rf, ;).

If these suites ever need to run on Windows, consider swapping rm -rf for a portable alternative (e.g. rimraf) and avoid ; chaining.

e2e/vue-router/basic-vue-query/package.json (1)

5-12: test:e2e script is not Windows-friendly (rm -rf, ;).

e2e/vue-router/basic-vue-query/tests/app.spec.ts (4)

3-5: Make initial navigation less flaky by waiting on a stable “home loaded” signal.
page.goto('/') alone can race hydration; consider asserting a stable element (e.g., Welcome Home!) before proceeding.


7-11: Avoid brittle selectors: don’t key the test on a truncated link label and a generic heading.
name: 'sunt aut facere repe' and getByRole('heading') can break if truncation/markup changes; prefer getByRole('heading', { name: /sunt aut facere/i }) or a data-testid.


13-24: Nested layout assertions look good; consider asserting on specific regions to reduce false positives.
All checks are against #app; if content is duplicated elsewhere, this could pass incorrectly—optionally narrow to the layout container if available.


26-33: Not-found flow is solid; consider asserting URL change (optional).
If the router keeps content but not URL, this could miss regressions; optionally assert page.url() contains the not-found path then returns to /.

e2e/vue-router/basic-vue-query-file-based/tests/app.spec.ts (1)

25-51: Same selector brittleness as the other suite (truncated link + generic heading).
Recommend aligning selectors to stable text/regex or test ids to prevent truncation-driven failures.

e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx (2)

11-42: Stringify postId params to satisfy strict typing and avoid subtle route key mismatches.
If post.id is numeric (common for posts APIs), pass postId: String(post.id) to keep params consistently string-typed.


18-36: Test-only “Non-existent Post” is fine, but consider making it explicit why it’s injected.
A short comment helps future readers understand it exists to exercise error/not-found paths.

e2e/vue-router/basic-vue-query-file-based/src/main.tsx (1)

29-39: Non-null assertion on #app is OK for e2e, but consider a clearer failure mode (optional).
If the element is missing, this will throw; optionally assert and throw a custom error for easier debugging.

e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx (2)

49-57: Keep @ts-expect-error but make it resilient to refactors.
If route typing changes, this could become a hard error or no longer error; consider adding a short comment explaining it exists to validate not-found navigation.


61-63: Consider gating devtools to reduce CI noise/flakiness (optional).
Devtools can affect layout and sometimes timing; consider showing them only when import.meta.env.DEV or a test flag is enabled.

e2e/vue-router/basic-vue-query-file-based/playwright.config.ts (1)

27-32: webServer.command env var syntax is shell-specific; consider cross-env for portability.
VITE_NODE_ENV="test" ... will fail in some environments (notably Windows cmd/powershell).

e2e/vue-router/basic-vue-query-file-based/src/routes/posts.$postId.tsx (2)

16-34: Retry should ideally invalidate just this route (not everything).
router.invalidate() with no args is broad; for e2e it’s probably OK, but it can add noise/flakiness as suites grow. If the API supports it, scope invalidation to this match/route.

-          router.invalidate()
+          router.invalidate(/* TODO: scope to /posts/$postId if supported */)

36-47: Prefer a single source of truth for rendering (useQuery or loader data).
Right now you subscribe via useQuery(...) but render from Route.useLoaderData(). If you want query-driven updates, render from the query’s data (and optionally fall back to loader data).

 function PostComponent() {
   const postId = Route.useParams().value.postId
-  useQuery(postQueryOptions(postId))
-  const post = Route.useLoaderData()
+  const post = Route.useLoaderData()
+  const { data } = useQuery(postQueryOptions(postId))

   return (
     <div class="space-y-2">
-      <h4 class="text-xl font-bold underline">{post.value.title}</h4>
-      <div class="text-sm">{post.value.body}</div>
+      <h4 class="text-xl font-bold underline">
+        {(data.value ?? post.value).title}
+      </h4>
+      <div class="text-sm">{(data.value ?? post.value).body}</div>
     </div>
   )
 }
e2e/vue-router/basic-vue-query/playwright.config.ts (1)

28-33: webServer.command env var syntax is not cross-platform.
If these suites are expected to run on Windows, consider using cross-env / cross-env-shell, or Playwright’s webServer.env (if available in your Playwright version).

   webServer: {
-    command: `VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} VITE_SERVER_PORT=${PORT} pnpm build && VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} VITE_SERVER_PORT=${PORT} pnpm preview --port ${PORT}`,
+    command: `cross-env VITE_NODE_ENV=test VITE_EXTERNAL_PORT=${EXTERNAL_PORT} VITE_SERVER_PORT=${PORT} pnpm build && cross-env VITE_NODE_ENV=test VITE_EXTERNAL_PORT=${EXTERNAL_PORT} VITE_SERVER_PORT=${PORT} pnpm preview --port ${PORT}`,
     url: baseURL,
     reuseExistingServer: !process.env.CI,
     stdout: 'pipe',
   },
e2e/vue-router/basic-vue-query/src/main.tsx (2)

120-138: Retry invalidation is broad; consider scoping if supported.
router.invalidate() without args may invalidate more than needed and slow the suite as more routes are added.


235-246: Router preload staleness comment is good—double-check it aligns with query staleness.
defaultPreloadStaleTime: 0 ensures router loaders rerun, but TanStack Query’s staleTime/refetchOnMount still controls whether the component observer refetches immediately after ensureQueryData. Worth confirming the combined behavior is what you want for stable e2e runs.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5d2f29 and 72b462b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (39)
  • e2e/vue-router/basic-vue-query-file-based/.gitignore (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/index.html (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/package.json (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/playwright.config.ts (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/postcss.config.mjs (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/main.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/postQueryOptions.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/posts.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/postsQueryOptions.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/routeTree.gen.ts (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.$postId.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.index.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/src/styles.css (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/tests/app.spec.ts (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/tests/setup/global.setup.ts (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/tests/setup/global.teardown.ts (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/tsconfig.json (1 hunks)
  • e2e/vue-router/basic-vue-query-file-based/vite.config.js (1 hunks)
  • e2e/vue-router/basic-vue-query/.gitignore (1 hunks)
  • e2e/vue-router/basic-vue-query/index.html (1 hunks)
  • e2e/vue-router/basic-vue-query/package.json (1 hunks)
  • e2e/vue-router/basic-vue-query/playwright.config.ts (1 hunks)
  • e2e/vue-router/basic-vue-query/postcss.config.mjs (1 hunks)
  • e2e/vue-router/basic-vue-query/src/main.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query/src/posts.lazy.tsx (1 hunks)
  • e2e/vue-router/basic-vue-query/src/posts.ts (1 hunks)
  • e2e/vue-router/basic-vue-query/src/styles.css (1 hunks)
  • e2e/vue-router/basic-vue-query/tests/app.spec.ts (1 hunks)
  • e2e/vue-router/basic-vue-query/tests/setup/global.setup.ts (1 hunks)
  • e2e/vue-router/basic-vue-query/tests/setup/global.teardown.ts (1 hunks)
  • e2e/vue-router/basic-vue-query/tsconfig.json (1 hunks)
  • e2e/vue-router/basic-vue-query/vite.config.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript strict mode with extensive type safety for all code

Files:

  • e2e/vue-router/basic-vue-query-file-based/src/postsQueryOptions.tsx
  • e2e/vue-router/basic-vue-query/src/posts.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.index.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/posts.tsx
  • e2e/vue-router/basic-vue-query-file-based/tests/app.spec.ts
  • e2e/vue-router/basic-vue-query-file-based/tests/setup/global.teardown.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.$postId.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/postQueryOptions.tsx
  • e2e/vue-router/basic-vue-query/tests/setup/global.teardown.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx
  • e2e/vue-router/basic-vue-query/src/posts.lazy.tsx
  • e2e/vue-router/basic-vue-query/tests/setup/global.setup.ts
  • e2e/vue-router/basic-vue-query-file-based/src/main.tsx
  • e2e/vue-router/basic-vue-query-file-based/playwright.config.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routeTree.gen.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx
  • e2e/vue-router/basic-vue-query/src/main.tsx
  • e2e/vue-router/basic-vue-query/tests/app.spec.ts
  • e2e/vue-router/basic-vue-query-file-based/tests/setup/global.setup.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx
  • e2e/vue-router/basic-vue-query/playwright.config.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Implement ESLint rules for router best practices using the ESLint plugin router

Files:

  • e2e/vue-router/basic-vue-query-file-based/src/postsQueryOptions.tsx
  • e2e/vue-router/basic-vue-query/src/posts.ts
  • e2e/vue-router/basic-vue-query/vite.config.js
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.index.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/posts.tsx
  • e2e/vue-router/basic-vue-query-file-based/tests/app.spec.ts
  • e2e/vue-router/basic-vue-query-file-based/tests/setup/global.teardown.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.$postId.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/postQueryOptions.tsx
  • e2e/vue-router/basic-vue-query/tests/setup/global.teardown.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx
  • e2e/vue-router/basic-vue-query/src/posts.lazy.tsx
  • e2e/vue-router/basic-vue-query/tests/setup/global.setup.ts
  • e2e/vue-router/basic-vue-query-file-based/src/main.tsx
  • e2e/vue-router/basic-vue-query-file-based/vite.config.js
  • e2e/vue-router/basic-vue-query-file-based/playwright.config.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routeTree.gen.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx
  • e2e/vue-router/basic-vue-query/src/main.tsx
  • e2e/vue-router/basic-vue-query/tests/app.spec.ts
  • e2e/vue-router/basic-vue-query-file-based/tests/setup/global.setup.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx
  • e2e/vue-router/basic-vue-query/playwright.config.ts
**/package.json

📄 CodeRabbit inference engine (AGENTS.md)

Use workspace protocol workspace:* for internal dependencies in package.json files

Files:

  • e2e/vue-router/basic-vue-query/package.json
  • e2e/vue-router/basic-vue-query-file-based/package.json
🧠 Learnings (10)
📓 Common learnings
Learnt from: nlynzaad
Repo: TanStack/router PR: 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.
Learnt from: FatahChan
Repo: TanStack/router PR: 5475
File: e2e/react-start/basic-prerendering/src/routes/redirect/$target/via-beforeLoad.tsx:8-0
Timestamp: 2025-10-14T18:59:33.990Z
Learning: In TanStack Router e2e test files, when a route parameter is validated at the route level (e.g., using zod in validateSearch or param validation), switch statements on that parameter do not require a default case, as the validation ensures only expected values will reach the switch.
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.

Applied to files:

  • e2e/vue-router/basic-vue-query/.gitignore
  • e2e/vue-router/basic-vue-query-file-based/.gitignore
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2.tsx
  • e2e/vue-router/basic-vue-query-file-based/tsconfig.json
  • e2e/vue-router/basic-vue-query-file-based/src/routeTree.gen.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 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:

  • e2e/vue-router/basic-vue-query/.gitignore
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.index.tsx
  • e2e/vue-router/basic-vue-query-file-based/.gitignore
  • e2e/vue-router/basic-vue-query-file-based/tests/app.spec.ts
  • e2e/vue-router/basic-vue-query-file-based/tests/setup/global.teardown.ts
  • e2e/vue-router/basic-vue-query/tsconfig.json
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx
  • e2e/vue-router/basic-vue-query/tests/setup/global.setup.ts
  • e2e/vue-router/basic-vue-query-file-based/tsconfig.json
  • e2e/vue-router/basic-vue-query-file-based/src/routeTree.gen.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx
  • e2e/vue-router/basic-vue-query/src/main.tsx
  • e2e/vue-router/basic-vue-query/tests/app.spec.ts
  • e2e/vue-router/basic-vue-query/package.json
  • e2e/vue-router/basic-vue-query-file-based/tests/setup/global.setup.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx
  • e2e/vue-router/basic-vue-query-file-based/package.json
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Use file-based routing in `src/routes/` directories or code-based routing with route definitions

Applied to files:

  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.index.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routeTree.gen.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin router

Applied to files:

  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.index.tsx
  • e2e/vue-router/basic-vue-query-file-based/tests/app.spec.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.$postId.tsx
  • e2e/vue-router/basic-vue-query/tsconfig.json
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2.tsx
  • e2e/vue-router/basic-vue-query-file-based/tsconfig.json
  • e2e/vue-router/basic-vue-query-file-based/src/routeTree.gen.ts
  • e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx
  • e2e/vue-router/basic-vue-query/src/main.tsx
  • e2e/vue-router/basic-vue-query/tests/app.spec.ts
  • e2e/vue-router/basic-vue-query/package.json
  • e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx
  • e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx
  • e2e/vue-router/basic-vue-query-file-based/package.json
📚 Learning: 2025-10-09T12:59:02.129Z
Learnt from: hokkyss
Repo: TanStack/router PR: 5418
File: e2e/react-start/custom-identifier-prefix/src/styles/app.css:19-21
Timestamp: 2025-10-09T12:59:02.129Z
Learning: In e2e test directories (paths containing `e2e/`), accessibility concerns like outline suppression patterns are less critical since the code is for testing purposes, not production use.

Applied to files:

  • e2e/vue-router/basic-vue-query-file-based/.gitignore
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript strict mode with extensive type safety for all code

Applied to files:

  • e2e/vue-router/basic-vue-query/tsconfig.json
  • e2e/vue-router/basic-vue-query-file-based/tsconfig.json
📚 Learning: 2025-11-02T16:16:24.898Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5732
File: packages/start-client-core/src/client/hydrateStart.ts:6-9
Timestamp: 2025-11-02T16:16:24.898Z
Learning: In packages/start-client-core/src/client/hydrateStart.ts, the `import/no-duplicates` ESLint disable is necessary for imports from `#tanstack-router-entry` and `#tanstack-start-entry` because both aliases resolve to the same placeholder file (`fake-start-entry.js`) in package.json during static analysis, even though they resolve to different files at runtime.

Applied to files:

  • e2e/vue-router/basic-vue-query/tsconfig.json
  • e2e/vue-router/basic-vue-query/tests/setup/global.setup.ts
  • e2e/vue-router/basic-vue-query/package.json
  • e2e/vue-router/basic-vue-query-file-based/tests/setup/global.setup.ts
📚 Learning: 2025-10-09T12:59:14.842Z
Learnt from: hokkyss
Repo: TanStack/router PR: 5418
File: e2e/react-start/custom-identifier-prefix/public/site.webmanifest:2-3
Timestamp: 2025-10-09T12:59:14.842Z
Learning: In e2e test fixtures (files under e2e directories), empty or placeholder values in configuration files like site.webmanifest are acceptable and should not be flagged unless the test specifically validates those fields.

Applied to files:

  • e2e/vue-router/basic-vue-query-file-based/playwright.config.ts
  • e2e/vue-router/basic-vue-query-file-based/tests/setup/global.setup.ts
  • e2e/vue-router/basic-vue-query/playwright.config.ts
📚 Learning: 2025-10-14T18:59:33.990Z
Learnt from: FatahChan
Repo: TanStack/router PR: 5475
File: e2e/react-start/basic-prerendering/src/routes/redirect/$target/via-beforeLoad.tsx:8-0
Timestamp: 2025-10-14T18:59:33.990Z
Learning: In TanStack Router e2e test files, when a route parameter is validated at the route level (e.g., using zod in validateSearch or param validation), switch statements on that parameter do not require a default case, as the validation ensures only expected values will reach the switch.

Applied to files:

  • e2e/vue-router/basic-vue-query/src/main.tsx
🧬 Code graph analysis (17)
e2e/vue-router/basic-vue-query-file-based/src/postsQueryOptions.tsx (2)
e2e/vue-router/basic-vue-query/src/posts.ts (1)
  • postsQueryOptions (45-48)
e2e/vue-router/basic-vue-query-file-based/src/posts.tsx (1)
  • fetchPosts (32-37)
e2e/vue-router/basic-vue-query/src/posts.ts (2)
e2e/vue-router/basic-vue-query-file-based/src/posts.tsx (2)
  • PostType (3-7)
  • fetchPost (17-30)
e2e/vue-router/basic-vue-query-file-based/src/postQueryOptions.tsx (1)
  • postQueryOptions (4-8)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.index.tsx (8)
e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx (1)
  • Route (6-18)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx (1)
  • Route (2-4)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx (1)
  • Route (2-4)
e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.$postId.tsx (1)
  • Route (8-14)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx (1)
  • Route (5-9)
e2e/vue-router/basic-vue-query-file-based/tests/app.spec.ts (1)
scripts/set-ts-version.js (1)
  • packageJson (33-33)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx (7)
e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx (1)
  • Route (6-18)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx (1)
  • Route (2-4)
e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.$postId.tsx (1)
  • Route (8-14)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.index.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx (1)
  • Route (5-9)
e2e/vue-router/basic-vue-query-file-based/src/postQueryOptions.tsx (2)
e2e/vue-router/basic-vue-query/src/posts.ts (1)
  • postQueryOptions (39-43)
e2e/vue-router/basic-vue-query-file-based/src/posts.tsx (1)
  • fetchPost (17-30)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2.tsx (2)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx (1)
  • Route (2-4)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx (9)
e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx (1)
  • Route (6-18)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx (1)
  • Route (2-4)
e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.$postId.tsx (1)
  • Route (8-14)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.index.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx (1)
  • Route (5-9)
e2e/vue-router/basic-vue-query/src/posts.lazy.tsx (1)
  • Route (5-7)
e2e/vue-router/basic-vue-query/src/posts.lazy.tsx (4)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.$postId.tsx (1)
  • Route (8-14)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx (1)
  • Route (5-9)
e2e/vue-router/basic-vue-query-file-based/src/postsQueryOptions.tsx (1)
  • postsQueryOptions (4-7)
e2e/vue-router/basic-vue-query/src/posts.ts (1)
  • postsQueryOptions (45-48)
e2e/vue-router/basic-vue-query/tests/setup/global.setup.ts (4)
e2e/vue-router/basic-vue-query-file-based/src/main.tsx (1)
  • setup (33-35)
e2e/vue-router/basic-vue-query-file-based/tests/setup/global.setup.ts (1)
  • setup (4-6)
e2e/vue-router/basic-vue-query/src/main.tsx (1)
  • setup (259-261)
scripts/set-ts-version.js (1)
  • packageJson (33-33)
e2e/vue-router/basic-vue-query-file-based/playwright.config.ts (1)
scripts/set-ts-version.js (1)
  • packageJson (33-33)
e2e/vue-router/basic-vue-query-file-based/src/routeTree.gen.ts (2)
packages/router-generator/tests/generator/types-disabled/routeTree.nonnested.snapshot.js (3)
  • PostsRoute (17-21)
  • PostsRouteWithChildren (42-42)
  • PostsRouteChildren (38-40)
e2e/solid-router/js-only-file-based/src/routeTree.gen.js (1)
  • PostsIndexRoute (35-39)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx (1)
e2e/vue-router/basic-vue-query-file-based/src/postsQueryOptions.tsx (1)
  • postsQueryOptions (4-7)
e2e/vue-router/basic-vue-query/src/main.tsx (1)
e2e/vue-router/basic-vue-query/src/posts.ts (3)
  • postsQueryOptions (45-48)
  • postQueryOptions (39-43)
  • NotFoundError (4-4)
e2e/vue-router/basic-vue-query-file-based/tests/setup/global.setup.ts (2)
e2e/vue-router/basic-vue-query/src/main.tsx (1)
  • setup (259-261)
scripts/set-ts-version.js (1)
  • packageJson (33-33)
e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx (3)
e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx (1)
  • Route (3-5)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.$postId.tsx (1)
  • Route (8-14)
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx (1)
  • Route (5-9)
e2e/vue-router/basic-vue-query/playwright.config.ts (1)
scripts/set-ts-version.js (1)
  • packageJson (33-33)
⏰ 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: Test
  • GitHub Check: Preview
🔇 Additional comments (37)
e2e/vue-router/basic-vue-query/vite.config.js (1)

1-8: Minimal Vite config looks correct for Vue + JSX.

Imports and defineConfig({ plugins: [vue(), vueJsx()] }) are appropriate for a Vue 3 e2e scaffold; nothing concerning here.

e2e/vue-router/basic-vue-query-file-based/tsconfig.json (2)

1-17: Solid baseline tsconfig for a Vite/Vue e2e scaffold.
ESNext + moduleResolution: "Bundler", noEmit, and strict: true are all aligned with modern Vite/Vue setups. As per retrieved learnings, strict mode is enabled.


10-16: No action required. The tsconfig configuration is correct for this Playwright-based e2e project.

The types array in TypeScript controls automatic inclusion of ambient type declarations from @types packages, not module imports. When test files import from @playwright/test, TypeScript uses the types exported by the package itself—not affected by the types array. The successful build (with vue-tsc --noEmit) confirms Playwright types resolve correctly. The skipLibCheck: true setting is intentional and consistent with the root tsconfig; it's a project-wide decision that doesn't interfere with test file type checking.

e2e/vue-router/basic-vue-query-file-based/.gitignore (1)

1-11: Reasonable ignore set for build + Playwright artifacts.

e2e/vue-router/basic-vue-query/.gitignore (1)

1-11: Matches the file-based suite; ignore set looks complete.

e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-a.tsx (1)

1-8: LGTM for a basic file-route + component.

Please confirm the new e2e workspace enables the repo’s ESLint “router” plugin rules for **/*.{js,ts,tsx} (per coding guidelines).

e2e/vue-router/basic-vue-query/tsconfig.json (1)

1-17: Strict TS + Vue TSX settings look appropriate for Vite.

e2e/vue-router/basic-vue-query-file-based/src/routes/index.tsx (1)

1-13: Root route is fine; JSX class usage is consistent with Vue JSX.

Please confirm the new e2e workspace runs ESLint with the repo’s router best-practices plugin for these TSX routes (per coding guidelines).

e2e/vue-router/basic-vue-query/postcss.config.mjs (1)

1-5: No changes needed. The PostCSS Tailwind plugin configuration is correct for Tailwind v4. The project has @tailwindcss/postcss@^4.1.15, tailwindcss@^4.1.17, and postcss@^8.5.1 properly configured as dependencies, meeting all Tailwind v4 requirements. The config format matches the documented pattern for Tailwind v4 PostCSS integration in Vite/Vue projects.

e2e/vue-router/basic-vue-query-file-based/postcss.config.mjs (1)

1-5: Tailwind v4 PostCSS configuration is correct and properly wired. @tailwindcss/postcss v4.1.15 and tailwindcss v4.1.17 are both present in package.json and the plugin configuration matches the official Tailwind v4 PostCSS setup. Consistent with all e2e test suites.

e2e/vue-router/basic-vue-query-file-based/src/routes/posts.index.tsx (1)

1-9: Looks good for a /posts/ index route.

e2e/vue-router/basic-vue-query-file-based/src/routes/_layout.tsx (1)

1-16: Layout + <Outlet /> wiring looks correct.

e2e/vue-router/basic-vue-query-file-based/index.html (1)

1-12: Standard Vite entry HTML; no issues.

e2e/vue-router/basic-vue-query/index.html (1)

1-12: Standard Vite entry HTML; no issues.

e2e/vue-router/basic-vue-query/tests/setup/global.teardown.ts (1)

1-6: Verify Node/TS support for JSON import attributes (with { type: 'json' }).

If CI/runtime doesn’t support this form, consider switching to a small fs.readFile + JSON.parse (or align on the supported import-attributes syntax for your Node baseline).

e2e/vue-router/basic-vue-query/package.json (1)

1-33: The review comment is based on outdated or misapplied guidelines. The entire e2e/ directory consistently uses workspace:^ across all framework variants (react, vue, solid), and this file correctly follows that established pattern. All other e2e packages use workspace:^ for their internal dependencies, including @tanstack/router-e2e-utils, @tanstack/vue-router, and @tanstack/vue-router-devtools. Changing to workspace:* would create inconsistency with the rest of the e2e suite.

Likely an incorrect or invalid review comment.

e2e/vue-router/basic-vue-query/src/posts.ts (1)

12-16: Environment variables are guaranteed to be set together by Playwright config.

The VITE_NODE_ENV and VITE_EXTERNAL_PORT variables are always initialized together in the Playwright configuration command (playwright.config.ts line 29). Both are populated from async port derivation functions (getDummyServerPort() returns a number) before any build occurs. The conditional check if (import.meta.env.VITE_NODE_ENV === 'test') ensures these variables are only used in the test build context where they're guaranteed to exist. No additional validation is needed.

e2e/vue-router/basic-vue-query-file-based/tests/setup/global.setup.ts (1)

1-6: Guard packageJson.name and verify JSON-import syntax compatibility (with { type: 'json' }).

If name is missing you’ll pass undefined to e2eStartDummyServer, and the with { type: 'json' } syntax may not be supported by the repo’s Playwright/TS pipeline.

 import { e2eStartDummyServer } from '@tanstack/router-e2e-utils'
 import packageJson from '../../package.json' with { type: 'json' }

 export default async function setup() {
-  await e2eStartDummyServer(packageJson.name)
+  if (!packageJson.name) throw new Error('package.json#name is required for e2e dummy server')
+  await e2eStartDummyServer(packageJson.name)
 }
e2e/vue-router/basic-vue-query-file-based/src/styles.css (1)

1-21: LGTM: Tailwind v4 base layer + light/dark defaults look consistent.

e2e/vue-router/basic-vue-query/tests/setup/global.setup.ts (1)

1-6: Guard packageJson.name and verify JSON-import syntax compatibility (with { type: 'json' }).

 import { e2eStartDummyServer } from '@tanstack/router-e2e-utils'
 import packageJson from '../../package.json' with { type: 'json' }

 export default async function setup() {
-  await e2eStartDummyServer(packageJson.name)
+  if (!packageJson.name) throw new Error('package.json#name is required for e2e dummy server')
+  await e2eStartDummyServer(packageJson.name)
 }
e2e/vue-router/basic-vue-query-file-based/tests/setup/global.teardown.ts (1)

1-6: Guard packageJson.name and verify JSON-import syntax compatibility (with { type: 'json' }).

 import { e2eStopDummyServer } from '@tanstack/router-e2e-utils'
 import packageJson from '../../package.json' with { type: 'json' }

 export default async function teardown() {
-  await e2eStopDummyServer(packageJson.name)
+  if (!packageJson.name) throw new Error('package.json#name is required for e2e dummy server')
+  await e2eStopDummyServer(packageJson.name)
 }
e2e/vue-router/basic-vue-query-file-based/src/postQueryOptions.tsx (1)

1-8: LGTM: queryKey/queryFn wiring matches expected Vue Query usage.

e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2.tsx (1)

1-34: Verify to="/layout-a" / to="/layout-b" match the actual generated URLs for these file-based routes.

If _layout segments are pathless in this fixture, this is fine; if not, these links will 404 and/or not activate as expected.

e2e/vue-router/basic-vue-query/src/styles.css (1)

1-21: LGTM: consistent Tailwind v4 base + light/dark theming defaults.

e2e/vue-router/basic-vue-query-file-based/src/posts.tsx (1)

1-37: Fix type mismatch and guard VITE_EXTERNAL_PORT (current code may fail in test mode).

The code has two issues:

  1. id: string should be id: number — JSONPlaceholder API returns post IDs as numeric values, not strings.
  2. VITE_EXTERNAL_PORT is not guarded; if missing in test mode, the URL becomes http://localhost:undefined.

Regarding the 404 detection: the codebase consistently uses err.status === 404 across 60+ similar files with redaxios, suggesting this is the correct error structure for this library, despite some API documentation suggesting err.response.status. If 404 handling is not working, the issue may be elsewhere (e.g., redaxios version, fetch behavior, or mocking setup in tests).

 export type PostType = {
-  id: string
+  id: number
   title: string
   body: string
 }

 export class PostNotFoundError extends Error {}

 let queryURL = 'https://jsonplaceholder.typicode.com'

 if (import.meta.env.VITE_NODE_ENV === 'test') {
-  queryURL = `http://localhost:${import.meta.env.VITE_EXTERNAL_PORT}`
+  const port = import.meta.env.VITE_EXTERNAL_PORT
+  if (!port) throw new Error('VITE_EXTERNAL_PORT is required in test mode')
+  queryURL = `http://localhost:${port}`
 }
e2e/vue-router/basic-vue-query-file-based/src/routes/posts.tsx (1)

5-9: Loader + component query wiring looks correct for Vue Query prefetch.
Using ensureQueryData in the loader and useQuery in the component is a good e2e pattern for “prefetch then subscribe”.

e2e/vue-router/basic-vue-query-file-based/src/main.tsx (2)

23-27: Module augmentation for router type safety looks good.
This should give nice end-to-end type checking for route definitions and Links.


7-20: No changes needed. Both defaultPreload: 'intent' and defaultPreloadStaleTime: 0 are valid, well-supported options in @tanstack/vue-router. They are properly defined in the router-core options and actively used in the preload logic with appropriate defaults and fallbacks.

e2e/vue-router/basic-vue-query-file-based/src/routes/_layout/_layout-2/layout-b.tsx (1)

1-8: Simple file-route component; looks good.
Matches the file-based routing conventions used elsewhere in the suite.

e2e/vue-router/basic-vue-query-file-based/src/routes/__root.tsx (1)

6-18: Root route context typing + notFoundComponent are a good e2e coverage hook.
This cleanly exercises “not found” behavior and the queryClient plumbing.

e2e/vue-router/basic-vue-query-file-based/playwright.config.ts (2)

15-40: Overall config is clear and appropriately scoped to a single chromium project.
Workers=1 and reuseExistingServer behavior are reasonable defaults for e2e fixtures.


1-11: Top-level await in this Playwright config is fully supported.

The configuration correctly uses ESM mode with "type": "module" in package.json, appropriate TypeScript settings (module: "ESNext", target: "ESNext"), and Playwright 1.56.1, all of which fully support top-level await. No changes are needed.

e2e/vue-router/basic-vue-query-file-based/vite.config.js (1)

1-13: No issues found. The plugin order is correct—tanstackRouter must come before the Vue and JSX plugins to transform file-based routes for automatic code splitting, and the code already follows this pattern. autoCodeSplitting: true is properly enabled and requires no additional setup beyond being set in the plugin options, which is already done.

e2e/vue-router/basic-vue-query-file-based/tests/app.spec.ts (1)

1-4: The JSON import assertion syntax with { type: 'json' } is properly supported in your TypeScript and Playwright configuration. All e2e projects have resolveJsonModule: true in their tsconfigs, TypeScript 5.8+ fully supports import attributes, and this pattern is consistently used across the e2e suite. No runtime compatibility issues exist with this approach.

However, consider using the Playwright request fixture instead of Node's fetch() for HTTP assertions—it provides built-in retry logic, request/response logging, and tracing that are valuable for E2E tests.

e2e/vue-router/basic-vue-query/src/main.tsx (2)

19-31: Typed router context wiring looks solid.
createRootRouteWithContext<{ queryClient: QueryClient }>() matches the loader usage and keeps loaders type-safe.


94-100: No action needed. The lazy contract is correctly implemented. The posts.lazy.tsx file exports const Route = createLazyRoute('/posts')({...}), and the code correctly accesses it via d.Route in the .then() callback. The export name and access pattern match—there is no mismatch that would cause runtime failures during navigation.

e2e/vue-router/basic-vue-query/playwright.config.ts (1)

6-10: The import attributes syntax and top-level await are already used and working in this file and throughout the entire e2e codebase. The setup supports these features: TypeScript 5.8.3 (supports import attributes since 5.3), resolveJsonModule: true in tsconfig, and ESNext target/module settings. The suggested change to createRequire is unnecessary—the current modern syntax is properly supported and functioning.

Likely an incorrect or invalid review comment.

Comment on lines +1 to +35
{
"name": "tanstack-router-e2e-vue-basic-vue-query-file-based",
"private": true,
"type": "module",
"scripts": {
"dev": "vite --port 3000",
"dev:e2e": "vite",
"build": "vite build && vue-tsc --noEmit",
"preview": "vite preview",
"start": "vite",
"test:e2e": "rm -rf port*.txt; playwright test --project=chromium"
},
"dependencies": {
"@tailwindcss/postcss": "^4.1.15",
"@tanstack/vue-query": "^5.90.0",
"@tanstack/vue-query-devtools": "^6.1.2",
"@tanstack/vue-router": "workspace:^",
"@tanstack/vue-router-devtools": "workspace:^",
"@tanstack/router-plugin": "workspace:^",
"postcss": "^8.5.1",
"redaxios": "^0.5.1",
"tailwindcss": "^4.1.17",
"vue": "^3.5.16",
"zod": "^3.24.2"
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@tanstack/router-e2e-utils": "workspace:^",
"@vitejs/plugin-vue": "^5.2.3",
"@vitejs/plugin-vue-jsx": "^4.1.2",
"typescript": "~5.8.3",
"vite": "^7.1.7",
"vue-tsc": "^3.1.5"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find all package.json files to see what pattern is used
git ls-files "**package.json" | head -20

Repository: TanStack/router

Length of output: 1105


🏁 Script executed:

# Look for workspace protocol usage patterns in the repo
rg "workspace:\*|workspace:\^" --type json | head -30

Repository: TanStack/router

Length of output: 2758


🏁 Script executed:

# Check for workspace protocol documentation in the repo
rg "workspace:\*|workspace:\^" --type md -B 2 -A 2 | head -50

Repository: TanStack/router

Length of output: 580


🏁 Script executed:

# Check the git history to see when these guidelines were introduced
git log --all --oneline -- "**/AGENTS.md" "**/*guidelines*" | head -10

Repository: TanStack/router

Length of output: 41


🏁 Script executed:

# Check root package.json to understand workspace configuration
cat -n package.json | head -50

Repository: TanStack/router

Length of output: 2574


🏁 Script executed:

# Check git log for changes to AGENTS.md related to workspace protocol
git log --all --oneline --follow -- AGENTS.md | head -20

Repository: TanStack/router

Length of output: 180


🏁 Script executed:

# Look at the actual diff/content changes in AGENTS.md
git log --all --pretty=format:"%h %s" -- AGENTS.md | head -5

Repository: TanStack/router

Length of output: 180


🏁 Script executed:

# Check if there are any recent commits updating package.json files to workspace:*
git log --all --oneline --grep="workspace" | head -10

Repository: TanStack/router

Length of output: 512


🏁 Script executed:

# Check a few other e2e package.json files to confirm the pattern is universal
for file in e2e/react-router/basic-file-based/package.json e2e/solid-start/website/package.json e2e/vue-router/basic/package.json; do
  echo "=== $file ==="; 
  rg "workspace:" "$file" | head -5; 
done

Repository: TanStack/router

Length of output: 774


Use workspace:* for internal dependencies per repo guidelines.

   "dependencies": {
-    "@tanstack/vue-router": "workspace:^",
-    "@tanstack/vue-router-devtools": "workspace:^",
-    "@tanstack/router-plugin": "workspace:^",
+    "@tanstack/vue-router": "workspace:*",
+    "@tanstack/vue-router-devtools": "workspace:*",
+    "@tanstack/router-plugin": "workspace:*",
   "devDependencies": {
-    "@tanstack/router-e2e-utils": "workspace:^",
+    "@tanstack/router-e2e-utils": "workspace:*",

Note: The entire e2e suite currently uses workspace:^, so consider applying this guideline repo-wide for consistency.

🤖 Prompt for AI Agents
In e2e/vue-router/basic-vue-query-file-based/package.json lines 1-35, internal
workspace dependencies use "workspace:^"; update every occurrence of
"workspace:^" to "workspace:*" (for @tanstack/vue-router,
@tanstack/vue-router-devtools, @tanstack/router-plugin,
@tanstack/router-e2e-utils) so internal packages follow repo guidelines; save
the file and run a quick install to verify lockfile updates.

Comment on lines +8 to +14
export const Route = createFileRoute('/posts/$postId')({
loader: ({ context: { queryClient }, params: { postId } }) => {
return queryClient.ensureQueryData(postQueryOptions(postId))
},
errorComponent: PostErrorComponent,
component: PostComponent,
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n e2e/vue-router/basic-vue-query-file-based/src/routes/posts.\$postId.tsx

Repository: TanStack/router

Length of output: 1690


🏁 Script executed:

find . -name "*postQueryOptions*" -type f

Repository: TanStack/router

Length of output: 595


🏁 Script executed:

cat -n e2e/vue-router/basic-vue-query-file-based/src/postQueryOptions.tsx

Repository: TanStack/router

Length of output: 351


🏁 Script executed:

rg "useQuery" e2e/vue-router/basic-vue-query-file-based/src/routes/ -A 2 -B 2

Repository: TanStack/router

Length of output: 2033


🏁 Script executed:

cat -n e2e/vue-router/basic-vue-query-file-based/src/posts.tsx | head -30

Repository: TanStack/router

Length of output: 980


Loader + useQuery() causes unnecessary refetch with default staleTime.

The loader: ensureQueryData(...) populates the cache, but with postQueryOptions having no explicit staleTime, TanStack Query defaults to staleTime=0 (immediately stale). When the component mounts, useQuery(postQueryOptions(postId)) sees stale data and refetches, causing a duplicate network request. Since the component renders from Route.useLoaderData() and ignores the useQuery() result, either set a positive staleTime in postQueryOptions, use the result from useQuery(), or disable the mount refetch with enabled: false.

🤖 Prompt for AI Agents
In e2e/vue-router/basic-vue-query-file-based/src/routes/posts.$postId.tsx around
lines 8–14, the loader uses queryClient.ensureQueryData but postQueryOptions has
no explicit staleTime so TanStack Query treats the cached data as immediately
stale and the component’s useQuery triggers a duplicate refetch on mount; fix by
giving postQueryOptions a positive staleTime (e.g. minutes) so the
loader-populated data stays fresh, or alternatively change the component to
consume the loader data from Route.useLoaderData() instead of calling useQuery,
or disable the automatic refetch on mount by configuring useQuery with enabled:
false or refetchOnMount: false.

Comment on lines +9 to +23
test('GetPosts', async () => {
const port = await getDummyServerPort(packageJson.name)
const res = await fetch(`http://localhost:${port}/posts`)

expect(res.status).toBe(200)

const posts = await res.json()

expect(posts.length).toBeGreaterThan(0)

const postRes = await fetch(`http://localhost:${port}/posts/1`)
expect(postRes.status).toBe(200)
const post = await postRes.json()
expect(post).toEqual(posts[0])
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find and examine package.json to check Playwright and Node versions
fd -t f "package\.json" | head -5

Repository: TanStack/router

Length of output: 174


🏁 Script executed:

#!/bin/bash
# Check the root package.json for Playwright version and Node requirements
cat package.json | head -50

Repository: TanStack/router

Length of output: 2224


🏁 Script executed:

#!/bin/bash
# Look for Playwright config files
fd -t f "playwright\.config\.(ts|js)"

Repository: TanStack/router

Length of output: 4026


🏁 Script executed:

#!/bin/bash
# Check the Playwright config for this specific test
cat "e2e/vue-router/basic-vue-query-file-based/playwright.config.ts"

Repository: TanStack/router

Length of output: 1208


🏁 Script executed:

#!/bin/bash
# Read the full test file to understand context
cat "e2e/vue-router/basic-vue-query-file-based/tests/app.spec.ts"

Repository: TanStack/router

Length of output: 1937


🏁 Script executed:

#!/bin/bash
# Search for fetch usage in test files across the e2e directory
rg "fetch\(" e2e/ -t ts -t tsx --max-count=20 | head -40

Repository: TanStack/router

Length of output: 86


🏁 Script executed:

#!/bin/bash
# Search for request fixture usage in test files
rg "request\." e2e/ -t ts --max-count=30

Repository: TanStack/router

Length of output: 8586


🏁 Script executed:

#!/bin/bash
# Search for async test signatures to see what fixtures are typically injected
rg "test\('.*',\s+async\s+\(\{" e2e/ -t ts | head -20

Repository: TanStack/router

Length of output: 2544


🏁 Script executed:

#!/bin/bash
# Check if there are any other fetch() calls in test files
rg "await fetch\(" e2e/ -t ts -B 2 -A 2 | head -60

Repository: TanStack/router

Length of output: 5015


🌐 Web query:

Playwright request fixture vs fetch API in tests best practices

💡 Result:

Short answer — prefer Playwright's request fixture / APIRequestContext for test setup, API-driven auth, and backend checks; use page.fetch/page.evaluate or browser-side fetch only when you must exercise the in-page JavaScript environment or need the request to originate from the page (same-origin, JS headers, ServiceWorker, or instrumentation). See official docs for request fixture and APIRequestContext behavior. [1][2][3]

Recommended best practices

  • Use the built-in request fixture (APIRequestContext) for test setup/teardown, creating test data, calling internal APIs, and getting/setting authentication state. It is fast, isolated per-test, and can persist storageState to reuse cookies between API and browser contexts. [1][2][3]
  • Prefer request.post/get/fetch from APIRequestContext over Node fetch or custom HTTP clients inside tests because Playwright manages timeouts, cookies, redirects, and integration with BrowserContext storageState. That reduces flakiness and simplifies storageState interchange. [2][3]
  • Use page.request or browser_context.request (when you need the request to share the BrowserContext cookie jar) if you want requests that share cookies with the page; use a standalone request.newContext when you want an isolated API client with custom baseURL/credentials. [3]
  • Use in-page fetch (page.evaluate(() => fetch(...))) when you must exercise client-side JavaScript behavior, ServiceWorkers, CORS behavior, or same-origin constraints that only appear inside the page. Avoid it for pure API-level setup because it’s slower, more brittle, and entangles tests with page state.
  • Keep API tests and E2E UI flows distinct: use APIRequestContext for API tests and environment setup; drive user flows via page interactions. When combining (e.g., log in via API then test UI), log in with request, save storageState, then create BrowserContext with that state. [2][3]
  • Centralize shared API helpers/fixtures (baseURL, auth helpers, test data creation) in test fixtures so tests remain readable and teardown is reliable. Use proper scopes (per-test vs per-suite) depending on isolation needs. [1]

When to choose which (quick checklist)

  • Need speed, stability, auth setup, or server-side state checks → request fixture / APIRequestContext. [2]
  • Need to test client-side JS, ServiceWorker, CORS, or observe how the page issues requests → in-page fetch / page.evaluate. [3]
  • Need requests that share the same cookie storage as a BrowserContext page → page.request or browserContext.request. [3]

References

  • Playwright fixtures and built-in request fixture docs. [1]
  • Playwright API testing guide (request.newContext, storageState, examples). [2]
  • APIRequestContext cookie-sharing and fetch behavior (cookie/storageState details). [3]

Use Playwright's request fixture to make API calls in tests instead of global fetch().

This test should inject the request fixture as a parameter and use request.get() for API calls. The Playwright request fixture provides proper timeout handling, cookie management, and integration with BrowserContext state—all of which are lost when using global fetch(). Change the test signature from async () => { to async ({ request }) => { and replace await fetch(...) with await request.get(...).

🤖 Prompt for AI Agents
In e2e/vue-router/basic-vue-query-file-based/tests/app.spec.ts around lines 9 to
23, the test uses global fetch() which bypasses Playwright's request fixture;
change the test signature to accept the Playwright fixture (async ({ request })
=> { ...) and replace fetch(...) calls with await request.get(...) (use
response.status() and await response.json() accordingly) so requests use
Playwright's timeout, cookie and context handling.

Comment on lines +111 to +151
const postRoute = createRoute({
getParentRoute: () => postsRoute,
path: '$postId',
errorComponent: PostErrorComponent,
loader: ({ context: { queryClient }, params: { postId } }) =>
queryClient.ensureQueryData(postQueryOptions(postId)),
component: PostRouteComponent,
})

function PostErrorComponent({ error }: ErrorComponentProps) {
const router = useRouter()
if (error instanceof NotFoundError) {
return <div>{error.message}</div>
}

return (
<div>
<button
onClick={() => {
router.invalidate()
}}
>
retry
</button>
<ErrorComponent error={error} />
</div>
)
}

function PostRouteComponent() {
const postId = postRoute.useParams().value.postId
useQuery(postQueryOptions(postId))
const post = postRoute.useLoaderData()

return (
<div class="space-y-2">
<h4 class="text-xl font-bold underline">{post.value.title}</h4>
<div class="text-sm">{post.value.body}</div>
</div>
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Same concern as file-based: loader + useQuery() may refetch, and you’re not rendering from query data.
If you want to keep loader-driven rendering, consider disabling mount refetch for the query observer; if you want query-driven rendering, render from useQuery’s data (optionally falling back to loader data).

🤖 Prompt for AI Agents
In e2e/vue-router/basic-vue-query/src/main.tsx around lines 111 to 151, the
component uses a loader plus a separate useQuery which can trigger an extra
refetch and then the UI renders from loader data instead of the query result;
either disable mount refetch on the query observer or render from the query data
(with loader as fallback). Fix by updating the useQuery call to include
refetchOnMount: false (and any other observer options to prevent duplicate
fetches) if you want loader-driven rendering, or change the component to read
data from the useQuery result (e.g., const { data } = useQuery(...); render from
data with postRoute.useLoaderData() as a fallback) if you want query-driven
rendering.

Comment on lines +10 to +11
const postsQuery = useQuery(postsQueryOptions)
const posts = postsQuery.data
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add loading and error state handling.

The component doesn't handle loading or error states from the query. This means:

  • During initial load, users see an empty list without feedback
  • If the query fails, there's no error message displayed
  • The app may crash if posts.value is accessed in an error state

Consider adding state handling:

 function PostsComponent() {
   const postsQuery = useQuery(postsQueryOptions)
-  const posts = postsQuery.data
+  const posts = postsQuery.data
+
+  if (postsQuery.isLoading) {
+    return <div class="p-2">Loading posts...</div>
+  }
+
+  if (postsQuery.isError) {
+    return <div class="p-2 text-red-600">Error loading posts: {postsQuery.error.message}</div>
+  }

   return (
     <div class="p-2 flex gap-2">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const postsQuery = useQuery(postsQueryOptions)
const posts = postsQuery.data
const postsQuery = useQuery(postsQueryOptions)
const posts = postsQuery.data
if (postsQuery.isLoading) {
return <div class="p-2">Loading posts...</div>
}
if (postsQuery.isError) {
return <div class="p-2 text-red-600">Error loading posts: {postsQuery.error.message}</div>
}
🤖 Prompt for AI Agents
In e2e/vue-router/basic-vue-query/src/posts.lazy.tsx around lines 10 to 11, the
component reads postsQuery.data directly and doesn't handle loading or error
states; update the component to check postsQuery.isLoading and
postsQuery.isError (or postsQuery.error) before accessing postsQuery.data,
render a loading indicator (e.g., "Loading..." or a spinner) while isLoading is
true, render a user-visible error message when isError is true and avoid
accessing postsQuery.data in that case, and only map/render posts when
postsQuery.data (or posts.value) is defined; ensure any template/JSX branches
return early or conditional-render to prevent crashes.

Comment on lines +12 to +37
let queryURL = 'https://jsonplaceholder.typicode.com'

if (import.meta.env.VITE_NODE_ENV === 'test') {
queryURL = `http://localhost:${import.meta.env.VITE_EXTERNAL_PORT}`
}

const fetchPosts = async () => {
console.info('Fetching posts...')
return axios
.get<Array<PostType>>(`${queryURL}/posts`)
.then((r) => r.data.slice(0, 10))
}

const fetchPost = async (postId: string) => {
console.info(`Fetching post with id ${postId}...`)
const post = await axios
.get<PostType>(`${queryURL}/posts/${postId}`)
.then((r) => r.data)

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!post) {
throw new NotFoundError(`Post with id "${postId}" not found!`)
}

return post
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix not-found handling: fetchPost likely never throws NotFoundError on 404.

If redaxios rejects on non-2xx (common), aFC, the code won’t reach if (!post). Map 404 explicitly:

 const fetchPost = async (postId: string) => {
   console.info(`Fetching post with id ${postId}...`)
-  const post = await axios
-    .get<PostType>(`${queryURL}/posts/${postId}`)
-    .then((r) => r.data)
-
-  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
-  if (!post) {
-    throw new NotFoundError(`Post with id "${postId}" not found!`)
-  }
-
-  return post
+  return axios
+    .get<PostType>(`${queryURL}/posts/${postId}`)
+    .then((r) => r.data)
+    .catch((err) => {
+      if (err?.status === 404) {
+        throw new NotFoundError(`Post with id "${postId}" not found!`)
+      }
+      throw err
+    })
 }
🤖 Prompt for AI Agents
In e2e/vue-router/basic-vue-query/src/posts.ts around lines 12 to 37, fetchPost
currently assumes a falsy response to detect 404 but axios/redaxios will reject
on non-2xx so that check never runs; update fetchPost to catch the request
error, inspect error.response?.status and if it is 404 throw the NotFoundError
with the postId, otherwise rethrow the original error (or wrap with a
descriptive error) so other failures surface normally; ensure the error type
check is safe (use optional chaining) and preserve return of the post when
successful.

@birkskyum birkskyum merged commit eccfd26 into main Dec 12, 2025
6 checks passed
@birkskyum birkskyum deleted the e2e(vue-router)--vue-query-suites branch December 12, 2025 16:40
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