Compare commits

..

21 Commits

Author SHA1 Message Date
2ab8e88924 release: cut the v10.0.8 release 2020-08-04 15:51:57 -07:00
a91dd2e42a build: cleanup .bazelrc file to no longer set unused flags (#38124)
This option is no longer needed in Bazel and will be an error in the future

PR Close #38124
2020-08-03 12:53:11 -07:00
6eca80b4aa revert: docs(core): correct SomeService to SomeComponent (#38325)
This reverts commit b4449e35bf.

The example given from the previous change was for a component selector and not a provider selector.

This change fixes it.

Fixes #38323.

PR Close #38325
2020-08-03 12:52:20 -07:00
cea46786a2 fix(compiler): update unparsable character reference entity error messages (#38319)
Within an angular template, when a character entity is unable to be parsed, previously a generic
unexpected character error was thrown.  This does not properly express the issue that was discovered
as the issue is actually caused by the discovered character making the whole of the entity unparsable.
The compiler will now instead inform via the error message what string was attempted to be parsed
and what it was attempted to be parsed as.

Example, for this template:
```
<p>
  &#x123p
</p>
```
Before this change:
`Unexpected character "p"`

After this change:
`Unable to parse entity "&#x123p" - hexadecimal character reference entities must end with ";"`

Fixes #26067

PR Close #38319
2020-07-31 15:32:54 -07:00
9c5fc1693a refactor(docs-infra): update docs examples tslint.json to match CLI and fix failures (#38143)
This commit updates the `tslint.json` configuration file, that is used
to lint the docs examples, to match the one generated for new Angular
CLI apps. There are some minimal differences (marked with `TODO`
comments) for things, such as component selector prefix, that would
require extensive and/or difficult to validate changes in guides.

This commit also includes the final adjustments to make the docs
examples code compatible with the new tslint rules. (The bulk of the
work has been done in previous commits.)

PR Close #38143
2020-07-31 11:00:08 -07:00
42f5770b7b refactor(docs-infra): fix docs examples for Angular-specific tslint rules (#38143)
This commit updates the docs examples to be compatible with the
following Angular-specific tslint rules:
- `component-selector`
- `directive-selector`
- `no-conflicting-lifecycle`
- `no-host-metadata-property`
- `no-input-rename`
- `no-output-native`
- `no-output-rename`

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:08 -07:00
01db37435f refactor(docs-infra): fix docs examples for tslint rule prefer-const (#38143)
This commit updates the docs examples to be compatible with the
`prefer-const` tslint rule.

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:08 -07:00
07a003352d refactor(docs-infra): fix docs examples for tslint rules related to underscores in variable names (#38143)
This commit updates the docs examples to be compatible with the
`variable-name` tslint rule without requiring the
`allow-leading-underscore` and `allow-trailing-underscore` options.

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:08 -07:00
ac009d293d refactor(docs-infra): fix docs examples for tslint rules related to variable names (#38143)
This commit updates the docs examples to be compatible with the
`no-shadowed-variable` and `variable-name` tslint rules.

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:08 -07:00
eb8f8c93c8 refactor(docs-infra): fix docs examples for tslint rule member-ordering (#38143)
This commit updates the docs examples to be compatible with the
`member-ordering` tslint rule.

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:08 -07:00
18a5117d1e refactor(docs-infra): fix docs examples for tslint rule no-angle-bracket-type-assertion (#38143)
This commit updates the docs examples to be compatible with the
`no-angle-bracket-type-assertion` tslint rule.

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:08 -07:00
ff72da60d3 refactor(docs-infra): fix docs examples for tslint rules related to object properties (#38143)
This commit updates the docs examples to be compatible with the
`no-string-literal`, `object-literal-key-quotes` and
`object-literal-shorthand` tslint rules.

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:08 -07:00
d4a723a464 refactor(docs-infra): fix docs examples for tslint rule only-arrow-functions (#38143)
This commit updates the docs examples to be compatible with the
`only-arrow-functions` tslint rule.

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:08 -07:00
9c2f0b8ac4 style(docs-infra): fix docs examples for tslint rule jsdoc-format (#38143)
This commit updates the docs examples to be compatible with the
`jsdoc-format` tslint rule.

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:07 -07:00
dc081fb0bf style(docs-infra): fix docs examples for tslint rule semicolon (#38143)
This commit updates the docs examples to be compatible with the
`semicolon` tslint rule.

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:07 -07:00
f882099f9d style(docs-infra): fix docs examples for tslint rules related to whitespace (#38143)
This commit updates the docs examples to be compatible with the `align`,
`space-before-function-paren` and `typedef-whitespace` tslint rules.

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:07 -07:00
24498eb416 style(docs-infra): fix docs examples for tslint rule import-spacing (#38143)
This commit updates the docs examples to be compatible with the
`import-spacing` tslint rule.

This is in preparation of updating the docs examples `tslint.json` to
match the one generated for new Angular CLI apps in a future commit.

PR Close #38143
2020-07-31 11:00:07 -07:00
4c2cdc682b refactor(docs-infra): remove unnecessary use strict from docs examples TS files (#38143)
By default, TypeScript will emit `"use strict"` directives, so it is not
necessary to include `'use strict'` in `.ts` files:
https://www.typescriptlang.org/docs/handbook/compiler-options.html#:~:text=--noImplicitUseStrict

PR Close #38143
2020-07-31 11:00:07 -07:00
1cb66bb39f refactor(docs-infra): remove unused styleguide examples (#38143)
The `03-*` code style rule have been removed from the style guide in
be0bc799f3.

This commit removes the corresponding files and related unused code from
the`styleguide` example project.

PR Close #38143
2020-07-31 11:00:07 -07:00
7ff5ef27c7 fix(language-service): [ivy] do not retrieve ts.Program at startup (#38120)
This commit removes compiler instantiation at startup.
This is because the constructor is invoked during the plugin loading phase,
in which the project has not been completely loaded.

Retrieving `ts.Program` at startup will trigger an `updateGraph` operation,
which could only be called after the Project has loaded completely.
Without this change, the Ivy LS cannot be loaded as a tsserver plugin.

Note that the whole `Compiler` class is temporary, so changes made there are
only for development. Once we have proper integration with ngtsc the
`Compiler` class would be removed.

PR Close #38120
2020-07-30 16:54:20 -07:00
03d8e317c4 fix(compiler): add PURE annotation to getInheritedFactory calls (#38291)
Currently the `getInheritedFactory` function is implemented to allow
closure to remove the call if the base factory is unused.  However, this
method does not work with terser.  By adding the PURE annotation,
terser will also be able to remove the call when unused.

PR Close #38291
2020-07-30 16:53:52 -07:00
449 changed files with 2512 additions and 2977 deletions

View File

@ -136,15 +136,6 @@ build:remote --remote_executor=remotebuildexecution.googleapis.com
# retry mechanism and we do not want to retry unnecessarily if Karma already tried multiple times.
test:saucelabs --flaky_test_attempts=1
###############################
# NodeJS rules settings
# These settings are required for rules_nodejs
###############################
# Turn on managed directories feature in Bazel
# This allows us to avoid installing a second copy of node_modules
common --experimental_allow_incremental_repository_updates
####################################################
# User bazel configuration
# NOTE: This needs to be the *last* entry in the config.

View File

@ -1,3 +1,14 @@
<a name="10.0.8"></a>
## 10.0.8 (2020-08-04)
### Bug Fixes
* **compiler:** add PURE annotation to getInheritedFactory calls ([#38291](https://github.com/angular/angular/issues/38291)) ([03d8e31](https://github.com/angular/angular/commit/03d8e31))
* **compiler:** update unparsable character reference entity error messages ([#38319](https://github.com/angular/angular/issues/38319)) ([cea4678](https://github.com/angular/angular/commit/cea4678)), closes [#26067](https://github.com/angular/angular/issues/26067)
<a name="10.0.7"></a>
## 10.0.7 (2020-07-30)

View File

@ -1,5 +1,3 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Accessibility example e2e tests', () => {
@ -8,11 +6,11 @@ describe('Accessibility example e2e tests', () => {
browser.get('');
});
it('should display Accessibility Example', function () {
it('should display Accessibility Example', () => {
expect(element(by.css('h1')).getText()).toEqual('Accessibility Example');
});
it('should take a number and change progressbar width', function () {
it('should take a number and change progressbar width', () => {
element(by.css('input')).sendKeys('16');
expect(element(by.css('input')).getAttribute('value')).toEqual('016');
expect(element(by.css('app-example-progressbar div')).getCssValue('width')).toBe('48px');

View File

@ -1,3 +1,4 @@
// tslint:disable: no-host-metadata-property
// #docregion progressbar-component
import { Component, Input } from '@angular/core';

View File

@ -1,20 +1,18 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('AngularJS to Angular Quick Reference Tests', function () {
describe('AngularJS to Angular Quick Reference Tests', () => {
beforeAll(function () {
beforeAll(() => {
browser.get('');
});
it('should display no poster images after bootstrap', function () {
it('should display no poster images after bootstrap', () => {
testImagesAreDisplayed(false);
});
it('should display proper movie data', function () {
it('should display proper movie data', () => {
// We check only a few samples
let expectedSamples: any[] = [
const expectedSamples: any[] = [
{row: 0, column: 0, element: 'img', attr: 'src', value: 'images/hero.png', contains: true},
{row: 0, column: 2, value: 'Celeritas'},
{row: 1, column: 3, matches: /Dec 1[678], 2015/}, // absorb timezone dif; we care about date format
@ -25,18 +23,17 @@ describe('AngularJS to Angular Quick Reference Tests', function () {
];
// Go through the samples
let movieRows = getMovieRows();
for (let i = 0; i < expectedSamples.length; i++) {
let sample = expectedSamples[i];
let tableCell = movieRows.get(sample.row)
const movieRows = getMovieRows();
for (const sample of expectedSamples) {
const tableCell = movieRows.get(sample.row)
.all(by.tagName('td')).get(sample.column);
// Check the cell or its nested element
let elementToCheck = sample.element
const elementToCheck = sample.element
? tableCell.element(by.tagName(sample.element))
: tableCell;
// Check element attribute or text
let valueToCheck = sample.attr
const valueToCheck = sample.attr
? elementToCheck.getAttribute(sample.attr)
: elementToCheck.getText();
@ -51,42 +48,42 @@ describe('AngularJS to Angular Quick Reference Tests', function () {
}
});
it('should display images after Show Poster', function () {
it('should display images after Show Poster', () => {
testPosterButtonClick('Show Poster', true);
});
it('should hide images after Hide Poster', function () {
it('should hide images after Hide Poster', () => {
testPosterButtonClick('Hide Poster', false);
});
it('should display no movie when no favorite hero is specified', function () {
it('should display no movie when no favorite hero is specified', () => {
testFavoriteHero(null, 'Please enter your favorite hero.');
});
it('should display no movie for Magneta', function () {
it('should display no movie for Magneta', () => {
testFavoriteHero('Magneta', 'No movie, sorry!');
});
it('should display a movie for Dr Nice', function () {
it('should display a movie for Dr Nice', () => {
testFavoriteHero('Dr Nice', 'Excellent choice!');
});
function testImagesAreDisplayed(isDisplayed: boolean) {
let expectedMovieCount = 3;
const expectedMovieCount = 3;
let movieRows = getMovieRows();
const movieRows = getMovieRows();
expect(movieRows.count()).toBe(expectedMovieCount);
for (let i = 0; i < expectedMovieCount; i++) {
let movieImage = movieRows.get(i).element(by.css('td > img'));
const movieImage = movieRows.get(i).element(by.css('td > img'));
expect(movieImage.isDisplayed()).toBe(isDisplayed);
}
}
function testPosterButtonClick(expectedButtonText: string, isDisplayed: boolean) {
let posterButton = element(by.css('app-movie-list tr > th > button'));
const posterButton = element(by.css('app-movie-list tr > th > button'));
expect(posterButton.getText()).toBe(expectedButtonText);
posterButton.click().then(function () {
posterButton.click().then(() => {
testImagesAreDisplayed(isDisplayed);
});
}
@ -96,12 +93,12 @@ describe('AngularJS to Angular Quick Reference Tests', function () {
}
function testFavoriteHero(heroName: string, expectedLabel: string) {
let movieListComp = element(by.tagName('app-movie-list'));
let heroInput = movieListComp.element(by.tagName('input'));
let favoriteHeroLabel = movieListComp.element(by.tagName('h3'));
let resultLabel = movieListComp.element(by.css('span > p'));
const movieListComp = element(by.tagName('app-movie-list'));
const heroInput = movieListComp.element(by.tagName('input'));
const favoriteHeroLabel = movieListComp.element(by.tagName('h3'));
const resultLabel = movieListComp.element(by.css('span > p'));
heroInput.clear().then(function () {
heroInput.clear().then(() => {
heroInput.sendKeys(heroName || '');
expect(resultLabel.getText()).toBe(expectedLabel);
if (heroName) {

View File

@ -1,6 +1,6 @@
// #docregion
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { Routes, RouterModule } from '@angular/router';
import { MovieListComponent } from './movie-list.component';

View File

@ -1,8 +1,8 @@
// #docregion
import { NgModule } from '@angular/core';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { AppComponent } from './app.component';
@NgModule({
imports: [ BrowserModule ],

View File

@ -1,9 +1,9 @@
// #docregion
import { NgModule } from '@angular/core';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { AppComponent } from './app.component';
import { MovieListComponent } from './movie-list.component';
import { AppRoutingModule } from './app-routing.module';

View File

@ -1,5 +1,3 @@
'use strict'; // necessary for es6 output in node
import { browser, ExpectedConditions as EC } from 'protractor';
import { logging } from 'selenium-webdriver';
import * as openClose from './open-close.po';

View File

@ -34,7 +34,7 @@ export class AppComponent {
// #docregion prepare-router-outlet
prepareRoute(outlet: RouterOutlet) {
return outlet && outlet.activatedRouteData && outlet.activatedRouteData['animation'];
return outlet && outlet.activatedRouteData && outlet.activatedRouteData.animation;
}
// #enddocregion prepare-router-outlet

View File

@ -1,4 +1,6 @@
// tslint:disable: variable-name
// #docplaster
// #docregion
import { Component, HostBinding, OnInit } from '@angular/core';
import { trigger, transition, animate, style, query, stagger } from '@angular/animations';
import { HEROES } from './mock-heroes';
@ -52,13 +54,11 @@ export class HeroListPageComponent implements OnInit {
@HostBinding('@pageAnimations')
public animatePage = true;
_heroes = [];
// #docregion filter-animations
heroTotal = -1;
// #enddocregion filter-animations
get heroes() {
return this._heroes;
}
get heroes() { return this._heroes; }
private _heroes = [];
ngOnInit() {
this._heroes = HEROES;

View File

@ -8,8 +8,7 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
// #docregion trigger, trigger-wildcard1, trigger-transition
animations: [
trigger('openClose', [
// #enddocregion events1
// #docregion state1, events1
// #docregion state1
// ...
// #enddocregion events1
state('open', style({
@ -34,8 +33,7 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
transition('closed => open', [
animate('0.5s')
]),
// #enddocregion trigger, component
// #enddocregion transition2
// #enddocregion transition2, trigger, component
// #docregion trigger-wildcard1
transition('* => closed', [
animate('1s')
@ -70,7 +68,9 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
})
// #docregion events
export class OpenCloseComponent {
// #enddocregion events1, events
// #enddocregion events1, events, component
@Input() logging = false;
// #docregion component
isOpen = true;
toggle() {
@ -78,9 +78,8 @@ export class OpenCloseComponent {
}
// #enddocregion component
@Input() logging = false;
// #docregion events1, events
onAnimationEvent ( event: AnimationEvent ) {
onAnimationEvent( event: AnimationEvent ) {
// #enddocregion events1, events
if (!this.logging) {
return;

View File

@ -1,5 +1,3 @@
'use strict'; // necessary for es6 output in node
import { protractor, browser, element, by, ElementFinder } from 'protractor';
const nameSuffix = 'X';
@ -21,7 +19,7 @@ describe('Architecture', () => {
});
it(`has h2 '${expectedH2}'`, () => {
let h2 = element.all(by.css('h2')).map((elt: any) => elt.getText());
const h2 = element.all(by.css('h2')).map((elt: any) => elt.getText());
expect(h2).toEqual(expectedH2);
});
@ -34,42 +32,42 @@ function heroTests() {
const targetHero: Hero = { id: 2, name: 'Dr Nice' };
it('has the right number of heroes', () => {
let page = getPageElts();
const page = getPageElts();
expect(page.heroes.count()).toEqual(3);
});
it('has no hero details initially', function () {
let page = getPageElts();
it('has no hero details initially', () => {
const page = getPageElts();
expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail');
});
it('shows selected hero details', async () => {
await element(by.cssContainingText('li', targetHero.name)).click();
let page = getPageElts();
let hero = await heroFromDetail(page.heroDetail);
const page = getPageElts();
const hero = await heroFromDetail(page.heroDetail);
expect(hero.id).toEqual(targetHero.id);
expect(hero.name).toEqual(targetHero.name);
});
it(`shows updated hero name in details`, async () => {
let input = element.all(by.css('input')).first();
const input = element.all(by.css('input')).first();
input.sendKeys(nameSuffix);
let page = getPageElts();
let hero = await heroFromDetail(page.heroDetail);
let newName = targetHero.name + nameSuffix;
const page = getPageElts();
const hero = await heroFromDetail(page.heroDetail);
const newName = targetHero.name + nameSuffix;
expect(hero.id).toEqual(targetHero.id);
expect(hero.name).toEqual(newName);
});
}
function salesTaxTests() {
it('has no sales tax initially', function () {
let page = getPageElts();
it('has no sales tax initially', () => {
const page = getPageElts();
expect(page.salesTaxDetail.isPresent()).toBeFalsy('no sales tax info');
});
it('shows sales tax', async function () {
let page = getPageElts();
it('shows sales tax', async () => {
const page = getPageElts();
page.salesTaxAmountInput.sendKeys('10', protractor.Key.ENTER);
expect(page.salesTaxDetail.getText()).toEqual('The sales tax is $1.00');
});
@ -88,13 +86,11 @@ function getPageElts() {
async function heroFromDetail(detail: ElementFinder): Promise<Hero> {
// Get hero id from the first <div>
// let _id = await detail.all(by.css('div')).first().getText();
let _id = await detail.all(by.css('div')).first().getText();
const id = await detail.all(by.css('div')).first().getText();
// Get name from the h2
// let _name = await detail.element(by.css('h4')).getText();
let _name = await detail.element(by.css('h4')).getText();
const name = await detail.element(by.css('h4')).getText();
return {
id: +_id.substr(_id.indexOf(' ') + 1),
name: _name.substr(0, _name.lastIndexOf(' '))
id: +id.substr(id.indexOf(' ') + 1),
name: name.substr(0, name.lastIndexOf(' ')),
};
}

View File

@ -1,15 +1,15 @@
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
// #docregion imports
import { NgModule } from '@angular/core';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
// #enddocregion imports
import { HeroDetailComponent } from './hero-detail.component';
import { HeroListComponent } from './hero-list.component';
import { SalesTaxComponent } from './sales-tax.component';
import { HeroService } from './hero.service';
import { BackendService } from './backend.service';
import { Logger } from './logger.service';
import { HeroListComponent } from './hero-list.component';
import { SalesTaxComponent } from './sales-tax.component';
import { HeroService } from './hero.service';
import { BackendService } from './backend.service';
import { Logger } from './logger.service';
@NgModule({
imports: [

View File

@ -18,7 +18,7 @@ export class BackendService {
// TODO: get from the database
return Promise.resolve<Hero[]>(HEROES);
}
let err = new Error('Cannot get object of this type');
const err = new Error('Cannot get object of this type');
this.logger.error(err);
throw err;
}

View File

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
import { Hero } from './hero';
import { HeroService } from './hero.service';
// #docregion metadata, providers
@Component({

View File

@ -22,7 +22,7 @@ export class AppComponent {
}
// #docregion module
import { NgModule } from '@angular/core';
import { NgModule } from '@angular/core';
// #docregion import-browser-module
import { BrowserModule } from '@angular/platform-browser';
// #enddocregion import-browser-module

View File

@ -1,7 +1,7 @@
import { Component } from '@angular/core';
import { Component } from '@angular/core';
import { SalesTaxService } from './sales-tax.service';
import { TaxRateService } from './tax-rate.service';
import { TaxRateService } from './tax-rate.service';
@Component({
selector: 'app-sales-tax',

View File

@ -7,7 +7,7 @@ export class SalesTaxService {
constructor(private rateService: TaxRateService) { }
getVAT(value: string | number) {
let amount = (typeof value === 'string') ?
const amount = (typeof value === 'string') ?
parseFloat(value) : value;
return (amount || 0) * this.rateService.getRate('VAT');
}

View File

@ -1,34 +1,32 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Attribute binding example', function () {
describe('Attribute binding example', () => {
beforeEach(function () {
beforeEach(() => {
browser.get('');
});
it('should display Property Binding with Angular', function () {
it('should display Property Binding with Angular', () => {
expect(element(by.css('h1')).getText()).toEqual('Attribute, class, and style bindings');
});
it('should display a table', function() {
it('should display a table', () => {
expect(element.all(by.css('table')).isPresent()).toBe(true);
});
it('should display an Aria button', function () {
it('should display an Aria button', () => {
expect(element.all(by.css('button')).get(0).getText()).toBe('Go for it with Aria');
});
it('should display a blue background on div', function () {
it('should display a blue background on div', () => {
expect(element.all(by.css('div')).get(1).getCssValue('background-color')).toEqual('rgba(25, 118, 210, 1)');
});
it('should display a blue div with a red border', function () {
it('should display a blue div with a red border', () => {
expect(element.all(by.css('div')).get(1).getCssValue('border')).toEqual('2px solid rgb(212, 30, 46)');
});
it('should display a div with many classes', function () {
it('should display a div with many classes', () => {
expect(element.all(by.css('div')).get(1).getAttribute('class')).toContain('special');
expect(element.all(by.css('div')).get(1).getAttribute('class')).toContain('clearance');
});

View File

@ -1,16 +1,16 @@
import { Component } from '@angular/core';
import { Component, HostBinding } from '@angular/core';
@Component({
selector: 'comp-with-host-binding',
template: 'I am a component!',
host: {
'[class.special]': 'isSpecial',
'[style.color]': 'color',
'[style.width]': 'width'
}
})
export class CompWithHostBindingComponent {
@HostBinding('class.special')
isSpecial = false;
@HostBinding('style.color')
color = 'green';
@HostBinding('style.width')
width = '200px';
}

View File

@ -1,17 +1,15 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Attribute directives', () => {
let _title = 'My First Attribute Directive';
const title = 'My First Attribute Directive';
beforeAll(() => {
browser.get('');
});
it(`should display correct title: ${_title}`, () => {
expect(element(by.css('h1')).getText()).toEqual(_title);
it(`should display correct title: ${title}`, () => {
expect(element(by.css('h1')).getText()).toEqual(title);
});
it('should be able to select green highlight', () => {

View File

@ -3,7 +3,7 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component.1';
import { AppComponent } from './app.component.1';
import { HighlightDirective as HLD1 } from './highlight.directive.1';
import { HighlightDirective as HLD2 } from './highlight.directive.2';
import { HighlightDirective as HLD3 } from './highlight.directive.3';

View File

@ -3,57 +3,55 @@ import { logging } from 'selenium-webdriver';
describe('Binding syntax e2e tests', () => {
beforeEach(function () {
browser.get('');
});
beforeEach(() => browser.get(''));
// helper function used to test what's logged to the console
async function logChecker(button, contents) {
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
const message = logs.filter(({ message }) => message.indexOf(contents) !== -1 ? true : false);
expect(message.length).toBeGreaterThan(0);
}
// helper function used to test what's logged to the console
async function logChecker(button, contents) {
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
const messages = logs.filter(({ message }) => message.indexOf(contents) !== -1 ? true : false);
expect(messages.length).toBeGreaterThan(0);
}
it('should display Binding syntax', function () {
it('should display Binding syntax', () => {
expect(element(by.css('h1')).getText()).toEqual('Binding syntax');
});
it('should display Save button', function () {
it('should display Save button', () => {
expect(element.all(by.css('button')).get(0).getText()).toBe('Save');
});
it('should display HTML attributes and DOM properties', function () {
it('should display HTML attributes and DOM properties', () => {
expect(element.all(by.css('h2')).get(1).getText()).toBe('HTML attributes and DOM properties');
});
it('should display 1. Use the inspector...', function () {
it('should display 1. Use the inspector...', () => {
expect(element.all(by.css('p')).get(0).getText()).toContain('1. Use the inspector');
});
it('should display Disabled property vs. attribute', function () {
it('should display Disabled property vs. attribute', () => {
expect(element.all(by.css('h3')).get(0).getText()).toBe('Disabled property vs. attribute');
});
it('should log a message including Sarah', async () => {
let attributeButton = element.all(by.css('button')).get(1);
const attributeButton = element.all(by.css('button')).get(1);
await attributeButton.click();
const contents = 'Sarah';
logChecker(attributeButton, contents);
});
it('should log a message including Sarah for DOM property', async () => {
let DOMPropertyButton = element.all(by.css('button')).get(2);
const DOMPropertyButton = element.all(by.css('button')).get(2);
await DOMPropertyButton.click();
const contents = 'Sarah';
logChecker(DOMPropertyButton, contents);
});
it('should log a message including Sally for DOM property', async () => {
let DOMPropertyButton = element.all(by.css('button')).get(2);
let input = element(by.css('input'));
const DOMPropertyButton = element.all(by.css('button')).get(2);
const input = element(by.css('input'));
input.sendKeys('Sally');
await DOMPropertyButton.click();
const contents = 'Sally';
@ -61,14 +59,14 @@ describe('Binding syntax e2e tests', () => {
});
it('should log a message that Test Button works', async () => {
let testButton = element.all(by.css('button')).get(3);
const testButton = element.all(by.css('button')).get(3);
await testButton.click();
const contents = 'Test';
logChecker(testButton, contents);
});
it('should toggle Test Button disabled', async () => {
let toggleButton = element.all(by.css('button')).get(4);
const toggleButton = element.all(by.css('button')).get(4);
await toggleButton.click();
const contents = 'true';
logChecker(toggleButton, contents);

View File

@ -26,7 +26,7 @@ export class AppComponent {
toggleDisabled(): any {
let testButton = <HTMLInputElement> document.getElementById('testButton');
const testButton = document.getElementById('testButton') as HTMLInputElement;
testButton.disabled = !testButton.disabled;
console.warn(testButton.disabled);
}

View File

@ -1,21 +1,19 @@
'use strict';
import { browser, element, by } from 'protractor';
describe('Built-in Directives', function () {
describe('Built-in Directives', () => {
beforeAll(function () {
beforeAll(() => {
browser.get('');
});
it('should have title Built-in Directives', function () {
let title = element.all(by.css('h1')).get(0);
it('should have title Built-in Directives', () => {
const title = element.all(by.css('h1')).get(0);
expect(title.getText()).toEqual('Built-in Directives');
});
it('should change first Teapot header', async () => {
let firstLabel = element.all(by.css('p')).get(0);
let firstInput = element.all(by.css('input')).get(0);
const firstLabel = element.all(by.css('p')).get(0);
const firstInput = element.all(by.css('input')).get(0);
expect(firstLabel.getText()).toEqual('Current item name: Teapot');
firstInput.sendKeys('abc');
@ -23,49 +21,49 @@ describe('Built-in Directives', function () {
});
it('should modify sentence when modified checkbox checked', function () {
let modifiedChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(1);
let modifiedSentence = element.all(by.css('div')).get(1);
it('should modify sentence when modified checkbox checked', () => {
const modifiedChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(1);
const modifiedSentence = element.all(by.css('div')).get(1);
modifiedChkbxLabel.click();
expect(modifiedSentence.getText()).toContain('modified');
});
it('should modify sentence when normal checkbox checked', function () {
let normalChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(4);
let normalSentence = element.all(by.css('div')).get(7);
it('should modify sentence when normal checkbox checked', () => {
const normalChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(4);
const normalSentence = element.all(by.css('div')).get(7);
normalChkbxLabel.click();
expect(normalSentence.getText()).toContain('normal weight and, extra large');
});
it('should toggle app-item-detail', function () {
let toggleButton = element.all(by.css('button')).get(3);
let toggledDiv = element.all(by.css('app-item-detail')).get(0);
it('should toggle app-item-detail', () => {
const toggleButton = element.all(by.css('button')).get(3);
const toggledDiv = element.all(by.css('app-item-detail')).get(0);
toggleButton.click();
expect(toggledDiv.isDisplayed()).toBe(true);
});
it('should hide app-item-detail', function () {
let hiddenMessage = element.all(by.css('p')).get(11);
let hiddenDiv = element.all(by.css('app-item-detail')).get(2);
it('should hide app-item-detail', () => {
const hiddenMessage = element.all(by.css('p')).get(11);
const hiddenDiv = element.all(by.css('app-item-detail')).get(2);
expect(hiddenMessage.getText()).toContain('in the DOM');
expect(hiddenDiv.isDisplayed()).toBe(true);
});
it('should have 10 lists each containing the string Teapot', function () {
let listDiv = element.all(by.cssContainingText('.box', 'Teapot'));
it('should have 10 lists each containing the string Teapot', () => {
const listDiv = element.all(by.cssContainingText('.box', 'Teapot'));
expect(listDiv.count()).toBe(10);
});
it('should switch case', function () {
let tvRadioButton = element.all(by.css('input[type="radio"]')).get(3);
let tvDiv = element(by.css('app-lost-item'));
it('should switch case', () => {
const tvRadioButton = element.all(by.css('input[type="radio"]')).get(3);
const tvDiv = element(by.css('app-lost-item'));
let fishbowlRadioButton = element.all(by.css('input[type="radio"]')).get(4);
let fishbowlDiv = element(by.css('app-unknown-item'));
const fishbowlRadioButton = element.all(by.css('input[type="radio"]')).get(4);
const fishbowlDiv = element(by.css('app-unknown-item'));
tvRadioButton.click();
expect(tvDiv.getText()).toContain('Television');

View File

@ -30,6 +30,14 @@ export class AppComponent implements OnInit {
itemsWithTrackByCountReset = 0;
itemIdIncrement = 1;
// #docregion setClasses
currentClasses: {};
// #enddocregion setClasses
// #docregion setStyles
currentStyles: {};
// #enddocregion setStyles
ngOnInit() {
this.resetItems();
this.setCurrentClasses();
@ -41,20 +49,18 @@ export class AppComponent implements OnInit {
this.currentItem.name = name.toUpperCase();
}
// #docregion setClasses
currentClasses: {};
// #docregion setClasses
setCurrentClasses() {
// CSS classes: added/removed per current state of component properties
this.currentClasses = {
'saveable': this.canSave,
'modified': !this.isUnchanged,
'special': this.isSpecial
saveable: this.canSave,
modified: !this.isUnchanged,
special: this.isSpecial
};
}
// #enddocregion setClasses
// #docregion setStyles
currentStyles: {};
setCurrentStyles() {
// CSS styles: set per current state of component properties
this.currentStyles = {
@ -70,11 +76,7 @@ export class AppComponent implements OnInit {
}
giveNullCustomerValue() {
!(this.nullCustomer = null) ? (this.nullCustomer = 'Kelly') : (this.nullCustomer = null);
}
resetNullItem() {
this.nullCustomer = null;
this.nullCustomer = 'Kelly';
}
resetItems() {
@ -84,7 +86,7 @@ export class AppComponent implements OnInit {
}
resetList() {
this.resetItems()
this.resetItems();
this.itemsWithTrackByCountReset = 0;
this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
}
@ -107,7 +109,7 @@ export class AppComponent implements OnInit {
trackByItems(index: number, item: Item): number { return item.id; }
// #enddocregion trackByItems
trackById(index: number, item: any): number { return item['id']; }
trackById(index: number, item: any): number { return item.id; }
}

View File

@ -1,19 +1,17 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Built Template Functions Example', function () {
beforeAll(function () {
describe('Built Template Functions Example', () => {
beforeAll(() => {
browser.get('');
});
it('should have title Built-in Template Functions', function () {
let title = element.all(by.css('h1')).get(0);
it('should have title Built-in Template Functions', () => {
const title = element.all(by.css('h1')).get(0);
expect(title.getText()).toEqual('Built-in Template Functions');
});
it('should display $any( ) in h2', function () {
let header = element(by.css('h2'));
it('should display $any( ) in h2', () => {
const header = element(by.css('h2'));
expect(header.getText()).toContain('$any( )');
});

View File

@ -1,87 +1,85 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Component Communication Cookbook Tests', function () {
describe('Component Communication Cookbook Tests', () => {
// Note: '?e2e' which app can read to know it is running in protractor
// e.g. `if (!/e2e/.test(location.search)) { ...`
beforeAll(function () {
beforeAll(() => {
browser.get('?e2e');
});
describe('Parent-to-child communication', function() {
describe('Parent-to-child communication', () => {
// #docregion parent-to-child
// ...
let _heroNames = ['Dr IQ', 'Magneta', 'Bombasto'];
let _masterName = 'Master';
const heroNames = ['Dr IQ', 'Magneta', 'Bombasto'];
const masterName = 'Master';
it('should pass properties to children properly', function () {
let parent = element.all(by.tagName('app-hero-parent')).get(0);
let heroes = parent.all(by.tagName('app-hero-child'));
it('should pass properties to children properly', () => {
const parent = element.all(by.tagName('app-hero-parent')).get(0);
const heroes = parent.all(by.tagName('app-hero-child'));
for (let i = 0; i < _heroNames.length; i++) {
let childTitle = heroes.get(i).element(by.tagName('h3')).getText();
let childDetail = heroes.get(i).element(by.tagName('p')).getText();
expect(childTitle).toEqual(_heroNames[i] + ' says:');
expect(childDetail).toContain(_masterName);
for (let i = 0; i < heroNames.length; i++) {
const childTitle = heroes.get(i).element(by.tagName('h3')).getText();
const childDetail = heroes.get(i).element(by.tagName('p')).getText();
expect(childTitle).toEqual(heroNames[i] + ' says:');
expect(childDetail).toContain(masterName);
}
});
// ...
// #enddocregion parent-to-child
});
describe('Parent-to-child communication with setter', function() {
describe('Parent-to-child communication with setter', () => {
// #docregion parent-to-child-setter
// ...
it('should display trimmed, non-empty names', function () {
let _nonEmptyNameIndex = 0;
let _nonEmptyName = '"Dr IQ"';
let parent = element.all(by.tagName('app-name-parent')).get(0);
let hero = parent.all(by.tagName('app-name-child')).get(_nonEmptyNameIndex);
it('should display trimmed, non-empty names', () => {
const nonEmptyNameIndex = 0;
const nonEmptyName = '"Dr IQ"';
const parent = element.all(by.tagName('app-name-parent')).get(0);
const hero = parent.all(by.tagName('app-name-child')).get(nonEmptyNameIndex);
let displayName = hero.element(by.tagName('h3')).getText();
expect(displayName).toEqual(_nonEmptyName);
const displayName = hero.element(by.tagName('h3')).getText();
expect(displayName).toEqual(nonEmptyName);
});
it('should replace empty name with default name', function () {
let _emptyNameIndex = 1;
let _defaultName = '"<no name set>"';
let parent = element.all(by.tagName('app-name-parent')).get(0);
let hero = parent.all(by.tagName('app-name-child')).get(_emptyNameIndex);
it('should replace empty name with default name', () => {
const emptyNameIndex = 1;
const defaultName = '"<no name set>"';
const parent = element.all(by.tagName('app-name-parent')).get(0);
const hero = parent.all(by.tagName('app-name-child')).get(emptyNameIndex);
let displayName = hero.element(by.tagName('h3')).getText();
expect(displayName).toEqual(_defaultName);
const displayName = hero.element(by.tagName('h3')).getText();
expect(displayName).toEqual(defaultName);
});
// ...
// #enddocregion parent-to-child-setter
});
describe('Parent-to-child communication with ngOnChanges', function() {
describe('Parent-to-child communication with ngOnChanges', () => {
// #docregion parent-to-child-onchanges
// ...
// Test must all execute in this exact order
it('should set expected initial values', function () {
let actual = getActual();
it('should set expected initial values', () => {
const actual = getActual();
let initialLabel = 'Version 1.23';
let initialLog = 'Initial value of major set to 1, Initial value of minor set to 23';
const initialLabel = 'Version 1.23';
const initialLog = 'Initial value of major set to 1, Initial value of minor set to 23';
expect(actual.label).toBe(initialLabel);
expect(actual.count).toBe(1);
expect(actual.logs.get(0).getText()).toBe(initialLog);
});
it('should set expected values after clicking \'Minor\' twice', function () {
let repoTag = element(by.tagName('app-version-parent'));
let newMinorButton = repoTag.all(by.tagName('button')).get(0);
it('should set expected values after clicking \'Minor\' twice', () => {
const repoTag = element(by.tagName('app-version-parent'));
const newMinorButton = repoTag.all(by.tagName('button')).get(0);
newMinorButton.click().then(function() {
newMinorButton.click().then(function() {
let actual = getActual();
newMinorButton.click().then(() => {
newMinorButton.click().then(() => {
const actual = getActual();
let labelAfter2Minor = 'Version 1.25';
let logAfter2Minor = 'minor changed from 24 to 25';
const labelAfter2Minor = 'Version 1.25';
const logAfter2Minor = 'minor changed from 24 to 25';
expect(actual.label).toBe(labelAfter2Minor);
expect(actual.count).toBe(3);
@ -90,15 +88,15 @@ describe('Component Communication Cookbook Tests', function () {
});
});
it('should set expected values after clicking \'Major\' once', function () {
let repoTag = element(by.tagName('app-version-parent'));
let newMajorButton = repoTag.all(by.tagName('button')).get(1);
it('should set expected values after clicking \'Major\' once', () => {
const repoTag = element(by.tagName('app-version-parent'));
const newMajorButton = repoTag.all(by.tagName('button')).get(1);
newMajorButton.click().then(function() {
let actual = getActual();
newMajorButton.click().then(() => {
const actual = getActual();
let labelAfterMajor = 'Version 2.0';
let logAfterMajor = 'major changed from 1 to 2, minor changed from 25 to 0';
const labelAfterMajor = 'Version 2.0';
const logAfterMajor = 'major changed from 1 to 2, minor changed from 25 to 0';
expect(actual.label).toBe(labelAfterMajor);
expect(actual.count).toBe(4);
@ -107,14 +105,14 @@ describe('Component Communication Cookbook Tests', function () {
});
function getActual() {
let versionTag = element(by.tagName('app-version-child'));
let label = versionTag.element(by.tagName('h3')).getText();
let ul = versionTag.element((by.tagName('ul')));
let logs = ul.all(by.tagName('li'));
const versionTag = element(by.tagName('app-version-child'));
const label = versionTag.element(by.tagName('h3')).getText();
const ul = versionTag.element((by.tagName('ul')));
const logs = ul.all(by.tagName('li'));
return {
label: label,
logs: logs,
label,
logs,
count: logs.count()
};
}
@ -123,30 +121,30 @@ describe('Component Communication Cookbook Tests', function () {
});
describe('Child-to-parent communication', function() {
describe('Child-to-parent communication', () => {
// #docregion child-to-parent
// ...
it('should not emit the event initially', function () {
let voteLabel = element(by.tagName('app-vote-taker'))
it('should not emit the event initially', () => {
const voteLabel = element(by.tagName('app-vote-taker'))
.element(by.tagName('h3')).getText();
expect(voteLabel).toBe('Agree: 0, Disagree: 0');
});
it('should process Agree vote', function () {
let agreeButton1 = element.all(by.tagName('app-voter')).get(0)
it('should process Agree vote', () => {
const agreeButton1 = element.all(by.tagName('app-voter')).get(0)
.all(by.tagName('button')).get(0);
agreeButton1.click().then(function() {
let voteLabel = element(by.tagName('app-vote-taker'))
agreeButton1.click().then(() => {
const voteLabel = element(by.tagName('app-vote-taker'))
.element(by.tagName('h3')).getText();
expect(voteLabel).toBe('Agree: 1, Disagree: 0');
});
});
it('should process Disagree vote', function () {
let agreeButton1 = element.all(by.tagName('app-voter')).get(1)
it('should process Disagree vote', () => {
const agreeButton1 = element.all(by.tagName('app-voter')).get(1)
.all(by.tagName('button')).get(1);
agreeButton1.click().then(function() {
let voteLabel = element(by.tagName('app-vote-taker'))
agreeButton1.click().then(() => {
const voteLabel = element(by.tagName('app-vote-taker'))
.element(by.tagName('h3')).getText();
expect(voteLabel).toBe('Agree: 1, Disagree: 1');
});
@ -157,31 +155,31 @@ describe('Component Communication Cookbook Tests', function () {
// Can't run timer tests in protractor because
// interaction w/ zones causes all tests to freeze & timeout.
xdescribe('Parent calls child via local var', function() {
xdescribe('Parent calls child via local var', () => {
countDownTimerTests('countdown-parent-lv');
});
xdescribe('Parent calls ViewChild', function() {
xdescribe('Parent calls ViewChild', () => {
countDownTimerTests('countdown-parent-vc');
});
function countDownTimerTests(parentTag: string) {
// #docregion countdown-timer-tests
// ...
it('timer and parent seconds should match', function () {
let parent = element(by.tagName(parentTag));
let message = parent.element(by.tagName('app-countdown-timer')).getText();
it('timer and parent seconds should match', () => {
const parent = element(by.tagName(parentTag));
const message = parent.element(by.tagName('app-countdown-timer')).getText();
browser.sleep(10); // give `seconds` a chance to catchup with `message`
let seconds = parent.element(by.className('seconds')).getText();
const seconds = parent.element(by.className('seconds')).getText();
expect(message).toContain(seconds);
});
it('should stop the countdown', function () {
let parent = element(by.tagName(parentTag));
let stopButton = parent.all(by.tagName('button')).get(1);
it('should stop the countdown', () => {
const parent = element(by.tagName(parentTag));
const stopButton = parent.all(by.tagName('button')).get(1);
stopButton.click().then(function() {
let message = parent.element(by.tagName('app-countdown-timer')).getText();
stopButton.click().then(() => {
const message = parent.element(by.tagName('app-countdown-timer')).getText();
expect(message).toContain('Holding');
});
});
@ -190,39 +188,39 @@ describe('Component Communication Cookbook Tests', function () {
}
describe('Parent and children communicate via a service', function() {
describe('Parent and children communicate via a service', () => {
// #docregion bidirectional-service
// ...
it('should announce a mission', function () {
let missionControl = element(by.tagName('app-mission-control'));
let announceButton = missionControl.all(by.tagName('button')).get(0);
announceButton.click().then(function () {
let history = missionControl.all(by.tagName('li'));
it('should announce a mission', () => {
const missionControl = element(by.tagName('app-mission-control'));
const announceButton = missionControl.all(by.tagName('button')).get(0);
announceButton.click().then(() => {
const history = missionControl.all(by.tagName('li'));
expect(history.count()).toBe(1);
expect(history.get(0).getText()).toMatch(/Mission.* announced/);
});
});
it('should confirm the mission by Lovell', function () {
it('should confirm the mission by Lovell', () => {
testConfirmMission(1, 2, 'Lovell');
});
it('should confirm the mission by Haise', function () {
it('should confirm the mission by Haise', () => {
testConfirmMission(3, 3, 'Haise');
});
it('should confirm the mission by Swigert', function () {
it('should confirm the mission by Swigert', () => {
testConfirmMission(2, 4, 'Swigert');
});
function testConfirmMission(buttonIndex: number, expectedLogCount: number, astronaut: string) {
let _confirmedLog = ' confirmed the mission';
let missionControl = element(by.tagName('app-mission-control'));
let confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex);
confirmButton.click().then(function () {
let history = missionControl.all(by.tagName('li'));
const confirmedLog = ' confirmed the mission';
const missionControl = element(by.tagName('app-mission-control'));
const confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex);
confirmButton.click().then(() => {
const history = missionControl.all(by.tagName('li'));
expect(history.count()).toBe(expectedLogCount);
expect(history.get(expectedLogCount - 1).getText()).toBe(astronaut + _confirmedLog);
expect(history.get(expectedLogCount - 1).getText()).toBe(astronaut + confirmedLog);
});
}
// ...

View File

@ -1,5 +1,5 @@
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { AstronautComponent } from './astronaut.component';
@ -15,7 +15,7 @@ import { VersionParentComponent } from './version-parent.component';
import { VoterComponent } from './voter.component';
import { VoteTakerComponent } from './votetaker.component';
let directives: any[] = [
const directives: any[] = [
AppComponent,
AstronautComponent,
CountdownTimerComponent,
@ -30,7 +30,7 @@ let directives: any[] = [
VoteTakerComponent
];
let schemas: any[] = [];
const schemas: any[] = [];
// Include Countdown examples
// unless in e2e tests which they break.
@ -49,6 +49,6 @@ if (!/e2e/.test(location.search)) {
],
declarations: directives,
bootstrap: [ AppComponent ],
schemas: schemas
schemas
})
export class AppModule { }

View File

@ -2,7 +2,7 @@
import { Component, Input, OnDestroy } from '@angular/core';
import { MissionService } from './mission.service';
import { Subscription } from 'rxjs';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-astronaut',

View File

@ -2,8 +2,8 @@
// #docregion vc
import { AfterViewInit, ViewChild } from '@angular/core';
// #docregion lv
import { Component } from '@angular/core';
import { CountdownTimerComponent } from './countdown-timer.component';
import { Component } from '@angular/core';
import { CountdownTimerComponent } from './countdown-timer.component';
// #enddocregion lv
// #enddocregion vc

View File

@ -12,6 +12,6 @@ import { Hero } from './hero';
})
export class HeroChildComponent {
@Input() hero: Hero;
@Input('master') masterName: string;
@Input('master') masterName: string; // tslint:disable-line: no-input-rename
}
// #enddocregion

View File

@ -1,6 +1,6 @@
// #docregion
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { Subject } from 'rxjs';
@Injectable()
export class MissionService {

View File

@ -1,7 +1,7 @@
// #docregion
import { Component } from '@angular/core';
import { Component } from '@angular/core';
import { MissionService } from './mission.service';
import { MissionService } from './mission.service';
@Component({
selector: 'app-mission-control',
@ -34,7 +34,7 @@ export class MissionControlComponent {
}
announce() {
let mission = this.missions[this.nextMission++];
const mission = this.missions[this.nextMission++];
this.missionService.announceMission(mission);
this.history.push(`Mission "${mission}" announced`);
if (this.nextMission >= this.missions.length) { this.nextMission = 0; }

View File

@ -1,3 +1,4 @@
// tslint:disable: variable-name
// #docregion
import { Component, Input } from '@angular/core';
@ -6,13 +7,11 @@ import { Component, Input } from '@angular/core';
template: '<h3>"{{name}}"</h3>'
})
export class NameChildComponent {
private _name = '';
@Input()
get name(): string { return this._name; }
set name(name: string) {
this._name = (name && name.trim()) || '<no name set>';
}
get name(): string { return this._name; }
private _name = '';
}
// #enddocregion

View File

@ -18,14 +18,14 @@ export class VersionChildComponent implements OnChanges {
changeLog: string[] = [];
ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
let log: string[] = [];
for (let propName in changes) {
let changedProp = changes[propName];
let to = JSON.stringify(changedProp.currentValue);
const log: string[] = [];
for (const propName in changes) {
const changedProp = changes[propName];
const to = JSON.stringify(changedProp.currentValue);
if (changedProp.isFirstChange()) {
log.push(`Initial value of ${propName} set to ${to}`);
} else {
let from = JSON.stringify(changedProp.previousValue);
const from = JSON.stringify(changedProp.previousValue);
log.push(`${propName} changed from ${from} to ${to}`);
}
}

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from '@angular/core';
import { Component } from '@angular/core';
@Component({
selector: 'app-vote-taker',

View File

@ -1,16 +1,14 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Component Style Tests', function () {
describe('Component Style Tests', () => {
beforeAll(function () {
beforeAll(() => {
browser.get('');
});
it('scopes component styles to component view', function() {
let componentH1 = element(by.css('app-root > h1'));
let externalH1 = element(by.css('body > h1'));
it('scopes component styles to component view', () => {
const componentH1 = element(by.css('app-root > h1'));
const externalH1 = element(by.css('body > h1'));
// Note: sometimes webdriver returns the fontWeight as "normal",
// other times as "400", both of which are equal in CSS terms.
@ -19,49 +17,49 @@ describe('Component Style Tests', function () {
});
it('allows styling :host element', function() {
let host = element(by.css('app-hero-details'));
it('allows styling :host element', () => {
const host = element(by.css('app-hero-details'));
expect(host.getCssValue('borderWidth')).toEqual('1px');
});
it('supports :host() in function form', function() {
let host = element(by.css('app-hero-details'));
it('supports :host() in function form', () => {
const host = element(by.css('app-hero-details'));
host.element(by.buttonText('Activate')).click();
expect(host.getCssValue('borderWidth')).toEqual('3px');
});
it('allows conditional :host-context() styling', function() {
let h2 = element(by.css('app-hero-details h2'));
it('allows conditional :host-context() styling', () => {
const h2 = element(by.css('app-hero-details h2'));
expect(h2.getCssValue('backgroundColor')).toEqual('rgba(238, 238, 255, 1)'); // #eeeeff
});
it('styles both view and content children with /deep/', function() {
let viewH3 = element(by.css('app-hero-team h3'));
let contentH3 = element(by.css('app-hero-controls h3'));
it('styles both view and content children with /deep/', () => {
const viewH3 = element(by.css('app-hero-team h3'));
const contentH3 = element(by.css('app-hero-controls h3'));
expect(viewH3.getCssValue('fontStyle')).toEqual('italic');
expect(contentH3.getCssValue('fontStyle')).toEqual('italic');
});
it('includes styles loaded with CSS @import', function() {
let host = element(by.css('app-hero-details'));
it('includes styles loaded with CSS @import', () => {
const host = element(by.css('app-hero-details'));
expect(host.getCssValue('padding')).toEqual('10px');
});
it('processes template inline styles', function() {
let button = element(by.css('app-hero-controls button'));
let externalButton = element(by.css('body > button'));
it('processes template inline styles', () => {
const button = element(by.css('app-hero-controls button'));
const externalButton = element(by.css('body > button'));
expect(button.getCssValue('backgroundColor')).toEqual('rgba(255, 255, 255, 1)'); // #ffffff
expect(externalButton.getCssValue('backgroundColor')).not.toEqual('rgba(255, 255, 255, 1)');
});
it('processes template <link>s', function() {
let li = element(by.css('app-hero-team li:first-child'));
let externalLi = element(by.css('body > ul li'));
it('processes template <link>s', () => {
const li = element(by.css('app-hero-team li:first-child'));
const externalLi = element(by.css('body > ul li'));
expect(li.getCssValue('listStyleType')).toEqual('square');
expect(externalLi.getCssValue('listStyleType')).not.toEqual('square');

View File

@ -1,76 +1,74 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Dependency Injection Cookbook', function () {
describe('Dependency Injection Cookbook', () => {
beforeAll(function () {
beforeAll(() => {
browser.get('');
});
it('should render Logged in User example', function () {
let loggedInUser = element.all(by.xpath('//h3[text()="Logged in user"]')).get(0);
it('should render Logged in User example', () => {
const loggedInUser = element.all(by.xpath('//h3[text()="Logged in user"]')).get(0);
expect(loggedInUser).toBeDefined();
});
it('"Bombasto" should be the logged in user', function () {
let loggedInUser = element.all(by.xpath('//div[text()="Name: Bombasto"]')).get(0);
it('"Bombasto" should be the logged in user', () => {
const loggedInUser = element.all(by.xpath('//div[text()="Name: Bombasto"]')).get(0);
expect(loggedInUser).toBeDefined();
});
it('should render sorted heroes', function () {
let sortedHeroes = element.all(by.xpath('//h3[text()="Sorted Heroes" and position()=1]')).get(0);
it('should render sorted heroes', () => {
const sortedHeroes = element.all(by.xpath('//h3[text()="Sorted Heroes" and position()=1]')).get(0);
expect(sortedHeroes).toBeDefined();
});
it('Dr Nice should be in sorted heroes', function () {
let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Dr Nice" and position()=2]')).get(0);
it('Dr Nice should be in sorted heroes', () => {
const sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Dr Nice" and position()=2]')).get(0);
expect(sortedHero).toBeDefined();
});
it('RubberMan should be in sorted heroes', function () {
let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="RubberMan" and position()=3]')).get(0);
it('RubberMan should be in sorted heroes', () => {
const sortedHero = element.all(by.xpath('//sorted-heroes/[text()="RubberMan" and position()=3]')).get(0);
expect(sortedHero).toBeDefined();
});
it('Magma should be in sorted heroes', function () {
let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Magma"]')).get(0);
it('Magma should be in sorted heroes', () => {
const sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Magma"]')).get(0);
expect(sortedHero).toBeDefined();
});
it('should render Hero of the Month', function () {
let heroOfTheMonth = element.all(by.xpath('//h3[text()="Hero of the month"]')).get(0);
it('should render Hero of the Month', () => {
const heroOfTheMonth = element.all(by.xpath('//h3[text()="Hero of the month"]')).get(0);
expect(heroOfTheMonth).toBeDefined();
});
it('should render Hero Bios', function () {
let heroBios = element.all(by.xpath('//h3[text()="Hero Bios"]')).get(0);
it('should render Hero Bios', () => {
const heroBios = element.all(by.xpath('//h3[text()="Hero Bios"]')).get(0);
expect(heroBios).toBeDefined();
});
it('should render Magma\'s description in Hero Bios', function () {
let magmaText = element.all(by.xpath('//textarea[text()="Hero of all trades"]')).get(0);
it('should render Magma\'s description in Hero Bios', () => {
const magmaText = element.all(by.xpath('//textarea[text()="Hero of all trades"]')).get(0);
expect(magmaText).toBeDefined();
});
it('should render Magma\'s phone in Hero Bios and Contacts', function () {
let magmaPhone = element.all(by.xpath('//div[text()="Phone #: 555-555-5555"]')).get(0);
it('should render Magma\'s phone in Hero Bios and Contacts', () => {
const magmaPhone = element.all(by.xpath('//div[text()="Phone #: 555-555-5555"]')).get(0);
expect(magmaPhone).toBeDefined();
});
it('should render Hero-of-the-Month runner-ups', function () {
let runnersUp = element(by.id('rups1')).getText();
it('should render Hero-of-the-Month runner-ups', () => {
const runnersUp = element(by.id('rups1')).getText();
expect(runnersUp).toContain('RubberMan, Dr Nice');
});
it('should render DateLogger log entry in Hero-of-the-Month', function () {
let logs = element.all(by.id('logs')).get(0).getText();
it('should render DateLogger log entry in Hero-of-the-Month', () => {
const logs = element.all(by.id('logs')).get(0).getText();
expect(logs).toContain('INFO: starting up at');
});
it('should highlight Hero Bios and Contacts container when mouseover', function () {
let target = element(by.css('div[appHighlight="yellow"]'));
let yellow = 'rgba(255, 255, 0, 1)';
it('should highlight Hero Bios and Contacts container when mouseover', () => {
const target = element(by.css('div[appHighlight="yellow"]'));
const yellow = 'rgba(255, 255, 0, 1)';
expect(target.getCssValue('background-color')).not.toEqual(yellow);
@ -81,25 +79,25 @@ describe('Dependency Injection Cookbook', function () {
browser.wait(() => target.getCssValue('background-color').then(c => c === yellow), 2000);
});
describe('in Parent Finder', function () {
let cathy1 = element(by.css('alex cathy'));
let craig1 = element(by.css('alex craig'));
let carol1 = element(by.css('alex carol p'));
let carol2 = element(by.css('barry carol p'));
describe('in Parent Finder', () => {
const cathy1 = element(by.css('alex cathy'));
const craig1 = element(by.css('alex craig'));
const carol1 = element(by.css('alex carol p'));
const carol2 = element(by.css('barry carol p'));
it('"Cathy" should find "Alex" via the component class', function () {
it('"Cathy" should find "Alex" via the component class', () => {
expect(cathy1.getText()).toContain('Found Alex via the component');
});
it('"Craig" should not find "Alex" via the base class', function () {
it('"Craig" should not find "Alex" via the base class', () => {
expect(craig1.getText()).toContain('Did not find Alex via the base');
});
it('"Carol" within "Alex" should have "Alex" parent', function () {
it('"Carol" within "Alex" should have "Alex" parent', () => {
expect(carol1.getText()).toContain('Alex');
});
it('"Carol" within "Barry" should have "Barry" parent', function () {
it('"Carol" within "Barry" should have "Barry" parent', () => {
expect(carol2.getText()).toContain('Barry');
});
});

View File

@ -1,5 +1,5 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [];

View File

@ -2,9 +2,9 @@
import { Component } from '@angular/core';
// #docregion import-services
import { LoggerService } from './logger.service';
import { LoggerService } from './logger.service';
import { UserContextService } from './user-context.service';
import { UserService } from './user.service';
import { UserService } from './user.service';
@Component({
selector: 'app-root',

View File

@ -1,26 +1,26 @@
// #docregion
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
// import { AppRoutingModule } from './app-routing.module';
// import { AppRoutingModule } from './app-routing.module';
import { LocationStrategy,
HashLocationStrategy } from '@angular/common';
import { NgModule } from '@angular/core';
HashLocationStrategy } from '@angular/common';
import { NgModule } from '@angular/core';
import { HeroData } from './hero-data';
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { HeroData } from './hero-data';
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { AppComponent } from './app.component';
import { HeroBioComponent } from './hero-bio.component';
import { AppComponent } from './app.component';
import { HeroBioComponent } from './hero-bio.component';
import { HeroBiosComponent,
HeroBiosAndContactsComponent } from './hero-bios.component';
import { HeroOfTheMonthComponent } from './hero-of-the-month.component';
import { HeroContactComponent } from './hero-contact.component';
import { HeroOfTheMonthComponent } from './hero-of-the-month.component';
import { HeroContactComponent } from './hero-contact.component';
import { HeroesBaseComponent,
SortedHeroesComponent } from './sorted-heroes.component';
import { HighlightDirective } from './highlight.directive';
SortedHeroesComponent } from './sorted-heroes.component';
import { HighlightDirective } from './highlight.directive';
import { ParentFinderComponent,
AlexComponent,
AliceComponent,
@ -30,8 +30,8 @@ import { ParentFinderComponent,
CathyComponent,
BarryComponent,
BethComponent,
BobComponent } from './parent-finder.component';
import { StorageComponent } from './storage.component';
BobComponent } from './parent-finder.component';
import { StorageComponent } from './storage.component';
const declarations = [
AppComponent,
@ -42,11 +42,11 @@ const declarations = [
ParentFinderComponent,
];
const a_components = [AliceComponent, AlexComponent ];
const componentListA = [ AliceComponent, AlexComponent ];
const b_components = [ BarryComponent, BethComponent, BobComponent ];
const componentListB = [ BarryComponent, BethComponent, BobComponent ];
const c_components = [
const componentListC = [
CarolComponent, ChrisComponent, CraigComponent,
CathyComponent
];
@ -61,9 +61,9 @@ const c_components = [
],
declarations: [
declarations,
a_components,
b_components,
c_components,
componentListA,
componentListB,
componentListC,
StorageComponent,
],
bootstrap: [ AppComponent ],

View File

@ -1,6 +1,6 @@
/* tslint:disable:one-line*/
// #docregion
import { Injectable } from '@angular/core';
import { Injectable } from '@angular/core';
import { LoggerService } from './logger.service';

View File

@ -1,7 +1,7 @@
// #docregion
import { Component, Input, OnInit } from '@angular/core';
import { HeroCacheService } from './hero-cache.service';
import { HeroCacheService } from './hero-cache.service';
// #docregion component
@Component({

View File

@ -1,9 +1,9 @@
// #docplaster
// #docregion
import { Component } from '@angular/core';
import { Component } from '@angular/core';
import { HeroService } from './hero.service';
import { LoggerService } from './logger.service';
import { HeroService } from './hero.service';
import { LoggerService } from './logger.service';
//////// HeroBiosComponent ////
// #docregion simple

View File

@ -1,7 +1,7 @@
// #docregion
import { Injectable } from '@angular/core';
import { Injectable } from '@angular/core';
import { Hero } from './hero';
import { Hero } from './hero';
import { HeroService } from './hero.service';
// #docregion service

View File

@ -3,7 +3,7 @@
import { Component, Host, Optional } from '@angular/core';
import { HeroCacheService } from './hero-cache.service';
import { LoggerService } from './logger.service';
import { LoggerService } from './logger.service';
// #docregion component
@Component({

View File

@ -3,7 +3,7 @@ import { Hero } from './hero';
export class HeroData {
createDb() {
let heroes = [
const heroes = [
new Hero(1, 'Windstorm'),
new Hero(2, 'Bombasto'),
new Hero(3, 'Magneta'),

View File

@ -1,8 +1,8 @@
// Illustrative (not used), mini-version of the actual HeroOfTheMonthComponent
// Injecting with the MinimalLogger "interface-class"
import { Component, NgModule } from '@angular/core';
import { LoggerService } from './logger.service';
import { MinimalLogger } from './minimal-logger.service';
import { LoggerService } from './logger.service';
import { MinimalLogger } from './minimal-logger.service';
// #docregion
@Component({

View File

@ -10,12 +10,12 @@ export const TITLE = new InjectionToken<string>('title');
import { Component, Inject } from '@angular/core';
import { DateLoggerService } from './date-logger.service';
import { Hero } from './hero';
import { HeroService } from './hero.service';
import { LoggerService } from './logger.service';
import { MinimalLogger } from './minimal-logger.service';
import { Hero } from './hero';
import { HeroService } from './hero.service';
import { LoggerService } from './logger.service';
import { MinimalLogger } from './minimal-logger.service';
import { RUNNERS_UP,
runnersUpFactory } from './runners-up';
runnersUpFactory } from './runners-up';
// #enddocregion hero-of-the-month
// #docregion some-hero

View File

@ -1,6 +1,6 @@
// #docregion
import { Injectable } from '@angular/core';
import { Hero } from './hero';
import { Hero } from './hero';
@Injectable({
providedIn: 'root'

View File

@ -1,5 +1,4 @@
/* tslint:disable:no-unused-variable component-selector-name one-line check-open-brace */
/* tslint:disable:*/
// tslint:disable: component-selector space-before-function-paren
// #docplaster
// #docregion
import { Component, forwardRef, Optional, SkipSelf } from '@angular/core';
@ -20,8 +19,7 @@ const DifferentParent = Parent;
// The `parentType` defaults to `Parent` when omitting the second parameter.
// #docregion provide-the-parent
export function provideParent
// #enddocregion provide-parent, provide-the-parent
// #docregion provide-parent
// #enddocregion provide-the-parent
(component: any, parentType?: any) {
return { provide: parentType || Parent, useExisting: forwardRef(() => component) };
}

View File

@ -2,7 +2,7 @@
// #docregion
import { InjectionToken } from '@angular/core';
import { Hero } from './hero';
import { Hero } from './hero';
import { HeroService } from './hero.service';
// #docregion runners-up
@ -22,5 +22,5 @@ export function runnersUpFactory(take: number) {
.join(', ');
// #docregion factory-synopsis
};
};
}
// #enddocregion factory-synopsis

View File

@ -2,8 +2,8 @@
// #docregion
import { Component, OnInit } from '@angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
import { Hero } from './hero';
import { HeroService } from './hero.service';
/////// HeroesBaseComponent /////
// #docregion heroes-base, injection

View File

@ -1,9 +1,9 @@
// #docplaster
// #docregion
import { Injectable } from '@angular/core';
import { Injectable } from '@angular/core';
import { LoggerService } from './logger.service';
import { UserService } from './user.service';
import { UserService } from './user.service';
// #docregion injectables, injectable
@Injectable({
@ -24,7 +24,7 @@ export class UserContextService {
// #enddocregion ctor, injectables
loadUser(userId: number) {
let user = this.userService.getUserById(userId);
const user = this.userService.getUserById(userId);
this.name = user.name;
this.role = user.role;

View File

@ -1,202 +1,196 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by, ElementFinder } from 'protractor';
describe('Dependency Injection Tests', function () {
describe('Dependency Injection Tests', () => {
let expectedMsg: string;
let expectedMsgRx: RegExp;
beforeAll(function () {
beforeAll(() => {
browser.get('');
});
describe('Cars:', function() {
describe('Cars:', () => {
it('DI car displays as expected', function () {
it('DI car displays as expected', () => {
expectedMsg = 'DI car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#di')).getText()).toEqual(expectedMsg);
});
it('No DI car displays as expected', function () {
it('No DI car displays as expected', () => {
expectedMsg = 'No DI car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#nodi')).getText()).toEqual(expectedMsg);
});
it('Injector car displays as expected', function () {
it('Injector car displays as expected', () => {
expectedMsg = 'Injector car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#injector')).getText()).toEqual(expectedMsg);
});
it('Factory car displays as expected', function () {
it('Factory car displays as expected', () => {
expectedMsg = 'Factory car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#factory')).getText()).toEqual(expectedMsg);
});
it('Simple car displays as expected', function () {
it('Simple car displays as expected', () => {
expectedMsg = 'Simple car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#simple')).getText()).toEqual(expectedMsg);
});
it('Super car displays as expected', function () {
it('Super car displays as expected', () => {
expectedMsg = 'Super car with 12 cylinders and Flintstone tires.';
expect(element(by.css('#super')).getText()).toEqual(expectedMsg);
});
it('Test car displays as expected', function () {
it('Test car displays as expected', () => {
expectedMsg = 'Test car with 8 cylinders and YokoGoodStone tires.';
expect(element(by.css('#test')).getText()).toEqual(expectedMsg);
});
});
describe('Other Injections:', function() {
it('DI car displays as expected', function () {
describe('Other Injections:', () => {
it('DI car displays as expected', () => {
expectedMsg = 'DI car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#car')).getText()).toEqual(expectedMsg);
});
it('Hero displays as expected', function () {
it('Hero displays as expected', () => {
expectedMsg = 'Dr Nice';
expect(element(by.css('#hero')).getText()).toEqual(expectedMsg);
});
it('Optional injection displays as expected', function () {
it('Optional injection displays as expected', () => {
expectedMsg = 'R.O.U.S.\'s? I don\'t think they exist!';
expect(element(by.css('#rodent')).getText()).toEqual(expectedMsg);
});
});
describe('Tests:', function() {
describe('Tests:', () => {
it('Tests display as expected', function () {
it('Tests display as expected', () => {
expectedMsgRx = /Tests passed/;
expect(element(by.css('#tests')).getText()).toMatch(expectedMsgRx);
});
});
describe('Provider variations:', function() {
describe('Provider variations:', () => {
it('P1 (class) displays as expected', function () {
it('P1 (class) displays as expected', () => {
expectedMsg = 'Hello from logger provided with Logger class';
expect(element(by.css('#p1')).getText()).toEqual(expectedMsg);
});
it('P3 (provide) displays as expected', function () {
it('P3 (provide) displays as expected', () => {
expectedMsg = 'Hello from logger provided with useClass:Logger';
expect(element(by.css('#p3')).getText()).toEqual(expectedMsg);
});
it('P4 (useClass:BetterLogger) displays as expected', function () {
it('P4 (useClass:BetterLogger) displays as expected', () => {
expectedMsg = 'Hello from logger provided with useClass:BetterLogger';
expect(element(by.css('#p4')).getText()).toEqual(expectedMsg);
});
it('P5 (useClass:EvenBetterLogger - dependency) displays as expected', function () {
it('P5 (useClass:EvenBetterLogger - dependency) displays as expected', () => {
expectedMsg = 'Message to Bob: Hello from EvenBetterlogger';
expect(element(by.css('#p5')).getText()).toEqual(expectedMsg);
});
it('P6a (no alias) displays as expected', function () {
it('P6a (no alias) displays as expected', () => {
expectedMsg = 'Hello OldLogger (but we want NewLogger)';
expect(element(by.css('#p6a')).getText()).toEqual(expectedMsg);
});
it('P6b (alias) displays as expected', function () {
it('P6b (alias) displays as expected', () => {
expectedMsg = 'Hello from NewLogger (via aliased OldLogger)';
expect(element(by.css('#p6b')).getText()).toEqual(expectedMsg);
});
it('P7 (useValue) displays as expected', function () {
it('P7 (useValue) displays as expected', () => {
expectedMsg = 'Silent logger says "Shhhhh!". Provided via "useValue"';
expect(element(by.css('#p7')).getText()).toEqual(expectedMsg);
});
it('P8 (useFactory) displays as expected', function () {
it('P8 (useFactory) displays as expected', () => {
expectedMsg = 'Hero service injected successfully via heroServiceProvider';
expect(element(by.css('#p8')).getText()).toEqual(expectedMsg);
});
it('P9 (InjectionToken) displays as expected', function () {
it('P9 (InjectionToken) displays as expected', () => {
expectedMsg = 'APP_CONFIG Application title is Dependency Injection';
expect(element(by.css('#p9')).getText()).toEqual(expectedMsg);
});
it('P10 (optional dependency) displays as expected', function () {
it('P10 (optional dependency) displays as expected', () => {
expectedMsg = 'Optional logger was not available';
expect(element(by.css('#p10')).getText()).toEqual(expectedMsg);
});
});
describe('User/Heroes:', function() {
it('User is Bob - unauthorized', function () {
describe('User/Heroes:', () => {
it('User is Bob - unauthorized', () => {
expectedMsgRx = /Bob, is not authorized/;
expect(element(by.css('#user')).getText()).toMatch(expectedMsgRx);
});
it('should have button', function () {
it('should have button', () => {
expect(element.all(by.cssContainingText('button', 'Next User'))
.get(0).isDisplayed()).toBe(true, '\'Next User\' button should be displayed');
});
it('unauthorized user should have multiple unauthorized heroes', function () {
let heroes = element.all(by.css('#unauthorized app-hero-list div'));
it('unauthorized user should have multiple unauthorized heroes', () => {
const heroes = element.all(by.css('#unauthorized app-hero-list div'));
expect(heroes.count()).toBeGreaterThan(0);
});
it('unauthorized user should have no secret heroes', function () {
let heroes = element.all(by.css('#unauthorized app-hero-list div'));
it('unauthorized user should have no secret heroes', () => {
const heroes = element.all(by.css('#unauthorized app-hero-list div'));
expect(heroes.count()).toBeGreaterThan(0);
let filteredHeroes = heroes.filter((elem: ElementFinder, index: number) => {
return elem.getText().then((text: string) => {
return /secret/.test(text);
});
const filteredHeroes = heroes.filter((elem: ElementFinder, index: number) => {
return elem.getText().then((text: string) => /secret/.test(text));
});
expect(filteredHeroes.count()).toEqual(0);
});
it('unauthorized user should have no authorized heroes listed', function () {
it('unauthorized user should have no authorized heroes listed', () => {
expect(element.all(by.css('#authorized app-hero-list div')).count()).toEqual(0);
});
describe('after button click', function() {
describe('after button click', () => {
beforeAll(function (done: any) {
let buttonEle = element.all(by.cssContainingText('button', 'Next User')).get(0);
beforeAll((done: any) => {
const buttonEle = element.all(by.cssContainingText('button', 'Next User')).get(0);
buttonEle.click().then(done, done);
});
it('User is Alice - authorized', function () {
it('User is Alice - authorized', () => {
expectedMsgRx = /Alice, is authorized/;
expect(element(by.css('#user')).getText()).toMatch(expectedMsgRx);
});
it('authorized user should have multiple authorized heroes ', function () {
let heroes = element.all(by.css('#authorized app-hero-list div'));
it('authorized user should have multiple authorized heroes ', () => {
const heroes = element.all(by.css('#authorized app-hero-list div'));
expect(heroes.count()).toBeGreaterThan(0);
});
it('authorized user should have multiple authorized heroes with tree-shakeable HeroesService', function () {
let heroes = element.all(by.css('#tspAuthorized app-hero-list div'));
it('authorized user should have multiple authorized heroes with tree-shakeable HeroesService', () => {
const heroes = element.all(by.css('#tspAuthorized app-hero-list div'));
expect(heroes.count()).toBeGreaterThan(0);
});
it('authorized user should have secret heroes', function () {
let heroes = element.all(by.css('#authorized app-hero-list div'));
it('authorized user should have secret heroes', () => {
const heroes = element.all(by.css('#authorized app-hero-list div'));
expect(heroes.count()).toBeGreaterThan(0);
let filteredHeroes = heroes.filter(function(elem: ElementFinder, index: number) {
return elem.getText().then(function(text: string) {
return /secret/.test(text);
});
const filteredHeroes = heroes.filter((elem: ElementFinder, index: number) => {
return elem.getText().then((text: string) => /secret/.test(text));
});
expect(filteredHeroes.count()).toBeGreaterThan(0);
});
it('authorized user should have no unauthorized heroes listed', function () {
it('authorized user should have no unauthorized heroes listed', () => {
expect(element.all(by.css('#unauthorized app-hero-list div')).count()).toEqual(0);
});
});

View File

@ -2,7 +2,7 @@
// #docregion imports
import { Component, Inject } from '@angular/core';
import { APP_CONFIG, AppConfig } from './app.config';
import { APP_CONFIG, AppConfig } from './app.config';
// #enddocregion imports
@Component({

View File

@ -1,8 +1,8 @@
// #docplaster
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserModule } from '@angular/platform-browser';
import { APP_CONFIG, HERO_DI_CONFIG } from './app.config';
import { APP_CONFIG, HERO_DI_CONFIG } from './app.config';
import { AppComponent } from './app.component';
import { CarComponent } from './car/car.component';
import { HeroesComponent } from './heroes/heroes.component';

View File

@ -7,7 +7,7 @@ import { Car, Engine, Tires } from './car';
export function simpleCar() {
// #docregion car-ctor-instantiation
// Simple car with 4 cylinders and Flintstone tires.
let car = new Car(new Engine(), new Tires());
const car = new Car(new Engine(), new Tires());
// #enddocregion car-ctor-instantiation
car.description = 'Simple';
return car;
@ -16,30 +16,31 @@ export function simpleCar() {
///////// example 2 ////////////
// #docregion car-ctor-instantiation-with-param
class Engine2 {
constructor(public cylinders: number) { }
}
class Engine2 {
constructor(public cylinders: number) { }
}
// #enddocregion car-ctor-instantiation-with-param
export function superCar() {
// #docregion car-ctor-instantiation-with-param
// #docregion car-ctor-instantiation-with-param
// Super car with 12 cylinders and Flintstone tires.
let bigCylinders = 12;
let car = new Car(new Engine2(bigCylinders), new Tires());
// #enddocregion car-ctor-instantiation-with-param
const bigCylinders = 12;
const car = new Car(new Engine2(bigCylinders), new Tires());
// #enddocregion car-ctor-instantiation-with-param
car.description = 'Super';
return car;
}
/////////// example 3 //////////
// #docregion car-ctor-instantiation-with-mocks
class MockEngine extends Engine { cylinders = 8; }
class MockTires extends Tires { make = 'YokoGoodStone'; }
// #docregion car-ctor-instantiation-with-mocks
class MockEngine extends Engine { cylinders = 8; }
class MockTires extends Tires { make = 'YokoGoodStone'; }
// #enddocregion car-ctor-instantiation-with-mocks
// #enddocregion car-ctor-instantiation-with-mocks
export function testCar() {
// #docregion car-ctor-instantiation-with-mocks
// Test car with 8 cylinders and YokoGoodStone tires.
let car = new Car(new MockEngine(), new MockTires());
const car = new Car(new MockEngine(), new MockTires());
// #enddocregion car-ctor-instantiation-with-mocks
car.description = 'Test';
return car;

View File

@ -4,7 +4,7 @@ import { Engine, Tires, Car } from './car';
// BAD pattern!
export class CarFactory {
createCar() {
let car = new Car(this.createEngine(), this.createTires());
const car = new Car(this.createEngine(), this.createTires());
car.description = 'Factory';
return car;
}

View File

@ -1,7 +1,7 @@
import { Injector } from '@angular/core';
import { Car, Engine, Tires } from './car';
import { Logger } from '../logger.service';
import { Logger } from '../logger.service';
// #docregion injector
export function useInjector() {
@ -26,14 +26,14 @@ export function useInjector() {
]
});
// #docregion injector-call
let car = injector.get(Car);
const car = injector.get(Car);
// #enddocregion injector-call, injector-create-and-call
car.description = 'Injector';
injector = Injector.create({
providers: [{ provide: Logger, deps: [] }]
});
let logger = injector.get(Logger);
const logger = injector.get(Logger);
logger.log('Injector car.drive() said: ' + car.drive());
return car;
}

View File

@ -1,15 +1,15 @@
// #docregion
import { Component } from '@angular/core';
import { Car, Engine, Tires } from './car';
import { Car as CarNoDi } from './car-no-di';
import { CarFactory } from './car-factory';
import { Car, Engine, Tires } from './car';
import { Car as CarNoDi } from './car-no-di';
import { CarFactory } from './car-factory';
import { testCar,
simpleCar,
superCar } from './car-creations';
superCar } from './car-creations';
import { useInjector } from './car-injector';
import { useInjector } from './car-injector';
@Component({
@ -27,9 +27,9 @@ import { useInjector } from './car-injector';
providers: [Car, Engine, Tires]
})
export class CarComponent {
factoryCar = (new CarFactory).createCar();
factoryCar = (new CarFactory()).createCar();
injectorCar = useInjector();
noDiCar = new CarNoDi;
noDiCar = new CarNoDi();
simpleCar = simpleCar();
superCar = superCar();
testCar = testCar();

View File

@ -1,6 +1,6 @@
// #docregion
import { Component } from '@angular/core';
import { HEROES } from './mock-heroes';
import { Component } from '@angular/core';
import { HEROES } from './mock-heroes';
@Component({
selector: 'app-hero-list',

View File

@ -1,7 +1,7 @@
// #docplaster
// #docregion
import { Component } from '@angular/core';
import { Hero } from './hero';
import { Component } from '@angular/core';
import { Hero } from './hero';
// #enddocregion
import { HeroService } from './hero.service.1';
/*

View File

@ -1,7 +1,7 @@
/* tslint:disable:one-line */
// #docregion
import { Component } from '@angular/core';
import { Hero } from './hero';
import { Component } from '@angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
@Component({

View File

@ -1,6 +1,6 @@
// #docregion
import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';
import { HEROES } from './mock-heroes';
@Injectable({
providedIn: 'root',

View File

@ -1,7 +1,7 @@
// #docregion
import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';
import { Logger } from '../logger.service';
import { HEROES } from './mock-heroes';
import { Logger } from '../logger.service';
@Injectable({
providedIn: 'root',

View File

@ -1,11 +1,11 @@
/* tslint:disable:one-line */
// #docregion
import { HeroService } from './hero.service';
import { Logger } from '../logger.service';
import { Logger } from '../logger.service';
import { UserService } from '../user.service';
// #docregion factory
let heroServiceFactory = (logger: Logger, userService: UserService) => {
const heroServiceFactory = (logger: Logger, userService: UserService) => {
return new HeroService(logger, userService.user.isAuthorized);
};
// #enddocregion factory

View File

@ -1,7 +1,7 @@
// #docregion
import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';
import { Logger } from '../logger.service';
import { HEROES } from './mock-heroes';
import { Logger } from '../logger.service';
import { UserService } from '../user.service';
@Injectable({
@ -17,7 +17,7 @@ export class HeroService {
private isAuthorized: boolean) { }
getHeroes() {
let auth = this.isAuthorized ? 'authorized ' : 'unauthorized';
const auth = this.isAuthorized ? 'authorized ' : 'unauthorized';
this.logger.log(`Getting heroes for ${auth} user.`);
return HEROES.filter(hero => this.isAuthorized || !hero.isSecret);
}

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from '@angular/core';
import { Component } from '@angular/core';
import { heroServiceProvider } from './hero.service.provider';
@Component({

View File

@ -2,11 +2,11 @@
// #docregion
import { Component, Injector, OnInit } from '@angular/core';
import { Car, Engine, Tires } from './car/car';
import { Hero } from './heroes/hero';
import { HeroService } from './heroes/hero.service';
import { heroServiceProvider } from './heroes/hero.service.provider';
import { Logger } from './logger.service';
import { Car, Engine, Tires } from './car/car';
import { Hero } from './heroes/hero';
import { HeroService } from './heroes/hero.service';
import { heroServiceProvider } from './heroes/hero.service.provider';
import { Logger } from './logger.service';
// #docregion injector
@Component({
@ -36,7 +36,7 @@ export class InjectorComponent implements OnInit {
}
get rodent() {
let rousDontExist = `R.O.U.S.'s? I don't think they exist!`;
const rousDontExist = `R.O.U.S.'s? I don't think they exist!`;
return this.injector.get(ROUS, rousDontExist);
}
}

View File

@ -18,7 +18,7 @@ const template = '{{log}}';
@Component({
selector: 'provider-1',
template: template,
template,
// #docregion providers-1, providers-logger
providers: [Logger]
// #enddocregion providers-1, providers-logger
@ -35,7 +35,7 @@ export class Provider1Component {
@Component({
selector: 'provider-3',
template: template,
template,
providers:
// #docregion providers-3
[{ provide: Logger, useClass: Logger }]
@ -54,7 +54,7 @@ export class BetterLogger extends Logger {}
@Component({
selector: 'provider-4',
template: template,
template,
providers:
// #docregion providers-4
[{ provide: Logger, useClass: BetterLogger }]
@ -76,7 +76,7 @@ export class EvenBetterLogger extends Logger {
constructor(private userService: UserService) { super(); }
log(message: string) {
let name = this.userService.user.name;
const name = this.userService.user.name;
super.log(`Message to ${name}: ${message}`);
}
}
@ -84,7 +84,7 @@ export class EvenBetterLogger extends Logger {
@Component({
selector: 'provider-5',
template: template,
template,
providers:
// #docregion providers-5
[ UserService,
@ -107,12 +107,12 @@ export class OldLogger {
logs: string[] = [];
log(message: string) {
throw new Error('Should not call the old logger!');
};
}
}
@Component({
selector: 'provider-6a',
template: template,
template,
providers:
// #docregion providers-6a
[ NewLogger,
@ -135,7 +135,7 @@ export class Provider6aComponent {
@Component({
selector: 'provider-6b',
template: template,
template,
providers:
// #docregion providers-6b
[ NewLogger,
@ -168,7 +168,7 @@ export const SilentLogger = {
@Component({
selector: 'provider-7',
template: template,
template,
providers:
// #docregion providers-7
[{ provide: Logger, useValue: SilentLogger }]
@ -186,7 +186,7 @@ export class Provider7Component {
@Component({
selector: 'provider-8',
template: template,
template,
providers: [heroServiceProvider, Logger, UserService]
})
export class Provider8Component {
@ -202,7 +202,7 @@ export class Provider8Component {
@Component({
selector: 'provider-9',
template: template,
template,
/*
// #docregion providers-9-interface
// FAIL! Can't use interface as provider token
@ -237,11 +237,11 @@ export class Provider9Component implements OnInit {
import { Optional } from '@angular/core';
// #enddocregion import-optional
let some_message = 'Hello from the injected logger';
const someMessage = 'Hello from the injected logger';
@Component({
selector: 'provider-10',
template: template,
template,
providers: [{ provide: Logger, useValue: null }]
})
export class Provider10Component implements OnInit {
@ -249,7 +249,7 @@ export class Provider10Component implements OnInit {
// #docregion provider-10-ctor
constructor(@Optional() private logger?: Logger) {
if (this.logger) {
this.logger.log(some_message);
this.logger.log(someMessage);
}
}
// #enddocregion provider-10-ctor

View File

@ -43,7 +43,7 @@ var testResults: {pass: string; message: string};
function expect(actual: any) {
return {
toEqual: function(expected: any){
toEqual: (expected: any) => {
testResults = actual === expected ?
{pass: 'passed', message: testName} :
{pass: 'failed', message: `${testName}; expected ${actual} to equal ${expected}.`};

View File

@ -1,6 +1,6 @@
import { NgModule } from '@angular/core';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { RouterModule } from '@angular/router';
import { ServiceModule } from './service-and-module';
// #docregion

View File

@ -8,8 +8,8 @@ export class User {
}
// TODO: get the user; don't 'new' it.
let alice = new User('Alice', true);
let bob = new User('Bob', false);
const alice = new User('Alice', true);
const bob = new User('Bob', false);
@Injectable({
providedIn: 'root'

View File

@ -1,29 +1,27 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Displaying Data Tests', function () {
let _title = 'Tour of Heroes';
let _defaultHero = 'Windstorm';
describe('Displaying Data Tests', () => {
const title = 'Tour of Heroes';
const defaultHero = 'Windstorm';
beforeAll(function () {
beforeAll(() => {
browser.get('');
});
it('should display correct title: ' + _title, function () {
expect(element(by.css('h1')).getText()).toEqual(_title);
it('should display correct title: ' + title, () => {
expect(element(by.css('h1')).getText()).toEqual(title);
});
it('should have correct default hero: ' + _defaultHero, function () {
expect(element(by.css('h2')).getText()).toContain(_defaultHero);
it('should have correct default hero: ' + defaultHero, () => {
expect(element(by.css('h2')).getText()).toContain(defaultHero);
});
it('should have heroes', function () {
let heroEls = element.all(by.css('li'));
it('should have heroes', () => {
const heroEls = element.all(by.css('li'));
expect(heroEls.count()).not.toBe(0, 'should have heroes');
});
it('should display "there are many heroes!"', function () {
it('should display "there are many heroes!"', () => {
expect(element(by.css('ul ~ p')).getText()).toContain('There are many heroes!');
});
});

View File

@ -1,6 +1,6 @@
// #docregion
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';

View File

@ -1,15 +1,13 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Docs Style Guide', function () {
let _title = 'Authors Style Guide Sample';
describe('Docs Style Guide', () => {
const title = 'Authors Style Guide Sample';
beforeAll(function () {
beforeAll(() => {
browser.get('');
});
it('should display correct title: ' + _title, function () {
expect(element(by.css('h1')).getText()).toEqual(_title);
it('should display correct title: ' + title, () => {
expect(element(by.css('h1')).getText()).toEqual(title);
});
});

View File

@ -1,9 +1,9 @@
// #docregion
import { NgModule } from '@angular/core';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { AppComponent } from './app.component';
// #docregion class
@NgModule({

View File

@ -1,18 +1,16 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
/* tslint:disable:quotemark */
describe('Dynamic Component Loader', function () {
describe('Dynamic Component Loader', () => {
beforeEach(function () {
beforeEach(() => {
browser.get('');
});
it('should load ad banner', function () {
let headline = element(by.xpath("//h4[text()='Featured Hero Profile']"));
let name = element(by.xpath("//h3[text()='Bombasto']"));
let bio = element(by.xpath("//p[text()='Brave as they come']"));
it('should load ad banner', () => {
const headline = element(by.xpath("//h4[text()='Featured Hero Profile']"));
const name = element(by.xpath("//h3[text()='Bombasto']"));
const bio = element(by.xpath("//p[text()='Brave as they come']"));
expect(name).toBeDefined();
expect(headline).toBeDefined();

View File

@ -2,7 +2,7 @@
import { Component, Input, OnInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '@angular/core';
import { AdDirective } from './ad.directive';
import { AdItem } from './ad-item';
import { AdItem } from './ad-item';
import { AdComponent } from './ad.component';
@Component({
@ -11,7 +11,7 @@ import { AdComponent } from './ad.component';
template: `
<div class="ad-banner-example">
<h3>Advertisements</h3>
<ng-template ad-host></ng-template>
<ng-template adHost></ng-template>
</div>
`
// #enddocregion ad-host
@ -43,8 +43,8 @@ export class AdBannerComponent implements OnInit, OnDestroy {
const viewContainerRef = this.adHost.viewContainerRef;
viewContainerRef.clear();
const componentRef = viewContainerRef.createComponent(componentFactory);
(<AdComponent>componentRef.instance).data = adItem.data;
const componentRef = viewContainerRef.createComponent<AdComponent>(componentFactory);
componentRef.instance.data = adItem.data;
}
getAds() {

View File

@ -1,8 +1,9 @@
// tslint:disable: directive-selector
// #docregion
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[ad-host]',
selector: '[adHost]',
})
export class AdDirective {
constructor(public viewContainerRef: ViewContainerRef) { }

View File

@ -1,9 +1,9 @@
// #docregion
import { Injectable } from '@angular/core';
import { Injectable } from '@angular/core';
import { HeroJobAdComponent } from './hero-job-ad.component';
import { HeroJobAdComponent } from './hero-job-ad.component';
import { HeroProfileComponent } from './hero-profile.component';
import { AdItem } from './ad-item';
import { AdItem } from './ad-item';
@Injectable()
export class AdService {

View File

@ -1,8 +1,8 @@
// #docregion
import { Component, OnInit } from '@angular/core';
import { AdService } from './ad.service';
import { AdItem } from './ad-item';
import { AdService } from './ad.service';
import { AdItem } from './ad-item';
@Component({
selector: 'app-root',

View File

@ -1,12 +1,12 @@
// #docregion
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HeroJobAdComponent } from './hero-job-ad.component';
import { AdBannerComponent } from './ad-banner.component';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HeroJobAdComponent } from './hero-job-ad.component';
import { AdBannerComponent } from './ad-banner.component';
import { HeroProfileComponent } from './hero-profile.component';
import { AdDirective } from './ad.directive';
import { AdService } from './ad.service';
import { AdDirective } from './ad.directive';
import { AdService } from './ad.service';
@NgModule({
imports: [ BrowserModule ],

View File

@ -1,7 +1,7 @@
// #docregion
import { Component, Input } from '@angular/core';
import { AdComponent } from './ad.component';
import { AdComponent } from './ad.component';
@Component({
template: `

View File

@ -1,7 +1,7 @@
// #docregion
import { Component, Input } from '@angular/core';
import { Component, Input } from '@angular/core';
import { AdComponent } from './ad.component';
import { AdComponent } from './ad.component';
@Component({
template: `

View File

@ -1,27 +1,25 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
/* tslint:disable:quotemark */
describe('Dynamic Form', function () {
describe('Dynamic Form', () => {
beforeAll(function () {
beforeAll(() => {
browser.get('');
});
it('should submit form', function () {
let firstNameElement = element.all(by.css('input[id=firstName]')).get(0);
it('should submit form', () => {
const firstNameElement = element.all(by.css('input[id=firstName]')).get(0);
expect(firstNameElement.getAttribute('value')).toEqual('Bombasto');
let emailElement = element.all(by.css('input[id=emailAddress]')).get(0);
let email = 'test@test.com';
const emailElement = element.all(by.css('input[id=emailAddress]')).get(0);
const email = 'test@test.com';
emailElement.sendKeys(email);
expect(emailElement.getAttribute('value')).toEqual(email);
element(by.css('select option[value="solid"]')).click();
let saveButton = element.all(by.css('button')).get(0);
saveButton.click().then(function() {
const saveButton = element.all(by.css('button')).get(0);
saveButton.click().then(() => {
expect(element(by.xpath("//strong[contains(text(),'Saved the following values')]")).isPresent()).toBe(true);
});
});

View File

@ -1,9 +1,9 @@
// #docregion
import { Component } from '@angular/core';
import { Component } from '@angular/core';
import { QuestionService } from './question.service';
import { QuestionBase } from './question-base';
import { Observable } from 'rxjs';
import { QuestionBase } from './question-base';
import { Observable } from 'rxjs';
@Component({
selector: 'app-root',

View File

@ -1,10 +1,10 @@
// #docregion
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { DynamicFormComponent } from './dynamic-form.component';
import { AppComponent } from './app.component';
import { DynamicFormComponent } from './dynamic-form.component';
import { DynamicFormQuestionComponent } from './dynamic-form-question.component';
@NgModule({

View File

@ -1,8 +1,8 @@
// #docregion
import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormGroup } from '@angular/forms';
import { QuestionBase } from './question-base';
import { QuestionBase } from './question-base';
@Component({
selector: 'app-question',

View File

@ -1,9 +1,9 @@
// #docregion
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { QuestionBase } from './question-base';
import { QuestionControlService } from './question-control.service';
import { QuestionBase } from './question-base';
import { QuestionControlService } from './question-control.service';
@Component({
selector: 'app-dynamic-form',

View File

@ -10,13 +10,14 @@ export class QuestionBase<T> {
options: {key: string, value: string}[];
constructor(options: {
value?: T,
key?: string,
label?: string,
required?: boolean,
order?: number,
controlType?: string,
type?: string
value?: T;
key?: string;
label?: string;
required?: boolean;
order?: number;
controlType?: string;
type?: string;
options?: {key: string, value: string}[];
} = {}) {
this.value = options.value;
this.key = options.key || '';
@ -25,5 +26,6 @@ export class QuestionBase<T> {
this.order = options.order === undefined ? 1 : options.order;
this.controlType = options.controlType || '';
this.type = options.type || '';
this.options = options.options || [];
}
}

View File

@ -1,5 +1,5 @@
// #docregion
import { Injectable } from '@angular/core';
import { Injectable } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { QuestionBase } from './question-base';
@ -9,7 +9,7 @@ export class QuestionControlService {
constructor() { }
toFormGroup(questions: QuestionBase<string>[] ) {
let group: any = {};
const group: any = {};
questions.forEach(question => {
group[question.key] = question.required ? new FormControl(question.value || '', Validators.required)

View File

@ -3,10 +3,4 @@ import { QuestionBase } from './question-base';
export class DropdownQuestion extends QuestionBase<string> {
controlType = 'dropdown';
options: {key: string, value: string}[] = [];
constructor(options: {} = {}) {
super(options);
this.options = options['options'] || [];
}
}

View File

@ -3,10 +3,4 @@ import { QuestionBase } from './question-base';
export class TextboxQuestion extends QuestionBase<string> {
controlType = 'textbox';
type: string;
constructor(options: {} = {}) {
super(options);
this.type = options['type'] || '';
}
}

View File

@ -1,9 +1,9 @@
// #docregion
import { Injectable } from '@angular/core';
import { Injectable } from '@angular/core';
import { DropdownQuestion } from './question-dropdown';
import { QuestionBase } from './question-base';
import { TextboxQuestion } from './question-textbox';
import { QuestionBase } from './question-base';
import { TextboxQuestion } from './question-textbox';
import { of } from 'rxjs';
@Injectable()
@ -12,7 +12,7 @@ export class QuestionService {
// TODO: get from a remote source of question metadata
getQuestions() {
let questions: QuestionBase<string>[] = [
const questions: QuestionBase<string>[] = [
new DropdownQuestion({
key: 'brave',

View File

@ -1,5 +1,3 @@
'use strict'; // necessary for es6 output in node
import { browser, by, element, ElementFinder, ExpectedConditions as EC } from 'protractor';
/* tslint:disable:quotemark */
@ -16,7 +14,7 @@ describe('Elements', () => {
const waitForText = (elem: ElementFinder) => {
// Waiting for the element to have some text, makes the tests less flaky.
browser.wait(async () => /\S/.test(await elem.getText()), 5000);
}
};
beforeEach(() => browser.get(''));

View File

@ -1,4 +1,6 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
// tslint:disable: variable-name
// #docregion
import { Component, EventEmitter, HostBinding, Input, Output } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
@Component({
@ -7,9 +9,6 @@ import { animate, state, style, transition, trigger } from '@angular/animations'
<span>Popup: {{message}}</span>
<button (click)="closed.next()">&#x2716;</button>
`,
host: {
'[@state]': 'state',
},
animations: [
trigger('state', [
state('opened', style({transform: 'translateY(0%)'})),
@ -39,15 +38,16 @@ import { animate, state, style, transition, trigger } from '@angular/animations'
`]
})
export class PopupComponent {
@HostBinding('@state')
state: 'opened' | 'closed' = 'closed';
@Input()
get message(): string { return this._message; }
set message(message: string) {
this._message = message;
this.state = 'opened';
}
get message(): string { return this._message; }
_message: string;
private _message: string;
@Output()
closed = new EventEmitter();

Some files were not shown because too many files have changed in this diff Show More