diff --git a/packages/examples/common/BUILD.bazel b/packages/examples/common/BUILD.bazel index 050b9cc3686..8b2ea31e9de 100644 --- a/packages/examples/common/BUILD.bazel +++ b/packages/examples/common/BUILD.bazel @@ -1,5 +1,5 @@ load("@aspect_rules_esbuild//esbuild:defs.bzl", "esbuild") -load("//tools:defaults.bzl", "http_server", "ng_project", "protractor_web_test_suite", "ts_project") +load("//tools:defaults.bzl", "http_server", "ng_project", "ts_project", "webdriver_test") package(default_visibility = ["//visibility:public"]) @@ -25,8 +25,9 @@ ts_project( srcs = glob(["**/*_spec.ts"]), tsconfig = "//packages/examples:tsconfig_e2e", deps = [ - "//:node_modules/@types/jasminewd2", - "//:node_modules/protractor", + "//:node_modules/@types/jasmine", + "//:node_modules/@types/selenium-webdriver", + "//:node_modules/selenium-webdriver", "//packages/examples/test-utils", "//packages/private/testing", ], @@ -52,8 +53,8 @@ http_server( deps = [":app_bundle"], ) -protractor_web_test_suite( - name = "protractor_tests", +webdriver_test( + name = "webdriver_tests", server = ":devserver", deps = [ ":common_tests_lib", diff --git a/packages/examples/common/location/ts/e2e_test/location_component_spec.ts b/packages/examples/common/location/ts/e2e_test/location_component_spec.ts index dc917386d68..f17d707ae7a 100644 --- a/packages/examples/common/location/ts/e2e_test/location_component_spec.ts +++ b/packages/examples/common/location/ts/e2e_test/location_component_spec.ts @@ -6,23 +6,31 @@ * found in the LICENSE file at https://angular.dev/license */ -import {$, browser, by, element, protractor} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; - -function waitForElement(selector: string) { - const EC = (protractor).ExpectedConditions; - // Waits for the element with id 'abc' to be present on the dom. - browser.wait(EC.presenceOf($(selector)), 20000); -} +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('Location', () => { - afterEach(verifyNoBrowserErrors); + let driver: webdriver.WebDriver; + let baseUrl: string; - it('should verify paths', () => { - browser.get('/location/#/bar/baz'); - waitForElement('hash-location'); - expect(element.all(by.css('path-location code')).get(0).getText()).toEqual('/location'); - expect(element.all(by.css('hash-location code')).get(0).getText()).toEqual('/bar/baz'); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); + + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); + + it('should verify paths', async () => { + await driver.get(`${baseUrl}/location/#/bar/baz`); + await waitForAngular(driver); + const pathCode = await driver.findElement(webdriver.By.css('path-location code')); + const hashCode = await driver.findElement(webdriver.By.css('hash-location code')); + expect(await pathCode.getText()).toEqual('/location'); + expect(await hashCode.getText()).toEqual('/bar/baz'); }); }); diff --git a/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts b/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts index ec180ed306b..9cd83559285 100644 --- a/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts +++ b/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts @@ -6,25 +6,32 @@ * found in the LICENSE file at https://angular.dev/license */ -import {$, browser, by, element, ExpectedConditions} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; - -function waitForElement(selector: string) { - const EC = ExpectedConditions; - // Waits for the element with id 'abc' to be present on the dom. - browser.wait(EC.presenceOf($(selector)), 20000); -} +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('ngComponentOutlet', () => { - const URL = '/ngComponentOutlet'; - afterEach(verifyNoBrowserErrors); + let driver: webdriver.WebDriver; + let baseUrl: string; + + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); + + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); describe('ng-component-outlet-example', () => { - it('should render simple', () => { - browser.get(URL); - waitForElement('ng-component-outlet-simple-example'); - expect(element.all(by.css('hello-world')).getText()).toEqual(['Hello World!']); + it('should render simple', async () => { + await driver.get(`${baseUrl}/ngComponentOutlet`); + await waitForAngular(driver); + const helloWorlds = await driver.findElements(webdriver.By.css('hello-world')); + const texts = await Promise.all(helloWorlds.map((el) => el.getText())); + expect(texts).toEqual(['Hello World!']); }); }); }); diff --git a/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts b/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts index 76b8ec584d2..2abaa9ed4d6 100644 --- a/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts +++ b/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts @@ -6,80 +6,92 @@ * found in the LICENSE file at https://angular.dev/license */ -import {$, browser, by, element, ExpectedConditions} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; - -function waitForElement(selector: string) { - const EC = ExpectedConditions; - // Waits for the element with id 'abc' to be present on the dom. - browser.wait(EC.presenceOf($(selector)), 20000); -} +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('ngIf', () => { - const URL = '/ngIf'; - afterEach(verifyNoBrowserErrors); + let driver: webdriver.WebDriver; + let baseUrl: string; + + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); + + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); + + async function loadPage() { + await driver.get(`${baseUrl}/ngIf`); + await waitForAngular(driver); + } describe('ng-if-simple', () => { - let comp = 'ng-if-simple'; - it('should hide/show content', () => { - browser.get(URL); - waitForElement(comp); - expect(element.all(by.css(comp)).get(0).getText()).toEqual('hide show = true\nText to show'); - element(by.css(comp + ' button')).click(); - expect(element.all(by.css(comp)).get(0).getText()).toEqual('show show = false'); + const comp = 'ng-if-simple'; + it('should hide/show content', async () => { + await loadPage(); + const compEl = await driver.findElement(webdriver.By.css(comp)); + expect(await compEl.getText()).toEqual('hide show = true\nText to show'); + const button = await driver.findElement(webdriver.By.css(`${comp} button`)); + await button.click(); + await waitForAngular(driver); + expect(await compEl.getText()).toEqual('show show = false'); }); }); describe('ng-if-else', () => { - let comp = 'ng-if-else'; - it('should hide/show content', () => { - browser.get(URL); - waitForElement(comp); - expect(element.all(by.css(comp)).get(0).getText()).toEqual('hide show = true\nText to show'); - element(by.css(comp + ' button')).click(); - expect(element.all(by.css(comp)).get(0).getText()).toEqual( + const comp = 'ng-if-else'; + it('should hide/show content', async () => { + await loadPage(); + const compEl = await driver.findElement(webdriver.By.css(comp)); + expect(await compEl.getText()).toEqual('hide show = true\nText to show'); + const button = await driver.findElement(webdriver.By.css(`${comp} button`)); + await button.click(); + await waitForAngular(driver); + expect(await compEl.getText()).toEqual( 'show show = false\nAlternate text while primary text is hidden', ); }); }); describe('ng-if-then-else', () => { - let comp = 'ng-if-then-else'; + const comp = 'ng-if-then-else'; - it('should hide/show content', () => { - browser.get(URL); - waitForElement(comp); - expect(element.all(by.css(comp)).get(0).getText()).toEqual( + it('should hide/show content', async () => { + await loadPage(); + const compEl = await driver.findElement(webdriver.By.css(comp)); + expect(await compEl.getText()).toEqual( 'hideSwitch Primary show = true\nPrimary text to show', ); - element - .all(by.css(comp + ' button')) - .get(1) - .click(); - expect(element.all(by.css(comp)).get(0).getText()).toEqual( + const buttons = await driver.findElements(webdriver.By.css(`${comp} button`)); + await buttons[1].click(); + await waitForAngular(driver); + expect(await compEl.getText()).toEqual( 'hideSwitch Primary show = true\nSecondary text to show', ); - element - .all(by.css(comp + ' button')) - .get(0) - .click(); - expect(element.all(by.css(comp)).get(0).getText()).toEqual( + const updatedButtons = await driver.findElements(webdriver.By.css(`${comp} button`)); + await updatedButtons[0].click(); + await waitForAngular(driver); + expect(await compEl.getText()).toEqual( 'showSwitch Primary show = false\nAlternate text while primary text is hidden', ); }); }); describe('ng-if-as', () => { - let comp = 'ng-if-as'; - it('should hide/show content', () => { - browser.get(URL); - waitForElement(comp); - expect(element.all(by.css(comp)).get(0).getText()).toEqual( - 'Next User\nWaiting... (user is null)', - ); - element(by.css(comp + ' button')).click(); - expect(element.all(by.css(comp)).get(0).getText()).toEqual('Next User\nHello Smith, John!'); + const comp = 'ng-if-as'; + it('should hide/show content', async () => { + await loadPage(); + const compEl = await driver.findElement(webdriver.By.css(comp)); + expect(await compEl.getText()).toEqual('Next User\nWaiting... (user is null)'); + const button = await driver.findElement(webdriver.By.css(`${comp} button`)); + await button.click(); + await waitForAngular(driver); + expect(await compEl.getText()).toEqual('Next User\nHello Smith, John!'); }); }); }); diff --git a/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts b/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts index efd5dce1850..49b71de6990 100644 --- a/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts +++ b/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts @@ -6,29 +6,32 @@ * found in the LICENSE file at https://angular.dev/license */ -import {$, browser, by, element, ExpectedConditions} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; - -function waitForElement(selector: string) { - const EC = ExpectedConditions; - // Waits for the element with id 'abc' to be present on the dom. - browser.wait(EC.presenceOf($(selector)), 20000); -} +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('ngTemplateOutlet', () => { - const URL = '/ngTemplateOutlet'; - afterEach(verifyNoBrowserErrors); + let driver: webdriver.WebDriver; + let baseUrl: string; + + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); + + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); describe('ng-template-outlet-example', () => { - it('should render', () => { - browser.get(URL); - waitForElement('ng-template-outlet-example'); - expect(element.all(by.css('ng-template-outlet-example span')).getText()).toEqual([ - 'Hello', - 'Hello World!', - 'Ahoj Svet!', - ]); + it('should render', async () => { + await driver.get(`${baseUrl}/ngTemplateOutlet`); + await waitForAngular(driver); + const spans = await driver.findElements(webdriver.By.css('ng-template-outlet-example span')); + const texts = await Promise.all(spans.map((el) => el.getText())); + expect(texts).toEqual(['Hello', 'Hello World!', 'Ahoj Svet!']); }); }); }); diff --git a/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts b/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts index 786b622d149..0919974eb92 100644 --- a/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts +++ b/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts @@ -6,108 +6,114 @@ * found in the LICENSE file at https://angular.dev/license */ -import {$, browser, by, element, ExpectedConditions} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; - -function waitForElement(selector: string) { - const EC = ExpectedConditions; - // Waits for the element with id 'abc' to be present on the dom. - browser.wait(EC.presenceOf($(selector)), 20000); -} +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('pipe', () => { - afterEach(verifyNoBrowserErrors); - const URL = '/pipes'; + let driver: webdriver.WebDriver; + let baseUrl: string; + + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); + + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); + + async function loadPage() { + await driver.get(`${baseUrl}/pipes`); + await waitForAngular(driver); + } describe('async', () => { - it('should resolve and display promise', () => { - browser.get(URL); - waitForElement('async-promise-pipe'); - expect(element.all(by.css('async-promise-pipe span')).get(0).getText()).toEqual( - 'Wait for it...', - ); - element(by.css('async-promise-pipe button')).click(); - expect(element.all(by.css('async-promise-pipe span')).get(0).getText()).toEqual( - 'Wait for it... hi there!', - ); + it('should resolve and display promise', async () => { + await loadPage(); + const spans = await driver.findElements(webdriver.By.css('async-promise-pipe span')); + expect(await spans[0].getText()).toEqual('Wait for it...'); + const button = await driver.findElement(webdriver.By.css('async-promise-pipe button')); + await button.click(); + await waitForAngular(driver); + const updatedSpans = await driver.findElements(webdriver.By.css('async-promise-pipe span')); + expect(await updatedSpans[0].getText()).toEqual('Wait for it... hi there!'); }); }); describe('lowercase/uppercase', () => { - it('should work properly', () => { - browser.get(URL); - waitForElement('lowerupper-pipe'); - element(by.css('lowerupper-pipe input')).sendKeys('Hello World!'); - expect(element.all(by.css('lowerupper-pipe pre')).get(0).getText()).toEqual("'hello world!'"); - expect(element.all(by.css('lowerupper-pipe pre')).get(1).getText()).toEqual("'HELLO WORLD!'"); + it('should work properly', async () => { + await loadPage(); + const input = await driver.findElement(webdriver.By.css('lowerupper-pipe input')); + await input.sendKeys('Hello World!'); + await waitForAngular(driver); + const pres = await driver.findElements(webdriver.By.css('lowerupper-pipe pre')); + expect(await pres[0].getText()).toEqual("'hello world!'"); + expect(await pres[1].getText()).toEqual("'HELLO WORLD!'"); }); }); describe('titlecase', () => { - it('should work properly', () => { - browser.get(URL); - waitForElement('titlecase-pipe'); - expect(element.all(by.css('titlecase-pipe p')).get(0).getText()).toEqual('Some String'); - expect(element.all(by.css('titlecase-pipe p')).get(1).getText()).toEqual( - 'This Is Mixed Case', - ); - expect(element.all(by.css('titlecase-pipe p')).get(2).getText()).toEqual( - "It's Non-trivial Question", - ); - expect(element.all(by.css('titlecase-pipe p')).get(3).getText()).toEqual('One,two,three'); - expect(element.all(by.css('titlecase-pipe p')).get(4).getText()).toEqual('True|false'); - expect(element.all(by.css('titlecase-pipe p')).get(5).getText()).toEqual('Foo-vs-bar'); + it('should work properly', async () => { + await loadPage(); + const ps = await driver.findElements(webdriver.By.css('titlecase-pipe p')); + expect(await ps[0].getText()).toEqual('Some String'); + expect(await ps[1].getText()).toEqual('This Is Mixed Case'); + expect(await ps[2].getText()).toEqual("It's Non-trivial Question"); + expect(await ps[3].getText()).toEqual('One,two,three'); + expect(await ps[4].getText()).toEqual('True|false'); + expect(await ps[5].getText()).toEqual('Foo-vs-bar'); }); }); describe('keyvalue', () => { - it('should work properly', () => { - browser.get(URL); - waitForElement('keyvalue-pipe'); - expect(element.all(by.css('keyvalue-pipe div')).get(0).getText()).toEqual('1:bar'); - expect(element.all(by.css('keyvalue-pipe div')).get(1).getText()).toEqual('2:foo'); - expect(element.all(by.css('keyvalue-pipe div')).get(2).getText()).toEqual('1:bar'); - expect(element.all(by.css('keyvalue-pipe div')).get(3).getText()).toEqual('2:foo'); + it('should work properly', async () => { + await loadPage(); + const divs = await driver.findElements(webdriver.By.css('keyvalue-pipe div')); + expect(await divs[0].getText()).toEqual('1:bar'); + expect(await divs[1].getText()).toEqual('2:foo'); + expect(await divs[2].getText()).toEqual('1:bar'); + expect(await divs[3].getText()).toEqual('2:foo'); }); }); describe('number', () => { - it('should work properly', () => { - browser.get(URL); - waitForElement('number-pipe'); - const examples = element.all(by.css('number-pipe p')); - expect(examples.get(0).getText()).toEqual('No specified formatting: 3.142'); - expect(examples.get(1).getText()).toEqual('With digitsInfo parameter specified: 0,003.14159'); - expect(examples.get(2).getText()).toEqual( + it('should work properly', async () => { + await loadPage(); + const examples = await driver.findElements(webdriver.By.css('number-pipe p')); + expect(await examples[0].getText()).toEqual('No specified formatting: 3.142'); + expect(await examples[1].getText()).toEqual( + 'With digitsInfo parameter specified: 0,003.14159', + ); + expect(await examples[2].getText()).toEqual( 'With digitsInfo and locale parameters specified: 0\u202f003,14159', ); }); }); describe('percent', () => { - it('should work properly', () => { - browser.get(URL); - waitForElement('percent-pipe'); - const examples = element.all(by.css('percent-pipe p')); - expect(examples.get(0).getText()).toEqual('A: 26%'); - expect(examples.get(1).getText()).toEqual('B: 0,134.950%'); - expect(examples.get(2).getText()).toEqual('B: 0\u202f134,950 %'); + it('should work properly', async () => { + await loadPage(); + const examples = await driver.findElements(webdriver.By.css('percent-pipe p')); + expect(await examples[0].getText()).toEqual('A: 26%'); + expect(await examples[1].getText()).toEqual('B: 0,134.950%'); + expect(await examples[2].getText()).toEqual('B: 0\u202f134,950 %'); }); }); describe('currency', () => { - it('should work properly', () => { - browser.get(URL); - waitForElement('currency-pipe'); - const examples = element.all(by.css('currency-pipe p')); - expect(examples.get(0).getText()).toEqual('A: $0.26'); - expect(examples.get(1).getText()).toEqual('A: CA$0.26'); - expect(examples.get(2).getText()).toEqual('A: CAD0.26'); - expect(examples.get(3).getText()).toEqual('B: CA$0,001.35'); - expect(examples.get(4).getText()).toEqual('B: $0,001.35'); - expect(examples.get(5).getText()).toEqual('B: 0\u202f001,35 $CA'); - expect(examples.get(6).getText()).toEqual('B: CLP1'); + it('should work properly', async () => { + await loadPage(); + const examples = await driver.findElements(webdriver.By.css('currency-pipe p')); + expect(await examples[0].getText()).toEqual('A: $0.26'); + expect(await examples[1].getText()).toEqual('A: CA$0.26'); + expect(await examples[2].getText()).toEqual('A: CAD0.26'); + expect(await examples[3].getText()).toEqual('B: CA$0,001.35'); + expect(await examples[4].getText()).toEqual('B: $0,001.35'); + expect(await examples[5].getText()).toEqual('B: 0\u202f001,35 $CA'); + expect(await examples[6].getText()).toEqual('B: CLP1'); }); }); }); diff --git a/packages/examples/core/BUILD.bazel b/packages/examples/core/BUILD.bazel index 098c9ae3119..8fb9bb91ca1 100644 --- a/packages/examples/core/BUILD.bazel +++ b/packages/examples/core/BUILD.bazel @@ -1,5 +1,5 @@ load("@aspect_rules_esbuild//esbuild:defs.bzl", "esbuild") -load("//tools:defaults.bzl", "angular_jasmine_test", "http_server", "ng_project", "protractor_web_test_suite", "ts_project") +load("//tools:defaults.bzl", "angular_jasmine_test", "http_server", "ng_project", "ts_project", "webdriver_test") package(default_visibility = ["//visibility:public"]) @@ -43,8 +43,9 @@ ts_project( srcs = glob(["**/e2e_test/*_spec.ts"]), tsconfig = "//packages/examples:tsconfig_e2e", deps = [ - "//:node_modules/@types/jasminewd2", - "//:node_modules/protractor", + "//:node_modules/@types/jasmine", + "//:node_modules/@types/selenium-webdriver", + "//:node_modules/selenium-webdriver", "//packages/examples/test-utils", ], ) @@ -69,8 +70,8 @@ http_server( deps = [":app_bundle"], ) -protractor_web_test_suite( - name = "protractor_tests", +webdriver_test( + name = "webdriver_tests", server = ":devserver", deps = [ ":core_e2e_tests_lib", diff --git a/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts b/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts index 2d38f67ac3f..bc434f15772 100644 --- a/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts +++ b/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts @@ -6,26 +6,31 @@ * found in the LICENSE file at https://angular.dev/license */ -import {$, browser, by, element, ExpectedConditions} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../../test-utils'; - -function waitForElement(selector: string) { - const EC = ExpectedConditions; - // Waits for the element with id 'abc' to be present on the dom. - browser.wait(EC.presenceOf($(selector)), 20000); -} +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../../test-utils'; describe('animation example', () => { - afterEach(verifyNoBrowserErrors); + let driver: webdriver.WebDriver; + let baseUrl: string; + + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); + + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); describe('index view', () => { - const URL = '/animation/dsl/'; - - it('should list out the current collection of items', () => { - browser.get(URL); - waitForElement('.toggle-container'); - expect(element.all(by.css('.toggle-container')).get(0).getText()).toEqual('Look at this box'); + it('should list out the current collection of items', async () => { + await driver.get(`${baseUrl}/animation/dsl/`); + await waitForAngular(driver); + const container = await driver.findElement(webdriver.By.css('.toggle-container')); + expect(await container.getText()).toEqual('Look at this box'); }); }); }); diff --git a/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts b/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts index 93766fca8bb..f2e3da8fc9e 100644 --- a/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts +++ b/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts @@ -6,26 +6,38 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../../test-utils'; describe('contentChild example', () => { - afterEach(verifyNoBrowserErrors); - let button: ElementFinder; - let result: ElementFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/di/contentChild'); - button = element(by.css('button')); - result = element(by.css('div')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should query content child', () => { - expect(result.getText()).toEqual('pane: 1'); + afterAll(async () => { + await driver.quit(); + }); - button.click(); + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); - expect(result.getText()).toEqual('pane: 2'); + beforeEach(async () => { + await driver.get(`${baseUrl}/di/contentChild`); + await waitForAngular(driver); + }); + + it('should query content child', async () => { + const result = await driver.findElement(webdriver.By.css('div')); + expect(await result.getText()).toEqual('pane: 1'); + + const button = await driver.findElement(webdriver.By.css('button')); + await button.click(); + await waitForAngular(driver); + + expect(await result.getText()).toEqual('pane: 2'); }); }); diff --git a/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts b/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts index 62fff72c2bf..e91e1010719 100644 --- a/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts +++ b/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts @@ -6,36 +6,49 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../../test-utils'; describe('contentChildren example', () => { - afterEach(verifyNoBrowserErrors); - let button: ElementFinder; - let resultTopLevel: ElementFinder; - let resultNested: ElementFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/di/contentChildren'); - button = element(by.css('button')); - resultTopLevel = element(by.css('.top-level')); - resultNested = element(by.css('.nested')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should query content children', () => { - expect(resultTopLevel.getText()).toEqual('Top level panes: 1, 2'); - - button.click(); - - expect(resultTopLevel.getText()).toEqual('Top level panes: 1, 2, 3'); + afterAll(async () => { + await driver.quit(); }); - it('should query nested content children', () => { - expect(resultNested.getText()).toEqual('Arbitrary nested panes: 1, 2'); + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); - button.click(); + beforeEach(async () => { + await driver.get(`${baseUrl}/di/contentChildren`); + await waitForAngular(driver); + }); - expect(resultNested.getText()).toEqual('Arbitrary nested panes: 1, 2, 3, 3_1, 3_2'); + it('should query content children', async () => { + const resultTopLevel = await driver.findElement(webdriver.By.css('.top-level')); + expect(await resultTopLevel.getText()).toEqual('Top level panes: 1, 2'); + + const button = await driver.findElement(webdriver.By.css('button')); + await button.click(); + await waitForAngular(driver); + + expect(await resultTopLevel.getText()).toEqual('Top level panes: 1, 2, 3'); + }); + + it('should query nested content children', async () => { + const resultNested = await driver.findElement(webdriver.By.css('.nested')); + expect(await resultNested.getText()).toEqual('Arbitrary nested panes: 1, 2'); + + const button = await driver.findElement(webdriver.By.css('button')); + await button.click(); + await waitForAngular(driver); + + expect(await resultNested.getText()).toEqual('Arbitrary nested panes: 1, 2, 3, 3_1, 3_2'); }); }); diff --git a/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts b/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts index c2b92e890b7..91ed59a6974 100644 --- a/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts +++ b/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts @@ -6,26 +6,38 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../../test-utils'; describe('viewChild example', () => { - afterEach(verifyNoBrowserErrors); - let button: ElementFinder; - let result: ElementFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/di/viewChild'); - button = element(by.css('button')); - result = element(by.css('div')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should query view child', () => { - expect(result.getText()).toEqual('Selected: 1'); + afterAll(async () => { + await driver.quit(); + }); - button.click(); + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); - expect(result.getText()).toEqual('Selected: 2'); + beforeEach(async () => { + await driver.get(`${baseUrl}/di/viewChild`); + await waitForAngular(driver); + }); + + it('should query view child', async () => { + const result = await driver.findElement(webdriver.By.css('div')); + expect(await result.getText()).toEqual('Selected: 1'); + + const button = await driver.findElement(webdriver.By.css('button')); + await button.click(); + await waitForAngular(driver); + + expect(await result.getText()).toEqual('Selected: 2'); }); }); diff --git a/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts b/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts index eb387fa94e1..0d23ec5c6f9 100644 --- a/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts +++ b/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts @@ -6,26 +6,38 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../../test-utils'; describe('viewChildren example', () => { - afterEach(verifyNoBrowserErrors); - let button: ElementFinder; - let result: ElementFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/di/viewChildren'); - button = element(by.css('button')); - result = element(by.css('div')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should query view children', () => { - expect(result.getText()).toEqual('panes: 1, 2'); + afterAll(async () => { + await driver.quit(); + }); - button.click(); + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); - expect(result.getText()).toEqual('panes: 1, 2, 3'); + beforeEach(async () => { + await driver.get(`${baseUrl}/di/viewChildren`); + await waitForAngular(driver); + }); + + it('should query view children', async () => { + const result = await driver.findElement(webdriver.By.css('div')); + expect(await result.getText()).toEqual('panes: 1, 2'); + + const button = await driver.findElement(webdriver.By.css('button')); + await button.click(); + await waitForAngular(driver); + + expect(await result.getText()).toEqual('panes: 1, 2, 3'); }); }); diff --git a/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts b/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts index 9bedc0178c8..bd7ae5ea51b 100644 --- a/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts +++ b/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts @@ -6,45 +6,45 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../../test-utils'; - -// Declare the global "window" and "document" constant since we don't want to add the "dom" -// TypeScript lib for the e2e specs that execute code in the browser and reference such -// global constants. -declare const window: any; -declare const document: any; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors} from '../../../../../test-utils'; describe('testability example', () => { - afterEach(verifyNoBrowserErrors); + let driver: webdriver.WebDriver; + let baseUrl: string; + + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); + + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); describe('using task tracking', () => { - const URL = '/testability/whenStable/'; - - it('times out with a list of tasks', (done) => { - browser.get(URL); - browser.ignoreSynchronization = true; + it('times out with a list of tasks', async () => { + await driver.get(`${baseUrl}/testability/whenStable/`); // Script that runs in the browser and calls whenStable with a timeout. - let waitWithResultScript = function (done: any) { - let rootEl = document.querySelector('example-app'); - let testability = window.getAngularTestability(rootEl); - testability.whenStable(() => { + const waitWithResultScript = ` + var done = arguments[arguments.length - 1]; + var rootEl = document.querySelector('example-app'); + var testability = window.getAngularTestability(rootEl); + testability.whenStable(function() { done(); }, 1000); - }; + `; - element(by.css('.start-button')).click(); + const startButton = await driver.findElement(webdriver.By.css('.start-button')); + await startButton.click(); - browser.driver.executeAsyncScript(waitWithResultScript).then(() => { - expect(element(by.css('.status')).getText()).not.toContain('done'); - done(); - }); - }); - - afterAll(() => { - browser.ignoreSynchronization = false; + await driver.executeAsyncScript(waitWithResultScript); + const statusEl = await driver.findElement(webdriver.By.css('.status')); + expect(await statusEl.getText()).not.toContain('done'); }); }); }); diff --git a/packages/examples/forms/BUILD.bazel b/packages/examples/forms/BUILD.bazel index f8772c46ef8..5fcbef43e95 100644 --- a/packages/examples/forms/BUILD.bazel +++ b/packages/examples/forms/BUILD.bazel @@ -1,5 +1,5 @@ load("@aspect_rules_esbuild//esbuild:defs.bzl", "esbuild") -load("//tools:defaults.bzl", "http_server", "ng_project", "protractor_web_test_suite", "ts_project") +load("//tools:defaults.bzl", "http_server", "ng_project", "ts_project", "webdriver_test") package(default_visibility = ["//visibility:public"]) @@ -25,8 +25,9 @@ ts_project( srcs = glob(["**/e2e_test/*_spec.ts"]), tsconfig = "//packages/examples:tsconfig_e2e", deps = [ - "//:node_modules/@types/jasminewd2", - "//:node_modules/protractor", + "//:node_modules/@types/jasmine", + "//:node_modules/@types/selenium-webdriver", + "//:node_modules/selenium-webdriver", "//packages/examples/test-utils", "//packages/private/testing", ], @@ -52,8 +53,8 @@ http_server( deps = [":app_bundle"], ) -protractor_web_test_suite( - name = "protractor_tests", +webdriver_test( + name = "webdriver_tests", server = ":devserver", deps = [ ":forms_e2e_tests_lib", diff --git a/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts b/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts index 41d24f8caf1..dd6b7d756a5 100644 --- a/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts +++ b/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts @@ -6,32 +6,47 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementArrayFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('formBuilder example', () => { - afterEach(verifyNoBrowserErrors); - let inputs: ElementArrayFinder; - let paragraphs: ElementArrayFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/formBuilder'); - inputs = element.all(by.css('input')); - paragraphs = element.all(by.css('p')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should populate the UI with initial values', () => { - expect(inputs.get(0).getAttribute('value')).toEqual('Nancy'); - expect(inputs.get(1).getAttribute('value')).toEqual('Drew'); + afterAll(async () => { + await driver.quit(); }); - it('should update the validation status', () => { - expect(paragraphs.get(1).getText()).toEqual('Validation status: VALID'); + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); - inputs.get(0).click(); - inputs.get(0).clear(); - inputs.get(0).sendKeys('a'); - expect(paragraphs.get(1).getText()).toEqual('Validation status: INVALID'); + beforeEach(async () => { + await driver.get(`${baseUrl}/formBuilder`); + await waitForAngular(driver); + }); + + it('should populate the UI with initial values', async () => { + const inputs = await driver.findElements(webdriver.By.css('input')); + expect(await inputs[0].getAttribute('value')).toEqual('Nancy'); + expect(await inputs[1].getAttribute('value')).toEqual('Drew'); + }); + + it('should update the validation status', async () => { + const paragraphs = await driver.findElements(webdriver.By.css('p')); + expect(await paragraphs[1].getText()).toEqual('Validation status: VALID'); + + const inputs = await driver.findElements(webdriver.By.css('input')); + await inputs[0].click(); + await inputs[0].clear(); + await inputs[0].sendKeys('a'); + await waitForAngular(driver); + + const updatedParagraphs = await driver.findElements(webdriver.By.css('p')); + expect(await updatedParagraphs[1].getText()).toEqual('Validation status: INVALID'); }); }); diff --git a/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts b/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts index ba054fcff02..58b2e72310c 100644 --- a/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts +++ b/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts @@ -6,38 +6,55 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementArrayFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('nestedFormArray example', () => { - afterEach(verifyNoBrowserErrors); - let inputs: ElementArrayFinder; - let buttons: ElementArrayFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/nestedFormArray'); - inputs = element.all(by.css('input')); - buttons = element.all(by.css('button')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should populate the UI with initial values', () => { - expect(inputs.get(0).getAttribute('value')).toEqual('SF'); - expect(inputs.get(1).getAttribute('value')).toEqual('NY'); + afterAll(async () => { + await driver.quit(); }); - it('should add inputs programmatically', () => { - expect(inputs.count()).toBe(2); - - buttons.get(1).click(); - inputs = element.all(by.css('input')); - - expect(inputs.count()).toBe(3); + afterEach(async () => { + await verifyNoBrowserErrors(driver); }); - it('should set the value programmatically', () => { - buttons.get(2).click(); - expect(inputs.get(0).getAttribute('value')).toEqual('LA'); - expect(inputs.get(1).getAttribute('value')).toEqual('MTV'); + beforeEach(async () => { + await driver.get(`${baseUrl}/nestedFormArray`); + await waitForAngular(driver); + }); + + it('should populate the UI with initial values', async () => { + const inputs = await driver.findElements(webdriver.By.css('input')); + expect(await inputs[0].getAttribute('value')).toEqual('SF'); + expect(await inputs[1].getAttribute('value')).toEqual('NY'); + }); + + it('should add inputs programmatically', async () => { + let inputs = await driver.findElements(webdriver.By.css('input')); + expect(inputs.length).toBe(2); + + const buttons = await driver.findElements(webdriver.By.css('button')); + await buttons[1].click(); + await waitForAngular(driver); + + inputs = await driver.findElements(webdriver.By.css('input')); + expect(inputs.length).toBe(3); + }); + + it('should set the value programmatically', async () => { + const buttons = await driver.findElements(webdriver.By.css('button')); + await buttons[2].click(); + await waitForAngular(driver); + + const inputs = await driver.findElements(webdriver.By.css('input')); + expect(await inputs[0].getAttribute('value')).toEqual('LA'); + expect(await inputs[1].getAttribute('value')).toEqual('MTV'); }); }); diff --git a/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts b/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts index adc7ce37188..98f2e9399ab 100644 --- a/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts +++ b/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts @@ -6,39 +6,56 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('nestedFormGroup example', () => { - afterEach(verifyNoBrowserErrors); - let firstInput: ElementFinder; - let lastInput: ElementFinder; - let button: ElementFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/nestedFormGroup'); - firstInput = element(by.css('[formControlName="first"]')); - lastInput = element(by.css('[formControlName="last"]')); - button = element(by.css('button:not([type="submit"])')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should populate the UI with initial values', () => { - expect(firstInput.getAttribute('value')).toEqual('Nancy'); - expect(lastInput.getAttribute('value')).toEqual('Drew'); + afterAll(async () => { + await driver.quit(); }); - it('should show the error when name is invalid', () => { - firstInput.click(); - firstInput.clear(); - firstInput.sendKeys('a'); - - expect(element(by.css('p')).getText()).toEqual('Name is invalid.'); + afterEach(async () => { + await verifyNoBrowserErrors(driver); }); - it('should set the value programmatically', () => { - button.click(); - expect(firstInput.getAttribute('value')).toEqual('Bess'); - expect(lastInput.getAttribute('value')).toEqual('Marvin'); + beforeEach(async () => { + await driver.get(`${baseUrl}/nestedFormGroup`); + await waitForAngular(driver); + }); + + it('should populate the UI with initial values', async () => { + const firstInput = await driver.findElement(webdriver.By.css('[formControlName="first"]')); + const lastInput = await driver.findElement(webdriver.By.css('[formControlName="last"]')); + expect(await firstInput.getAttribute('value')).toEqual('Nancy'); + expect(await lastInput.getAttribute('value')).toEqual('Drew'); + }); + + it('should show the error when name is invalid', async () => { + const firstInput = await driver.findElement(webdriver.By.css('[formControlName="first"]')); + await firstInput.click(); + await firstInput.clear(); + await firstInput.sendKeys('a'); + await waitForAngular(driver); + + const p = await driver.findElement(webdriver.By.css('p')); + expect(await p.getText()).toEqual('Name is invalid.'); + }); + + it('should set the value programmatically', async () => { + const button = await driver.findElement(webdriver.By.css('button:not([type="submit"])')); + await button.click(); + await waitForAngular(driver); + + const firstInput = await driver.findElement(webdriver.By.css('[formControlName="first"]')); + const lastInput = await driver.findElement(webdriver.By.css('[formControlName="last"]')); + expect(await firstInput.getAttribute('value')).toEqual('Bess'); + expect(await lastInput.getAttribute('value')).toEqual('Marvin'); }); }); diff --git a/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts b/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts index f46016ebc3d..8e2911574ba 100644 --- a/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts +++ b/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts @@ -6,39 +6,56 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementArrayFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('ngModelGroup example', () => { - afterEach(verifyNoBrowserErrors); - let inputs: ElementArrayFinder; - let buttons: ElementArrayFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/ngModelGroup'); - inputs = element.all(by.css('input')); - buttons = element.all(by.css('button')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should populate the UI with initial values', () => { - expect(inputs.get(0).getAttribute('value')).toEqual('Nancy'); - expect(inputs.get(1).getAttribute('value')).toEqual('J'); - expect(inputs.get(2).getAttribute('value')).toEqual('Drew'); + afterAll(async () => { + await driver.quit(); }); - it('should show the error when name is invalid', () => { - inputs.get(0).click(); - inputs.get(0).clear(); - inputs.get(0).sendKeys('a'); - - expect(element(by.css('p')).getText()).toEqual('Name is invalid.'); + afterEach(async () => { + await verifyNoBrowserErrors(driver); }); - it('should set the value when changing the domain model', () => { - buttons.get(1).click(); - expect(inputs.get(0).getAttribute('value')).toEqual('Bess'); - expect(inputs.get(1).getAttribute('value')).toEqual('S'); - expect(inputs.get(2).getAttribute('value')).toEqual('Marvin'); + beforeEach(async () => { + await driver.get(`${baseUrl}/ngModelGroup`); + await waitForAngular(driver); + }); + + it('should populate the UI with initial values', async () => { + const inputs = await driver.findElements(webdriver.By.css('input')); + expect(await inputs[0].getAttribute('value')).toEqual('Nancy'); + expect(await inputs[1].getAttribute('value')).toEqual('J'); + expect(await inputs[2].getAttribute('value')).toEqual('Drew'); + }); + + it('should show the error when name is invalid', async () => { + const inputs = await driver.findElements(webdriver.By.css('input')); + await inputs[0].click(); + await inputs[0].clear(); + await inputs[0].sendKeys('a'); + await waitForAngular(driver); + + const p = await driver.findElement(webdriver.By.css('p')); + expect(await p.getText()).toEqual('Name is invalid.'); + }); + + it('should set the value when changing the domain model', async () => { + const buttons = await driver.findElements(webdriver.By.css('button')); + await buttons[1].click(); + await waitForAngular(driver); + + const inputs = await driver.findElements(webdriver.By.css('input')); + expect(await inputs[0].getAttribute('value')).toEqual('Bess'); + expect(await inputs[1].getAttribute('value')).toEqual('S'); + expect(await inputs[2].getAttribute('value')).toEqual('Marvin'); }); }); diff --git a/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts b/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts index ca4c6298037..24ec00db547 100644 --- a/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts +++ b/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts @@ -6,38 +6,52 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementArrayFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('radioButtons example', () => { - afterEach(verifyNoBrowserErrors); - let inputs: ElementArrayFinder; - let paragraphs: ElementArrayFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/radioButtons'); - inputs = element.all(by.css('input')); - paragraphs = element.all(by.css('p')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should populate the UI with initial values', () => { - expect(inputs.get(0).getAttribute('checked')).toEqual(null); - expect(inputs.get(1).getAttribute('checked')).toEqual('true'); - expect(inputs.get(2).getAttribute('checked')).toEqual(null); - - expect(paragraphs.get(0).getText()).toEqual('Form value: { "food": "lamb" }'); - expect(paragraphs.get(1).getText()).toEqual('myFood value: lamb'); + afterAll(async () => { + await driver.quit(); }); - it('update model and other buttons as the UI value changes', () => { - inputs.get(0).click(); + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); - expect(inputs.get(0).getAttribute('checked')).toEqual('true'); - expect(inputs.get(1).getAttribute('checked')).toEqual(null); - expect(inputs.get(2).getAttribute('checked')).toEqual(null); + beforeEach(async () => { + await driver.get(`${baseUrl}/radioButtons`); + await waitForAngular(driver); + }); - expect(paragraphs.get(0).getText()).toEqual('Form value: { "food": "beef" }'); - expect(paragraphs.get(1).getText()).toEqual('myFood value: beef'); + it('should populate the UI with initial values', async () => { + const inputs = await driver.findElements(webdriver.By.css('input')); + expect(await inputs[0].isSelected()).toBe(false); + expect(await inputs[1].isSelected()).toBe(true); + expect(await inputs[2].isSelected()).toBe(false); + + const paragraphs = await driver.findElements(webdriver.By.css('p')); + expect(await paragraphs[0].getText()).toEqual('Form value: { "food": "lamb" }'); + expect(await paragraphs[1].getText()).toEqual('myFood value: lamb'); + }); + + it('update model and other buttons as the UI value changes', async () => { + const inputs = await driver.findElements(webdriver.By.css('input')); + await inputs[0].click(); + await waitForAngular(driver); + + expect(await inputs[0].isSelected()).toBe(true); + expect(await inputs[1].isSelected()).toBe(false); + expect(await inputs[2].isSelected()).toBe(false); + + const paragraphs = await driver.findElements(webdriver.By.css('p')); + expect(await paragraphs[0].getText()).toEqual('Form value: { "food": "beef" }'); + expect(await paragraphs[1].getText()).toEqual('myFood value: beef'); }); }); diff --git a/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts b/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts index 71ebb7ecadb..215f862ad9f 100644 --- a/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts +++ b/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts @@ -6,34 +6,50 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementArrayFinder} from 'protractor'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; -import {verifyNoBrowserErrors} from '../../../../test-utils'; +describe('reactiveRadioButtons example', () => { + let driver: webdriver.WebDriver; + let baseUrl: string; -describe('radioButtons example', () => { - afterEach(verifyNoBrowserErrors); - let inputs: ElementArrayFinder; - - beforeEach(() => { - browser.get('/reactiveRadioButtons'); - inputs = element.all(by.css('input')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should populate the UI with initial values', () => { - expect(inputs.get(0).getAttribute('checked')).toEqual(null); - expect(inputs.get(1).getAttribute('checked')).toEqual('true'); - expect(inputs.get(2).getAttribute('checked')).toEqual(null); - - expect(element(by.css('p')).getText()).toEqual('Form value: { "food": "lamb" }'); + afterAll(async () => { + await driver.quit(); }); - it('update model and other buttons as the UI value changes', () => { - inputs.get(0).click(); + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); - expect(inputs.get(0).getAttribute('checked')).toEqual('true'); - expect(inputs.get(1).getAttribute('checked')).toEqual(null); - expect(inputs.get(2).getAttribute('checked')).toEqual(null); + beforeEach(async () => { + await driver.get(`${baseUrl}/reactiveRadioButtons`); + await waitForAngular(driver); + }); - expect(element(by.css('p')).getText()).toEqual('Form value: { "food": "beef" }'); + it('should populate the UI with initial values', async () => { + const inputs = await driver.findElements(webdriver.By.css('input')); + expect(await inputs[0].isSelected()).toBe(false); + expect(await inputs[1].isSelected()).toBe(true); + expect(await inputs[2].isSelected()).toBe(false); + + const p = await driver.findElement(webdriver.By.css('p')); + expect(await p.getText()).toEqual('Form value: { "food": "lamb" }'); + }); + + it('update model and other buttons as the UI value changes', async () => { + const inputs = await driver.findElements(webdriver.By.css('input')); + await inputs[0].click(); + await waitForAngular(driver); + + expect(await inputs[0].isSelected()).toBe(true); + expect(await inputs[1].isSelected()).toBe(false); + expect(await inputs[2].isSelected()).toBe(false); + + const p = await driver.findElement(webdriver.By.css('p')); + expect(await p.getText()).toEqual('Form value: { "food": "beef" }'); }); }); diff --git a/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts b/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts index 5c2af706f33..2b4eccbcc5b 100644 --- a/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts +++ b/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts @@ -6,32 +6,47 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementArrayFinder, ElementFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('reactiveSelectControl example', () => { - afterEach(verifyNoBrowserErrors); - let select: ElementFinder; - let options: ElementArrayFinder; - let p: ElementFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/reactiveSelectControl'); - select = element(by.css('select')); - options = element.all(by.css('option')); - p = element(by.css('p')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should populate the initial selection', () => { - expect(select.getAttribute('value')).toEqual('3: Object'); - expect(options.get(3).getAttribute('selected')).toBe('true'); + afterAll(async () => { + await driver.quit(); }); - it('should update the model when the value changes in the UI', () => { - select.click(); - options.get(0).click(); + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); - expect(p.getText()).toEqual('Form value: { "state": { "name": "Arizona", "abbrev": "AZ" } }'); + beforeEach(async () => { + await driver.get(`${baseUrl}/reactiveSelectControl`); + await waitForAngular(driver); + }); + + it('should populate the initial selection', async () => { + const select = await driver.findElement(webdriver.By.css('select')); + const options = await driver.findElements(webdriver.By.css('option')); + expect(await select.getAttribute('value')).toEqual('3: Object'); + expect(await options[3].isSelected()).toBe(true); + }); + + it('should update the model when the value changes in the UI', async () => { + const select = await driver.findElement(webdriver.By.css('select')); + const options = await driver.findElements(webdriver.By.css('option')); + await select.click(); + await options[0].click(); + await waitForAngular(driver); + + const p = await driver.findElement(webdriver.By.css('p')); + expect(await p.getText()).toEqual( + 'Form value: { "state": { "name": "Arizona", "abbrev": "AZ" } }', + ); }); }); diff --git a/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts b/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts index 26f385afb92..1364b099b63 100644 --- a/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts +++ b/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts @@ -6,31 +6,45 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementArrayFinder, ElementFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('selectControl example', () => { - afterEach(verifyNoBrowserErrors); - let select: ElementFinder; - let options: ElementArrayFinder; - let p: ElementFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/selectControl'); - select = element(by.css('select')); - options = element.all(by.css('option')); - p = element(by.css('p')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should initially select the placeholder option', () => { - expect(options.get(0).getAttribute('selected')).toBe('true'); + afterAll(async () => { + await driver.quit(); }); - it('should update the model when the value changes in the UI', () => { - select.click(); - options.get(1).click(); + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); - expect(p.getText()).toEqual('Form value: { "state": { "name": "Arizona", "abbrev": "AZ" } }'); + beforeEach(async () => { + await driver.get(`${baseUrl}/selectControl`); + await waitForAngular(driver); + }); + + it('should initially select the placeholder option', async () => { + const options = await driver.findElements(webdriver.By.css('option')); + expect(await options[0].isSelected()).toBe(true); + }); + + it('should update the model when the value changes in the UI', async () => { + const select = await driver.findElement(webdriver.By.css('select')); + const options = await driver.findElements(webdriver.By.css('option')); + await select.click(); + await options[1].click(); + await waitForAngular(driver); + + const p = await driver.findElement(webdriver.By.css('p')); + expect(await p.getText()).toEqual( + 'Form value: { "state": { "name": "Arizona", "abbrev": "AZ" } }', + ); }); }); diff --git a/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts b/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts index fdb01fba5f9..29b436dd816 100644 --- a/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts +++ b/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts @@ -6,39 +6,59 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementArrayFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('simpleForm example', () => { - afterEach(verifyNoBrowserErrors); - let inputs: ElementArrayFinder; - let paragraphs: ElementArrayFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/simpleForm'); - inputs = element.all(by.css('input')); - paragraphs = element.all(by.css('p')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should update the domain model as you type', () => { - inputs.get(0).click(); - inputs.get(0).sendKeys('Nancy'); - - inputs.get(1).click(); - inputs.get(1).sendKeys('Drew'); - - expect(paragraphs.get(0).getText()).toEqual('First name value: Nancy'); - expect(paragraphs.get(2).getText()).toEqual('Form value: { "first": "Nancy", "last": "Drew" }'); + afterAll(async () => { + await driver.quit(); }); - it('should report the validity correctly', () => { - expect(paragraphs.get(1).getText()).toEqual('First name valid: false'); - expect(paragraphs.get(3).getText()).toEqual('Form valid: false'); - inputs.get(0).click(); - inputs.get(0).sendKeys('a'); + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); - expect(paragraphs.get(1).getText()).toEqual('First name valid: true'); - expect(paragraphs.get(3).getText()).toEqual('Form valid: true'); + beforeEach(async () => { + await driver.get(`${baseUrl}/simpleForm`); + await waitForAngular(driver); + }); + + it('should update the domain model as you type', async () => { + const inputs = await driver.findElements(webdriver.By.css('input')); + await inputs[0].click(); + await inputs[0].sendKeys('Nancy'); + await waitForAngular(driver); + + await inputs[1].click(); + await inputs[1].sendKeys('Drew'); + await waitForAngular(driver); + + const paragraphs = await driver.findElements(webdriver.By.css('p')); + expect(await paragraphs[0].getText()).toEqual('First name value: Nancy'); + expect(await paragraphs[2].getText()).toEqual( + 'Form value: { "first": "Nancy", "last": "Drew" }', + ); + }); + + it('should report the validity correctly', async () => { + let paragraphs = await driver.findElements(webdriver.By.css('p')); + expect(await paragraphs[1].getText()).toEqual('First name valid: false'); + expect(await paragraphs[3].getText()).toEqual('Form valid: false'); + + const inputs = await driver.findElements(webdriver.By.css('input')); + await inputs[0].click(); + await inputs[0].sendKeys('a'); + await waitForAngular(driver); + + paragraphs = await driver.findElements(webdriver.By.css('p')); + expect(await paragraphs[1].getText()).toEqual('First name valid: true'); + expect(await paragraphs[3].getText()).toEqual('Form valid: true'); }); }); diff --git a/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts b/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts index c01c7529432..a628f6fdd4a 100644 --- a/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts +++ b/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts @@ -6,49 +6,68 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('simpleFormControl example', () => { - afterEach(verifyNoBrowserErrors); + let driver: webdriver.WebDriver; + let baseUrl: string; + + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); + + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); describe('index view', () => { - let input: ElementFinder; - let valueP: ElementFinder; - let statusP: ElementFinder; - - beforeEach(() => { - browser.get('/simpleFormControl'); - input = element(by.css('input')); - valueP = element(by.css('p:first-of-type')); - statusP = element(by.css('p:last-of-type')); + beforeEach(async () => { + await driver.get(`${baseUrl}/simpleFormControl`); + await waitForAngular(driver); }); - it('should populate the form control value in the DOM', () => { - expect(input.getAttribute('value')).toEqual('value'); - expect(valueP.getText()).toEqual('Value: value'); + it('should populate the form control value in the DOM', async () => { + const input = await driver.findElement(webdriver.By.css('input')); + const valueP = await driver.findElement(webdriver.By.css('p:first-of-type')); + expect(await input.getAttribute('value')).toEqual('value'); + expect(await valueP.getText()).toEqual('Value: value'); }); - it('should update the value as user types', () => { - input.click(); - input.sendKeys('s!'); + it('should update the value as user types', async () => { + const input = await driver.findElement(webdriver.By.css('input')); + await input.click(); + await input.sendKeys('s!'); + await waitForAngular(driver); - expect(valueP.getText()).toEqual('Value: values!'); + const valueP = await driver.findElement(webdriver.By.css('p:first-of-type')); + expect(await valueP.getText()).toEqual('Value: values!'); }); - it('should show the correct validity state', () => { - expect(statusP.getText()).toEqual('Validation status: VALID'); + it('should show the correct validity state', async () => { + const statusP = await driver.findElement(webdriver.By.css('p:last-of-type')); + expect(await statusP.getText()).toEqual('Validation status: VALID'); - input.click(); - input.clear(); - input.sendKeys('a'); - expect(statusP.getText()).toEqual('Validation status: INVALID'); + const input = await driver.findElement(webdriver.By.css('input')); + await input.click(); + await input.clear(); + await input.sendKeys('a'); + await waitForAngular(driver); + + expect(await statusP.getText()).toEqual('Validation status: INVALID'); }); - it('should set the value programmatically', () => { - element(by.css('button')).click(); - expect(input.getAttribute('value')).toEqual('new value'); + it('should set the value programmatically', async () => { + const button = await driver.findElement(webdriver.By.css('button')); + await button.click(); + await waitForAngular(driver); + + const input = await driver.findElement(webdriver.By.css('input')); + expect(await input.getAttribute('value')).toEqual('new value'); }); }); }); diff --git a/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts b/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts index 2404c1aad24..4c078e8bdd8 100644 --- a/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts +++ b/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts @@ -6,40 +6,58 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('formControlName example', () => { - afterEach(verifyNoBrowserErrors); + let driver: webdriver.WebDriver; + let baseUrl: string; + + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); + + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); describe('index view', () => { - let firstInput: ElementFinder; - let lastInput: ElementFinder; - - beforeEach(() => { - browser.get('/simpleFormGroup'); - firstInput = element(by.css('[formControlName="first"]')); - lastInput = element(by.css('[formControlName="last"]')); + beforeEach(async () => { + await driver.get(`${baseUrl}/simpleFormGroup`); + await waitForAngular(driver); }); - it('should populate the form control values in the DOM', () => { - expect(firstInput.getAttribute('value')).toEqual('Nancy'); - expect(lastInput.getAttribute('value')).toEqual('Drew'); + it('should populate the form control values in the DOM', async () => { + const firstInput = await driver.findElement(webdriver.By.css('[formControlName="first"]')); + const lastInput = await driver.findElement(webdriver.By.css('[formControlName="last"]')); + expect(await firstInput.getAttribute('value')).toEqual('Nancy'); + expect(await lastInput.getAttribute('value')).toEqual('Drew'); }); - it('should show the error when the form is invalid', () => { - firstInput.click(); - firstInput.clear(); - firstInput.sendKeys('a'); + it('should show the error when the form is invalid', async () => { + const firstInput = await driver.findElement(webdriver.By.css('[formControlName="first"]')); + await firstInput.click(); + await firstInput.clear(); + await firstInput.sendKeys('a'); + await waitForAngular(driver); - expect(element(by.css('div')).getText()).toEqual('Name is too short.'); + const errorDiv = await driver.findElement(webdriver.By.css('div')); + expect(await errorDiv.getText()).toEqual('Name is too short.'); }); - it('should set the value programmatically', () => { - element(by.css('button:not([type="submit"])')).click(); - expect(firstInput.getAttribute('value')).toEqual('Carson'); - expect(lastInput.getAttribute('value')).toEqual('Drew'); + it('should set the value programmatically', async () => { + const button = await driver.findElement(webdriver.By.css('button:not([type="submit"])')); + await button.click(); + await waitForAngular(driver); + + const firstInput = await driver.findElement(webdriver.By.css('[formControlName="first"]')); + const lastInput = await driver.findElement(webdriver.By.css('[formControlName="last"]')); + expect(await firstInput.getAttribute('value')).toEqual('Carson'); + expect(await lastInput.getAttribute('value')).toEqual('Drew'); }); }); }); diff --git a/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts b/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts index 1b089eece0d..c9a4c7acbcd 100644 --- a/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts +++ b/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts @@ -6,40 +6,59 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementArrayFinder, ElementFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../test-utils'; describe('simpleNgModel example', () => { - afterEach(verifyNoBrowserErrors); - let input: ElementFinder; - let paragraphs: ElementArrayFinder; - let button: ElementFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => { - browser.get('/simpleNgModel'); - input = element(by.css('input')); - paragraphs = element.all(by.css('p')); - button = element(by.css('button')); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should update the domain model as you type', () => { - input.click(); - input.sendKeys('Carson'); - - expect(paragraphs.get(0).getText()).toEqual('Value: Carson'); + afterAll(async () => { + await driver.quit(); }); - it('should report the validity correctly', () => { - expect(paragraphs.get(1).getText()).toEqual('Valid: false'); - input.click(); - input.sendKeys('a'); - - expect(paragraphs.get(1).getText()).toEqual('Valid: true'); + afterEach(async () => { + await verifyNoBrowserErrors(driver); }); - it('should set the value by changing the domain model', () => { - button.click(); - expect(input.getAttribute('value')).toEqual('Nancy'); + beforeEach(async () => { + await driver.get(`${baseUrl}/simpleNgModel`); + await waitForAngular(driver); + }); + + it('should update the domain model as you type', async () => { + const input = await driver.findElement(webdriver.By.css('input')); + await input.click(); + await input.sendKeys('Carson'); + await waitForAngular(driver); + + const paragraphs = await driver.findElements(webdriver.By.css('p')); + expect(await paragraphs[0].getText()).toEqual('Value: Carson'); + }); + + it('should report the validity correctly', async () => { + let paragraphs = await driver.findElements(webdriver.By.css('p')); + expect(await paragraphs[1].getText()).toEqual('Valid: false'); + + const input = await driver.findElement(webdriver.By.css('input')); + await input.click(); + await input.sendKeys('a'); + await waitForAngular(driver); + + paragraphs = await driver.findElements(webdriver.By.css('p')); + expect(await paragraphs[1].getText()).toEqual('Valid: true'); + }); + + it('should set the value by changing the domain model', async () => { + const button = await driver.findElement(webdriver.By.css('button')); + await button.click(); + await waitForAngular(driver); + + const input = await driver.findElement(webdriver.By.css('input')); + expect(await input.getAttribute('value')).toEqual('Nancy'); }); }); diff --git a/packages/examples/service-worker/push/BUILD.bazel b/packages/examples/service-worker/push/BUILD.bazel index 83f30a7b25c..1222681d386 100644 --- a/packages/examples/service-worker/push/BUILD.bazel +++ b/packages/examples/service-worker/push/BUILD.bazel @@ -1,5 +1,5 @@ load("@aspect_rules_esbuild//esbuild:defs.bzl", "esbuild") -load("//tools:defaults.bzl", "http_server", "ng_project", "protractor_web_test_suite", "ts_project") +load("//tools:defaults.bzl", "http_server", "ng_project", "ts_project", "webdriver_test") package(default_visibility = ["//visibility:public"]) @@ -23,8 +23,9 @@ ts_project( srcs = glob(["**/e2e_test/*_spec.ts"]), tsconfig = "//packages/examples:tsconfig_e2e", deps = [ - "//:node_modules/@types/jasminewd2", - "//:node_modules/protractor", + "//:node_modules/@types/jasmine", + "//:node_modules/@types/selenium-webdriver", + "//:node_modules/selenium-webdriver", "//packages/examples/test-utils", "//packages/private/testing", ], @@ -53,8 +54,8 @@ http_server( deps = [":app_bundle"], ) -protractor_web_test_suite( - name = "protractor_tests", +webdriver_test( + name = "webdriver_tests", server = ":devserver", deps = [ ":sw_push_e2e_tests_lib", diff --git a/packages/examples/service-worker/push/e2e_test/push_spec.ts b/packages/examples/service-worker/push/e2e_test/push_spec.ts index 0a4128cd190..642a3a92a01 100644 --- a/packages/examples/service-worker/push/e2e_test/push_spec.ts +++ b/packages/examples/service-worker/push/e2e_test/push_spec.ts @@ -6,17 +6,29 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../test-utils'; describe('SW `SwPush` example', () => { - const pageUrl = '/push'; - const appElem = element(by.css('example-app')); + let driver: webdriver.WebDriver; + let baseUrl: string; - afterEach(verifyNoBrowserErrors); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); - it('should be enabled', () => { - browser.get(pageUrl); - expect(appElem.getText()).toBe('SW enabled: true'); + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); + + it('should be enabled', async () => { + await driver.get(`${baseUrl}/push`); + await waitForAngular(driver); + const appElem = await driver.findElement(webdriver.By.css('example-app')); + expect(await appElem.getText()).toBe('SW enabled: true'); }); }); diff --git a/packages/examples/service-worker/registration-options/BUILD.bazel b/packages/examples/service-worker/registration-options/BUILD.bazel index 9f00f6caa18..a8a1ebd1a61 100644 --- a/packages/examples/service-worker/registration-options/BUILD.bazel +++ b/packages/examples/service-worker/registration-options/BUILD.bazel @@ -1,5 +1,5 @@ load("@aspect_rules_esbuild//esbuild:defs.bzl", "esbuild") -load("//tools:defaults.bzl", "http_server", "ng_project", "protractor_web_test_suite", "ts_project") +load("//tools:defaults.bzl", "http_server", "ng_project", "ts_project", "webdriver_test") package(default_visibility = ["//visibility:public"]) @@ -23,8 +23,9 @@ ts_project( srcs = glob(["**/e2e_test/*_spec.ts"]), tsconfig = "//packages/examples:tsconfig_e2e", deps = [ - "//:node_modules/@types/jasminewd2", - "//:node_modules/protractor", + "//:node_modules/@types/jasmine", + "//:node_modules/@types/selenium-webdriver", + "//:node_modules/selenium-webdriver", "//packages/examples/test-utils", "//packages/private/testing", ], @@ -53,8 +54,8 @@ http_server( deps = [":app_bundle"], ) -protractor_web_test_suite( - name = "protractor_tests", +webdriver_test( + name = "webdriver_tests", server = ":devserver", deps = [ ":sw_registration_options_e2e_tests_lib", diff --git a/packages/examples/service-worker/registration-options/e2e_test/registration-options_spec.ts b/packages/examples/service-worker/registration-options/e2e_test/registration-options_spec.ts index cf751112b47..c890bf1a612 100644 --- a/packages/examples/service-worker/registration-options/e2e_test/registration-options_spec.ts +++ b/packages/examples/service-worker/registration-options/e2e_test/registration-options_spec.ts @@ -6,22 +6,36 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../test-utils'; describe('SW `SwRegistrationOptions` example', () => { - const pageUrl = '/registration-options'; - const appElem = element(by.css('example-app')); + let driver: webdriver.WebDriver; + let baseUrl: string; - afterEach(verifyNoBrowserErrors); - - it('not register the SW by default', () => { - browser.get(pageUrl); - expect(appElem.getText()).toBe('SW enabled: false'); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('register the SW when navigating to `?sw=true`', () => { - browser.get(`${pageUrl}?sw=true`); - expect(appElem.getText()).toBe('SW enabled: true'); + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); + + it('not register the SW by default', async () => { + await driver.get(`${baseUrl}/registration-options`); + await waitForAngular(driver); + const appElem = await driver.findElement(webdriver.By.css('example-app')); + expect(await appElem.getText()).toBe('SW enabled: false'); + }); + + it('register the SW when navigating to `?sw=true`', async () => { + await driver.get(`${baseUrl}/registration-options?sw=true`); + await waitForAngular(driver); + const appElem = await driver.findElement(webdriver.By.css('example-app')); + expect(await appElem.getText()).toBe('SW enabled: true'); }); }); diff --git a/packages/examples/test-utils/BUILD.bazel b/packages/examples/test-utils/BUILD.bazel index 51f7407593b..baacdc76605 100644 --- a/packages/examples/test-utils/BUILD.bazel +++ b/packages/examples/test-utils/BUILD.bazel @@ -4,9 +4,14 @@ package(default_visibility = ["//visibility:public"]) ts_project( name = "test-utils", + testonly = True, srcs = ["index.ts"], + tsconfig = "//packages/examples:tsconfig_e2e", deps = [ + "//:node_modules/@types/jasmine", + "//:node_modules/@types/node", "//:node_modules/@types/selenium-webdriver", + "//:node_modules/selenium-webdriver", ], ) diff --git a/packages/examples/test-utils/index.ts b/packages/examples/test-utils/index.ts index 727375002a4..fb63e6f1725 100644 --- a/packages/examples/test-utils/index.ts +++ b/packages/examples/test-utils/index.ts @@ -5,26 +5,164 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ + /* tslint:disable:no-console */ -import {logging, WebDriver} from 'selenium-webdriver'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as webdriver from 'selenium-webdriver'; +import * as chrome from 'selenium-webdriver/chrome.js'; -declare var browser: WebDriver; -declare var expect: any; +declare const jasmine: any; +if (typeof jasmine !== 'undefined') { + jasmine.DEFAULT_TIMEOUT_INTERVAL = 120000; +} -// TODO (juliemr): remove this method once this becomes a protractor plugin -export async function verifyNoBrowserErrors() { - const browserLog = await browser.manage().logs().get('browser'); - const collectedErrors: any[] = []; +function resolveRunfile(filePath: string): string { + if (fs.existsSync(filePath)) { + return filePath; + } + const runfilesDir = process.env['JS_BINARY__RUNFILES'] || process.env['RUNFILES_DIR']; + if (runfilesDir) { + const candidates = [ + path.join(runfilesDir, filePath), + path.join(runfilesDir, '_main', filePath), + path.join(runfilesDir, filePath.replace(/^(\.\.\/)+/, '')), + path.join(runfilesDir, '_main', filePath.replace(/^(\.\.\/)+/, '')), + ]; + for (const c of candidates) { + if (fs.existsSync(c)) { + return c; + } + } + } + return filePath; +} + +export interface E2eContext { + driver: webdriver.WebDriver; + baseUrl: string; +} + +let serviceInitialized = false; + +export async function createWebDriver(): Promise { + const port = process.env['TEST_SERVER_PORT'] || '8080'; + const baseUrl = `http://localhost:${port}`; + + if (!serviceInitialized && process.env['CHROMEDRIVER']) { + const chromeDriverPath = resolveRunfile(process.env['CHROMEDRIVER']); + const service = new chrome.ServiceBuilder(chromeDriverPath).build(); + chrome.setDefaultService(service); + serviceInitialized = true; + } + + const options = new chrome.Options(); + if (process.env['CHROME_HEADLESS_BIN']) { + options.setChromeBinaryPath(resolveRunfile(process.env['CHROME_HEADLESS_BIN'])); + } + options.headless(); + options.addArguments('--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage'); + + const builder = new webdriver.Builder().forBrowser('chrome').setChromeOptions(options); + const driver = await builder.build(); + return {driver, baseUrl}; +} + +export async function waitForAngular(driver: webdriver.WebDriver): Promise { + try { + await driver.executeAsyncScript(` + var done = arguments[arguments.length - 1]; + setTimeout(function() { + var testabilities = []; + if (window.getAllAngularTestabilities) { + try { + testabilities = testabilities.concat(window.getAllAngularTestabilities()); + } catch (e) {} + } + if (window.angular) { + try { + var ng1Roots = document.querySelectorAll('[ng-app], [ng\\\\:app], [x-ng-app], body'); + for (var i = 0; i < ng1Roots.length; i++) { + var el = window.angular.element(ng1Roots[i]); + if (el && el.injector && el.injector()) { + var $browser = el.injector().get('$browser'); + if ($browser && $browser.notifyWhenNoOutstandingRequests) { + testabilities.push({ + whenStable: function(cb) { $browser.notifyWhenNoOutstandingRequests(cb); } + }); + break; + } + } + } + } catch (e) {} + } + if (testabilities.length > 0) { + var count = testabilities.length; + var decrement = function() { + if (--count === 0) { + done(); + } + }; + testabilities.forEach(function(t) { + try { + t.whenStable(decrement); + } catch (e) { + decrement(); + } + }); + return; + } + done(); + }, 50); + `); + } catch { + // Ignore errors if testability is not present + } +} + +export async function openBrowser( + driver: webdriver.WebDriver, + baseUrl: string, + urlPath: string, + params?: {name: string; value: any}[], +): Promise { + const urlParams: string[] = []; + if (params) { + params.forEach((param) => urlParams.push(param.name + '=' + param.value)); + } + const relative = urlPath.startsWith('/') ? urlPath : '/' + urlPath; + const fullUrl = encodeURI( + `${baseUrl}${relative}${urlParams.length ? '?' + urlParams.join('&') : ''}`, + ); + await driver.get(fullUrl); + await waitForAngular(driver); +} + +export async function collectBrowserLogs( + driver: webdriver.WebDriver, + loggingLevel: webdriver.logging.Level, + collectMoreSevereErrors: boolean = false, +): Promise { + const browserLog = await driver.manage().logs().get('browser'); + const collectedLogs: webdriver.logging.Entry[] = []; browserLog.forEach((logEntry) => { const msg = logEntry.message; - - console.log('>> ' + msg, logEntry); - - if (logEntry.level.value >= logging.Level.INFO.value) { - collectedErrors.push(msg); + if ( + (!collectMoreSevereErrors && logEntry.level.value === loggingLevel.value) || + (collectMoreSevereErrors && logEntry.level.value >= loggingLevel.value) + ) { + collectedLogs.push(logEntry); } }); - - expect(collectedErrors).toEqual([]); + return collectedLogs; +} + +export async function verifyNoBrowserErrors(driver: webdriver.WebDriver): Promise { + const logs = await collectBrowserLogs( + driver, + webdriver.logging.Level.WARNING, + true /* collect more severe errors too */, + ); + expect(logs).toEqual([]); } diff --git a/packages/examples/tsconfig-e2e.json b/packages/examples/tsconfig-e2e.json index 7727251c9a7..47bd5101456 100644 --- a/packages/examples/tsconfig-e2e.json +++ b/packages/examples/tsconfig-e2e.json @@ -1,6 +1,6 @@ { "extends": "./tsconfig-test.json", "compilerOptions": { - "types": ["node", "jasminewd2"] + "types": ["node", "jasmine", "selenium-webdriver"] } } diff --git a/packages/examples/upgrade/static/ts/full/e2e_test/static_full_spec.ts b/packages/examples/upgrade/static/ts/full/e2e_test/static_full_spec.ts index 861eb412c08..4c1caee2ed9 100644 --- a/packages/examples/upgrade/static/ts/full/e2e_test/static_full_spec.ts +++ b/packages/examples/upgrade/static/ts/full/e2e_test/static_full_spec.ts @@ -6,48 +6,73 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../../test-utils'; - -function loadPage() { - browser.rootEl = 'example-app'; - browser.get('/'); -} +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../../test-utils'; describe('upgrade/static (full)', () => { - beforeEach(loadPage); - afterEach(verifyNoBrowserErrors); + let driver: webdriver.WebDriver; + let baseUrl: string; - it('should render the `ng2-heroes` component', () => { - expect(element(by.css('h1')).getText()).toEqual('Heroes'); - expect(element.all(by.css('p')).get(0).getText()).toEqual('There are 3 heroes.'); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should render 3 ng1-hero components', () => { - const heroComponents = element.all(by.css('ng1-hero')); - expect(heroComponents.count()).toEqual(3); + afterAll(async () => { + await driver.quit(); }); - it('should add a new hero when the "Add Hero" button is pressed', () => { - const addHeroButton = element.all(by.css('button')).last(); - expect(addHeroButton.getText()).toEqual('Add Hero'); - addHeroButton.click(); - const heroComponents = element.all(by.css('ng1-hero')); - expect(heroComponents.last().element(by.css('h2')).getText()).toEqual('Kamala Khan'); + afterEach(async () => { + await verifyNoBrowserErrors(driver); }); - it('should remove a hero when the "Remove" button is pressed', () => { - let firstHero = element.all(by.css('ng1-hero')).get(0); - expect(firstHero.element(by.css('h2')).getText()).toEqual('Superman'); + beforeEach(async () => { + await driver.get(`${baseUrl}/`); + await waitForAngular(driver); + }); - const removeHeroButton = firstHero.element(by.css('button')); - expect(removeHeroButton.getText()).toEqual('Remove'); - removeHeroButton.click(); + it('should render the `ng2-heroes` component', async () => { + const h1 = await driver.findElement(webdriver.By.css('h1')); + expect(await h1.getText()).toEqual('Heroes'); - const heroComponents = element.all(by.css('ng1-hero')); - expect(heroComponents.count()).toEqual(2); + const ps = await driver.findElements(webdriver.By.css('p')); + expect(await ps[0].getText()).toEqual('There are 3 heroes.'); + }); - firstHero = element.all(by.css('ng1-hero')).get(0); - expect(firstHero.element(by.css('h2')).getText()).toEqual('Wonder Woman'); + it('should render 3 ng1-hero components', async () => { + const heroComponents = await driver.findElements(webdriver.By.css('ng1-hero')); + expect(heroComponents.length).toEqual(3); + }); + + it('should add a new hero when the "Add Hero" button is pressed', async () => { + const buttons = await driver.findElements(webdriver.By.css('button')); + const addHeroButton = buttons[buttons.length - 1]; + expect(await addHeroButton.getText()).toEqual('Add Hero'); + await addHeroButton.click(); + await waitForAngular(driver); + + const heroComponents = await driver.findElements(webdriver.By.css('ng1-hero')); + const lastHeroName = await heroComponents[heroComponents.length - 1] + .findElement(webdriver.By.css('h2')) + .getText(); + expect(lastHeroName).toEqual('Kamala Khan'); + }); + + it('should remove a hero when the "Remove" button is pressed', async () => { + let heroComponents = await driver.findElements(webdriver.By.css('ng1-hero')); + const firstHeroName = await heroComponents[0].findElement(webdriver.By.css('h2')).getText(); + expect(firstHeroName).toEqual('Superman'); + + const removeHeroButton = await heroComponents[0].findElement( + webdriver.By.xpath(".//button[text()='Remove']"), + ); + expect(await removeHeroButton.getText()).toEqual('Remove'); + await removeHeroButton.click(); + await waitForAngular(driver); + + heroComponents = await driver.findElements(webdriver.By.css('ng1-hero')); + expect(heroComponents.length).toEqual(2); + + const newFirstHeroName = await heroComponents[0].findElement(webdriver.By.css('h2')).getText(); + expect(newFirstHeroName).toEqual('Wonder Woman'); }); }); diff --git a/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts b/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts index 695964ebb6a..a9052977835 100644 --- a/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts +++ b/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts @@ -6,24 +6,39 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../../test-utils'; describe('upgrade/static (lite with multiple downgraded modules and shared root module)', () => { - const compA = element(by.css('ng2-a')); - const compB = element(by.css('ng2-b')); - const compC = element(by.css('ng2-c')); + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => browser.get('/')); - afterEach(verifyNoBrowserErrors); - - it('should share the same injectable instance across downgraded modules A and B', () => { - expect(compA.getText()).toBe('Component A (Service ID: 2)'); - expect(compB.getText()).toBe('Component B (Service ID: 2)'); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); }); - it('should use a different injectable instance on downgraded module C', () => { - expect(compC.getText()).toBe('Component C (Service ID: 1)'); + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); + + beforeEach(async () => { + await driver.get(`${baseUrl}/`); + await waitForAngular(driver); + }); + + it('should share the same injectable instance across downgraded modules A and B', async () => { + const compA = await driver.findElement(webdriver.By.css('ng2-a')); + const compB = await driver.findElement(webdriver.By.css('ng2-b')); + expect(await compA.getText()).toBe('Component A (Service ID: 2)'); + expect(await compB.getText()).toBe('Component B (Service ID: 2)'); + }); + + it('should use a different injectable instance on downgraded module C', async () => { + const compC = await driver.findElement(webdriver.By.css('ng2-c')); + expect(await compC.getText()).toBe('Component C (Service ID: 1)'); }); }); diff --git a/packages/examples/upgrade/static/ts/lite-multi/e2e_test/static_lite_multi_spec.ts b/packages/examples/upgrade/static/ts/lite-multi/e2e_test/static_lite_multi_spec.ts index a479e865abd..d8b87284e33 100644 --- a/packages/examples/upgrade/static/ts/lite-multi/e2e_test/static_lite_multi_spec.ts +++ b/packages/examples/upgrade/static/ts/lite-multi/e2e_test/static_lite_multi_spec.ts @@ -6,22 +6,42 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../../test-utils'; +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../../test-utils'; describe('upgrade/static (lite with multiple downgraded modules)', () => { - const navButtons = element.all(by.css('nav button')); - const mainContent = element(by.css('main')); + let driver: webdriver.WebDriver; + let baseUrl: string; - beforeEach(() => browser.get('/')); - afterEach(verifyNoBrowserErrors); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); - it('should correctly bootstrap multiple downgraded modules', () => { - navButtons.get(1).click(); - expect(mainContent.getText()).toBe('Component B'); + afterAll(async () => { + await driver.quit(); + }); - navButtons.get(0).click(); - expect(mainContent.getText()).toBe('Component A | ng1(ng2)'); + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); + + beforeEach(async () => { + await driver.get(`${baseUrl}/`); + await waitForAngular(driver); + }); + + it('should correctly bootstrap multiple downgraded modules', async () => { + const navButtons = await driver.findElements(webdriver.By.css('nav button')); + await navButtons[1].click(); + await waitForAngular(driver); + + const mainContent = await driver.findElement(webdriver.By.css('main')); + expect(await mainContent.getText()).toBe('Component B'); + + const updatedNavButtons = await driver.findElements(webdriver.By.css('nav button')); + await updatedNavButtons[0].click(); + await waitForAngular(driver); + + expect(await mainContent.getText()).toBe('Component A | ng1(ng2)'); }); }); diff --git a/packages/examples/upgrade/static/ts/lite/e2e_test/e2e_util.ts b/packages/examples/upgrade/static/ts/lite/e2e_test/e2e_util.ts index c3b56d7674e..a303885b2fa 100644 --- a/packages/examples/upgrade/static/ts/lite/e2e_test/e2e_util.ts +++ b/packages/examples/upgrade/static/ts/lite/e2e_test/e2e_util.ts @@ -6,65 +6,25 @@ * found in the LICENSE file at https://angular.dev/license */ -import {by, ElementFinder} from 'protractor'; - -declare global { - namespace jasmine { - interface Matchers { - toBeAHero(): Promise; - toHaveName(exectedName: string): Promise; - } - } -} +import * as webdriver from 'selenium-webdriver'; const isTitleCased = (text: string) => text.split(/\s+/).every((word) => word[0] === word[0].toUpperCase()); -export function addCustomMatchers() { - jasmine.addMatchers({ - toBeAHero: () => ({ - compare(actualNg1Hero: ElementFinder | undefined) { - const getText = (selector: string) => actualNg1Hero!.element(by.css(selector)).getText(); - const result = { - message: 'Expected undefined to be an `ng1Hero` ElementFinder.', - pass: - !!actualNg1Hero && - Promise.all(['.title', 'h2', 'p'].map(getText) as PromiseLike[]).then( - ([actualTitle, actualName, actualDescription]) => { - const pass = - actualTitle === 'Super Hero' && - isTitleCased(actualName) && - actualDescription.length > 0; +export async function expectToBeAHero(actualNg1Hero: webdriver.WebElement): Promise { + const title = await actualNg1Hero.findElement(webdriver.By.css('.title')).getText(); + const name = await actualNg1Hero.findElement(webdriver.By.css('h2')).getText(); + const description = await actualNg1Hero.findElement(webdriver.By.css('p')).getText(); - const actualHero = `Hero(${actualTitle}, ${actualName}, ${actualDescription})`; - result.message = `Expected ${actualHero}'${pass ? ' not' : ''} to be a real hero.`; - - return pass; - }, - ), - }; - return result; - }, - }), - toHaveName: () => ({ - compare(actualNg1Hero: ElementFinder | undefined, expectedName: string) { - const result = { - message: 'Expected undefined to be an `ng1Hero` ElementFinder.', - pass: - !!actualNg1Hero && - actualNg1Hero - .element(by.css('h2')) - .getText() - .then((actualName) => { - const pass = actualName === expectedName; - result.message = `Expected Hero(${actualName})${ - pass ? ' not' : '' - } to have name '${expectedName}'.`; - return pass; - }), - }; - return result; - }, - }), - } as any); + expect(title).toBe('Super Hero'); + expect(isTitleCased(name)).toBe(true); + expect(description.length).toBeGreaterThan(0); +} + +export async function expectToHaveName( + actualNg1Hero: webdriver.WebElement, + expectedName: string, +): Promise { + const name = await actualNg1Hero.findElement(webdriver.By.css('h2')).getText(); + expect(name).toBe(expectedName); } diff --git a/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts b/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts index f83c9f56aee..bca9073ed28 100644 --- a/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts +++ b/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts @@ -6,85 +6,102 @@ * found in the LICENSE file at https://angular.dev/license */ -import {browser, by, element, ElementArrayFinder, ElementFinder} from 'protractor'; - -import {verifyNoBrowserErrors} from '../../../../../test-utils'; - -import {addCustomMatchers} from './e2e_util'; - -function loadPage() { - browser.rootEl = 'example-app'; - browser.get('/'); -} +import * as webdriver from 'selenium-webdriver'; +import {createWebDriver, verifyNoBrowserErrors, waitForAngular} from '../../../../../test-utils'; +import {expectToBeAHero, expectToHaveName} from './e2e_util'; describe('upgrade/static (lite)', () => { - let showHideBtn: ElementFinder; - let ng2Heroes: ElementFinder; - let ng2HeroesHeader: ElementFinder; - let ng2HeroesExtra: ElementFinder; - let ng2HeroesAddBtn: ElementFinder; - let ng1Heroes: ElementArrayFinder; + let driver: webdriver.WebDriver; + let baseUrl: string; - const expectHeroes = (isShown: boolean, ng1HeroCount = 3, statusMessage = 'Ready') => { - // Verify the show/hide button text. - expect(showHideBtn.getText()).toBe(isShown ? 'Hide heroes' : 'Show heroes'); + beforeAll(async () => { + ({driver, baseUrl} = await createWebDriver()); + }); - // Verify the `` component. - expect(ng2Heroes.isPresent()).toBe(isShown); + afterAll(async () => { + await driver.quit(); + }); + + afterEach(async () => { + await verifyNoBrowserErrors(driver); + }); + + async function loadPage() { + await driver.get(`${baseUrl}/`); + await waitForAngular(driver); + } + + const expectHeroes = async (isShown: boolean, ng1HeroCount = 3, statusMessage = 'Ready') => { + const showHideBtn = await driver.findElement(webdriver.By.css('button')); + expect(await showHideBtn.getText()).toBe(isShown ? 'Hide heroes' : 'Show heroes'); + + const ng2HeroesList = await driver.findElements(webdriver.By.css('.ng2-heroes')); + expect(ng2HeroesList.length > 0).toBe(isShown); if (isShown) { - expect(ng2HeroesHeader.getText()).toBe('Heroes'); - expect(ng2HeroesExtra.getText()).toBe(`Status: ${statusMessage}`); + const ng2HeroesHeader = await ng2HeroesList[0].findElement(webdriver.By.css('h1')); + const ng2HeroesExtra = await ng2HeroesList[0].findElement(webdriver.By.css('.extra')); + expect(await ng2HeroesHeader.getText()).toBe('Heroes'); + expect(await ng2HeroesExtra.getText()).toBe(`Status: ${statusMessage}`); } - // Verify the `` components. - expect(ng1Heroes.count()).toBe(isShown ? ng1HeroCount : 0); + const ng1Heroes = await driver.findElements(webdriver.By.css('.ng1-hero')); + expect(ng1Heroes.length).toBe(isShown ? ng1HeroCount : 0); if (isShown) { - ng1Heroes.each((ng1Hero) => expect(ng1Hero).toBeAHero()); + for (const ng1Hero of ng1Heroes) { + await expectToBeAHero(ng1Hero); + } } }; - beforeEach(() => { - showHideBtn = element(by.binding('toggleBtnText')); - - ng2Heroes = element(by.css('.ng2-heroes')); - ng2HeroesHeader = ng2Heroes.element(by.css('h1')); - ng2HeroesExtra = ng2Heroes.element(by.css('.extra')); - ng2HeroesAddBtn = ng2Heroes.element(by.buttonText('Add Hero')); - - ng1Heroes = element.all(by.css('.ng1-hero')); - }); - beforeEach(addCustomMatchers); beforeEach(loadPage); - afterEach(verifyNoBrowserErrors); - it('should initially not render the heroes', () => expectHeroes(false)); + it('should initially not render the heroes', async () => expectHeroes(false)); - it('should toggle the heroes when clicking the "show/hide" button', () => { - showHideBtn.click(); - expectHeroes(true); + it('should toggle the heroes when clicking the "show/hide" button', async () => { + let showHideBtn = await driver.findElement(webdriver.By.css('button')); + await showHideBtn.click(); + await waitForAngular(driver); + await expectHeroes(true); - showHideBtn.click(); - expectHeroes(false); + showHideBtn = await driver.findElement(webdriver.By.css('button')); + await showHideBtn.click(); + await waitForAngular(driver); + await expectHeroes(false); }); - it('should add a new hero when clicking the "add" button', () => { - showHideBtn.click(); - ng2HeroesAddBtn.click(); + it('should add a new hero when clicking the "add" button', async () => { + let showHideBtn = await driver.findElement(webdriver.By.css('button')); + await showHideBtn.click(); + await waitForAngular(driver); - expectHeroes(true, 4, 'Added hero Kamala Khan'); - expect(ng1Heroes.last()).toHaveName('Kamala Khan'); + const ng2HeroesAddBtn = await driver.findElement( + webdriver.By.xpath("//button[text()='Add Hero']"), + ); + await ng2HeroesAddBtn.click(); + await waitForAngular(driver); + + await expectHeroes(true, 4, 'Added hero Kamala Khan'); + const ng1Heroes = await driver.findElements(webdriver.By.css('.ng1-hero')); + await expectToHaveName(ng1Heroes[ng1Heroes.length - 1], 'Kamala Khan'); }); - it('should remove a hero when clicking its "remove" button', () => { - showHideBtn.click(); + it('should remove a hero when clicking its "remove" button', async () => { + let showHideBtn = await driver.findElement(webdriver.By.css('button')); + await showHideBtn.click(); + await waitForAngular(driver); - const firstHero = ng1Heroes.first(); - expect(firstHero).toHaveName('Superman'); + let ng1Heroes = await driver.findElements(webdriver.By.css('.ng1-hero')); + await expectToHaveName(ng1Heroes[0], 'Superman'); - const removeBtn = firstHero.element(by.buttonText('Remove')); - removeBtn.click(); + const removeBtn = await ng1Heroes[0].findElement( + webdriver.By.xpath(".//button[text()='Remove']"), + ); + await removeBtn.click(); + await waitForAngular(driver); - expectHeroes(true, 2, 'Removed hero Superman'); - expect(ng1Heroes.first()).not.toHaveName('Superman'); + await expectHeroes(true, 2, 'Removed hero Superman'); + ng1Heroes = await driver.findElements(webdriver.By.css('.ng1-hero')); + const firstHeroName = await ng1Heroes[0].findElement(webdriver.By.css('h2')).getText(); + expect(firstHeroName).not.toBe('Superman'); }); }); diff --git a/packages/examples/upgrade/tsconfig-e2e.json b/packages/examples/upgrade/tsconfig-e2e.json index 0b30dff819b..a89494bf90c 100644 --- a/packages/examples/upgrade/tsconfig-e2e.json +++ b/packages/examples/upgrade/tsconfig-e2e.json @@ -2,6 +2,6 @@ "extends": "./tsconfig.json", "compilerOptions": { "lib": ["es2015"], - "types": ["node", "jasminewd2"] + "types": ["node", "jasmine", "selenium-webdriver"] } } \ No newline at end of file diff --git a/packages/examples/upgrade/upgrade_example.bzl b/packages/examples/upgrade/upgrade_example.bzl index ce4b0edb015..7df4f02acb1 100644 --- a/packages/examples/upgrade/upgrade_example.bzl +++ b/packages/examples/upgrade/upgrade_example.bzl @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "esbuild", "http_server", "ng_project", "protractor_web_test_suite", "ts_project") +load("//tools:defaults.bzl", "esbuild", "http_server", "ng_project", "ts_project", "webdriver_test") """ Macro that can be used to create the Bazel targets for an "upgrade" example. Since the @@ -30,8 +30,9 @@ def create_upgrade_example_targets(name, srcs, e2e_srcs, entry_point, assets = [ testonly = True, deps = [ "//packages/private/testing:testing", - "//:node_modules/@types/jasminewd2", - "//:node_modules/protractor", + "//:node_modules/@types/jasmine", + "//:node_modules/@types/selenium-webdriver", + "//:node_modules/selenium-webdriver", "//packages/examples/test-utils:test-utils", ], tsconfig = "//packages/examples/upgrade:tsconfig_e2e", @@ -59,11 +60,10 @@ def create_upgrade_example_targets(name, srcs, e2e_srcs, entry_point, assets = [ deps = [":app_bundle"], ) - protractor_web_test_suite( - name = "%s_protractor" % name, + webdriver_test( + name = "%s_webdriver" % name, server = ":devserver", deps = [ ":%s_e2e_lib" % name, - "//:node_modules/selenium-webdriver", ], )