diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d798ca10..ae3af631 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,6 +66,7 @@ jobs: flag-for-pinia: '--pinia' flag-for-vitest: '--vitest' flag-for-e2e: '--cypress' + flag-for-eslint: '--eslint' flag-for-devtools: '--devtools' - node-version: 18 @@ -76,6 +77,7 @@ jobs: flag-for-pinia: '--pinia' flag-for-vitest: '--vitest' flag-for-e2e: '--cypress' + flag-for-eslint: '--eslint' flag-for-devtools: '--devtools' - node-version: 20 @@ -86,6 +88,7 @@ jobs: flag-for-pinia: '--pinia' flag-for-vitest: '--vitest' flag-for-e2e: '--cypress' + flag-for-eslint: '--eslint' flag-for-devtools: '--devtools' - node-version: 22 @@ -96,11 +99,12 @@ jobs: flag-for-pinia: '--pinia' flag-for-vitest: '--vitest' flag-for-e2e: '--cypress' + flag-for-eslint: '--eslint' flag-for-devtools: '--devtools' runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.os == 'windows-latest' }} env: - FEATURE_FLAGS: ${{ matrix.flag-for-ts }} ${{ matrix.flag-for-jsx }} ${{ matrix.flag-for-router }} ${{ matrix.flag-for-pinia }} ${{ matrix.flag-for-vitest }} ${{ matrix.flag-for-e2e }} ${{matrix.flag-for-devtools}} + FEATURE_FLAGS: ${{ matrix.flag-for-ts }} ${{ matrix.flag-for-jsx }} ${{ matrix.flag-for-router }} ${{ matrix.flag-for-pinia }} ${{ matrix.flag-for-vitest }} ${{ matrix.flag-for-e2e }} ${{matrix.flag-for-eslint}} ${{matrix.flag-for-devtools}} # Sometimes the Linux runner can't verify Cypress in 30s CYPRESS_VERIFY_TIMEOUT: 60000 steps: @@ -189,3 +193,8 @@ jobs: name: Run e2e test script working-directory: ../sample-project run: pnpm test:e2e + + - if: ${{ contains(matrix.flag-for-eslint, '--') }} + name: Run lint script + working-directory: ../sample-project + run: pnpm lint --no-fix --max-warnings=0 diff --git a/.prettierignore b/.prettierignore index 688151cd..be18eeb0 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,6 +4,8 @@ pnpm-lock.yaml # https://github.com/prettier/prettier/issues/7884 **/*.spec.js **/*.spec.ts +# but let's format our unit tests +!__test__/**/*.spec.ts **/dist # https://github.com/prettier/prettier/issues/5246 **/*.html diff --git a/__test__/locale.spec.ts b/__test__/locale.spec.ts index 1ea0a112..6e36d3b9 100644 --- a/__test__/locale.spec.ts +++ b/__test__/locale.spec.ts @@ -6,23 +6,23 @@ import en from '../locales/en-US.json' function getKeys(obj: any, path = '', result: string[] = []) { for (let key in obj) { if (typeof obj[key] === 'object') { - getKeys(obj[key], path ? `${path}.${key}` : key, result); + getKeys(obj[key], path ? `${path}.${key}` : key, result) } else { - result.push(path ? `${path}.${key}` : key); + result.push(path ? `${path}.${key}` : key) } } - return result; + return result } const localesOtherThanEnglish = readdirSync(resolve(__dirname, '../locales')).filter((file) => { return file.endsWith('.json') && !file.startsWith('en-US') }) -const defaultKeys = getKeys(en); +const defaultKeys = getKeys(en) -describe("locale files should include all keys", () => { +describe('locale files should include all keys', () => { localesOtherThanEnglish.forEach((locale) => { it(`for ${locale}`, () => { expect(getKeys(require(`../locales/${locale}`))).toEqual(defaultKeys) }) }) -}) \ No newline at end of file +}) diff --git a/__test__/renderEslint.spec.ts b/__test__/renderEslint.spec.ts new file mode 100644 index 00000000..2a150669 --- /dev/null +++ b/__test__/renderEslint.spec.ts @@ -0,0 +1,76 @@ +import { it, describe, expect } from 'vitest' +import { getAdditionalConfigAndDependencies } from '../utils/renderEslint' + +describe('renderEslint', () => { + it('should get additional dependencies and config with no test flags', () => { + const { additionalConfig, additionalDependencies } = getAdditionalConfigAndDependencies({ + needsVitest: false, + needsCypress: false, + needsCypressCT: false, + needsPlaywright: false + }) + expect(additionalConfig).toStrictEqual({}) + expect(additionalDependencies).toStrictEqual({}) + }) + + it('should get additional dependencies and config with for vitest', () => { + const { additionalConfig, additionalDependencies } = getAdditionalConfigAndDependencies({ + needsVitest: true, + needsCypress: false, + needsCypressCT: false, + needsPlaywright: false + }) + expect(additionalConfig.overrides[0].files).toStrictEqual([ + 'src/**/*.{test,spec}.{js,ts,jsx,tsx}' + ]) + expect(additionalConfig.overrides[0].extends).toStrictEqual([ + 'plugin:@vitest/legacy-recommended' + ]) + expect(additionalDependencies['@vitest/eslint-plugin']).not.toBeUndefined() + }) + + it('should get additional dependencies and config with for cypress', () => { + const { additionalConfig, additionalDependencies } = getAdditionalConfigAndDependencies({ + needsVitest: false, + needsCypress: true, + needsCypressCT: false, + needsPlaywright: false + }) + expect(additionalConfig.overrides[0].files).toStrictEqual([ + 'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/support/**/*.{js,ts,jsx,tsx}' + ]) + expect(additionalConfig.overrides[0].extends).toStrictEqual(['plugin:cypress/recommended']) + expect(additionalDependencies['eslint-plugin-cypress']).not.toBeUndefined() + }) + + it('should get additional dependencies and config with for cypress with component testing', () => { + const { additionalConfig, additionalDependencies } = getAdditionalConfigAndDependencies({ + needsVitest: false, + needsCypress: true, + needsCypressCT: true, + needsPlaywright: false + }) + expect(additionalConfig.overrides[0].files).toStrictEqual([ + '**/__tests__/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/support/**/*.{js,ts,jsx,tsx}' + ]) + expect(additionalConfig.overrides[0].extends).toStrictEqual(['plugin:cypress/recommended']) + expect(additionalDependencies['eslint-plugin-cypress']).not.toBeUndefined() + }) + + it('should get additional dependencies and config with for playwright', () => { + const { additionalConfig, additionalDependencies } = getAdditionalConfigAndDependencies({ + needsVitest: false, + needsCypress: false, + needsCypressCT: false, + needsPlaywright: true + }) + expect(additionalConfig.overrides[0].files).toStrictEqual([ + 'e2e/**/*.{test,spec}.{js,ts,jsx,tsx}' + ]) + expect(additionalConfig.overrides[0].extends).toStrictEqual(['plugin:playwright/recommended']) + expect(additionalDependencies['eslint-plugin-playwright']).not.toBeUndefined() + }) +}) diff --git a/index.ts b/index.ts index f552cfd8..8e0e55c9 100755 --- a/index.ts +++ b/index.ts @@ -459,6 +459,7 @@ async function init() { if (needsEslint) { renderEslint(root, { needsTypeScript, + needsVitest, needsCypress, needsCypressCT, needsPrettier, diff --git a/scripts/snapshot.mjs b/scripts/snapshot.mjs index ea4c4ad1..b80da8e1 100644 --- a/scripts/snapshot.mjs +++ b/scripts/snapshot.mjs @@ -54,7 +54,12 @@ function fullCombination(arr) { } let flagCombinations = fullCombination(featureFlags) -flagCombinations.push(['default'], ['devtools', 'router', 'pinia'], ['eslint'], ['eslint-with-prettier']) +flagCombinations.push( + ['default'], + ['devtools', 'router', 'pinia'], + ['eslint'], + ['eslint-with-prettier'] +) // `--with-tests` are equivalent of `--vitest --cypress` // Previously it means `--cypress` without `--vitest`. diff --git a/template/eslint/package.json b/template/eslint/package.json index 7619f8df..9522c94b 100644 --- a/template/eslint/package.json +++ b/template/eslint/package.json @@ -1,5 +1,6 @@ { "devDependencies": { + "@vitest/eslint-plugin": "1.0.2", "eslint-plugin-cypress": "^3.4.0", "eslint-plugin-playwright": "^1.6.2" } diff --git a/utils/renderEslint.ts b/utils/renderEslint.ts index ecb74ae6..fb061814 100644 --- a/utils/renderEslint.ts +++ b/utils/renderEslint.ts @@ -13,38 +13,14 @@ const eslintDeps = eslintTemplatePackage.devDependencies export default function renderEslint( rootDir, - { needsTypeScript, needsCypress, needsCypressCT, needsPrettier, needsPlaywright } + { needsTypeScript, needsVitest, needsCypress, needsCypressCT, needsPrettier, needsPlaywright } ) { - const additionalConfig: Linter.Config = {} - const additionalDependencies = {} - - if (needsCypress) { - additionalConfig.overrides = [ - { - files: needsCypressCT - ? [ - '**/__tests__/*.{cy,spec}.{js,ts,jsx,tsx}', - 'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', - 'cypress/support/**/*.{js,ts,jsx,tsx}' - ] - : ['cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', 'cypress/support/**/*.{js,ts,jsx,tsx}'], - extends: ['plugin:cypress/recommended'] - } - ] - - additionalDependencies['eslint-plugin-cypress'] = eslintDeps['eslint-plugin-cypress'] - } - - if (needsPlaywright) { - additionalConfig.overrides = [ - { - files: ['e2e/**/*.{test,spec}.{js,ts,jsx,tsx}'], - extends: ['plugin:playwright/recommended'] - } - ] - - additionalDependencies['eslint-plugin-playwright'] = eslintDeps['eslint-plugin-playwright'] - } + const { additionalConfig, additionalDependencies } = getAdditionalConfigAndDependencies({ + needsVitest, + needsCypress, + needsCypressCT, + needsPlaywright + }) const { pkg, files } = createESLintConfig({ vueVersion: '3.x', @@ -86,3 +62,54 @@ export default function renderEslint( fs.writeFileSync(fullPath, content as string, 'utf-8') } } + +// visible for testing +export function getAdditionalConfigAndDependencies({ + needsVitest, + needsCypress, + needsCypressCT, + needsPlaywright +}) { + const additionalConfig: Linter.Config = {} + const additionalDependencies = {} + + if (needsVitest) { + additionalConfig.overrides = [ + { + files: ['src/**/*.{test,spec}.{js,ts,jsx,tsx}'], + extends: ['plugin:@vitest/legacy-recommended'] + } + ] + + additionalDependencies['@vitest/eslint-plugin'] = eslintDeps['@vitest/eslint-plugin'] + } + + if (needsCypress) { + additionalConfig.overrides = [ + { + files: needsCypressCT + ? [ + '**/__tests__/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/support/**/*.{js,ts,jsx,tsx}' + ] + : ['cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', 'cypress/support/**/*.{js,ts,jsx,tsx}'], + extends: ['plugin:cypress/recommended'] + } + ] + + additionalDependencies['eslint-plugin-cypress'] = eslintDeps['eslint-plugin-cypress'] + } + + if (needsPlaywright) { + additionalConfig.overrides = [ + { + files: ['e2e/**/*.{test,spec}.{js,ts,jsx,tsx}'], + extends: ['plugin:playwright/recommended'] + } + ] + + additionalDependencies['eslint-plugin-playwright'] = eslintDeps['eslint-plugin-playwright'] + } + return { additionalConfig, additionalDependencies } +}