diff --git a/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/layout.tsx b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/layout.tsx new file mode 100644 index 0000000000000..716a8db36f52c --- /dev/null +++ b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/layout.tsx @@ -0,0 +1,9 @@ +import { ReactNode } from 'react' + +export default function Root({ children }: { children: ReactNode }) { + return ( + + {children} + + ) +} diff --git a/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/learn/layout.tsx b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/learn/layout.tsx new file mode 100644 index 0000000000000..5c70dee3e39ac --- /dev/null +++ b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/learn/layout.tsx @@ -0,0 +1,9 @@ +import { ReactNode } from 'react' +import { getUser } from '../lib/get-user' +import { UserProvider } from '../user-provider' + +export default function LearnLayout({ children }: { children: ReactNode }) { + const userPromise = getUser() + + return {children} +} diff --git a/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/learn/page.tsx b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/learn/page.tsx new file mode 100644 index 0000000000000..87fc4ddc71430 --- /dev/null +++ b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/learn/page.tsx @@ -0,0 +1,12 @@ +import { UserCardShell } from '../user-card-shell' + +export default async function LearnPage() { + 'use cache' + + return ( +
+

Learn

+ +
+ ) +} diff --git a/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/lib/get-user.ts b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/lib/get-user.ts new file mode 100644 index 0000000000000..2dfb4d090a371 --- /dev/null +++ b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/lib/get-user.ts @@ -0,0 +1,12 @@ +import { cookies } from 'next/headers' + +export async function getUser(): Promise<{ name: string }> { + const cookieStore = await cookies() + const userCookie = cookieStore.get('user') + + if (!userCookie) { + return { name: 'Guest' } + } + + return { name: userCookie.value } +} diff --git a/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/page.tsx b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/page.tsx new file mode 100644 index 0000000000000..166b2d085c666 --- /dev/null +++ b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/page.tsx @@ -0,0 +1,12 @@ +import Link from 'next/link' + +export default function Page() { + return ( +
+

User promise demo

+ + Go to learn + +
+ ) +} diff --git a/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/user-card-shell.tsx b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/user-card-shell.tsx new file mode 100644 index 0000000000000..68b2ae89fdc2f --- /dev/null +++ b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/user-card-shell.tsx @@ -0,0 +1,12 @@ +'use client' + +import { Suspense } from 'react' +import { UserCard } from './user-card' + +export function UserCardShell() { + return ( + loading

}> + +
+ ) +} diff --git a/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/user-card.tsx b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/user-card.tsx new file mode 100644 index 0000000000000..e88bdd59ad4e5 --- /dev/null +++ b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/user-card.tsx @@ -0,0 +1,9 @@ +'use client' + +import { useUser } from './user-provider' + +export function UserCard() { + const user = useUser() + + return

user: {user?.name ?? 'unknown'}

+} diff --git a/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/user-provider.tsx b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/user-provider.tsx new file mode 100644 index 0000000000000..35c06dd843666 --- /dev/null +++ b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/app/user-provider.tsx @@ -0,0 +1,29 @@ +'use client' + +import { createContext, ReactNode, use } from 'react' + +type User = { name: string } | undefined + +const UserContext = createContext | null>(null) +UserContext.displayName = 'UserContext' + +export function UserProvider({ + children, + userPromise, +}: { + children: ReactNode + userPromise: Promise +}) { + return ( + {children} + ) +} + +export function useUser(): User { + const userPromise = use(UserContext) + if (!userPromise) { + throw new Error('useUser must be used within a UserProvider') + } + + return use(userPromise) +} diff --git a/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/next.config.js b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/next.config.js new file mode 100644 index 0000000000000..e64bae22d6580 --- /dev/null +++ b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/next.config.js @@ -0,0 +1,8 @@ +/** + * @type {import('next').NextConfig} + */ +const nextConfig = { + cacheComponents: true, +} + +module.exports = nextConfig diff --git a/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/prefetch-partial-rsc.test.ts b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/prefetch-partial-rsc.test.ts new file mode 100644 index 0000000000000..70dfe8ac8c903 --- /dev/null +++ b/test/e2e/app-dir/segment-cache/prefetch-partial-rsc/prefetch-partial-rsc.test.ts @@ -0,0 +1,17 @@ +import { nextTestSetup } from 'e2e-utils' +import { retry } from 'next-test-utils' + +describe('prefetch-partial-rsc', () => { + const { next } = nextTestSetup({ + files: __dirname, + }) + + it('resolves after a client-side navigation', async () => { + const browser = await next.browser('/') + await browser.elementByCss('#learn-link').click() + await retry(async () => { + const text = await browser.elementByCss('#user').text() + expect(text).toBe('user: Guest') + }) + }) +})