Skip to content

Commit

Permalink
fix(testing): improve error message for ct generators (#18597)
Browse files Browse the repository at this point in the history
  • Loading branch information
barbados-clemens authored Aug 23, 2023
1 parent bbae14b commit f5d55e3
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
}
},
"required": ["project"],
"examplesFile": "{% callout type=\"caution\" title=\"Can I use component testing?\" %}\nAngular component testing with Nx requires **Cypress version 10.7.0** and up.\n\nYou can migrate with to v10 via the [migrate-to-cypress-10 generator](/packages/cypress/generators/migrate-to-cypress-10).\n\nThis generator is for Cypress based component testing.\n\nIf you want to test components via Storybook with Cypress, then check out the [storybook-configuration generator docs](/packages/angular/generators/storybook-configuration)\n{% /callout %}\n\nThis generator is designed to get your Angular project up and running with Cypress Component Testing.\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project\n```\n\nRunning this generator, adds the required files to the specified project with a preconfigured `cypress.config.ts` designed for Nx workspaces.\n\n```ts {% fileName=\"cypress.config.ts\" %}\nimport { defineConfig } from 'cypress';\nimport { nxComponentTestingPreset } from '@nx/angular/plugins/component-testing';\n\nexport default defineConfig({\n component: nxComponentTestingPreset(__filename),\n});\n```\n\nHere is an example on how to add custom options to the configuration\n\n```ts {% fileName=\"cypress.config.ts\" %}\nimport { defineConfig } from 'cypress';\nimport { nxComponentTestingPreset } from '@nx/angular/plugins/component-testing';\n\nexport default defineConfig({\n component: {\n ...nxComponentTestingPreset(__filename),\n // extra options here\n },\n});\n```\n\n## Specifying a Build Target\n\nComponent testing requires a _build target_ to correctly run the component test dev server. This option can be manually specified with `--build-target=some-angular-app:build`, but Nx will infer this usage from the [project graph](/concepts/mental-model#the-project-graph) if one isn't provided.\n\nFor Angular projects, the build target needs to be using the `@nx/angular:webpack-browser` or\n`@angular-devkit/build-angular:browser` executor.\nThe generator will throw an error if a build target can't be found and suggest passing one in manually.\n\nLetting Nx infer the build target by default\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project\n```\n\nManually specifying the build target\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project --build-target:some-angular-app:build --generate-tests\n```\n\n{% callout type=\"note\" title=\"Build Target with Configuration\" %}\nIf you're wanting to use a build target with a specific configuration. i.e. `my-app:build:production`,\nthen manually providing `--build-target=my-app:build:production` is the best way to do that.\n{% /callout %}\n\n## Auto Generating Tests\n\nYou can optionally use the `--generate-tests` flag to generate a test file for each component in your project.\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project --generate-tests\n```\n\n## Running Component Tests\n\nA new `component-test` target will be added to the specified project to run your component tests.\n\n```shell\nnx g component-test my-cool-angular-project\n```\n\nHere is an example of the project configuration that is generated. The `--build-target` option is added as the `devServerTarget` which can be changed as needed.\n\n```json {% fileName=\"project.json\" %}\n{\n \"targets\" {\n \"component-test\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"<path-to-project-root>/cypress.config.ts\",\n \"testingType\": \"component\",\n \"devServerTarget\": \"some-angular-app:build\",\n \"skipServe\": true\n }\n }\n }\n}\n```\n\nNx also supports [React component testing](/packages/angular/generators/cypress-component-configuration).\n",
"examplesFile": "{% callout type=\"caution\" title=\"Can I use component testing?\" %}\nAngular component testing with Nx requires **Cypress version 10.7.0** and up.\n\nYou can migrate with to v10 via the [migrate-to-cypress-10 generator](/packages/cypress/generators/migrate-to-cypress-10).\n\nThis generator is for Cypress based component testing.\n\nIf you want to test components via Storybook with Cypress, then check out the [storybook-configuration generator docs](/packages/angular/generators/storybook-configuration)\n{% /callout %}\n\nThis generator is designed to get your Angular project up and running with Cypress Component Testing.\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project\n```\n\nRunning this generator, adds the required files to the specified project with a preconfigured `cypress.config.ts` designed for Nx workspaces.\n\n```ts {% fileName=\"cypress.config.ts\" %}\nimport { defineConfig } from 'cypress';\nimport { nxComponentTestingPreset } from '@nx/angular/plugins/component-testing';\n\nexport default defineConfig({\n component: nxComponentTestingPreset(__filename),\n});\n```\n\nHere is an example on how to add custom options to the configuration\n\n```ts {% fileName=\"cypress.config.ts\" %}\nimport { defineConfig } from 'cypress';\nimport { nxComponentTestingPreset } from '@nx/angular/plugins/component-testing';\n\nexport default defineConfig({\n component: {\n ...nxComponentTestingPreset(__filename),\n // extra options here\n },\n});\n```\n\n## Specifying a Build Target\n\nComponent testing requires a _build target_ to correctly run the component test dev server. This option can be manually specified with `--build-target=some-angular-app:build`, but Nx will infer this usage from the [project graph](/concepts/mental-model#the-project-graph) if one isn't provided.\n\nFor Angular projects, the build target needs to be using the `@nx/angular:webpack-browser` or\n`@angular-devkit/build-angular:browser` executor.\nThe generator will throw an error if a build target can't be found and suggest passing one in manually.\n\nLetting Nx infer the build target by default\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project\n```\n\nManually specifying the build target\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project --build-target:some-angular-app:build --generate-tests\n```\n\n{% callout type=\"note\" title=\"Build Target with Configuration\" %}\nIf you're wanting to use a build target with a specific configuration. i.e. `my-app:build:production`,\nthen manually providing `--build-target=my-app:build:production` is the best way to do that.\n{% /callout %}\n\n## Auto Generating Tests\n\nYou can optionally use the `--generate-tests` flag to generate a test file for each component in your project.\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project --generate-tests\n```\n\n## Running Component Tests\n\nA new `component-test` target will be added to the specified project to run your component tests.\n\n```shell\nnx g component-test my-cool-angular-project\n```\n\nHere is an example of the project configuration that is generated. The `--build-target` option is added as the `devServerTarget` which can be changed as needed.\n\n```json {% fileName=\"project.json\" %}\n{\n \"targets\" {\n \"component-test\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"<path-to-project-root>/cypress.config.ts\",\n \"testingType\": \"component\",\n \"devServerTarget\": \"some-angular-app:build\",\n \"skipServe\": true\n }\n }\n }\n}\n```\n\n## What is bundled\n\nWhen the project being tested is a dependent of the specified `--build-target`, then **assets, scripts, and styles** are applied to the component being tested. You can determine if the project is dependent by using the [project graph](/core-features/explore-graph). If there is no link between the two projects, then the **assets, scripts, and styles** won't be included in the build; therefore, they will not be applied to the component. To have a link between projects, you can import from the project being tested into the specified `--build-target` project, or set the `--build-target` project to [implicitly depend](/reference/project-configuration#implicitdependencies) on the project being tested.\n\nNx also supports [React component testing](/packages/angular/generators/cypress-component-configuration).\n",
"presets": []
},
"description": "Setup Cypress component testing for a project.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@ directly to a project, like [Jest](/packages/jest)

## Add Component Testing to a Project

> Currently only [@nx/react](/packages/react/generators/cypress-component-configuration) and [@nx/angular](/packages/angular/generators/cypress-component-configuration) plugins support component testing
> Currently only [@nx/react](/packages/react/generators/cypress-component-configuration), [@nx/angular](/packages/angular/generators/cypress-component-configuration), and [@nx/next](/packages/next/generators/cypress-component-configuration) plugins support component testing
Use the `cypress-component-configuration` generator from the respective plugin to add component testing to a project.

```shell
nx g @nx/react:cypress-component-configuration --project=your-project

nx g @nx/angular:cypress-component-configuration --project=your-project

nx g @nx/next:cypress-component-configuration --project=your-project
```

You can optionally pass in `--generate-tests` to create component tests for all components within the library.

Component testing supports both applications and libraries. By default, the generator attempts to find the build target for you based on the project's dependent apps. But you can manually specify the build target to use via the `--build-target` option. Note, in most cases, the build target will be from a different project than the one being configured. The only case where the build targets are from the same project is when the component tests are being added to an application.

> Note: The [@nx/next:cypress-component-configuration generator](/packages/next/generators/cypress-component-configuration) doesn't require a build target
```shell
nx g @nx/react:cypress-component-configuration --project=your-project --build-target=my-react-app:build

Expand Down
6 changes: 5 additions & 1 deletion docs/shared/packages/cypress/cypress-component-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@ directly to a project, like [Jest](/packages/jest)

## Add Component Testing to a Project

> Currently only [@nx/react](/packages/react/generators/cypress-component-configuration) and [@nx/angular](/packages/angular/generators/cypress-component-configuration) plugins support component testing
> Currently only [@nx/react](/packages/react/generators/cypress-component-configuration), [@nx/angular](/packages/angular/generators/cypress-component-configuration), and [@nx/next](/packages/next/generators/cypress-component-configuration) plugins support component testing
Use the `cypress-component-configuration` generator from the respective plugin to add component testing to a project.

```shell
nx g @nx/react:cypress-component-configuration --project=your-project

nx g @nx/angular:cypress-component-configuration --project=your-project

nx g @nx/next:cypress-component-configuration --project=your-project
```

You can optionally pass in `--generate-tests` to create component tests for all components within the library.

Component testing supports both applications and libraries. By default, the generator attempts to find the build target for you based on the project's dependent apps. But you can manually specify the build target to use via the `--build-target` option. Note, in most cases, the build target will be from a different project than the one being configured. The only case where the build targets are from the same project is when the component tests are being added to an application.

> Note: The [@nx/next:cypress-component-configuration generator](/packages/next/generators/cypress-component-configuration) doesn't require a build target
```shell
nx g @nx/react:cypress-component-configuration --project=your-project --build-target=my-react-app:build

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,8 @@ Here is an example of the project configuration that is generated. The `--build-
}
```

## What is bundled

When the project being tested is a dependent of the specified `--build-target`, then **assets, scripts, and styles** are applied to the component being tested. You can determine if the project is dependent by using the [project graph](/core-features/explore-graph). If there is no link between the two projects, then the **assets, scripts, and styles** won't be included in the build; therefore, they will not be applied to the component. To have a link between projects, you can import from the project being tested into the specified `--build-target` project, or set the `--build-target` project to [implicitly depend](/reference/project-configuration#implicitdependencies) on the project being tested.

Nx also supports [React component testing](/packages/angular/generators/cypress-component-configuration).
45 changes: 42 additions & 3 deletions packages/cypress/src/utils/find-target-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ export async function findBuildConfig(
return await findInGraph(tree, graph, options);
} catch (e) {
logger.error(e);
throw new Error(stripIndents`Error trying to find build configuration. Try manually specifying the build target with the --build-target flag.
throw new Error(stripIndents`Error trying to find build configuration. ${
options.buildTarget
? 'Try using an app of the same framework for the --build-target.'
: 'Try manually specifying the build target with the --build-target flag.'
}
Provided project? ${options.project}
Provided build target? ${options.buildTarget}
Provided Executors? ${[...options.validExecutorNames].join(', ')}`);
Expand All @@ -86,13 +90,15 @@ ${Array.from(options.validExecutorNames)
.map((ve) => ` - ${ve}`)
.join('\n')}
This is most likely because the provided --build-target is not a build target for an application.
${frameworkHelperMessage(Array.from(options.buildTarget), executorName)}
This is most likely because the provided --build-target is not a build target for an application or framework.
For example, the provide build target, '${options.buildTarget}' is:
- the build target for a buildable/publishable library instead of an app.
- using a different framework than expected like react library using an angular app build target.
- using a different framework than expected like react library using an angular or next app build target.
If you do not have an app in the workspace to you can make a new app with 'nx g app' and use it just for component testing
`);

throw new Error(
'The provided --build-target does not use an executor in the allow list of executors defined.'
);
Expand All @@ -112,6 +118,39 @@ If you do not have an app in the workspace to you can make a new app with 'nx g
);
}

function frameworkHelperMessage(
validExecutorNames: string[],
executorName: string
): string {
const executorsToFramework = {
'@nx/webpack:webpack': 'react',
'@nx/vite:build': 'react',
'@nrwl/webpack:webpack': 'react',
'@nrwl/vite:build': 'react',
'@nx/angular:webpack-browser': 'angular',
'@nrwl/angular:webpack-browser': 'angular',
'@angular-devkit/build-angular:browser': 'angular',
'@nx/next:build': 'next',
'@nrwl/next:build': 'next',
};
const buildTargetFramework = executorsToFramework[executorName];
const invokedGeneratorFramework = validExecutorNames.find(
(e) => !!executorsToFramework[e]
);

if (
buildTargetFramework &&
invokedGeneratorFramework &&
buildTargetFramework !== invokedGeneratorFramework
) {
return `It looks like you're using a different plugin generator than the --build-target framework is set up for.
The provided build target is configured for ${buildTargetFramework} instead of ${invokedGeneratorFramework}.
Try using @nx/${buildTargetFramework} instead.`;
}

return '';
}

async function findInGraph(
tree: Tree,
graph: ProjectGraph,
Expand Down

1 comment on commit f5d55e3

@vercel
Copy link

@vercel vercel bot commented on f5d55e3 Aug 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx.dev
nx-dev-nrwl.vercel.app
nx-dev-git-master-nrwl.vercel.app
nx-five.vercel.app

Please sign in to comment.