Test lint config after first-time setup (#67146)
This commit is contained in:
parent
ebc2c68c4c
commit
63908fcd2f
5 changed files with 580 additions and 17 deletions
|
@ -4,7 +4,6 @@ import { join } from 'path'
|
|||
|
||||
import { nextBuild } from 'next-test-utils'
|
||||
|
||||
const dirFirstTimeSetup = join(__dirname, '../first-time-setup')
|
||||
const dirCustomConfig = join(__dirname, '../custom-config')
|
||||
const dirIgnoreDuringBuilds = join(__dirname, '../ignore-during-builds')
|
||||
const dirBaseDirectories = join(__dirname, '../base-directories')
|
||||
|
@ -23,22 +22,6 @@ describe('Next Build', () => {
|
|||
;(process.env.TURBOPACK_DEV ? describe.skip : describe)(
|
||||
'production mode',
|
||||
() => {
|
||||
test('first time setup', async () => {
|
||||
const eslintrcJson = join(dirFirstTimeSetup, '.eslintrc.json')
|
||||
await fs.writeFile(eslintrcJson, '')
|
||||
|
||||
const { stdout, stderr } = await nextBuild(dirFirstTimeSetup, [], {
|
||||
stdout: true,
|
||||
stderr: true,
|
||||
lint: true,
|
||||
})
|
||||
const output = stdout + stderr
|
||||
|
||||
expect(output).toContain(
|
||||
'No ESLint configuration detected. Run next lint to begin setup'
|
||||
)
|
||||
})
|
||||
|
||||
test('shows warnings and errors', async () => {
|
||||
const { stdout, stderr } = await nextBuild(dirCustomConfig, [], {
|
||||
stdout: true,
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
export default function Test() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello title</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
7
test/production/eslint/first-time-setup/pages/index.js
Normal file
7
test/production/eslint/first-time-setup/pages/index.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
export default function Test() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello title</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,402 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Next Build production mode first time setup 1`] = `
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
},
|
||||
"globals": {},
|
||||
"ignorePatterns": [],
|
||||
"parserOptions": {
|
||||
"allowImportExportEverywhere": true,
|
||||
"babelOptions": {
|
||||
"caller": {
|
||||
"supportsTopLevelAwait": true,
|
||||
},
|
||||
"presets": [
|
||||
"next/babel",
|
||||
],
|
||||
},
|
||||
"ecmaFeatures": {
|
||||
"jsx": true,
|
||||
},
|
||||
"requireConfigFile": false,
|
||||
"sourceType": "module",
|
||||
},
|
||||
"plugins": [
|
||||
"react-hooks",
|
||||
"jsx-a11y",
|
||||
"react",
|
||||
"import",
|
||||
"@next/next",
|
||||
],
|
||||
"rules": {
|
||||
"@next/next/google-font-display": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/google-font-preconnect": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/inline-script-id": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/next-script-for-ga": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-assign-module-variable": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-async-client-component": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-before-interactive-script-outside-document": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-css-tags": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-document-import-in-page": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-duplicate-head": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-head-element": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-head-import-in-document": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-html-link-for-pages": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-img-element": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-page-custom-font": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-script-component-in-head": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-styled-jsx-in-document": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-sync-scripts": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-title-in-document-head": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-typos": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-unwanted-polyfillio": [
|
||||
"warn",
|
||||
],
|
||||
"import/no-anonymous-default-export": [
|
||||
"warn",
|
||||
],
|
||||
"jsx-a11y/alt-text": [
|
||||
"warn",
|
||||
{
|
||||
"elements": [
|
||||
"img",
|
||||
],
|
||||
"img": [
|
||||
"Image",
|
||||
],
|
||||
},
|
||||
],
|
||||
"jsx-a11y/aria-props": [
|
||||
"warn",
|
||||
],
|
||||
"jsx-a11y/aria-proptypes": [
|
||||
"warn",
|
||||
],
|
||||
"jsx-a11y/aria-unsupported-elements": [
|
||||
"warn",
|
||||
],
|
||||
"jsx-a11y/role-has-required-aria-props": [
|
||||
"warn",
|
||||
],
|
||||
"jsx-a11y/role-supports-aria-props": [
|
||||
"warn",
|
||||
],
|
||||
"react-hooks/exhaustive-deps": [
|
||||
"warn",
|
||||
],
|
||||
"react-hooks/rules-of-hooks": [
|
||||
"error",
|
||||
],
|
||||
"react/display-name": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-key": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-no-comment-textnodes": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-no-duplicate-props": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-no-target-blank": [
|
||||
"off",
|
||||
],
|
||||
"react/jsx-no-undef": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-uses-react": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-uses-vars": [
|
||||
2,
|
||||
],
|
||||
"react/no-children-prop": [
|
||||
2,
|
||||
],
|
||||
"react/no-danger-with-children": [
|
||||
2,
|
||||
],
|
||||
"react/no-deprecated": [
|
||||
2,
|
||||
],
|
||||
"react/no-direct-mutation-state": [
|
||||
2,
|
||||
],
|
||||
"react/no-find-dom-node": [
|
||||
2,
|
||||
],
|
||||
"react/no-is-mounted": [
|
||||
2,
|
||||
],
|
||||
"react/no-render-return-value": [
|
||||
2,
|
||||
],
|
||||
"react/no-string-refs": [
|
||||
2,
|
||||
],
|
||||
"react/no-unescaped-entities": [
|
||||
2,
|
||||
],
|
||||
"react/no-unknown-property": [
|
||||
"off",
|
||||
],
|
||||
"react/no-unsafe": [
|
||||
0,
|
||||
],
|
||||
"react/prop-types": [
|
||||
"off",
|
||||
],
|
||||
"react/react-in-jsx-scope": [
|
||||
"off",
|
||||
],
|
||||
"react/require-render-return": [
|
||||
2,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Next Build production mode first time setup with TypeScript 1`] = `
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
},
|
||||
"globals": {},
|
||||
"ignorePatterns": [],
|
||||
"parserOptions": {
|
||||
"allowImportExportEverywhere": true,
|
||||
"babelOptions": {
|
||||
"caller": {
|
||||
"supportsTopLevelAwait": true,
|
||||
},
|
||||
"presets": [
|
||||
"next/babel",
|
||||
],
|
||||
},
|
||||
"ecmaFeatures": {
|
||||
"jsx": true,
|
||||
},
|
||||
"requireConfigFile": false,
|
||||
"sourceType": "module",
|
||||
"warnOnUnsupportedTypeScriptVersion": true,
|
||||
},
|
||||
"plugins": [
|
||||
"react-hooks",
|
||||
"jsx-a11y",
|
||||
"react",
|
||||
"import",
|
||||
"@next/next",
|
||||
],
|
||||
"rules": {
|
||||
"@next/next/google-font-display": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/google-font-preconnect": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/inline-script-id": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/next-script-for-ga": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-assign-module-variable": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-async-client-component": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-before-interactive-script-outside-document": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-css-tags": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-document-import-in-page": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-duplicate-head": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-head-element": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-head-import-in-document": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-html-link-for-pages": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-img-element": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-page-custom-font": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-script-component-in-head": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-styled-jsx-in-document": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-sync-scripts": [
|
||||
"error",
|
||||
],
|
||||
"@next/next/no-title-in-document-head": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-typos": [
|
||||
"warn",
|
||||
],
|
||||
"@next/next/no-unwanted-polyfillio": [
|
||||
"warn",
|
||||
],
|
||||
"import/no-anonymous-default-export": [
|
||||
"warn",
|
||||
],
|
||||
"jsx-a11y/alt-text": [
|
||||
"warn",
|
||||
{
|
||||
"elements": [
|
||||
"img",
|
||||
],
|
||||
"img": [
|
||||
"Image",
|
||||
],
|
||||
},
|
||||
],
|
||||
"jsx-a11y/aria-props": [
|
||||
"warn",
|
||||
],
|
||||
"jsx-a11y/aria-proptypes": [
|
||||
"warn",
|
||||
],
|
||||
"jsx-a11y/aria-unsupported-elements": [
|
||||
"warn",
|
||||
],
|
||||
"jsx-a11y/role-has-required-aria-props": [
|
||||
"warn",
|
||||
],
|
||||
"jsx-a11y/role-supports-aria-props": [
|
||||
"warn",
|
||||
],
|
||||
"react-hooks/exhaustive-deps": [
|
||||
"warn",
|
||||
],
|
||||
"react-hooks/rules-of-hooks": [
|
||||
"error",
|
||||
],
|
||||
"react/display-name": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-key": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-no-comment-textnodes": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-no-duplicate-props": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-no-target-blank": [
|
||||
"off",
|
||||
],
|
||||
"react/jsx-no-undef": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-uses-react": [
|
||||
2,
|
||||
],
|
||||
"react/jsx-uses-vars": [
|
||||
2,
|
||||
],
|
||||
"react/no-children-prop": [
|
||||
2,
|
||||
],
|
||||
"react/no-danger-with-children": [
|
||||
2,
|
||||
],
|
||||
"react/no-deprecated": [
|
||||
2,
|
||||
],
|
||||
"react/no-direct-mutation-state": [
|
||||
2,
|
||||
],
|
||||
"react/no-find-dom-node": [
|
||||
2,
|
||||
],
|
||||
"react/no-is-mounted": [
|
||||
2,
|
||||
],
|
||||
"react/no-render-return-value": [
|
||||
2,
|
||||
],
|
||||
"react/no-string-refs": [
|
||||
2,
|
||||
],
|
||||
"react/no-unescaped-entities": [
|
||||
2,
|
||||
],
|
||||
"react/no-unknown-property": [
|
||||
"off",
|
||||
],
|
||||
"react/no-unsafe": [
|
||||
0,
|
||||
],
|
||||
"react/prop-types": [
|
||||
"off",
|
||||
],
|
||||
"react/react-in-jsx-scope": [
|
||||
"off",
|
||||
],
|
||||
"react/require-render-return": [
|
||||
2,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
164
test/production/eslint/test/next-build-and-lint.test.ts
Normal file
164
test/production/eslint/test/next-build-and-lint.test.ts
Normal file
|
@ -0,0 +1,164 @@
|
|||
import fs from 'fs-extra'
|
||||
|
||||
import { join } from 'path'
|
||||
import { execSync } from 'child_process'
|
||||
|
||||
import { FileRef, createNext } from 'e2e-utils'
|
||||
|
||||
const dirFirstTimeSetup = join(__dirname, '../first-time-setup')
|
||||
const dirFirstTimeSetupTS = join(__dirname, '../first-time-setup-ts')
|
||||
|
||||
describe('Next Build', () => {
|
||||
;(process.env.TURBOPACK_DEV ? describe.skip : describe)(
|
||||
'production mode',
|
||||
() => {
|
||||
test('first time setup', async () => {
|
||||
const next = await createNext({
|
||||
files: new FileRef(dirFirstTimeSetup),
|
||||
skipStart: true,
|
||||
})
|
||||
|
||||
try {
|
||||
const eslintrcJsonPath = join(next.testDir, '.eslintrc.json')
|
||||
await fs.writeFile(eslintrcJsonPath, '')
|
||||
|
||||
const nextBuildCommand = await next.build()
|
||||
const buildOutput = nextBuildCommand.cliOutput
|
||||
expect(buildOutput).toContain(
|
||||
'No ESLint configuration detected. Run next lint to begin setup'
|
||||
)
|
||||
|
||||
// TODO: Should we exit non-zero here if the config was created? Should we maybe even directly start linting?
|
||||
expect(() => {
|
||||
execSync(`pnpm next lint --strict`, {
|
||||
cwd: next.testDir,
|
||||
encoding: 'utf8',
|
||||
})
|
||||
}).toThrow('Command failed: pnpm next lint --strict')
|
||||
|
||||
const eslintConfigAfterSetupJSON = await execSync(
|
||||
`pnpm eslint --print-config pages/index.js`,
|
||||
{
|
||||
cwd: next.testDir,
|
||||
encoding: 'utf8',
|
||||
}
|
||||
)
|
||||
const { parser, settings, ...eslintConfigAfterSetup } = JSON.parse(
|
||||
eslintConfigAfterSetupJSON
|
||||
)
|
||||
|
||||
expect(eslintConfigAfterSetup).toMatchSnapshot()
|
||||
expect({
|
||||
parser,
|
||||
settings,
|
||||
}).toEqual({
|
||||
// parser: require.resolve('eslint-config-next')
|
||||
parser: expect.stringContaining('eslint-config-next'),
|
||||
settings: {
|
||||
'import/parsers': expect.any(Object),
|
||||
'import/resolver': expect.any(Object),
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
},
|
||||
})
|
||||
expect(Object.entries(settings['import/parsers'])).toEqual([
|
||||
[
|
||||
// require.resolve('@typescript-eslint/parser')
|
||||
expect.stringContaining('@typescript-eslint/parser'),
|
||||
['.ts', '.mts', '.cts', '.tsx', '.d.ts'],
|
||||
],
|
||||
])
|
||||
expect(Object.entries(settings['import/resolver'])).toEqual([
|
||||
[
|
||||
// require.resolve('eslint-import-resolver-node')
|
||||
expect.stringContaining('eslint-import-resolver-node'),
|
||||
{ extensions: ['.js', '.jsx', '.ts', '.tsx'] },
|
||||
],
|
||||
[
|
||||
// require.resolve('eslint-import-resolver-typescript')
|
||||
expect.stringContaining('eslint-import-resolver-typescript'),
|
||||
{ alwaysTryTypes: true },
|
||||
],
|
||||
])
|
||||
} finally {
|
||||
await next.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test('first time setup with TypeScript', async () => {
|
||||
const next = await createNext({
|
||||
files: new FileRef(dirFirstTimeSetupTS),
|
||||
skipStart: true,
|
||||
})
|
||||
|
||||
try {
|
||||
const eslintrcJsonPath = join(next.testDir, '.eslintrc.json')
|
||||
await fs.writeFile(eslintrcJsonPath, '')
|
||||
|
||||
const nextBuildCommand = await next.build()
|
||||
const buildOutput = nextBuildCommand.cliOutput
|
||||
expect(buildOutput).toContain(
|
||||
'No ESLint configuration detected. Run next lint to begin setup'
|
||||
)
|
||||
|
||||
// TODO: Should we exit non-zero here if the config was created? Should we maybe even directly start linting?
|
||||
expect(() => {
|
||||
execSync(`pnpm next lint --strict`, {
|
||||
cwd: next.testDir,
|
||||
encoding: 'utf8',
|
||||
})
|
||||
}).toThrow('Command failed: pnpm next lint --strict')
|
||||
|
||||
const eslintConfigAfterSetupJSON = await execSync(
|
||||
`pnpm eslint --print-config pages/index.tsx`,
|
||||
{
|
||||
cwd: next.testDir,
|
||||
encoding: 'utf8',
|
||||
}
|
||||
)
|
||||
const { parser, settings, ...eslintConfigAfterSetup } = JSON.parse(
|
||||
eslintConfigAfterSetupJSON
|
||||
)
|
||||
|
||||
expect(eslintConfigAfterSetup).toMatchSnapshot()
|
||||
expect({
|
||||
parser,
|
||||
settings,
|
||||
}).toEqual({
|
||||
// parser: require.resolve('@typescript-eslint/parser')
|
||||
parser: expect.stringContaining('@typescript-eslint/parser'),
|
||||
settings: {
|
||||
'import/parsers': expect.any(Object),
|
||||
'import/resolver': expect.any(Object),
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
},
|
||||
})
|
||||
expect(Object.entries(settings['import/parsers'])).toEqual([
|
||||
[
|
||||
// require.resolve('@typescript-eslint/parser')
|
||||
expect.stringContaining('@typescript-eslint/parser'),
|
||||
['.ts', '.mts', '.cts', '.tsx', '.d.ts'],
|
||||
],
|
||||
])
|
||||
expect(Object.entries(settings['import/resolver'])).toEqual([
|
||||
[
|
||||
// require.resolve('eslint-import-resolver-node')
|
||||
expect.stringContaining('eslint-import-resolver-node'),
|
||||
{ extensions: ['.js', '.jsx', '.ts', '.tsx'] },
|
||||
],
|
||||
[
|
||||
// require.resolve('eslint-import-resolver-typescript')
|
||||
expect.stringContaining('eslint-import-resolver-typescript'),
|
||||
{ alwaysTryTypes: true },
|
||||
],
|
||||
])
|
||||
} finally {
|
||||
await next.destroy()
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
Loading…
Reference in a new issue