Compare commits
116 Commits
Author | SHA1 | Date | |
---|---|---|---|
7d8dce11c0 | |||
91689193bf | |||
d06636848e | |||
4e263eb391 | |||
3c684d93c8 | |||
81db6a3171 | |||
8224e65e70 | |||
9e50cef507 | |||
66d8c223a9 | |||
814b43647d | |||
6b98567b6b | |||
7f2a3e4b6b | |||
1775f351d6 | |||
1df52d9acd | |||
77e8db4484 | |||
c90262e619 | |||
87bbf69ce8 | |||
552853648c | |||
07b99f5975 | |||
57d1a483fc | |||
d662a6449e | |||
e57a2b3c47 | |||
a3f3082bf0 | |||
0570c240e4 | |||
398118f708 | |||
dcc3f6d74d | |||
0af95332e9 | |||
f9a76a7d06 | |||
832a54ee42 | |||
e8f4294e7f | |||
ce448f4341 | |||
847eaa0fa3 | |||
3e80f0e526 | |||
f3dd6c224c | |||
863acb6c21 | |||
989e8a1f99 | |||
84d1ba792b | |||
b32126c335 | |||
d5e09f4d62 | |||
c25c57c3a3 | |||
692e34d4a2 | |||
071348eb72 | |||
8803f9f4dc | |||
aa816d3887 | |||
a5ba40a78b | |||
cb83b8a887 | |||
8bb726e899 | |||
88662a540d | |||
9b32a5917c | |||
ffd1691ba9 | |||
afd4417a7b | |||
2f53bbba20 | |||
a4f99f4de9 | |||
0711128d28 | |||
25f79ba73e | |||
2590a9b535 | |||
f68a1d3708 | |||
89f7f63e18 | |||
ca2b4bcd4b | |||
f6cfc9294b | |||
5b87c67aed | |||
f5b9d87913 | |||
3acebdcf5d | |||
02aca135bd | |||
32109dc414 | |||
c9acb7b7e2 | |||
545444d86f | |||
7f111491a8 | |||
ee5123f5dc | |||
3dfaf56fdd | |||
432a688edf | |||
42a649d80f | |||
47fbfb37bf | |||
4107abba2d | |||
1d26bc544e | |||
ef7b70a375 | |||
deb290bc2c | |||
5c8b7d2c64 | |||
f5d5bac076 | |||
ad16e2f97a | |||
d0191a7397 | |||
016a41b14d | |||
7a527b4f95 | |||
fd28f0c219 | |||
7342b1ecdf | |||
58f4b3ad80 | |||
3974312c3a | |||
db897f4f7a | |||
77093c21b7 | |||
415131413d | |||
df01a82fa2 | |||
1912fa34ba | |||
db5e1de07a | |||
84661eac64 | |||
629203f17a | |||
2ab8e88924 | |||
a91dd2e42a | |||
6eca80b4aa | |||
cea46786a2 | |||
9c5fc1693a | |||
42f5770b7b | |||
01db37435f | |||
07a003352d | |||
ac009d293d | |||
eb8f8c93c8 | |||
18a5117d1e | |||
ff72da60d3 | |||
d4a723a464 | |||
9c2f0b8ac4 | |||
dc081fb0bf | |||
f882099f9d | |||
24498eb416 | |||
4c2cdc682b | |||
1cb66bb39f | |||
7ff5ef27c7 | |||
03d8e317c4 |
9
.bazelrc
9
.bazelrc
@ -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.
|
||||
|
@ -32,8 +32,8 @@ var_4_win: &cache_key_win_fallback v7-angular-win-node-12-{{ checksum ".bazelver
|
||||
|
||||
# Cache key for the `components-repo-unit-tests` job. **Note** when updating the SHA in the
|
||||
# cache keys also update the SHA for the "COMPONENTS_REPO_COMMIT" environment variable.
|
||||
var_5: &components_repo_unit_tests_cache_key v7-angular-components-f428c00465dfcf8a020237f22532480eedbd2cb6
|
||||
var_6: &components_repo_unit_tests_cache_key_fallback v7-angular-components-
|
||||
var_5: &components_repo_unit_tests_cache_key v9-angular-components-09e68db8ed5b1253f2fe38ff954ef0df019fc25a
|
||||
var_6: &components_repo_unit_tests_cache_key_fallback v9-angular-components-
|
||||
|
||||
# Workspace initially persisted by the `setup` job, and then enhanced by `build-npm-packages` and
|
||||
# `build-ivy-npm-packages`.
|
||||
@ -656,6 +656,18 @@ jobs:
|
||||
- run: yarn tsc -p packages
|
||||
- run: yarn tsc -p modules
|
||||
- run: yarn bazel build //packages/zone.js:npm_package
|
||||
# Build test fixtures for a test that rely on Bazel-generated fixtures. Note that disabling
|
||||
# specific tests which are reliant on such generated fixtures is not an option as SystemJS
|
||||
# in the Saucelabs legacy job always fetches referenced files, even if the imports would be
|
||||
# guarded by an check to skip in the Saucelabs legacy job. We should be good running such
|
||||
# test in all supported browsers on Saucelabs anyway until this job can be removed.
|
||||
- run:
|
||||
name: Preparing Bazel-generated fixtures required in legacy tests
|
||||
command: |
|
||||
yarn bazel build //packages/core/test:downleveled_es5_fixture
|
||||
# Needed for the ES5 downlevel reflector test in `packages/core/test/reflection`.
|
||||
cp dist/bin/packages/core/test/reflection/es5_downleveled_inheritance_fixture.js \
|
||||
dist/all/@angular/core/test/reflection/es5_downleveled_inheritance_fixture.js
|
||||
- run:
|
||||
# Waiting on ready ensures that we don't run tests too early without Saucelabs not being ready.
|
||||
name: Waiting for Saucelabs tunnel to connect
|
||||
|
@ -74,7 +74,7 @@ setPublicVar COMPONENTS_REPO_TMP_DIR "/tmp/angular-components-repo"
|
||||
setPublicVar COMPONENTS_REPO_URL "https://github.com/angular/components.git"
|
||||
setPublicVar COMPONENTS_REPO_BRANCH "master"
|
||||
# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI `config.yml`.
|
||||
setPublicVar COMPONENTS_REPO_COMMIT "f428c00465dfcf8a020237f22532480eedbd2cb6"
|
||||
setPublicVar COMPONENTS_REPO_COMMIT "09e68db8ed5b1253f2fe38ff954ef0df019fc25a"
|
||||
|
||||
|
||||
####################################################################################################
|
||||
|
@ -7,18 +7,6 @@ export const commitMessage: CommitMessageConfig = {
|
||||
maxLineLength: 120,
|
||||
minBodyLength: 20,
|
||||
minBodyLengthTypeExcludes: ['docs'],
|
||||
types: [
|
||||
'build',
|
||||
'ci',
|
||||
'docs',
|
||||
'feat',
|
||||
'fix',
|
||||
'perf',
|
||||
'refactor',
|
||||
'release',
|
||||
'style',
|
||||
'test',
|
||||
],
|
||||
scopes: [
|
||||
'animations',
|
||||
'bazel',
|
||||
|
@ -505,8 +505,8 @@ groups:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'packages/core/src/i18n/**',
|
||||
'packages/core/src/render3/i18n.ts',
|
||||
'packages/core/src/render3/i18n.md',
|
||||
'packages/core/src/render3/i18n/**',
|
||||
'packages/core/src/render3/instructions/i18n.ts',
|
||||
'packages/core/src/render3/interfaces/i18n.ts',
|
||||
'packages/common/locales/**',
|
||||
'packages/common/src/i18n/**',
|
||||
@ -863,6 +863,7 @@ groups:
|
||||
- *can-be-global-docs-approved
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'aio/content/guide/roadmap.md',
|
||||
'aio/content/marketing/**',
|
||||
'aio/content/images/bios/**',
|
||||
'aio/content/images/marketing/**',
|
||||
|
81
CHANGELOG.md
81
CHANGELOG.md
@ -1,3 +1,84 @@
|
||||
<a name="10.0.14"></a>
|
||||
## 10.0.14 (2020-08-26)
|
||||
|
||||
|
||||
|
||||
<a name="10.0.12"></a>
|
||||
## 10.0.12 (2020-08-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler-cli:** adding references to const enums in runtime code ([#38542](https://github.com/angular/angular/issues/38542)) ([814b436](https://github.com/angular/angular/commit/814b436)), closes [#38513](https://github.com/angular/angular/issues/38513)
|
||||
* **core:** remove closing body tag from inert DOM builder ([#38454](https://github.com/angular/angular/issues/38454)) ([5528536](https://github.com/angular/angular/commit/5528536))
|
||||
* **localize:** include the last placeholder in parsed translation text ([#38452](https://github.com/angular/angular/issues/38452)) ([57d1a48](https://github.com/angular/angular/commit/57d1a48))
|
||||
* **localize:** parse all parts of a translation with nested HTML ([#38452](https://github.com/angular/angular/issues/38452)) ([07b99f5](https://github.com/angular/angular/commit/07b99f5)), closes [#38422](https://github.com/angular/angular/issues/38422)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **language-service:** introduce hybrid visitor to locate AST node ([#38540](https://github.com/angular/angular/issues/38540)) ([66d8c22](https://github.com/angular/angular/commit/66d8c22))
|
||||
|
||||
|
||||
|
||||
<a name="10.0.11"></a>
|
||||
## 10.0.11 (2020-08-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **router:** ensure routerLinkActive updates when associated routerLinks change (resubmit of [#38349](https://github.com/angular/angular/issues/38349)) ([#38511](https://github.com/angular/angular/issues/38511)) ([0af9533](https://github.com/angular/angular/commit/0af9533)), closes [#18469](https://github.com/angular/angular/issues/18469)
|
||||
|
||||
|
||||
|
||||
<a name="10.0.10"></a>
|
||||
## 10.0.10 (2020-08-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **common:** Allow scrolling when browser supports scrollTo ([#38468](https://github.com/angular/angular/issues/38468)) ([b32126c](https://github.com/angular/angular/commit/b32126c)), closes [#30630](https://github.com/angular/angular/issues/30630)
|
||||
* **core:** detect DI parameters in JIT mode for downleveled ES2015 classes ([#38500](https://github.com/angular/angular/issues/38500)) ([863acb6](https://github.com/angular/angular/commit/863acb6)), closes [#38453](https://github.com/angular/angular/issues/38453)
|
||||
* **core:** error if CSS custom property in host binding has number in name ([#38432](https://github.com/angular/angular/issues/38432)) ([cb83b8a](https://github.com/angular/angular/commit/cb83b8a)), closes [#37292](https://github.com/angular/angular/issues/37292)
|
||||
* **core:** fix multiple nested views removal from ViewContainerRef ([#38317](https://github.com/angular/angular/issues/38317)) ([d5e09f4](https://github.com/angular/angular/commit/d5e09f4)), closes [#38201](https://github.com/angular/angular/issues/38201)
|
||||
* **ngcc:** detect synthesized delegate constructors for downleveled ES2015 classes ([#38500](https://github.com/angular/angular/issues/38500)) ([f3dd6c2](https://github.com/angular/angular/commit/f3dd6c2)), closes [#38453](https://github.com/angular/angular/issues/38453) [#38453](https://github.com/angular/angular/issues/38453)
|
||||
* **router:** ensure routerLinkActive updates when associated routerLinks change ([#38349](https://github.com/angular/angular/issues/38349)) ([989e8a1](https://github.com/angular/angular/commit/989e8a1)), closes [#18469](https://github.com/angular/angular/issues/18469)
|
||||
|
||||
|
||||
|
||||
<a name="10.0.9"></a>
|
||||
## 10.0.9 (2020-08-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **common:** ensure scrollRestoration is writable ([#30630](https://github.com/angular/angular/issues/30630)) ([#38357](https://github.com/angular/angular/issues/38357)) ([58f4b3a](https://github.com/angular/angular/commit/58f4b3a)), closes [#30629](https://github.com/angular/angular/issues/30629)
|
||||
* **compiler:** evaluate safe navigation expressions in correct binding order ([#37911](https://github.com/angular/angular/issues/37911)) ([f5b9d87](https://github.com/angular/angular/commit/f5b9d87)), closes [#37194](https://github.com/angular/angular/issues/37194)
|
||||
* **compiler-cli:** avoid creating value expressions for symbols from type-only imports ([#38415](https://github.com/angular/angular/issues/38415)) ([ca2b4bc](https://github.com/angular/angular/commit/ca2b4bc)), closes [#37912](https://github.com/angular/angular/issues/37912)
|
||||
* **compiler-cli:** infer quote expressions as any type in type checker ([#37917](https://github.com/angular/angular/issues/37917)) ([5b87c67](https://github.com/angular/angular/commit/5b87c67)), closes [#36568](https://github.com/angular/angular/issues/36568)
|
||||
* **compiler-cli:** mark eager `NgModuleFactory` construction as not side effectful ([#38320](https://github.com/angular/angular/issues/38320)) ([016a41b](https://github.com/angular/angular/commit/016a41b)), closes [#38147](https://github.com/angular/angular/issues/38147)
|
||||
* **compiler-cli:** match wrapHost parameter types within plugin interface ([#38004](https://github.com/angular/angular/issues/38004)) ([df01a82](https://github.com/angular/angular/commit/df01a82))
|
||||
* **compiler-cli:** preserve quotes in class member names ([#38387](https://github.com/angular/angular/issues/38387)) ([c9acb7b](https://github.com/angular/angular/commit/c9acb7b)), closes [#38311](https://github.com/angular/angular/issues/38311)
|
||||
* **core:** prevent NgModule scope being overwritten in JIT compiler ([#37795](https://github.com/angular/angular/issues/37795)) ([3acebdc](https://github.com/angular/angular/commit/3acebdc)), closes [#37105](https://github.com/angular/angular/issues/37105)
|
||||
* **core:** queries not matching string injection tokens ([#38321](https://github.com/angular/angular/issues/38321)) ([32109dc](https://github.com/angular/angular/commit/32109dc)), closes [#38313](https://github.com/angular/angular/issues/38313) [#38315](https://github.com/angular/angular/issues/38315)
|
||||
* **core:** Store the currently selected ICU in `LView` ([#38345](https://github.com/angular/angular/issues/38345)) ([ee5123f](https://github.com/angular/angular/commit/ee5123f))
|
||||
* **platform-server:** remove styles added by ServerStylesHost on destruction ([#38367](https://github.com/angular/angular/issues/38367)) ([7f11149](https://github.com/angular/angular/commit/7f11149))
|
||||
* **router:** prevent calling unsubscribe on undefined subscription in RouterPreloader ([#38344](https://github.com/angular/angular/issues/38344)) ([4151314](https://github.com/angular/angular/commit/4151314))
|
||||
* **service-worker:** fix the chrome debugger syntax highlighter ([#38332](https://github.com/angular/angular/issues/38332)) ([f5d5bac](https://github.com/angular/angular/commit/f5d5bac))
|
||||
|
||||
|
||||
|
||||
<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)
|
||||
|
||||
|
@ -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');
|
||||
|
@ -1,3 +1,4 @@
|
||||
// tslint:disable: no-host-metadata-property
|
||||
// #docregion progressbar-component
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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 ],
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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';
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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(' ')),
|
||||
};
|
||||
}
|
||||
|
@ -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: [
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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({
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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');
|
||||
});
|
||||
|
@ -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';
|
||||
}
|
||||
|
@ -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', () => {
|
||||
|
@ -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';
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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');
|
||||
|
@ -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; }
|
||||
|
||||
}
|
||||
|
||||
|
@ -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( )');
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
// ...
|
||||
|
@ -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 { }
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
// #docregion
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class MissionService {
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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}`);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-vote-taker',
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
const routes: Routes = [];
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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 ],
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* tslint:disable:one-line*/
|
||||
// #docregion
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { LoggerService } from './logger.service';
|
||||
|
||||
|
@ -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({
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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({
|
||||
|
@ -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'),
|
||||
|
@ -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({
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
// #docregion
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Hero } from './hero';
|
||||
import { Hero } from './hero';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -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) };
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
@ -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({
|
||||
|
@ -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';
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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',
|
||||
|
@ -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';
|
||||
/*
|
||||
|
@ -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({
|
||||
|
@ -1,6 +1,6 @@
|
||||
// #docregion
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HEROES } from './mock-heroes';
|
||||
import { HEROES } from './mock-heroes';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { heroServiceProvider } from './hero.service.provider';
|
||||
|
||||
@Component({
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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}.`};
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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!');
|
||||
});
|
||||
});
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
@ -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({
|
||||
|
@ -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();
|
||||
|
@ -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() {
|
||||
|
@ -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) { }
|
||||
|
@ -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 {
|
||||
|
@ -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',
|
||||
|
@ -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 ],
|
||||
|
@ -1,7 +1,7 @@
|
||||
// #docregion
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
import { AdComponent } from './ad.component';
|
||||
import { AdComponent } from './ad.component';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
|
@ -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: `
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
@ -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',
|
||||
|
@ -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({
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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 || [];
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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'] || [];
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user