Skip to content

Commit

Permalink
Ensure path can be specified for clearPreviewData (#40238)
Browse files Browse the repository at this point in the history
As updated in #38313 this ensures the `path` option can also be passed to `clearPreviewData` to properly clear the preview cookies. 

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

Fixes: #39853
  • Loading branch information
ijjk committed Sep 5, 2022
1 parent 6e27382 commit 6f35235
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 4 deletions.
12 changes: 11 additions & 1 deletion packages/next/server/api-utils/index.ts
Expand Up @@ -2,6 +2,7 @@ import type { IncomingMessage } from 'http'
import type { BaseNextRequest } from '../base-http'

import { NextApiRequest, NextApiResponse } from '../../shared/lib/utils'
import type { CookieSerializeOptions } from 'next/dist/compiled/cookie'

export type NextApiRequestCookies = Partial<{ [key: string]: string }>
export type NextApiRequestQuery = Partial<{ [key: string]: string | string[] }>
Expand Down Expand Up @@ -98,7 +99,10 @@ export const SYMBOL_PREVIEW_DATA = Symbol(COOKIE_NAME_PRERENDER_DATA)
export const SYMBOL_CLEARED_COOKIES = Symbol(COOKIE_NAME_PRERENDER_BYPASS)

export function clearPreviewData<T>(
res: NextApiResponse<T>
res: NextApiResponse<T>,
options: {
path?: string
} = {}
): NextApiResponse<T> {
if (SYMBOL_CLEARED_COOKIES in res) {
return res
Expand All @@ -122,6 +126,9 @@ export function clearPreviewData<T>(
sameSite: process.env.NODE_ENV !== 'development' ? 'none' : 'lax',
secure: process.env.NODE_ENV !== 'development',
path: '/',
...(options.path !== undefined
? ({ path: options.path } as CookieSerializeOptions)
: undefined),
}),
serialize(COOKIE_NAME_PRERENDER_DATA, '', {
// To delete a cookie, set `expires` to a date in the past:
Expand All @@ -132,6 +139,9 @@ export function clearPreviewData<T>(
sameSite: process.env.NODE_ENV !== 'development' ? 'none' : 'lax',
secure: process.env.NODE_ENV !== 'development',
path: '/',
...(options.path !== undefined
? ({ path: options.path } as CookieSerializeOptions)
: undefined),
}),
])

Expand Down
3 changes: 2 additions & 1 deletion packages/next/server/api-utils/node.ts
Expand Up @@ -494,7 +494,8 @@ export async function apiResolver(
redirect(apiRes, statusOrUrl, url)
apiRes.setPreviewData = (data, options = {}) =>
setPreviewData(apiRes, data, Object.assign({}, apiContext, options))
apiRes.clearPreviewData = () => clearPreviewData(apiRes)
apiRes.clearPreviewData = (options = {}) =>
clearPreviewData(apiRes, options)
apiRes.revalidate = (
urlPath: string,
opts?: {
Expand Down
6 changes: 5 additions & 1 deletion packages/next/shared/lib/utils.ts
Expand Up @@ -263,7 +263,11 @@ export type NextApiResponse<T = any> = ServerResponse & {
path?: string
}
) => NextApiResponse<T>
clearPreviewData: () => NextApiResponse<T>

/**
* Clear preview data for Next.js' prerender mode
*/
clearPreviewData: (options?: { path?: string }) => NextApiResponse<T>

/**
* @deprecated `unstable_revalidate` has been renamed to `revalidate`
Expand Down
8 changes: 7 additions & 1 deletion test/integration/prerender-preview/pages/api/reset.js
@@ -1,4 +1,10 @@
export default (req, res) => {
res.clearPreviewData()
res.clearPreviewData(
req.query.cookiePath
? {
path: req.query.cookiePath,
}
: undefined
)
res.status(200).end()
}
32 changes: 32 additions & 0 deletions test/integration/prerender-preview/test/index.test.js
Expand Up @@ -211,6 +211,38 @@ function runTests(startServer = nextStart) {
expect(cookies[1]).not.toHaveProperty('Max-Age')
})

it('should return cookies to be expired on reset request with path specified', async () => {
const res = await fetchViaHTTP(
appPort,
'/api/reset',
{ cookiePath: '/blog' },
{ headers: { Cookie: previewCookieString } }
)
expect(res.status).toBe(200)

const cookies = res.headers
.get('set-cookie')
.replace(/(=(?!Lax)\w{3}),/g, '$1')
.split(',')
.map(cookie.parse)

expect(cookies.length).toBe(2)
expect(cookies[0]).toMatchObject({
Path: '/blog',
SameSite: 'None',
Expires: 'Thu 01 Jan 1970 00:00:00 GMT',
})
expect(cookies[0]).toHaveProperty('__prerender_bypass')
expect(cookies[0]).not.toHaveProperty('Max-Age')
expect(cookies[1]).toMatchObject({
Path: '/blog',
SameSite: 'None',
Expires: 'Thu 01 Jan 1970 00:00:00 GMT',
})
expect(cookies[1]).toHaveProperty('__next_preview_data')
expect(cookies[1]).not.toHaveProperty('Max-Age')
})

it('should pass undefined to API routes when not in preview', async () => {
const res = await fetchViaHTTP(appPort, `/api/read`)
const json = await res.json()
Expand Down

0 comments on commit 6f35235

Please sign in to comment.