From a5f2f7470537ebd4c9df404f4afa535f73577339 Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Tue, 8 Aug 2023 15:45:41 +0200 Subject: [PATCH 1/2] test: add test for preview mode when using middleware --- cypress/e2e/middleware/preview.cy.ts | 34 ++++++++++++++++++++++ demos/middleware/middleware.ts | 29 +++++++++++------- demos/middleware/pages/api/enterPreview.js | 6 ++++ demos/middleware/pages/api/exitPreview.js | 8 +++++ demos/middleware/pages/index.js | 3 ++ demos/middleware/pages/previewTest.js | 25 ++++++++++++++++ 6 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 cypress/e2e/middleware/preview.cy.ts create mode 100644 demos/middleware/pages/api/enterPreview.js create mode 100644 demos/middleware/pages/api/exitPreview.js create mode 100644 demos/middleware/pages/previewTest.js 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 ( +
+

Is preview? {isPreview ? 'Yes!' : 'No'}

+

+ + {isPreview ? 'Exit Preview' : 'Enter Preview'} + +

+ Go back home +
+ ) +} + +export const getStaticProps = async ({ preview }) => { + return { + props: { + isPreview: Boolean(preview), + }, + } +} + +export default StaticTest From 59682f6acb85e40184a9122f89dff52e5e12565c Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Wed, 9 Aug 2023 17:06:32 +0200 Subject: [PATCH 2/2] fix: skip ever trying to run middleware in lambda --- packages/runtime/src/templates/server.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/runtime/src/templates/server.ts b/packages/runtime/src/templates/server.ts index 2adfe366bc..12e64fd722 100644 --- a/packages/runtime/src/templates/server.ts +++ b/packages/runtime/src/templates/server.ts @@ -18,6 +18,7 @@ interface NetlifyConfig { revalidateToken?: string } +// eslint-disable-next-line max-lines-per-function const getNetlifyNextServer = (NextServer: NextServerType) => { class NetlifyNextServer extends NextServer { private netlifyConfig: NetlifyConfig @@ -118,6 +119,13 @@ const getNetlifyNextServer = (NextServer: NextServerType) => { } } + // eslint-disable-next-line class-methods-use-this, require-await + async runMiddleware(): Promise<{ finished: boolean }> { + return { + finished: false, + } + } + private getNetlifyPathsForRoute(route: string): string[] { const { i18n } = this.nextConfig const { routes, dynamicRoutes } = this.netlifyPrerenderManifest