UNPKG

@elastic/synthetics

Version:

Elastic synthetic monitoring agent

248 lines 10.3 kB
"use strict"; /** * MIT License * * Copyright (c) 2020-present, Elastic NV * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.parsePlaywrightOptions = exports.getCommonCommandOpts = exports.parseThrottling = exports.getHeadlessFlag = exports.normalizeOptions = void 0; const deepmerge_1 = __importDefault(require("deepmerge")); const commander_1 = require("commander"); const config_1 = require("./config"); const helpers_1 = require("./helpers"); /** * Normalize the options passed via CLI and Synthetics config file * * Order of preference for options: * 1. Local options configured via Runner API * 2. CLI flags * 3. Configuration file */ async function normalizeOptions(cliArgs, mode = 'run') { /** * Move filtering flags from the top level to filter object * and delete the old keys */ const grepOpts = { pattern: cliArgs.pattern, tags: cliArgs.tags, match: cliArgs.match, }; delete cliArgs.pattern; delete cliArgs.tags; delete cliArgs.match; const options = { ...cliArgs, grepOpts, environment: process.env['NODE_ENV'] || 'development', }; /** * Validate and read synthetics config file based on the environment */ const config = cliArgs.config || !cliArgs.inline ? await (0, config_1.readConfig)(options.environment, cliArgs.config) : {}; options.params = Object.freeze((0, deepmerge_1.default)(config.params, cliArgs.params || {})); options.fields = Object.freeze((0, deepmerge_1.default)(config.monitor?.fields ?? {}, cliArgs?.fields || {})); /** * Merge playwright options from CLI and Synthetics config * and prefer individual options over other option */ const playwrightOpts = (0, deepmerge_1.default)(config.playwrightOptions, cliArgs.playwrightOptions || {}, { arrayMerge(target, source) { if (source && source.length > 0) { return [...new Set(source)]; } return target; }, }); options.playwrightOptions = { ...playwrightOpts, headless: getHeadlessFlag(cliArgs.headless, playwrightOpts?.headless), chromiumSandbox: cliArgs.sandbox ?? playwrightOpts?.chromiumSandbox, ignoreHTTPSErrors: cliArgs.ignoreHttpsErrors ?? playwrightOpts?.ignoreHTTPSErrors, }; /** * Merge default options based on the mode of operation whether we are running tests locally * or pushing the project monitors */ switch (mode) { case 'run': if (cliArgs.capability) { const supportedCapabilities = [ 'trace', 'network', 'filmstrips', 'metrics', 'ssblocks', ]; /** * trace - record chrome trace events(LCP, FCP, CLS, etc.) for all journeys * network - capture network information for all journeys * filmstrips - record detailed filmstrips for all journeys * metrics - capture performance metrics (DOM Nodes, Heap size, etc.) for each step * ssblocks - Dedupes the screenshots in to blocks to save storage space */ for (const flag of cliArgs.capability) { if (supportedCapabilities.includes(flag)) { options[flag] = true; } else { console.warn(`Missing capability "${flag}", current supported capabilities are ${supportedCapabilities.join(', ')}`); } } } /** * Group all events that can be consumed by heartbeat and * eventually by the Synthetics UI. */ if (cliArgs.richEvents) { options.reporter = cliArgs.reporter ?? 'json'; options.ssblocks = true; options.network = true; options.trace = true; options.quietExitCode = true; } options.screenshots = cliArgs.screenshots ?? 'on'; break; case 'push': /** * Merge the default monitor config from synthetics.config.ts file * with the CLI options passed via push command */ const monitor = config.monitor; for (const key of Object.keys(monitor || {})) { // screenshots require special handling as the flags are different if (key === 'screenshot') { options.screenshots = options.screenshots ?? monitor[key]; continue; } options[key] = options[key] ?? monitor[key]; } break; } return options; } exports.normalizeOptions = normalizeOptions; function getHeadlessFlag(cliHeadless, configHeadless) { // if cliHeadless is false, then we don't care about configHeadless if (!cliHeadless) { return false; } // default is headless return configHeadless ?? true; } exports.getHeadlessFlag = getHeadlessFlag; /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ function toObject(value) { const defaulVal = {}; if (typeof value === 'boolean') { return defaulVal; } return value || defaulVal; } /** * Parses the throttling CLI settings with `{download: 5, upload: 3, latency: * 20}` format * * Since throttling is disabled for now, we warn the users if throttling/nothrottling * flag is passed to the CLI */ function parseThrottling() { (0, helpers_1.warn)(helpers_1.THROTTLING_WARNING_MSG); } exports.parseThrottling = parseThrottling; function getCommonCommandOpts() { const params = (0, commander_1.createOption)('-p, --params <jsonstring>', 'JSON object that defines any variables your tests require.').argParser(JSON.parse); const playwrightOpts = (0, commander_1.createOption)('--playwright-options <jsonstring>', 'JSON object to pass in custom Playwright options for the agent. Options passed will be merged with Playwright options defined in your synthetics.config.js file.').argParser(parsePlaywrightOptions); const pattern = (0, commander_1.createOption)('--pattern <pattern>', 'RegExp pattern to match journey files in the current working directory (default: /*.journey.(ts|js)$/)'); const apiDocsLink = 'API key used for Kibana authentication(https://www.elastic.co/guide/en/kibana/master/api-keys.html).'; const auth = (0, commander_1.createOption)('--auth <auth>', apiDocsLink).env('SYNTHETICS_API_KEY'); const authMandatory = (0, commander_1.createOption)('--auth <auth>', apiDocsLink) .env('SYNTHETICS_API_KEY') .makeOptionMandatory(true); const configOpt = (0, commander_1.createOption)('-c, --config <path>', 'path to the configuration file (default: synthetics.config.(js|ts))'); const tags = (0, commander_1.createOption)('--tags <name...>', 'run/push tests with the tag(s) matching a pattern'); const match = (0, commander_1.createOption)('--match <name>', 'run/push tests with a name or tags that matches a pattern'); const fields = (0, commander_1.createOption)('--fields <jsonstring>', 'add fields to the monitor(s) in the format { "key": "value"}').argParser((fieldsStr) => { const fields = JSON.parse(fieldsStr); if (typeof fields !== 'object') { throw new Error('Invalid fields format'); } // make sure all values are strings return Object.entries(fields).reduce((acc, [key, value]) => { if (typeof value !== 'string') { acc[key] = JSON.stringify(value); } else { acc[key] = value; } return acc; }, {}); }); return { auth, authMandatory, params, playwrightOpts, pattern, configOpt, tags, match, fields, }; } exports.getCommonCommandOpts = getCommonCommandOpts; function parsePlaywrightOptions(playwrightOpts) { return JSON.parse(playwrightOpts, (key, value) => { if (key !== 'clientCertificates') { return value; } // Revive serialized clientCertificates buffer objects return (value ?? []).map(item => { const revived = { ...item }; if (item.cert && !Buffer.isBuffer(item.cert)) { revived.cert = parseAsBuffer(item.cert); } if (item.key && !Buffer.isBuffer(item.key)) { revived.key = parseAsBuffer(item.key); } if (item.pfx && !Buffer.isBuffer(item.pfx)) { revived.pfx = parseAsBuffer(item.pfx); } return revived; }); }); } exports.parsePlaywrightOptions = parsePlaywrightOptions; function parseAsBuffer(value) { try { return Buffer.from(value); } catch (e) { return value; } } //# sourceMappingURL=options.js.map