diff --git a/cypress/e2e/middleware/preview.cy.ts b/cypress/e2e/middleware/preview.cy.ts new file mode 100644 index 0000000000..6249bb7fa3 --- /dev/null +++ b/cypress/e2e/middleware/preview.cy.ts @@ -0,0 +1,34 @@ +describe('Preview Mode', () => { + it('enters and exits preview mode', () => { + Cypress.Cookies.debug(true) + cy.getCookies().then((cookie) => cy.log('cookies', cookie)) + + cy.intercept('/previewTest', (req) => { + req.continue((res) => { + expect(res.headers?.['x-middleware-executed']).to.equal('true') + }) + }).as('previewTestVisit') + + // preview mode is off by default + cy.visit('/previewTest') + cy.findByText('Is preview? No', { selector: 'h1' }) + + // enter preview mode + cy.request('/api/enterPreview').then((response) => { + expect(response.body).to.have.property('name', 'preview mode') + }) + + // exptected content is rendered + cy.visit('/previewTest') + cy.findByText('Is preview? Yes!', { selector: 'h1' }) + + // exit preview mode + cy.request('/api/exitPreview') + cy.visit('/previewTest') + cy.findByText('Is preview? No', { selector: 'h1' }) + + // we should hit /previewTest 3 times (before entering preview, after entering preview, after exiting preview) + // this assertion is mainly to ensure interception works and assertion on response header is made + cy.get('@previewTestVisit.all').should('have.length', 3) + }) +}) diff --git a/demos/middleware/middleware.ts b/demos/middleware/middleware.ts index 49941dd039..04f894b042 100644 --- a/demos/middleware/middleware.ts +++ b/demos/middleware/middleware.ts @@ -15,11 +15,11 @@ export async function middleware(req: NextRequest) { headers.set('x-hello', 'world') return NextResponse.next({ request: { - headers - } + headers, + }, }) } - + const request = new MiddlewareRequest(req) // skipMiddlewareUrlNormalize next config option is used so we have to try to match both html path and data blob path @@ -41,12 +41,11 @@ export async function middleware(req: NextRequest) { // skipMiddlewareUrlNormalize next config option is used so we have to try to match both html path and data blob path if (pathname.startsWith('/request-rewrite') || pathname.endsWith('/request-rewrite.json')) { // request.rewrite() should return the MiddlewareResponse object instead of the Response object. - const res = await request.rewrite('/static-rewrite', - { + const res = await request.rewrite('/static-rewrite', { headers: { 'x-rewrite-test': 'hello', - 'x-rewrite-test-2': 'hello-2' - } + 'x-rewrite-test-2': 'hello-2', + }, }) const message = `This was static (& escaping test &) but has been transformed in ${req.geo?.city}` @@ -90,7 +89,7 @@ export async function middleware(req: NextRequest) { return response } - if(pathname.startsWith('/matcher-cookie')) { + if (pathname.startsWith('/matcher-cookie')) { response = NextResponse.next() response.cookies.set('missingCookie', 'true') return response @@ -109,6 +108,13 @@ export async function middleware(req: NextRequest) { return response } + if (pathname.startsWith('/previewTest')) { + response = NextResponse.next() + + response.headers.set('x-middleware-executed', 'true') + return response + } + if (pathname.includes('locale-preserving-rewrite')) { return NextResponse.rewrite(new URL('/locale-test', req.url)) } @@ -167,8 +173,8 @@ export const config = { '/:all*/locale-preserving-rewrite', '/cookies/:path*', { source: '/static' }, - {source: '/request-rewrite' }, - { source: '/matcher-cookie'}, + { source: '/request-rewrite' }, + { source: '/matcher-cookie' }, { source: '/shows/((?!99|88).*)' }, { source: '/conditional', @@ -186,8 +192,9 @@ export const config = { { type: 'cookie', key: 'missingCookie', - } + }, ], }, + '/previewTest', ], } diff --git a/demos/middleware/pages/api/enterPreview.js b/demos/middleware/pages/api/enterPreview.js new file mode 100644 index 0000000000..3557d0ff45 --- /dev/null +++ b/demos/middleware/pages/api/enterPreview.js @@ -0,0 +1,6 @@ +export default async function preview(req, res) { + // Enable Preview Mode by setting the cookies + res.setPreviewData({}) + + res.status(200).json({ name: 'preview mode' }) +} diff --git a/demos/middleware/pages/api/exitPreview.js b/demos/middleware/pages/api/exitPreview.js new file mode 100644 index 0000000000..6c63a0a6e8 --- /dev/null +++ b/demos/middleware/pages/api/exitPreview.js @@ -0,0 +1,8 @@ +export default async function exit(_, res) { + // Exit the current user from "Preview Mode". This function accepts no args. + res.clearPreviewData() + + // Redirect the user back to the index page. + res.writeHead(307, { Location: '/' }) + res.end() +} diff --git a/demos/middleware/pages/index.js b/demos/middleware/pages/index.js index 288eb25ffe..46bb467679 100644 --- a/demos/middleware/pages/index.js +++ b/demos/middleware/pages/index.js @@ -48,6 +48,9 @@ export default function Home() {
Adds `x-hello` request header to a rewrite
++ Preview mode +
) diff --git a/demos/middleware/pages/previewTest.js b/demos/middleware/pages/previewTest.js new file mode 100644 index 0000000000..5aac9598da --- /dev/null +++ b/demos/middleware/pages/previewTest.js @@ -0,0 +1,25 @@ +import Link from 'next/link' + +const StaticTest = ({ isPreview }) => { + return ( +