dev-utils/run-script.js (156 lines of code) (raw):
/**
* MIT License
*
* Copyright (c) 2017-present, Elasticsearch BV
*
* 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.
*
*/
const { join } = require('path')
const runAll = require('npm-run-all')
const {
runKarma,
runSauceConnect,
runJasmine,
runE2eTests: runE2eTestsUtils,
buildE2eBundles: buildE2eBundlesUtils
} = require('./test-utils')
const { startTestServers } = require('./test-servers')
const {
getTestEnvironmentVariables,
getSauceConnectOptions
} = require('./test-config')
const { generateNotice } = require('./dep-info')
const PROJECT_DIR = join(__dirname, '../')
const { sauceLabs } = getTestEnvironmentVariables()
let cleanUps = []
function startServersWithCleanups() {
let servers = startTestServers.apply(this, arguments)
cleanUps.push(() => {
servers.map(s => s.close())
})
return servers
}
function runUnitTests(packagePath, startSauceConnect = 'false') {
const karmaConfigFile = join(PROJECT_DIR, packagePath, 'karma.conf.js')
if (startSauceConnect === 'true') {
return launchSauceConnect(() => runKarma(karmaConfigFile))
}
runKarma(karmaConfigFile)
}
/**
* Checks if the MODE is set to "saucelabs" and decides where to run the
* corresponding callback function
*/
function launchSauceConnect(callback = () => {}) {
if (sauceLabs) {
const sauceOpts = getSauceConnectOptions()
return runSauceConnect(sauceOpts, callback)
}
console.info('Skipping sauce tests, MODE is not set to saucelabs')
return callback()
}
function runIntegrationTests() {
const servers = startTestServers('./')
const SPEC_DIR = 'test/integration'
runJasmine(SPEC_DIR, err => {
servers.forEach(server => server.close())
if (err) {
console.log('Integration tests failed:', err.message)
process.exit(2)
}
})
}
/**
* Ensure all the exports from our module works
* in Node.js without babel transpiling the modules
*/
function runNodeTests() {
const SPEC_DIR = 'test/node'
runJasmine(SPEC_DIR, err => {
if (err) {
console.log('Node tests for build failed:', err.message)
process.exit(2)
}
})
}
function runBundleTests() {
const SPEC_DIR = 'test/bundle'
runJasmine(SPEC_DIR, err => {
if (err) {
console.log('browser bundle tests failed:', err.message)
process.exit(2)
}
})
}
function runE2eTests(configPath) {
const webDriverConfig = join(PROJECT_DIR, configPath)
runE2eTestsUtils(webDriverConfig, false)
}
function buildE2eBundles(basePath) {
return buildE2eBundlesUtils(join(PROJECT_DIR, basePath))
}
function runSauceTests(packagePath, serve = 'true', ...scripts) {
/**
* Since there is no easy way to reuse the sauce connect tunnel even using same tunnel identifier,
* we launch the sauce connect tunnel before starting all the saucelab tests
*/
if (serve === 'true') {
startServersWithCleanups(join(PROJECT_DIR, packagePath))
}
launchSauceConnect(async sauceConnectProcess => {
/**
* Decides the saucelabs test status
*/
let exitCode = 0
const loggerOpts = {
stdout: process.stdout,
stderr: process.stderr
}
const exitProcess = () => process.exit(exitCode)
const runAllAndExit = async commands => {
try {
await runAll(commands, loggerOpts)
} catch (err) {
console.log('runSauceTests failed', err)
exitCode = 1
} finally {
if (sauceConnectProcess) {
sauceConnectProcess.close(exitProcess)
} else {
exitProcess()
}
}
}
/**
* `console.logs` from the tests will be truncated when the process exits
* To avoid truncation, we flush the data from stdout before exiting the process
*/
if (process.stdout.isTTY && process.stdout._handle) {
process.stdout._handle.setBlocking(true)
}
if (!sauceLabs) {
/**
* For Angular package we use `ng` commands for running the test instead of
* using our custom karma runner
*/
if (packagePath === 'packages/rum-angular') {
return await runAllAndExit(['test:unit'])
} else {
return runUnitTests(packagePath)
}
}
await runAllAndExit(scripts)
})
}
function exitHandler(exitCode) {
if (cleanUps.length > 0) {
console.log('Running cleanups:', cleanUps.length)
cleanUps.forEach(f => {
try {
f(exitCode)
} catch (e) {
console.error(e)
}
})
cleanUps = []
}
}
process.on('exit', exitHandler)
process.on('SIGINT', exitHandler)
const scripts = {
launchSauceConnect,
generateNotice,
runUnitTests,
runSauceTests,
runE2eTests,
runIntegrationTests,
runNodeTests,
runBundleTests,
buildE2eBundles,
startTestServers: startServersWithCleanups
}
function runScript() {
const [, , scriptName, ...scriptArgs] = process.argv
if (scriptName) {
var message = `Running: ${scriptName}(${scriptArgs
.map(a => a.trim())
.join(', ')}) \n`
console.log(message)
if (typeof scripts[scriptName] === 'function') {
return scripts[scriptName].apply(this, scriptArgs)
} else {
throw new Error('No script with name ' + scriptName)
}
}
}
runScript()