123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /**
- * Copied from Protractor 5.2.0
- *
- * Wait until Angular has finished rendering and has
- * no outstanding $http calls before continuing. The specific Angular app
- * is determined by the rootSelector.
- *
- * Asynchronous.
- *
- * @param {string} rootSelector The selector housing an ng-app
- * @param {function(string)} callback callback. If a failure occurs, it will
- * be passed as a parameter.
- */
- function waitForAngular(rootSelector, callback) {
- try {
- // Wait for both angular1 testability and angular2 testability.
- var testCallback = callback;
- // Wait for angular1 testability first and run waitForAngular2 as a callback
- var waitForAngular1 = function(callback) {
- if (window.angular) {
- var hooks = getNg1Hooks(rootSelector);
- if (!hooks){
- callback(); // not an angular1 app
- }
- else{
- if (hooks.$$testability) {
- hooks.$$testability.whenStable(callback);
- } else if (hooks.$injector) {
- hooks.$injector.get('$browser')
- .notifyWhenNoOutstandingRequests(callback);
- } else if (!!rootSelector) {
- throw new Error(
- 'Could not automatically find injector on page: "' +
- window.location.toString() + '". Consider using config.rootEl');
- } else {
- throw new Error(
- 'root element (' + rootSelector + ') has no injector.' +
- ' this may mean it is not inside ng-app.');
- }
- }
- }
- else {callback();} // not an angular1 app
- };
- // Wait for Angular2 testability and then run test callback
- var waitForAngular2 = function() {
- if (window.getAngularTestability) {
- if (rootSelector) {
- var testability = null;
- var el = document.querySelector(rootSelector);
- try{
- testability = window.getAngularTestability(el);
- }
- catch(e){}
- if (testability) {
- return testability.whenStable(testCallback);
- }
- }
- // Didn't specify root element or testability could not be found
- // by rootSelector. This may happen in a hybrid app, which could have
- // more than one root.
- var testabilities = window.getAllAngularTestabilities();
- var count = testabilities.length;
- // No angular2 testability, this happens when
- // going to a hybrid page and going back to a pure angular1 page
- if (count === 0) {
- return testCallback();
- }
- var decrement = function() {
- count--;
- if (count === 0) {
- testCallback();
- }
- };
- testabilities.forEach(function(testability) {
- testability.whenStable(decrement);
- });
- }
- else {testCallback();} // not an angular2 app
- };
- if (!(window.angular) && !(window.getAngularTestability)) {
- // no testability hook
- throw new Error(
- 'both angularJS testability and angular testability are undefined.' +
- ' This could be either ' +
- 'because this is a non-angular page or because your test involves ' +
- 'client-side navigation, which can interfere with Protractor\'s ' +
- 'bootstrapping. See http://git.io/v4gXM for details');
- } else {waitForAngular1(waitForAngular2);} // Wait for angular1 and angular2
- // Testability hooks sequentially
- } catch (err) {
- callback(err.message);
- }
- };
- /* Tries to find $$testability and possibly $injector for an ng1 app
- *
- * By default, doesn't care about $injector if it finds $$testability. However,
- * these priorities can be reversed.
- *
- * @param {string=} selector The selector for the element with the injector. If
- * falsy, tries a variety of methods to find an injector
- * @param {boolean=} injectorPlease Prioritize finding an injector
- * @return {$$testability?: Testability, $injector?: Injector} Returns whatever
- * ng1 app hooks it finds
- */
- function getNg1Hooks(selector, injectorPlease) {
- function tryEl(el) {
- try {
- if (!injectorPlease && angular.getTestability) {
- var $$testability = angular.getTestability(el);
- if ($$testability) {
- return {$$testability: $$testability};
- }
- } else {
- var $injector = angular.element(el).injector();
- if ($injector) {
- return {$injector: $injector};
- }
- }
- } catch(err) {}
- }
- function trySelector(selector) {
- var els = document.querySelectorAll(selector);
- for (var i = 0; i < els.length; i++) {
- var elHooks = tryEl(els[i]);
- if (elHooks) {
- return elHooks;
- }
- }
- }
- if (selector) {
- return trySelector(selector);
- } else if (window.__TESTABILITY__NG1_APP_ROOT_INJECTOR__) {
- var $injector = window.__TESTABILITY__NG1_APP_ROOT_INJECTOR__;
- var $$testability = null;
- try {
- $$testability = $injector.get('$$testability');
- } catch (e) {}
- return {$injector: $injector, $$testability: $$testability};
- } else {
- return tryEl(document.body) ||
- trySelector('[ng-app]') || trySelector('[ng\\:app]') ||
- trySelector('[ng-controller]') || trySelector('[ng\\:controller]');
- }
- }
- /* Wraps a function up into a string with its helper functions so that it can
- * call those helper functions client side
- *
- * @param {function} fun The function to wrap up with its helpers
- * @param {...function} The helper functions. Each function must be named
- *
- * @return {string} The string which, when executed, will invoke fun in such a
- * way that it has access to its helper functions
- */
- function wrapWithHelpers(fun) {
- var helpers = Array.prototype.slice.call(arguments, 1);
- if (!helpers.length) {
- return fun;
- }
- var FunClass = Function; // Get the linter to allow this eval
- return new FunClass(
- helpers.join(';') + String.fromCharCode(59) +
- ' return (' + fun.toString() + ').apply(this, arguments);');
- }
- exports.NG_WAIT_FN = wrapWithHelpers(waitForAngular, getNg1Hooks);
|