Skip to content

Commit 9c5b326

Browse files
committed
feat(browser): chain promises in lib/browser.ts and return promise from waitForAngularEnabled
Minor breaking change since `waitForAngularEnabled` no longer returns a boolean Closes angular#3904
1 parent f11fece commit 9c5b326

File tree

1 file changed

+120
-109
lines changed

1 file changed

+120
-109
lines changed

lib/browser.ts

+120-109
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,16 @@ function ptorMixin(to: any, from: any, fnName: string, setupFn?: Function) {
8888
arguments[i] = arguments[i].getWebElement();
8989
}
9090
}
91+
const run = () => {
92+
return from[fnName].apply(from, arguments);
93+
};
9194
if (setupFn) {
92-
setupFn();
95+
const setupResult = setupFn();
96+
if (setupResult && (typeof setupResult.then === 'function')) {
97+
return setupResult.then(run);
98+
}
9399
}
94-
return from[fnName].apply(from, arguments);
100+
return run();
95101
};
96102
};
97103

@@ -206,13 +212,7 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver {
206212
* @type {boolean}
207213
*/
208214
set ignoreSynchronization(value) {
209-
this.driver.controlFlow().execute(() => {
210-
if (this.bpClient) {
211-
logger.debug('Setting waitForAngular' + value);
212-
this.bpClient.setSynchronization(!value);
213-
}
214-
}, `Set proxy synchronization to ${value}`);
215-
this.internalIgnoreSynchronization = value;
215+
this.waitForAngularEnabled(!value);
216216
}
217217

218218
get ignoreSynchronization() {
@@ -403,11 +403,20 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver {
403403
* Call waitForAngularEnabled() without passing a value to read the current
404404
* state without changing it.
405405
*/
406-
waitForAngularEnabled(enabled: boolean = null): boolean {
406+
waitForAngularEnabled(enabled: boolean = null): wdpromise.Promise<boolean> {
407407
if (enabled != null) {
408-
this.ignoreSynchronization = !enabled;
408+
const ret = this.driver.controlFlow().execute(() => {
409+
if (this.bpClient) {
410+
logger.debug('Setting waitForAngular' + !enabled);
411+
return this.bpClient.setSynchronization(enabled).then(() => {
412+
return enabled;
413+
});
414+
}
415+
}, `Set proxy synchronization enabled to ${enabled}`);
416+
this.internalIgnoreSynchronization = !enabled;
417+
return ret;
409418
}
410-
return !this.ignoreSynchronization;
419+
return wdpromise.when(!this.ignoreSynchronization);
411420
}
412421

413422
/**
@@ -613,7 +622,9 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver {
613622

614623
let runWaitForAngularScript: () => wdpromise.Promise<any> = () => {
615624
if (this.plugins_.skipAngularStability() || this.bpClient) {
616-
return wdpromise.fulfilled();
625+
return this.driver.controlFlow().execute(() => {
626+
return true;
627+
}, 'A plugin has set skipAngularStability');
617628
} else {
618629
return this.executeAsyncScript_(
619630
clientSideScripts.waitForAngular, 'Protractor.waitForAngular()' + description,
@@ -837,79 +848,84 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver {
837848
return 'Protractor.get(' + destination + ') - ' + str;
838849
};
839850

851+
let retPromise: wdpromise.Promise<any>;
852+
let then = (fn: () => wdpromise.Promise<any>) => {
853+
if (retPromise) {
854+
return (retPromise = retPromise.then(fn));
855+
} else {
856+
return (retPromise = fn());
857+
}
858+
};
859+
840860
if (this.bpClient) {
841-
this.driver.controlFlow().execute(() => {
861+
then(() => this.driver.controlFlow().execute(() => {
842862
return this.bpClient.setSynchronization(false);
843-
});
863+
}));
844864
}
845865

846866
if (this.ignoreSynchronization) {
847-
this.driver.get(destination);
848-
return this.driver.controlFlow().execute(() => this.plugins_.onPageLoad()).then(() => {});
867+
then(() => this.driver.get(destination));
868+
return then(() => this.driver.controlFlow().execute(() => this.plugins_.onPageLoad()))
869+
.then(() => {});
849870
}
850871

851-
let deferred = wdpromise.defer<void>();
852-
853-
this.driver.get(this.resetUrl).then(null, deferred.reject);
854-
this.executeScriptWithDescription(
872+
then(() => this.driver.get(this.resetUrl));
873+
then(
874+
() => this.executeScriptWithDescription(
855875
'window.name = "' + DEFER_LABEL + '" + window.name;' +
856876
'window.location.replace("' + destination + '");',
857-
msg('reset url'))
858-
.then(null, deferred.reject);
877+
msg('reset url')));
859878

860879
// We need to make sure the new url has loaded before
861880
// we try to execute any asynchronous scripts.
862-
this.driver
863-
.wait(
864-
() => {
865-
return this
866-
.executeScriptWithDescription('return window.location.href;', msg('get url'))
867-
.then(
868-
(url: any) => {
869-
return url !== this.resetUrl;
870-
},
871-
(err: IError) => {
872-
if (err.code == 13) {
873-
// Ignore the error, and continue trying. This is
874-
// because IE driver sometimes (~1%) will throw an
875-
// unknown error from this execution. See
876-
// https://github.com/angular/protractor/issues/841
877-
// This shouldn't mask errors because it will fail
878-
// with the timeout anyway.
879-
return false;
880-
} else {
881-
throw err;
882-
}
883-
});
884-
},
885-
timeout, 'waiting for page to load for ' + timeout + 'ms')
886-
.then(null, deferred.reject);
881+
then(() => this.driver.wait(() => {
882+
return this.executeScriptWithDescription('return window.location.href;', msg('get url'))
883+
.then(
884+
(url: any) => {
885+
return url !== this.resetUrl;
886+
},
887+
(err: IError) => {
888+
if (err.code == 13) {
889+
// Ignore the error, and continue trying. This is
890+
// because IE driver sometimes (~1%) will throw an
891+
// unknown error from this execution. See
892+
// https://github.com/angular/protractor/issues/841
893+
// This shouldn't mask errors because it will fail
894+
// with the timeout anyway.
895+
return false;
896+
} else {
897+
throw err;
898+
}
899+
});
900+
}, timeout, 'waiting for page to load for ' + timeout + 'ms'));
887901

888-
this.driver.controlFlow().execute(() => {
902+
then(() => this.driver.controlFlow().execute(() => {
889903
return this.plugins_.onPageLoad();
890-
});
904+
}));
891905

892906
// Make sure the page is an Angular page.
893-
this.executeAsyncScript_(
894-
clientSideScripts.testForAngular, msg('test for angular'), Math.floor(timeout / 1000),
895-
this.ng12Hybrid)
896-
.then(
897-
(angularTestResult: {ver: number, message: string}) => {
898-
let angularVersion = angularTestResult.ver;
899-
if (!angularVersion) {
900-
let message = angularTestResult.message;
901-
logger.error(`Could not find Angular on page ${destination} : ${message}`);
902-
throw new Error(
903-
`Angular could not be found on the page ${destination}. If this is not an ` +
904-
`Angular application, you may need to turn off waiting for Angular. Please ` +
905-
`see https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular-on-page-load`);
906-
}
907-
return angularVersion;
908-
},
909-
(err: Error) => {
910-
throw new Error('Error while running testForAngular: ' + err.message);
911-
})
912-
.then(loadMocks, deferred.reject);
907+
then(
908+
() =>
909+
this.executeAsyncScript_(
910+
clientSideScripts.testForAngular, msg('test for angular'),
911+
Math.floor(timeout / 1000), this.ng12Hybrid)
912+
.then(
913+
(angularTestResult: {ver: number, message: string}) => {
914+
let angularVersion = angularTestResult.ver;
915+
if (!angularVersion) {
916+
let message = angularTestResult.message;
917+
logger.error(`Could not find Angular on page ${destination} : ${message}`);
918+
throw new Error(
919+
`Angular could not be found on the page ${destination
920+
}. If this is not an ` +
921+
`Angular application, you may need to turn off waiting for Angular. Please ` +
922+
`see https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular-on-page-load`);
923+
}
924+
return angularVersion;
925+
},
926+
(err: Error) => {
927+
throw new Error('Error while running testForAngular: ' + err.message);
928+
}));
913929

914930
let self = this;
915931
function loadMocks(angularVersion: number) {
@@ -919,45 +935,40 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver {
919935
for (const {name, script, args} of self.mockModules_) {
920936
moduleNames.push(name);
921937
let executeScriptArgs = [script, msg('add mock module ' + name), ...args];
922-
self.executeScriptWithDescription.apply(self, executeScriptArgs)
923-
.then(
924-
null,
925-
(err: Error) => {
926-
throw new Error(
927-
'Error while running module script ' + name + ': ' + err.message);
928-
})
929-
.then(null, deferred.reject);
938+
then(
939+
() => self.executeScriptWithDescription.apply(self, executeScriptArgs)
940+
.then(null, (err: Error) => {
941+
throw new Error(
942+
'Error while running module script ' + name + ': ' + err.message);
943+
}));
930944
}
931945

932-
self.executeScriptWithDescription(
946+
then(
947+
() => self.executeScriptWithDescription(
933948
'window.__TESTABILITY__NG1_APP_ROOT_INJECTOR__ = ' +
934949
'angular.resumeBootstrap(arguments[0]);',
935-
msg('resume bootstrap'), moduleNames)
936-
.then(null, deferred.reject);
950+
msg('resume bootstrap'), moduleNames));
937951
} else {
938952
// TODO: support mock modules in Angular2. For now, error if someone
939953
// has tried to use one.
940954
if (self.mockModules_.length > 1) {
941-
deferred.reject(
942-
'Trying to load mock modules on an Angular2 app ' +
943-
'is not yet supported.');
955+
then(() => {
956+
throw 'Trying to load mock modules on an Angular2 app is not yet supported.';
957+
});
944958
}
945959
}
946960
}
947961

948962
if (this.bpClient) {
949-
this.driver.controlFlow().execute(() => {
963+
then(() => this.driver.controlFlow().execute(() => {
950964
return this.bpClient.setSynchronization(!this.internalIgnoreSynchronization);
951-
});
965+
}));
952966
}
953967

954-
this.driver.controlFlow().execute(() => {
955-
return this.plugins_.onPageStable().then(() => {
956-
deferred.fulfill();
957-
}, deferred.reject);
958-
});
959-
960-
return deferred.promise;
968+
return then(() => this.driver.controlFlow().execute(() => {
969+
return this.plugins_.onPageStable();
970+
}))
971+
.then(() => {});
961972
}
962973

963974
/**
@@ -1007,15 +1018,15 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver {
10071018
* page has been changed.
10081019
*/
10091020
setLocation(url: string): wdpromise.Promise<any> {
1010-
this.waitForAngular();
1011-
return this
1012-
.executeScriptWithDescription(
1013-
clientSideScripts.setLocation, 'Protractor.setLocation()', this.rootEl, url)
1014-
.then((browserErr: Error) => {
1015-
if (browserErr) {
1016-
throw 'Error while navigating to \'' + url + '\' : ' + JSON.stringify(browserErr);
1017-
}
1018-
});
1021+
return this.waitForAngular().then(
1022+
() => this.executeScriptWithDescription(
1023+
clientSideScripts.setLocation, 'Protractor.setLocation()', this.rootEl, url)
1024+
.then((browserErr: Error) => {
1025+
if (browserErr) {
1026+
throw 'Error while navigating to \'' + url + '\' : ' +
1027+
JSON.stringify(browserErr);
1028+
}
1029+
}));
10191030
}
10201031

10211032
/**
@@ -1029,9 +1040,9 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver {
10291040
* AngularJS.
10301041
*/
10311042
getLocationAbsUrl(): wdpromise.Promise<any> {
1032-
this.waitForAngular();
1033-
return this.executeScriptWithDescription(
1034-
clientSideScripts.getLocationAbsUrl, 'Protractor.getLocationAbsUrl()', this.rootEl);
1043+
return this.waitForAngular().then(
1044+
() => this.executeScriptWithDescription(
1045+
clientSideScripts.getLocationAbsUrl, 'Protractor.getLocationAbsUrl()', this.rootEl));
10351046
}
10361047

10371048
/**
@@ -1056,10 +1067,10 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver {
10561067
*/
10571068
debugger() {
10581069
// jshint debug: true
1059-
this.driver.executeScript(clientSideScripts.installInBrowser);
1060-
wdpromise.controlFlow().execute(() => {
1061-
debugger;
1062-
}, 'add breakpoint to control flow');
1070+
return this.driver.executeScript(clientSideScripts.installInBrowser)
1071+
.then(() => wdpromise.controlFlow().execute(() => {
1072+
debugger;
1073+
}, 'add breakpoint to control flow'));
10631074
}
10641075

10651076
/**

0 commit comments

Comments
 (0)