index.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. // Licensed to the Software Freedom Conservancy (SFC) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The SFC licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. 'use strict';
  18. var assert = require('assert');
  19. var build = require('./build'),
  20. isDevMode = require('../devmode'),
  21. webdriver = require('../../'),
  22. flow = webdriver.promise.controlFlow(),
  23. firefox = require('../../firefox'),
  24. logging = require('../../lib/logging'),
  25. safari = require('../../safari'),
  26. remote = require('../../remote'),
  27. testing = require('../../testing'),
  28. fileserver = require('./fileserver');
  29. /**
  30. * Browsers with native support.
  31. * @type {!Array.<webdriver.Browser>}
  32. */
  33. var NATIVE_BROWSERS = [
  34. webdriver.Browser.CHROME,
  35. webdriver.Browser.EDGE,
  36. webdriver.Browser.FIREFOX,
  37. webdriver.Browser.IE,
  38. webdriver.Browser.OPERA,
  39. webdriver.Browser.PHANTOM_JS,
  40. webdriver.Browser.SAFARI
  41. ];
  42. var noBuild = /^1|true$/i.test(process.env['SELENIUM_NO_BUILD']);
  43. var serverJar = process.env['SELENIUM_SERVER_JAR'];
  44. var remoteUrl = process.env['SELENIUM_REMOTE_URL'];
  45. var useLoopback = process.env['SELENIUM_USE_LOOP_BACK'] == '1';
  46. var startServer = !!serverJar && !remoteUrl;
  47. var nativeRun = !serverJar && !remoteUrl;
  48. if (/^1|true$/i.test(process.env['SELENIUM_VERBOSE'])) {
  49. logging.installConsoleHandler();
  50. logging.getLogger('webdriver.http').setLevel(logging.Level.ALL);
  51. }
  52. var browsersToTest = (function() {
  53. var permitRemoteBrowsers = !!remoteUrl || !!serverJar;
  54. var permitUnknownBrowsers = !nativeRun;
  55. var browsers = process.env['SELENIUM_BROWSER'] || webdriver.Browser.FIREFOX;
  56. browsers = browsers.split(',').map(function(browser) {
  57. var parts = browser.split(/:/);
  58. if (parts[0] === 'ie') {
  59. parts[0] = webdriver.Browser.IE;
  60. }
  61. if (parts[0] === 'edge') {
  62. parts[0] = webdriver.Browser.EDGE;
  63. }
  64. return parts.join(':');
  65. });
  66. browsers.forEach(function(browser) {
  67. var parts = browser.split(/:/, 3);
  68. if (parts[0] === 'ie') {
  69. parts[0] = webdriver.Browser.IE;
  70. }
  71. if (NATIVE_BROWSERS.indexOf(parts[0]) == -1 && !permitRemoteBrowsers) {
  72. throw Error('Browser ' + parts[0] + ' requires a WebDriver server and ' +
  73. 'neither the SELENIUM_REMOTE_URL nor the SELENIUM_SERVER_JAR ' +
  74. 'environment variables have been set.');
  75. }
  76. var recognized = false;
  77. for (var prop in webdriver.Browser) {
  78. if (webdriver.Browser.hasOwnProperty(prop) &&
  79. webdriver.Browser[prop] === parts[0]) {
  80. recognized = true;
  81. break;
  82. }
  83. }
  84. if (!recognized && !permitUnknownBrowsers) {
  85. throw Error('Unrecognized browser: ' + browser);
  86. }
  87. });
  88. console.log('Running tests against [' + browsers.join(',') + ']');
  89. if (remoteUrl) {
  90. console.log('Using remote server ' + remoteUrl);
  91. } else if (serverJar) {
  92. console.log('Using standalone Selenium server ' + serverJar);
  93. if (useLoopback) {
  94. console.log('Running tests using loopback address')
  95. }
  96. }
  97. console.log(
  98. 'Promise manager is enabled? ' + webdriver.promise.USE_PROMISE_MANAGER);
  99. return browsers;
  100. })();
  101. /**
  102. * Creates a predicate function that ignores tests for specific browsers.
  103. * @param {string} currentBrowser The name of the current browser.
  104. * @param {!Array.<!Browser>} browsersToIgnore The browsers to ignore.
  105. * @return {function(): boolean} The predicate function.
  106. */
  107. function browsers(currentBrowser, browsersToIgnore) {
  108. return function() {
  109. return browsersToIgnore.indexOf(currentBrowser) != -1;
  110. };
  111. }
  112. /**
  113. * @param {string} browserName The name to use.
  114. * @param {remote.DriverService} server The server to use, if any.
  115. * @constructor
  116. */
  117. function TestEnvironment(browserName, server) {
  118. var name = browserName;
  119. this.currentBrowser = function() {
  120. return browserName;
  121. };
  122. this.isRemote = function() {
  123. return server || remoteUrl;
  124. };
  125. this.browsers = function(var_args) {
  126. var browsersToIgnore = Array.prototype.slice.apply(arguments, [0]);
  127. return browsers(browserName, browsersToIgnore);
  128. };
  129. this.builder = function() {
  130. var builder = new webdriver.Builder();
  131. var realBuild = builder.build;
  132. builder.build = function() {
  133. let parts = browserName.split(/:/, 3);
  134. builder.forBrowser(parts[0], parts[1], parts[2]);
  135. if (server) {
  136. builder.usingServer(server.address());
  137. } else if (remoteUrl) {
  138. builder.usingServer(remoteUrl);
  139. }
  140. builder.disableEnvironmentOverrides();
  141. return realBuild.call(builder);
  142. };
  143. return builder;
  144. };
  145. }
  146. var seleniumServer;
  147. var inSuite = false;
  148. /**
  149. * Expands a function to cover each of the target browsers.
  150. * @param {function(!TestEnvironment)} fn The top level suite
  151. * function.
  152. * @param {{browsers: !Array.<string>}=} opt_options Suite specific options.
  153. */
  154. function suite(fn, opt_options) {
  155. assert.ok(!inSuite, 'You may not nest suite calls');
  156. inSuite = true;
  157. var suiteOptions = opt_options || {};
  158. var browsers = suiteOptions.browsers;
  159. if (browsers) {
  160. // Filter out browser specific tests when that browser is not currently
  161. // selected for testing.
  162. browsers = browsers.filter(function(browser) {
  163. return browsersToTest.indexOf(browser) != -1;
  164. });
  165. } else {
  166. browsers = browsersToTest;
  167. }
  168. try {
  169. before(function() {
  170. if (isDevMode && !noBuild) {
  171. return build.of(
  172. '//javascript/atoms/fragments:is-displayed',
  173. '//javascript/webdriver/atoms:get-attribute')
  174. .onlyOnce().go();
  175. }
  176. });
  177. // Server is only started if required for a specific config.
  178. after(function() {
  179. if (seleniumServer) {
  180. return seleniumServer.stop();
  181. }
  182. });
  183. browsers.forEach(function(browser) {
  184. describe('[' + browser + ']', function() {
  185. var serverToUse = null;
  186. if (!!serverJar && !remoteUrl) {
  187. if (!(serverToUse = seleniumServer)) {
  188. serverToUse = seleniumServer = new remote.SeleniumServer(
  189. serverJar, {loopback: useLoopback});
  190. }
  191. before(function() {
  192. this.timeout(0);
  193. return seleniumServer.start(60 * 1000);
  194. });
  195. }
  196. fn(new TestEnvironment(browser, serverToUse));
  197. });
  198. });
  199. } finally {
  200. inSuite = false;
  201. }
  202. }
  203. // GLOBAL TEST SETUP
  204. before(function() {
  205. // Do not pass register fileserver.start directly with testing.before,
  206. // as start takes an optional port, which before assumes is an async
  207. // callback.
  208. return fileserver.start();
  209. });
  210. after(function() {
  211. return fileserver.stop();
  212. });
  213. // PUBLIC API
  214. exports.suite = suite;
  215. exports.after = testing.after;
  216. exports.afterEach = testing.afterEach;
  217. exports.before = testing.before;
  218. exports.beforeEach = testing.beforeEach;
  219. exports.it = testing.it;
  220. exports.ignore = testing.ignore;
  221. exports.Pages = fileserver.Pages;
  222. exports.whereIs = fileserver.whereIs;