From 33593cf8a29c6b03068c415bf1308a9429a1cd1a Mon Sep 17 00:00:00 2001 From: Marc Laval Date: Thu, 27 Aug 2015 17:44:59 +0200 Subject: [PATCH] fix(build): Use Angular's testability API to wait for end of e2e tests Closes #3911 --- .../core/testability/browser_testability.dart | 7 ++++++- .../core/testability/browser_testability.ts | 2 ++ .../src/core/testability/testability.ts | 4 +++- modules/angular2/src/test_lib/perf_util.ts | 4 +++- .../e2e_test/change_detection_perf.ts | 18 ++++++++++++------ modules/benchmarks/e2e_test/di_perf.ts | 18 ++++++++++++------ .../e2e_test/element_injector_perf.ts | 6 ++++-- modules/benchmarks/e2e_test/selector_perf.ts | 9 ++++++--- .../e2e_test/compiler_perf.ts | 6 ++++-- .../e2e_test/largetable_perf.ts | 3 ++- .../e2e_test/naive_infinite_scroll_perf.ts | 3 ++- .../e2e_test/polymer_tree_perf.ts | 3 ++- .../e2e_test/react_tree_perf.ts | 6 ++++-- .../e2e_test/static_tree_perf.ts | 10 +++++++--- .../benchmarks_external/e2e_test/tree_perf.ts | 3 ++- .../kitchen_sink/kitchen_sink_spec.ts | 11 +++++++---- .../message_broker/message_broker_spec.ts | 8 +++++--- .../e2e_test/web_workers/todo/todo_spec.ts | 5 +++-- protractor-shared.js | 17 ++++++++++++++++- 19 files changed, 102 insertions(+), 41 deletions(-) diff --git a/modules/angular2/src/core/testability/browser_testability.dart b/modules/angular2/src/core/testability/browser_testability.dart index fb4d2c09b0..5b48cb5c9c 100644 --- a/modules/angular2/src/core/testability/browser_testability.dart +++ b/modules/angular2/src/core/testability/browser_testability.dart @@ -63,6 +63,10 @@ class PublicTestability implements _JsObjectProxyable { this._testability = testability; } + bool isStable() { + return this._testability.isStable(); + } + whenStable(Function callback) { return this._testability.whenStable(callback); } @@ -75,7 +79,8 @@ class PublicTestability implements _JsObjectProxyable { return _jsify({ 'findBindings': (bindingString, [exactMatch, allowNonElementNodes]) => findBindings(bindingString, exactMatch, allowNonElementNodes), - 'whenStable': (callback) => whenStable(() => callback.apply([])), + 'isStable': () => isStable(), + 'whenStable': (callback) => whenStable(() => callback.apply([])) })..['_dart_'] = this; } } diff --git a/modules/angular2/src/core/testability/browser_testability.ts b/modules/angular2/src/core/testability/browser_testability.ts index de9fcefc4e..9a094911a3 100644 --- a/modules/angular2/src/core/testability/browser_testability.ts +++ b/modules/angular2/src/core/testability/browser_testability.ts @@ -11,6 +11,8 @@ class PublicTestability { constructor(testability: Testability) { this._testability = testability; } + isStable(): boolean { return this._testability.isStable(); } + whenStable(callback: Function) { this._testability.whenStable(callback); } findBindings(using: any, binding: string, exactMatch: boolean): any[] { diff --git a/modules/angular2/src/core/testability/testability.ts b/modules/angular2/src/core/testability/testability.ts index e4acb1ec85..5fe76ea364 100644 --- a/modules/angular2/src/core/testability/testability.ts +++ b/modules/angular2/src/core/testability/testability.ts @@ -42,8 +42,10 @@ export class Testability { return this._pendingCount; } + isStable(): boolean { return this._pendingCount == 0 && !this._isAngularEventPending; } + _runCallbacksIfReady(): void { - if (this._pendingCount != 0 || this._isAngularEventPending) { + if (!this.isStable()) { return; // Not ready } diff --git a/modules/angular2/src/test_lib/perf_util.ts b/modules/angular2/src/test_lib/perf_util.ts index 1433322d8a..9344172165 100644 --- a/modules/angular2/src/test_lib/perf_util.ts +++ b/modules/angular2/src/test_lib/perf_util.ts @@ -24,7 +24,9 @@ export function runBenchmark(config) { }); } var url = encodeURI(config.url + '?' + urlParams.join('&')); - return browser.get(url).then(function() { + var getter = config.waitForAngular2 !== false ? browser.get(url) : + browser.driver.get(browser.baseUrl + url); + return getter.then(function() { return global['benchpressRunner'].sample({ id: config.id, execute: config.work, diff --git a/modules/benchmarks/e2e_test/change_detection_perf.ts b/modules/benchmarks/e2e_test/change_detection_perf.ts index e9e01de873..4ce66b5b1d 100644 --- a/modules/benchmarks/e2e_test/change_detection_perf.ts +++ b/modules/benchmarks/e2e_test/change_detection_perf.ts @@ -15,7 +15,8 @@ describe('ng2 change detection benchmark', function() { {name: 'numberOfChecks', value: 900000}, {name: 'iterations', value: 20, scale: 'linear'} ], - microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'} + microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}, + waitForAngular2: false }).then(done, done.fail); }); @@ -28,7 +29,8 @@ describe('ng2 change detection benchmark', function() { {name: 'numberOfChecks', value: 900000}, {name: 'iterations', value: 20, scale: 'linear'} ], - microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'} + microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}, + waitForAngular2: false }).then(done, done.fail); }); @@ -41,7 +43,8 @@ describe('ng2 change detection benchmark', function() { {name: 'numberOfChecks', value: 900000}, {name: 'iterations', value: 20, scale: 'linear'} ], - microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'} + microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}, + waitForAngular2: false }).then(done, done.fail); }); @@ -54,7 +57,8 @@ describe('ng2 change detection benchmark', function() { {name: 'numberOfChecks', value: 900000}, {name: 'iterations', value: 20, scale: 'linear'} ], - microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'} + microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}, + waitForAngular2: false }).then(done, done.fail); }); @@ -67,7 +71,8 @@ describe('ng2 change detection benchmark', function() { {name: 'numberOfChecks', value: 900000}, {name: 'iterations', value: 20, scale: 'linear'} ], - microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'} + microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}, + waitForAngular2: false }).then(done, done.fail); }); @@ -80,7 +85,8 @@ describe('ng2 change detection benchmark', function() { {name: 'numberOfChecks', value: 900000}, {name: 'iterations', value: 20, scale: 'linear'} ], - microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'} + microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}, + waitForAngular2: false }).then(done, done.fail); }); diff --git a/modules/benchmarks/e2e_test/di_perf.ts b/modules/benchmarks/e2e_test/di_perf.ts index 1db7084026..4b2ba8410a 100644 --- a/modules/benchmarks/e2e_test/di_perf.ts +++ b/modules/benchmarks/e2e_test/di_perf.ts @@ -12,7 +12,8 @@ describe('ng2 di benchmark', function() { buttons: ['#getByToken'], id: 'ng2.di.getByToken', params: [{name: 'iterations', value: 20000, scale: 'linear'}], - microMetrics: {'injectAvg': 'avg time for injection (in ms)'} + microMetrics: {'injectAvg': 'avg time for injection (in ms)'}, + waitForAngular2: false }).then(done, done.fail); }); @@ -22,7 +23,8 @@ describe('ng2 di benchmark', function() { buttons: ['#getByKey'], id: 'ng2.di.getByKey', params: [{name: 'iterations', value: 20000, scale: 'linear'}], - microMetrics: {'injectAvg': 'avg time for injection (in ms)'} + microMetrics: {'injectAvg': 'avg time for injection (in ms)'}, + waitForAngular2: false }).then(done, done.fail); }); @@ -32,7 +34,8 @@ describe('ng2 di benchmark', function() { buttons: ['#getChild'], id: 'ng2.di.getChild', params: [{name: 'iterations', value: 20000, scale: 'linear'}], - microMetrics: {'injectAvg': 'avg time for getChild (in ms)'} + microMetrics: {'injectAvg': 'avg time for getChild (in ms)'}, + waitForAngular2: false }).then(done, done.fail); }); @@ -42,7 +45,8 @@ describe('ng2 di benchmark', function() { buttons: ['#instantiate'], id: 'ng2.di.instantiate', params: [{name: 'iterations', value: 10000, scale: 'linear'}], - microMetrics: {'injectAvg': 'avg time for instantiate (in ms)'} + microMetrics: {'injectAvg': 'avg time for instantiate (in ms)'}, + waitForAngular2: false }).then(done, done.fail); }); @@ -56,7 +60,8 @@ describe('ng2 di benchmark', function() { buttons: ['#createVariety'], id: 'ng2.di.createVariety', params: [{name: 'iterations', value: 10000, scale: 'linear'}], - microMetrics: {'injectAvg': 'avg time for createVariety (in ms)'} + microMetrics: {'injectAvg': 'avg time for createVariety (in ms)'}, + waitForAngular2: false }).then(done, done.fail); }); @@ -69,7 +74,8 @@ describe('ng2 di benchmark', function() { buttons: ['#createVarietyResolved'], id: 'ng2.di.createVarietyResolved', params: [{name: 'iterations', value: 10000, scale: 'linear'}], - microMetrics: {'injectAvg': 'avg time for createVarietyResolved (in ms)'} + microMetrics: {'injectAvg': 'avg time for createVarietyResolved (in ms)'}, + waitForAngular2: false }).then(done, done.fail); }); diff --git a/modules/benchmarks/e2e_test/element_injector_perf.ts b/modules/benchmarks/e2e_test/element_injector_perf.ts index a82fb28349..c6e3dbf9bf 100644 --- a/modules/benchmarks/e2e_test/element_injector_perf.ts +++ b/modules/benchmarks/e2e_test/element_injector_perf.ts @@ -12,7 +12,8 @@ describe('ng2 element injector benchmark', function() { buttons: ['#instantiate'], id: 'ng2.elementInjector.instantiate', params: [{name: 'iterations', value: 20000, scale: 'linear'}], - microMetrics: {'instantiateAvg': 'avg time for injection (in ms)'} + microMetrics: {'instantiateAvg': 'avg time for injection (in ms)'}, + waitForAngular2: false }).then(done, done.fail); }); @@ -22,7 +23,8 @@ describe('ng2 element injector benchmark', function() { buttons: ['#hydrate'], id: 'ng2.elementInjector.hydrate', params: [{name: 'iterations', value: 20000, scale: 'linear'}], - microMetrics: {'instantiateAvg': 'avg time for injection (in ms)'} + microMetrics: {'instantiateAvg': 'avg time for injection (in ms)'}, + waitForAngular2: false }).then(done, done.fail); }); diff --git a/modules/benchmarks/e2e_test/selector_perf.ts b/modules/benchmarks/e2e_test/selector_perf.ts index 2ba41763ac..6fbdbdd803 100644 --- a/modules/benchmarks/e2e_test/selector_perf.ts +++ b/modules/benchmarks/e2e_test/selector_perf.ts @@ -11,7 +11,8 @@ describe('ng2 selector benchmark', function() { url: URL, buttons: ['#parse'], id: 'ng2.selector.parse', - params: [{name: 'selectors', value: 10000, scale: 'linear'}] + params: [{name: 'selectors', value: 10000, scale: 'linear'}], + waitForAngular2: false }).then(done, done.fail); }); @@ -20,7 +21,8 @@ describe('ng2 selector benchmark', function() { url: URL, buttons: ['#addSelectable'], id: 'ng2.selector.addSelectable', - params: [{name: 'selectors', value: 10000, scale: 'linear'}] + params: [{name: 'selectors', value: 10000, scale: 'linear'}], + waitForAngular2: false }).then(done, done.fail); }); @@ -29,7 +31,8 @@ describe('ng2 selector benchmark', function() { url: URL, buttons: ['#match'], id: 'ng2.selector.match', - params: [{name: 'selectors', value: 10000, scale: 'linear'}] + params: [{name: 'selectors', value: 10000, scale: 'linear'}], + waitForAngular2: false }).then(done, done.fail); }); diff --git a/modules/benchmarks_external/e2e_test/compiler_perf.ts b/modules/benchmarks_external/e2e_test/compiler_perf.ts index df99e61b54..d424be20f4 100644 --- a/modules/benchmarks_external/e2e_test/compiler_perf.ts +++ b/modules/benchmarks_external/e2e_test/compiler_perf.ts @@ -11,7 +11,8 @@ describe('ng1.x compiler benchmark', function() { url: URL, buttons: ['#compileWithBindings'], id: 'ng1.compile.withBindings', - params: [{name: 'elements', value: 150, scale: 'linear'}] + params: [{name: 'elements', value: 150, scale: 'linear'}], + waitForAngular2: false }).then(done, done.fail); }); @@ -20,7 +21,8 @@ describe('ng1.x compiler benchmark', function() { url: URL, buttons: ['#compileNoBindings'], id: 'ng1.compile.noBindings', - params: [{name: 'elements', value: 150, scale: 'linear'}] + params: [{name: 'elements', value: 150, scale: 'linear'}], + waitForAngular2: false }).then(done, done.fail); }); diff --git a/modules/benchmarks_external/e2e_test/largetable_perf.ts b/modules/benchmarks_external/e2e_test/largetable_perf.ts index 4fcaf491d4..8d1d9657ba 100644 --- a/modules/benchmarks_external/e2e_test/largetable_perf.ts +++ b/modules/benchmarks_external/e2e_test/largetable_perf.ts @@ -17,7 +17,8 @@ describe('ng1.x largetable benchmark', function() { {name: 'columns', value: 100, scale: 'sqrt'}, {name: 'rows', value: 20, scale: 'sqrt'}, {name: 'benchmarkType', value: benchmarkType} - ] + ], + waitForAngular2: false }).then(done, done.fail); }); }); diff --git a/modules/benchmarks_external/e2e_test/naive_infinite_scroll_perf.ts b/modules/benchmarks_external/e2e_test/naive_infinite_scroll_perf.ts index 630a64aead..817f4db60d 100644 --- a/modules/benchmarks_external/e2e_test/naive_infinite_scroll_perf.ts +++ b/modules/benchmarks_external/e2e_test/naive_infinite_scroll_perf.ts @@ -24,7 +24,8 @@ describe('ng-dart1.x naive infinite scroll benchmark', function() { {name: 'appSize', value: appSize}, {name: 'iterationCount', value: 20, scale: 'linear'}, {name: 'scrollIncrement', value: 40} - ] + ], + waitForAngular2: false }).then(done, done.fail); }); }); diff --git a/modules/benchmarks_external/e2e_test/polymer_tree_perf.ts b/modules/benchmarks_external/e2e_test/polymer_tree_perf.ts index 85e3d44e66..86b974f71e 100644 --- a/modules/benchmarks_external/e2e_test/polymer_tree_perf.ts +++ b/modules/benchmarks_external/e2e_test/polymer_tree_perf.ts @@ -11,7 +11,8 @@ describe('polymer tree benchmark', function() { url: URL, buttons: ['#destroyDom', '#createDom'], id: 'polymer.tree', - params: [{name: 'depth', value: 9, scale: 'log2'}] + params: [{name: 'depth', value: 9, scale: 'log2'}], + waitForAngular2: false }).then(done, done.fail); }); diff --git a/modules/benchmarks_external/e2e_test/react_tree_perf.ts b/modules/benchmarks_external/e2e_test/react_tree_perf.ts index 496de81174..3b6994d237 100644 --- a/modules/benchmarks_external/e2e_test/react_tree_perf.ts +++ b/modules/benchmarks_external/e2e_test/react_tree_perf.ts @@ -11,7 +11,8 @@ describe('react tree benchmark', function() { url: URL, buttons: ['#destroyDom', '#createDom'], id: 'react.tree.create', - params: [{name: 'depth', value: 9, scale: 'log2'}] + params: [{name: 'depth', value: 9, scale: 'log2'}], + waitForAngular2: false }).then(done, done.fail); }); @@ -20,7 +21,8 @@ describe('react tree benchmark', function() { url: URL, buttons: ['#createDom'], id: 'react.tree.update', - params: [{name: 'depth', value: 9, scale: 'log2'}] + params: [{name: 'depth', value: 9, scale: 'log2'}], + waitForAngular2: false }).then(done, done.fail); }); diff --git a/modules/benchmarks_external/e2e_test/static_tree_perf.ts b/modules/benchmarks_external/e2e_test/static_tree_perf.ts index 08c4adf316..fef56e696f 100644 --- a/modules/benchmarks_external/e2e_test/static_tree_perf.ts +++ b/modules/benchmarks_external/e2e_test/static_tree_perf.ts @@ -7,9 +7,13 @@ describe('ng1.x tree benchmark', function() { afterEach(verifyNoBrowserErrors); it('should log the stats', function(done) { - runClickBenchmark( - {url: URL, buttons: ['#destroyDom', '#createDom'], id: 'ng1.static.tree', params: []}) - .then(done, done.fail); + runClickBenchmark({ + url: URL, + buttons: ['#destroyDom', '#createDom'], + id: 'ng1.static.tree', + params: [], + waitForAngular2: false + }).then(done, done.fail); }); }); diff --git a/modules/benchmarks_external/e2e_test/tree_perf.ts b/modules/benchmarks_external/e2e_test/tree_perf.ts index aae6200bfb..2383991b92 100644 --- a/modules/benchmarks_external/e2e_test/tree_perf.ts +++ b/modules/benchmarks_external/e2e_test/tree_perf.ts @@ -11,7 +11,8 @@ describe('ng1.x tree benchmark', function() { url: URL, buttons: ['#destroyDom', '#createDom'], id: 'ng1.tree', - params: [{name: 'depth', value: 9, scale: 'log2'}] + params: [{name: 'depth', value: 9, scale: 'log2'}], + waitForAngular2: false }).then(done, done.fail); }); diff --git a/modules/examples/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts b/modules/examples/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts index f0b6ffba10..26e1c99349 100644 --- a/modules/examples/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts +++ b/modules/examples/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts @@ -4,17 +4,19 @@ import {Promise} from 'angular2/src/core/facade/async'; describe('WebWorkers Kitchen Sink', function() { afterEach(verifyNoBrowserErrors); var selector = "hello-app .greeting"; - var URL = "examples/src/web_workers/kitchen_sink/index.html"; + var URL = browser.baseUrl + "examples/src/web_workers/kitchen_sink/index.html"; it('should greet', () => { - browser.get(URL); + // This test can't wait for Angular 2 as Testability is not available when using WebWorker + browser.driver.get(URL); browser.wait(protractor.until.elementLocated(by.css(selector)), 15000); expect(element.all(by.css(selector)).first().getText()).toEqual("hello world!"); }); it('should change greeting', () => { - browser.get(URL); + // This test can't wait for Angular 2 as Testability is not available when using WebWorker + browser.driver.get(URL); browser.wait(protractor.until.elementLocated(by.css(selector)), 15000); element(by.css("hello-app .changeButton")).click(); @@ -24,7 +26,8 @@ describe('WebWorkers Kitchen Sink', function() { }); it("should display correct key names", () => { - browser.get(URL); + // This test can't wait for Angular 2 as Testability is not available when using WebWorker + browser.driver.get(URL); browser.wait(protractor.until.elementLocated(by.css(".sample-area")), 15000); var area = element.all(by.css(".sample-area")).first(); diff --git a/modules/examples/e2e_test/web_workers/message_broker/message_broker_spec.ts b/modules/examples/e2e_test/web_workers/message_broker/message_broker_spec.ts index 2928d29b0d..82b5694698 100644 --- a/modules/examples/e2e_test/web_workers/message_broker/message_broker_spec.ts +++ b/modules/examples/e2e_test/web_workers/message_broker/message_broker_spec.ts @@ -1,21 +1,23 @@ import {verifyNoBrowserErrors} from "angular2/src/test_lib/e2e_util"; import {PromiseWrapper} from "angular2/src/core/facade/async"; -var URL = "examples/src/web_workers/message_broker/index.html"; +var URL = browser.baseUrl + 'examples/src/web_workers/message_broker/index.html'; describe("MessageBroker", function() { afterEach(verifyNoBrowserErrors); it("should bootstrap", () => { - browser.get(URL); + // This test can't wait for Angular 2 as Testability is not available when using WebWorker + browser.driver.get(URL); waitForBootstrap(); expect(element(by.css("app h1")).getText()).toEqual("WebWorker MessageBroker Test"); }); it("should echo messages", () => { const VALUE = "Hi There"; - browser.get(URL); + // This test can't wait for Angular 2 as Testability is not available when using WebWorker + browser.driver.get(URL); waitForBootstrap(); var input = element.all(by.css("#echo_input")).first(); diff --git a/modules/examples/e2e_test/web_workers/todo/todo_spec.ts b/modules/examples/e2e_test/web_workers/todo/todo_spec.ts index d30696ed38..9a8706f576 100644 --- a/modules/examples/e2e_test/web_workers/todo/todo_spec.ts +++ b/modules/examples/e2e_test/web_workers/todo/todo_spec.ts @@ -4,10 +4,11 @@ import {Promise} from 'angular2/src/core/facade/async'; describe('WebWorkers Todo', function() { afterEach(verifyNoBrowserErrors); - var URL = "examples/src/web_workers/todo/index.html"; + var URL = browser.baseUrl + "examples/src/web_workers/todo/index.html"; it('should bootstrap', () => { - browser.get(URL); + // This test can't wait for Angular 2 as Testability is not available when using WebWorker + browser.driver.get(URL); waitForBootstrap(); expect(element(by.css("#todoapp header")).getText()).toEqual("todos"); diff --git a/protractor-shared.js b/protractor-shared.js index d872768639..360c7f928e 100644 --- a/protractor-shared.js +++ b/protractor-shared.js @@ -188,11 +188,26 @@ var config = exports.config = { // and the sleeps in all tests. function patchProtractorWait(browser) { browser.ignoreSynchronization = true; + // Benchmarks never need to wait for Angular 2 to be ready var _get = browser.get; var sleepInterval = process.env.TRAVIS || process.env.JENKINS_URL ? 14000 : 8000; browser.get = function() { var result = _get.apply(this, arguments); - browser.driver.wait(protractor.until.elementLocated(By.js('var cs = document.body.children; var isLoading = false; for (var i = 0; i < cs.length; i++) {if (cs[i].textContent.indexOf("Loading...") > -1) isLoading = true; } return !isLoading ? document.body.children : null')), sleepInterval); + browser.driver.wait(protractor.until.elementLocated(By.js(function() { + var isLoading = true; + if (window.getAllAngularTestabilities) { + var testabilities = window.getAllAngularTestabilities(); + if (testabilities && testabilities.length > 0) { + isLoading = false; + testabilities.forEach(function(testability) { + if (!testability.isStable()) { + isLoading = true; + } + }); + } + } + return !isLoading ? document.body.children : null; + })), sleepInterval); return result; } }