[0] {
return {
files: {
@@ -144,7 +148,3 @@ describe('middleware can use wasm files with the experimental modes on', () => {
})
})
})
-
-function extractJSON(response) {
- return JSON.parse(response.headers.get('data') ?? '{}')
-}
diff --git a/test/e2e/middleware-general/test/index.test.ts b/test/e2e/middleware-general/test/index.test.ts
index 071391cdb0a5..44adbdf0f1ae 100644
--- a/test/e2e/middleware-general/test/index.test.ts
+++ b/test/e2e/middleware-general/test/index.test.ts
@@ -62,15 +62,13 @@ describe('Middleware Runtime', () => {
})
}
- describe('with i18n', () => {
- setup({ i18n: true })
- runTests({ i18n: true })
- })
+ function readMiddlewareJSON(response) {
+ return JSON.parse(response.headers.get('data'))
+ }
- describe('without i18n', () => {
- setup({ i18n: false })
- runTests({ i18n: false })
- })
+ function readMiddlewareError(response) {
+ return response.headers.get('error')
+ }
function runTests({ i18n }: { i18n?: boolean }) {
if ((global as any).isNextDev) {
@@ -618,12 +616,13 @@ describe('Middleware Runtime', () => {
])
})
}
-})
-
-function readMiddlewareJSON(response) {
- return JSON.parse(response.headers.get('data'))
-}
+ describe('with i18n', () => {
+ setup({ i18n: true })
+ runTests({ i18n: true })
+ })
-function readMiddlewareError(response) {
- return response.headers.get('error')
-}
+ describe('without i18n', () => {
+ setup({ i18n: false })
+ runTests({ i18n: false })
+ })
+})
diff --git a/test/e2e/middleware-redirects/test/index.test.ts b/test/e2e/middleware-redirects/test/index.test.ts
index 106599a04f07..f245b22fb38f 100644
--- a/test/e2e/middleware-redirects/test/index.test.ts
+++ b/test/e2e/middleware-redirects/test/index.test.ts
@@ -20,11 +20,6 @@ describe('Middleware Redirect', () => {
},
})
})
-
- tests()
- testsWithLocale()
- testsWithLocale('/fr')
-
function tests() {
it('should redirect correctly with redirect in next.config.js', async () => {
const browser = await webdriver(next.url, '/')
@@ -163,4 +158,7 @@ describe('Middleware Redirect', () => {
expect(errors).not.toContain('Failed to lookup route')
})
}
+ tests()
+ testsWithLocale()
+ testsWithLocale('/fr')
})
diff --git a/test/e2e/middleware-responses/test/index.test.ts b/test/e2e/middleware-responses/test/index.test.ts
index 07e3f1d5b67a..1cade1371abd 100644
--- a/test/e2e/middleware-responses/test/index.test.ts
+++ b/test/e2e/middleware-responses/test/index.test.ts
@@ -18,10 +18,6 @@ describe('Middleware Responses', () => {
},
})
})
-
- testsWithLocale()
- testsWithLocale('/fr')
-
function testsWithLocale(locale = '') {
const label = locale ? `${locale} ` : ``
@@ -92,4 +88,6 @@ describe('Middleware Responses', () => {
expect(res.headers.raw()['set-cookie']).toEqual(['bar=chocochip'])
})
}
+ testsWithLocale()
+ testsWithLocale('/fr')
})
diff --git a/test/e2e/middleware-rewrites/test/index.test.ts b/test/e2e/middleware-rewrites/test/index.test.ts
index 131282868802..59b2393868fb 100644
--- a/test/e2e/middleware-rewrites/test/index.test.ts
+++ b/test/e2e/middleware-rewrites/test/index.test.ts
@@ -22,10 +22,6 @@ describe('Middleware Rewrite', () => {
})
})
- tests()
- testsWithLocale()
- testsWithLocale('/fr')
-
function tests() {
it('should not have un-necessary data request on rewrite', async () => {
const browser = await webdriver(next.url, '/to-blog/first', {
@@ -576,6 +572,19 @@ describe('Middleware Rewrite', () => {
function testsWithLocale(locale = '') {
const label = locale ? `${locale} ` : ``
+ function getCookieFromResponse(res, cookieName) {
+ // node-fetch bundles the cookies as string in the Response
+ const cookieArray = res.headers.raw()['set-cookie']
+ for (const cookie of cookieArray) {
+ let individualCookieParams = cookie.split(';')
+ let individualCookie = individualCookieParams[0].split('=')
+ if (individualCookie[0] === cookieName) {
+ return individualCookie[1]
+ }
+ }
+ return -1
+ }
+
it(`${label}should add a cookie and rewrite to a/b test`, async () => {
const res = await fetchViaHTTP(next.url, `${locale}/rewrite-to-ab-test`)
const html = await res.text()
@@ -766,16 +775,7 @@ describe('Middleware Rewrite', () => {
})
}
- function getCookieFromResponse(res, cookieName) {
- // node-fetch bundles the cookies as string in the Response
- const cookieArray = res.headers.raw()['set-cookie']
- for (const cookie of cookieArray) {
- let individualCookieParams = cookie.split(';')
- let individualCookie = individualCookieParams[0].split('=')
- if (individualCookie[0] === cookieName) {
- return individualCookie[1]
- }
- }
- return -1
- }
+ tests()
+ testsWithLocale()
+ testsWithLocale('/fr')
})
diff --git a/test/e2e/proxy-request-with-middleware/test/index.test.ts b/test/e2e/proxy-request-with-middleware/test/index.test.ts
index 0b47e9d7d593..3795ca3052b2 100644
--- a/test/e2e/proxy-request-with-middleware/test/index.test.ts
+++ b/test/e2e/proxy-request-with-middleware/test/index.test.ts
@@ -21,9 +21,6 @@ describe('Requests not effected when middleware used', () => {
})
})
- sendRequest('GET')
- sendRequest('POST')
-
function sendRequest(method) {
const body = !['get', 'head'].includes(method.toLowerCase())
? JSON.stringify({
@@ -50,4 +47,7 @@ describe('Requests not effected when middleware used', () => {
expect(data.headers).toEqual(expect.objectContaining(headers))
})
}
+
+ sendRequest('GET')
+ sendRequest('POST')
})
diff --git a/test/e2e/switchable-runtime/index.test.ts b/test/e2e/switchable-runtime/index.test.ts
index a1868f18d0eb..7ec464455d62 100644
--- a/test/e2e/switchable-runtime/index.test.ts
+++ b/test/e2e/switchable-runtime/index.test.ts
@@ -70,6 +70,43 @@ describe('Switchable runtime', () => {
expect(devMiddlewareManifest).toEqual({})
})
+ it('should sort edge SSR routes correctly', async () => {
+ const res = await fetchViaHTTP(next.url, `/edge/foo`)
+ const html = await res.text()
+
+ // /edge/foo should be caught before /edge/[id]
+ expect(html).toContain(`to /edge/[id]`)
+ })
+
+ it('should be able to navigate between edge SSR routes without any errors', async () => {
+ const res = await fetchViaHTTP(next.url, `/edge/foo`)
+ const html = await res.text()
+
+ // /edge/foo should be caught before /edge/[id]
+ expect(html).toContain(`to /edge/[id]`)
+
+ const browser = await webdriver(context.appPort, '/edge/foo')
+
+ await browser.waitForElementByCss('a').click()
+
+ // on /edge/[id]
+ await check(
+ () => browser.eval('document.documentElement.innerHTML'),
+ /to \/edge\/foo/
+ )
+
+ await browser.waitForElementByCss('a').click()
+
+ // on /edge/foo
+ await check(
+ () => browser.eval('document.documentElement.innerHTML'),
+ /to \/edge\/\[id\]/
+ )
+
+ expect(context.stdout).not.toContain('self is not defined')
+ expect(context.stderr).not.toContain('self is not defined')
+ })
+
it.skip('should support client side navigation to ssr rsc pages', async () => {
let flightRequest = null
diff --git a/test/e2e/switchable-runtime/pages/edge/[id].js b/test/e2e/switchable-runtime/pages/edge/[id].js
new file mode 100644
index 000000000000..8e91214e16c7
--- /dev/null
+++ b/test/e2e/switchable-runtime/pages/edge/[id].js
@@ -0,0 +1,13 @@
+import Link from 'next/link'
+
+export default function Page() {
+ return (
+
+ to /edge/foo
+
+ )
+}
+
+export const config = {
+ runtime: 'experimental-edge',
+}
diff --git a/test/e2e/switchable-runtime/pages/edge/foo.js b/test/e2e/switchable-runtime/pages/edge/foo.js
new file mode 100644
index 000000000000..b14bc44d881f
--- /dev/null
+++ b/test/e2e/switchable-runtime/pages/edge/foo.js
@@ -0,0 +1,13 @@
+import Link from 'next/link'
+
+export default function Page() {
+ return (
+
+ to /edge/[id]
+
+ )
+}
+
+export const config = {
+ runtime: 'experimental-edge',
+}
diff --git a/test/integration/env-config/app/pages/another-global.js b/test/integration/env-config/app/pages/another-global.js
index 7db38a7029f9..c1d5d4a9da22 100644
--- a/test/integration/env-config/app/pages/another-global.js
+++ b/test/integration/env-config/app/pages/another-global.js
@@ -1 +1,3 @@
-export default () => {process.env.NEXT_PUBLIC_HELLO_WORLD}
+export default function Page() {
+ return {process.env.NEXT_PUBLIC_HELLO_WORLD}
+}
diff --git a/test/integration/env-config/app/pages/api/all.js b/test/integration/env-config/app/pages/api/all.js
index 52f181fe5fb8..e2021d6b38e2 100644
--- a/test/integration/env-config/app/pages/api/all.js
+++ b/test/integration/env-config/app/pages/api/all.js
@@ -27,7 +27,7 @@ const variables = [
'NEXT_PUBLIC_HELLO_WORLD',
]
-export default async (req, res) => {
+export default async function handler(req, res) {
const items = {
nextConfigEnv: process.env.nextConfigEnv,
nextConfigPublicEnv: process.env.nextConfigPublicEnv,
diff --git a/test/integration/env-config/app/pages/global.js b/test/integration/env-config/app/pages/global.js
index ded4746e3107..d4e4aefc644f 100644
--- a/test/integration/env-config/app/pages/global.js
+++ b/test/integration/env-config/app/pages/global.js
@@ -1 +1,3 @@
-export default () => {process.env.NEXT_PUBLIC_TEST_DEST}
+export default function Page() {
+ return {process.env.NEXT_PUBLIC_TEST_DEST}
+}
diff --git a/test/integration/env-config/app/pages/index.js b/test/integration/env-config/app/pages/index.js
index c8bc8ce3a77e..43756e2dd103 100644
--- a/test/integration/env-config/app/pages/index.js
+++ b/test/integration/env-config/app/pages/index.js
@@ -44,10 +44,12 @@ export async function getStaticProps() {
}
}
-export default ({ env }) => (
- <>
- {JSON.stringify(env)}
- {process.env.nextConfigEnv}
- {process.env.nextConfigPublicEnv}
- >
-)
+export default function Page({ env }) {
+ return (
+ <>
+ {JSON.stringify(env)}
+ {process.env.nextConfigEnv}
+ {process.env.nextConfigPublicEnv}
+ >
+ )
+}
diff --git a/test/integration/env-config/app/pages/some-ssg.js b/test/integration/env-config/app/pages/some-ssg.js
index d46d371b5906..75a3be8db867 100644
--- a/test/integration/env-config/app/pages/some-ssg.js
+++ b/test/integration/env-config/app/pages/some-ssg.js
@@ -44,10 +44,12 @@ export async function getStaticProps() {
}
}
-export default ({ env }) => (
- <>
- {JSON.stringify(env)}
- {process.env.nextConfigEnv}
- {process.env.nextConfigPublicEnv}
- >
-)
+export default function Page({ env }) {
+ return (
+ <>
+ {JSON.stringify(env)}
+ {process.env.nextConfigEnv}
+ {process.env.nextConfigPublicEnv}
+ >
+ )
+}
diff --git a/test/integration/env-config/app/pages/some-ssp.js b/test/integration/env-config/app/pages/some-ssp.js
index ee985c926e22..fc06ddc11540 100644
--- a/test/integration/env-config/app/pages/some-ssp.js
+++ b/test/integration/env-config/app/pages/some-ssp.js
@@ -43,10 +43,12 @@ export async function getServerSideProps() {
}
}
-export default ({ env }) => (
- <>
- {JSON.stringify(env)}
- {process.env.nextConfigEnv}
- {process.env.nextConfigPublicEnv}
- >
-)
+export default function Page({ env }) {
+ return (
+ <>
+ {JSON.stringify(env)}
+ {process.env.nextConfigEnv}
+ {process.env.nextConfigPublicEnv}
+ >
+ )
+}
diff --git a/test/integration/env-config/test/index.test.js b/test/integration/env-config/test/index.test.js
index 23baf525c59f..6846e9e2f24f 100644
--- a/test/integration/env-config/test/index.test.js
+++ b/test/integration/env-config/test/index.test.js
@@ -4,6 +4,7 @@ import url from 'url'
import fs from 'fs-extra'
import { join } from 'path'
import cheerio from 'cheerio'
+import webdriver from 'next-webdriver'
import {
nextBuild,
nextStart,
@@ -170,6 +171,9 @@ describe('Env Config', () => {
const originalContents = []
beforeAll(async () => {
const outputIndex = output.length
+ const envFiles = (await fs.readdir(appDir)).filter((file) =>
+ file.startsWith('.env')
+ )
const envToUpdate = [
{
toAdd: 'NEW_ENV_KEY=true',
@@ -185,12 +189,16 @@ describe('Env Config', () => {
},
]
- for (const { file, toAdd } of envToUpdate) {
- const content = await fs.readFile(join(appDir, file), 'utf8')
+ for (const file of envFiles) {
+ const filePath = join(appDir, file)
+ const content = await fs.readFile(filePath, 'utf8')
originalContents.push({ file, content })
- await fs.writeFile(join(appDir, file), content + '\n' + toAdd)
- }
+ const toUpdate = envToUpdate.find((item) => item.file === file)
+ if (toUpdate) {
+ await fs.writeFile(filePath, content + `\n${toUpdate.toAdd}`)
+ }
+ }
await check(() => {
return output.substring(outputIndex)
}, /Loaded env from/)
@@ -203,24 +211,138 @@ describe('Env Config', () => {
runTests('dev', true)
- it('should update inlined values correctly', async () => {
- await renderViaHTTP(appPort, '/another-global')
-
- const buildManifest = await fs.readJson(
- join(__dirname, '../app/.next/build-manifest.json')
- )
-
- const pageFile = buildManifest.pages['/another-global'].find(
- (filename) => filename.includes('pages/another-global')
- )
+ it('should have updated runtime values after change', async () => {
+ let html = await fetchViaHTTP(appPort, '/').then((res) => res.text())
+ let renderedEnv = JSON.parse(cheerio.load(html)('p').text())
+
+ expect(renderedEnv['ENV_FILE_KEY']).toBe('env')
+ expect(renderedEnv['ENV_FILE_LOCAL_OVERRIDE_TEST']).toBe('localenv')
+ let outputIdx = output.length
+
+ const envFile = join(appDir, '.env')
+ const envLocalFile = join(appDir, '.env.local')
+ const envContent = originalContents.find(
+ (item) => item.file === '.env'
+ ).content
+ const envLocalContent = originalContents.find(
+ (item) => item.file === '.env.local'
+ ).content
+
+ try {
+ await fs.writeFile(
+ envFile,
+ envContent.replace(`ENV_FILE_KEY=env`, `ENV_FILE_KEY=env-updated`)
+ )
+
+ // we should only log we loaded new env from .env
+ await check(() => output.substring(outputIdx), /Loaded env from/)
+ expect(
+ [...output.substring(outputIdx).matchAll(/Loaded env from/g)].length
+ ).toBe(1)
+ expect(output.substring(outputIdx)).not.toContain('.env.local')
+
+ await check(async () => {
+ html = await fetchViaHTTP(appPort, '/').then((res) => res.text())
+ renderedEnv = JSON.parse(cheerio.load(html)('p').text())
+ expect(renderedEnv['ENV_FILE_KEY']).toBe('env-updated')
+ expect(renderedEnv['ENV_FILE_LOCAL_OVERRIDE_TEST']).toBe('localenv')
+ return 'success'
+ }, 'success')
+
+ outputIdx = output.length
+
+ await fs.writeFile(
+ envLocalFile,
+ envLocalContent.replace(
+ `ENV_FILE_LOCAL_OVERRIDE_TEST=localenv`,
+ `ENV_FILE_LOCAL_OVERRIDE_TEST=localenv-updated`
+ )
+ )
+
+ // we should only log we loaded new env from .env
+ await check(() => output.substring(outputIdx), /Loaded env from/)
+ expect(
+ [...output.substring(outputIdx).matchAll(/Loaded env from/g)].length
+ ).toBe(1)
+ expect(output.substring(outputIdx)).toContain('.env.local')
+
+ await check(async () => {
+ html = await fetchViaHTTP(appPort, '/').then((res) => res.text())
+ renderedEnv = JSON.parse(cheerio.load(html)('p').text())
+ expect(renderedEnv['ENV_FILE_KEY']).toBe('env-updated')
+ expect(renderedEnv['ENV_FILE_LOCAL_OVERRIDE_TEST']).toBe(
+ 'localenv-updated'
+ )
+ return 'success'
+ }, 'success')
+ } finally {
+ await fs.writeFile(envFile, envContent)
+ await fs.writeFile(envLocalFile, envLocalContent)
+ }
+ })
- // read client bundle contents since a server side render can
- // have the value available during render but it not be injected
- const bundleContent = await fs.readFile(
- join(appDir, '.next', pageFile),
- 'utf8'
- )
- expect(bundleContent).toContain('again')
+ it('should trigger HMR correctly when NEXT_PUBLIC_ env is changed', async () => {
+ const envFile = join(appDir, '.env')
+ const envLocalFile = join(appDir, '.env.local')
+ const envContent = originalContents.find(
+ (item) => item.file === '.env'
+ ).content
+ const envLocalContent = originalContents.find(
+ (item) => item.file === '.env.local'
+ ).content
+
+ try {
+ const browser = await webdriver(appPort, '/global')
+ expect(await browser.elementByCss('p').text()).toBe('another')
+
+ let outputIdx = output.length
+
+ await fs.writeFile(
+ envFile,
+ envContent.replace(
+ `NEXT_PUBLIC_TEST_DEST=another`,
+ `NEXT_PUBLIC_TEST_DEST=replaced`
+ )
+ )
+ // we should only log we loaded new env from .env
+ await check(() => output.substring(outputIdx), /Loaded env from/)
+ expect(
+ [...output.substring(outputIdx).matchAll(/Loaded env from/g)].length
+ ).toBe(1)
+ expect(output.substring(outputIdx)).not.toContain('.env.local')
+
+ await check(() => browser.elementByCss('p').text(), 'replaced')
+
+ outputIdx = output.length
+
+ await fs.writeFile(
+ envLocalFile,
+ envLocalContent + `\nNEXT_PUBLIC_TEST_DEST=overridden`
+ )
+ // we should only log we loaded new env from .env
+ await check(() => output.substring(outputIdx), /Loaded env from/)
+ expect(
+ [...output.substring(outputIdx).matchAll(/Loaded env from/g)].length
+ ).toBe(1)
+ expect(output.substring(outputIdx)).toContain('.env.local')
+
+ await check(() => browser.elementByCss('p').text(), 'overridden')
+
+ outputIdx = output.length
+
+ await fs.writeFile(envLocalFile, envLocalContent)
+ // we should only log we loaded new env from .env
+ await check(() => output.substring(outputIdx), /Loaded env from/)
+ expect(
+ [...output.substring(outputIdx).matchAll(/Loaded env from/g)].length
+ ).toBe(1)
+ expect(output.substring(outputIdx)).toContain('.env.local')
+
+ await check(() => browser.elementByCss('p').text(), 'replaced')
+ } finally {
+ await fs.writeFile(envFile, envContent)
+ await fs.writeFile(envLocalFile, envLocalContent)
+ }
})
})
})
diff --git a/test/integration/jsconfig-paths/test/index.test.js b/test/integration/jsconfig-paths/test/index.test.js
index 7037101d8873..8680963c1a01 100644
--- a/test/integration/jsconfig-paths/test/index.test.js
+++ b/test/integration/jsconfig-paths/test/index.test.js
@@ -3,6 +3,7 @@
import fs from 'fs-extra'
import { join } from 'path'
import cheerio from 'cheerio'
+import * as path from 'path'
import {
renderViaHTTP,
findPort,
@@ -10,7 +11,9 @@ import {
nextBuild,
killApp,
check,
+ File,
} from 'next-test-utils'
+import * as JSON5 from 'json5'
const appDir = join(__dirname, '..')
let appPort
@@ -21,7 +24,7 @@ async function get$(path, query) {
return cheerio.load(html)
}
-describe('TypeScript Features', () => {
+function runTests() {
describe('default behavior', () => {
let output = ''
@@ -141,4 +144,30 @@ describe('TypeScript Features', () => {
).toBe(false)
})
})
+}
+
+describe('jsconfig paths', () => {
+ runTests()
+})
+
+const jsconfig = new File(path.resolve(__dirname, '../jsconfig.json'))
+
+describe('jsconfig paths without baseurl', () => {
+ beforeAll(() => {
+ const jsconfigContent = JSON5.parse(jsconfig.originalContent)
+ delete jsconfigContent.compilerOptions.baseUrl
+ jsconfigContent.compilerOptions.paths = {
+ '@c/*': ['./components/*'],
+ '@lib/*': ['./lib/a/*', './lib/b/*'],
+ '@mycomponent': ['./components/hello.js'],
+ '*': ['./node_modules/*'],
+ }
+ jsconfig.write(JSON.stringify(jsconfigContent, null, 2))
+ })
+
+ afterAll(() => {
+ jsconfig.restore()
+ })
+
+ runTests()
})
diff --git a/test/integration/typescript-paths/test/index.test.js b/test/integration/typescript-paths/test/index.test.js
index f7100467a146..aeb3c297dd62 100644
--- a/test/integration/typescript-paths/test/index.test.js
+++ b/test/integration/typescript-paths/test/index.test.js
@@ -2,7 +2,15 @@
import { join } from 'path'
import cheerio from 'cheerio'
-import { renderViaHTTP, findPort, launchApp, killApp } from 'next-test-utils'
+import * as path from 'path'
+import {
+ renderViaHTTP,
+ findPort,
+ launchApp,
+ killApp,
+ File,
+} from 'next-test-utils'
+import * as JSON5 from 'json5'
const appDir = join(__dirname, '..')
let appPort
@@ -13,7 +21,7 @@ async function get$(path, query) {
return cheerio.load(html)
}
-describe('TypeScript Features', () => {
+function runTests() {
describe('default behavior', () => {
beforeAll(async () => {
appPort = await findPort()
@@ -46,4 +54,34 @@ describe('TypeScript Features', () => {
expect($('body').text()).toMatch(/Not aliased to d\.ts file/)
})
})
+}
+
+describe('typescript paths', () => {
+ runTests()
+})
+
+const tsconfig = new File(path.resolve(__dirname, '../tsconfig.json'))
+
+describe('typescript paths without baseurl', () => {
+ beforeAll(async () => {
+ const tsconfigContent = JSON5.parse(tsconfig.originalContent)
+ delete tsconfigContent.compilerOptions.baseUrl
+ tsconfigContent.compilerOptions.paths = {
+ 'isomorphic-unfetch': ['./types/unfetch.d.ts'],
+ '@c/*': ['./components/*'],
+ '@lib/*': ['./lib/a/*', './lib/b/*'],
+ '@mycomponent': ['./components/hello.tsx'],
+ 'd-ts-alias': [
+ './components/alias-to-d-ts.d.ts',
+ './components/alias-to-d-ts.tsx',
+ ],
+ }
+ tsconfig.write(JSON.stringify(tsconfigContent, null, 2))
+ })
+
+ afterAll(() => {
+ tsconfig.restore()
+ })
+
+ runTests()
})