rsnext/test/e2e/app-dir/app-routes/helpers.ts
Jiachi Liu a63b89b140
Loose types of app routes return value (#55849)
### What

#51394 introduced a pretty strict type of return value of route type
that causing failure with `next build`.
There're few ways of writing a app route, it could contain few return
values based on the usage:

* return a `Response` or promise of it
* return `NextResponse` of promise of it, since it's extended from
`Response`, same type
* use `redirect()` or `notFound(), since it returns `never`, and the
below code is not reached, the handler itself could still return void.
e.g. using `redirect` in a `GET` route

We loosed the type so `redirect()` can be still allowed without
specifying the return value there.
Related typescript issue:
https://github.com/microsoft/TypeScript/issues/16608#issuecomment-309327984

### How
* Re-enable the bail on types / build error in the app-routes tests
* Separate the tests, move runtime erroring ones to
`test/e2e/app-dir/app-routes-errors`
* Add new case to app-routes tests of mixed return value

Closes #55623 
Related #55604
2023-09-25 11:34:21 +02:00

77 lines
2.4 KiB
TypeScript

import type { ReadonlyHeaders } from 'next/dist/server/web/spec-extension/adapters/headers'
import type { ReadonlyRequestCookies } from 'next/dist/server/web/spec-extension/adapters/request-cookies'
const KEY = 'x-request-meta'
/**
* Adds a new header to the headers object and serializes it. To be used in
* conjunction with the `getRequestMeta` function in tests to verify request
* data from the handler.
*
* @param meta metadata to inject into the headers
* @param headers the existing headers on the response to merge with
* @returns the merged headers with the request meta added
*/
export function withRequestMeta(
meta: Record<string, any>,
headers: Record<string, string> = {}
): Record<string, string> {
return {
...headers,
[KEY]: JSON.stringify(meta),
}
}
/**
* Adds a cookie to the headers with the provided request metadata. Existing
* cookies will be merged, but it will not merge request metadata that already
* exists on an existing cookie.
*
* @param meta metadata to inject into the headers via a cookie
* @param headers the existing headers on the response to merge with
* @returns the merged headers with the request meta added as a cookie
*/
export function cookieWithRequestMeta(
meta: Record<string, any>,
{ cookie = '', ...headers }: Record<string, string> = {}
): Record<string, string> {
if (cookie) cookie += '; '
// We encode this with `btoa` because the JSON string can contain characters
// that are invalid in a cookie value.
cookie += `${KEY}=${btoa(JSON.stringify(meta))}`
return {
...headers,
cookie,
}
}
type Cookies = {
get(name: string): { name: string; value: string } | undefined
}
/**
* Gets request metadata from the response headers or cookie.
*
* @param headersOrCookies response headers from the request or cookies object
* @returns any injected metadata on the request
*/
export function getRequestMeta(
headersOrCookies:
| Headers
| Cookies
| ReadonlyHeaders
| ReadonlyRequestCookies
| import('next/dist/compiled/node-fetch').Headers
): Record<string, any> {
const headerOrCookie = headersOrCookies.get(KEY)
if (!headerOrCookie) return {}
// If the value is a string, then parse it now, it was headers.
if (typeof headerOrCookie === 'string') return JSON.parse(headerOrCookie)
// It's a cookie! Parse it now. The cookie value should be encoded with
// `btoa`, hence the use of `atob`.
return JSON.parse(atob(headerOrCookie.value))
}