configParser.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const glob = require("glob");
  4. const path = require("path");
  5. const exitCodes_1 = require("./exitCodes");
  6. const logger_1 = require("./logger");
  7. let logger = new logger_1.Logger('configParser');
  8. // Coffee is required here to enable config files written in coffee-script.
  9. try {
  10. require('coffee-script').register();
  11. }
  12. catch (e) {
  13. // Intentionally blank - ignore if coffee-script is not available.
  14. }
  15. // CoffeeScript lost the hyphen in the module name a long time ago, all new version are named this:
  16. try {
  17. require('coffeescript').register();
  18. }
  19. catch (e) {
  20. // Intentionally blank - ignore if coffeescript is not available.
  21. }
  22. // LiveScript is required here to enable config files written in LiveScript.
  23. try {
  24. require('LiveScript');
  25. }
  26. catch (e) {
  27. // Intentionally blank - ignore if LiveScript is not available.
  28. }
  29. class ConfigParser {
  30. constructor() {
  31. // Default configuration.
  32. this.config_ = {
  33. specs: [],
  34. multiCapabilities: [],
  35. verboseMultiSessions: false,
  36. rootElement: '',
  37. allScriptsTimeout: 11000,
  38. getPageTimeout: 10000,
  39. params: {},
  40. framework: 'jasmine',
  41. jasmineNodeOpts: { showColors: true, defaultTimeoutInterval: (30 * 1000) },
  42. seleniumArgs: [],
  43. mochaOpts: { ui: 'bdd', reporter: 'list' },
  44. configDir: './',
  45. noGlobals: false,
  46. plugins: [],
  47. skipSourceMapSupport: false,
  48. ng12Hybrid: false
  49. };
  50. }
  51. /**
  52. * Resolve a list of file patterns into a list of individual file paths.
  53. *
  54. * @param {Array.<string> | string} patterns
  55. * @param {=boolean} opt_omitWarnings Whether to omit did not match warnings
  56. * @param {=string} opt_relativeTo Path to resolve patterns against
  57. *
  58. * @return {Array} The resolved file paths.
  59. */
  60. static resolveFilePatterns(patterns, opt_omitWarnings, opt_relativeTo) {
  61. let resolvedFiles = [];
  62. let cwd = opt_relativeTo || process.cwd();
  63. patterns = (typeof patterns === 'string') ? [patterns] : patterns;
  64. if (patterns) {
  65. for (let fileName of patterns) {
  66. let matches = glob.hasMagic(fileName) ? glob.sync(fileName, { cwd }) : [fileName];
  67. if (!matches.length && !opt_omitWarnings) {
  68. logger.warn('pattern ' + fileName + ' did not match any files.');
  69. }
  70. for (let match of matches) {
  71. let resolvedPath = path.resolve(cwd, match);
  72. resolvedFiles.push(resolvedPath);
  73. }
  74. }
  75. }
  76. return resolvedFiles;
  77. }
  78. /**
  79. * Returns only the specs that should run currently based on `config.suite`
  80. *
  81. * @return {Array} An array of globs locating the spec files
  82. */
  83. static getSpecs(config) {
  84. let specs = [];
  85. if (config.suite) {
  86. config.suite.split(',').forEach((suite) => {
  87. let suiteList = config.suites ? config.suites[suite] : null;
  88. if (suiteList == null) {
  89. throw new exitCodes_1.ConfigError(logger, 'Unknown test suite: ' + suite);
  90. }
  91. union(specs, makeArray(suiteList));
  92. });
  93. return specs;
  94. }
  95. if (config.specs.length > 0) {
  96. return config.specs;
  97. }
  98. Object.keys(config.suites || {}).forEach((suite) => {
  99. union(specs, makeArray(config.suites[suite]));
  100. });
  101. return specs;
  102. }
  103. /**
  104. * Add the options in the parameter config to this runner instance.
  105. *
  106. * @private
  107. * @param {Object} additionalConfig
  108. * @param {string} relativeTo the file path to resolve paths against
  109. */
  110. addConfig_(additionalConfig, relativeTo) {
  111. // All filepaths should be kept relative to the current config location.
  112. // This will not affect absolute paths.
  113. ['seleniumServerJar', 'chromeDriver', 'firefoxPath', 'frameworkPath', 'geckoDriver',
  114. 'onPrepare']
  115. .forEach((name) => {
  116. if (additionalConfig[name] && typeof additionalConfig[name] === 'string') {
  117. additionalConfig[name] = path.resolve(relativeTo, additionalConfig[name]);
  118. }
  119. });
  120. merge_(this.config_, additionalConfig);
  121. }
  122. /**
  123. * Public function specialized towards merging in a file's config
  124. *
  125. * @public
  126. * @param {String} filename
  127. */
  128. addFileConfig(filename) {
  129. if (!filename) {
  130. return this;
  131. }
  132. let filePath = path.resolve(process.cwd(), filename);
  133. let fileConfig;
  134. try {
  135. fileConfig = require(filePath).config;
  136. }
  137. catch (e) {
  138. throw new exitCodes_1.ConfigError(logger, 'failed loading configuration file ' + filename, e);
  139. }
  140. if (!fileConfig) {
  141. throw new exitCodes_1.ConfigError(logger, 'configuration file ' + filename + ' did not export a config object');
  142. }
  143. fileConfig.configDir = path.dirname(filePath);
  144. this.addConfig_(fileConfig, fileConfig.configDir);
  145. return this;
  146. }
  147. /**
  148. * Public function specialized towards merging in config from argv
  149. *
  150. * @public
  151. * @param {Object} argv
  152. */
  153. addConfig(argv) {
  154. this.addConfig_(argv, process.cwd());
  155. return this;
  156. }
  157. /**
  158. * Public getter for the final, computed config object
  159. *
  160. * @public
  161. * @return {Object} config
  162. */
  163. getConfig() {
  164. return this.config_;
  165. }
  166. }
  167. exports.ConfigParser = ConfigParser;
  168. /**
  169. * Merge config objects together.
  170. *
  171. * @private
  172. * @param {Object} into
  173. * @param {Object} from
  174. *
  175. * @return {Object} The 'into' config.
  176. */
  177. let merge_ = function (into, from) {
  178. for (let key in from) {
  179. if (into[key] instanceof Object && !(into[key] instanceof Array) &&
  180. !(into[key] instanceof Function)) {
  181. merge_(into[key], from[key]);
  182. }
  183. else {
  184. into[key] = from[key];
  185. }
  186. }
  187. return into;
  188. };
  189. /**
  190. * Returns the item if it's an array or puts the item in an array
  191. * if it was not one already.
  192. */
  193. let makeArray = function (item) {
  194. return Array.isArray(item) ? item : [item];
  195. };
  196. /**
  197. * Adds to an array all the elements in another array without adding any
  198. * duplicates
  199. *
  200. * @param {string[]} dest The array to add to
  201. * @param {string[]} src The array to copy from
  202. */
  203. let union = function (dest, src) {
  204. let elems = {};
  205. for (let key in dest) {
  206. elems[dest[key]] = true;
  207. }
  208. for (let key in src) {
  209. if (!elems[src[key]]) {
  210. dest.push(src[key]);
  211. elems[src[key]] = true;
  212. }
  213. }
  214. };
  215. //# sourceMappingURL=configParser.js.map