@nxextensions/firebase-cypress
Version:
An NX Plugin for Firebase Applications that would like to use emulators for E2E testing with Cypress
310 lines • 13.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createNodesV2 = exports.NX_PLUGIN_OPTIONS = void 0;
const devkit_1 = require("@nx/devkit");
const fs_1 = require("fs");
const devkit_internals_1 = require("nx/src/devkit-internals");
const path_1 = require("path");
const cache_directory_1 = require("nx/src/utils/cache-directory");
const calculate_hash_for_create_nodes_1 = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes");
const js_1 = require("@nx/js");
const config_utils_1 = require("@nx/devkit/src/utils/config-utils");
const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs");
const workspace_context_1 = require("nx/src/utils/workspace-context");
exports.NX_PLUGIN_OPTIONS = '__NX_PLUGIN_OPTIONS__';
function readTargetsCache(cachePath) {
return (0, fs_1.existsSync)(cachePath) ? (0, devkit_1.readJsonFile)(cachePath) : {};
}
function writeTargetsToCache(cachePath, targets) {
(0, devkit_1.writeJsonFile)(cachePath, targets);
}
const cypressConfigGlob = '**/cypress.config.{js,ts,mjs,cjs}';
const pmc = (0, devkit_1.getPackageManagerCommand)();
exports.createNodesV2 = [
cypressConfigGlob,
async (configFiles, options, context) => {
const optionsHash = (0, devkit_internals_1.hashObject)(options);
const cachePath = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `cypress-${optionsHash}.hash`);
const targetsCache = readTargetsCache(cachePath);
try {
return await (0, devkit_1.createNodesFromFiles)((configFile, options, context) => createNodesInternal(configFile, options, context, targetsCache), configFiles, options, context);
}
finally {
writeTargetsToCache(cachePath, targetsCache);
}
}
];
async function createNodesInternal(configFile, options, context, targetsCache) {
var _a;
options = normalizeOptions(options);
const projectRoot = (0, path_1.dirname)(configFile);
const siblingFiles = (0, fs_1.readdirSync)((0, path_1.join)(context.workspaceRoot, projectRoot));
if (!siblingFiles.includes('package.json') &&
!siblingFiles.includes('project.json')) {
return {};
}
const hash = await (0, calculate_hash_for_create_nodes_1.calculateHashForCreateNodes)(projectRoot, options, context, [(0, js_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot))]);
(_a = targetsCache[hash]) !== null && _a !== void 0 ? _a : (targetsCache[hash] = await buildCypressTargets(configFile, projectRoot, options, context));
const { targets, metadata } = targetsCache[hash];
const project = {
projectType: 'application',
targets,
metadata
};
return {
projects: {
[projectRoot]: project
}
};
}
async function buildCypressTargets(configFile, projectRoot, options, context) {
var _a, _b, _c, _d;
var _e, _f;
const cypressConfig = await (0, config_utils_1.loadConfigFile)((0, path_1.join)(context.workspaceRoot, configFile));
const pluginPresetOptions = {
...(_a = cypressConfig.e2e) === null || _a === void 0 ? void 0 : _a[exports.NX_PLUGIN_OPTIONS],
...cypressConfig.env,
...(_b = cypressConfig.e2e) === null || _b === void 0 ? void 0 : _b.env
};
const webServerCommands = pluginPresetOptions.webServerCommands;
const namedInputs = (0, get_named_inputs_1.getNamedInputs)(projectRoot, context);
const targets = {};
let metadata;
if ('e2e' in cypressConfig) {
const opts = buildCypressOptions(configFile, cypressConfig, projectRoot, 'e2e', false);
targets[options.targetName] = {
executor: '@nxextensions/firebase-cypress:run',
options: opts,
cache: true,
inputs: getInputs(namedInputs),
outputs: getOutputs(projectRoot, cypressConfig, 'e2e'),
parallelism: false,
metadata: {
technologies: ['cypress'],
description: 'Runs Cypress Tests',
help: {
command: `${pmc.exec} cypress run --help`,
example: {
args: ['--dev', '--headed']
}
}
}
};
if (Object.keys(webServerCommands !== null && webServerCommands !== void 0 ? webServerCommands : {}).length > 0) {
(_c = (_e = targets[options.targetName]).configurations) !== null && _c !== void 0 ? _c : (_e.configurations = {});
for (const [configuration, webServerCommand] of Object.entries(webServerCommands !== null && webServerCommands !== void 0 ? webServerCommands : {})) {
if (configuration !== 'default') {
targets[options.targetName].configurations[configuration] = {
env: {
webServerCommand
}
};
}
}
}
const ciWebServerCommand = pluginPresetOptions === null || pluginPresetOptions === void 0 ? void 0 : pluginPresetOptions.ciWebServerCommand;
if (ciWebServerCommand) {
const specPatterns = Array.isArray(cypressConfig.e2e.specPattern)
? cypressConfig.e2e.specPattern.map((p) => (0, path_1.join)(projectRoot, p))
: [(0, path_1.join)(projectRoot, cypressConfig.e2e.specPattern)];
const excludeSpecPatterns = !cypressConfig.e2e
.excludeSpecPattern
? cypressConfig.e2e.excludeSpecPattern
: Array.isArray(cypressConfig.e2e.excludeSpecPattern)
? cypressConfig.e2e.excludeSpecPattern.map((p) => (0, path_1.join)(projectRoot, p))
: [(0, path_1.join)(projectRoot, cypressConfig.e2e.excludeSpecPattern)];
const specFiles = await (0, workspace_context_1.globWithWorkspaceContext)(context.workspaceRoot, specPatterns, excludeSpecPatterns);
const dependsOn = [];
const outputs = getOutputs(projectRoot, cypressConfig, 'e2e');
const inputs = getInputs(namedInputs);
const groupName = 'E2E (CI)';
metadata = { targetGroups: { [groupName]: [] } };
const ciTargetGroup = metadata.targetGroups[groupName];
for (const file of specFiles) {
const relativeSpecPath = (0, devkit_1.normalizePath)((0, path_1.relative)(projectRoot, file));
const targetName = `${options.ciTargetName}--${relativeSpecPath}`;
const opt = buildCypressOptions(configFile, cypressConfig, projectRoot, 'e2e', true);
ciTargetGroup.push(targetName);
targets[targetName] = {
outputs,
inputs,
cache: true,
executor: '@nxextensions/firebase-cypress:run-ci',
options: {
...opt,
cwd: projectRoot,
env: {
webServerCommand: ciWebServerCommand,
spec: relativeSpecPath
}
},
parallelism: false,
metadata: {
technologies: ['cypress'],
description: `Runs Cypress Tests in ${relativeSpecPath} in CI`,
help: {
command: `${pmc.exec} cypress run --help`,
example: {
args: ['--dev', '--headed']
}
}
}
};
dependsOn.push({
target: targetName,
projects: 'self',
params: 'forward'
});
}
const opt = buildCypressOptions(configFile, cypressConfig, projectRoot, 'e2e', true);
targets[options.ciTargetName] = {
executor: 'nx:noop',
cache: true,
inputs,
outputs,
dependsOn,
options: opt,
parallelism: false,
metadata: {
technologies: ['cypress'],
description: 'Runs Cypress Tests in CI',
nonAtomizedTarget: options.targetName,
help: {
command: `${pmc.exec} cypress run --help`,
example: {
args: ['--dev', '--headed']
}
}
}
};
ciTargetGroup.push(options.ciTargetName);
}
}
if ('component' in cypressConfig) {
(_d = targets[_f = options.componentTestingTargetName]) !== null && _d !== void 0 ? _d : (targets[_f] = {
executor: '@nxextensions/firebase-cypress:run-component',
options: {
cwd: projectRoot
},
cache: true,
inputs: getInputs(namedInputs),
outputs: getOutputs(projectRoot, cypressConfig, 'component'),
metadata: {
technologies: ['cypress'],
description: 'Runs Cypress Component Tests',
help: {
command: `${pmc.exec} cypress run --help`,
example: {
args: ['--dev', '--headed']
}
}
}
});
}
targets[options.openTargetName] = {
executor: '@nxextensions/firebase-cypress:open',
options: {
...buildCypressOptions(configFile, cypressConfig, projectRoot, undefined, false),
cwd: projectRoot
},
metadata: {
technologies: ['cypress'],
description: 'Opens Cypress',
help: {
command: `${pmc.exec} cypress open --help`,
example: {
args: ['--dev', '--e2e']
}
}
}
};
return { targets, metadata };
}
function normalizeOptions(options) {
var _a, _b, _c, _d;
options !== null && options !== void 0 ? options : (options = {});
(_a = options.ciTargetName) !== null && _a !== void 0 ? _a : (options.ciTargetName = 'e2e-ci');
(_b = options.componentTestingTargetName) !== null && _b !== void 0 ? _b : (options.componentTestingTargetName = 'component');
(_c = options.openTargetName) !== null && _c !== void 0 ? _c : (options.openTargetName = 'open-cypress');
(_d = options.targetName) !== null && _d !== void 0 ? _d : (options.targetName = 'e2e');
return options;
}
function getInputs(namedInputs) {
return [
...('production' in namedInputs
? ['default', '^production']
: ['default', '^default']),
{
externalDependencies: ['cypress']
}
];
}
function getOutputs(projectRoot,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
cypressConfig, testingType) {
function getOutput(path) {
if (path.startsWith('..')) {
return (0, devkit_1.joinPathFragments)('{workspaceRoot}', projectRoot, path, path);
}
else {
return (0, devkit_1.joinPathFragments)('{projectRoot}', path);
}
}
const { screenshotsFolder, videosFolder, e2e, component } = cypressConfig;
const outputs = [];
if (videosFolder) {
outputs.push(getOutput(videosFolder));
}
if (screenshotsFolder) {
outputs.push(getOutput(screenshotsFolder));
}
switch (testingType) {
case 'e2e':
if (e2e.videosFolder) {
outputs.push(getOutput(e2e.videosFolder));
}
if (e2e.screenshotsFolder) {
outputs.push(getOutput(e2e.screenshotsFolder));
}
break;
case 'component':
if (component.videosFolder) {
outputs.push(getOutput(component.videosFolder));
}
if (component.screenshotsFolder) {
outputs.push(getOutput(component.screenshotsFolder));
}
break;
}
return outputs;
}
function buildCypressOptions(configFilePath,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
cypressConfig, _projectRoot, testingType, isCi) {
const config = testingType && testingType in cypressConfig ? cypressConfig[testingType] : {};
if (config === null || config === void 0 ? void 0 : config.baseUrl) {
return {
devServerTarget: isCi
? config[exports.NX_PLUGIN_OPTIONS].ciWebServerCommand
: config[exports.NX_PLUGIN_OPTIONS].webServerCommands.default,
baseUrl: config.baseUrl,
cypressConfig: configFilePath,
testingType,
emulatorCommand: config[exports.NX_PLUGIN_OPTIONS].emulatorCommand
};
}
return {
devServerTarget: isCi
? cypressConfig["e2e"][exports.NX_PLUGIN_OPTIONS].ciWebServerCommand
: 'default' in cypressConfig["e2e"][exports.NX_PLUGIN_OPTIONS].webServerCommands
? cypressConfig["e2e"][exports.NX_PLUGIN_OPTIONS].webServerCommands.default
: cypressConfig["e2e"][exports.NX_PLUGIN_OPTIONS].webServerCommands[Object.keys(cypressConfig["e2e"][exports.NX_PLUGIN_OPTIONS].webServerCommands)[0]],
cypressConfig: configFilePath,
testingType,
baseUrl: 'e2e' in cypressConfig ? cypressConfig['e2e'].baseUrl : undefined,
emulatorCommand: 'e2e' in cypressConfig
? cypressConfig['e2e'][exports.NX_PLUGIN_OPTIONS].emulatorCommand
: cypressConfig['component'][exports.NX_PLUGIN_OPTIONS].emulatorCommand
};
}
//# sourceMappingURL=index.js.map