test: organize react 18 tests (#36003)
* Organize react 18 test cases, group invalid cases to speed up the regular test cases * Add `runDevSuite` and `runProdSuite` for group next dev/prod test cases ```js runDevSuite(name, appDir, { runTests: (context, env) => { ... }, beforeAll, afterAll, }) runProdvSuite(name, appDir, { runTests: (context, env) => { ... }, beforeAll, afterAll, }) ```
This commit is contained in:
parent
1c92591466
commit
de0bc57b6e
10 changed files with 181 additions and 210 deletions
|
@ -1,37 +1,8 @@
|
|||
import { join } from 'path'
|
||||
import {
|
||||
nextBuild,
|
||||
nextStart,
|
||||
launchApp,
|
||||
killApp,
|
||||
findPort,
|
||||
renderViaHTTP,
|
||||
} from 'next-test-utils'
|
||||
import { renderViaHTTP, runDevSuite, runProdSuite } from 'next-test-utils'
|
||||
|
||||
const appDir = join(__dirname, '../')
|
||||
|
||||
function runSuite(suiteName, env, runTests) {
|
||||
const context = { appDir }
|
||||
describe(`${suiteName} ${env}`, () => {
|
||||
if (env === 'prod') {
|
||||
beforeAll(async () => {
|
||||
context.appPort = await findPort()
|
||||
await nextBuild(context.appDir)
|
||||
context.server = await nextStart(context.appDir, context.appPort)
|
||||
})
|
||||
}
|
||||
if (env === 'dev') {
|
||||
beforeAll(async () => {
|
||||
context.appPort = await findPort()
|
||||
context.server = await launchApp(context.appDir, context.appPort)
|
||||
})
|
||||
}
|
||||
afterAll(async () => await killApp(context.server))
|
||||
|
||||
runTests(context, env)
|
||||
})
|
||||
}
|
||||
|
||||
function basic(context) {
|
||||
it('should handle json assertions', async () => {
|
||||
const esHtml = await renderViaHTTP(context.appPort, '/es')
|
||||
|
@ -41,5 +12,5 @@ function basic(context) {
|
|||
})
|
||||
}
|
||||
|
||||
runSuite('import-assertion', 'dev', basic)
|
||||
runSuite('import-assertion', 'prod', basic)
|
||||
runDevSuite('import-assertion', appDir, { runTests: basic })
|
||||
runProdSuite('import-assertion', appDir, { runTests: basic })
|
||||
|
|
|
@ -2,19 +2,47 @@
|
|||
|
||||
import fs from 'fs-extra'
|
||||
import { join } from 'path'
|
||||
import { File, nextBuild } from 'next-test-utils'
|
||||
import {
|
||||
File,
|
||||
nextBuild,
|
||||
runDevSuite,
|
||||
runProdSuite,
|
||||
fetchViaHTTP,
|
||||
} from 'next-test-utils'
|
||||
|
||||
const appDir = __dirname
|
||||
const nodeArgs = ['-r', join(appDir, '../../lib/react-17-require-hook.js')]
|
||||
const nextConfig = new File(join(appDir, 'next.config.js'))
|
||||
const reactDomPackagePah = join(appDir, 'node_modules/react-dom')
|
||||
const nextConfig = new File(join(appDir, 'next.config.js'))
|
||||
const documentPage = new File(join(appDir, 'pages/_document.js'))
|
||||
const indexPage = join(appDir, 'pages/index.js')
|
||||
const indexServerPage = join(appDir, 'pages/index.server.js')
|
||||
|
||||
function writeNextConfig(config) {
|
||||
const documentWithGip = `
|
||||
import { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
|
||||
Document.getInitialProps = (ctx) => {
|
||||
return ctx.defaultGetInitialProps(ctx)
|
||||
}
|
||||
`
|
||||
|
||||
function writeNextConfig(config, reactVersion = 17) {
|
||||
const content = `
|
||||
const path = require('path')
|
||||
module.exports = require(path.join(__dirname, '../../lib/with-react-17.js'))({ experimental: ${JSON.stringify(
|
||||
config
|
||||
)} })
|
||||
const withReact = ${reactVersion} === 18 ? v => v : require(path.join(__dirname, '../../lib/with-react-17.js'))
|
||||
module.exports = withReact({ experimental: ${JSON.stringify(config)} })
|
||||
`
|
||||
nextConfig.write(content)
|
||||
}
|
||||
|
@ -65,3 +93,36 @@ describe('React 17 with React 18 config', () => {
|
|||
expect(code).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
const documentSuite = {
|
||||
runTests: (context, env) => {
|
||||
if (env === 'dev') {
|
||||
it('should error when custom _document has getInitialProps method', async () => {
|
||||
const res = await fetchViaHTTP(context.appPort, '/')
|
||||
expect(res.status).toBe(500)
|
||||
})
|
||||
} else {
|
||||
it('should failed building', async () => {
|
||||
expect(context.code).toBe(1)
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeAll: async () => {
|
||||
writeNextConfig(
|
||||
{
|
||||
serverComponents: true,
|
||||
},
|
||||
18
|
||||
)
|
||||
documentPage.write(documentWithGip)
|
||||
await fs.rename(indexPage, indexServerPage)
|
||||
},
|
||||
afterAll: async () => {
|
||||
documentPage.delete()
|
||||
nextConfig.restore()
|
||||
await fs.rename(indexServerPage, indexPage)
|
||||
},
|
||||
}
|
||||
|
||||
runDevSuite('Invalid custom document with gip', appDir, documentSuite)
|
||||
runProdSuite('Invalid custom document with gip', appDir, documentSuite)
|
||||
|
|
|
@ -7,27 +7,23 @@ import {
|
|||
findPort,
|
||||
killApp,
|
||||
launchApp,
|
||||
nextBuild,
|
||||
nextStart,
|
||||
renderViaHTTP,
|
||||
hasRedbox,
|
||||
getRedboxHeader,
|
||||
runDevSuite,
|
||||
runProdSuite,
|
||||
} from 'next-test-utils'
|
||||
import concurrent from './concurrent'
|
||||
import basics from './basics'
|
||||
import strictMode from './strict-mode'
|
||||
import webdriver from 'next-webdriver'
|
||||
|
||||
// overrides react and react-dom to v18
|
||||
const nodeArgs = []
|
||||
const appDir = join(__dirname, '../app')
|
||||
const nextConfig = new File(join(appDir, 'next.config.js'))
|
||||
const invalidPage = new File(join(appDir, 'pages/invalid.js'))
|
||||
|
||||
describe('Basics', () => {
|
||||
runTests('default setting with react 18', (context, env) =>
|
||||
basics(context, env)
|
||||
)
|
||||
runTests('default setting with react 18', basics)
|
||||
})
|
||||
|
||||
// React 18 with Strict Mode enabled might cause double invocation of lifecycle methods.
|
||||
|
@ -37,9 +33,7 @@ describe('Strict mode - dev', () => {
|
|||
beforeAll(async () => {
|
||||
nextConfig.replace('// reactStrictMode: true,', 'reactStrictMode: true,')
|
||||
context.appPort = await findPort()
|
||||
context.server = await launchApp(context.appDir, context.appPort, {
|
||||
nodeArgs,
|
||||
})
|
||||
context.server = await launchApp(context.appDir, context.appPort)
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
|
@ -84,42 +78,11 @@ function runTestsAgainstRuntime(runtime) {
|
|||
)
|
||||
}
|
||||
|
||||
function runTest(env, name, fn, options) {
|
||||
const context = { appDir }
|
||||
describe(`${name} (${env})`, () => {
|
||||
beforeAll(async () => {
|
||||
context.appPort = await findPort()
|
||||
context.stderr = ''
|
||||
options?.beforeAll(env)
|
||||
if (env === 'dev') {
|
||||
context.server = await launchApp(context.appDir, context.appPort, {
|
||||
nodeArgs,
|
||||
onStderr(msg) {
|
||||
context.stderr += msg
|
||||
},
|
||||
})
|
||||
} else {
|
||||
await nextBuild(context.appDir, [], { nodeArgs })
|
||||
context.server = await nextStart(context.appDir, context.appPort, {
|
||||
nodeArgs,
|
||||
onStderr(msg) {
|
||||
context.stderr += msg
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
afterAll(async () => {
|
||||
options?.afterAll(env)
|
||||
await killApp(context.server)
|
||||
})
|
||||
fn(context, env)
|
||||
})
|
||||
}
|
||||
|
||||
runTestsAgainstRuntime('edge')
|
||||
runTestsAgainstRuntime('nodejs')
|
||||
|
||||
function runTests(name, fn, options) {
|
||||
runTest('dev', name, fn, options)
|
||||
runTest('prod', name, fn, options)
|
||||
function runTests(name, fn, opts) {
|
||||
const suiteOptions = { ...opts, runTests: fn }
|
||||
runDevSuite(name, appDir, suiteOptions)
|
||||
runProdSuite(name, appDir, suiteOptions)
|
||||
}
|
||||
|
|
|
@ -10,20 +10,23 @@ import { nextBuild } from './utils'
|
|||
export default function (context) {
|
||||
it('should not generate functions manifest when filesystem API is not enabled', async () => {
|
||||
// Make sure there is no existing functions manifest (caused by failed tests etc).
|
||||
await fs.remove(join(context.appDir, '.next'))
|
||||
const distDir = join(context.appDir, '.next')
|
||||
await fs.remove(distDir)
|
||||
await nextBuild(context.appDir)
|
||||
const functionsManifestPath = join(
|
||||
context.distDir,
|
||||
distDir,
|
||||
'server',
|
||||
'functions-manifest.json'
|
||||
)
|
||||
expect(fs.existsSync(functionsManifestPath)).toBe(false)
|
||||
await fs.remove(join(context.appDir, '.next'))
|
||||
})
|
||||
|
||||
it('should contain rsc paths in functions manifest', async () => {
|
||||
const distDir = join(context.appDir, '.next')
|
||||
await nextBuild(context.appDir, { env: { ENABLE_FILE_SYSTEM_API: '1' } })
|
||||
const functionsManifestPath = join(
|
||||
context.distDir,
|
||||
distDir,
|
||||
'server',
|
||||
'functions-manifest.json'
|
||||
)
|
||||
|
|
|
@ -3,16 +3,17 @@
|
|||
import { join } from 'path'
|
||||
import fs from 'fs-extra'
|
||||
|
||||
import { fetchViaHTTP, findPort, killApp, renderViaHTTP } from 'next-test-utils'
|
||||
import {
|
||||
fetchViaHTTP,
|
||||
renderViaHTTP,
|
||||
nextBuild,
|
||||
runDevSuite,
|
||||
runProdSuite,
|
||||
} from 'next-test-utils'
|
||||
|
||||
import {
|
||||
nextBuild,
|
||||
nextStart,
|
||||
nextDev,
|
||||
appDir,
|
||||
nativeModuleTestAppDir,
|
||||
distDir,
|
||||
documentPage,
|
||||
appPage,
|
||||
appServerPage,
|
||||
error500Page,
|
||||
|
@ -25,26 +26,6 @@ import streaming from './streaming'
|
|||
import basic from './basic'
|
||||
import runtime from './runtime'
|
||||
|
||||
const documentWithGip = `
|
||||
import { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
|
||||
Document.getInitialProps = (ctx) => {
|
||||
return ctx.defaultGetInitialProps(ctx)
|
||||
}
|
||||
`
|
||||
|
||||
const rscAppPage = `
|
||||
import Container from '../components/container.server'
|
||||
export default function App({children}) {
|
||||
|
@ -72,7 +53,9 @@ describe('Edge runtime - errors', () => {
|
|||
it('should warn user that native node APIs are not supported', async () => {
|
||||
const fsImportedErrorMessage =
|
||||
'Native Node.js APIs are not supported in the Edge Runtime. Found `dns` imported.'
|
||||
const { stderr } = await nextBuild(nativeModuleTestAppDir)
|
||||
const { stderr } = await nextBuild(nativeModuleTestAppDir, [], {
|
||||
stderr: true,
|
||||
})
|
||||
expect(stderr).toContain(fsImportedErrorMessage)
|
||||
})
|
||||
})
|
||||
|
@ -80,6 +63,7 @@ describe('Edge runtime - errors', () => {
|
|||
const edgeRuntimeBasicSuite = {
|
||||
runTests: (context, env) => {
|
||||
const options = { runtime: 'edge', env }
|
||||
const distDir = join(appDir, '.next')
|
||||
basic(context, options)
|
||||
streaming(context, options)
|
||||
rsc(context, options)
|
||||
|
@ -158,6 +142,7 @@ const edgeRuntimeBasicSuite = {
|
|||
const nodejsRuntimeBasicSuite = {
|
||||
runTests: (context, env) => {
|
||||
const options = { runtime: 'nodejs', env }
|
||||
const distDir = join(appDir, '.next')
|
||||
basic(context, options)
|
||||
streaming(context, options)
|
||||
rsc(context, options)
|
||||
|
@ -217,61 +202,13 @@ const cssSuite = {
|
|||
afterAll: () => appPage.delete(),
|
||||
}
|
||||
|
||||
const documentSuite = {
|
||||
runTests: (context, env) => {
|
||||
if (env === 'dev') {
|
||||
it('should error when custom _document has getInitialProps method', async () => {
|
||||
const res = await fetchViaHTTP(context.appPort, '/')
|
||||
expect(res.status).toBe(500)
|
||||
})
|
||||
} else {
|
||||
it('should failed building', async () => {
|
||||
expect(context.code).toBe(1)
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeAll: () => documentPage.write(documentWithGip),
|
||||
afterAll: () => documentPage.delete(),
|
||||
}
|
||||
runDevSuite('Node.js runtime', appDir, nodejsRuntimeBasicSuite)
|
||||
runProdSuite('Node.js runtime', appDir, nodejsRuntimeBasicSuite)
|
||||
runDevSuite('Edge runtime', appDir, edgeRuntimeBasicSuite)
|
||||
runProdSuite('Edge runtime', appDir, edgeRuntimeBasicSuite)
|
||||
|
||||
runSuite('Node.js runtime', 'dev', nodejsRuntimeBasicSuite)
|
||||
runSuite('Node.js runtime', 'prod', nodejsRuntimeBasicSuite)
|
||||
runSuite('Edge runtime', 'dev', edgeRuntimeBasicSuite)
|
||||
runSuite('Edge runtime', 'prod', edgeRuntimeBasicSuite)
|
||||
runDevSuite('Custom App', appDir, customAppPageSuite)
|
||||
runProdSuite('Custom App', appDir, customAppPageSuite)
|
||||
|
||||
runSuite('Custom App', 'dev', customAppPageSuite)
|
||||
runSuite('Custom App', 'prod', customAppPageSuite)
|
||||
|
||||
runSuite('CSS', 'dev', cssSuite)
|
||||
runSuite('CSS', 'prod', cssSuite)
|
||||
|
||||
runSuite('Custom Document', 'dev', documentSuite)
|
||||
runSuite('Custom Document', 'prod', documentSuite)
|
||||
|
||||
function runSuite(suiteName, env, options) {
|
||||
const context = { appDir, distDir }
|
||||
describe(`${suiteName} ${env}`, () => {
|
||||
beforeAll(async () => {
|
||||
options.beforeAll?.()
|
||||
if (env === 'prod') {
|
||||
context.appPort = await findPort()
|
||||
const { stdout, stderr, code } = await nextBuild(context.appDir)
|
||||
context.stdout = stdout
|
||||
context.stderr = stderr
|
||||
context.code = code
|
||||
context.server = await nextStart(context.appDir, context.appPort)
|
||||
}
|
||||
if (env === 'dev') {
|
||||
context.appPort = await findPort()
|
||||
context.server = await nextDev(context.appDir, context.appPort)
|
||||
}
|
||||
})
|
||||
afterAll(async () => {
|
||||
options.afterAll?.()
|
||||
if (context.server) {
|
||||
await killApp(context.server)
|
||||
}
|
||||
})
|
||||
options.runTests(context, env)
|
||||
})
|
||||
}
|
||||
runDevSuite('CSS', appDir, cssSuite)
|
||||
runProdSuite('CSS', appDir, cssSuite)
|
||||
|
|
|
@ -3,9 +3,10 @@ import webdriver from 'next-webdriver'
|
|||
import { renderViaHTTP, check } from 'next-test-utils'
|
||||
import { join } from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import { distDir, getNodeBySelector } from './utils'
|
||||
import { getNodeBySelector } from './utils'
|
||||
|
||||
export default function (context, { runtime, env }) {
|
||||
const distDir = join(context.appDir, '.next')
|
||||
it('should render server components correctly', async () => {
|
||||
const homeHTML = await renderViaHTTP(context.appPort, '/', null, {
|
||||
headers: {
|
||||
|
|
|
@ -2,9 +2,9 @@ import { renderViaHTTP } from 'next-test-utils'
|
|||
import { join } from 'path'
|
||||
import fs from 'fs-extra'
|
||||
|
||||
import { distDir } from './utils'
|
||||
|
||||
export default async function runtime(context, { runtime, env }) {
|
||||
const distDir = join(context.appDir, '.next')
|
||||
|
||||
if (runtime === 'edge') {
|
||||
it('should support per-page runtime configuration', async () => {
|
||||
const html1 = await renderViaHTTP(context.appPort, '/runtime')
|
||||
|
|
|
@ -5,10 +5,12 @@ import {
|
|||
check,
|
||||
findPort,
|
||||
killApp,
|
||||
launchApp,
|
||||
nextBuild,
|
||||
nextStart,
|
||||
renderViaHTTP,
|
||||
waitFor,
|
||||
} from 'next-test-utils'
|
||||
import { nextBuild, nextDev, nextStart } from './utils'
|
||||
|
||||
const appDir = join(__dirname, '../switchable-runtime')
|
||||
|
||||
|
@ -48,7 +50,10 @@ describe('Switchable runtime (prod)', () => {
|
|||
|
||||
beforeAll(async () => {
|
||||
context.appPort = await findPort()
|
||||
const { stdout, stderr } = await nextBuild(context.appDir)
|
||||
const { stdout, stderr } = await nextBuild(context.appDir, [], {
|
||||
stderr: true,
|
||||
stdout: true,
|
||||
})
|
||||
context.stdout = stdout
|
||||
context.stderr = stderr
|
||||
context.server = await nextStart(context.appDir, context.appPort)
|
||||
|
@ -252,7 +257,7 @@ describe('Switchable runtime (dev)', () => {
|
|||
|
||||
beforeAll(async () => {
|
||||
context.appPort = await findPort()
|
||||
context.server = await nextDev(context.appDir, context.appPort)
|
||||
context.server = await launchApp(context.appDir, context.appPort)
|
||||
})
|
||||
afterAll(async () => {
|
||||
await killApp(context.server)
|
||||
|
|
|
@ -1,51 +1,17 @@
|
|||
import { join } from 'path'
|
||||
import {
|
||||
File,
|
||||
launchApp,
|
||||
nextBuild as _nextBuild,
|
||||
nextStart as _nextStart,
|
||||
} from 'next-test-utils'
|
||||
import { File } from 'next-test-utils'
|
||||
import cheerio from 'cheerio'
|
||||
|
||||
const nodeArgs = []
|
||||
|
||||
export const appDir = join(__dirname, '../app')
|
||||
export const nativeModuleTestAppDir = join(
|
||||
__dirname,
|
||||
'../unsupported-native-module'
|
||||
)
|
||||
export const distDir = join(__dirname, '../app/.next')
|
||||
export const documentPage = new File(join(appDir, 'pages/_document.jsx'))
|
||||
export const appPage = new File(join(appDir, 'pages/_app.js'))
|
||||
export const appServerPage = new File(join(appDir, 'pages/_app.server.js'))
|
||||
export const error500Page = new File(join(appDir, 'pages/500.js'))
|
||||
export const nextConfig = new File(join(appDir, 'next.config.js'))
|
||||
|
||||
export async function nextBuild(dir, options) {
|
||||
return await _nextBuild(dir, [], {
|
||||
...options,
|
||||
stdout: true,
|
||||
stderr: true,
|
||||
nodeArgs,
|
||||
})
|
||||
}
|
||||
|
||||
export async function nextStart(dir, port) {
|
||||
return await _nextStart(dir, port, {
|
||||
stdout: true,
|
||||
stderr: true,
|
||||
nodeArgs,
|
||||
})
|
||||
}
|
||||
|
||||
export async function nextDev(dir, port) {
|
||||
return await launchApp(dir, port, {
|
||||
stdout: true,
|
||||
stderr: true,
|
||||
nodeArgs,
|
||||
})
|
||||
}
|
||||
|
||||
export function getNodeBySelector(html, selector) {
|
||||
const $ = cheerio.load(html)
|
||||
return $(selector)
|
||||
|
|
|
@ -722,3 +722,67 @@ export function readNextBuildServerPageFile(appDir, page) {
|
|||
const pageFile = getPageFileFromPagesManifest(appDir, page)
|
||||
return readFileSync(path.join(appDir, '.next', 'server', pageFile), 'utf8')
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} suiteName
|
||||
* @param {{env: 'prod' | 'dev', appDir: string}} context
|
||||
* @param {{beforeAll?: Function; afterAll?: Function; runTests: Function}} options
|
||||
*/
|
||||
function runSuite(suiteName, context, options) {
|
||||
const { appDir, env } = context
|
||||
describe(`${suiteName} ${env}`, () => {
|
||||
beforeAll(async () => {
|
||||
options.beforeAll?.(env)
|
||||
context.stderr = ''
|
||||
const onStderr = (msg) => {
|
||||
context.stderr += msg
|
||||
}
|
||||
if (env === 'prod') {
|
||||
context.appPort = await findPort()
|
||||
const { stdout, stderr, code } = await nextBuild(appDir, [], {
|
||||
stderr: true,
|
||||
stdout: true,
|
||||
})
|
||||
context.stdout = stdout
|
||||
context.stderr = stderr
|
||||
context.code = code
|
||||
context.server = await nextStart(context.appDir, context.appPort, {
|
||||
onStderr,
|
||||
})
|
||||
} else if (env === 'dev') {
|
||||
context.appPort = await findPort()
|
||||
context.server = await launchApp(context.appDir, context.appPort, {
|
||||
onStderr,
|
||||
})
|
||||
}
|
||||
})
|
||||
afterAll(async () => {
|
||||
options.afterAll?.(env)
|
||||
if (context.server) {
|
||||
await killApp(context.server)
|
||||
}
|
||||
})
|
||||
options.runTests(context, env)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} suiteName
|
||||
* @param {string} appDir
|
||||
* @param {{beforeAll?: Function; afterAll?: Function; runTests: Function}} options
|
||||
*/
|
||||
export function runDevSuite(suiteName, appDir, options) {
|
||||
return runSuite(suiteName, { appDir, env: 'dev' }, options)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} suiteName
|
||||
* @param {string} appDir
|
||||
* @param {{beforeAll?: Function; afterAll?: Function; runTests: Function}} options
|
||||
*/
|
||||
export function runProdSuite(suiteName, appDir, options) {
|
||||
return runSuite(suiteName, { appDir, env: 'prod' }, options)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue