Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled
358 lines
9.3 KiB
TypeScript
358 lines
9.3 KiB
TypeScript
import { check } from 'next-test-utils'
|
|
import { join } from 'path'
|
|
import { createNextApp, projectFilesShouldExist, useTempDir } from './utils'
|
|
|
|
describe('create-next-app prompts', () => {
|
|
let nextTgzFilename: string
|
|
|
|
beforeAll(() => {
|
|
if (!process.env.NEXT_TEST_PKG_PATHS) {
|
|
throw new Error('This test needs to be run with `node run-tests.js`.')
|
|
}
|
|
|
|
const pkgPaths = new Map<string, string>(
|
|
JSON.parse(process.env.NEXT_TEST_PKG_PATHS)
|
|
)
|
|
|
|
nextTgzFilename = pkgPaths.get('next')
|
|
})
|
|
|
|
it('should prompt user for choice if directory name is absent', async () => {
|
|
await useTempDir(async (cwd) => {
|
|
const projectName = 'no-dir-name'
|
|
const childProcess = createNextApp(
|
|
[
|
|
'--ts',
|
|
'--app',
|
|
'--eslint',
|
|
'--no-src-dir',
|
|
'--no-tailwind',
|
|
'--no-import-alias',
|
|
'--no-react-compiler',
|
|
'--no-agents-md',
|
|
],
|
|
{
|
|
cwd,
|
|
},
|
|
nextTgzFilename
|
|
)
|
|
|
|
await new Promise<void>((resolve) => {
|
|
childProcess.on('exit', async (exitCode) => {
|
|
expect(exitCode).toBe(0)
|
|
projectFilesShouldExist({
|
|
cwd,
|
|
projectName,
|
|
files: ['package.json'],
|
|
})
|
|
resolve()
|
|
})
|
|
|
|
// enter project name
|
|
childProcess.stdin.write(`${projectName}\n`)
|
|
})
|
|
|
|
const pkg = require(join(cwd, projectName, 'package.json'))
|
|
expect(pkg.name).toBe(projectName)
|
|
})
|
|
})
|
|
|
|
it('should prompt user for choice if --js or --ts flag is absent', async () => {
|
|
await useTempDir(async (cwd) => {
|
|
const projectName = 'ts-js'
|
|
const childProcess = createNextApp(
|
|
[
|
|
projectName,
|
|
'--app',
|
|
'--eslint',
|
|
'--no-tailwind',
|
|
'--no-src-dir',
|
|
'--no-import-alias',
|
|
'--no-react-compiler',
|
|
'--no-agents-md',
|
|
],
|
|
{
|
|
cwd,
|
|
},
|
|
nextTgzFilename
|
|
)
|
|
|
|
await new Promise<void>((resolve) => {
|
|
childProcess.on('exit', async (exitCode) => {
|
|
expect(exitCode).toBe(0)
|
|
projectFilesShouldExist({
|
|
cwd,
|
|
projectName,
|
|
files: ['tsconfig.json'],
|
|
})
|
|
resolve()
|
|
})
|
|
|
|
// select default choice: typescript
|
|
childProcess.stdin.write('\n')
|
|
})
|
|
})
|
|
})
|
|
|
|
it('should prompt user for choice if --tailwind is absent', async () => {
|
|
await useTempDir(async (cwd) => {
|
|
const projectName = 'tw'
|
|
const childProcess = createNextApp(
|
|
[
|
|
projectName,
|
|
'--ts',
|
|
'--app',
|
|
'--eslint',
|
|
'--no-src-dir',
|
|
'--no-import-alias',
|
|
'--no-react-compiler',
|
|
'--no-agents-md',
|
|
],
|
|
{
|
|
cwd,
|
|
},
|
|
nextTgzFilename
|
|
)
|
|
|
|
await new Promise<void>((resolve) => {
|
|
childProcess.on('exit', async (exitCode) => {
|
|
expect(exitCode).toBe(0)
|
|
projectFilesShouldExist({
|
|
cwd,
|
|
projectName,
|
|
files: ['postcss.config.mjs'],
|
|
})
|
|
resolve()
|
|
})
|
|
|
|
// select default choice: tailwind
|
|
childProcess.stdin.write('\n')
|
|
})
|
|
})
|
|
})
|
|
|
|
it('should prompt user for choice if --import-alias is absent', async () => {
|
|
await useTempDir(async (cwd) => {
|
|
const projectName = 'import-alias'
|
|
const childProcess = createNextApp(
|
|
[
|
|
projectName,
|
|
'--ts',
|
|
'--app',
|
|
'--eslint',
|
|
'--no-tailwind',
|
|
'--no-src-dir',
|
|
'--no-react-compiler',
|
|
'--no-agents-md',
|
|
],
|
|
{
|
|
cwd,
|
|
},
|
|
nextTgzFilename
|
|
)
|
|
|
|
await new Promise<void>(async (resolve) => {
|
|
childProcess.on('exit', async (exitCode) => {
|
|
expect(exitCode).toBe(0)
|
|
resolve()
|
|
})
|
|
let output = ''
|
|
childProcess.stdout.on('data', (data) => {
|
|
output += data
|
|
process.stdout.write(data)
|
|
})
|
|
// cursor forward, choose 'Yes' for custom import alias
|
|
childProcess.stdin.write('\u001b[C\n')
|
|
// used check here since it needs to wait for the prompt
|
|
await check(() => output, /What import alias would you like configured/)
|
|
childProcess.stdin.write('@/something/*\n')
|
|
})
|
|
|
|
const tsConfig = require(join(cwd, projectName, 'tsconfig.json'))
|
|
expect(tsConfig.compilerOptions.paths).toMatchInlineSnapshot(`
|
|
{
|
|
"@/something/*": [
|
|
"./*",
|
|
],
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('should not prompt user for choice and use defaults if --yes is defined', async () => {
|
|
await useTempDir(async (cwd) => {
|
|
const projectName = 'yes-we-can'
|
|
const childProcess = createNextApp(
|
|
[projectName, '--yes'],
|
|
{
|
|
cwd,
|
|
},
|
|
nextTgzFilename
|
|
)
|
|
|
|
await new Promise<void>((resolve) => {
|
|
childProcess.on('exit', async (exitCode) => {
|
|
expect(exitCode).toBe(0)
|
|
projectFilesShouldExist({
|
|
cwd,
|
|
projectName,
|
|
files: [
|
|
'app',
|
|
'package.json',
|
|
'postcss.config.mjs',
|
|
'tsconfig.json',
|
|
'AGENTS.md',
|
|
'CLAUDE.md',
|
|
],
|
|
})
|
|
resolve()
|
|
})
|
|
})
|
|
|
|
const pkg = require(join(cwd, projectName, 'package.json'))
|
|
expect(pkg.name).toBe(projectName)
|
|
const tsConfig = require(join(cwd, projectName, 'tsconfig.json'))
|
|
expect(tsConfig.compilerOptions.paths).toMatchInlineSnapshot(`
|
|
{
|
|
"@/*": [
|
|
"./*",
|
|
],
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('should use recommended defaults when user selects that option', async () => {
|
|
await useTempDir(async (cwd) => {
|
|
const projectName = 'recommended-defaults'
|
|
const childProcess = createNextApp(
|
|
[projectName],
|
|
{
|
|
cwd,
|
|
},
|
|
nextTgzFilename
|
|
)
|
|
|
|
await new Promise<void>((resolve) => {
|
|
childProcess.on('exit', async (exitCode) => {
|
|
expect(exitCode).toBe(0)
|
|
projectFilesShouldExist({
|
|
cwd,
|
|
projectName,
|
|
files: [
|
|
'app',
|
|
'package.json',
|
|
'postcss.config.mjs', // tailwind
|
|
'tsconfig.json', // typescript
|
|
'AGENTS.md', // agent files
|
|
'CLAUDE.md',
|
|
],
|
|
})
|
|
resolve()
|
|
})
|
|
|
|
// Select "Yes, use recommended defaults" (default option, just press enter)
|
|
childProcess.stdin.write('\n')
|
|
})
|
|
|
|
const pkg = require(join(cwd, projectName, 'package.json'))
|
|
expect(pkg.name).toBe(projectName)
|
|
})
|
|
})
|
|
|
|
it('should show reuse previous settings option when preferences exist', async () => {
|
|
const Conf = require('next/dist/compiled/conf')
|
|
|
|
await useTempDir(async (cwd) => {
|
|
// Manually set preferences to simulate a previous run
|
|
const conf = new Conf({ projectName: 'create-next-app' })
|
|
conf.set('preferences', {
|
|
typescript: false,
|
|
eslint: true,
|
|
linter: 'eslint',
|
|
tailwind: false,
|
|
app: false,
|
|
srcDir: false,
|
|
importAlias: '@/*',
|
|
customizeImportAlias: false,
|
|
reactCompiler: false,
|
|
})
|
|
|
|
const projectName = 'reuse-prefs-project'
|
|
const childProcess = createNextApp(
|
|
[projectName],
|
|
{
|
|
cwd,
|
|
},
|
|
nextTgzFilename,
|
|
false // Don't clear preferences
|
|
)
|
|
|
|
await new Promise<void>(async (resolve) => {
|
|
let output = ''
|
|
childProcess.stdout.on('data', (data) => {
|
|
output += data
|
|
process.stdout.write(data)
|
|
})
|
|
|
|
// Select "reuse previous settings" (cursor down once, then enter)
|
|
childProcess.stdin.write('\u001b[B\n')
|
|
|
|
// Wait for the prompt to appear with "reuse previous settings"
|
|
await check(() => output, /No, reuse previous settings/)
|
|
|
|
childProcess.on('exit', async (exitCode) => {
|
|
expect(exitCode).toBe(0)
|
|
projectFilesShouldExist({
|
|
cwd,
|
|
projectName,
|
|
files: [
|
|
'pages', // pages router (not app)
|
|
'package.json',
|
|
'jsconfig.json', // javascript
|
|
],
|
|
})
|
|
resolve()
|
|
})
|
|
})
|
|
|
|
const pkg = require(join(cwd, projectName, 'package.json'))
|
|
expect(pkg.name).toBe(projectName)
|
|
})
|
|
})
|
|
|
|
it('should prompt user to confirm reset preferences', async () => {
|
|
await useTempDir(async (cwd) => {
|
|
const childProcess = createNextApp(
|
|
['--reset'],
|
|
{
|
|
cwd,
|
|
},
|
|
nextTgzFilename
|
|
)
|
|
|
|
await new Promise<void>(async (resolve) => {
|
|
childProcess.on('exit', async (exitCode) => {
|
|
expect(exitCode).toBe(0)
|
|
resolve()
|
|
})
|
|
let output = ''
|
|
childProcess.stdout.on('data', (data) => {
|
|
output += data
|
|
process.stdout.write(data)
|
|
})
|
|
await check(
|
|
() => output,
|
|
/Would you like to reset the saved preferences/
|
|
)
|
|
// cursor forward, choose 'Yes' for reset preferences
|
|
childProcess.stdin.write('\u001b[C\n')
|
|
await check(
|
|
() => output,
|
|
/The preferences have been reset successfully/
|
|
)
|
|
})
|
|
})
|
|
})
|
|
})
|