UNPKG

33.1 kBJavaScriptView Raw
1(function (factory) {
2 if (typeof module === "object" && typeof module.exports === "object") {
3 var v = factory(require, exports);
4 if (v !== undefined) module.exports = v;
5 }
6 else if (typeof define === "function" && define.amd) {
7 define(["require", "exports", "tslib", "@theintern/common", "./path"], factory);
8 }
9})(function (require, exports) {
10 "use strict";
11 Object.defineProperty(exports, "__esModule", { value: true });
12 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;
13 var tslib_1 = require("tslib");
14 var common_1 = require("@theintern/common");
15 var path_1 = require("./path");
16 function evalProperty(key) {
17 var strKey = key;
18 var addToExisting = strKey[strKey.length - 1] === '+';
19 var name = ((addToExisting ? strKey.slice(0, strKey.length - 1) : key));
20 return { name: name, addToExisting: addToExisting };
21 }
22 exports.evalProperty = evalProperty;
23 function getBasePath(configFile, basePath, isAbsolute, pathSep) {
24 pathSep = pathSep || path_1.getPathSep(configFile, basePath);
25 var configPathParts = configFile.replace(/\\/g, '/').split('/');
26 var initialBasePath;
27 if (configFile[0] === '/' && configPathParts.length === 2) {
28 initialBasePath = '/';
29 }
30 else {
31 initialBasePath = configPathParts.slice(0, -1).join('/');
32 }
33 var finalBasePath;
34 if (basePath) {
35 basePath = path_1.normalize(basePath);
36 if (isAbsolute(basePath)) {
37 finalBasePath = basePath;
38 }
39 else {
40 finalBasePath = path_1.join(initialBasePath, basePath);
41 }
42 }
43 else {
44 finalBasePath = initialBasePath;
45 }
46 return finalBasePath.split('/').join(pathSep);
47 }
48 exports.getBasePath = getBasePath;
49 function getConfigDescription(config, prefix) {
50 if (prefix === void 0) { prefix = ''; }
51 var description = '';
52 if (config.description) {
53 description += "" + prefix + config.description + "\n\n";
54 }
55 if (config.configs) {
56 description += prefix + "Configs:\n";
57 var width_1 = Object.keys(config.configs).reduce(function (width, name) {
58 return Math.max(width, name.length);
59 }, 0);
60 var lines = Object.keys(config.configs).map(function (name) {
61 var child = config.configs[name];
62 while (name.length < width_1) {
63 name += ' ';
64 }
65 var line = " " + name;
66 if (child.description) {
67 line += " (" + child.description + ")";
68 }
69 return "" + prefix + line;
70 });
71 description += lines.join('\n');
72 }
73 return description;
74 }
75 exports.getConfigDescription = getConfigDescription;
76 function loadConfig(configPath, loadText, args, childConfig) {
77 return _loadConfig(configPath, loadText, args, childConfig).then(function (config) {
78 delete config.config;
79 delete config.extends;
80 if (!(args && (args.showConfigs || args.help))) {
81 delete config.configs;
82 }
83 return config;
84 });
85 }
86 exports.loadConfig = loadConfig;
87 function parseArgs(rawArgs) {
88 var parsedArgs = {};
89 for (var _i = 0, rawArgs_1 = rawArgs; _i < rawArgs_1.length; _i++) {
90 var arg = rawArgs_1[_i];
91 var name_1 = arg;
92 var value = void 0;
93 var args = parsedArgs;
94 var eq = arg.indexOf('=');
95 if (eq !== -1) {
96 name_1 = arg.slice(0, eq);
97 value = arg.slice(eq + 1);
98 }
99 if (name_1.indexOf('.') !== -1) {
100 var parts = name_1.split('.');
101 var head = parts.slice(0, parts.length - 1);
102 name_1 = parts[parts.length - 1];
103 for (var _a = 0, head_1 = head; _a < head_1.length; _a++) {
104 var part = head_1[_a];
105 if (!args[part]) {
106 args[part] = {};
107 }
108 args = args[part];
109 }
110 }
111 if (typeof value === 'undefined') {
112 args[name_1] = true;
113 }
114 else {
115 if (!(name_1 in args)) {
116 args[name_1] = value;
117 }
118 else if (!Array.isArray(args[name_1])) {
119 args[name_1] = [args[name_1], value];
120 }
121 else {
122 args[name_1].push(value);
123 }
124 }
125 }
126 return parsedArgs;
127 }
128 exports.parseArgs = parseArgs;
129 function parseJson(json) {
130 return JSON.parse(removeComments(json));
131 }
132 exports.parseJson = parseJson;
133 function parseValue(name, value, parser, requiredProperty) {
134 var _a;
135 switch (parser) {
136 case 'boolean':
137 if (typeof value === 'boolean') {
138 return value;
139 }
140 if (value === 'true') {
141 return true;
142 }
143 if (value === 'false') {
144 return false;
145 }
146 throw new Error("Non-boolean value \"" + value + "\" for " + name);
147 case 'number':
148 var numValue = Number(value);
149 if (!isNaN(numValue)) {
150 return numValue;
151 }
152 throw new Error("Non-numeric value \"" + value + "\" for " + name);
153 case 'regexp':
154 if (typeof value === 'string') {
155 return new RegExp(value);
156 }
157 if (value instanceof RegExp) {
158 return value;
159 }
160 throw new Error("Non-regexp value \"" + value + "\" for " + name);
161 case 'object':
162 if (typeof value === 'string') {
163 try {
164 value = value ? JSON.parse(value) : {};
165 }
166 catch (error) {
167 if (!requiredProperty) {
168 throw new Error("Non-object value \"" + value + "\" for " + name);
169 }
170 value = (_a = {}, _a[requiredProperty] = value, _a);
171 }
172 }
173 if (Object.prototype.toString.call(value) === '[object Object]') {
174 if (requiredProperty && !value[requiredProperty]) {
175 throw new Error("Invalid value \"" + JSON.stringify(value) + "\" for " + name + ": missing '" + requiredProperty + "' property");
176 }
177 return value;
178 }
179 throw new Error("Non-object value \"" + value + "\" for " + name);
180 case 'object[]':
181 if (!value) {
182 value = [];
183 }
184 if (!Array.isArray(value)) {
185 value = [value];
186 }
187 return value.map(function (item) {
188 return parseValue(name, item, 'object', requiredProperty);
189 });
190 case 'string':
191 if (typeof value === 'string') {
192 return value;
193 }
194 throw new Error("Non-string value \"" + value + "\" for " + name);
195 case 'string[]':
196 if (!value) {
197 value = [];
198 }
199 if (typeof value === 'string') {
200 value = [value];
201 }
202 if (Array.isArray(value) && value.every(function (v) { return typeof v === 'string'; })) {
203 return value;
204 }
205 throw new Error("Non-string[] value \"" + value + "\" for " + name);
206 default:
207 if (typeof parser === 'function') {
208 return parser(value);
209 }
210 else {
211 throw new Error('Parser must be a valid type name');
212 }
213 }
214 }
215 exports.parseValue = parseValue;
216 function prefix(message, prefix) {
217 return message
218 .split('\n')
219 .map(function (line) { return prefix + line; })
220 .join('\n');
221 }
222 exports.prefix = prefix;
223 function processOption(key, value, config, executor) {
224 var _a = evalProperty(key), name = _a.name, addToExisting = _a.addToExisting;
225 var emit = executor
226 ? function (eventName, data) {
227 executor.emit(eventName, data);
228 }
229 : function () {
230 var _args = [];
231 for (var _i = 0; _i < arguments.length; _i++) {
232 _args[_i] = arguments[_i];
233 }
234 };
235 switch (name) {
236 case 'loader': {
237 setOption(config, name, parseValue(name, value, 'object', 'script'));
238 break;
239 }
240 case 'bail':
241 case 'baseline':
242 case 'benchmark':
243 case 'debug':
244 case 'filterErrorStack':
245 case 'showConfig': {
246 setOption(config, name, parseValue(name, value, 'boolean'));
247 break;
248 }
249 case 'basePath':
250 case 'coverageVariable':
251 case 'description':
252 case 'internPath':
253 case 'name':
254 case 'sessionId': {
255 setOption(config, name, parseValue(name, value, 'string'));
256 break;
257 }
258 case 'defaultTimeout': {
259 setOption(config, name, parseValue(name, value, 'number'));
260 break;
261 }
262 case 'grep': {
263 setOption(config, name, parseValue(name, value, 'regexp'));
264 break;
265 }
266 case 'reporters': {
267 setOption(config, name, parseValue(name, value, 'object[]', 'name'), addToExisting);
268 break;
269 }
270 case 'plugins':
271 case 'requires':
272 case 'require':
273 case 'scripts': {
274 var useLoader = false;
275 var _name = name;
276 switch (name) {
277 case 'scripts':
278 emit('deprecated', {
279 original: 'scripts',
280 replacement: 'plugins',
281 });
282 _name = 'plugins';
283 break;
284 case 'require':
285 emit('deprecated', {
286 original: 'require',
287 replacement: 'plugins',
288 });
289 _name = 'plugins';
290 break;
291 case 'requires':
292 emit('deprecated', {
293 original: 'require',
294 replacement: 'plugins',
295 message: 'Set `useLoader: true`',
296 });
297 _name = 'plugins';
298 useLoader = true;
299 break;
300 }
301 var parsed = parseValue(_name, value, 'object[]', 'script');
302 if (useLoader) {
303 parsed.forEach(function (entry) {
304 entry.useLoader = true;
305 });
306 }
307 setOption(config, _name, parsed, addToExisting);
308 break;
309 }
310 case 'suites': {
311 setOption(config, name, parseValue(name, value, 'string[]'), addToExisting);
312 break;
313 }
314 case 'node':
315 case 'browser': {
316 var envConfig_1 = config[name] || {};
317 if (!config[name]) {
318 config[name] = envConfig_1;
319 }
320 var envName_1 = name;
321 var _value_1 = parseValue(name, value, 'object');
322 if (_value_1) {
323 Object.keys(_value_1).forEach(function (valueKey) {
324 var key = valueKey;
325 var resource = _value_1[key];
326 var _a = evalProperty(key), name = _a.name, addToExisting = _a.addToExisting;
327 switch (name) {
328 case 'loader': {
329 resource = parseValue(name, resource, 'object', 'script');
330 setOption(envConfig_1, name, resource, false);
331 break;
332 }
333 case 'reporters': {
334 resource = parseValue('reporters', resource, 'object[]', 'name');
335 setOption(envConfig_1, name, resource, addToExisting);
336 break;
337 }
338 case 'plugins':
339 case 'require':
340 case 'requires':
341 case 'scripts': {
342 var useLoader = false;
343 switch (name) {
344 case 'scripts': {
345 emit('deprecated', {
346 original: 'scripts',
347 replacement: 'plugins',
348 });
349 name = 'plugins';
350 break;
351 }
352 case 'require': {
353 emit('deprecated', {
354 original: 'require',
355 replacement: 'plugins',
356 });
357 name = 'plugins';
358 break;
359 }
360 case 'requires': {
361 emit('deprecated', {
362 original: 'requires',
363 replacement: 'plugins',
364 message: 'Set `useLoader: true`',
365 });
366 name = 'plugins';
367 useLoader = true;
368 break;
369 }
370 }
371 resource = parseValue(name, resource, 'object[]', 'script');
372 if (useLoader) {
373 resource.forEach(function (entry) {
374 entry.useLoader = true;
375 });
376 }
377 setOption(envConfig_1, name, resource, addToExisting);
378 break;
379 }
380 case 'suites': {
381 resource = parseValue(name, resource, 'string[]');
382 setOption(envConfig_1, name, resource, addToExisting);
383 break;
384 }
385 case 'tsconfig': {
386 resource = parseValue(name, resource, function (tsconfig) {
387 var value;
388 if (tsconfig === false || tsconfig === 'false') {
389 value = false;
390 }
391 else if (typeof tsconfig === 'string') {
392 value = tsconfig;
393 }
394 if (typeof value === 'undefined') {
395 throw new Error('"tsconfig" must be a string or `false`');
396 }
397 return value;
398 });
399 setOption(envConfig_1, name, resource);
400 break;
401 }
402 default: {
403 throw new Error("Invalid property " + key + " in " + envName_1 + " config");
404 }
405 }
406 });
407 }
408 break;
409 }
410 case 'functionalBaseUrl':
411 case 'serverUrl': {
412 setOption(config, name, parseValue(name, value, 'string'));
413 break;
414 }
415 case 'proxy': {
416 if (value == null) {
417 setOption(config, name, undefined);
418 }
419 else {
420 setOption(config, name, parseValue(name, value, 'string'));
421 }
422 break;
423 }
424 case 'capabilities':
425 case 'instrumenterOptions':
426 case 'tunnelOptions': {
427 setOption(config, name, parseValue(name, value, 'object'), addToExisting);
428 break;
429 }
430 case 'environments': {
431 var _value = value;
432 if (!_value) {
433 _value = [];
434 }
435 else if (!Array.isArray(_value)) {
436 _value = [_value];
437 }
438 _value = _value.map(function (val) {
439 if (typeof val === 'object') {
440 if (val.browserName == null && typeof val.browser !== 'undefined') {
441 val.browserName = val.browser;
442 }
443 delete val.browser;
444 }
445 if (typeof val === 'object' && val.version == null) {
446 val.version = val.browserVersion;
447 }
448 return val;
449 });
450 setOption(config, name, parseValue(name, _value, 'object[]', 'browserName'), addToExisting);
451 break;
452 }
453 case 'remoteOptions': {
454 setOption(config, name, parseValue(name, value, 'object'));
455 break;
456 }
457 case 'excludeInstrumentation': {
458 emit('deprecated', {
459 original: 'excludeInstrumentation',
460 replacement: 'coverage',
461 });
462 break;
463 }
464 case 'tunnel': {
465 setOption(config, name, parseValue(name, value, 'string'));
466 break;
467 }
468 case 'functionalCoverage':
469 case 'serveOnly':
470 case 'runInSync': {
471 setOption(config, name, parseValue(name, value, 'boolean'));
472 break;
473 }
474 case 'leaveRemoteOpen': {
475 var parsed = void 0;
476 try {
477 parsed = parseValue(name, value, 'boolean');
478 }
479 catch (error) {
480 parsed = parseValue(name, value, 'string');
481 if (parsed !== 'fail') {
482 throw new Error("Invalid value '" + parsed + "' for leaveRemoteOpen");
483 }
484 }
485 setOption(config, name, parsed);
486 break;
487 }
488 case 'coverage': {
489 var parsed = void 0;
490 try {
491 parsed = parseValue(name, value, 'boolean');
492 }
493 catch (error) {
494 parsed = parseValue(name, value, 'string[]');
495 }
496 if (typeof parsed === 'boolean' && parsed !== false) {
497 throw new Error("Non-false boolean for 'coverage'");
498 }
499 setOption(config, name, parsed);
500 break;
501 }
502 case 'functionalSuites': {
503 setOption(config, name, parseValue(name, value, 'string[]'), addToExisting);
504 break;
505 }
506 case 'functionalTimeouts': {
507 if (!config.functionalTimeouts) {
508 config.functionalTimeouts = {};
509 }
510 var parsedTimeout_1 = parseValue(name, value, 'object');
511 if (parsedTimeout_1) {
512 Object.keys(parsedTimeout_1).forEach(function (timeoutKey) {
513 var key = timeoutKey;
514 if (key === 'connectTimeout') {
515 emit('deprecated', {
516 original: 'functionalTimeouts.connectTimeout',
517 replacement: 'connectTimeout',
518 });
519 setOption(config, key, parseValue(key, parsedTimeout_1[key], 'number'));
520 }
521 else {
522 config.functionalTimeouts[key] = parseValue("functionalTimeouts." + key, parsedTimeout_1[key], 'number');
523 }
524 });
525 }
526 else {
527 setOption(config, name, {});
528 }
529 break;
530 }
531 case 'connectTimeout':
532 case 'heartbeatInterval':
533 case 'maxConcurrency':
534 case 'serverPort':
535 case 'socketPort':
536 case 'socketTimeout': {
537 setOption(config, name, parseValue(name, value, 'number'));
538 break;
539 }
540 case 'warnOnUncaughtException':
541 case 'warnOnUnhandledRejection': {
542 var parsed = void 0;
543 try {
544 parsed = parseValue(name, value, 'boolean');
545 }
546 catch (error) {
547 parsed = parseValue(name, value, 'regexp');
548 }
549 setOption(config, name, parsed);
550 break;
551 }
552 default: {
553 emit('log', "Config has unknown option \"" + name + "\"");
554 setOption(config, name, value);
555 }
556 }
557 }
558 exports.processOption = processOption;
559 function pullFromArray(haystack, needle) {
560 var removed = [];
561 var i = 0;
562 while ((i = haystack.indexOf(needle, i)) > -1) {
563 removed.push(haystack.splice(i, 1)[0]);
564 }
565 return removed;
566 }
567 exports.pullFromArray = pullFromArray;
568 function removeComments(text) {
569 var state = 'default';
570 var i = 0;
571 var chars = text.split('');
572 while (i < chars.length) {
573 switch (state) {
574 case 'block-comment':
575 if (chars[i] === '*' && chars[i + 1] === '/') {
576 chars[i] = ' ';
577 chars[i + 1] = ' ';
578 state = 'default';
579 i += 2;
580 }
581 else if (chars[i] !== '\n') {
582 chars[i] = ' ';
583 i += 1;
584 }
585 else {
586 i += 1;
587 }
588 break;
589 case 'line-comment':
590 if (chars[i] === '\n') {
591 state = 'default';
592 }
593 else {
594 chars[i] = ' ';
595 }
596 i += 1;
597 break;
598 case 'string':
599 if (chars[i] === '"') {
600 state = 'default';
601 i += 1;
602 }
603 else if (chars[i] === '\\' && chars[i + 1] === '\\') {
604 i += 2;
605 }
606 else if (chars[i] === '\\' && chars[i + 1] === '"') {
607 i += 2;
608 }
609 else {
610 i += 1;
611 }
612 break;
613 default:
614 if (chars[i] === '"') {
615 state = 'string';
616 i += 1;
617 }
618 else if (chars[i] === '/' && chars[i + 1] === '*') {
619 chars[i] = ' ';
620 chars[i + 1] = ' ';
621 state = 'block-comment';
622 i += 2;
623 }
624 else if (chars[i] === '/' && chars[i + 1] === '/') {
625 chars[i] = ' ';
626 chars[i + 1] = ' ';
627 state = 'line-comment';
628 i += 2;
629 }
630 else {
631 i += 1;
632 }
633 }
634 }
635 return chars.join('');
636 }
637 function setOption(config, name, value, addToExisting) {
638 if (addToExisting === void 0) { addToExisting = false; }
639 if (addToExisting) {
640 var currentValue = config[name];
641 if (currentValue == null) {
642 config[name] = value;
643 }
644 else if (Array.isArray(currentValue)) {
645 currentValue.push.apply(currentValue, value);
646 }
647 else if (typeof config[name] === 'object') {
648 config[name] = common_1.deepMixin({}, config[name], value);
649 }
650 else {
651 throw new Error('Only array or object options may be added');
652 }
653 }
654 else {
655 config[name] = value;
656 }
657 }
658 exports.setOption = setOption;
659 function splitConfigPath(path, separator) {
660 if (separator === void 0) { separator = '/'; }
661 var lastSep = path.lastIndexOf(configPathSeparator);
662 if (lastSep === 0) {
663 return { configFile: '', childConfig: path.slice(1) };
664 }
665 if (lastSep === -1 || path[lastSep - 1] === separator) {
666 return { configFile: path };
667 }
668 return {
669 configFile: path.slice(0, lastSep),
670 childConfig: path.slice(lastSep + 1),
671 };
672 }
673 exports.splitConfigPath = splitConfigPath;
674 function stringify(object, indent) {
675 return JSON.stringify(object, getSerializeReplacer(), indent);
676 }
677 exports.stringify = stringify;
678 function _loadConfig(configPath, loadText, args, childConfig) {
679 return loadText(configPath)
680 .then(function (text) {
681 var preConfig;
682 try {
683 preConfig = parseJson(text);
684 }
685 catch (error) {
686 throw new Error("Invalid JSON in " + configPath);
687 }
688 if (preConfig.extends) {
689 var parts = configPath.split('/');
690 var _a = splitConfigPath(preConfig.extends), configFile = _a.configFile, childConfig_1 = _a.childConfig;
691 var extensionPath = parts
692 .slice(0, parts.length - 1)
693 .concat(configFile)
694 .join('/');
695 return _loadConfig(extensionPath, loadText, undefined, childConfig_1).then(function (extension) {
696 Object.keys(preConfig)
697 .filter(function (key) { return key !== 'configs'; })
698 .forEach(function (key) {
699 processOption(key, preConfig[key], extension);
700 });
701 if (preConfig.configs) {
702 if (extension.configs == null) {
703 extension.configs = {};
704 }
705 Object.keys(preConfig.configs).forEach(function (key) {
706 extension.configs[key] = preConfig.configs[key];
707 });
708 }
709 return extension;
710 });
711 }
712 else {
713 var config_1 = {};
714 Object.keys(preConfig).forEach(function (key) {
715 processOption(key, preConfig[key], config_1);
716 });
717 return config_1;
718 }
719 })
720 .then(function (config) {
721 if (args && (args.showConfigs || args.help)) {
722 return config;
723 }
724 if (childConfig) {
725 var mixinConfig_1 = function (childConfig) {
726 var configs = Array.isArray(childConfig)
727 ? childConfig
728 : [childConfig];
729 configs.forEach(function (childConfig) {
730 var child = config.configs[childConfig];
731 if (!child) {
732 throw new Error("Unknown child config \"" + childConfig + "\"");
733 }
734 if (child.extends) {
735 mixinConfig_1(child.extends);
736 }
737 Object.keys(child)
738 .filter(function (key) { return key !== 'node' && key !== 'browser'; })
739 .forEach(function (key) {
740 processOption(key, child[key], config);
741 });
742 ['node', 'browser'].forEach(function (key) {
743 if (child[key]) {
744 if (config[key]) {
745 var envConfig = {};
746 processOption(key, child[key], envConfig);
747 Object.assign(config[key], envConfig[key]);
748 }
749 else {
750 processOption(key, child[key], config);
751 }
752 }
753 });
754 });
755 };
756 mixinConfig_1(childConfig);
757 }
758 return config;
759 })
760 .then(function (config) {
761 if (args) {
762 var resources = [
763 'plugins',
764 'reporters',
765 'suites',
766 ];
767 resources
768 .filter(function (resource) { return resource in args; })
769 .forEach(function (resource) {
770 var environments = ['node', 'browser'];
771 environments
772 .filter(function (environment) { return config[environment]; })
773 .forEach(function (environment) {
774 delete config[environment][resource];
775 });
776 });
777 Object.keys(args).forEach(function (key) {
778 processOption(key, args[key], config);
779 });
780 }
781 return config;
782 });
783 }
784 var configPathSeparator = '@';
785 function getSerializeReplacer() {
786 var seen = new WeakSet();
787 return function (_key, value) {
788 if (!value) {
789 return value;
790 }
791 if (value instanceof RegExp) {
792 return value.source;
793 }
794 if (typeof value === 'function') {
795 return value.toString();
796 }
797 if (typeof value === 'object') {
798 if (seen.has(value)) {
799 return;
800 }
801 seen.add(value);
802 }
803 return value;
804 };
805 }
806 function errorToJSON(error) {
807 if (!error) {
808 return undefined;
809 }
810 var name = error.name, message = error.message, stack = error.stack, lifecycleMethod = error.lifecycleMethod, showDiff = error.showDiff, actual = error.actual, expected = error.expected;
811 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 } : {}));
812 }
813 exports.errorToJSON = errorToJSON;
814});
815//# sourceMappingURL=util.js.map
\No newline at end of file