Skip to content

Commit

Permalink
action: support not found (#49209)
Browse files Browse the repository at this point in the history
<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Improving Documentation or adding/fixing Examples

- The "examples guidelines" are followed from our contributing doc
https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md
- Make sure the linting passes by running `pnpm build && pnpm lint`. See
https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See:
https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature
request has been accepted for implementation before opening a PR. (A
discussion must be opened, see
https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added
(https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md



## For Maintainers

- Minimal description (aim for explaining to someone not on the team to
understand the PR)
- When linking to a Slack thread, you might want to share details of the
conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Closes NEXT-
Fixes #

-->
  • Loading branch information
feedthejim authored May 4, 2023
1 parent 10af8c8 commit 51e51d2
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 15 deletions.
32 changes: 19 additions & 13 deletions packages/next/src/server/app-render/action-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ export async function handleAction({
generateFlight: (options: {
actionResult: ActionResult
skipFlight: boolean
asNotFound?: boolean
}) => Promise<RenderResult>
staticGenerationStore: StaticGenerationStore
}): Promise<undefined | RenderResult | 'not-found'> {
Expand Down Expand Up @@ -363,28 +364,33 @@ export async function handleAction({
res.statusCode = 303
return new RenderResult('')
} else if (isNotFoundError(err)) {
res.statusCode = 404

await Promise.all(staticGenerationStore.pendingRevalidates || [])
if (isFetchAction) {
throw new Error('Invariant: not implemented.')
const promise = Promise.reject(err)
try {
await promise
} catch (_) {}
return generateFlight({
skipFlight: false,
actionResult: promise,
asNotFound: true,
})
}
await Promise.all(staticGenerationStore.pendingRevalidates || [])
res.statusCode = 404
return 'not-found'
}

if (isFetchAction) {
res.statusCode = 500
const rejectedPromise = Promise.reject(err)
await Promise.all(staticGenerationStore.pendingRevalidates || [])
const promise = Promise.reject(err)
try {
// we need to await the promise to trigger the rejection early
// so that it's already handled by the time we call
// the RSC runtime. Otherwise, it will throw an unhandled
// promise rejection error in the renderer.
await rejectedPromise
} catch (_) {
// swallow error, it's gonna be handled on the client
}
await promise
} catch (_) {}

return generateFlight({
actionResult: rejectedPromise,
actionResult: promise,
// if the page was not revalidated, we can skip the rendering the flight tree
skipFlight: !staticGenerationStore.pathWasRevalidated,
})
Expand Down
3 changes: 2 additions & 1 deletion packages/next/src/server/app-render/app-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,7 @@ export async function renderToHTMLOrFlight(
const generateFlight = async (options?: {
actionResult: ActionResult
skipFlight: boolean
asNotFound?: boolean
}): Promise<RenderResult> => {
/**
* Use router state to decide at what common layout to render the page.
Expand Down Expand Up @@ -1176,7 +1177,7 @@ export async function renderToHTMLOrFlight(
injectedCSS: new Set(),
injectedFontPreloadTags: new Set(),
rootLayoutIncluded: false,
asNotFound: pathname === '/404',
asNotFound: pathname === '/404' || options?.asNotFound,
})
).map((path) => path.slice(1)) // remove the '' (root) segment

Expand Down
12 changes: 11 additions & 1 deletion test/e2e/app-dir/actions/app-action.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ createNextDescribe(
}, '/header?name=test&constructor=FormData')
})

it('should support notFound', async () => {
it('should support notFound (javascript disabled)', async () => {
const browser = await next.browser('/server', {
// TODO we should also test this with javascript on but not-found is not implemented yet.
disableJavaScript: true,
Expand All @@ -91,6 +91,16 @@ createNextDescribe(
}, 'my-not-found')
})

it('should support notFound', async () => {
const browser = await next.browser('/server')

await browser.elementByCss('#nowhere').click()

await check(() => {
return browser.elementByCss('h1').text()
}, 'my-not-found')
})

it('should support uploading files', async () => {
const logs: string[] = []
next.on('stdout', (log) => {
Expand Down

0 comments on commit 51e51d2

Please sign in to comment.