build: switch examples away from protractor

Reworks the `examples` tests not to depend on Protractor.
This commit is contained in:
Kristiyan Kostadinov
2026-08-14 09:15:20 +02:00
committed by Jessica Janiuk
parent 413c79c10b
commit 204265f9a3
40 changed files with 1297 additions and 795 deletions
+6 -5
View File
@@ -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",
@@ -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 = (<any>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');
});
});
@@ -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!']);
});
});
});
@@ -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!');
});
});
});
@@ -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!']);
});
});
});
@@ -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');
});
});
});
+6 -5
View File
@@ -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",
@@ -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');
});
});
});
@@ -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');
});
});
@@ -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');
});
});
@@ -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');
});
});
@@ -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');
});
});
@@ -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');
});
});
});
+6 -5
View File
@@ -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",
@@ -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');
});
});
@@ -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');
});
});
@@ -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');
});
});
@@ -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');
});
});
@@ -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');
});
});
@@ -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" }');
});
});
@@ -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" } }',
);
});
});
@@ -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" } }',
);
});
});
@@ -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');
});
});
@@ -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');
});
});
});
@@ -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');
});
});
});
@@ -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');
});
});
@@ -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",
@@ -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');
});
});
@@ -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",
@@ -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');
});
});
+5
View File
@@ -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",
],
)
+152 -14
View File
@@ -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<E2eContext> {
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<void> {
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<void> {
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<webdriver.logging.Entry[]> {
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<void> {
const logs = await collectBrowserLogs(
driver,
webdriver.logging.Level.WARNING,
true /* collect more severe errors too */,
);
expect(logs).toEqual([]);
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"extends": "./tsconfig-test.json",
"compilerOptions": {
"types": ["node", "jasminewd2"]
"types": ["node", "jasmine", "selenium-webdriver"]
}
}
@@ -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');
});
});
@@ -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)');
});
});
@@ -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)');
});
});
@@ -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<T> {
toBeAHero(): Promise<void>;
toHaveName(exectedName: string): Promise<void>;
}
}
}
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<string>[]).then(
([actualTitle, actualName, actualDescription]) => {
const pass =
actualTitle === 'Super Hero' &&
isTitleCased(actualName) &&
actualDescription.length > 0;
export async function expectToBeAHero(actualNg1Hero: webdriver.WebElement): Promise<void> {
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<void> {
const name = await actualNg1Hero.findElement(webdriver.By.css('h2')).getText();
expect(name).toBe(expectedName);
}
@@ -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 `<ng2-heroes>` 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 `<ng1-hero>` 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');
});
});
+1 -1
View File
@@ -2,6 +2,6 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"lib": ["es2015"],
"types": ["node", "jasminewd2"]
"types": ["node", "jasmine", "selenium-webdriver"]
}
}
@@ -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",
],
)