Skip to content

Commit

Permalink
Merge branch 'canary' into update-with-styletron-example
Browse files Browse the repository at this point in the history
  • Loading branch information
PapatMayuri authored Nov 29, 2024
2 parents 5ab30d1 + f5e35b8 commit df95d9f
Show file tree
Hide file tree
Showing 15 changed files with 142 additions and 127 deletions.
9 changes: 4 additions & 5 deletions packages/next/src/server/request/draft-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,6 @@ export function draftMode(): Promise<DraftMode> {
const workUnitStore = workUnitAsyncStorage.getStore()

if (workUnitStore) {
if (workStore && workUnitStore.phase === 'after') {
throw new Error(
`Route ${workStore.route} used "draftMode" inside "unstable_after(...)". This is not supported, because "unstable_after(...)" runs after the request is finished and cannot affect the response. See more info here: https://nextjs.org/docs/canary/app/api-reference/functions/unstable_after`
)
}
if (
workUnitStore.type === 'cache' ||
workUnitStore.type === 'unstable-cache' ||
Expand Down Expand Up @@ -240,6 +235,10 @@ function trackDynamicDraftMode(expression: string) {
throw new Error(
`Route ${store.route} used "${expression}" inside a function cached with "unstable_cache(...)". The enabled status of draftMode can be read in caches but you must not enable or disable draftMode inside a cache. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache`
)
} else if (workUnitStore.phase === 'after') {
throw new Error(
`Route ${store.route} used "${expression}" inside \`unstable_after\`. The enabled status of draftMode can be read inside \`unstable_after\` but you cannot enable or disable draftMode. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_after`
)
}
}

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
/* eslint-env jest */
import { nextTestSetup } from 'e2e-utils'
import * as Log from './basic/utils/log'
import {
assertHasRedbox,
getRedboxSource,
retry,
} from '../../../lib/next-test-utils'
import { assertHasRedbox, getRedboxSource } from '../../../lib/next-test-utils'
import { join } from 'path'

describe('unstable_after() - invalid usages', () => {
Expand Down Expand Up @@ -36,70 +32,3 @@ describe('unstable_after() - invalid usages', () => {
expect(getAfterLogs()).toHaveLength(0)
})
})

describe('unstable_after() - dynamic APIs', () => {
const { next } = nextTestSetup({
files: join(__dirname, 'dynamic-apis'),
})

let currentCliOutputIndex = 0
beforeEach(() => {
resetLogs()
})

const resetLogs = () => {
currentCliOutputIndex = next.cliOutput.length
}

const getLogs = () => {
if (next.cliOutput.length < currentCliOutputIndex) {
// cliOutput shrank since we started the test, so something (like a `sandbox`) reset the logs
currentCliOutputIndex = 0
}
return next.cliOutput.slice(currentCliOutputIndex)
}

describe('awaited calls', () => {
it.each([
{
api: 'connection',
path: '/dynamic-apis/connection',
expectedError: `An error occurred in a function passed to \`unstable_after()\`: Error: Route /dynamic-apis/connection used "connection" inside "unstable_after(...)".`,
},
{
api: 'cookies',
path: '/dynamic-apis/cookies',
expectedError: `An error occurred in a function passed to \`unstable_after()\`: Error: Route /dynamic-apis/cookies used "cookies" inside "unstable_after(...)".`,
},
{
api: 'draftMode',
path: '/dynamic-apis/draft-mode',
expectedError: `An error occurred in a function passed to \`unstable_after()\`: Error: Route /dynamic-apis/draft-mode used "draftMode" inside "unstable_after(...)".`,
},
{
api: 'headers',
path: '/dynamic-apis/headers',
expectedError: `An error occurred in a function passed to \`unstable_after()\`: Error: Route /dynamic-apis/headers used "headers" inside "unstable_after(...)".`,
},
])(
'does not allow calling $api inside unstable_after',
async ({ path, expectedError }) => {
const res = await next.fetch(path)
await res.text()
await retry(() => {
expect(getLogs()).toInclude(expectedError)
})
}
)
})

// TODO(after): test unawaited calls, like this
//
// export default function Page() {
// const promise = headers()
// after(async () => {
// const headerStore = await promise
// })
// return null
// }
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { unstable_after as after } from 'next/server'
import { draftMode } from 'next/headers'

export function testDraftMode(/** @type {string} */ route) {
after(async () => {
const draft = await draftMode()
try {
console.log(`[${route}] draft.isEnabled: ${draft.isEnabled}`)
} catch (err) {
console.error(err)
}
})

after(async () => {
const draft = await draftMode()
try {
draft.enable()
} catch (err) {
console.error(err)
}
})

after(async () => {
const draft = await draftMode()
try {
draft.disable()
} catch (err) {
console.error(err)
}
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { connection } from 'next/server'
import { testDraftMode } from '../helpers'

export default async function Page() {
await connection()
testDraftMode('/draft-mode/page-dynamic')
return null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { testDraftMode } from '../helpers'

export default function Page() {
testDraftMode('/draft-mode/page-static')
return null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { testDraftMode } from '../helpers'

export async function GET() {
testDraftMode('/draft-mode/route-handler-dynamic')
return new Response()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { testDraftMode } from '../helpers'

export const dynamic = 'force-static'

export async function GET() {
testDraftMode('/draft-mode/route-handler-static')
return new Response()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { testDraftMode } from '../helpers'

export default async function Page() {
return (
<form
action={async () => {
'use server'
testDraftMode('/draft-mode/server-action')
}}
>
<button type="submit">Submit</button>
</form>
)
}
64 changes: 64 additions & 0 deletions test/e2e/app-dir/next-after-app-api-usage/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ describe('nextjs APIs in unstable_after()', () => {
})

describe('request APIs cannot be called inside unstable_after()', () => {
// TODO(after): test unawaited calls, like this
//
// export default function Page() {
// const promise = headers()
// after(async () => {
// const headerStore = await promise
// })
// return null
// }

it('in a dynamic page', async () => {
const path = '/request-apis/page-dynamic'
await next.render(path)
Expand Down Expand Up @@ -140,4 +150,58 @@ describe('nextjs APIs in unstable_after()', () => {
})
})
})

describe('draftMode status is readable, but cannot be changed', () => {
it.each([
{
title: 'dynamic page',
path: '/draft-mode/page-dynamic',
isDynamic: true,
},
{
title: 'static page',
path: '/draft-mode/page-static',
isDynamic: false,
},
{
title: 'dynamic route handler',
path: '/draft-mode/route-handler-dynamic',
isDynamic: true,
},
{
title: 'static route handler',
path: '/draft-mode/route-handler-static',
isDynamic: false,
},
])('$title', async ({ path, isDynamic }) => {
await next.render(path)
await retry(() => {
// in `next start`, static routes log the error at build time
const logs = isDynamic || isNextDev ? getLogs() : buildLogs
expect(logs).toContain(`[${path}] draft.isEnabled: false`)
expect(logs).toContain(
`Route ${path} used "draftMode().enable()" inside \`unstable_after\``
)
expect(logs).toContain(
`Route ${path} used "draftMode().disable()" inside \`unstable_after\``
)
})
})

it('server action', async () => {
const path = '/draft-mode/server-action'
const browser = await next.browser(path)
await browser.elementByCss('button[type="submit"]').click()
await retry(() => {
const logs = getLogs()
expect(logs).toContain(`[${path}] draft.isEnabled: false`)
expect(logs).toContain(
`Route ${path} used "draftMode().enable()" inside \`unstable_after\``
)
expect(logs).toContain(
`Route ${path} used "draftMode().disable()" inside \`unstable_after\``
)
})
})
})
})

0 comments on commit df95d9f

Please sign in to comment.