2023-02-22 18:47:40 -05:00

115 lines
3.1 KiB
TypeScript

import {
ensurePackage,
generateFiles,
joinPathFragments,
readProjectConfiguration,
Tree,
} from '@nrwl/devkit';
import { basename, dirname, extname, relative } from 'path';
import {
findExportDeclarationsForJsx,
getComponentNode,
} from '../../utils/ast-utils';
import { getDefaultsForComponent } from '../../utils/component-props';
import { nxVersion } from '../../utils/versions';
import { ComponentTestSchema } from './schema';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript');
export async function componentTestGenerator(
tree: Tree,
options: ComponentTestSchema
) {
ensurePackage('@nrwl/cypress', nxVersion);
const { assertMinimumCypressVersion } = await import(
'@nrwl/cypress/src/utils/cypress-version'
);
assertMinimumCypressVersion(10);
const projectConfig = readProjectConfiguration(tree, options.project);
const normalizedPath = options.componentPath.startsWith(
projectConfig.sourceRoot
)
? relative(projectConfig.sourceRoot, options.componentPath)
: options.componentPath;
const componentPath = joinPathFragments(
projectConfig.sourceRoot,
normalizedPath
);
if (tree.exists(componentPath)) {
generateSpecsForComponents(tree, componentPath);
}
}
function generateSpecsForComponents(tree: Tree, filePath: string) {
if (!tsModule) {
tsModule = ensureTypescript();
}
const sourceFile = tsModule.createSourceFile(
filePath,
tree.read(filePath, 'utf-8'),
tsModule.ScriptTarget.Latest,
true
);
const cmpNodes = findExportDeclarationsForJsx(sourceFile);
const componentDir = dirname(filePath);
const ext = extname(filePath);
const fileName = basename(filePath, ext);
if (tree.exists(joinPathFragments(componentDir, `${fileName}.cy${ext}`))) {
return;
}
const defaultExport = getComponentNode(sourceFile);
if (cmpNodes?.length) {
const components = cmpNodes.map((cmp) => {
const defaults = getDefaultsForComponent(sourceFile, cmp);
const isDefaultExport = defaultExport
? (defaultExport as any).name.text === (cmp as any).name.text
: false;
return {
isDefaultExport,
props: [...defaults.props, ...defaults.argTypes],
name: (cmp as any).name.text as string,
typeName: defaults.propsTypeName,
};
});
const namedImports = components
.reduce((imports, cmp) => {
if (cmp.typeName) {
imports.push(cmp.typeName);
}
if (cmp.isDefaultExport) {
return imports;
}
imports.push(cmp.name);
return imports;
}, [])
.join(', ');
const namedImportStatement =
namedImports.length > 0 ? `, { ${namedImports} }` : '';
generateFiles(tree, joinPathFragments(__dirname, 'files'), componentDir, {
fileName,
components,
importStatement: defaultExport
? `import ${
(defaultExport as any).name.text
}${namedImportStatement} from './${fileName}'`
: `import { ${namedImports} } from './${fileName}'`,
ext,
});
}
}
export default componentTestGenerator;