fix(testing): component testing generator should trust user to provide valid build target (#17600)

This commit is contained in:
Colum Ferry 2023-06-15 10:37:04 +01:00 committed by GitHub
parent f8ea4b6117
commit a25d1fca47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 67 additions and 51 deletions

View File

@ -4,7 +4,6 @@ import {
joinPathFragments, joinPathFragments,
ProjectGraph, ProjectGraph,
readProjectConfiguration, readProjectConfiguration,
stripIndents,
Tree, Tree,
updateProjectConfiguration, updateProjectConfiguration,
} from '@nx/devkit'; } from '@nx/devkit';
@ -40,6 +39,10 @@ describe('Cypress Component Testing Configuration', () => {
mockedInstalledCypressVersion.mockReturnValue(10); mockedInstalledCypressVersion.mockReturnValue(10);
}); });
afterEach(() => {
jest.clearAllMocks();
});
describe('updateProjectConfig', () => { describe('updateProjectConfig', () => {
it('should add project config with --target=<project>:<target>', async () => { it('should add project config with --target=<project>:<target>', async () => {
await generateTestApplication(tree, { await generateTestApplication(tree, {
@ -165,7 +168,7 @@ describe('Cypress Component Testing Configuration', () => {
}); });
}); });
it('should throw with invalid --build-target', async () => { it('should not throw with invalid --build-target', async () => {
await generateTestApplication(tree, { await generateTestApplication(tree, {
name: 'fancy-app', name: 'fancy-app',
}); });
@ -213,12 +216,11 @@ describe('Cypress Component Testing Configuration', () => {
buildTarget: 'fancy-app:build', buildTarget: 'fancy-app:build',
generateTests: false, generateTests: false,
}); });
}).rejects.toThrowErrorMatchingInlineSnapshot(` }).resolves;
"Error trying to find build configuration. Try manually specifying the build target with the --build-target flag.
Provided project? fancy-lib expect(
Provided build target? fancy-app:build require('@nx/devkit').createProjectGraphAsync
Provided Executors? @nx/angular:webpack-browser, @nrwl/angular:webpack-browser, @angular-devkit/build-angular:browser" ).not.toHaveBeenCalled();
`);
}); });
it('should use own project config', async () => { it('should use own project config', async () => {
await generateTestApplication(tree, { await generateTestApplication(tree, {
@ -847,6 +849,7 @@ async function setup(
} }
} }
} }
function getCmpsFromTree( function getCmpsFromTree(
tree: Tree, tree: Tree,
options: { basePath: string; name: string } options: { basePath: string; name: string }

View File

@ -1,9 +1,12 @@
import { cypressComponentConfiguration as baseCyCTConfig } from '@nx/cypress'; import { cypressComponentConfiguration as baseCyCTConfig } from '@nx/cypress';
import { import {
addMountDefinition,
addDefaultCTConfig, addDefaultCTConfig,
addMountDefinition,
} from '@nx/cypress/src/utils/config'; } from '@nx/cypress/src/utils/config';
import { findBuildConfig } from '@nx/cypress/src/utils/find-target-options'; import {
findBuildConfig,
FoundTarget,
} from '@nx/cypress/src/utils/find-target-options';
import { import {
formatFiles, formatFiles,
joinPathFragments, joinPathFragments,
@ -45,6 +48,7 @@ export async function cypressComponentConfiguration(
installTask(); installTask();
}; };
} }
async function addFiles( async function addFiles(
tree: Tree, tree: Tree,
projectConfig: ProjectConfiguration, projectConfig: ProjectConfiguration,
@ -116,7 +120,10 @@ async function updateProjectConfig(
tree: Tree, tree: Tree,
options: CypressComponentConfigSchema options: CypressComponentConfigSchema
) { ) {
const found = await findBuildConfig(tree, { let found: FoundTarget = { target: options.buildTarget, config: undefined };
if (!options.buildTarget) {
found = await findBuildConfig(tree, {
project: options.project, project: options.project,
buildTarget: options.buildTarget, buildTarget: options.buildTarget,
validExecutorNames: new Set<string>([ validExecutorNames: new Set<string>([
@ -127,6 +134,7 @@ async function updateProjectConfig(
}); });
assertValidConfig(found?.config); assertValidConfig(found?.config);
}
const projectConfig = readProjectConfiguration(tree, options.project); const projectConfig = readProjectConfiguration(tree, options.project);
projectConfig.targets['component-test'].options = { projectConfig.targets['component-test'].options = {

View File

@ -27,7 +27,7 @@ interface FindTargetOptions {
skipGetOptions?: boolean; skipGetOptions?: boolean;
} }
interface FoundTarget { export interface FoundTarget {
config?: TargetConfiguration; config?: TargetConfiguration;
target: string; target: string;
} }

View File

@ -37,6 +37,10 @@ describe('React:CypressComponentTestConfiguration', () => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
}); });
afterEach(() => {
jest.clearAllMocks();
});
it('should generate cypress config with vite', async () => { it('should generate cypress config with vite', async () => {
mockedAssertCypressVersion.mockReturnValue(); mockedAssertCypressVersion.mockReturnValue();
@ -395,7 +399,8 @@ describe('React:CypressComponentTestConfiguration', () => {
tree.exists('libs/some-lib/src/lib/another-cmp/another-cmp.spec.cy.js') tree.exists('libs/some-lib/src/lib/another-cmp/another-cmp.spec.cy.js')
).toBeFalsy(); ).toBeFalsy();
}); });
it('should throw error when an invalid --build-target is provided', async () => {
it('should not throw error when an invalid --build-target is provided', async () => {
mockedAssertCypressVersion.mockReturnValue(); mockedAssertCypressVersion.mockReturnValue();
await applicationGenerator(tree, { await applicationGenerator(tree, {
e2eTestRunner: 'none', e2eTestRunner: 'none',
@ -442,12 +447,10 @@ describe('React:CypressComponentTestConfiguration', () => {
generateTests: true, generateTests: true,
buildTarget: 'my-app:build', buildTarget: 'my-app:build',
}); });
}).rejects.toThrowErrorMatchingInlineSnapshot(` }).resolves;
"Error trying to find build configuration. Try manually specifying the build target with the --build-target flag. expect(
Provided project? some-lib require('@nx/devkit').createProjectGraphAsync
Provided build target? my-app:build ).not.toHaveBeenCalled();
Provided Executors? @nx/webpack:webpack, @nx/vite:build, @nrwl/webpack:webpack, @nrwl/vite:build"
`);
}); });
it('should setup cypress config files correctly', async () => { it('should setup cypress config files correctly', async () => {

View File

@ -6,7 +6,7 @@ import {
} from '@nx/devkit'; } from '@nx/devkit';
import { nxVersion } from '../../utils/versions'; import { nxVersion } from '../../utils/versions';
import { addFiles } from './lib/add-files'; import { addFiles } from './lib/add-files';
import { FoundTarget, addCTTargetWithBuildTarget } from '../../utils/ct-utils'; import { addCTTargetWithBuildTarget } from '../../utils/ct-utils';
import { CypressComponentConfigurationSchema } from './schema.d'; import { CypressComponentConfigurationSchema } from './schema.d';
/** /**
@ -27,7 +27,7 @@ export async function cypressComponentConfigGenerator(
skipFormat: true, skipFormat: true,
}); });
const found: FoundTarget = await addCTTargetWithBuildTarget(tree, { const found = await addCTTargetWithBuildTarget(tree, {
project: options.project, project: options.project,
buildTarget: options.buildTarget, buildTarget: options.buildTarget,
validExecutorNames: new Set<string>([ validExecutorNames: new Set<string>([

View File

@ -9,11 +9,8 @@ import {
import { nxVersion } from 'nx/src/utils/versions'; import { nxVersion } from 'nx/src/utils/versions';
import { componentTestGenerator } from '../../component-test/component-test'; import { componentTestGenerator } from '../../component-test/component-test';
import type { CypressComponentConfigurationSchema } from '../schema'; import type { CypressComponentConfigurationSchema } from '../schema';
import { import { getBundlerFromTarget, isComponent } from '../../../utils/ct-utils';
FoundTarget, import { FoundTarget } from '@nx/cypress/src/utils/find-target-options';
getBundlerFromTarget,
isComponent,
} from '../../../utils/ct-utils';
export async function addFiles( export async function addFiles(
tree: Tree, tree: Tree,
@ -26,7 +23,12 @@ export async function addFiles(
const { addMountDefinition, addDefaultCTConfig } = await import( const { addMountDefinition, addDefaultCTConfig } = await import(
'@nx/cypress/src/utils/config' '@nx/cypress/src/utils/config'
); );
const actualBundler = await getBundlerFromTarget(found, tree);
// Specifically undefined to allow Remix workaround of passing an empty string
const actualBundler =
options.buildTarget !== undefined && options.bundler
? options.bundler
: await getBundlerFromTarget(found, tree);
if (options.bundler && options.bundler !== actualBundler) { if (options.bundler && options.bundler !== actualBundler) {
logger.warn( logger.warn(

View File

@ -2,23 +2,18 @@ import {
createProjectGraphAsync, createProjectGraphAsync,
parseTargetString, parseTargetString,
readProjectConfiguration, readProjectConfiguration,
TargetConfiguration,
Tree, Tree,
updateProjectConfiguration, updateProjectConfiguration,
} from '@nx/devkit'; } from '@nx/devkit';
import { ensureTypescript } from '@nx/js/src/utils/typescript/ensure-typescript'; import { ensureTypescript } from '@nx/js/src/utils/typescript/ensure-typescript';
import { getComponentNode } from './ast-utils'; import { getComponentNode } from './ast-utils';
import { type FoundTarget } from '@nx/cypress/src/utils/find-target-options';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
const allowedFileExt = new RegExp(/\.[jt]sx?/); const allowedFileExt = new RegExp(/\.[jt]sx?/);
const isSpecFile = new RegExp(/(spec|test)\./); const isSpecFile = new RegExp(/(spec|test)\./);
export interface FoundTarget {
config?: TargetConfiguration;
target: string;
}
export async function addCTTargetWithBuildTarget( export async function addCTTargetWithBuildTarget(
tree: Tree, tree: Tree,
options: { options: {
@ -27,16 +22,21 @@ export async function addCTTargetWithBuildTarget(
validExecutorNames: Set<string>; validExecutorNames: Set<string>;
} }
): Promise<FoundTarget> { ): Promise<FoundTarget> {
let found: FoundTarget = { target: options.buildTarget, config: undefined };
// Specifically undefined as a workaround for Remix to pass an empty string as the buildTarget
if (options.buildTarget === undefined) {
const { findBuildConfig } = await import( const { findBuildConfig } = await import(
'@nx/cypress/src/utils/find-target-options' '@nx/cypress/src/utils/find-target-options'
); );
const found = await findBuildConfig(tree, { found = await findBuildConfig(tree, {
project: options.project, project: options.project,
buildTarget: options.buildTarget, buildTarget: options.buildTarget,
validExecutorNames: options.validExecutorNames, validExecutorNames: options.validExecutorNames,
}); });
assertValidConfig(found?.config); assertValidConfig(found?.config);
}
const projectConfig = readProjectConfiguration(tree, options.project); const projectConfig = readProjectConfiguration(tree, options.project);
projectConfig.targets['component-test'].options = { projectConfig.targets['component-test'].options = {