build: switch adev tests away from protractor

Reworks the tests in adev not to depend on Protractor.

(cherry picked from commit 7b74bee5b4)
This commit is contained in:
Kristiyan Kostadinov
2026-08-14 09:23:04 +02:00
committed by Jessica Janiuk
parent 3e02b0a2e5
commit e120d2830b
61 changed files with 924 additions and 844 deletions
@@ -1,15 +1,26 @@
import {browser, element, by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('Accessibility example e2e tests', () => {
beforeEach(() => browser.get(''));
let driver: webdriver.WebDriver;
beforeEach(async () => {
await driver.get('');
});
it('should display Accessibility Example', async () => {
expect(await element(by.css('h1')).getText()).toEqual('Accessibility Example');
expect(await driver.findElement(webdriver.By.css('h1')).getText()).toEqual(
'Accessibility Example',
);
});
it('should take a number and change progressbar width', async () => {
await element(by.css('input')).sendKeys('16');
expect(await element(by.css('input')).getAttribute('value')).toEqual('16');
expect(await element(by.css('app-example-progressbar div')).getCssValue('width')).toBe('48px');
const input = driver.findElement(webdriver.By.css('input'));
await input.sendKeys('16');
expect(await input.getAttribute('value')).toEqual('16');
expect(
await driver
.findElement(webdriver.By.css('app-example-progressbar div'))
.getCssValue('width'),
).toBe('48px');
});
});
@@ -1,7 +1,5 @@
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [provideProtractorTestingSupport()],
}).catch((err) => console.error(err));
bootstrapApplication(AppComponent).catch((err) => console.error(err));
@@ -1,22 +1,21 @@
import {AppPage} from './app.po';
import {browser, logging} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('workspace-project App', () => {
let page: AppPage;
let driver: webdriver.WebDriver;
beforeEach(() => {
page = new AppPage();
beforeEach(async () => {
await driver.get('');
});
// Add your e2e tests here
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
const logs = await driver.manage().logs().get(webdriver.logging.Type.BROWSER);
expect(logs).not.toContain(
jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry),
level: webdriver.logging.Level.SEVERE,
} as webdriver.logging.Entry),
);
});
});
@@ -1,19 +1,10 @@
{
"projectType": "cli",
"overrideBoilerplate": [
"tsconfig.json",
"tsconfig.app.json"
],
"tests": [
{
"cmd": "yarn",
"args": [
"e2e",
"--protractor-config=e2e/protractor-bazel.conf.js",
"--no-webdriver-update",
"--port=0"
]
}
]
}
"projectType": "cli",
"overrideBoilerplate": ["tsconfig.json", "tsconfig.app.json"],
"tests": [
{
"cmd": "yarn",
"args": ["e2e"]
}
]
}
@@ -1,7 +1,5 @@
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [provideProtractorTestingSupport()],
}).catch((err) => console.error(err));
bootstrapApplication(AppComponent).catch((err) => console.error(err));
@@ -1,5 +1,4 @@
import {browser} from 'protractor';
import {logging} from 'selenium-webdriver';
import * as webdriver from 'selenium-webdriver';
import * as openClose from './open-close.po';
import * as statusSlider from './status-slider.po';
import * as toggle from './toggle.po';
@@ -11,41 +10,32 @@ import {getLinkById, sleepFor} from './util';
import {getComponentSection, getToggleButton} from './querying.po';
describe('Animation Tests', () => {
let driver: webdriver.WebDriver;
const routingAnimationDuration = 350;
const openCloseHref = getLinkById('open-close');
const statusSliderHref = getLinkById('status');
const toggleHref = getLinkById('toggle');
const enterLeaveHref = getLinkById('enter-leave');
const autoHref = getLinkById('auto');
const filterHref = getLinkById('heroes');
const heroGroupsHref = getLinkById('hero-groups');
const queryingHref = getLinkById('querying');
const newPageSleepFor = (ms = 0) => sleepFor(ms + routingAnimationDuration);
beforeAll(() => browser.get(''));
beforeAll(async () => {
await driver.get('');
});
describe('Open/Close Component', () => {
const closedHeight = '100px';
const openHeight = '200px';
beforeAll(async () => {
await openCloseHref.click();
await (await getLinkById(driver, 'open-close')).click();
await newPageSleepFor(300);
});
it('should be open', async () => {
const toggleButton = openClose.getToggleButton();
const container = openClose.getComponentContainer();
const toggleButton = await openClose.getToggleButton(driver);
const container = await openClose.getComponentContainer(driver);
let text = await container.getText();
if (text.includes('Closed')) {
await toggleButton.click();
await browser.wait(
async () => (await container.getCssValue('height')) === openHeight,
2000,
);
await driver.wait(async () => (await container.getCssValue('height')) === openHeight, 2000);
}
text = await container.getText();
@@ -56,13 +46,13 @@ describe('Animation Tests', () => {
});
it('should be closed', async () => {
const toggleButton = openClose.getToggleButton();
const container = openClose.getComponentContainer();
const toggleButton = await openClose.getToggleButton(driver);
const container = await openClose.getComponentContainer(driver);
let text = await container.getText();
if (text.includes('Open')) {
await toggleButton.click();
await browser.wait(
await driver.wait(
async () => (await container.getCssValue('height')) === closedHeight,
2000,
);
@@ -76,12 +66,12 @@ describe('Animation Tests', () => {
});
it('should log animation events', async () => {
const toggleButton = openClose.getToggleButton();
const loggingCheckbox = openClose.getLoggingCheckbox();
const toggleButton = await openClose.getToggleButton(driver);
const loggingCheckbox = await openClose.getLoggingCheckbox(driver);
await loggingCheckbox.click();
await toggleButton.click();
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
const logs = await driver.manage().logs().get(webdriver.logging.Type.BROWSER);
const animationMessages = logs.filter(({message}) => message.includes('Animation'));
expect(animationMessages.length).toBeGreaterThan(0);
@@ -93,18 +83,18 @@ describe('Animation Tests', () => {
const inactiveColor = 'rgba(0, 0, 255, 1)';
beforeAll(async () => {
await statusSliderHref.click();
await (await getLinkById(driver, 'status')).click();
await newPageSleepFor(2000);
});
it('should be inactive with a blue background', async () => {
const toggleButton = statusSlider.getToggleButton();
const container = statusSlider.getComponentContainer();
const toggleButton = await statusSlider.getToggleButton(driver);
const container = await statusSlider.getComponentContainer(driver);
let text = await container.getText();
if (text === 'Active') {
await toggleButton.click();
await browser.wait(
await driver.wait(
async () => (await container.getCssValue('backgroundColor')) === inactiveColor,
3000,
);
@@ -118,13 +108,13 @@ describe('Animation Tests', () => {
});
it('should be active with an orange background', async () => {
const toggleButton = statusSlider.getToggleButton();
const container = statusSlider.getComponentContainer();
const toggleButton = await statusSlider.getToggleButton(driver);
const container = await statusSlider.getComponentContainer(driver);
let text = await container.getText();
if (text === 'Inactive') {
await toggleButton.click();
await browser.wait(
await driver.wait(
async () => (await container.getCssValue('backgroundColor')) === activeColor,
3000,
);
@@ -140,16 +130,16 @@ describe('Animation Tests', () => {
describe('Toggle Animations Component', () => {
beforeAll(async () => {
await toggleHref.click();
await (await getLinkById(driver, 'toggle')).click();
await newPageSleepFor();
});
it('should disabled animations on the child element', async () => {
const toggleButton = toggle.getToggleAnimationsButton();
const toggleButton = await toggle.getToggleAnimationsButton(driver);
await toggleButton.click();
const container = toggle.getComponentContainer();
const container = await toggle.getComponentContainer(driver);
const cssClasses = await container.getAttribute('class');
expect(cssClasses).toContain('ng-animate-disabled');
@@ -158,13 +148,13 @@ describe('Animation Tests', () => {
describe('Enter/Leave Component', () => {
beforeAll(async () => {
await enterLeaveHref.click();
await (await getLinkById(driver, 'enter-leave')).click();
await newPageSleepFor(100);
});
it('should attach a flyInOut trigger to the list of items', async () => {
const heroesList = enterLeave.getHeroesList();
const hero = heroesList.get(0);
const heroesList = await enterLeave.getHeroesList(driver);
const hero = heroesList[0];
const cssClasses = await hero.getAttribute('class');
const transform = await hero.getCssValue('transform');
@@ -173,75 +163,75 @@ describe('Animation Tests', () => {
});
it('should remove the hero from the list when clicked', async () => {
const heroesList = enterLeave.getHeroesList();
const total = await heroesList.count();
const hero = heroesList.get(0);
const heroesList = await enterLeave.getHeroesList(driver);
const total = heroesList.length;
const hero = heroesList[0];
await hero.click();
await browser.wait(async () => (await heroesList.count()) < total, 2000);
await driver.wait(async () => (await enterLeave.getHeroesList(driver)).length < total, 2000);
});
});
describe('Auto Calculation Component', () => {
beforeAll(async () => {
await autoHref.click();
await (await getLinkById(driver, 'auto')).click();
await newPageSleepFor();
});
it('should attach a shrinkOut trigger to the list of items', async () => {
const heroesList = auto.getHeroesList();
const hero = heroesList.get(0);
const heroesList = await auto.getHeroesList(driver);
const hero = heroesList[0];
const cssClasses = await hero.getAttribute('class');
expect(cssClasses).toContain('ng-trigger-shrinkOut');
});
it('should remove the hero from the list when clicked', async () => {
const heroesList = auto.getHeroesList();
const total = await heroesList.count();
const hero = heroesList.get(0);
const heroesList = await auto.getHeroesList(driver);
const total = heroesList.length;
const hero = heroesList[0];
await hero.click();
await browser.wait(async () => (await heroesList.count()) < total, 2000);
await driver.wait(async () => (await auto.getHeroesList(driver)).length < total, 2000);
});
});
describe('Filter/Stagger Component', () => {
beforeAll(async () => {
await filterHref.click();
await (await getLinkById(driver, 'heroes')).click();
await newPageSleepFor();
});
it('should attach a filterAnimations trigger to the list container', async () => {
const heroesList = filterStagger.getComponentContainer();
const heroesList = await filterStagger.getComponentContainer(driver);
const cssClasses = await heroesList.getAttribute('class');
expect(cssClasses).toContain('ng-trigger-filterAnimation');
});
it('should filter down the list when a search is performed', async () => {
const heroesList = filterStagger.getHeroesList();
const total = await heroesList.count();
const heroesList = await filterStagger.getHeroesList(driver);
const total = heroesList.length;
const input = filterStagger.getInput();
const input = await filterStagger.getInput(driver);
await input.sendKeys('Mag');
await browser.wait(async () => (await heroesList.count()) === 2, 2000);
await driver.wait(async () => (await filterStagger.getHeroesList(driver)).length === 2, 2000);
const newTotal = await heroesList.count();
const newTotal = (await filterStagger.getHeroesList(driver)).length;
expect(newTotal).toBeLessThan(total);
});
});
describe('Hero Groups Component', () => {
beforeAll(async () => {
await heroGroupsHref.click();
await (await getLinkById(driver, 'hero-groups')).click();
await newPageSleepFor(400);
});
it('should attach a flyInOut trigger to the list of items', async () => {
const heroesList = heroGroups.getHeroesList();
const hero = heroesList.get(0);
const heroesList = await heroGroups.getHeroesList(driver);
const hero = heroesList[0];
const cssClasses = await hero.getAttribute('class');
const transform = await hero.getCssValue('transform');
const opacity = await hero.getCssValue('opacity');
@@ -252,12 +242,12 @@ describe('Animation Tests', () => {
});
it('should remove the hero from the list when clicked', async () => {
const heroesList = heroGroups.getHeroesList();
const total = await heroesList.count();
const hero = heroesList.get(0);
const heroesList = await heroGroups.getHeroesList(driver);
const total = heroesList.length;
const hero = heroesList[0];
await hero.click();
await browser.wait(async () => (await heroesList.count()) < total, 2000);
await driver.wait(async () => (await heroGroups.getHeroesList(driver)).length < total, 2000);
});
});
@@ -265,30 +255,32 @@ describe('Animation Tests', () => {
const queryingAnimationDuration = 2500;
beforeAll(async () => {
await queryingHref.click();
await (await getLinkById(driver, 'querying')).click();
await newPageSleepFor(queryingAnimationDuration);
});
it('should toggle the section', async () => {
const toggleButton = getToggleButton();
const section = getComponentSection();
const toggleButton = await getToggleButton(driver);
const section = await getComponentSection(driver);
expect(await section.isPresent()).toBe(true);
expect(await section.isDisplayed()).toBe(true);
// toggling off
await toggleButton.click();
await newPageSleepFor(queryingAnimationDuration);
expect(await section.isPresent()).toBe(false);
const sectionsOff = await driver.findElements(webdriver.By.css('app-querying section'));
expect(sectionsOff.length).toBe(0);
// toggling on
await toggleButton.click();
await newPageSleepFor(queryingAnimationDuration);
expect(await section.isPresent()).toBe(true);
const sectionsOn = await driver.findElements(webdriver.By.css('app-querying section'));
expect(sectionsOn.length).toBe(1);
await newPageSleepFor(queryingAnimationDuration);
});
it(`should disable the button for the animation's duration`, async () => {
const toggleButton = getToggleButton();
const toggleButton = await getToggleButton(driver);
expect(await toggleButton.isEnabled()).toBe(true);
// toggling off
@@ -1,19 +1,19 @@
import {by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
import {locate} from './util';
export function getPage() {
return by.css('app-hero-list-auto-page');
export function getPage(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-hero-list-auto-page'));
}
export function getComponent() {
return by.css('app-hero-list-auto');
export function getComponent(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-hero-list-auto'));
}
export function getComponentContainer() {
const findContainer = () => by.css('ul');
return locate(getComponent(), findContainer());
export async function getComponentContainer(driver: webdriver.WebDriver) {
return locate(driver, webdriver.By.css('app-hero-list-auto'), webdriver.By.css('ul'));
}
export function getHeroesList() {
return getComponentContainer().all(by.css('li'));
export async function getHeroesList(driver: webdriver.WebDriver) {
const container = await getComponentContainer(driver);
return container.findElements(webdriver.By.css('li'));
}
@@ -1,19 +1,19 @@
import {by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
import {locate} from './util';
export function getPage() {
return by.css('app-hero-list-enter-leave-page');
export function getPage(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-hero-list-enter-leave-page'));
}
export function getComponent() {
return by.css('app-hero-list-enter-leave');
export function getComponent(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-hero-list-enter-leave'));
}
export function getComponentContainer() {
const findContainer = () => by.css('ul');
return locate(getComponent(), findContainer());
export async function getComponentContainer(driver: webdriver.WebDriver) {
return locate(driver, webdriver.By.css('app-hero-list-enter-leave'), webdriver.By.css('ul'));
}
export function getHeroesList() {
return getComponentContainer().all(by.css('li'));
export async function getHeroesList(driver: webdriver.WebDriver) {
const container = await getComponentContainer(driver);
return container.findElements(webdriver.By.css('li'));
}
@@ -1,20 +1,19 @@
import {by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
import {locate} from './util';
export function getPage() {
return by.css('app-hero-list-page');
export function getPage(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-hero-list-page'));
}
export function getComponentContainer() {
const findContainer = () => by.css('ul');
return locate(getPage(), findContainer());
export async function getComponentContainer(driver: webdriver.WebDriver) {
return locate(driver, webdriver.By.css('app-hero-list-page'), webdriver.By.css('ul'));
}
export function getHeroesList() {
return getComponentContainer().all(by.css('li'));
export async function getHeroesList(driver: webdriver.WebDriver) {
const container = await getComponentContainer(driver);
return container.findElements(webdriver.By.css('li'));
}
export function getInput() {
const input = () => by.css('input');
return locate(getPage(), input());
export async function getInput(driver: webdriver.WebDriver) {
return locate(driver, webdriver.By.css('app-hero-list-page'), webdriver.By.css('input'));
}
@@ -1,19 +1,19 @@
import {by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
import {locate} from './util';
export function getPage() {
return by.css('app-hero-list-groups-page');
export function getPage(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-hero-list-groups-page'));
}
export function getComponent() {
return by.css('app-hero-list-groups');
export function getComponent(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-hero-list-groups'));
}
export function getComponentContainer() {
const findContainer = () => by.css('ul');
return locate(getComponent(), findContainer());
export async function getComponentContainer(driver: webdriver.WebDriver) {
return locate(driver, webdriver.By.css('app-hero-list-groups'), webdriver.By.css('ul'));
}
export function getHeroesList() {
return getComponentContainer().all(by.css('li'));
export async function getHeroesList(driver: webdriver.WebDriver) {
const container = await getComponentContainer(driver);
return container.findElements(webdriver.By.css('li'));
}
@@ -1,25 +1,27 @@
import {by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
import {locate} from './util';
export function getPage() {
return by.css('app-open-close-page');
export function getPage(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-open-close-page'));
}
export function getComponent() {
return by.css('app-open-close');
export function getComponent(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-open-close'));
}
export function getToggleButton() {
const toggleButton = () => by.buttonText('Toggle Open/Close');
return locate(getComponent(), toggleButton());
export async function getToggleButton(driver: webdriver.WebDriver) {
const comp = await getComponent(driver);
return comp.findElement(webdriver.By.xpath('.//button[normalize-space()="Toggle Open/Close"]'));
}
export function getLoggingCheckbox() {
const loggingCheckbox = () => by.css('section > input[type="checkbox"]');
return locate(getPage(), loggingCheckbox());
export async function getLoggingCheckbox(driver: webdriver.WebDriver) {
return locate(
driver,
webdriver.By.css('app-open-close-page'),
webdriver.By.css('section > input[type="checkbox"]'),
);
}
export function getComponentContainer() {
const findContainer = () => by.css('div');
return locate(getComponent(), findContainer());
export async function getComponentContainer(driver: webdriver.WebDriver) {
return locate(driver, webdriver.By.css('app-open-close'), webdriver.By.css('div'));
}
@@ -1,16 +1,14 @@
import {by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
import {locate} from './util';
export function getComponent() {
return by.css('app-querying');
export function getComponent(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-querying'));
}
export function getToggleButton() {
const toggleButton = () => by.className('toggle');
return locate(getComponent(), toggleButton());
export async function getToggleButton(driver: webdriver.WebDriver) {
return locate(driver, webdriver.By.css('app-querying'), webdriver.By.className('toggle'));
}
export function getComponentSection() {
const findSection = () => by.css('section');
return locate(getComponent(), findSection());
export async function getComponentSection(driver: webdriver.WebDriver) {
return locate(driver, webdriver.By.css('app-querying'), webdriver.By.css('section'));
}
@@ -1,20 +1,19 @@
import {by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
import {locate} from './util';
export function getPage() {
return by.css('app-status-slider-page');
export function getPage(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-status-slider-page'));
}
export function getComponent() {
return by.css('app-status-slider');
export function getComponent(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-status-slider'));
}
export function getToggleButton() {
const toggleButton = () => by.buttonText('Toggle Status');
return locate(getComponent(), toggleButton());
export async function getToggleButton(driver: webdriver.WebDriver) {
const comp = await getComponent(driver);
return comp.findElement(webdriver.By.xpath('.//button[normalize-space()="Toggle Status"]'));
}
export function getComponentContainer() {
const findContainer = () => by.css('div');
return locate(getComponent(), findContainer());
export async function getComponentContainer(driver: webdriver.WebDriver) {
return locate(driver, webdriver.By.css('app-status-slider'), webdriver.By.css('div'));
}
@@ -1,25 +1,26 @@
import {by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
import {locate} from './util';
export function getPage() {
return by.css('app-toggle-animations-child-page');
export function getPage(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-toggle-animations-child-page'));
}
export function getComponent() {
return by.css('app-open-close-toggle');
export function getComponent(driver: webdriver.WebDriver) {
return driver.findElement(webdriver.By.css('app-open-close-toggle'));
}
export function getToggleButton() {
const toggleButton = () => by.buttonText('Toggle Open/Closed');
return locate(getComponent(), toggleButton());
export async function getToggleButton(driver: webdriver.WebDriver) {
const comp = await getComponent(driver);
return comp.findElement(webdriver.By.xpath('.//button[normalize-space()="Toggle Open/Closed"]'));
}
export function getToggleAnimationsButton() {
const toggleAnimationsButton = () => by.buttonText('Toggle Animations');
return locate(getComponent(), toggleAnimationsButton());
export async function getToggleAnimationsButton(driver: webdriver.WebDriver) {
const comp = await getComponent(driver);
return comp.findElement(webdriver.By.xpath('.//button[normalize-space()="Toggle Animations"]'));
}
export function getComponentContainer() {
const findContainer = () => by.css('div');
return locate(getComponent()).all(findContainer()).get(0);
export async function getComponentContainer(driver: webdriver.WebDriver) {
const comp = await getComponent(driver);
const divs = await comp.findElements(webdriver.By.css('div'));
return divs[0];
}
@@ -1,20 +1,23 @@
import {Locator, ElementFinder, browser, by, element} from 'protractor';
import * as webdriver from 'selenium-webdriver';
/**
*
* locate(finder1, finder2) => element(finder1).element(finder2).element(finderN);
* locate(parent, finder1, finder2) => parent.findElement(finder1).findElement(finder2);
*/
export function locate(locator: Locator, ...locators: Locator[]) {
return locators.reduce(
(current: ElementFinder, next: Locator) => current.element(next),
element(locator),
) as ElementFinder;
export async function locate(
parent: webdriver.WebDriver | webdriver.WebElement,
...locators: webdriver.Locator[]
): Promise<webdriver.WebElement> {
let current: webdriver.WebElement = await parent.findElement(locators[0]);
for (let i = 1; i < locators.length; i++) {
current = await current.findElement(locators[i]);
}
return current;
}
export async function sleepFor(time = 1000) {
return await browser.sleep(time);
return new Promise((resolve) => setTimeout(resolve, time));
}
export function getLinkById(id: string) {
return element(by.css(`a[id=${id}]`));
export function getLinkById(driver: webdriver.WebDriver, id: string) {
return driver.findElement(webdriver.By.css(`a[id=${id}]`));
}
@@ -1,14 +1,8 @@
import {ApplicationConfig} from '@angular/core';
import {routes} from './app.routes';
import {provideRouter} from '@angular/router';
import {provideProtractorTestingSupport} from '@angular/platform-browser';
import {provideAnimations} from '@angular/platform-browser/animations';
export const appConfig: ApplicationConfig = {
providers: [
// needed for supporting e2e tests
provideProtractorTestingSupport(),
provideRouter(routes),
provideAnimations(),
],
providers: [provideRouter(routes), provideAnimations()],
};
@@ -1,27 +1,37 @@
import {browser, element, by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('Attribute directives', () => {
let driver: webdriver.WebDriver;
const title = 'My First Attribute Directive';
beforeAll(() => browser.get(''));
beforeAll(async () => {
await driver.get('');
});
it(`should display correct title: ${title}`, async () => {
expect(await element(by.css('h1')).getText()).toEqual(title);
expect(await driver.findElement(webdriver.By.css('h1')).getText()).toEqual(title);
});
it('should be able to select green highlight', async () => {
const highlightedEle = element(by.cssContainingText('p', 'Highlight me!'));
const paragraphs = await driver.findElements(webdriver.By.css('p'));
let highlightedEle: webdriver.WebElement | null = null;
for (const p of paragraphs) {
if ((await p.getText()).includes('Highlight me!')) {
highlightedEle = p;
break;
}
}
const lightGreen = 'rgba(144, 238, 144, 1)';
const getBgColor = () => highlightedEle.getCssValue('background-color');
const getBgColor = () => highlightedEle!.getCssValue('background-color');
expect(await highlightedEle.getCssValue('background-color')).not.toEqual(lightGreen);
expect(await getBgColor()).not.toEqual(lightGreen);
const greenRb = element.all(by.css('input')).get(0);
const greenRb = (await driver.findElements(webdriver.By.css('input')))[0];
await greenRb.click();
await browser.actions().mouseMove(highlightedEle).perform();
await driver.actions().move({origin: highlightedEle!}).perform();
// Wait for up to 4s for the background color to be updated,
// to account for slow environments (e.g. CI).
await browser.wait(async () => (await getBgColor()) === lightGreen, 4000);
await driver.wait(async () => (await getBgColor()) === lightGreen, 4000);
});
});
@@ -1,8 +1,6 @@
// #docregion
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [provideProtractorTestingSupport()],
}).catch((err) => console.error(err));
bootstrapApplication(AppComponent).catch((err) => console.error(err));
@@ -1,16 +1,20 @@
import {browser, element, by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('Built-in Directives', () => {
beforeAll(() => browser.get(''));
let driver: webdriver.WebDriver;
beforeAll(async () => {
await driver.get('');
});
it('should have title Built-in Directives', async () => {
const title = element.all(by.css('h1')).get(0);
const title = (await driver.findElements(webdriver.By.css('h1')))[0];
expect(await title.getText()).toEqual('Built-in Directives');
});
it('should change first Teapot header', async () => {
const firstLabel = element.all(by.css('p')).get(0);
const firstInput = element.all(by.css('input')).get(0);
const firstLabel = (await driver.findElements(webdriver.By.css('p')))[0];
const firstInput = (await driver.findElements(webdriver.By.css('input')))[0];
expect(await firstLabel.getText()).toEqual('Current item name: Teapot');
await firstInput.sendKeys('abc');
@@ -18,48 +22,60 @@ describe('Built-in Directives', () => {
});
it('should modify sentence when modified checkbox checked', async () => {
const modifiedChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(1);
const modifiedSentence = element.all(by.css('div')).get(1);
const modifiedChkbxLabel = (
await driver.findElements(webdriver.By.css('input[type="checkbox"]'))
)[1];
const modifiedSentence = (await driver.findElements(webdriver.By.css('div')))[1];
await modifiedChkbxLabel.click();
expect(await modifiedSentence.getText()).toContain('modified');
});
it('should modify sentence when normal checkbox checked', async () => {
const normalChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(4);
const normalSentence = element.all(by.css('div')).get(7);
const normalChkbxLabel = (
await driver.findElements(webdriver.By.css('input[type="checkbox"]'))
)[4];
const normalSentence = (await driver.findElements(webdriver.By.css('div')))[7];
await normalChkbxLabel.click();
expect(await normalSentence.getText()).toContain('normal weight and, extra large');
});
it('should toggle app-item-detail', async () => {
const toggleButton = element.all(by.css('button')).get(3);
const toggledDiv = element.all(by.css('app-item-detail')).get(0);
const toggleButton = (await driver.findElements(webdriver.By.css('button')))[3];
const toggledDiv = (await driver.findElements(webdriver.By.css('app-item-detail')))[0];
await toggleButton.click();
expect(await toggledDiv.isDisplayed()).toBe(true);
});
it('should hide app-item-detail', async () => {
const hiddenMessage = element.all(by.css('p')).get(10);
const hiddenDiv = element.all(by.css('app-item-detail')).get(2);
const hiddenMessage = (await driver.findElements(webdriver.By.css('p')))[10];
const hiddenDiv = (await driver.findElements(webdriver.By.css('app-item-detail')))[2];
expect(await hiddenMessage.getText()).toContain('in the DOM');
expect(await hiddenDiv.isDisplayed()).toBe(true);
});
it('should have 10 lists each containing the string Teapot', async () => {
const listDiv = element.all(by.cssContainingText('.box', 'Teapot'));
expect(await listDiv.count()).toBe(10);
const boxes = await driver.findElements(webdriver.By.css('.box'));
const teapotBoxes: webdriver.WebElement[] = [];
for (const b of boxes) {
if ((await b.getText()).includes('Teapot')) {
teapotBoxes.push(b);
}
}
expect(teapotBoxes.length).toBe(10);
});
it('should switch case', async () => {
const tvRadioButton = element.all(by.css('input[type="radio"]')).get(3);
const tvDiv = element(by.css('app-lost-item'));
const tvRadioButton = (await driver.findElements(webdriver.By.css('input[type="radio"]')))[3];
const tvDiv = driver.findElement(webdriver.By.css('app-lost-item'));
const fishbowlRadioButton = element.all(by.css('input[type="radio"]')).get(4);
const fishbowlDiv = element(by.css('app-unknown-item'));
const fishbowlRadioButton = (
await driver.findElements(webdriver.By.css('input[type="radio"]'))
)[4];
const fishbowlDiv = driver.findElement(webdriver.By.css('app-unknown-item'));
await tvRadioButton.click();
expect(await tvDiv.getText()).toContain('Television');
@@ -1,7 +1,5 @@
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [provideProtractorTestingSupport()],
}).catch((err) => console.error(err));
bootstrapApplication(AppComponent).catch((err) => console.error(err));
@@ -1,21 +1,34 @@
import {browser, element, by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('Dynamic Form', () => {
beforeAll(() => browser.get(''));
let driver: webdriver.WebDriver;
beforeAll(async () => {
await driver.get('');
});
it('should submit form', async () => {
const firstNameElement = element.all(by.css('input[id=firstName]')).get(0);
const firstNameElement = (
await driver.findElements(webdriver.By.css('input[id=firstName]'))
)[0];
expect(await firstNameElement.getAttribute('value')).toEqual('Bombasto');
const emailElement = element.all(by.css('input[id=emailAddress]')).get(0);
const emailElement = (await driver.findElements(webdriver.By.css('input[id=emailAddress]')))[0];
const email = 'test@test.com';
await emailElement.sendKeys(email);
expect(await emailElement.getAttribute('value')).toEqual(email);
await element(by.css('select option[value="solid"]')).click();
await element.all(by.css('button')).get(0).click();
expect(
await element(by.cssContainingText('strong', 'Saved the following values')).isPresent(),
).toBe(true);
await (await driver.findElement(webdriver.By.css('select option[value="solid"]'))).click();
await (await driver.findElements(webdriver.By.css('button')))[0].click();
const strongs = await driver.findElements(webdriver.By.css('strong'));
let found = false;
for (const s of strongs) {
if ((await s.getText()).includes('Saved the following values')) {
found = true;
break;
}
}
expect(found).toBe(true);
});
});
@@ -1,8 +1,6 @@
// #docregion
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [provideProtractorTestingSupport()],
});
bootstrapApplication(AppComponent);
@@ -1,81 +1,97 @@
import {browser, by, element, ElementFinder, ExpectedConditions as EC} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('Elements', () => {
const messageInput = element(by.css('input'));
const popupButtons = element.all(by.css('button'));
let driver: webdriver.WebDriver;
// Helpers
const click = async (elem: ElementFinder) => {
// Waiting for the element to be clickable, makes the tests less flaky.
await browser.wait(EC.elementToBeClickable(elem), 5000);
const click = async (elem: webdriver.WebElement) => {
await driver.wait(webdriver.until.elementIsVisible(elem), 5000);
await elem.click();
};
const waitForText = async (elem: ElementFinder) => {
// Waiting for the element to have some text, makes the tests less flaky.
await browser.wait(async () => /\S/.test(await elem.getText()), 5000);
const waitForText = async (elem: webdriver.WebElement) => {
await driver.wait(async () => /\S/.test(await elem.getText()), 5000);
};
beforeEach(() => browser.get(''));
const isPresent = async (locator: webdriver.Locator) => {
const els = await driver.findElements(locator);
return els.length > 0;
};
beforeEach(async () => {
await driver.get('');
});
describe('popup component', () => {
const popupComponentButton = popupButtons.get(0);
const popupComponent = element(by.css('popup-component'));
const closeButton = popupComponent.element(by.css('button'));
it('should be displayed on button click', async () => {
expect(await popupComponent.isPresent()).toBe(false);
const popupComponentLocator = webdriver.By.css('popup-component');
expect(await isPresent(popupComponentLocator)).toBe(false);
await click(popupComponentButton);
expect(await popupComponent.isPresent()).toBe(true);
const popupButtons = await driver.findElements(webdriver.By.css('button'));
await click(popupButtons[0]);
expect(await isPresent(popupComponentLocator)).toBe(true);
});
it('should display the specified message', async () => {
const messageInput = await driver.findElement(webdriver.By.css('input'));
await messageInput.clear();
await messageInput.sendKeys('Angular rocks!');
await click(popupComponentButton);
const popupButtons = await driver.findElements(webdriver.By.css('button'));
await click(popupButtons[0]);
const popupComponent = await driver.findElement(webdriver.By.css('popup-component'));
await waitForText(popupComponent);
expect(await popupComponent.getText()).toContain('Popup: Angular rocks!');
});
it('should be closed on "close" button click', async () => {
await click(popupComponentButton);
expect(await popupComponent.isPresent()).toBe(true);
const popupComponentLocator = webdriver.By.css('popup-component');
const popupButtons = await driver.findElements(webdriver.By.css('button'));
await click(popupButtons[0]);
expect(await isPresent(popupComponentLocator)).toBe(true);
const popupComponent = await driver.findElement(popupComponentLocator);
const closeButton = await popupComponent.findElement(webdriver.By.css('button'));
await click(closeButton);
expect(await popupComponent.isPresent()).toBe(false);
expect(await isPresent(popupComponentLocator)).toBe(false);
});
});
describe('popup element', () => {
const popupElementButton = popupButtons.get(1);
const popupElement = element(by.css('popup-element'));
const closeButton = popupElement.element(by.css('button'));
it('should be displayed on button click', async () => {
expect(await popupElement.isPresent()).toBe(false);
const popupElementLocator = webdriver.By.css('popup-element');
expect(await isPresent(popupElementLocator)).toBe(false);
await click(popupElementButton);
expect(await popupElement.isPresent()).toBe(true);
const popupButtons = await driver.findElements(webdriver.By.css('button'));
await click(popupButtons[1]);
expect(await isPresent(popupElementLocator)).toBe(true);
});
it('should display the specified message', async () => {
const messageInput = await driver.findElement(webdriver.By.css('input'));
await messageInput.clear();
await messageInput.sendKeys('Angular rocks!');
await click(popupElementButton);
const popupButtons = await driver.findElements(webdriver.By.css('button'));
await click(popupButtons[1]);
const popupElement = await driver.findElement(webdriver.By.css('popup-element'));
await waitForText(popupElement);
expect(await popupElement.getText()).toContain('Popup: Angular rocks!');
});
it('should be closed on "close" button click', async () => {
await click(popupElementButton);
expect(await popupElement.isPresent()).toBe(true);
const popupElementLocator = webdriver.By.css('popup-element');
const popupButtons = await driver.findElements(webdriver.By.css('button'));
await click(popupButtons[1]);
expect(await isPresent(popupElementLocator)).toBe(true);
const popupElement = await driver.findElement(popupElementLocator);
const closeButton = await popupElement.findElement(webdriver.By.css('button'));
await click(closeButton);
expect(await popupElement.isPresent()).toBe(false);
expect(await isPresent(popupElementLocator)).toBe(false);
});
});
});
@@ -1,7 +1,5 @@
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {
providers: [provideProtractorTestingSupport()],
}).catch((err) => console.error(err));
bootstrapApplication(App).catch((err) => console.error(err));
@@ -1,8 +1,12 @@
import {browser, element, by, protractor, ElementFinder, ElementArrayFinder} from 'protractor';
import * as webdriver from 'selenium-webdriver';
// THESE TESTS ARE INCOMPLETE
describe('Form Validation Tests', () => {
beforeAll(() => browser.get(''));
let driver: webdriver.WebDriver;
beforeAll(async () => {
await driver.get('');
});
describe('Template-driven form', () => {
beforeAll(() => {
@@ -25,222 +29,221 @@ describe('Form Validation Tests', () => {
asyncValidationTests();
crossValidationTests();
});
});
//////////
const testName = 'Test Name';
const testName = 'Test Name';
let page: {
section: ElementFinder;
form: ElementFinder;
title: ElementFinder;
nameInput: ElementFinder;
roleInput: ElementFinder;
skillSelect: ElementFinder;
skillOption: ElementFinder;
errorMessages: ElementArrayFinder;
actorFormButtons: ElementArrayFinder;
actorSubmitted: ElementFinder;
roleErrors: ElementFinder;
crossValidationErrorMessage: ElementFinder;
};
function getPage(sectionTag: string) {
const section = element(by.css(sectionTag));
const buttons = section.all(by.css('button'));
page = {
section,
form: section.element(by.css('form')),
title: section.element(by.css('h2')),
nameInput: section.element(by.css('#name')),
roleInput: section.element(by.css('#role')),
skillSelect: section.element(by.css('#skill')),
skillOption: section.element(by.css('#skill option')),
errorMessages: section.all(by.css('div.alert')),
actorFormButtons: buttons,
actorSubmitted: section.element(by.css('.submitted-message')),
roleErrors: section.element(by.css('.role-errors')),
crossValidationErrorMessage: section.element(by.css('.cross-validation-error-message')),
let page: {
sectionTag: string;
section: () => webdriver.WebElement;
form: () => webdriver.WebElement;
title: () => webdriver.WebElement;
nameInput: () => webdriver.WebElement;
roleInput: () => webdriver.WebElement;
skillSelect: () => webdriver.WebElement;
skillOption: () => webdriver.WebElement;
errorMessages: () => Promise<webdriver.WebElement[]>;
actorFormButtons: () => Promise<webdriver.WebElement[]>;
actorSubmitted: () => webdriver.WebElement;
roleErrors: () => webdriver.WebElement;
crossValidationErrorMessage: () => webdriver.WebElement;
};
}
function tests(title: string) {
it('should display correct title', async () => {
expect(await page.title.getText()).toContain(title);
});
function getPage(sectionTag: string) {
const sec = () => driver.findElement(webdriver.By.css(sectionTag));
it('should not display submitted message before submit', async () => {
expect(await page.actorSubmitted.isElementPresent(by.css('p'))).toBe(false);
});
page = {
sectionTag,
section: sec,
form: () => sec().findElement(webdriver.By.css('form')),
title: () => sec().findElement(webdriver.By.css('h2')),
nameInput: () => sec().findElement(webdriver.By.css('#name')),
roleInput: () => sec().findElement(webdriver.By.css('#role')),
skillSelect: () => sec().findElement(webdriver.By.css('#skill')),
skillOption: () => sec().findElement(webdriver.By.css('#skill option')),
errorMessages: () => sec().findElements(webdriver.By.css('div.alert')),
actorFormButtons: () => sec().findElements(webdriver.By.css('button')),
actorSubmitted: () => sec().findElement(webdriver.By.css('.submitted-message')),
roleErrors: () => sec().findElement(webdriver.By.css('.role-errors')),
crossValidationErrorMessage: () =>
sec().findElement(webdriver.By.css('.cross-validation-error-message')),
};
}
it('should have form buttons', async () => {
expect(await page.actorFormButtons.count()).toEqual(2);
});
function tests(title: string) {
it('should display correct title', async () => {
expect(await page.title().getText()).toContain(title);
});
it('should have error at start', async () => {
await expectFormIsInvalid();
});
it('should not display submitted message before submit', async () => {
const p = await page.actorSubmitted().findElements(webdriver.By.css('p'));
expect(p.length).toBe(0);
});
// it('showForm', () => {
// page.form.getInnerHtml().then(html => console.log(html));
// });
it('should have form buttons', async () => {
expect((await page.actorFormButtons()).length).toEqual(2);
});
it('should have disabled submit button', async () => {
expect(await page.actorFormButtons.get(0).isEnabled()).toBe(false);
});
it('should have error at start', async () => {
await expectFormIsInvalid();
});
it('resetting name to valid name should clear errors', async () => {
const ele = page.nameInput;
expect(await ele.isPresent()).toBe(true, 'nameInput should exist');
await ele.clear();
await ele.sendKeys(testName);
await expectFormIsValid();
});
it('should have disabled submit button', async () => {
expect(await (await page.actorFormButtons())[0].isEnabled()).toBe(false);
});
it('should produce "required" error after clearing name', async () => {
await page.nameInput.clear();
// await page.roleInput.click(); // to blur ... didn't work
await page.nameInput.sendKeys('x', protractor.Key.BACK_SPACE); // ugh!
expect(await page.form.getAttribute('class')).toMatch('ng-invalid');
expect(await page.errorMessages.get(0).getText()).toContain('required');
});
it('resetting name to valid name should clear errors', async () => {
const ele = page.nameInput();
expect(await ele.isDisplayed()).toBe(true, 'nameInput should exist');
await ele.clear();
await ele.sendKeys(testName);
await expectFormIsValid();
});
it('should produce "at least 4 characters" error when name="x"', async () => {
await page.nameInput.clear();
await page.nameInput.sendKeys('x'); // too short
await expectFormIsInvalid();
expect(await page.errorMessages.get(0).getText()).toContain('at least 4 characters');
});
it('should produce "required" error after clearing name', async () => {
await page.nameInput().clear();
await page.nameInput().sendKeys('x', webdriver.Key.BACK_SPACE);
expect(await page.form().getAttribute('class')).toMatch('ng-invalid');
expect(await (await page.errorMessages())[0].getText()).toContain('required');
});
it('resetting name to valid name again should clear errors', async () => {
await page.nameInput.sendKeys(testName);
await expectFormIsValid();
});
it('should produce "at least 4 characters" error when name="x"', async () => {
await page.nameInput().clear();
await page.nameInput().sendKeys('x');
await expectFormIsInvalid();
expect(await (await page.errorMessages())[0].getText()).toContain('at least 4 characters');
});
it('should have enabled submit button', async () => {
const submitBtn = page.actorFormButtons.get(0);
expect(await submitBtn.isEnabled()).toBe(true);
});
it('resetting name to valid name again should clear errors', async () => {
await page.nameInput().sendKeys(testName);
await expectFormIsValid();
});
it('should hide form after submit', async () => {
await page.actorFormButtons.get(0).click();
expect(await page.actorFormButtons.get(0).isDisplayed()).toBe(false);
});
it('should have enabled submit button', async () => {
const submitBtn = (await page.actorFormButtons())[0];
expect(await submitBtn.isEnabled()).toBe(true);
});
it('submitted form should be displayed', async () => {
expect(await page.actorSubmitted.isElementPresent(by.css('p'))).toBe(true);
});
it('should hide form after submit', async () => {
await (await page.actorFormButtons())[0].click();
const forms = await driver.findElements(webdriver.By.css(`${page.sectionTag} form`));
expect(forms.length === 0 || !(await forms[0].isDisplayed())).toBe(true);
});
it('submitted form should have new actor name', async () => {
expect(await page.actorSubmitted.getText()).toContain(testName);
});
it('submitted form should be displayed', async () => {
const p = await page.actorSubmitted().findElements(webdriver.By.css('p'));
expect(p.length).toBeGreaterThan(0);
});
it('clicking edit button should reveal form again', async () => {
const newFormBtn = page.actorSubmitted.element(by.css('button'));
await newFormBtn.click();
expect(await page.actorSubmitted.isElementPresent(by.css('p'))).toBe(
false,
'submitted hidden again',
);
expect(await page.title.isDisplayed()).toBe(true, 'can see form title');
});
}
it('submitted form should have new actor name', async () => {
expect(await page.actorSubmitted().getText()).toContain(testName);
});
async function expectFormIsValid() {
expect(await page.form.getAttribute('class')).toMatch('ng-valid');
}
it('clicking edit button should reveal form again', async () => {
const newFormBtn = page.actorSubmitted().findElement(webdriver.By.css('button'));
await newFormBtn.click();
const p = await page.actorSubmitted().findElements(webdriver.By.css('p'));
expect(p.length).toBe(0, 'submitted hidden again');
expect(await page.title().isDisplayed()).toBe(true, 'can see form title');
});
}
async function expectFormIsInvalid() {
expect(await page.form.getAttribute('class')).toMatch('ng-invalid');
}
async function expectFormIsValid() {
expect(await page.form().getAttribute('class')).toMatch('ng-valid');
}
async function triggerRoleValidation() {
// role has updateOn set to 'blur', click outside of the input to trigger the blur event
await element(by.css('app-root')).click();
}
async function expectFormIsInvalid() {
expect(await page.form().getAttribute('class')).toMatch('ng-invalid');
}
async function waitForAlterEgoValidation() {
// role async validation will be performed in 400ms
await browser.sleep(400);
}
async function triggerRoleValidation() {
await driver.findElement(webdriver.By.css('app-root')).click();
}
function bobTests() {
const emsg = 'Name cannot be Bob.';
async function waitForAlterEgoValidation() {
await new Promise((resolve) => setTimeout(resolve, 400));
}
it('should produce "no bob" error after setting name to "Bobby"', async () => {
// Re-populate select element
await page.skillSelect.click();
await page.skillOption.click();
function bobTests() {
const emsg = 'Name cannot be Bob.';
await page.nameInput.clear();
await page.nameInput.sendKeys('Bobby');
await expectFormIsInvalid();
expect(await page.errorMessages.get(0).getText()).toBe(emsg);
});
it('should produce "no bob" error after setting name to "Bobby"', async () => {
await page.skillSelect().click();
await page.skillOption().click();
it('should be ok again with valid name', async () => {
await page.nameInput.clear();
await page.nameInput.sendKeys(testName);
await expectFormIsValid();
});
}
await page.nameInput().clear();
await page.nameInput().sendKeys('Bobby');
await expectFormIsInvalid();
expect(await (await page.errorMessages())[0].getText()).toBe(emsg);
});
function asyncValidationTests() {
const emsg = 'Role is already taken.';
it('should be ok again with valid name', async () => {
await page.nameInput().clear();
await page.nameInput().sendKeys(testName);
await expectFormIsValid();
});
}
it(`should produce "${emsg}" error after setting role to Eric`, async () => {
await page.roleInput.clear();
await page.roleInput.sendKeys('Eric');
function asyncValidationTests() {
const emsg = 'Role is already taken.';
await triggerRoleValidation();
await waitForAlterEgoValidation();
it(`should produce "${emsg}" error after setting role to Eric`, async () => {
await page.roleInput().clear();
await page.roleInput().sendKeys('Eric');
await expectFormIsInvalid();
expect(await page.roleErrors.getText()).toBe(emsg);
});
await triggerRoleValidation();
await waitForAlterEgoValidation();
it('should be ok again with different values', async () => {
await page.roleInput.clear();
await page.roleInput.sendKeys('John');
await expectFormIsInvalid();
expect(await page.roleErrors().getText()).toBe(emsg);
});
await triggerRoleValidation();
await waitForAlterEgoValidation();
it('should be ok again with different values', async () => {
await page.roleInput().clear();
await page.roleInput().sendKeys('John');
await expectFormIsValid();
expect(await page.roleErrors.isPresent()).toBe(false);
});
}
await triggerRoleValidation();
await waitForAlterEgoValidation();
function crossValidationTests() {
const emsg = 'Name cannot match role.';
await expectFormIsValid();
const roleErrors = await driver.findElements(
webdriver.By.css(`${page.sectionTag} .role-errors`),
);
expect(roleErrors.length).toBe(0);
});
}
it(`should produce "${emsg}" error after setting name and role to the same value`, async () => {
await page.nameInput.clear();
await page.nameInput.sendKeys('Romeo');
function crossValidationTests() {
const emsg = 'Name cannot match role.';
await page.roleInput.clear();
await page.roleInput.sendKeys('Romeo');
it(`should produce "${emsg}" error after setting name and role to the same value`, async () => {
await page.nameInput().clear();
await page.nameInput().sendKeys('Romeo');
await triggerRoleValidation();
await waitForAlterEgoValidation();
await page.roleInput().clear();
await page.roleInput().sendKeys('Romeo');
await expectFormIsInvalid();
expect(await page.crossValidationErrorMessage.getText()).toBe(emsg);
});
await triggerRoleValidation();
await waitForAlterEgoValidation();
it('should be ok again with different values', async () => {
await page.nameInput.clear();
await page.nameInput.sendKeys('Romeo');
await expectFormIsInvalid();
expect(await page.crossValidationErrorMessage().getText()).toBe(emsg);
});
await page.roleInput.clear();
await page.roleInput.sendKeys('Juliet');
it('should be ok again with different values', async () => {
await page.nameInput().clear();
await page.nameInput().sendKeys('Romeo');
await triggerRoleValidation();
await waitForAlterEgoValidation();
await page.roleInput().clear();
await page.roleInput().sendKeys('Juliet');
await expectFormIsValid();
expect(await page.crossValidationErrorMessage.isPresent()).toBe(false);
});
}
await triggerRoleValidation();
await waitForAlterEgoValidation();
await expectFormIsValid();
const crossErrors = await driver.findElements(
webdriver.By.css(`${page.sectionTag} .cross-validation-error-message`),
);
expect(crossErrors.length).toBe(0);
});
}
});
@@ -1,14 +1,15 @@
import {AppPage} from './app.po';
import * as webdriver from 'selenium-webdriver';
describe('forms-overview App', () => {
let page: AppPage;
let driver: webdriver.WebDriver;
beforeEach(() => {
page = new AppPage();
beforeEach(async () => {
await driver.get('');
});
it('should display a title', async () => {
await page.navigateTo();
expect(await page.getTitleText()).toEqual('Forms Overview');
expect(await driver.findElement(webdriver.By.css('h1, h2')).getText()).toEqual(
'Forms Overview',
);
});
});
@@ -1,6 +1,6 @@
{
"tests": [
{"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadlessNoSandbox", "--no-watch"]},
{"cmd": "yarn", "args": ["e2e", "--configuration=production", "--protractor-config=e2e/protractor-bazel.conf.js", "--no-webdriver-update", "--port=0"]}
{"cmd": "yarn", "args": ["e2e", "--configuration=production"]}
]
}
@@ -1,43 +1,52 @@
import {browser, element, by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('Forms Tests', () => {
beforeEach(() => browser.get(''));
let driver: webdriver.WebDriver;
beforeEach(async () => {
await driver.get('');
});
it('should display correct title', async () => {
expect(await element.all(by.css('h1')).get(0).getText()).toEqual('Actor Form');
const h1s = await driver.findElements(webdriver.By.css('h1'));
expect(await h1s[0].getText()).toEqual('Actor Form');
});
it('should not display message before submit', async () => {
const ele = element(by.css('h2'));
expect(await ele.isDisplayed()).toBe(false);
const h2s = await driver.findElements(webdriver.By.css('h2'));
expect(h2s.length === 0 || !(await h2s[0].isDisplayed())).toBe(true);
});
it('should hide form after submit', async () => {
const ele = element.all(by.css('h1')).get(0);
const ele = (await driver.findElements(webdriver.By.css('h1')))[0];
expect(await ele.isDisplayed()).toBe(true);
const b = element.all(by.css('button[type=submit]')).get(0);
const b = (await driver.findElements(webdriver.By.css('button[type=submit]')))[0];
await b.click();
expect(await ele.isDisplayed()).toBe(false);
const h1s = await driver.findElements(webdriver.By.css('h1'));
expect(h1s.length === 0 || !(await h1s[0].isDisplayed())).toBe(true);
});
it('should display message after submit', async () => {
const b = element.all(by.css('button[type=submit]')).get(0);
const b = (await driver.findElements(webdriver.By.css('button[type=submit]')))[0];
await b.click();
expect(await element(by.css('h2')).getText()).toContain('You submitted the following');
expect(await (await driver.findElement(webdriver.By.css('h2'))).getText()).toContain(
'You submitted the following',
);
});
it('should hide form after submit', async () => {
const studioEle = element.all(by.css('input[name=studio]')).get(0);
const studioEle = (await driver.findElements(webdriver.By.css('input[name=studio]')))[0];
expect(await studioEle.isDisplayed()).toBe(true);
const submitButtonEle = element.all(by.css('button[type=submit]')).get(0);
const submitButtonEle = (await driver.findElements(webdriver.By.css('button[type=submit]')))[0];
await submitButtonEle.click();
expect(await studioEle.isDisplayed()).toBe(false);
const studioEles = await driver.findElements(webdriver.By.css('input[name=studio]'));
expect(studioEles.length === 0 || !(await studioEles[0].isDisplayed())).toBe(true);
});
it('should reflect submitted data after submit', async () => {
const studioEle = element.all(by.css('input[name=studio]')).get(0);
const studioEle = (await driver.findElements(webdriver.By.css('input[name=studio]')))[0];
const value = await studioEle.getAttribute('value');
const test = 'testing 1 2 3';
const newValue = value + test;
@@ -45,12 +54,18 @@ describe('Forms Tests', () => {
await studioEle.sendKeys(test);
expect(await studioEle.getAttribute('value')).toEqual(newValue);
const b = element.all(by.css('button[type=submit]')).get(0);
const b = (await driver.findElements(webdriver.By.css('button[type=submit]')))[0];
await b.click();
const studioTextEle = element(by.cssContainingText('div', 'Studio'));
expect(await studioTextEle.isPresent()).toBe(true, 'cannot locate "Studio" label');
const divEle = element(by.cssContainingText('div', newValue));
expect(await divEle.isPresent()).toBe(true, `cannot locate div with this text: ${newValue}`);
const divs = await driver.findElements(webdriver.By.css('div'));
let foundStudio = false;
let foundNewValue = false;
for (const d of divs) {
const text = await d.getText();
if (text.includes('Studio')) foundStudio = true;
if (text.includes(newValue)) foundNewValue = true;
}
expect(foundStudio).toBe(true, 'cannot locate "Studio" label');
expect(foundNewValue).toBe(true, `cannot locate div with this text: ${newValue}`);
});
});
@@ -1,41 +1,51 @@
import {browser, element, by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('i18n E2E Tests', () => {
beforeEach(() => browser.get(''));
let driver: webdriver.WebDriver;
beforeEach(async () => {
await driver.get('');
});
it('should display i18n translated welcome: Bonjour !', async () => {
expect(await element(by.css('h1')).getText()).toEqual('Bonjour i18n !');
expect(await (await driver.findElement(webdriver.By.css('h1'))).getText()).toEqual(
'Bonjour i18n !',
);
});
it('should display the node texts without elements', async () => {
expect(await element(by.css('app-root')).getText()).toContain(`Je n'affiche aucun élément`);
expect(await (await driver.findElement(webdriver.By.css('app-root'))).getText()).toContain(
`Je n'affiche aucun élément`,
);
});
it('should display the translated title attribute', async () => {
const title = await element(by.css('img')).getAttribute('title');
const title = await (await driver.findElement(webdriver.By.css('img'))).getAttribute('title');
expect(title).toBe(`Logo d'Angular`);
});
it('should display the ICU plural expression', async () => {
expect(await element.all(by.css('span')).get(0).getText()).toBe(`Mis à jour à l'instant`);
const spans = await driver.findElements(webdriver.By.css('span'));
expect(await spans[0].getText()).toBe(`Mis à jour à l'instant`);
});
it('should display the ICU select expression', async () => {
const selectIcuExp = element.all(by.css('span')).get(1);
expect(await selectIcuExp.getText()).toBe(`L'auteur est une femme`);
await element.all(by.css('button')).get(2).click();
expect(await selectIcuExp.getText()).toBe(`L'auteur est un homme`);
const spans = await driver.findElements(webdriver.By.css('span'));
const buttons = await driver.findElements(webdriver.By.css('button'));
expect(await spans[1].getText()).toBe(`L'auteur est une femme`);
await buttons[2].click();
expect(await spans[1].getText()).toBe(`L'auteur est un homme`);
});
it('should display the nested expression', async () => {
const nestedExp = element.all(by.css('span')).get(2);
const incBtn = element.all(by.css('button')).get(0);
expect(await nestedExp.getText()).toBe(`Mis à jour: à l'instant`);
await incBtn.click();
expect(await nestedExp.getText()).toBe(`Mis à jour: il y a une minute`);
await incBtn.click();
await incBtn.click();
await element.all(by.css('button')).get(4).click();
expect(await nestedExp.getText()).toBe(`Mis à jour: il y a 3 minutes par autre`);
const spans = await driver.findElements(webdriver.By.css('span'));
const buttons = await driver.findElements(webdriver.By.css('button'));
expect(await spans[2].getText()).toBe(`Mis à jour: à l'instant`);
await buttons[0].click();
expect(await spans[2].getText()).toBe(`Mis à jour: il y a une minute`);
await buttons[0].click();
await buttons[0].click();
await buttons[4].click();
expect(await spans[2].getText()).toBe(`Mis à jour: il y a 3 minutes par autre`);
});
});
@@ -1,17 +1,10 @@
{
"projectType": "i18n",
"overrideBoilerplate": [
"angular.json"
],
"overrideBoilerplate": ["angular.json"],
"tests": [
{
"cmd": "yarn",
"args": [
"e2e",
"--protractor-config=e2e/protractor-bazel.conf.js",
"--no-webdriver-update",
"--port=0"
]
"args": ["e2e"]
}
]
}
+1 -6
View File
@@ -2,12 +2,7 @@
import '@angular/common/locales/global/fr';
// #enddocregion global-locale
import {provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [
provideProtractorTestingSupport(), // essential for e2e testing
],
});
bootstrapApplication(AppComponent);
@@ -1,52 +1,73 @@
import {browser, element, by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('Reactive forms', () => {
const nameEditor = element(by.css('app-name-editor'));
const profileEditor = element(by.css('app-profile-editor'));
const nameEditorButton = element(by.cssContainingText('app-root > nav > button', 'Name Editor'));
const profileEditorButton = element(
by.cssContainingText('app-root > nav > button', 'Profile Editor'),
);
let driver: webdriver.WebDriver;
beforeAll(() => browser.get(''));
const getNameEditor = () => driver.findElement(webdriver.By.css('app-name-editor'));
const getProfileEditor = () => driver.findElement(webdriver.By.css('app-profile-editor'));
const findNavButton = async (text: string) => {
const buttons = await driver.findElements(webdriver.By.css('app-root > nav > button'));
for (const b of buttons) {
if ((await b.getText()).includes(text)) {
return b;
}
}
throw new Error(`Nav button "${text}" not found`);
};
beforeAll(async () => {
await driver.get('');
});
describe('Name Editor', () => {
const nameInput = nameEditor.element(by.css('input'));
const updateButton = nameEditor.element(by.buttonText('Update Name'));
const nameText = 'John Smith';
beforeAll(async () => {
await nameEditorButton.click();
await (await findNavButton('Name Editor')).click();
});
beforeEach(async () => {
const nameInput = await (await getNameEditor()).findElement(webdriver.By.css('input'));
await nameInput.clear();
});
it('should update the name value when the name control is updated', async () => {
const nameInput = await (await getNameEditor()).findElement(webdriver.By.css('input'));
await nameInput.sendKeys(nameText);
const value = await nameInput.getAttribute('value');
expect(value).toBe(nameText);
});
it('should update the name control when the Update Name button is clicked', async () => {
const nameInput = await (await getNameEditor()).findElement(webdriver.By.css('input'));
const updateButton = await (
await getNameEditor()
).findElement(webdriver.By.xpath('.//button[normalize-space()="Update Name"]'));
await nameInput.sendKeys(nameText);
const value1 = await nameInput.getAttribute('value');
expect(value1).toBe(nameText);
await updateButton.click();
const value2 = await nameInput.getAttribute('value');
expect(value2).toBe('Nancy');
});
it('should update the displayed control value when the name control updated', async () => {
const nameInput = await (await getNameEditor()).findElement(webdriver.By.css('input'));
await nameInput.sendKeys(nameText);
const valueElement = nameEditor.element(by.cssContainingText('p', 'Value:'));
const nameValueElement = await valueElement.getText();
const paragraphs = await (await getNameEditor()).findElements(webdriver.By.css('p'));
let valueElement: webdriver.WebElement | null = null;
for (const p of paragraphs) {
if ((await p.getText()).includes('Value:')) {
valueElement = p;
break;
}
}
const nameValueElement = await valueElement!.getText();
const nameValue = nameValueElement.toString().replace('Value: ', '');
expect(nameValue).toBe(nameText);
@@ -54,10 +75,6 @@ describe('Reactive forms', () => {
});
describe('Profile Editor', () => {
const firstNameInput = getInput('firstName');
const streetInput = getInput('street');
const addAliasButton = element(by.buttonText('+ Add another alias'));
const updateButton = profileEditor.element(by.buttonText('Update Profile'));
const profile: Record<string, string | number> = {
firstName: 'John',
lastName: 'Smith',
@@ -68,26 +85,33 @@ describe('Reactive forms', () => {
};
beforeAll(async () => {
await profileEditorButton.click();
await (await findNavButton('Profile Editor')).click();
});
beforeEach(async () => {
await browser.get('');
await profileEditorButton.click();
await driver.get('');
await (await findNavButton('Profile Editor')).click();
});
it('should be invalid by default', async () => {
expect(await profileEditor.getText()).toContain('Form Status: INVALID');
expect(await (await getProfileEditor()).getText()).toContain('Form Status: INVALID');
});
it('should be valid if the First Name is filled in', async () => {
const firstNameInput = await getInput('firstName');
await firstNameInput.clear();
await firstNameInput.sendKeys('John Smith');
expect(await profileEditor.getText()).toContain('Form Status: VALID');
expect(await (await getProfileEditor()).getText()).toContain('Form Status: VALID');
});
it('should update the name when the button is clicked', async () => {
const firstNameInput = await getInput('firstName');
const streetInput = await getInput('street');
const updateButton = await (
await getProfileEditor()
).findElement(webdriver.By.xpath('.//button[normalize-space()="Update Profile"]'));
await firstNameInput.clear();
await streetInput.clear();
await firstNameInput.sendKeys('John');
@@ -107,23 +131,42 @@ describe('Reactive forms', () => {
});
it('should add an alias field when the Add Alias button is clicked', async () => {
const addAliasButton = await driver.findElement(
webdriver.By.xpath('.//button[normalize-space()="+ Add another alias"]'),
);
await addAliasButton.click();
const aliasInputs = profileEditor.all(by.cssContainingText('label', 'Alias'));
const labels = await (await getProfileEditor()).findElements(webdriver.By.css('label'));
const aliasLabels: webdriver.WebElement[] = [];
for (const l of labels) {
if ((await l.getText()).includes('Alias')) {
aliasLabels.push(l);
}
}
expect(await aliasInputs.count()).toBe(2);
expect(aliasLabels.length).toBe(2);
});
it('should update the displayed form value when form inputs are updated', async () => {
const aliasText = 'Johnny';
await Promise.all(
Object.keys(profile).map((key) => getInput(key).sendKeys(`${profile[key]}`)),
);
for (const key of Object.keys(profile)) {
await (await getInput(key)).sendKeys(`${profile[key]}`);
}
const aliasInput = profileEditor.all(by.css('#alias-0'));
const aliasInput = (
await (await getProfileEditor()).findElements(webdriver.By.css('#alias-0'))
)[0];
await aliasInput.sendKeys(aliasText);
const formValueElement = profileEditor.all(by.cssContainingText('p', 'Form Value:'));
const formValue = await formValueElement.getText();
const paragraphs = await (await getProfileEditor()).findElements(webdriver.By.css('p'));
let formValueElement: webdriver.WebElement | null = null;
for (const p of paragraphs) {
if ((await p.getText()).includes('Form Value:')) {
formValueElement = p;
break;
}
}
const formValue = await formValueElement!.getText();
const formJson = JSON.parse(formValue.toString().replace('Form Value:', ''));
expect(profile['firstName']).toBe(formJson.firstName);
@@ -133,6 +176,6 @@ describe('Reactive forms', () => {
});
function getInput(key: string) {
return element(by.css(`input[formcontrolname=${key}`));
return driver.findElement(webdriver.By.css(`input[formcontrolname=${key}]`));
}
});
@@ -1,9 +1,15 @@
import {browser, element, by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('Routing with Custom Matching', () => {
beforeAll(() => browser.get(''));
let driver: webdriver.WebDriver;
it('should display Routing with Custom Matching ', async () => {
expect(await element(by.css('h2')).getText()).toEqual('Routing with Custom Matching');
beforeAll(async () => {
await driver.get('');
});
it('should display Routing with Custom Matching', async () => {
expect(await (await driver.findElement(webdriver.By.css('h2'))).getText()).toEqual(
'Routing with Custom Matching',
);
});
});
@@ -1,12 +1,8 @@
import {ApplicationConfig} from '@angular/core';
import {provideProtractorTestingSupport} from '@angular/platform-browser';
import {provideRouter, withComponentInputBinding} from '@angular/router';
import {routes} from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes, withComponentInputBinding()),
provideProtractorTestingSupport(),
],
providers: [provideRouter(routes, withComponentInputBinding())],
};
@@ -1,36 +1,42 @@
import {browser, element, By} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('Security E2E Tests', () => {
beforeAll(() => browser.get(''));
let driver: webdriver.WebDriver;
beforeAll(async () => {
await driver.get('');
});
it('sanitizes innerHTML', async () => {
const interpolated = element(By.className('e2e-inner-html-interpolated'));
const interpolated = await driver.findElement(
webdriver.By.className('e2e-inner-html-interpolated'),
);
expect(await interpolated.getText()).toContain(
'Template <script>alert("0wned")</script> <b>Syntax</b>',
);
const bound = element(By.className('e2e-inner-html-bound'));
const bound = await driver.findElement(webdriver.By.className('e2e-inner-html-bound'));
expect(await bound.getText()).toContain('Template Syntax');
const bold = element(By.css('.e2e-inner-html-bound b'));
const bold = await driver.findElement(webdriver.By.css('.e2e-inner-html-bound b'));
expect(await bold.getText()).toContain('Syntax');
});
it('escapes untrusted URLs', async () => {
const untrustedUrl = element(By.className('e2e-dangerous-url'));
const untrustedUrl = await driver.findElement(webdriver.By.className('e2e-dangerous-url'));
expect(await untrustedUrl.getAttribute('href')).toMatch(/^unsafe:javascript/);
});
it('binds trusted URLs', async () => {
const trustedUrl = element(By.className('e2e-trusted-url'));
const trustedUrl = await driver.findElement(webdriver.By.className('e2e-trusted-url'));
expect(await trustedUrl.getAttribute('href')).toMatch(/^javascript:alert/);
});
it('escapes untrusted resource URLs', async () => {
const iframe = element(By.className('e2e-iframe-untrusted-src'));
const iframe = await driver.findElement(webdriver.By.className('e2e-iframe-untrusted-src'));
expect(await iframe.getAttribute('src')).toBe('');
});
it('binds trusted resource URLs', async () => {
const iframe = element(By.className('e2e-iframe-trusted-src'));
const iframe = await driver.findElement(webdriver.By.className('e2e-iframe-trusted-src'));
expect(await iframe.getAttribute('src')).toMatch(/^https:\/\/www\.youtube\.com\//);
});
});
@@ -1,7 +1,5 @@
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [provideProtractorTestingSupport()],
}).catch((err) => console.error(err));
bootstrapApplication(AppComponent).catch((err) => console.error(err));
@@ -1,30 +1,30 @@
import {AppPage} from './app.po';
import {element, by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('sw-example App', () => {
let page: AppPage;
let driver: webdriver.WebDriver;
beforeEach(async () => {
page = new AppPage();
await page.navigateTo();
await driver.get('');
});
it('should display welcome message', async () => {
expect(await page.getTitleText()).toEqual('Welcome to Service Workers!');
expect(await (await driver.findElement(webdriver.By.css('h1, app-root h1'))).getText()).toEqual(
'Welcome to Service Workers!',
);
});
it('should display the Angular logo', async () => {
const logo = element(by.css('img'));
expect(await logo.isPresent()).toBe(true);
const imgs = await driver.findElements(webdriver.By.css('img'));
expect(imgs.length).toBeGreaterThan(0);
});
it('should show a header for the list of links', async () => {
const listHeader = element(by.css('app-root > h2'));
const listHeader = await driver.findElement(webdriver.By.css('app-root > h2'));
expect(await listHeader.getText()).toEqual('Here are some links to help you start:');
});
it('should show a list of links', async () => {
const items = await element.all(by.css('ul > li > h2 > a'));
const items = await driver.findElements(webdriver.By.css('ul > li > h2 > a'));
expect(items.length).toBe(4);
expect(await items[0].getText()).toBe('Angular Service Worker Intro');
@@ -35,8 +35,8 @@ describe('sw-example App', () => {
// Check for a rejected promise as the service worker is not enabled
it('SwUpdate.checkForUpdate() should return a rejected promise', async () => {
const button = element(by.css('button'));
const rejectMessage = element(by.css('p'));
const button = await driver.findElement(webdriver.By.css('button'));
const rejectMessage = await driver.findElement(webdriver.By.css('p'));
await button.click();
expect(await rejectMessage.getText()).toContain('rejected: ');
});
@@ -1,10 +1,25 @@
{
"projectType": "service-worker",
"tests": [
{"cmd": "yarn", "args": ["e2e", "--protractor-config=e2e/protractor-bazel.conf.js", "--no-webdriver-update", "--port=0"]},
{"cmd": "yarn", "args": ["e2e"]},
{"cmd": "yarn", "args": ["build"]},
{"cmd": "node", "args": ["--eval", "assert(fs.existsSync('./dist/ngsw.json'), 'ngsw.json is missing')"]},
{"cmd": "node", "args": ["--eval", "assert(fs.existsSync('./dist/ngsw-worker.js'), 'ngsw-worker.js is missing')"]},
{"cmd": "node", "args": ["--eval", "assert(require('./package.json').dependencies['@angular/service-worker'], '@angular/service-worker is missing')"]}
{
"cmd": "node",
"args": ["--eval", "assert(fs.existsSync('./dist/ngsw.json'), 'ngsw.json is missing')"]
},
{
"cmd": "node",
"args": [
"--eval",
"assert(fs.existsSync('./dist/ngsw-worker.js'), 'ngsw-worker.js is missing')"
]
},
{
"cmd": "node",
"args": [
"--eval",
"assert(require('./package.json').dependencies['@angular/service-worker'], '@angular/service-worker is missing')"
]
}
]
}
@@ -1,9 +1,5 @@
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [
provideProtractorTestingSupport(), // essential for e2e testing
],
});
bootstrapApplication(AppComponent);
@@ -1,48 +1,73 @@
import {browser, element, by} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('Structural Directives', () => {
beforeAll(() => browser.get(''));
let driver: webdriver.WebDriver;
beforeAll(async () => {
await driver.get('');
});
it('first div should show hero name with *ngIf', async () => {
const allDivs = element.all(by.tagName('div'));
expect(await allDivs.get(0).getText()).toEqual('Dr. Nice');
const allDivs = await driver.findElements(webdriver.By.css('div'));
expect(await allDivs[0].getText()).toEqual('Dr. Nice');
});
it('first li should show hero name with *ngFor', async () => {
const allLis = element.all(by.tagName('li'));
expect(await allLis.get(0).getText()).toEqual('Dr. Nice');
const allLis = await driver.findElements(webdriver.By.css('li'));
expect(await allLis[0].getText()).toEqual('Dr. Nice');
});
it('ngSwitch have two <happy-hero> instances', async () => {
const happyHeroEls = element.all(by.tagName('app-happy-hero'));
expect(await happyHeroEls.count()).toEqual(2);
const happyHeroEls = await driver.findElements(webdriver.By.css('app-happy-hero'));
expect(happyHeroEls.length).toEqual(2);
});
it('should toggle *ngIf="hero" with a button', async () => {
const toggleHeroButton = element.all(by.cssContainingText('button', 'Toggle hero')).get(0);
const paragraph = element.all(by.cssContainingText('p', 'I turned the corner'));
expect(await paragraph.get(0).getText()).toContain('I waved');
await toggleHeroButton.click();
expect(await paragraph.get(0).getText()).not.toContain('I waved');
const buttons = await driver.findElements(webdriver.By.css('button'));
let toggleHeroButton: webdriver.WebElement | null = null;
for (const b of buttons) {
if ((await b.getText()).includes('Toggle hero')) {
toggleHeroButton = b;
break;
}
}
const paragraphs = await driver.findElements(webdriver.By.css('p'));
let paragraph: webdriver.WebElement | null = null;
for (const p of paragraphs) {
if ((await p.getText()).includes('I turned the corner')) {
paragraph = p;
break;
}
}
expect(await paragraph!.getText()).toContain('I waved');
await toggleHeroButton!.click();
expect(await paragraph!.getText()).not.toContain('I waved');
});
it('appUnless should show 3 paragraph (A)s and (B)s at the start', async () => {
const paragraph = element.all(by.css('p.unless'));
expect(await paragraph.count()).toEqual(3);
const paragraph = await driver.findElements(webdriver.By.css('p.unless'));
expect(paragraph.length).toEqual(3);
for (let i = 0; i < 3; i++) {
expect(await paragraph.get(i).getText()).toContain('(A)');
expect(await paragraph[i].getText()).toContain('(A)');
}
});
it('appUnless should show 1 paragraph (B) after toggling condition', async () => {
const toggleConditionButton = element
.all(by.cssContainingText('button', 'Toggle condition'))
.get(0);
const paragraph = element.all(by.css('p.unless'));
const buttons = await driver.findElements(webdriver.By.css('button'));
let toggleConditionButton: webdriver.WebElement | null = null;
for (const b of buttons) {
if ((await b.getText()).includes('Toggle condition')) {
toggleConditionButton = b;
break;
}
}
await toggleConditionButton.click();
await toggleConditionButton!.click();
expect(await paragraph.count()).toEqual(1);
expect(await paragraph.get(0).getText()).toContain('(B)');
const paragraph = await driver.findElements(webdriver.By.css('p.unless'));
expect(paragraph.length).toEqual(1);
expect(await paragraph[0].getText()).toContain('(B)');
});
});
@@ -1,7 +1,5 @@
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [provideProtractorTestingSupport()],
}).catch((err) => console.error(err));
bootstrapApplication(AppComponent).catch((err) => console.error(err));
@@ -1,10 +1,21 @@
import {browser, element, by, Key, ExpectedConditions} from 'protractor';
import * as webdriver from 'selenium-webdriver';
describe('Angular v21 World', () => {
beforeEach(() => browser.get(''));
let driver: webdriver.WebDriver;
const isPresent = async (locator: webdriver.Locator) => {
const els = await driver.findElements(locator);
return els.length > 0;
};
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
beforeEach(async () => {
await driver.get('');
});
async function getCharacterPosition(): Promise<{x: string; y: string}> {
const character = element(by.css('.character'));
const character = await driver.findElement(webdriver.By.css('.character'));
const left = await character.getCssValue('left');
const top = await character.getCssValue('top');
return {x: left, y: top};
@@ -12,31 +23,33 @@ describe('Angular v21 World', () => {
it('should display the initial game state correctly', async () => {
// Character is visible
expect(await element(by.css('.character')).isDisplayed()).toBe(true);
expect(await (await driver.findElement(webdriver.By.css('.character'))).isDisplayed()).toBe(
true,
);
// Info sign is shown with welcome message
const infoSign = element(by.css('.info-sign'));
const infoSign = await driver.findElement(webdriver.By.css('.info-sign'));
expect(await infoSign.isDisplayed()).toBe(true);
expect(await infoSign.getAttribute('src')).toContain('welcome-sign.png');
// D-pad is visible
expect(await element(by.css('.d-pad')).isDisplayed()).toBe(true);
expect(await (await driver.findElement(webdriver.By.css('.d-pad'))).isDisplayed()).toBe(true);
// Explore button is not visible
expect(await element(by.css('.explore-button')).isPresent()).toBe(false);
expect(await isPresent(webdriver.By.css('.explore-button'))).toBe(false);
// No keys are present
expect(await element.all(by.css('.key-icon')).count()).toBe(0);
expect((await driver.findElements(webdriver.By.css('.key-icon'))).length).toBe(0);
});
it('should move the character with the D-pad buttons', async () => {
const initialPosition = await getCharacterPosition();
const leftButton = element(by.css('.d-pad-button.left'));
const leftButton = await driver.findElement(webdriver.By.css('.d-pad-button.left'));
// Hold the button down for a short period to simulate walking
await browser.actions().mouseDown(leftButton).perform();
await browser.sleep(200);
await browser.actions().mouseUp(leftButton).perform();
await driver.actions().move({origin: leftButton}).press().perform();
await sleep(200);
await driver.actions().release().perform();
const newPosition = await getCharacterPosition();
expect(newPosition.x).not.toEqual(initialPosition.x);
@@ -46,127 +59,146 @@ describe('Angular v21 World', () => {
const initialPosition = await getCharacterPosition();
// Send arrow key press
await browser.actions().sendKeys(Key.ARROW_RIGHT).perform();
await browser.sleep(200); // Allow time for movement
await browser.actions().sendKeys(Key.NULL).perform(); // Release key
const body = await driver.findElement(webdriver.By.css('body'));
await body.sendKeys(webdriver.Key.ARROW_RIGHT);
await sleep(200);
const newPosition = await getCharacterPosition();
expect(newPosition.x).not.toEqual(initialPosition.x);
});
it('should show explore button, open dialog, and collect a key when a destination is reached', async () => {
const body = element(by.css('body'));
const exploreButton = element(by.css('.explore-button'));
const dialog = element(by.css('.dialog-overlay'));
const body = await driver.findElement(webdriver.By.css('body'));
// Move left until we reach the Palm Tree destination
for (let i = 0; i < 20; i++) {
await body.sendKeys(Key.ARROW_LEFT);
await browser.sleep(100);
await body.sendKeys(webdriver.Key.ARROW_LEFT);
await sleep(100);
}
// Wait for the explore button to appear and check info sign
await browser.wait(ExpectedConditions.visibilityOf(exploreButton), 5000);
const exploreButtonLocator = webdriver.By.css('.explore-button');
await driver.wait(webdriver.until.elementLocated(exploreButtonLocator), 5000);
const exploreButton = await driver.findElement(exploreButtonLocator);
expect(await exploreButton.isDisplayed()).toBe(true);
expect(await element(by.css('.info-sign')).getAttribute('src')).toContain('enter-sign.png');
expect(
await (await driver.findElement(webdriver.By.css('.info-sign'))).getAttribute('src'),
).toContain('enter-sign.png');
// Click explore button to open dialog
await exploreButton.click();
await browser.wait(ExpectedConditions.visibilityOf(dialog), 1000);
const dialogLocator = webdriver.By.css('.dialog-overlay');
await driver.wait(webdriver.until.elementLocated(dialogLocator), 1000);
const dialog = await driver.findElement(dialogLocator);
expect(await dialog.isDisplayed()).toBe(true);
expect(await dialog.element(by.css('h2')).getText()).toEqual("What's new in Angular AI");
expect(await (await dialog.findElement(webdriver.By.css('h2'))).getText()).toEqual(
"What's new in Angular AI",
);
// Close the dialog
await dialog.element(by.css('.close-button')).click();
await browser.wait(ExpectedConditions.invisibilityOf(dialog), 1000);
expect(await dialog.isPresent()).toBe(false);
await (await dialog.findElement(webdriver.By.css('.close-button'))).click();
await driver.wait(async () => !(await isPresent(dialogLocator)), 1000);
expect(await isPresent(dialogLocator)).toBe(false);
// Check that one key has been collected
expect(await element.all(by.css('.key-icon')).count()).toBe(1);
expect((await driver.findElements(webdriver.By.css('.key-icon'))).length).toBe(1);
});
it('should show entry denied at castle without all keys', async () => {
const body = element(by.css('body'));
const exploreButton = element(by.css('.explore-button'));
const body = await driver.findElement(webdriver.By.css('body'));
// Move to a position near the castle without collecting keys
for (let i = 0; i < 20; i++) (await body.sendKeys(Key.ARROW_RIGHT), await browser.sleep(100));
for (let i = 0; i < 20; i++) (await body.sendKeys(Key.ARROW_DOWN), await browser.sleep(100));
for (let i = 0; i < 20; i++) {
await body.sendKeys(webdriver.Key.ARROW_RIGHT);
await sleep(100);
}
for (let i = 0; i < 20; i++) {
await body.sendKeys(webdriver.Key.ARROW_DOWN);
await sleep(100);
}
await browser.sleep(1000); // Settle
await sleep(1000); // Settle
// Check that the entry denied sign is shown and the button is not present
expect(await element(by.css('.info-sign')).getAttribute('src')).toContain(
'entry-denied-sign.png',
);
expect(await exploreButton.isPresent()).toBe(false);
expect(
await (await driver.findElement(webdriver.By.css('.info-sign'))).getAttribute('src'),
).toContain('entry-denied-sign.png');
expect(await isPresent(webdriver.By.css('.explore-button'))).toBe(false);
});
it('should handle the full game flow and show congrats state', async () => {
const body = element(by.css('body'));
const exploreButton = element(by.css('.explore-button'));
const dialog = element(by.css('.dialog-overlay'));
const keys = element.all(by.css('.key-icon'));
const mascot = element(by.css('.mascot-icon'));
const body = await driver.findElement(webdriver.By.css('body'));
const exploreButtonLocator = webdriver.By.css('.explore-button');
const dialogLocator = webdriver.By.css('.dialog-overlay');
const mascotLocator = webdriver.By.css('.mascot-icon');
// **Navigate to Palm Tree (d1) and collect the first key**
for (let i = 0; i < 20; i++) {
await body.sendKeys(Key.ARROW_LEFT);
await browser.sleep(100);
await body.sendKeys(webdriver.Key.ARROW_LEFT);
await sleep(100);
}
await browser.wait(ExpectedConditions.visibilityOf(exploreButton), 5000);
await exploreButton.click();
await browser.wait(ExpectedConditions.visibilityOf(dialog), 1000);
await dialog.element(by.css('.close-button')).click();
await browser.wait(ExpectedConditions.invisibilityOf(dialog), 1000);
expect(await keys.count()).toBe(1);
await driver.wait(webdriver.until.elementLocated(exploreButtonLocator), 5000);
await (await driver.findElement(exploreButtonLocator)).click();
await driver.wait(webdriver.until.elementLocated(dialogLocator), 1000);
let dialog = await driver.findElement(dialogLocator);
await (await dialog.findElement(webdriver.By.css('.close-button'))).click();
await driver.wait(async () => !(await isPresent(dialogLocator)), 1000);
expect((await driver.findElements(webdriver.By.css('.key-icon'))).length).toBe(1);
// **Navigate to Red Door (d2) and collect the second key**
for (let i = 0; i < 15; i++) {
await body.sendKeys(Key.ARROW_UP);
await browser.sleep(100);
await body.sendKeys(webdriver.Key.ARROW_UP);
await sleep(100);
}
await browser.wait(ExpectedConditions.visibilityOf(exploreButton), 5000);
await exploreButton.click();
await browser.wait(ExpectedConditions.visibilityOf(dialog), 1000);
await dialog.element(by.css('.close-button')).click();
await browser.wait(ExpectedConditions.invisibilityOf(dialog), 1000);
expect(await keys.count()).toBe(2);
await driver.wait(webdriver.until.elementLocated(exploreButtonLocator), 5000);
await (await driver.findElement(exploreButtonLocator)).click();
await driver.wait(webdriver.until.elementLocated(dialogLocator), 1000);
dialog = await driver.findElement(dialogLocator);
await (await dialog.findElement(webdriver.By.css('.close-button'))).click();
await driver.wait(async () => !(await isPresent(dialogLocator)), 1000);
expect((await driver.findElements(webdriver.By.css('.key-icon'))).length).toBe(2);
// **Navigate to Volcano (d3) and collect the third key**
for (let i = 0; i < 25; i++) {
await body.sendKeys(Key.ARROW_RIGHT);
await browser.sleep(100);
await body.sendKeys(webdriver.Key.ARROW_RIGHT);
await sleep(100);
}
await browser.wait(ExpectedConditions.visibilityOf(exploreButton), 5000);
await exploreButton.click();
await browser.wait(ExpectedConditions.visibilityOf(dialog), 1000);
await dialog.element(by.css('.close-button')).click();
await browser.wait(ExpectedConditions.invisibilityOf(dialog), 1000);
expect(await keys.count()).toBe(3);
await driver.wait(webdriver.until.elementLocated(exploreButtonLocator), 5000);
await (await driver.findElement(exploreButtonLocator)).click();
await driver.wait(webdriver.until.elementLocated(dialogLocator), 1000);
dialog = await driver.findElement(dialogLocator);
await (await dialog.findElement(webdriver.By.css('.close-button'))).click();
await driver.wait(async () => !(await isPresent(dialogLocator)), 1000);
expect((await driver.findElements(webdriver.By.css('.key-icon'))).length).toBe(3);
// **Navigate to Castle (d4) with all keys**
for (let i = 0; i < 15; i++) {
await body.sendKeys(Key.ARROW_DOWN);
await browser.sleep(100);
await body.sendKeys(webdriver.Key.ARROW_DOWN);
await sleep(100);
}
await browser.sleep(1000); // Wait for character to settle
await sleep(1000); // Wait for character to settle
// Check for correct sign and button visibility
expect(await element(by.css('.info-sign')).getAttribute('src')).toContain('castle-sign.png');
await browser.wait(ExpectedConditions.visibilityOf(exploreButton), 5000);
expect(
await (await driver.findElement(webdriver.By.css('.info-sign'))).getAttribute('src'),
).toContain('castle-sign.png');
await driver.wait(webdriver.until.elementLocated(exploreButtonLocator), 5000);
// **Open Castle dialog, close it, and see mascot and final sign**
await exploreButton.click();
await browser.wait(ExpectedConditions.visibilityOf(dialog), 1000);
await dialog.element(by.css('.close-button')).click();
await browser.wait(ExpectedConditions.invisibilityOf(dialog), 1000);
await (await driver.findElement(exploreButtonLocator)).click();
await driver.wait(webdriver.until.elementLocated(dialogLocator), 1000);
dialog = await driver.findElement(dialogLocator);
await (await dialog.findElement(webdriver.By.css('.close-button'))).click();
await driver.wait(async () => !(await isPresent(dialogLocator)), 1000);
// Mascot appears
await browser.wait(ExpectedConditions.visibilityOf(mascot), 1000);
await driver.wait(webdriver.until.elementLocated(mascotLocator), 1000);
const mascot = await driver.findElement(mascotLocator);
expect(await mascot.isDisplayed()).toBe(true);
// Congrats sign appears
expect(await element(by.css('.info-sign')).getAttribute('src')).toContain('congrats-sign.png');
expect(
await (await driver.findElement(webdriver.By.css('.info-sign'))).getAttribute('src'),
).toContain('congrats-sign.png');
});
});
@@ -1,6 +1,6 @@
{
"tests": [
{"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadlessNoSandbox", "--no-watch"]},
{"cmd": "yarn", "args": ["e2e", "--configuration=production", "--protractor-config=e2e/protractor-bazel.conf.js", "--no-webdriver-update", "--port=0"]}
{"cmd": "yarn", "args": ["e2e", "--configuration=production"]}
]
}
@@ -1,9 +1,5 @@
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {
providers: [
provideProtractorTestingSupport(), // essential for e2e testing
],
});
bootstrapApplication(App);
@@ -1,10 +1,4 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {providers: [provideProtractorTestingSupport()]}).catch((err) =>
console.error(err),
);
bootstrapApplication(App).catch((err) => console.error(err));
@@ -1,10 +1,4 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {providers: [provideProtractorTestingSupport()]}).catch((err) =>
console.error(err),
);
bootstrapApplication(App).catch((err) => console.error(err));
@@ -1,10 +1,4 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {providers: [provideProtractorTestingSupport()]}).catch((err) =>
console.error(err),
);
bootstrapApplication(App).catch((err) => console.error(err));
@@ -1,10 +1,4 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {providers: [provideProtractorTestingSupport()]}).catch((err) =>
console.error(err),
);
bootstrapApplication(App).catch((err) => console.error(err));
@@ -1,10 +1,4 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {providers: [provideProtractorTestingSupport()]}).catch((err) =>
console.error(err),
);
bootstrapApplication(App).catch((err) => console.error(err));
@@ -1,10 +1,4 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {providers: [provideProtractorTestingSupport()]}).catch((err) =>
console.error(err),
);
bootstrapApplication(App).catch((err) => console.error(err));
@@ -1,10 +1,4 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {providers: [provideProtractorTestingSupport()]}).catch((err) =>
console.error(err),
);
bootstrapApplication(App).catch((err) => console.error(err));
@@ -1,10 +1,4 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {providers: [provideProtractorTestingSupport()]}).catch((err) =>
console.error(err),
);
bootstrapApplication(App).catch((err) => console.error(err));
@@ -1,10 +1,4 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {providers: [provideProtractorTestingSupport()]}).catch((err) =>
console.error(err),
);
bootstrapApplication(App).catch((err) => console.error(err));
@@ -1,10 +1,4 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
bootstrapApplication(App, {providers: [provideProtractorTestingSupport()]}).catch((err) =>
console.error(err),
);
bootstrapApplication(App).catch((err) => console.error(err));
@@ -1,12 +1,8 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
import {provideRouter} from '@angular/router';
import routeConfig from './app/routes';
bootstrapApplication(App, {
providers: [provideProtractorTestingSupport(), provideRouter(routeConfig)],
providers: [provideRouter(routeConfig)],
}).catch((err) => console.error(err));
@@ -1,12 +1,8 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
import {provideRouter} from '@angular/router';
import routeConfig from './app/routes';
bootstrapApplication(App, {
providers: [provideProtractorTestingSupport(), provideRouter(routeConfig)],
providers: [provideRouter(routeConfig)],
}).catch((err) => console.error(err));
@@ -1,12 +1,8 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
import {provideRouter} from '@angular/router';
import routeConfig from './app/routes';
bootstrapApplication(App, {
providers: [provideProtractorTestingSupport(), provideRouter(routeConfig)],
providers: [provideRouter(routeConfig)],
}).catch((err) => console.error(err));
@@ -1,12 +1,8 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
import {provideRouter} from '@angular/router';
import routeConfig from './app/routes';
bootstrapApplication(App, {
providers: [provideProtractorTestingSupport(), provideRouter(routeConfig)],
providers: [provideRouter(routeConfig)],
}).catch((err) => console.error(err));
@@ -1,12 +1,8 @@
/*
* Protractor support is deprecated in Angular.
* Protractor is used in this example for compatibility with Angular documentation tools.
*/
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
import {provideRouter} from '@angular/router';
import routeConfig from './app/routes';
bootstrapApplication(App, {
providers: [provideProtractorTestingSupport(), provideRouter(routeConfig)],
providers: [provideRouter(routeConfig)],
}).catch((err) => console.error(err));
+1 -1
View File
@@ -4,4 +4,4 @@
"lib": ["es2015"],
"types": ["node", "jasmine", "selenium-webdriver"]
}
}
}
+1 -1
View File
@@ -14,9 +14,9 @@ load("//tools/bazel:esbuild.bzl", _esbuild = "esbuild", _esbuild_checked_in = "e
load("//tools/bazel:jasmine_test.bzl", _angular_jasmine_test = "angular_jasmine_test", _jasmine_test = "jasmine_test", _zone_compatible_jasmine_test = "zone_compatible_jasmine_test", _zoneless_jasmine_test = "zoneless_jasmine_test")
load("//tools/bazel:js_defs.bzl", _js_binary = "js_binary", _js_run_binary = "js_run_binary", _js_test = "js_test")
load("//tools/bazel:npm_packages.bzl", _ng_package = "ng_package", _npm_package = "npm_package")
load("//tools/bazel:webdriver_test.bzl", _webdriver_test = "webdriver_test")
load("//tools/bazel:tsec.bzl", _tsec_test = "tsec_test")
load("//tools/bazel:web_test.bzl", _ng_web_test_suite = "ng_web_test_suite", _web_test = "web_test", _zoneless_web_test_suite = "zoneless_web_test_suite")
load("//tools/bazel:webdriver_test.bzl", _webdriver_test = "webdriver_test")
extract_types = _extract_types
esbuild = _esbuild