diff --git a/tests/e2e/with-integrations.test.ts b/tests/e2e/with-integrations.test.ts new file mode 100644 index 0000000000..5df1582ff9 --- /dev/null +++ b/tests/e2e/with-integrations.test.ts @@ -0,0 +1,56 @@ +import { expect } from '@playwright/test' +import { test } from '../utils/playwright-helpers.js' + +test('Renders the Home page correctly', async ({ page, withIntegrations }) => { + await page.goto(withIntegrations.url) + + expect(page.locator('body')).toHaveText('Hello World') +}) + +test.describe('Should clear stale functions produced by previous builds by @netlify/plugin-nextjs', () => { + test('Serverless functions', async ({ page, withIntegrations }) => { + const response1 = await page.goto(new URL('/test/serverless/v4', withIntegrations.url).href) + expect(response1?.status()).toBe(404) + + const response2 = await page.goto(new URL('/test/serverless/v5', withIntegrations.url).href) + expect(response2?.status()).toBe(404) + }) + + test('Edge functions', async ({ page, withIntegrations }) => { + const response1 = await page.goto(new URL('/test/edge/v4', withIntegrations.url).href) + expect(response1?.status()).toBe(404) + + const response2 = await page.goto(new URL('/test/edge/v5', withIntegrations.url).href) + expect(response2?.status()).toBe(404) + }) +}) + +test.describe('Should keep functions produced by other build plugins', () => { + test('Serverless functions', async ({ page, withIntegrations }) => { + const response1 = await page.goto( + new URL('/test/serverless/integration-with-json-config', withIntegrations.url).href, + ) + expect(response1?.status()).toBe(200) + expect(await response1?.text()).toBe('Hello from /test/serverless/integration-with-json-config') + + const response2 = await page.goto( + new URL('/test/serverless/integration-with-json-config', withIntegrations.url).href, + ) + expect(response2?.status()).toBe(200) + expect(await response2?.text()).toBe('Hello from /test/serverless/integration-with-json-config') + }) + + test('Edge functions', async ({ page, withIntegrations }) => { + const response1 = await page.goto( + new URL('/test/edge/integration-in-manifest', withIntegrations.url).href, + ) + expect(response1?.status()).toBe(200) + expect(await response1?.text()).toBe('Hello from /test/edge/integration-in-manifest') + + const response2 = await page.goto( + new URL('/test/edge/integration-not-in-manifest', withIntegrations.url).href, + ) + expect(response2?.status()).toBe(200) + expect(await response2?.text()).toBe('Hello from /test/edge/integration-not-in-manifest') + }) +}) diff --git a/tests/fixtures/with-integrations/netlify.toml b/tests/fixtures/with-integrations/netlify.toml new file mode 100644 index 0000000000..4c48c42e10 --- /dev/null +++ b/tests/fixtures/with-integrations/netlify.toml @@ -0,0 +1,2 @@ +[[plugins]] +package = "/plugins/create-other-functions" diff --git a/tests/fixtures/with-integrations/next.config.js b/tests/fixtures/with-integrations/next.config.js new file mode 100644 index 0000000000..8d2a9bf37a --- /dev/null +++ b/tests/fixtures/with-integrations/next.config.js @@ -0,0 +1,8 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + eslint: { + ignoreDuringBuilds: true, + }, +} + +module.exports = nextConfig diff --git a/tests/fixtures/with-integrations/package.json b/tests/fixtures/with-integrations/package.json new file mode 100644 index 0000000000..4c3fe8a3ac --- /dev/null +++ b/tests/fixtures/with-integrations/package.json @@ -0,0 +1,13 @@ +{ + "name": "with-integrations", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "next build" + }, + "dependencies": { + "next": "latest", + "react": "18.2.0", + "react-dom": "18.2.0" + } +} diff --git a/tests/fixtures/with-integrations/pages/index.js b/tests/fixtures/with-integrations/pages/index.js new file mode 100644 index 0000000000..c76736b1d1 --- /dev/null +++ b/tests/fixtures/with-integrations/pages/index.js @@ -0,0 +1,7 @@ +export default function Home() { + return ( +
+

Hello World

+
+ ) +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/integration-in-manifest.mjs b/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/integration-in-manifest.mjs new file mode 100644 index 0000000000..fa0e08423a --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/integration-in-manifest.mjs @@ -0,0 +1,3 @@ +export default function handler() { + return new Response('Hello from /test/edge/integration-in-manifest', { status: 200 }) +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/integration-not-in-manifest.mjs b/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/integration-not-in-manifest.mjs new file mode 100644 index 0000000000..6ae83beeae --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/integration-not-in-manifest.mjs @@ -0,0 +1,7 @@ +export default function handler() { + return new Response('Hello from /test/edge/integration-not-in-manifest', { status: 200 }) +} + +export const config = { + path: '/test/edge/integration-not-in-manifest', +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/manifest.json b/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/manifest.json new file mode 100644 index 0000000000..e666c230ed --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/manifest.json @@ -0,0 +1,24 @@ +{ + "functions": [ + { + "function": "next-runtime-v4", + "name": "next-runtime-v4", + "path": "/test/edge/v4", + "generator": "@netlify/plugin-nextjs@4.41.3" + }, + { + "function": "next-runtime-v5", + "name": "next-runtime-v5", + "path": "/test/edge/v5", + "generator": "@netlify/plugin-nextjs@5.3.3" + }, + { + "function": "integration-in-manifest", + "name": "integration-in-manifest", + "path": "/test/edge/integration-in-manifest", + "generator": "@netlify/some-integration@1.0.0" + } + ], + "layers": [], + "version": 1 +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/next-runtime-v4/next-runtime-v4.mjs b/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/next-runtime-v4/next-runtime-v4.mjs new file mode 100644 index 0000000000..049598094a --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/next-runtime-v4/next-runtime-v4.mjs @@ -0,0 +1,5 @@ +export default function handler() { + return new Response('Hello from edge functions generated by @netlify/plugin-nextjs@4', { + status: 200, + }) +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/next-runtime-v5.mjs b/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/next-runtime-v5.mjs new file mode 100644 index 0000000000..c9d66887dc --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/edge-functions/next-runtime-v5.mjs @@ -0,0 +1,5 @@ +export default function handler() { + return new Response('Hello from edge functions generated by @netlify/plugin-nextjs@5', { + status: 200, + }) +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/integration-no-json-config.mjs b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/integration-no-json-config.mjs new file mode 100644 index 0000000000..ebde11d0db --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/integration-no-json-config.mjs @@ -0,0 +1,7 @@ +export default function handler() { + return new Response('Hello from /test/serverless/integration-with-json-config', { status: 200 }) +} + +export const config = { + path: '/test/serverless/integration-with-json-config', +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/integration-with-json-config.json b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/integration-with-json-config.json new file mode 100644 index 0000000000..e8c468d4a8 --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/integration-with-json-config.json @@ -0,0 +1,7 @@ +{ + "config": { + "name": "Some integration", + "generator": "@netlify/some-integration@1.0.0" + }, + "version": 1 +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/integration-with-json-config.mjs b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/integration-with-json-config.mjs new file mode 100644 index 0000000000..cdc63ea00c --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/integration-with-json-config.mjs @@ -0,0 +1,7 @@ +export default function handler() { + return new Response('Hello from integration generated serverless function', { status: 200 }) +} + +export const config = { + path: '/test/serverless/integration-with-json-config', +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v4/next-runtime-v4.json b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v4/next-runtime-v4.json new file mode 100644 index 0000000000..bd03425470 --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v4/next-runtime-v4.json @@ -0,0 +1,6 @@ +{ + "config": { + "generator": "@netlify/plugin-nextjs@4.41.3" + }, + "version": 1 +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v4/next-runtime-v4.mjs b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v4/next-runtime-v4.mjs new file mode 100644 index 0000000000..a511b8aebb --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v4/next-runtime-v4.mjs @@ -0,0 +1,9 @@ +export default function handler() { + return new Response('Hello from edge functions generated by @netlify/plugin-nextjs@5', { + status: 200, + }) +} + +export const config = { + path: '/test/serverless/v4', +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v5.json b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v5.json new file mode 100644 index 0000000000..5745d57acd --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v5.json @@ -0,0 +1,6 @@ +{ + "config": { + "generator": "@netlify/plugin-nextjs@5.3.3" + }, + "version": 1 +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v5.mjs b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v5.mjs new file mode 100644 index 0000000000..771a820020 --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/functions-internal/next-runtime-v5.mjs @@ -0,0 +1,9 @@ +export default function handler() { + return new Response('Hello from edge functions generated by @netlify/plugin-nextjs@5', { + status: 200, + }) +} + +export const config = { + path: '/test/serverless/v5', +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/index.js b/tests/fixtures/with-integrations/plugins/create-other-functions/index.js new file mode 100644 index 0000000000..495fab67a3 --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/index.js @@ -0,0 +1,14 @@ +const { cp } = require('node:fs/promises') +const { join } = require('node:path') + +exports.onPreBuild = async function onPreBuild({ + constants: { INTERNAL_FUNCTIONS_SRC, INTERNAL_EDGE_FUNCTIONS_SRC }, +}) { + // copying functions: + // - mocked functions to represent stale function produced by @netlify/plugin-nextjs (specified by `generator`) for v4 and v5 of runtime + // - mocked functions to represent functions produced by other build plugins (either specified by `generator` or missing `generator` metadata) + await Promise.all([ + cp(join(__dirname, 'edge-functions'), INTERNAL_EDGE_FUNCTIONS_SRC, { recursive: true }), + cp(join(__dirname, 'functions-internal'), INTERNAL_FUNCTIONS_SRC, { recursive: true }), + ]) +} diff --git a/tests/fixtures/with-integrations/plugins/create-other-functions/manifest.yml b/tests/fixtures/with-integrations/plugins/create-other-functions/manifest.yml new file mode 100644 index 0000000000..2e34b6ffbc --- /dev/null +++ b/tests/fixtures/with-integrations/plugins/create-other-functions/manifest.yml @@ -0,0 +1 @@ +name: 'simulate-integration' diff --git a/tests/utils/create-e2e-fixture.ts b/tests/utils/create-e2e-fixture.ts index eab7dc4f79..4ca773ebde 100644 --- a/tests/utils/create-e2e-fixture.ts +++ b/tests/utils/create-e2e-fixture.ts @@ -353,6 +353,7 @@ export const fixtureFactories = { createE2EFixture('cli-before-regional-blobs-support', { expectedCliVersion: '17.21.1', }), + withIntegrations: () => createE2EFixture('with-integrations'), yarnMonorepoWithPnpmLinker: () => createE2EFixture('yarn-monorepo-with-pnpm-linker', { packageManger: 'berry',