Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { PathnameLabel } from './pathname-label'

export default function Page() {
return (
<main>
<PathnameLabel />
</main>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use client'

import { usePathname } from 'next/navigation'

export function PathnameLabel() {
const pathname = usePathname()
return <span data-testid="pathname-label">{pathname}</span>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use client'

import { useSelectedLayoutSegment } from 'next/navigation'

export function ActiveTab() {
const segment = useSelectedLayoutSegment()
return <span data-testid="active-tab">{segment}</span>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ActiveTab } from './active-tab'

export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div>
<ActiveTab />
{children}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return <main>Leaf page</main>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use client'

import { useSelectedLayoutSegments } from 'next/navigation'

export function BreadcrumbTrail() {
const segments = useSelectedLayoutSegments()
return <span data-testid="breadcrumb-trail">{segments.join('/')}</span>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { BreadcrumbTrail } from './breadcrumb-trail'

export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div>
<BreadcrumbTrail />
{children}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return <main>Leaf page</main>
}
9 changes: 9 additions & 0 deletions test/e2e/app-dir/instant-validation/app/default/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ export default async function Page() {
<li>
<DebugLinks href="/default/static/valid-blocking-inside-static" />
</li>
<li>
<DebugLinks href="/default/invalid-use-pathname-no-samples/123" />
</li>
<li>
<DebugLinks href="/default/invalid-use-selected-layout-segment-no-samples/123" />
</li>
<li>
<DebugLinks href="/default/invalid-use-selected-layout-segments-no-samples/123" />
</li>
</ul>
</main>
)
Expand Down
43 changes: 43 additions & 0 deletions test/e2e/app-dir/instant-validation/instant-validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
waitForValidation,
} from 'e2e-utils/instant-validation'
import {
getRedboxSource,
openRedbox,
retry,
waitForNoErrorToast,
Expand Down Expand Up @@ -1893,6 +1894,48 @@ describe('instant validation', () => {
expectNoBuildValidationErrors(result)
}
})

// usePathname is misclassified as "uncached data" today and the dev
// overlay attributes the error to the parent's JSX line. This test
// asserts the correct stack attribution. When the URL-hook factory
// lands, `it.failing` will itself fail — flip to `it`.
/* eslint-disable jest/no-standalone-expect */
;(isNextDev && !isClientNav ? it.failing : it)(
'invalid - usePathname() in a client component on a route with a fallback param',
async () => {
if (!isNextDev || isClientNav) return
const browser = await navigateTo(
'/default/invalid-use-pathname-no-samples/123'
)
await openRedbox(browser)
const source = await getRedboxSource(browser)
expect(source).toContain('pathname-label.tsx')
expect(source).toContain('PathnameLabel')
}
)

it('invalid - useSelectedLayoutSegment() in a layout on a route with a fallback param', async () => {
if (!isNextDev || isClientNav) return
const browser = await navigateTo(
'/default/invalid-use-selected-layout-segment-no-samples/123'
)
await openRedbox(browser)
const source = await getRedboxSource(browser)
expect(source).toContain('active-tab.tsx')
expect(source).toContain('ActiveTab')
})

it('invalid - useSelectedLayoutSegments() in a layout on a route with a fallback param', async () => {
if (!isNextDev || isClientNav) return
const browser = await navigateTo(
'/default/invalid-use-selected-layout-segments-no-samples/123'
)
await openRedbox(browser)
const source = await getRedboxSource(browser)
expect(source).toContain('breadcrumb-trail.tsx')
expect(source).toContain('BreadcrumbTrail')
})
/* eslint-enable jest/no-standalone-expect */
})

describe('client errors', () => {
Expand Down
Loading