nx/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts
Caleb Ukle 8154191eb1
feat(testing): Cypress 10 and component testing support (#9201)
* feat(testing): add generator to aid in the migration to cypress 10

cypress 10 introduces a new configuration format and new layout that requires update settings and
files for e2e projects

* feat(testing): cypress component tests for react/next

initial work for cypress component tests for react and next

* feat(testing): add support for v10 e2e cypress projects

create the correct files for cypress projects >v10 and reorganize tests based on version to allow
easier parsing of tests

* feat(testing): add utils for modifying cypress v10 config

provide ts transformers to take in an existing cypress config and update/add properties within the
given configuration

* fix(testing): fix tests affected by the cypress v10 changes

update tests to assert the correct files/folders/file contents due to the cypress changes in v10

* cleanup(testing): move cypress component testing plugins into the respective packages

move the plugins into out of cypress plugins into the specific vertical plugin to prevent issues
with circular refs

* cleanup(testing): bump cypress version

bump to latest cypress v10 release

* docs(testing): update docs for cypress 10

update cypress docs to include info about component testing and migration to cypress v10

* fix(repo): revert cypress version bump

keep v9 of cypress installed for nx repo until v10 release

* fix(testing): update cypress gen tsconfig and infer targets with converter

* fix(testing): make sure tests use the cypress v10 (for the intermediate)

* fix(testing): update target name after feedback

* fix(testing): support multiple target w/custom configs for cypress v10 migration

* fix(testing): refactor cy component tests into seperate verticals

* feat(testing): create storybook cypress preset

* fix(testing): clean up cy v10 migration

* fix(testing): don't branch for cypress executor testingType

* fix(testing): move cy comp test generator to next

* fix(testing): bump cypress deps

* fix(testing): clean up cy component testing generators

* fix(testing): update cy component testing docs

* fix(testign): dep check. runtime plugin pulls from @nrwl/react

* fix(testing): move e2e into verticals

* fix(testing): address PR feedback

* fix(testing): clean up unit tests

* feat(angular): support migrating angular cli workspaces using cypress v10

* chore(testing): update e2e tests

* fix(testing): address pr feedback

* chore(testing): remove cypress component testing for next.js

* fix(testing): address pr feedback

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2022-07-08 14:34:00 -05:00

153 lines
3.7 KiB
TypeScript

import { cypressComponentProject } from '@nrwl/cypress';
import {
formatFiles,
generateFiles,
joinPathFragments,
ProjectConfiguration,
readProjectConfiguration,
Tree,
updateJson,
visitNotIgnoredFiles,
} from '@nrwl/devkit';
import * as ts from 'typescript';
import { getComponentNode } from '../../utils/ast-utils';
import componentTestGenerator from '../component-test/component-test';
import { CypressComponentConfigurationSchema } from './schema';
const allowedFileExt = new RegExp(/\.[jt]sx?/g);
const isSpecFile = new RegExp(/(spec|test)\./g);
/**
* This is for using cypresses own Component testing, if you want to use test
* storybook components then use componentCypressGenerator instead.
*
*/
export async function cypressComponentConfigGenerator(
tree: Tree,
options: CypressComponentConfigurationSchema
) {
const projectConfig = readProjectConfiguration(tree, options.project);
const installTask = await cypressComponentProject(tree, {
project: options.project,
skipFormat: true,
});
addFiles(tree, projectConfig, options);
updateTsConfig(tree, projectConfig);
if (options.skipFormat) {
await formatFiles(tree);
}
return () => {
installTask();
};
}
function addFiles(
tree: Tree,
projectConfig: ProjectConfiguration,
options: CypressComponentConfigurationSchema
) {
const cypressConfigPath = joinPathFragments(
projectConfig.root,
'cypress.config.ts'
);
if (tree.exists(cypressConfigPath)) {
tree.delete(cypressConfigPath);
}
generateFiles(
tree,
joinPathFragments(__dirname, 'files'),
projectConfig.root,
{
tpl: '',
}
);
if (options.generateTests) {
visitNotIgnoredFiles(tree, projectConfig.sourceRoot, (filePath) => {
if (isComponent(tree, filePath)) {
componentTestGenerator(tree, {
project: options.project,
componentPath: filePath,
});
}
});
}
}
function updateTsConfig(tree: Tree, projectConfig: ProjectConfiguration) {
const tsConfigPath = joinPathFragments(
projectConfig.root,
projectConfig.projectType === 'library'
? 'tsconfig.lib.json'
: 'tsconfig.app.json'
);
if (tree.exists(tsConfigPath)) {
updateJson(tree, tsConfigPath, (json) => {
const excluded = new Set([
...(json.exclude || []),
'cypress/**/*',
'cypress.config.ts',
'**/*.cy.ts',
'**/*.cy.js',
'**/*.cy.tsx',
'**/*.cy.jsx',
]);
json.exclude = Array.from(excluded);
return json;
});
}
const projectBaseTsConfig = joinPathFragments(
projectConfig.root,
'tsconfig.json'
);
if (tree.exists(projectBaseTsConfig)) {
updateJson(tree, projectBaseTsConfig, (json) => {
if (json.references) {
const hasCyTsConfig = json.references.some(
(r) => r.path === './tsconfig.cy.json'
);
if (!hasCyTsConfig) {
json.references.push({ path: './tsconfig.cy.json' });
}
} else {
const excluded = new Set([
...(json.exclude || []),
'cypress/**/*',
'cypress.config.ts',
'**/*.cy.ts',
'**/*.cy.js',
'**/*.cy.tsx',
'**/*.cy.jsx',
]);
json.exclude = Array.from(excluded);
}
return json;
});
}
}
function isComponent(tree: Tree, filePath: string): boolean {
if (isSpecFile.test(filePath) || !allowedFileExt.test(filePath)) {
return false;
}
const content = tree.read(filePath, 'utf-8');
const sourceFile = ts.createSourceFile(
filePath,
content,
ts.ScriptTarget.Latest,
true
);
const cmpDeclaration = getComponentNode(sourceFile);
return !!cmpDeclaration;
}
export default cypressComponentConfigGenerator;