UNPKG

codeceptjs

Version:

Supercharged End 2 End Testing Framework for NodeJS

189 lines (155 loc) 5.7 kB
import { fork } from 'child_process' import path from 'path' import crypto from 'crypto' import { fileURLToPath } from 'url' import runHook from '../hooks.js' import event from '../event.js' import { createRuns } from './run-multiple/collection.js' import { clearString, replaceValueDeep } from '../utils.js' import { getConfig, getTestRoot, fail } from './utils.js' import store from '../store.js' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) const runner = path.join(__dirname, '/../../bin/codecept') let config const childOpts = {} const copyOptions = ['override', 'steps', 'reporter', 'verbose', 'config', 'reporter-options', 'grep', 'fgrep', 'invert', 'debug', 'plugins', 'colors'] let overrides = {} // codeceptjs run-multiple smoke:chrome regression:firefox - will launch smoke run in chrome and regression in firefox // codeceptjs run-multiple smoke:chrome regression - will launch smoke run in chrome and regression in firefox and chrome // codeceptjs run-multiple --all - will launch all runs // codeceptjs run-multiple smoke regression' let runId = 1 let subprocessCount = 0 let totalSubprocessCount = 0 let processesDone export default async function (selectedRuns, options) { // registering options globally to use in config if (options.profile) { process.env.profile = options.profile } const configFile = options.config const testRoot = getTestRoot(configFile) store.codeceptDir = testRoot global.codecept_dir = testRoot // copy opts to run Object.keys(options) .filter(key => copyOptions.indexOf(key) > -1) .forEach(key => { childOpts[key] = options[key] }) try { overrides = JSON.parse(childOpts.override) delete childOpts.override } catch (e) { overrides = {} } config = { ...(await getConfig(configFile)), ...overrides, } if (!config.multiple) { fail('Multiple runs not configured, add "multiple": { /../ } section to config') } selectedRuns = options.all ? Object.keys(config.multiple) : selectedRuns if (!selectedRuns.length) { fail('No runs provided. Use --all option to run all configured runs') } await runHook(config.bootstrapAll, 'bootstrapAll') event.emit(event.multiple.before, null) if (options.config) { // update paths to config path if (config.tests) { config.tests = path.resolve(testRoot, config.tests) } if (config.gherkin && config.gherkin.features) { config.gherkin.features = path.resolve(testRoot, config.gherkin.features) } } if (options.features) { config.tests = '' } if (options.tests && config.gherkin) { config.gherkin.features = '' } const childProcessesPromise = new Promise(resolve => { processesDone = resolve }) const runsToExecute = [] createRuns(selectedRuns, config).forEach(run => { const runName = run.getOriginalName() || run.getName() const runConfig = run.getConfig() runsToExecute.push(executeRun(runName, runConfig)) }) if (!runsToExecute.length) { fail('Nothing scheduled for execution') } // Execute all forks totalSubprocessCount = runsToExecute.length runsToExecute.forEach(runToExecute => runToExecute.call(this)) return childProcessesPromise.then(async () => { // fire hook await runHook(config.teardownAll, 'teardownAll') event.emit(event.multiple.after, null) }) } function executeRun(runName, runConfig) { // clone config let overriddenConfig = { ...config } // get configuration const browserConfig = runConfig.browser const browserName = browserConfig.browser for (const key in browserConfig) { overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key]) } let outputDir = `${runName}_` if (browserConfig.outputName) { outputDir += typeof browserConfig.outputName === 'function' ? browserConfig.outputName() : browserConfig.outputName } else { const hash = crypto.createHash('sha256') hash.update(JSON.stringify(browserConfig)) outputDir += hash.digest('hex') } outputDir += `_${runId}` outputDir = clearString(outputDir) // tweaking default output directories overriddenConfig = replaceValueDeep(overriddenConfig, 'output', path.join(config.output, outputDir)) overriddenConfig = replaceValueDeep(overriddenConfig, 'reportDir', path.join(config.output, outputDir)) overriddenConfig = replaceValueDeep(overriddenConfig, 'mochaFile', path.join(config.output, outputDir, `${browserName}_report.xml`)) // override tests configuration if (overriddenConfig.tests) { overriddenConfig.tests = runConfig.tests } if (overriddenConfig.gherkin && runConfig.gherkin && runConfig.gherkin.features) { overriddenConfig.gherkin.features = runConfig.gherkin.features } // override grep param and collect all params const params = ['run', '--child', `${runId++}.${runName}:${browserName}`, '--override', JSON.stringify(overriddenConfig)] Object.keys(childOpts).forEach(key => { params.push(`--${key}`) if (childOpts[key] !== true) params.push(childOpts[key]) }) if (runConfig.grep) { params.push('--grep') params.push(runConfig.grep) } const onProcessEnd = errorCode => { if (errorCode !== 0) { process.exitCode = errorCode } subprocessCount += 1 if (subprocessCount === totalSubprocessCount) { processesDone() } return errorCode } // Return function of fork for later execution return () => fork(runner, params, { stdio: [0, 1, 2, 'ipc'] }) .on('exit', code => { return onProcessEnd(code) }) .on('error', () => { return onProcessEnd(1) }) }