cumulocity-cypress
Version:
Cypress commands for Cumulocity IoT
282 lines (275 loc) • 9.52 kB
JavaScript
#!/usr/bin/env node
'use strict';
var cypress = require('cypress');
var path = require('path');
var fs = require('fs');
var _ = require('lodash');
var yargs = require('yargs/yargs');
var helpers = require('yargs/helpers');
var dotenv = require('dotenv');
var c8yscrn_helper = require('./helper.js');
var debug = require('debug');
var util = require('../util-CJ8J1x_Y.js');
require('yaml');
require('../ajv-qt7Q2OLe.js');
require('semver');
require('ajv');
require('ajv-formats');
require('ajv/lib/refs/json-schema-draft-06.json');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
const log = debug("c8y:scrn:startup");
const logEnv = debug("c8y:scrn:env");
(async () => {
try {
const args = getConfigFromArgs();
if (!args.config) {
throw new Error("No config file provided. Use --config option to provide the config file.");
}
const resolvedCypressConfig = c8yscrn_helper.resolveConfigOptions(args);
let baseUrl = c8yscrn_helper.resolveBaseUrl(args);
const yamlFile = path__namespace.resolve(process.cwd(), args.config);
if (args.init === true) {
if (!fs__namespace.existsSync(yamlFile)) {
fs__namespace.writeFileSync(yamlFile, c8yscrn_helper.createInitConfig(baseUrl ?? "http://localhost:8080"), "utf8");
log(`Config file ${yamlFile} created.`);
}
else {
throw new Error(`Config file ${yamlFile} already exists.`);
}
return;
}
if (!fs__namespace.existsSync(yamlFile)) {
log(`Config file ${yamlFile} does not exist.`);
throw new Error(`Config file ${yamlFile} does not exist.`);
}
const tags = (args.tags ?? []).join(",");
log(`Running with tags: ${tags}`);
const envs = {
...(dotenv.config().parsed ?? {}),
...(dotenv.config({ path: ".c8yscrn" }).parsed ?? {}),
...(tags.length > 0 ? { grepTags: tags } : {}),
..._.pickBy(process.env, (value, key) => key.startsWith("C8Y_") ||
key.endsWith("_username") ||
key.endsWith("_password")),
};
logEnv(util.sanitizeStringifiedObject(JSON.stringify(envs, null, 2)));
// we need to read config here to get some config values
const configData = c8yscrn_helper.loadConfigFile(yamlFile);
if (configData == null) {
throw new Error(`Config file ${yamlFile} is empty.`);
}
baseUrl = baseUrl ?? configData.baseUrl ?? "http://localhost:8080";
resolvedCypressConfig.config.e2e.baseUrl = baseUrl;
log(`Using baseUrl ${baseUrl}`);
const screenshotsFolder = resolvedCypressConfig.config.e2e.screenshotsFolder;
log(`Using screenshots folder ${screenshotsFolder}`);
const cypressConfigFile = resolvedCypressConfig.configFile;
log(`Using cypress config file ${cypressConfigFile}`);
const browser = resolvedCypressConfig.browser;
log(`Using browser ${browser}`);
const browserLaunchArgs = process.env[`C8Y_${browser.toUpperCase()}_LAUNCH_ARGS`] ??
process.env.C8Y_BROWSER_LAUNCH_ARGS ??
"";
if (args.highlight === false) {
log(`Disabling highlights in screenshots`);
}
const diffFolder = args.diffFolder != null
? c8yscrn_helper.resolveScreenshotFolder(args.diffFolder)
: undefined;
const failureFolder = args.failureFolder != null
? c8yscrn_helper.resolveScreenshotFolder(args.failureFolder)
: undefined;
let diffOptions = undefined;
if (args.diff === true) {
diffOptions = {
...{
antialiasing: true,
noFailOnFsErrors: true,
reduceRamUsage: true,
},
...(configData.global?.diff ?? {}),
targetFolder: diffFolder,
skipMove: args.diffSkip,
};
}
// https://docs.cypress.io/guides/guides/module-api
const config = {
...resolvedCypressConfig,
...{
env: {
...envs,
...{
_c8yscrnHighlight: args.highlight,
_c8yscrnCli: true,
_c8yscrnConfigFile: yamlFile,
_c8yscrnyaml: configData,
_c8yscrnBrowserLaunchArgs: browserLaunchArgs,
_c8yscrnDiffOptions: diffOptions,
_c8yscrnFailureFolder: failureFolder,
},
},
},
};
if (args.open === true) {
await cypress.open(config);
}
else {
const result = await cypress.run(config);
if (isFailedRunResult(result)) {
console.error(result.message);
process.exit(result.failures);
}
else {
process.exit(result.totalFailed);
}
}
}
catch (error) {
console.error(error.message);
process.exit(1);
}
})();
function isFailedRunResult(result) {
return "status" in result && result.status === "failed";
}
function getConfigFromArgs() {
const result = yargs(helpers.hideBin(process.argv))
.usage("Usage: $0 [options]")
.scriptName("c8yscrn")
.command("run", "Run workflows in headless mode", (yargs) => {
return runOptions(sharedOptions(yargs));
})
.command("open", "Run workflows in Cypress open mode", (yargs) => {
return runOptions(sharedOptions(yargs)).options("open", {
type: "boolean",
default: true,
hidden: true,
});
})
.command("init", "Initialize and create a new config file", (yargs) => {
return sharedOptions(yargs).options("init", {
type: "boolean",
default: true,
hidden: true,
});
})
.help()
.wrap(100)
.parseSync();
const filteredResult = Object.fromEntries(Object.entries(result).filter(([, value]) => value !== undefined));
return filteredResult;
}
function sharedOptions(yargs) {
return yargs
.option("config", {
alias: "c",
type: "string",
requiresArg: true,
description: "The yaml config file",
default: "c8yscrn.config.yaml",
})
.option("baseUrl", {
alias: "u",
type: "string",
requiresArg: true,
description: "The Cumulocity base url",
});
}
function runOptions(yargs) {
return yargs
.option("folder", {
alias: "f",
type: "string",
requiresArg: true,
description: "The target folder for the screenshots",
})
.option("failureFolder", {
alias: "e",
type: "string",
requiresArg: true,
description: "The target folder for failure screenshots",
})
.option("skipFailure", {
type: "boolean",
requiresArg: false,
description: "Disable failure screenshots",
default: false,
})
.option("clear", {
type: "boolean",
requiresArg: false,
description: "Clear the target folder and remove all data",
default: false,
})
.option("browser", {
alias: "b",
type: "string",
requiresArg: true,
default: "chrome",
description: "Browser to use",
})
.option("quiet", {
type: "boolean",
default: true,
requiresArg: true,
hidden: true,
})
.option("diff", {
type: "boolean",
default: false,
requiresArg: false,
description: "Enable image diffing",
})
.option("diffFolder", {
type: "string",
requiresArg: true,
description: "Optional target folder for the diff images",
})
.option("diffSkip", {
type: "boolean",
default: true,
requiresArg: false,
description: "Skip screenshots without difference",
})
.option("highlight", {
type: "boolean",
alias: "h",
default: true,
requiresArg: true,
description: "Enable or disable highlights in screenshots",
})
.option("tags", {
alias: "t",
type: "array",
requiresArg: true,
description: "Run only screenshot workflows with the given tags",
coerce: (arg) => {
const result = [];
(Array.isArray(arg) ? arg : [arg]).forEach((tag) => {
const t = tag?.split(",");
if (t != null) {
result.push(...t);
}
});
return result;
},
});
}
exports.getConfigFromArgs = getConfigFromArgs;