@cypress/schematic
Version:
Official Cypress schematic for the Angular CLI
285 lines • 13.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.removeE2ELinting = exports.addCypressTsConfig = exports.getCypressConfigFile = void 0;
const core_1 = require("@angular-devkit/core");
const schematics_1 = require("@angular-devkit/schematics");
const tasks_1 = require("@angular-devkit/schematics/tasks");
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const semver_1 = require("semver");
const dependencies_1 = require("../utils/dependencies");
const utils_1 = require("../utils");
const path_1 = require("path");
const jsonFile_1 = require("../utils/jsonFile");
function default_1(_options) {
return (tree, _context) => {
_options = Object.assign(Object.assign({}, _options), { __version__: (0, utils_1.getAngularSemverVersion)(tree) });
return (0, schematics_1.chain)([
updateDependencies(),
addCypressCoreFiles(_options),
addCypressComponentTestingFiles(_options),
addCtSpecs(_options),
addCypressTestScriptsToPackageJson(),
modifyAngularJson(_options),
addDefaultSchematic(),
])(tree, _context);
};
}
exports.default = default_1;
function addPropertyToPackageJson(tree, path, value) {
const json = new jsonFile_1.JSONFile(tree, '/package.json');
json.modify(path, value);
}
function updateDependencies() {
return (tree, context) => {
context.logger.debug('Updating dependencies...');
context.addTask(new tasks_1.NodePackageInstallTask({ allowScripts: true }));
const addDependencies = (0, rxjs_1.of)('cypress').pipe((0, operators_1.concatMap)((packageName) => (0, utils_1.getLatestNodeVersion)(packageName)), (0, operators_1.map)((packageFromRegistry) => {
const { name, version } = packageFromRegistry;
context.logger.debug(`Adding ${name}:${version} to ${dependencies_1.NodeDependencyType.Dev}`);
(0, dependencies_1.addPackageJsonDependency)(tree, {
type: dependencies_1.NodeDependencyType.Dev,
name,
version,
});
return tree;
}));
return addDependencies;
};
}
function addCypressTestScriptsToPackageJson() {
return (tree) => {
addPropertyToPackageJson(tree, ['scripts'], {
'e2e': 'ng e2e',
'cypress:open': 'cypress open',
'cypress:run': 'cypress run',
});
};
}
function handleFiles(tree, context, { projects, options, applyPath, movePath, relativeToWorkspacePath }) {
return (0, schematics_1.chain)(Object.keys(projects).map((name) => {
const project = projects[name];
const projectPath = (0, path_1.resolve)((0, core_1.getSystemPath)((0, core_1.normalize)(project.root)));
const workspacePath = (0, path_1.resolve)((0, core_1.getSystemPath)((0, core_1.normalize)('')));
const relativeToWorkspace = (0, path_1.relative)(`${projectPath}${relativeToWorkspacePath}`, workspacePath);
const baseUrl = getBaseUrl(project);
return (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)(applyPath), [
(0, schematics_1.move)(movePath ? `${project.root}${movePath}` : project.root),
(0, schematics_1.applyTemplates)(Object.assign(Object.assign(Object.assign({}, options), core_1.strings), { root: project.root ? `${project.root}/` : project.root, baseUrl,
relativeToWorkspace })),
]));
}))(tree, context);
}
function addCypressCoreFiles(options) {
return (tree, context) => {
context.logger.debug('Adding cypress files');
const angularJsonValue = (0, utils_1.getAngularJsonValue)(tree);
const { projects } = angularJsonValue;
return handleFiles(tree, context, {
projects,
options,
applyPath: './files-core',
relativeToWorkspacePath: `/`,
});
};
}
function addCypressComponentTestingFiles(options) {
return (tree, context) => {
if (options.component) {
context.logger.debug('Adding cypress component testing files');
const angularJsonValue = (0, utils_1.getAngularJsonValue)(tree);
const { projects } = angularJsonValue;
let applyPath = './files-ct';
try {
// if using Angular 21 or greater, we need to use the cypress/angular-zoneless mount function, which was introduced in Cypress 15.8.0
// and will likely be the default in the future in Cypress 16
applyPath = (0, semver_1.gte)(options.__version__, '21.0.0') ? './files-ct-zoneless' : './files-ct';
}
catch (error) {
context.logger.debug('Error checking Angular version', error);
}
return handleFiles(tree, context, {
projects,
options,
applyPath,
movePath: '/cypress/support',
relativeToWorkspacePath: `/cypress`,
});
}
};
}
function addCtSpecs(options) {
return (tree) => {
if (options.addCtSpecs) {
const angularJsonValue = (0, utils_1.getAngularJsonValue)(tree);
const { projects } = angularJsonValue;
Object.keys(projects).map((name) => {
const project = projects[name];
const appPath = `${project.root}/${project.sourceRoot}/${project.prefix}`;
return (0, utils_1.getDirectoriesAndCreateSpecs)({ tree, appPath });
});
}
};
}
function getBaseUrl(project) {
var _a, _b, _c, _d;
let options = { protocol: 'http', port: 4200, host: 'localhost' };
if ((_b = (_a = project.architect) === null || _a === void 0 ? void 0 : _a.serve) === null || _b === void 0 ? void 0 : _b.options) {
const projectOptions = (_d = (_c = project.architect) === null || _c === void 0 ? void 0 : _c.serve) === null || _d === void 0 ? void 0 : _d.options;
options = Object.assign(Object.assign({}, options), projectOptions);
options.protocol = projectOptions.ssl ? 'https' : 'http';
}
return `${options.protocol}://${options.host}:${options.port}`;
}
function addNewCypressCommands(tree, angularJsonVal, project, runJson, openJson, e2eJson, e2e, componentJson, component) {
const projectArchitectJson = angularJsonVal['projects'][project]['architect'];
projectArchitectJson['cypress-run'] = runJson;
projectArchitectJson['cypress-open'] = openJson;
if (component) {
projectArchitectJson['ct'] = componentJson;
}
if (e2e || !projectArchitectJson['e2e']) {
projectArchitectJson['e2e'] = e2eJson;
}
return tree.overwrite('./angular.json', JSON.stringify(angularJsonVal, null, 2));
}
function modifyAngularJson(options) {
return (tree, context) => {
if (tree.exists('./angular.json')) {
const angularJsonVal = (0, utils_1.getAngularJsonValue)(tree);
const { projects } = angularJsonVal;
if (!projects) {
throw new schematics_1.SchematicsException('projects in angular.json is not defined');
}
Object.keys(projects).forEach((project) => {
const builder = '@cypress/schematic:cypress';
const runJson = {
builder,
options: {
devServerTarget: `${project}:serve`,
},
configurations: {
production: {
devServerTarget: `${project}:serve:production`,
},
},
};
const openJson = {
builder,
options: {
watch: true,
headless: false,
},
};
const e2eJson = {
builder,
options: {
devServerTarget: `${project}:serve`,
watch: true,
headless: false,
},
configurations: {
production: {
devServerTarget: `${project}:serve:production`,
},
},
};
const componentJson = {
builder,
options: {
devServerTarget: `${project}:serve`,
watch: true,
headless: false,
testingType: 'component',
},
configurations: {
development: {
devServerTarget: `${project}:serve:development`,
},
},
};
const configFile = (0, exports.getCypressConfigFile)(angularJsonVal, project);
if (configFile) {
Object.assign(runJson.options, { configFile });
Object.assign(openJson.options, { configFile });
}
if (options.e2e) {
context.logger.debug(`Replacing e2e command with cypress-run in angular.json`);
(0, exports.removeE2ELinting)(tree, angularJsonVal, project);
}
context.logger.debug(`Adding cypress/tsconfig.json to angular.json-tslint config`);
(0, exports.addCypressTsConfig)(tree, angularJsonVal, project);
context.logger.debug(`Adding cypress-run and cypress-open commands in angular.json`);
addNewCypressCommands(tree, angularJsonVal, project, runJson, openJson, e2eJson, options.e2e, componentJson, options.component);
});
}
else {
throw new schematics_1.SchematicsException('angular.json not found');
}
return tree;
};
}
function addDefaultSchematic() {
return (tree, _) => {
var _a, _b;
if (tree.exists('./angular.json')) {
const angularJsonVal = (0, utils_1.getAngularJsonValue)(tree);
const angularSchematic = '@schematics/angular';
const cli = Object.assign(Object.assign({}, angularJsonVal.cli), { schematicCollections: ['@cypress/schematic', ...(_b = (_a = angularJsonVal === null || angularJsonVal === void 0 ? void 0 : angularJsonVal.cli) === null || _a === void 0 ? void 0 : _a.schematicCollections) !== null && _b !== void 0 ? _b : []] });
if (cli.schematicCollections.indexOf('@schematics/angular') === -1) {
cli.schematicCollections.push(angularSchematic);
}
return tree.overwrite('./angular.json', JSON.stringify(Object.assign(Object.assign({}, angularJsonVal), { cli }), null, 2));
}
throw new schematics_1.SchematicsException('angular.json not found');
};
}
const getCypressConfigFile = (angularJsonVal, projectName) => {
var _a, _b, _c;
const project = angularJsonVal.projects[projectName];
const tsConfig = (_c = (_b = (_a = project === null || project === void 0 ? void 0 : project.architect) === null || _a === void 0 ? void 0 : _a.lint) === null || _b === void 0 ? void 0 : _b.options) === null || _c === void 0 ? void 0 : _c.tsConfig;
if (project.root) {
return `${project.root}/cypress.config.${tsConfig ? 'ts' : 'js'}`;
}
return null;
};
exports.getCypressConfigFile = getCypressConfigFile;
const addCypressTsConfig = (tree, angularJsonVal, projectName) => {
var _a, _b, _c;
const project = angularJsonVal.projects[projectName];
let tsConfig = (_c = (_b = (_a = project === null || project === void 0 ? void 0 : project.architect) === null || _a === void 0 ? void 0 : _a.lint) === null || _b === void 0 ? void 0 : _b.options) === null || _c === void 0 ? void 0 : _c.tsConfig;
if (tsConfig) {
let prefix = '';
if (project.root) {
prefix = `${project.root}/`;
}
if (!Array.isArray(tsConfig)) {
project.architect.lint.options.tsConfig = tsConfig = [tsConfig];
}
tsConfig.push(`${prefix}cypress/tsconfig.json`);
}
return tree.overwrite('./angular.json', JSON.stringify(angularJsonVal, null, 2));
};
exports.addCypressTsConfig = addCypressTsConfig;
const removeE2ELinting = (tree, angularJsonVal, project) => {
var _a, _b, _c, _d, _e;
const projectLintOptionsJson = (_c = (_b = (_a = angularJsonVal.projects[project]) === null || _a === void 0 ? void 0 : _a.architect) === null || _b === void 0 ? void 0 : _b.lint) === null || _c === void 0 ? void 0 : _c.options;
if (projectLintOptionsJson) {
let filteredTsConfigPaths;
if (Array.isArray(projectLintOptionsJson['tsConfig'])) {
filteredTsConfigPaths = (_d = projectLintOptionsJson === null || projectLintOptionsJson === void 0 ? void 0 : projectLintOptionsJson.tsConfig) === null || _d === void 0 ? void 0 : _d.filter((path) => {
const pathIncludesE2e = path.includes('e2e');
return !pathIncludesE2e && path;
});
}
else {
filteredTsConfigPaths = !((_e = projectLintOptionsJson === null || projectLintOptionsJson === void 0 ? void 0 : projectLintOptionsJson.tsConfig) === null || _e === void 0 ? void 0 : _e.includes('e2e'))
? projectLintOptionsJson === null || projectLintOptionsJson === void 0 ? void 0 : projectLintOptionsJson.tsConfig
: '';
}
projectLintOptionsJson['tsConfig'] = filteredTsConfigPaths;
}
return tree.overwrite('./angular.json', JSON.stringify(angularJsonVal, null, 2));
};
exports.removeE2ELinting = removeE2ELinting;
//# sourceMappingURL=index.js.map