intern
Version:
Intern. A next-generation code testing stack for JavaScript.
815 lines • 33.1 kB
JavaScript
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define(["require", "exports", "tslib", "@theintern/common", "./path"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.errorToJSON = exports.stringify = exports.splitConfigPath = exports.setOption = exports.pullFromArray = exports.processOption = exports.prefix = exports.parseValue = exports.parseJson = exports.parseArgs = exports.loadConfig = exports.getConfigDescription = exports.getBasePath = exports.evalProperty = void 0;
var tslib_1 = require("tslib");
var common_1 = require("@theintern/common");
var path_1 = require("./path");
function evalProperty(key) {
var strKey = key;
var addToExisting = strKey[strKey.length - 1] === '+';
var name = ((addToExisting ? strKey.slice(0, strKey.length - 1) : key));
return { name: name, addToExisting: addToExisting };
}
exports.evalProperty = evalProperty;
function getBasePath(configFile, basePath, isAbsolute, pathSep) {
pathSep = pathSep || path_1.getPathSep(configFile, basePath);
var configPathParts = configFile.replace(/\\/g, '/').split('/');
var initialBasePath;
if (configFile[0] === '/' && configPathParts.length === 2) {
initialBasePath = '/';
}
else {
initialBasePath = configPathParts.slice(0, -1).join('/');
}
var finalBasePath;
if (basePath) {
basePath = path_1.normalize(basePath);
if (isAbsolute(basePath)) {
finalBasePath = basePath;
}
else {
finalBasePath = path_1.join(initialBasePath, basePath);
}
}
else {
finalBasePath = initialBasePath;
}
return finalBasePath.split('/').join(pathSep);
}
exports.getBasePath = getBasePath;
function getConfigDescription(config, prefix) {
if (prefix === void 0) { prefix = ''; }
var description = '';
if (config.description) {
description += "" + prefix + config.description + "\n\n";
}
if (config.configs) {
description += prefix + "Configs:\n";
var width_1 = Object.keys(config.configs).reduce(function (width, name) {
return Math.max(width, name.length);
}, 0);
var lines = Object.keys(config.configs).map(function (name) {
var child = config.configs[name];
while (name.length < width_1) {
name += ' ';
}
var line = " " + name;
if (child.description) {
line += " (" + child.description + ")";
}
return "" + prefix + line;
});
description += lines.join('\n');
}
return description;
}
exports.getConfigDescription = getConfigDescription;
function loadConfig(configPath, loadText, args, childConfig) {
return _loadConfig(configPath, loadText, args, childConfig).then(function (config) {
delete config.config;
delete config.extends;
if (!(args && (args.showConfigs || args.help))) {
delete config.configs;
}
return config;
});
}
exports.loadConfig = loadConfig;
function parseArgs(rawArgs) {
var parsedArgs = {};
for (var _i = 0, rawArgs_1 = rawArgs; _i < rawArgs_1.length; _i++) {
var arg = rawArgs_1[_i];
var name_1 = arg;
var value = void 0;
var args = parsedArgs;
var eq = arg.indexOf('=');
if (eq !== -1) {
name_1 = arg.slice(0, eq);
value = arg.slice(eq + 1);
}
if (name_1.indexOf('.') !== -1) {
var parts = name_1.split('.');
var head = parts.slice(0, parts.length - 1);
name_1 = parts[parts.length - 1];
for (var _a = 0, head_1 = head; _a < head_1.length; _a++) {
var part = head_1[_a];
if (!args[part]) {
args[part] = {};
}
args = args[part];
}
}
if (typeof value === 'undefined') {
args[name_1] = true;
}
else {
if (!(name_1 in args)) {
args[name_1] = value;
}
else if (!Array.isArray(args[name_1])) {
args[name_1] = [args[name_1], value];
}
else {
args[name_1].push(value);
}
}
}
return parsedArgs;
}
exports.parseArgs = parseArgs;
function parseJson(json) {
return JSON.parse(removeComments(json));
}
exports.parseJson = parseJson;
function parseValue(name, value, parser, requiredProperty) {
var _a;
switch (parser) {
case 'boolean':
if (typeof value === 'boolean') {
return value;
}
if (value === 'true') {
return true;
}
if (value === 'false') {
return false;
}
throw new Error("Non-boolean value \"" + value + "\" for " + name);
case 'number':
var numValue = Number(value);
if (!isNaN(numValue)) {
return numValue;
}
throw new Error("Non-numeric value \"" + value + "\" for " + name);
case 'regexp':
if (typeof value === 'string') {
return new RegExp(value);
}
if (value instanceof RegExp) {
return value;
}
throw new Error("Non-regexp value \"" + value + "\" for " + name);
case 'object':
if (typeof value === 'string') {
try {
value = value ? JSON.parse(value) : {};
}
catch (error) {
if (!requiredProperty) {
throw new Error("Non-object value \"" + value + "\" for " + name);
}
value = (_a = {}, _a[requiredProperty] = value, _a);
}
}
if (Object.prototype.toString.call(value) === '[object Object]') {
if (requiredProperty && !value[requiredProperty]) {
throw new Error("Invalid value \"" + JSON.stringify(value) + "\" for " + name + ": missing '" + requiredProperty + "' property");
}
return value;
}
throw new Error("Non-object value \"" + value + "\" for " + name);
case 'object[]':
if (!value) {
value = [];
}
if (!Array.isArray(value)) {
value = [value];
}
return value.map(function (item) {
return parseValue(name, item, 'object', requiredProperty);
});
case 'string':
if (typeof value === 'string') {
return value;
}
throw new Error("Non-string value \"" + value + "\" for " + name);
case 'string[]':
if (!value) {
value = [];
}
if (typeof value === 'string') {
value = [value];
}
if (Array.isArray(value) && value.every(function (v) { return typeof v === 'string'; })) {
return value;
}
throw new Error("Non-string[] value \"" + value + "\" for " + name);
default:
if (typeof parser === 'function') {
return parser(value);
}
else {
throw new Error('Parser must be a valid type name');
}
}
}
exports.parseValue = parseValue;
function prefix(message, prefix) {
return message
.split('\n')
.map(function (line) { return prefix + line; })
.join('\n');
}
exports.prefix = prefix;
function processOption(key, value, config, executor) {
var _a = evalProperty(key), name = _a.name, addToExisting = _a.addToExisting;
var emit = executor
? function (eventName, data) {
executor.emit(eventName, data);
}
: function () {
var _args = [];
for (var _i = 0; _i < arguments.length; _i++) {
_args[_i] = arguments[_i];
}
};
switch (name) {
case 'loader': {
setOption(config, name, parseValue(name, value, 'object', 'script'));
break;
}
case 'bail':
case 'baseline':
case 'benchmark':
case 'debug':
case 'filterErrorStack':
case 'showConfig': {
setOption(config, name, parseValue(name, value, 'boolean'));
break;
}
case 'basePath':
case 'coverageVariable':
case 'description':
case 'internPath':
case 'name':
case 'sessionId': {
setOption(config, name, parseValue(name, value, 'string'));
break;
}
case 'defaultTimeout': {
setOption(config, name, parseValue(name, value, 'number'));
break;
}
case 'grep': {
setOption(config, name, parseValue(name, value, 'regexp'));
break;
}
case 'reporters': {
setOption(config, name, parseValue(name, value, 'object[]', 'name'), addToExisting);
break;
}
case 'plugins':
case 'requires':
case 'require':
case 'scripts': {
var useLoader = false;
var _name = name;
switch (name) {
case 'scripts':
emit('deprecated', {
original: 'scripts',
replacement: 'plugins',
});
_name = 'plugins';
break;
case 'require':
emit('deprecated', {
original: 'require',
replacement: 'plugins',
});
_name = 'plugins';
break;
case 'requires':
emit('deprecated', {
original: 'require',
replacement: 'plugins',
message: 'Set `useLoader: true`',
});
_name = 'plugins';
useLoader = true;
break;
}
var parsed = parseValue(_name, value, 'object[]', 'script');
if (useLoader) {
parsed.forEach(function (entry) {
entry.useLoader = true;
});
}
setOption(config, _name, parsed, addToExisting);
break;
}
case 'suites': {
setOption(config, name, parseValue(name, value, 'string[]'), addToExisting);
break;
}
case 'node':
case 'browser': {
var envConfig_1 = config[name] || {};
if (!config[name]) {
config[name] = envConfig_1;
}
var envName_1 = name;
var _value_1 = parseValue(name, value, 'object');
if (_value_1) {
Object.keys(_value_1).forEach(function (valueKey) {
var key = valueKey;
var resource = _value_1[key];
var _a = evalProperty(key), name = _a.name, addToExisting = _a.addToExisting;
switch (name) {
case 'loader': {
resource = parseValue(name, resource, 'object', 'script');
setOption(envConfig_1, name, resource, false);
break;
}
case 'reporters': {
resource = parseValue('reporters', resource, 'object[]', 'name');
setOption(envConfig_1, name, resource, addToExisting);
break;
}
case 'plugins':
case 'require':
case 'requires':
case 'scripts': {
var useLoader = false;
switch (name) {
case 'scripts': {
emit('deprecated', {
original: 'scripts',
replacement: 'plugins',
});
name = 'plugins';
break;
}
case 'require': {
emit('deprecated', {
original: 'require',
replacement: 'plugins',
});
name = 'plugins';
break;
}
case 'requires': {
emit('deprecated', {
original: 'requires',
replacement: 'plugins',
message: 'Set `useLoader: true`',
});
name = 'plugins';
useLoader = true;
break;
}
}
resource = parseValue(name, resource, 'object[]', 'script');
if (useLoader) {
resource.forEach(function (entry) {
entry.useLoader = true;
});
}
setOption(envConfig_1, name, resource, addToExisting);
break;
}
case 'suites': {
resource = parseValue(name, resource, 'string[]');
setOption(envConfig_1, name, resource, addToExisting);
break;
}
case 'tsconfig': {
resource = parseValue(name, resource, function (tsconfig) {
var value;
if (tsconfig === false || tsconfig === 'false') {
value = false;
}
else if (typeof tsconfig === 'string') {
value = tsconfig;
}
if (typeof value === 'undefined') {
throw new Error('"tsconfig" must be a string or `false`');
}
return value;
});
setOption(envConfig_1, name, resource);
break;
}
default: {
throw new Error("Invalid property " + key + " in " + envName_1 + " config");
}
}
});
}
break;
}
case 'functionalBaseUrl':
case 'serverUrl': {
setOption(config, name, parseValue(name, value, 'string'));
break;
}
case 'proxy': {
if (value == null) {
setOption(config, name, undefined);
}
else {
setOption(config, name, parseValue(name, value, 'string'));
}
break;
}
case 'capabilities':
case 'instrumenterOptions':
case 'tunnelOptions': {
setOption(config, name, parseValue(name, value, 'object'), addToExisting);
break;
}
case 'environments': {
var _value = value;
if (!_value) {
_value = [];
}
else if (!Array.isArray(_value)) {
_value = [_value];
}
_value = _value.map(function (val) {
if (typeof val === 'object') {
if (val.browserName == null && typeof val.browser !== 'undefined') {
val.browserName = val.browser;
}
delete val.browser;
}
if (typeof val === 'object' && val.version == null) {
val.version = val.browserVersion;
}
return val;
});
setOption(config, name, parseValue(name, _value, 'object[]', 'browserName'), addToExisting);
break;
}
case 'remoteOptions': {
setOption(config, name, parseValue(name, value, 'object'));
break;
}
case 'excludeInstrumentation': {
emit('deprecated', {
original: 'excludeInstrumentation',
replacement: 'coverage',
});
break;
}
case 'tunnel': {
setOption(config, name, parseValue(name, value, 'string'));
break;
}
case 'functionalCoverage':
case 'serveOnly':
case 'runInSync': {
setOption(config, name, parseValue(name, value, 'boolean'));
break;
}
case 'leaveRemoteOpen': {
var parsed = void 0;
try {
parsed = parseValue(name, value, 'boolean');
}
catch (error) {
parsed = parseValue(name, value, 'string');
if (parsed !== 'fail') {
throw new Error("Invalid value '" + parsed + "' for leaveRemoteOpen");
}
}
setOption(config, name, parsed);
break;
}
case 'coverage': {
var parsed = void 0;
try {
parsed = parseValue(name, value, 'boolean');
}
catch (error) {
parsed = parseValue(name, value, 'string[]');
}
if (typeof parsed === 'boolean' && parsed !== false) {
throw new Error("Non-false boolean for 'coverage'");
}
setOption(config, name, parsed);
break;
}
case 'functionalSuites': {
setOption(config, name, parseValue(name, value, 'string[]'), addToExisting);
break;
}
case 'functionalTimeouts': {
if (!config.functionalTimeouts) {
config.functionalTimeouts = {};
}
var parsedTimeout_1 = parseValue(name, value, 'object');
if (parsedTimeout_1) {
Object.keys(parsedTimeout_1).forEach(function (timeoutKey) {
var key = timeoutKey;
if (key === 'connectTimeout') {
emit('deprecated', {
original: 'functionalTimeouts.connectTimeout',
replacement: 'connectTimeout',
});
setOption(config, key, parseValue(key, parsedTimeout_1[key], 'number'));
}
else {
config.functionalTimeouts[key] = parseValue("functionalTimeouts." + key, parsedTimeout_1[key], 'number');
}
});
}
else {
setOption(config, name, {});
}
break;
}
case 'connectTimeout':
case 'heartbeatInterval':
case 'maxConcurrency':
case 'serverPort':
case 'socketPort':
case 'socketTimeout': {
setOption(config, name, parseValue(name, value, 'number'));
break;
}
case 'warnOnUncaughtException':
case 'warnOnUnhandledRejection': {
var parsed = void 0;
try {
parsed = parseValue(name, value, 'boolean');
}
catch (error) {
parsed = parseValue(name, value, 'regexp');
}
setOption(config, name, parsed);
break;
}
default: {
emit('log', "Config has unknown option \"" + name + "\"");
setOption(config, name, value);
}
}
}
exports.processOption = processOption;
function pullFromArray(haystack, needle) {
var removed = [];
var i = 0;
while ((i = haystack.indexOf(needle, i)) > -1) {
removed.push(haystack.splice(i, 1)[0]);
}
return removed;
}
exports.pullFromArray = pullFromArray;
function removeComments(text) {
var state = 'default';
var i = 0;
var chars = text.split('');
while (i < chars.length) {
switch (state) {
case 'block-comment':
if (chars[i] === '*' && chars[i + 1] === '/') {
chars[i] = ' ';
chars[i + 1] = ' ';
state = 'default';
i += 2;
}
else if (chars[i] !== '\n') {
chars[i] = ' ';
i += 1;
}
else {
i += 1;
}
break;
case 'line-comment':
if (chars[i] === '\n') {
state = 'default';
}
else {
chars[i] = ' ';
}
i += 1;
break;
case 'string':
if (chars[i] === '"') {
state = 'default';
i += 1;
}
else if (chars[i] === '\\' && chars[i + 1] === '\\') {
i += 2;
}
else if (chars[i] === '\\' && chars[i + 1] === '"') {
i += 2;
}
else {
i += 1;
}
break;
default:
if (chars[i] === '"') {
state = 'string';
i += 1;
}
else if (chars[i] === '/' && chars[i + 1] === '*') {
chars[i] = ' ';
chars[i + 1] = ' ';
state = 'block-comment';
i += 2;
}
else if (chars[i] === '/' && chars[i + 1] === '/') {
chars[i] = ' ';
chars[i + 1] = ' ';
state = 'line-comment';
i += 2;
}
else {
i += 1;
}
}
}
return chars.join('');
}
function setOption(config, name, value, addToExisting) {
if (addToExisting === void 0) { addToExisting = false; }
if (addToExisting) {
var currentValue = config[name];
if (currentValue == null) {
config[name] = value;
}
else if (Array.isArray(currentValue)) {
currentValue.push.apply(currentValue, value);
}
else if (typeof config[name] === 'object') {
config[name] = common_1.deepMixin({}, config[name], value);
}
else {
throw new Error('Only array or object options may be added');
}
}
else {
config[name] = value;
}
}
exports.setOption = setOption;
function splitConfigPath(path, separator) {
if (separator === void 0) { separator = '/'; }
var lastSep = path.lastIndexOf(configPathSeparator);
if (lastSep === 0) {
return { configFile: '', childConfig: path.slice(1) };
}
if (lastSep === -1 || path[lastSep - 1] === separator) {
return { configFile: path };
}
return {
configFile: path.slice(0, lastSep),
childConfig: path.slice(lastSep + 1),
};
}
exports.splitConfigPath = splitConfigPath;
function stringify(object, indent) {
return JSON.stringify(object, getSerializeReplacer(), indent);
}
exports.stringify = stringify;
function _loadConfig(configPath, loadText, args, childConfig) {
return loadText(configPath)
.then(function (text) {
var preConfig;
try {
preConfig = parseJson(text);
}
catch (error) {
throw new Error("Invalid JSON in " + configPath);
}
if (preConfig.extends) {
var parts = configPath.split('/');
var _a = splitConfigPath(preConfig.extends), configFile = _a.configFile, childConfig_1 = _a.childConfig;
var extensionPath = parts
.slice(0, parts.length - 1)
.concat(configFile)
.join('/');
return _loadConfig(extensionPath, loadText, undefined, childConfig_1).then(function (extension) {
Object.keys(preConfig)
.filter(function (key) { return key !== 'configs'; })
.forEach(function (key) {
processOption(key, preConfig[key], extension);
});
if (preConfig.configs) {
if (extension.configs == null) {
extension.configs = {};
}
Object.keys(preConfig.configs).forEach(function (key) {
extension.configs[key] = preConfig.configs[key];
});
}
return extension;
});
}
else {
var config_1 = {};
Object.keys(preConfig).forEach(function (key) {
processOption(key, preConfig[key], config_1);
});
return config_1;
}
})
.then(function (config) {
if (args && (args.showConfigs || args.help)) {
return config;
}
if (childConfig) {
var mixinConfig_1 = function (childConfig) {
var configs = Array.isArray(childConfig)
? childConfig
: [childConfig];
configs.forEach(function (childConfig) {
var child = config.configs[childConfig];
if (!child) {
throw new Error("Unknown child config \"" + childConfig + "\"");
}
if (child.extends) {
mixinConfig_1(child.extends);
}
Object.keys(child)
.filter(function (key) { return key !== 'node' && key !== 'browser'; })
.forEach(function (key) {
processOption(key, child[key], config);
});
['node', 'browser'].forEach(function (key) {
if (child[key]) {
if (config[key]) {
var envConfig = {};
processOption(key, child[key], envConfig);
Object.assign(config[key], envConfig[key]);
}
else {
processOption(key, child[key], config);
}
}
});
});
};
mixinConfig_1(childConfig);
}
return config;
})
.then(function (config) {
if (args) {
var resources = [
'plugins',
'reporters',
'suites',
];
resources
.filter(function (resource) { return resource in args; })
.forEach(function (resource) {
var environments = ['node', 'browser'];
environments
.filter(function (environment) { return config[environment]; })
.forEach(function (environment) {
delete config[environment][resource];
});
});
Object.keys(args).forEach(function (key) {
processOption(key, args[key], config);
});
}
return config;
});
}
var configPathSeparator = '@';
function getSerializeReplacer() {
var seen = new WeakSet();
return function (_key, value) {
if (!value) {
return value;
}
if (value instanceof RegExp) {
return value.source;
}
if (typeof value === 'function') {
return value.toString();
}
if (typeof value === 'object') {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
}
function errorToJSON(error) {
if (!error) {
return undefined;
}
var name = error.name, message = error.message, stack = error.stack, lifecycleMethod = error.lifecycleMethod, showDiff = error.showDiff, actual = error.actual, expected = error.expected;
return tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({ name: name, message: message, stack: stack }, (lifecycleMethod ? { lifecycleMethod: lifecycleMethod } : {})), { showDiff: Boolean(showDiff) }), (showDiff ? { actual: actual, expected: expected } : {}));
}
exports.errorToJSON = errorToJSON;
});
//# sourceMappingURL=util.js.map