From 70e1aabb090532618164dfa782df250a1a9db07a Mon Sep 17 00:00:00 2001 From: Nicholas Cunningham Date: Thu, 15 Dec 2022 09:32:27 -0700 Subject: [PATCH] fix(vite): Failing to build when generated library uses jest (#13797) Co-authored-by: Nicholas Cunningham --- e2e/react/src/cypress-component-tests.test.ts | 21 +++++++++++-- e2e/react/src/react-misc.test.ts | 4 ++- e2e/react/src/react-package.test.ts | 31 +++++++++++++------ e2e/react/src/react.test.ts | 16 +++++++--- packages/react/package.json | 1 + .../application/application.spec.ts | 17 ---------- .../src/generators/application/application.ts | 2 +- .../application/lib/set-defaults.ts | 6 +--- .../component-test/component-test.spec.ts | 4 +++ .../cypress-component-configuration.spec.ts | 4 +++ .../library/lib/normalize-options.spec.ts | 2 ++ .../library/lib/normalize-options.ts | 4 --- .../generators/library/lib/set-defaults.ts | 31 +++++++++++++++++++ .../src/generators/library/library.spec.ts | 4 +++ .../react/src/generators/library/library.ts | 19 +++++++++++- .../generators/stories/stories.lib.spec.ts | 4 +++ .../configuration.spec.ts | 4 +++ 17 files changed, 129 insertions(+), 45 deletions(-) create mode 100644 packages/react/src/generators/library/lib/set-defaults.ts diff --git a/e2e/react/src/cypress-component-tests.test.ts b/e2e/react/src/cypress-component-tests.test.ts index a1e1fc4949da2..8692b785fb080 100644 --- a/e2e/react/src/cypress-component-tests.test.ts +++ b/e2e/react/src/cypress-component-tests.test.ts @@ -5,6 +5,7 @@ import { runCLI, uniq, updateFile, + updateJson, updateProjectConfig, } from '../../utils'; @@ -16,13 +17,29 @@ describe('React Cypress Component Tests', () => { beforeAll(() => { projectName = newProject({ name: uniq('cy-react') }); + runCLI( `generate @nrwl/react:app ${appName} --bundler=webpack --no-interactive` ); + + updateJson('nx.json', (json) => ({ + ...json, + generators: { + ...json.generators, + '@nrwl/react': { + library: { + unitTestRunner: 'jest', + }, + }, + }, + })); + runCLI( `generate @nrwl/react:component fancy-cmp --project=${appName} --no-interactive` ); - runCLI(`generate @nrwl/react:lib ${usedInAppLibName} --no-interactive`); + runCLI( + `generate @nrwl/react:lib ${usedInAppLibName} --no-interactive --unitTestRunner=jest` + ); runCLI( `generate @nrwl/react:component btn --project=${usedInAppLibName} --export --no-interactive` ); @@ -83,7 +100,7 @@ export default App;` ); runCLI( - `generate @nrwl/react:lib ${buildableLibName} --buildable --no-interactive` + `generate @nrwl/react:lib ${buildableLibName} --buildable --no-interactive --unitTestRunner=jest` ); runCLI( `generate @nrwl/react:component input --project=${buildableLibName} --export --no-interactive` diff --git a/e2e/react/src/react-misc.test.ts b/e2e/react/src/react-misc.test.ts index 845c7823302ff..5d1b9ec07f727 100644 --- a/e2e/react/src/react-misc.test.ts +++ b/e2e/react/src/react-misc.test.ts @@ -31,7 +31,9 @@ describe('React Applications: additional packages', () => { runCLI(`g @nrwl/react:app ${appName} --bundler=webpack --no-interactive`); runCLI(`g @nrwl/react:redux lemon --project=${appName}`); - runCLI(`g @nrwl/react:lib ${libName} --no-interactive`); + runCLI( + `g @nrwl/react:lib ${libName} --unit-test-runner=jest --no-interactive` + ); runCLI(`g @nrwl/react:redux orange --project=${libName}`); const appTestResults = await runCLIAsync(`test ${appName}`); diff --git a/e2e/react/src/react-package.test.ts b/e2e/react/src/react-package.test.ts index 4a0ba0b6e2ebd..500d74c169d7d 100644 --- a/e2e/react/src/react-package.test.ts +++ b/e2e/react/src/react-package.test.ts @@ -12,6 +12,7 @@ import { tmpProjPath, uniq, updateFile, + updateJson, updateProjectConfig, } from '@nrwl/e2e/utils'; import { names } from '@nrwl/devkit'; @@ -64,16 +65,26 @@ describe('Build React libraries and apps', () => { }; runCLI(`generate @nrwl/react:app ${app} `); - + updateJson('nx.json', (json) => ({ + ...json, + generators: { + ...json.generators, + '@nrwl/react': { + library: { + unitTestRunner: 'none', + }, + }, + }, + })); // generate buildable libs runCLI( - `generate @nrwl/react:library ${parentLib} --bundler=rollup --importPath=@${proj}/${parentLib} --no-interactive ` + `generate @nrwl/react:library ${parentLib} --bundler=rollup --importPath=@${proj}/${parentLib} --no-interactive --unitTestRunner=jest` ); runCLI( - `generate @nrwl/react:library ${childLib} --bundler=rollup --importPath=@${proj}/${childLib} --no-interactive ` + `generate @nrwl/react:library ${childLib} --bundler=rollup --importPath=@${proj}/${childLib} --no-interactive --unitTestRunner=jest` ); runCLI( - `generate @nrwl/react:library ${childLib2} --bundler=rollup --importPath=@${proj}/${childLib2} --no-interactive ` + `generate @nrwl/react:library ${childLib2} --bundler=rollup --importPath=@${proj}/${childLib2} --no-interactive --unitTestRunner=jest` ); createDep(parentLib, [childLib, childLib2]); @@ -178,7 +189,7 @@ export async function h() { return 'c'; } // Setup const myLib = uniq('my-lib'); runCLI( - `generate @nrwl/react:library ${myLib} --bundler=rollup --publishable --importPath="@mproj/${myLib}" --no-interactive` + `generate @nrwl/react:library ${myLib} --bundler=rollup --publishable --importPath="@mproj/${myLib}" --no-interactive --unitTestRunner=jest` ); /** @@ -237,7 +248,7 @@ export async function h() { return 'c'; } const libName = uniq('lib'); runCLI( - `generate @nrwl/react:lib ${libName} --bundler=rollup --importPath=@${proj}/${libName} --no-interactive` + `generate @nrwl/react:lib ${libName} --bundler=rollup --importPath=@${proj}/${libName} --no-interactive --unitTestRunner=jest` ); const mainPath = `libs/${libName}/src/lib/${libName}.tsx`; @@ -306,7 +317,7 @@ describe('Build React applications and libraries with Vite', () => { checkFilesExist(`dist/apps/${viteApp}/index.html`); runCLI( - `generate @nrwl/react:lib ${viteLib} --bundler=vite --inSourceTests --no-interactive` + `generate @nrwl/react:lib ${viteLib} --bundler=vite --inSourceTests --unitTestRunner=vitest --no-interactive` ); expect(() => { checkFilesExist(`libs/${viteLib}/src/lib/${viteLib}.spec.tsx`); @@ -346,7 +357,7 @@ describe('Build React applications and libraries with Vite', () => { const viteLib = uniq('vitelib'); runCLI( - `generate @nrwl/react:lib ${viteLib} --bundler=vite --no-interactive` + `generate @nrwl/react:lib ${viteLib} --bundler=vite --no-interactive --unit-test-runner=none` ); const packageJson = readJson('package.json'); @@ -365,7 +376,9 @@ describe('Build React applications and libraries with Vite', () => { // Convert non-buildable lib to buildable one const nonBuildableLib = uniq('nonbuildablelib'); - runCLI(`generate @nrwl/react:lib ${nonBuildableLib} --no-interactive`); + runCLI( + `generate @nrwl/react:lib ${nonBuildableLib} --no-interactive --unitTestRunner=none` + ); runCLI( `generate @nrwl/vite:configuration ${nonBuildableLib} --uiFramework=react --no-interactive` ); diff --git a/e2e/react/src/react.test.ts b/e2e/react/src/react.test.ts index d0d92a78a2afe..1634736e5bb47 100644 --- a/e2e/react/src/react.test.ts +++ b/e2e/react/src/react.test.ts @@ -30,9 +30,11 @@ describe('React Applications', () => { runCLI( `generate @nrwl/react:app ${appName} --style=css --bundler=webpack --no-interactive` ); - runCLI(`generate @nrwl/react:lib ${libName} --style=css --no-interactive`); runCLI( - `generate @nrwl/react:lib ${libWithNoComponents} --no-interactive --no-component` + `generate @nrwl/react:lib ${libName} --style=css --no-interactive --unit-test-runner=jest` + ); + runCLI( + `generate @nrwl/react:lib ${libWithNoComponents} --no-interactive --no-component --unit-test-runner=jest` ); // Libs should not include package.json by default @@ -80,7 +82,9 @@ describe('React Applications', () => { runCLI( `generate @nrwl/react:app ${appName} --bundler=webpack --no-interactive --js` ); - runCLI(`generate @nrwl/react:lib ${libName} --no-interactive --js`); + runCLI( + `generate @nrwl/react:lib ${libName} --no-interactive --js --unit-test-runner=none` + ); const mainPath = `apps/${appName}/src/main.js`; updateFile( @@ -103,7 +107,7 @@ describe('React Applications', () => { `generate @nrwl/react:app ${appName} --bundler=vite --no-interactive` ); runCLI( - `generate @nrwl/react:lib ${libName} --bundler=none --no-interactive` + `generate @nrwl/react:lib ${libName} --bundler=none --no-interactive --unit-test-runner=vitest` ); // Library generated with Vite @@ -230,7 +234,9 @@ describe('React Applications and Libs with PostCSS', () => { const libName = uniq('lib'); runCLI(`g @nrwl/react:app ${appName} --bundler=webpack --no-interactive`); - runCLI(`g @nrwl/react:lib ${libName} --no-interactive`); + runCLI( + `g @nrwl/react:lib ${libName} --no-interactive --unit-test-runner=none` + ); const mainPath = `apps/${appName}/src/main.tsx`; updateFile( diff --git a/packages/react/package.json b/packages/react/package.json index d6b2b051b7bab..5ccdc7058e1fd 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -36,6 +36,7 @@ "@nrwl/workspace": "file:../workspace", "@phenomnomnominal/tsquery": "4.1.1", "chalk": "4.1.0", + "enquirer": "~2.3.6", "minimatch": "3.0.5", "semver": "7.3.4" }, diff --git a/packages/react/src/generators/application/application.spec.ts b/packages/react/src/generators/application/application.spec.ts index d81a8e367bfd6..36a783b02f150 100644 --- a/packages/react/src/generators/application/application.spec.ts +++ b/packages/react/src/generators/application/application.spec.ts @@ -1004,21 +1004,4 @@ describe('app', () => { } ); }); - - describe('setting generator defaults', () => { - it('should set libraries to use vitest when app uses vite bundler', async () => { - await applicationGenerator(appTree, { - ...schema, - name: 'my-app', - bundler: 'vite', - }); - - const workspace = readWorkspaceConfiguration(appTree); - expect(workspace.generators['@nrwl/react']).toMatchObject({ - library: { - unitTestRunner: 'vitest', - }, - }); - }); - }); }); diff --git a/packages/react/src/generators/application/application.ts b/packages/react/src/generators/application/application.ts index ee6e0c8baa31f..1225554cd60a7 100644 --- a/packages/react/src/generators/application/application.ts +++ b/packages/react/src/generators/application/application.ts @@ -109,7 +109,7 @@ export async function applicationGenerator(host: Tree, schema: Schema) { uiFramework: 'react', project: options.projectName, newProject: true, - includeVitest: true, + includeVitest: options.unitTestRunner === 'vitest', inSourceTests: options.inSourceTests, }); tasks.push(viteTask); diff --git a/packages/react/src/generators/application/lib/set-defaults.ts b/packages/react/src/generators/application/lib/set-defaults.ts index cebbea636f692..47ca33c97ba46 100644 --- a/packages/react/src/generators/application/lib/set-defaults.ts +++ b/packages/react/src/generators/application/lib/set-defaults.ts @@ -37,11 +37,7 @@ export function setDefaults(host: Tree, options: NormalizedSchema) { linter: options.linter, ...prev.library, }; - // Future react libs should use same test runner as the app. - if (options.unitTestRunner === 'vitest') { - // Note: We don't set bundler: 'vite' for libraries because that means they are buildable. - libDefaults.unitTestRunner ??= 'vitest'; - } + workspace.generators = { ...workspace.generators, '@nrwl/react': { diff --git a/packages/react/src/generators/component-test/component-test.spec.ts b/packages/react/src/generators/component-test/component-test.spec.ts index fe9acc514544c..c752f4d2468a5 100644 --- a/packages/react/src/generators/component-test/component-test.spec.ts +++ b/packages/react/src/generators/component-test/component-test.spec.ts @@ -2,6 +2,7 @@ import { assertMinimumCypressVersion } from '@nrwl/cypress/src/utils/cypress-ver import { Tree } from '@nrwl/devkit'; import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; import { Linter } from '@nrwl/linter'; +import enquirer = require('enquirer'); import libraryGenerator from '../library/library'; import { componentTestGenerator } from './component-test'; @@ -13,6 +14,9 @@ describe(componentTestGenerator.name, () => { > = assertMinimumCypressVersion as never; beforeEach(() => { tree = createTreeWithEmptyV1Workspace(); + jest + .spyOn(enquirer, 'prompt') + .mockReturnValue(new Promise((res) => res({ runner: 'jest' }))); }); it('should create component test for tsx files', async () => { mockedAssertMinimumCypressVersion.mockReturnValue(); diff --git a/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts b/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts index 40acf9e08f3ce..8323a14430c13 100644 --- a/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts +++ b/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts @@ -12,6 +12,7 @@ import { applicationGenerator } from '../application/application'; import { componentGenerator } from '../component/component'; import { libraryGenerator } from '../library/library'; import { cypressComponentConfigGenerator } from './cypress-component-configuration'; +import enquirer = require('enquirer'); let projectGraph: ProjectGraph; jest.mock('@nrwl/devkit', () => ({ @@ -29,6 +30,9 @@ describe('React:CypressComponentTestConfiguration', () => { > = assertMinimumCypressVersion as never; beforeEach(() => { tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); + jest + .spyOn(enquirer, 'prompt') + .mockReturnValue(new Promise((res) => res({ runner: 'jest' }))); }); it('should generate cypress config with vite', async () => { diff --git a/packages/react/src/generators/library/lib/normalize-options.spec.ts b/packages/react/src/generators/library/lib/normalize-options.spec.ts index 62a2407c5a350..5fa93893549a6 100644 --- a/packages/react/src/generators/library/lib/normalize-options.spec.ts +++ b/packages/react/src/generators/library/lib/normalize-options.spec.ts @@ -15,6 +15,7 @@ describe('normalizeOptions', () => { name: 'test', style: 'css', linter: Linter.None, + unitTestRunner: 'jest', }); expect(options).toMatchObject({ @@ -57,6 +58,7 @@ describe('normalizeOptions', () => { style: 'css', linter: Linter.None, bundler: 'vite', + unitTestRunner: 'vitest', }); expect(options).toMatchObject({ diff --git a/packages/react/src/generators/library/lib/normalize-options.ts b/packages/react/src/generators/library/lib/normalize-options.ts index 3e33ee70d5b99..1118a9888878b 100644 --- a/packages/react/src/generators/library/lib/normalize-options.ts +++ b/packages/react/src/generators/library/lib/normalize-options.ts @@ -57,10 +57,6 @@ export function normalizeOptions( normalized.bundler !== 'none' || options.buildable || options.publishable ); - normalized.unitTestRunner = - normalized.unitTestRunner ?? - (normalized.bundler === 'vite' ? 'vitest' : 'jest'); - normalized.inSourceTests === normalized.minimal || normalized.inSourceTests; if (options.appProject) { diff --git a/packages/react/src/generators/library/lib/set-defaults.ts b/packages/react/src/generators/library/lib/set-defaults.ts new file mode 100644 index 0000000000000..645936f94ed36 --- /dev/null +++ b/packages/react/src/generators/library/lib/set-defaults.ts @@ -0,0 +1,31 @@ +import { + readWorkspaceConfiguration, + Tree, + updateWorkspaceConfiguration, +} from '@nrwl/devkit'; +import { NormalizedSchema } from '../schema'; + +export function setDefaults(host: Tree, options: NormalizedSchema) { + const workspace = readWorkspaceConfiguration(host); + + workspace.generators = workspace.generators || {}; + workspace.generators['@nrwl/react'] = + workspace.generators['@nrwl/react'] || {}; + + const prev = { ...workspace.generators['@nrwl/react'] }; + + const libDefaults = { + ...prev.library, + unitTestRunner: prev.library?.unitTestRunner ?? options.unitTestRunner, + }; + + workspace.generators = { + ...workspace.generators, + '@nrwl/react': { + ...prev, + library: libDefaults, + }, + }; + + updateWorkspaceConfiguration(host, workspace); +} diff --git a/packages/react/src/generators/library/library.spec.ts b/packages/react/src/generators/library/library.spec.ts index e59e750894e27..754985088e7f3 100644 --- a/packages/react/src/generators/library/library.spec.ts +++ b/packages/react/src/generators/library/library.spec.ts @@ -11,6 +11,7 @@ import { createTreeWithEmptyWorkspace, } from '@nrwl/devkit/testing'; import { Linter } from '@nrwl/linter'; +import enquirer = require('enquirer'); import { nxVersion } from '../../utils/versions'; import applicationGenerator from '../application/application'; import libraryGenerator from './library'; @@ -370,6 +371,9 @@ describe('lib', () => { describe('--unit-test-runner none', () => { it('should not generate test configuration', async () => { + jest + .spyOn(enquirer, 'prompt') + .mockReturnValue(new Promise((res) => res({ runner: 'none' }))); await libraryGenerator(tree, { ...defaultSchema, unitTestRunner: 'none', diff --git a/packages/react/src/generators/library/library.ts b/packages/react/src/generators/library/library.ts index de9461cc87432..12b8ded58f5a7 100644 --- a/packages/react/src/generators/library/library.ts +++ b/packages/react/src/generators/library/library.ts @@ -23,10 +23,26 @@ import { createFiles } from './lib/create-files'; import { updateBaseTsConfig } from './lib/update-base-tsconfig'; import { extractTsConfigBase } from '../../utils/create-ts-config'; import { installCommonDependencies } from './lib/install-common-dependencies'; +import { prompt } from 'enquirer'; +import { setDefaults } from './lib/set-defaults'; export async function libraryGenerator(host: Tree, schema: Schema) { const tasks: GeneratorCallback[] = []; + // Check if unit test runner was provided or if we have a default + if (!schema.unitTestRunner) { + schema.unitTestRunner = ( + await prompt<{ runner: 'vitest' | 'jest' | 'none' }>([ + { + message: 'What unit test runner should be used?', + type: 'select', + name: 'runner', + choices: ['vitest', 'jest', 'none'], + }, + ]) + ).runner; + } + const options = normalizeOptions(host, schema); if (options.publishable === true && !schema.importPath) { throw new Error( @@ -80,7 +96,7 @@ export async function libraryGenerator(host: Tree, schema: Schema) { newProject: true, includeLib: true, inSourceTests: options.inSourceTests, - includeVitest: true, + includeVitest: options.unitTestRunner === 'vitest', }); tasks.push(viteTask); } else if (options.buildable && options.bundler === 'rollup') { @@ -159,6 +175,7 @@ export async function libraryGenerator(host: Tree, schema: Schema) { const routeTask = updateAppRoutes(host, options); tasks.push(routeTask); + setDefaults(host, options); if (!options.skipFormat) { await formatFiles(host); diff --git a/packages/react/src/generators/stories/stories.lib.spec.ts b/packages/react/src/generators/stories/stories.lib.spec.ts index 0c92e83059015..20e43daa8cbcc 100644 --- a/packages/react/src/generators/stories/stories.lib.spec.ts +++ b/packages/react/src/generators/stories/stories.lib.spec.ts @@ -4,11 +4,15 @@ import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; import applicationGenerator from '../application/application'; import { Linter } from '@nrwl/linter'; import libraryGenerator from '../library/library'; +import enquirer = require('enquirer'); describe('react:stories for libraries', () => { let appTree: Tree; beforeEach(async () => { + jest + .spyOn(enquirer, 'prompt') + .mockReturnValue(new Promise((res) => res({ runner: 'jest' }))); appTree = await createTestUILib('test-ui-lib'); // create another component diff --git a/packages/react/src/generators/storybook-configuration/configuration.spec.ts b/packages/react/src/generators/storybook-configuration/configuration.spec.ts index be9dcb8eada43..793f50f912040 100644 --- a/packages/react/src/generators/storybook-configuration/configuration.spec.ts +++ b/packages/react/src/generators/storybook-configuration/configuration.spec.ts @@ -2,6 +2,7 @@ import { installedCypressVersion } from '@nrwl/cypress/src/utils/cypress-version import { logger, Tree } from '@nrwl/devkit'; import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; import { Linter } from '@nrwl/linter'; +import enquirer = require('enquirer'); import applicationGenerator from '../application/application'; import componentGenerator from '../component/component'; import libraryGenerator from '../library/library'; @@ -24,6 +25,9 @@ describe('react:storybook-configuration', () => { mockedInstalledCypressVersion.mockReturnValue(10); jest.spyOn(logger, 'warn').mockImplementation(() => {}); jest.spyOn(logger, 'debug').mockImplementation(() => {}); + jest + .spyOn(enquirer, 'prompt') + .mockReturnValue(new Promise((res) => res({ runner: 'jest' }))); }); afterEach(() => {