Skip to content

fix(pages-router): router.push() resolves to true on success#1566

Open
james-elicx wants to merge 1 commit into
mainfrom
fix/pages-router-push-return
Open

fix(pages-router): router.push() resolves to true on success#1566
james-elicx wants to merge 1 commit into
mainfrom
fix/pages-router-push-return

Conversation

@james-elicx
Copy link
Copy Markdown
Member

Closes #1467

Summary

  • Pages Router router.push/router.replace already resolved to true on success and false on a hard-navigation fallback via performNavigation. This PR pins down the contract on the public window.next.router surface so consumers (and the Next.js deploy test suite that awaits the return value) get a typed Promise<boolean> instead of unknown.
  • Adds regression unit tests asserting await window.next.router.push("/foo") and await window.next.router.replace("/foo") resolve to true.
  • Voids two router.push(...) calls in tests/e2e/app-router/build-id-navigation.spec.ts to satisfy the tightened union (App Router push is void).

Test plan

  • vp test run tests/shims.test.ts -t "window.next.router.push resolves to true" (added test)
  • vp test run tests/shims.test.ts (974 passed)
  • vp test run tests/pages-router.test.ts (241 passed)
  • vp test run tests/router-javascript-urls.test.ts (21 passed)
  • vp check (no warnings or errors)

Pages Router `window.next.router.push`/`replace` already resolved to
`true` on a successful navigation (and `false` on a hard-navigation
fallback) via `performNavigation`, but the public `window.next.router`
surface typed both as `(...args: unknown[]) => unknown`, leaving
consumers (and the Next.js deploy test suite that `awaits` the result)
without a typed boolean to assert on.

- Narrow `PagesRouterPublicInstance.push`/`replace` to
  `(...args: unknown[]) => Promise<boolean>` to match Next.js's
  `Router.change` contract (router.ts:1206 — `Promise<boolean>`).
- Add unit-test regression coverage asserting
  `window.next.router.push`/`replace` resolve to `true` on success.
- Void the `router.push(...)` calls in `tests/e2e/app-router/build-id-navigation.spec.ts`
  to satisfy the tightened union (App Router push is `void`).

Closes #1467
@james-elicx
Copy link
Copy Markdown
Member Author

/bigbonk review

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 22, 2026

Open in StackBlitz

npm i https://pkg.pr.new/vinext@1566

commit: ceda632

@github-actions
Copy link
Copy Markdown

Example Preview Production Original
app-router-cloudflare preview production
pages-router-cloudflare preview production
app-router-playground preview production original
realworld-api-rest preview production
nextra-docs-template preview production
benchmarks preview production
hackernews preview production original
web preview production

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot left a comment

Choose a reason for hiding this comment

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

Clean, minimal fix. The type tightening, void annotations, and regression tests all look correct.

Verified:

  • performNavigation exhaustively returns true or false on every non-throwing path (lines 916, 939, 948, 949, 960 in router.ts), so the Promise<boolean> annotation is accurate.
  • push/replace in RouterMethods directly return performNavigation(...) with no intermediate processing — no path can resolve to undefined.
  • The void router.push(target) in the E2E spec is the right fix: App Router push returns void, Pages Router returns Promise<boolean>, so the union is void | Promise<boolean>. void suppresses the floating-promise lint without changing behavior.
  • Tests cover both push and replace via shallow navigation, which is sufficient to exercise the return-value contract without needing a full navigateClient stub.
  • Test cleanup (finally block restoring window + vi.resetModules()) matches the established pattern in the surrounding window.next test block.

LGTM.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented May 22, 2026

Approved PR #1566. The change is straightforward and correct:

  • The Promise<boolean> return type on PagesRouterPublicInstance.push/.replace accurately reflects what performNavigation already returns at runtime — every non-throwing path returns true or false explicitly.
  • The void router.push(...) in the E2E spec is the right way to handle the void | Promise<boolean> union from the App/Pages Router type split.
  • Regression tests cover both methods and use shallow navigation to isolate the return-value contract.

github run

@james-elicx james-elicx marked this pull request as ready for review May 22, 2026 14:53
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.

Pages Router: router.push() resolves to undefined instead of true

1 participant