nx/e2e/eslint/src/linter-legacy.test.ts
James Henry 68eeb2eeed
feat(linter): create new workspaces with ESLint v9 and typescript-eslint v8 (#27404)
Closes #27451

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2024-09-12 16:02:27 -04:00

226 lines
6.9 KiB
TypeScript

import {
checkFilesDoNotExist,
checkFilesExist,
cleanupProject,
getSelectedPackageManager,
newProject,
readFile,
readJson,
renameFile,
runCLI,
runCreateWorkspace,
uniq,
updateFile,
} from '@nx/e2e/utils';
describe('Linter (legacy)', () => {
describe('Integrated (eslintrc config)', () => {
let originalEslintUseFlatConfigVal: string | undefined;
const myapp = uniq('myapp');
const mylib = uniq('mylib');
beforeAll(() => {
// Opt into legacy .eslintrc config format for these tests
originalEslintUseFlatConfigVal = process.env.ESLINT_USE_FLAT_CONFIG;
process.env.ESLINT_USE_FLAT_CONFIG = 'false';
newProject({
packages: ['@nx/react', '@nx/js', '@nx/eslint'],
});
runCLI(`generate @nx/react:app ${myapp} --tags=validtag`, {
env: { NX_ADD_PLUGINS: 'false' },
});
runCLI(`generate @nx/js:lib ${mylib}`, {
env: { NX_ADD_PLUGINS: 'false' },
});
});
afterAll(() => {
process.env.ESLINT_USE_FLAT_CONFIG = originalEslintUseFlatConfigVal;
cleanupProject();
});
describe('linting errors', () => {
let defaultEslintrc;
beforeAll(() => {
updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
defaultEslintrc = readJson('.eslintrc.json');
});
afterEach(() => {
updateFile('.eslintrc.json', JSON.stringify(defaultEslintrc, null, 2));
});
it('should check for linting errors', () => {
// create faulty file
updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
const eslintrc = readJson('.eslintrc.json');
// set the eslint rules to error
eslintrc.overrides.forEach((override) => {
if (override.files.includes('*.ts')) {
override.rules['no-console'] = 'error';
}
});
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));
// 1. linting should error when rules are not followed
expect(() => runCLI(`lint ${myapp}`)).toThrow();
// 2. linting should not error when rules are not followed and the force flag is specified
expect(() => runCLI(`lint ${myapp} --force`)).not.toThrow();
eslintrc.overrides.forEach((override) => {
if (override.files.includes('*.ts')) {
override.rules['no-console'] = undefined;
}
});
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));
// 3. linting should not error when all rules are followed
expect(() =>
runCLI(`lint ${myapp}`, { silenceError: true })
).not.toThrow();
}, 1000000);
it('should print the effective configuration for a file specified using --print-config', () => {
const eslint = readJson('.eslintrc.json');
eslint.overrides.push({
files: ['src/index.ts'],
rules: {
'specific-rule': 'off',
},
});
updateFile('.eslintrc.json', JSON.stringify(eslint, null, 2));
const out = runCLI(`lint ${myapp} --print-config src/index.ts`, {
env: { CI: 'false' }, // We don't want to show the summary table from cloud runner
silenceError: true,
});
expect(out).toContain('"specific-rule": [');
}, 1000000);
});
});
describe('eslintrc convert to flat config', () => {
let originalEslintUseFlatConfigVal: string | undefined;
const packageManager = getSelectedPackageManager() || 'pnpm';
beforeAll(() => {
// Opt into legacy .eslintrc config format for these tests
originalEslintUseFlatConfigVal = process.env.ESLINT_USE_FLAT_CONFIG;
process.env.ESLINT_USE_FLAT_CONFIG = 'false';
});
afterAll(() => {
process.env.ESLINT_USE_FLAT_CONFIG = originalEslintUseFlatConfigVal;
});
beforeEach(() => {
process.env.NX_ADD_PLUGINS = 'false';
});
afterEach(() => {
delete process.env.NX_ADD_PLUGINS;
cleanupProject();
});
it('should convert integrated to flat config', () => {
const myapp = uniq('myapp');
const mylib = uniq('mylib');
const mylib2 = uniq('mylib2');
runCreateWorkspace(myapp, {
preset: 'react-monorepo',
appName: myapp,
style: 'css',
packageManager,
bundler: 'vite',
e2eTestRunner: 'none',
});
runCLI(
`generate @nx/js:lib ${mylib} --directory libs/${mylib} --projectNameAndRootFormat as-provided`,
{
env: { NX_ADD_PLUGINS: 'false' },
}
);
runCLI(
`generate @nx/js:lib ${mylib2} --directory libs/${mylib2} --projectNameAndRootFormat as-provided`,
{
env: { NX_ADD_PLUGINS: 'false' },
}
);
// migrate to flat structure
runCLI(`generate @nx/eslint:convert-to-flat-config`, {
env: { NX_ADD_PLUGINS: 'false' },
});
checkFilesExist(
'eslint.config.js',
`apps/${myapp}/eslint.config.js`,
`libs/${mylib}/eslint.config.js`,
`libs/${mylib2}/eslint.config.js`
);
checkFilesDoNotExist(
'.eslintrc.json',
`apps/${myapp}/.eslintrc.json`,
`libs/${mylib}/.eslintrc.json`,
`libs/${mylib2}/.eslintrc.json`
);
// move eslint.config one step up
// to test the absence of the flat eslint config in the project root folder
renameFile(`libs/${mylib2}/eslint.config.js`, `libs/eslint.config.js`);
updateFile(
`libs/eslint.config.js`,
readFile(`libs/eslint.config.js`).replace(
`../../eslint.config.js`,
`../eslint.config.js`
)
);
const outFlat = runCLI(`affected -t lint`, {
silenceError: true,
});
expect(outFlat).toContain(`${myapp}:lint`);
expect(outFlat).toContain(`${mylib}:lint`);
expect(outFlat).toContain(`${mylib2}:lint`);
}, 1000000);
it('should convert standalone to flat config', () => {
const myapp = uniq('myapp');
const mylib = uniq('mylib');
runCreateWorkspace(myapp, {
preset: 'react-standalone',
appName: myapp,
style: 'css',
packageManager,
bundler: 'vite',
e2eTestRunner: 'none',
});
runCLI(`generate @nx/js:lib ${mylib}`, {
env: { NX_ADD_PLUGINS: 'false' },
});
// migrate to flat structure
runCLI(`generate @nx/eslint:convert-to-flat-config`, {
env: { NX_ADD_PLUGINS: 'false' },
});
checkFilesExist(
'eslint.config.js',
`${mylib}/eslint.config.js`,
'eslint.base.config.js'
);
checkFilesDoNotExist(
'.eslintrc.json',
`${mylib}/.eslintrc.json`,
'.eslintrc.base.json'
);
const outFlat = runCLI(`affected -t lint`, {
silenceError: true,
});
expect(outFlat).toContain(`${myapp}:lint`);
expect(outFlat).toContain(`${mylib}:lint`);
}, 1000000);
});
});