Compare commits
268 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
1de4fe5dbf | |||
879ff08f0e | |||
a15d7ac1da | |||
4a6abbdfc6 | |||
78eb5f6777 | |||
0cdb5231c2 | |||
5af845d049 | |||
a5c28497b5 | |||
801ad62ae3 | |||
7d4d2e29b0 | |||
c33f719ddc | |||
69fc6b4f75 | |||
5ec4c02a43 | |||
f0489ee72a | |||
d0f625305b | |||
c15a58fa2b | |||
3d67d1970b | |||
ce08a3c8c7 | |||
bc29712271 | |||
cc48b5c066 | |||
deba0e21f1 | |||
0469d9240a | |||
cdda60a430 | |||
7570356bfa | |||
c4a97d822e | |||
fc4dfc5eb1 | |||
25d95dae6d | |||
1c4fcce2a1 | |||
6e73faaed7 | |||
41c9910613 | |||
aaddef213d | |||
02f3aee1db | |||
c27ba96093 | |||
c5a474cb54 | |||
d5264f5645 | |||
0cd4b87021 | |||
b1e7775a8a | |||
87f5feff11 | |||
c3ddc3d6b1 | |||
cec39a7d16 | |||
c6c8e15813 | |||
752fd14fe5 | |||
776067cd43 | |||
e87a46be21 | |||
89a7ff3ada | |||
3d6e50dc02 | |||
264950bbf2 | |||
84c5be0b5b | |||
eda8f2f8b9 | |||
cc52945d00 | |||
07f184a69d | |||
a123ef58b1 | |||
024126dde4 | |||
4275c34818 | |||
c4e6f585c5 | |||
7467fd36b9 | |||
aca01985fd | |||
eb5e14e6e0 | |||
b8af10902f | |||
f411c9e5b9 | |||
7f455e6eec | |||
e36caafa52 | |||
5e89d98876 | |||
200dbd4860 | |||
c90952884a | |||
7c2d8fc672 | |||
a50a688aaf | |||
6ec7297e43 | |||
f264cd1cb8 | |||
fc17bddcde | |||
0765626761 | |||
f146b34042 | |||
f899d6ea44 | |||
c18d7a1469 | |||
2c7ff82f31 | |||
3f8f3a2daa | |||
f5eeb1a714 | |||
2af3d9c040 | |||
4664acce50 | |||
3797861dfe | |||
d6d3984524 | |||
c17f5c10cc | |||
9cb318f5a2 | |||
b026dd8b52 | |||
0ebc316311 | |||
dc412c5f02 | |||
e80278cf02 | |||
307699ac89 | |||
4df0b7e9de | |||
371831f9cb | |||
8e305e7099 | |||
481df830ad | |||
14b4718cc2 | |||
7b6e73cb98 | |||
f2ca4634e2 | |||
d30cf2f9d6 | |||
e9cb6fbe87 | |||
99960a98d2 | |||
9ac3383d01 | |||
06ac75724f | |||
a1d691ecc8 | |||
6e329721be | |||
739bf5c325 | |||
ee340b7c6c | |||
17ddab98fb | |||
4f65f473e4 | |||
527a04d21e | |||
f2ee468d76 | |||
0320096538 | |||
7abb48adfe | |||
b40d3c0817 | |||
0e5617152a | |||
dba402344f | |||
13d176302b | |||
e3b801053a | |||
6626739798 | |||
396033da80 | |||
02ee9d2938 | |||
a4c7f183d7 | |||
d690eec88f | |||
10e4dfae27 | |||
f8d948b46b | |||
9cf78d5701 | |||
45471dbbd6 | |||
387e8386d1 | |||
eec6e4be7a | |||
b711f25892 | |||
788f0453f7 | |||
45b1775a53 | |||
53e4ff72d2 | |||
7813a7d129 | |||
c0ced6dc2d | |||
8157ee87b0 | |||
ab051aba27 | |||
5a61ef0c49 | |||
c451dbda9f | |||
0d38288078 | |||
2e9b953e9d | |||
a94383f168 | |||
75c40ddd61 | |||
86a75a0670 | |||
c776825fdd | |||
1cc9383d91 | |||
8ed1e53e99 | |||
7833c88ac4 | |||
12f177399f | |||
5be32366be | |||
5b7d2eeabf | |||
6cd10a1b10 | |||
822652aa0d | |||
cf47ace493 | |||
0595f11950 | |||
35df312ea4 | |||
489eb8519e | |||
b76a2dc2cb | |||
f2f5f7fc6e | |||
8ee23ba67b | |||
ecb422b360 | |||
60389d5441 | |||
b186db70db | |||
324b6f1b1a | |||
cdba1d37a4 | |||
dc42c97ee4 | |||
bc00e8d312 | |||
720b71d01f | |||
1132b07c53 | |||
9230194794 | |||
d724896f04 | |||
29866dfb91 | |||
a249622159 | |||
9f2393fb80 | |||
d5f8040d0a | |||
e0b8ea136b | |||
879b2273c1 |
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.
|
# retry mechanism and we do not want to retry unnecessarily if Karma already tried multiple times.
|
||||||
test:saucelabs --flaky_test_attempts=1
|
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
|
# User bazel configuration
|
||||||
# NOTE: This needs to be the *last* entry in the config.
|
# 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 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.
|
# cache keys also update the SHA for the "COMPONENTS_REPO_COMMIT" environment variable.
|
||||||
var_5: &components_repo_unit_tests_cache_key v7-angular-components-189d98e8b01b33974328255f085de04251d61567
|
var_5: &components_repo_unit_tests_cache_key v9-angular-components-09e68db8ed5b1253f2fe38ff954ef0df019fc25a
|
||||||
var_6: &components_repo_unit_tests_cache_key_fallback v7-angular-components-
|
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
|
# Workspace initially persisted by the `setup` job, and then enhanced by `build-npm-packages` and
|
||||||
# `build-ivy-npm-packages`.
|
# `build-ivy-npm-packages`.
|
||||||
@ -656,6 +656,18 @@ jobs:
|
|||||||
- run: yarn tsc -p packages
|
- run: yarn tsc -p packages
|
||||||
- run: yarn tsc -p modules
|
- run: yarn tsc -p modules
|
||||||
- run: yarn bazel build //packages/zone.js:npm_package
|
- 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:
|
- run:
|
||||||
# Waiting on ready ensures that we don't run tests too early without Saucelabs not being ready.
|
# Waiting on ready ensures that we don't run tests too early without Saucelabs not being ready.
|
||||||
name: Waiting for Saucelabs tunnel to connect
|
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_URL "https://github.com/angular/components.git"
|
||||||
setPublicVar COMPONENTS_REPO_BRANCH "master"
|
setPublicVar COMPONENTS_REPO_BRANCH "master"
|
||||||
# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI `config.yml`.
|
# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI `config.yml`.
|
||||||
setPublicVar COMPONENTS_REPO_COMMIT "189d98e8b01b33974328255f085de04251d61567"
|
setPublicVar COMPONENTS_REPO_COMMIT "09e68db8ed5b1253f2fe38ff954ef0df019fc25a"
|
||||||
|
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
6
.github/angular-robot.yml
vendored
6
.github/angular-robot.yml
vendored
@ -154,6 +154,12 @@ triage:
|
|||||||
-
|
-
|
||||||
- "type: RFC / Discussion / question"
|
- "type: RFC / Discussion / question"
|
||||||
- "comp: *"
|
- "comp: *"
|
||||||
|
-
|
||||||
|
- "type: confusing"
|
||||||
|
- "comp: *"
|
||||||
|
-
|
||||||
|
- "type: use-case"
|
||||||
|
- "comp: *"
|
||||||
|
|
||||||
# options for the triage PR plugin
|
# options for the triage PR plugin
|
||||||
triagePR:
|
triagePR:
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -42,3 +42,6 @@ yarn-error.log
|
|||||||
|
|
||||||
.notes.md
|
.notes.md
|
||||||
baseline.json
|
baseline.json
|
||||||
|
|
||||||
|
# Ignore .history for the xyz.local-history VSCode extension
|
||||||
|
.history
|
||||||
|
145
.gitmessage
Normal file
145
.gitmessage
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
<type>(<scope>): <summary>
|
||||||
|
|
||||||
|
<Describe the motivation behind this change - explain WHY you are making this change. Wrap all lines
|
||||||
|
at 100 characters.>
|
||||||
|
|
||||||
|
Fixes #<issue number>
|
||||||
|
|
||||||
|
# ────────────────────────────────────────── 100 chars ────────────────────────────────────────────┤
|
||||||
|
|
||||||
|
|
||||||
|
# Example Commit Messages
|
||||||
|
# =======================
|
||||||
|
|
||||||
|
|
||||||
|
# ─── Example: Simple refactor ────────────────────────────────────────────────────────────────────┤
|
||||||
|
# refactor(core): rename refreshDynamicEmbeddedViews to refreshEmbeddedViews
|
||||||
|
#
|
||||||
|
# Improve code readability. The original name no longer matches how the function is used.
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
|
||||||
|
|
||||||
|
# ─── Example: Simple docs change ─────────────────────────────────────────────────────────────────┤
|
||||||
|
# docs: clarify the service limitation in providers.md guide
|
||||||
|
#
|
||||||
|
# Fixes #36332
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
|
||||||
|
|
||||||
|
# ─── Example: A bug fix ──────────────────────────────────────────────────────────────────────────┤
|
||||||
|
# fix(ngcc): ensure lockfile is removed when `analyzeFn` fails
|
||||||
|
#
|
||||||
|
# Previously an error thrown in the `analyzeFn` would cause the ngcc process to exit immediately
|
||||||
|
# without removing the lockfile, and potentially before the unlocker process had been successfully
|
||||||
|
# spawned resulting in the lockfile being orphaned and left behind.
|
||||||
|
#
|
||||||
|
# Now we catch these errors and remove the lockfile as needed.
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
|
||||||
|
|
||||||
|
# ─── Example: Breaking change ────────────────────────────────────────────────────────────────────┤
|
||||||
|
# feat(bazel): simplify ng_package by dropping esm5 and fesm5
|
||||||
|
#
|
||||||
|
# esm5 and fesm5 distributions are no longer needed and have been deprecated in the past.
|
||||||
|
#
|
||||||
|
# https://v9.angular.io/guide/deprecations#esm5-and-fesm5-code-formats-in-angular-npm-packages
|
||||||
|
#
|
||||||
|
# This commit modifies ng_package to no longer distribute these two formats in npm packages built by
|
||||||
|
# ng_package (e.g. @angular/core).
|
||||||
|
#
|
||||||
|
# This commit intentionally doesn't fully clean up the ng_package rule to remove all traces of esm5
|
||||||
|
# and fems5 build artifacts as that is a bigger cleanup and currently we are narrowing down the
|
||||||
|
# scope of this change to the MVP needed for v10, which in this case is 'do not put esm5 and fesm5'
|
||||||
|
# into the npm packages.
|
||||||
|
#
|
||||||
|
# More cleanup to follow: https://angular-team.atlassian.net/browse/FW-2143
|
||||||
|
#
|
||||||
|
# BREAKING CHANGE: esm5 and fesm5 format is no longer distributed in Angular's npm packages e.g.
|
||||||
|
# @angular/core
|
||||||
|
#
|
||||||
|
# Angular CLI will automatically downlevel the code to es5 if differential loading is enabled in the
|
||||||
|
# Angular project, so no action is required from Angular CLI users.
|
||||||
|
#
|
||||||
|
# If you are not using Angular CLI to build your application or library, and you need to be able to
|
||||||
|
# build es5 artifacts, then you will need to downlevel the distributed Angular code to es5 on your
|
||||||
|
# own.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Fixes #1234
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Angular Commit Message Format
|
||||||
|
# =============================
|
||||||
|
#
|
||||||
|
# The full specification of the Angular Commit Message Format can be found at
|
||||||
|
# https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit
|
||||||
|
#
|
||||||
|
# The following is an excerpt of the specification with the most commonly needed info.
|
||||||
|
#
|
||||||
|
# Each commit message consists of a *header*, a *body*, and a *footer*.
|
||||||
|
#
|
||||||
|
# <header>
|
||||||
|
# <BLANK LINE>
|
||||||
|
# <body>
|
||||||
|
# <BLANK LINE>
|
||||||
|
# <footer>
|
||||||
|
#
|
||||||
|
# The header is mandatory.
|
||||||
|
#
|
||||||
|
# The body is mandatory for all commits except for those of scope "docs". When the body is required
|
||||||
|
# it must be at least 20 characters long.
|
||||||
|
#
|
||||||
|
# The footer is optional.
|
||||||
|
#
|
||||||
|
# Any line of the commit message cannot be longer than 100 characters.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Commit Message Header
|
||||||
|
# ---------------------
|
||||||
|
#
|
||||||
|
# <type>(<scope>): <short summary>
|
||||||
|
# │ │ │
|
||||||
|
# │ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
|
||||||
|
# │ │
|
||||||
|
# │ └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
|
||||||
|
# │ elements|forms|http|language-service|localize|platform-browser|
|
||||||
|
# │ platform-browser-dynamic|platform-server|platform-webworker|
|
||||||
|
# │ platform-webworker-dynamic|router|service-worker|upgrade|zone.js|
|
||||||
|
# │ packaging|changelog|dev-infra|docs-infra|migrations|ngcc|ve
|
||||||
|
# │ https://github.com/angular/angular/blob/master/CONTRIBUTING.md#scope
|
||||||
|
# │
|
||||||
|
# └─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|style|test
|
||||||
|
# https://github.com/angular/angular/blob/master/CONTRIBUTING.md#type
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Commit Message Body
|
||||||
|
# ---------------------
|
||||||
|
#
|
||||||
|
# Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
|
||||||
|
#
|
||||||
|
# Explain the motivation for the change in the commit message body. This commit message should
|
||||||
|
# explain WHY you are making the change. You can include a comparison of the previous behavior with
|
||||||
|
# the new behavior in order to illustrate the impact of the change.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Commit Message Footer
|
||||||
|
# ---------------------
|
||||||
|
#
|
||||||
|
# The footer can contain information about breaking changes and is also the place to reference
|
||||||
|
# GitHub issues, Jira tickets, and other PRs that this commit closes or is related to.
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# BREAKING CHANGE: <breaking change summary>
|
||||||
|
# <BLANK LINE>
|
||||||
|
# <breaking change description + migration instructions>
|
||||||
|
# <BLANK LINE>
|
||||||
|
# <BLANK LINE>
|
||||||
|
# Fixes #<issue number>
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# Breaking Change section should start with the phrase "BREAKING CHANGE: " followed by a summary of
|
||||||
|
# the breaking change, a blank line, and a detailed description of the breaking change that also
|
||||||
|
# includes migration instructions.
|
||||||
|
#
|
40
.ng-dev/commit-message.ts
Normal file
40
.ng-dev/commit-message.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import {CommitMessageConfig} from '../dev-infra/commit-message/config';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration for `ng-dev commit-message` commands.
|
||||||
|
*/
|
||||||
|
export const commitMessage: CommitMessageConfig = {
|
||||||
|
maxLineLength: 120,
|
||||||
|
minBodyLength: 20,
|
||||||
|
minBodyLengthTypeExcludes: ['docs'],
|
||||||
|
scopes: [
|
||||||
|
'animations',
|
||||||
|
'bazel',
|
||||||
|
'benchpress',
|
||||||
|
'changelog',
|
||||||
|
'common',
|
||||||
|
'compiler',
|
||||||
|
'compiler-cli',
|
||||||
|
'core',
|
||||||
|
'dev-infra',
|
||||||
|
'docs-infra',
|
||||||
|
'elements',
|
||||||
|
'forms',
|
||||||
|
'http',
|
||||||
|
'language-service',
|
||||||
|
'localize',
|
||||||
|
'migrations',
|
||||||
|
'ngcc',
|
||||||
|
'packaging',
|
||||||
|
'platform-browser',
|
||||||
|
'platform-browser-dynamic',
|
||||||
|
'platform-server',
|
||||||
|
'platform-webworker',
|
||||||
|
'platform-webworker-dynamic',
|
||||||
|
'router',
|
||||||
|
'service-worker',
|
||||||
|
'upgrade',
|
||||||
|
've',
|
||||||
|
'zone.js',
|
||||||
|
]
|
||||||
|
};
|
@ -1,115 +1,8 @@
|
|||||||
import {MergeConfig} from '../dev-infra/pr/merge/config';
|
import {commitMessage} from './commit-message';
|
||||||
|
import {format} from './format';
|
||||||
|
import {github} from './github';
|
||||||
|
import {merge} from './merge';
|
||||||
|
|
||||||
// The configuration for `ng-dev commit-message` commands.
|
|
||||||
const commitMessage = {
|
|
||||||
'maxLength': 120,
|
|
||||||
'minBodyLength': 100,
|
|
||||||
'minBodyLengthTypeExcludes': ['docs'],
|
|
||||||
'types': [
|
|
||||||
'build',
|
|
||||||
'ci',
|
|
||||||
'docs',
|
|
||||||
'feat',
|
|
||||||
'fix',
|
|
||||||
'perf',
|
|
||||||
'refactor',
|
|
||||||
'release',
|
|
||||||
'style',
|
|
||||||
'test',
|
|
||||||
],
|
|
||||||
'scopes': [
|
|
||||||
'animations',
|
|
||||||
'bazel',
|
|
||||||
'benchpress',
|
|
||||||
'changelog',
|
|
||||||
'common',
|
|
||||||
'compiler',
|
|
||||||
'compiler-cli',
|
|
||||||
'core',
|
|
||||||
'dev-infra',
|
|
||||||
'docs-infra',
|
|
||||||
'elements',
|
|
||||||
'forms',
|
|
||||||
'http',
|
|
||||||
'language-service',
|
|
||||||
'localize',
|
|
||||||
'migrations',
|
|
||||||
'ngcc',
|
|
||||||
'packaging',
|
|
||||||
'platform-browser',
|
|
||||||
'platform-browser-dynamic',
|
|
||||||
'platform-server',
|
|
||||||
'platform-webworker',
|
|
||||||
'platform-webworker-dynamic',
|
|
||||||
'router',
|
|
||||||
'service-worker',
|
|
||||||
'upgrade',
|
|
||||||
've',
|
|
||||||
'zone.js',
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
// The configuration for `ng-dev format` commands.
|
|
||||||
const format = {
|
|
||||||
'clang-format': {
|
|
||||||
'matchers': [
|
|
||||||
'**/*.{js,ts}',
|
|
||||||
// TODO: burn down format failures and remove aio and integration exceptions.
|
|
||||||
'!aio/**',
|
|
||||||
'!integration/**',
|
|
||||||
// Both third_party and .yarn are directories containing copied code which should
|
|
||||||
// not be modified.
|
|
||||||
'!third_party/**',
|
|
||||||
'!.yarn/**',
|
|
||||||
// Do not format d.ts files as they are generated
|
|
||||||
'!**/*.d.ts',
|
|
||||||
]
|
|
||||||
},
|
|
||||||
'buildifier': true
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Github metadata information for `ng-dev` commands. */
|
|
||||||
const github = {
|
|
||||||
owner: 'angular',
|
|
||||||
name: 'angular',
|
|
||||||
};
|
|
||||||
|
|
||||||
// Configuration for the `ng-dev pr merge` command. The command can be used
|
|
||||||
// for merging upstream pull requests into branches based on a PR target label.
|
|
||||||
const merge = () => {
|
|
||||||
// TODO: resume dynamically determining patch branch
|
|
||||||
const patch = '10.0.x';
|
|
||||||
const config: MergeConfig = {
|
|
||||||
githubApiMerge: false,
|
|
||||||
claSignedLabel: 'cla: yes',
|
|
||||||
mergeReadyLabel: /^PR action: merge(-assistance)?/,
|
|
||||||
commitMessageFixupLabel: 'commit message fixup',
|
|
||||||
labels: [
|
|
||||||
{
|
|
||||||
pattern: 'PR target: master-only',
|
|
||||||
branches: ['master'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: 'PR target: patch-only',
|
|
||||||
branches: [patch],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: 'PR target: master & patch',
|
|
||||||
branches: ['master', patch],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
requiredBaseCommits: {
|
|
||||||
// PRs that target either `master` or the patch branch, need to be rebased
|
|
||||||
// on top of the latest commit message validation fix.
|
|
||||||
// These SHAs are the commits that update the required license text in the header.
|
|
||||||
'master': '5aeb9a4124922d8ac08eb73b8f322905a32b0b3a',
|
|
||||||
[patch]: '27b95ba64a5d99757f4042073fd1860e20e3ed24'
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Export function to build ng-dev configuration object.
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
commitMessage,
|
commitMessage,
|
||||||
format,
|
format,
|
||||||
|
22
.ng-dev/format.ts
Normal file
22
.ng-dev/format.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import {FormatConfig} from '../dev-infra/format/config';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the `ng-dev format` command.
|
||||||
|
*/
|
||||||
|
export const format: FormatConfig = {
|
||||||
|
'clang-format': {
|
||||||
|
'matchers': [
|
||||||
|
'**/*.{js,ts}',
|
||||||
|
// TODO: burn down format failures and remove aio and integration exceptions.
|
||||||
|
'!aio/**',
|
||||||
|
'!integration/**',
|
||||||
|
// Both third_party and .yarn are directories containing copied code which should
|
||||||
|
// not be modified.
|
||||||
|
'!third_party/**',
|
||||||
|
'!.yarn/**',
|
||||||
|
// Do not format d.ts files as they are generated
|
||||||
|
'!**/*.d.ts',
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'buildifier': true
|
||||||
|
};
|
15
.ng-dev/gitconfig
Normal file
15
.ng-dev/gitconfig
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# The file is inert unless it's explicitly included into the local git config via:
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# git config --add include.path '../.ng-dev/gitconfig'
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# Calling that command will append the following into `.git/config` of the current git workspace
|
||||||
|
# (i.e. $GIT_DIR, typically `angular/.git/config`):
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# [include]
|
||||||
|
# path = ../.ng-dev/gitconfig
|
||||||
|
# ```
|
||||||
|
[commit]
|
||||||
|
template = .gitmessage
|
11
.ng-dev/github.ts
Normal file
11
.ng-dev/github.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import {GithubConfig} from '../dev-infra/utils/config';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Github configuration for the `ng-dev` command. This repository is used as
|
||||||
|
* remote for the merge script and other utilities like `ng-dev pr rebase`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const github: GithubConfig = {
|
||||||
|
owner: 'angular',
|
||||||
|
name: 'angular'
|
||||||
|
};
|
38
.ng-dev/merge.ts
Normal file
38
.ng-dev/merge.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import {MergeConfig} from '../dev-infra/pr/merge/config';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the merge tool in `ng-dev`. This sets up the labels which
|
||||||
|
* are respected by the merge script (e.g. the target labels).
|
||||||
|
*/
|
||||||
|
export const merge = (): MergeConfig => {
|
||||||
|
// TODO: resume dynamically determining patch branch
|
||||||
|
const patch = '10.0.x';
|
||||||
|
return {
|
||||||
|
githubApiMerge: false,
|
||||||
|
claSignedLabel: 'cla: yes',
|
||||||
|
mergeReadyLabel: /^PR action: merge(-assistance)?/,
|
||||||
|
caretakerNoteLabel: 'PR action: merge-assistance',
|
||||||
|
commitMessageFixupLabel: 'commit message fixup',
|
||||||
|
labels: [
|
||||||
|
{
|
||||||
|
pattern: 'PR target: master-only',
|
||||||
|
branches: ['master'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: 'PR target: patch-only',
|
||||||
|
branches: [patch],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: 'PR target: master & patch',
|
||||||
|
branches: ['master', patch],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
requiredBaseCommits: {
|
||||||
|
// PRs that target either `master` or the patch branch, need to be rebased
|
||||||
|
// on top of the latest commit message validation fix.
|
||||||
|
// These SHAs are the commits that update the required license text in the header.
|
||||||
|
'master': '5aeb9a4124922d8ac08eb73b8f322905a32b0b3a',
|
||||||
|
[patch]: '27b95ba64a5d99757f4042073fd1860e20e3ed24'
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
102
.pullapprove.yml
102
.pullapprove.yml
@ -67,6 +67,25 @@ version: 3
|
|||||||
# Meta field that goes unused by PullApprove to allow for defining aliases to be
|
# Meta field that goes unused by PullApprove to allow for defining aliases to be
|
||||||
# used throughout the config.
|
# used throughout the config.
|
||||||
meta:
|
meta:
|
||||||
|
# The following groups have no file based conditions and will be initially `active` on all PRs
|
||||||
|
# - `global-approvers`
|
||||||
|
# - `global-docs-approvers`
|
||||||
|
# - `required-minimum-review`
|
||||||
|
#
|
||||||
|
# By checking the number of active/pending/rejected groups when these are excluded, we can determine
|
||||||
|
# if any other groups are matched.
|
||||||
|
#
|
||||||
|
# Note: Because all inactive groups start as pending, we are only checking pending and rejected active groups.
|
||||||
|
#
|
||||||
|
# Also note that the ordering of groups matters in this file. The only groups visible to the current
|
||||||
|
# one are those that appear above it.
|
||||||
|
no-groups-above-this-pending: &no-groups-above-this-pending
|
||||||
|
len(groups.active.pending.exclude("required-minimum-review").exclude("global-approvers").exclude("global-docs-approvers")) == 0
|
||||||
|
no-groups-above-this-rejected: &no-groups-above-this-rejected
|
||||||
|
len(groups.active.rejected.exclude("required-minimum-review").exclude("global-approvers").exclude("global-docs-approvers")) == 0
|
||||||
|
no-groups-above-this-active: &no-groups-above-this-active
|
||||||
|
len(groups.active.exclude("required-minimum-review").exclude("global-approvers").exclude("global-docs-approvers")) == 0
|
||||||
|
|
||||||
can-be-global-approved: &can-be-global-approved "\"global-approvers\" not in groups.approved"
|
can-be-global-approved: &can-be-global-approved "\"global-approvers\" not in groups.approved"
|
||||||
can-be-global-docs-approved: &can-be-global-docs-approved "\"global-docs-approvers\" not in groups.approved"
|
can-be-global-docs-approved: &can-be-global-docs-approved "\"global-docs-approvers\" not in groups.approved"
|
||||||
defaults: &defaults
|
defaults: &defaults
|
||||||
@ -136,7 +155,6 @@ groups:
|
|||||||
- kara # Kara Erickson
|
- kara # Kara Erickson
|
||||||
- kyliau # Keen Yee Liau
|
- kyliau # Keen Yee Liau
|
||||||
- manughub # Manu Murthy
|
- manughub # Manu Murthy
|
||||||
- matsko # Matias Niemela
|
|
||||||
- mgechev # Minko Gechev
|
- mgechev # Minko Gechev
|
||||||
- mhevery # Miško Hevery
|
- mhevery # Miško Hevery
|
||||||
- michaelprentice # Michael Prentice
|
- michaelprentice # Michael Prentice
|
||||||
@ -203,7 +221,9 @@ groups:
|
|||||||
])
|
])
|
||||||
reviewers:
|
reviewers:
|
||||||
users:
|
users:
|
||||||
- matsko
|
- crisbeto
|
||||||
|
- IgorMinar
|
||||||
|
- jelbourn
|
||||||
|
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
@ -342,26 +362,38 @@ groups:
|
|||||||
'aio/content/guide/ngmodule-vs-jsmodule.md',
|
'aio/content/guide/ngmodule-vs-jsmodule.md',
|
||||||
'aio/content/guide/module-types.md',
|
'aio/content/guide/module-types.md',
|
||||||
'aio/content/guide/template-syntax.md',
|
'aio/content/guide/template-syntax.md',
|
||||||
|
'aio/content/guide/built-in-template-functions.md',
|
||||||
'aio/content/examples/built-in-template-functions/**',
|
'aio/content/examples/built-in-template-functions/**',
|
||||||
|
'aio/content/guide/event-binding.md',
|
||||||
'aio/content/examples/event-binding/**',
|
'aio/content/examples/event-binding/**',
|
||||||
|
'aio/content/guide/interpolation.md',
|
||||||
'aio/content/examples/interpolation/**',
|
'aio/content/examples/interpolation/**',
|
||||||
'aio/content/examples/template-syntax/**',
|
'aio/content/examples/template-syntax/**',
|
||||||
'aio/content/images/guide/template-syntax/**',
|
'aio/content/images/guide/template-syntax/**',
|
||||||
|
'aio/content/guide/binding-syntax.md',
|
||||||
'aio/content/examples/binding-syntax/**',
|
'aio/content/examples/binding-syntax/**',
|
||||||
|
'aio/content/guide/property-binding.md',
|
||||||
'aio/content/examples/property-binding/**',
|
'aio/content/examples/property-binding/**',
|
||||||
|
'aio/content/guide/attribute-binding.md',
|
||||||
'aio/content/examples/attribute-binding/**',
|
'aio/content/examples/attribute-binding/**',
|
||||||
|
'aio/content/guide/two-way-binding.md',
|
||||||
'aio/content/examples/two-way-binding/**',
|
'aio/content/examples/two-way-binding/**',
|
||||||
|
'aio/content/guide/built-in-directives.md',
|
||||||
'aio/content/examples/built-in-directives/**',
|
'aio/content/examples/built-in-directives/**',
|
||||||
'aio/content/images/guide/built-in-directives/**',
|
'aio/content/images/guide/built-in-directives/**',
|
||||||
|
'aio/content/guide/template-reference-variables.md',
|
||||||
'aio/content/examples/template-reference-variables/**',
|
'aio/content/examples/template-reference-variables/**',
|
||||||
|
'aio/content/guide/inputs-outputs.md',
|
||||||
'aio/content/examples/inputs-outputs/**',
|
'aio/content/examples/inputs-outputs/**',
|
||||||
'aio/content/images/guide/inputs-outputs/**',
|
'aio/content/images/guide/inputs-outputs/**',
|
||||||
|
'aio/content/guide/template-expression-operators.md',
|
||||||
'aio/content/examples/template-expression-operators/**',
|
'aio/content/examples/template-expression-operators/**',
|
||||||
'aio/content/guide/pipes.md',
|
'aio/content/guide/pipes.md',
|
||||||
'aio/content/examples/pipes/**',
|
'aio/content/examples/pipes/**',
|
||||||
'aio/content/images/guide/pipes/**',
|
'aio/content/images/guide/pipes/**',
|
||||||
'aio/content/guide/providers.md',
|
'aio/content/guide/providers.md',
|
||||||
'aio/content/examples/providers/**',
|
'aio/content/examples/providers/**',
|
||||||
|
'aio/content/images/guide/providers/**',
|
||||||
'aio/content/guide/singleton-services.md',
|
'aio/content/guide/singleton-services.md',
|
||||||
'aio/content/guide/set-document-title.md',
|
'aio/content/guide/set-document-title.md',
|
||||||
'aio/content/examples/set-document-title/**',
|
'aio/content/examples/set-document-title/**',
|
||||||
@ -369,7 +401,9 @@ groups:
|
|||||||
'aio/content/guide/sharing-ngmodules.md',
|
'aio/content/guide/sharing-ngmodules.md',
|
||||||
'aio/content/guide/structural-directives.md',
|
'aio/content/guide/structural-directives.md',
|
||||||
'aio/content/examples/structural-directives/**',
|
'aio/content/examples/structural-directives/**',
|
||||||
|
'aio/content/guide/svg-in-templates.md',
|
||||||
'aio/content/images/guide/structural-directives/**',
|
'aio/content/images/guide/structural-directives/**',
|
||||||
|
'aio/content/guide/template-statements.md',
|
||||||
'aio/content/guide/user-input.md',
|
'aio/content/guide/user-input.md',
|
||||||
'aio/content/examples/user-input/**',
|
'aio/content/examples/user-input/**',
|
||||||
'aio/content/images/guide/user-input/**'
|
'aio/content/images/guide/user-input/**'
|
||||||
@ -471,8 +505,8 @@ groups:
|
|||||||
- >
|
- >
|
||||||
contains_any_globs(files, [
|
contains_any_globs(files, [
|
||||||
'packages/core/src/i18n/**',
|
'packages/core/src/i18n/**',
|
||||||
'packages/core/src/render3/i18n.ts',
|
'packages/core/src/render3/i18n/**',
|
||||||
'packages/core/src/render3/i18n.md',
|
'packages/core/src/render3/instructions/i18n.ts',
|
||||||
'packages/core/src/render3/interfaces/i18n.ts',
|
'packages/core/src/render3/interfaces/i18n.ts',
|
||||||
'packages/common/locales/**',
|
'packages/common/locales/**',
|
||||||
'packages/common/src/i18n/**',
|
'packages/common/src/i18n/**',
|
||||||
@ -528,6 +562,7 @@ groups:
|
|||||||
'packages/examples/router/**',
|
'packages/examples/router/**',
|
||||||
'aio/content/guide/router.md',
|
'aio/content/guide/router.md',
|
||||||
'aio/content/guide/router-tutorial.md',
|
'aio/content/guide/router-tutorial.md',
|
||||||
|
'aio/content/guide/router-tutorial-toh.md',
|
||||||
'aio/content/examples/router-tutorial/**',
|
'aio/content/examples/router-tutorial/**',
|
||||||
'aio/content/examples/router/**',
|
'aio/content/examples/router/**',
|
||||||
'aio/content/images/guide/router/**'
|
'aio/content/images/guide/router/**'
|
||||||
@ -608,6 +643,14 @@ groups:
|
|||||||
contains_any_globs(files.exclude('packages/compiler-cli/**'), [
|
contains_any_globs(files.exclude('packages/compiler-cli/**'), [
|
||||||
'**/testing/**',
|
'**/testing/**',
|
||||||
'aio/content/guide/testing.md',
|
'aio/content/guide/testing.md',
|
||||||
|
'aio/content/guide/test-debugging.md',
|
||||||
|
'aio/content/guide/testing-attribute-directives.md',
|
||||||
|
'aio/content/guide/testing-code-coverage.md',
|
||||||
|
'aio/content/guide/testing-components-basics.md',
|
||||||
|
'aio/content/guide/testing-components-scenarios.md',
|
||||||
|
'aio/content/guide/testing-pipes.md',
|
||||||
|
'aio/content/guide/testing-services.md',
|
||||||
|
'aio/content/guide/testing-utility-apis.md',
|
||||||
'aio/content/examples/testing/**',
|
'aio/content/examples/testing/**',
|
||||||
'aio/content/images/guide/testing/**'
|
'aio/content/images/guide/testing/**'
|
||||||
])
|
])
|
||||||
@ -820,6 +863,7 @@ groups:
|
|||||||
- *can-be-global-docs-approved
|
- *can-be-global-docs-approved
|
||||||
- >
|
- >
|
||||||
contains_any_globs(files, [
|
contains_any_globs(files, [
|
||||||
|
'aio/content/guide/roadmap.md',
|
||||||
'aio/content/marketing/**',
|
'aio/content/marketing/**',
|
||||||
'aio/content/images/bios/**',
|
'aio/content/images/bios/**',
|
||||||
'aio/content/images/marketing/**',
|
'aio/content/images/marketing/**',
|
||||||
@ -1099,6 +1143,8 @@ groups:
|
|||||||
public-api:
|
public-api:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
conditions:
|
conditions:
|
||||||
|
- *no-groups-above-this-pending
|
||||||
|
- *no-groups-above-this-rejected
|
||||||
- *can-be-global-approved
|
- *can-be-global-approved
|
||||||
- >
|
- >
|
||||||
contains_any_globs(files, [
|
contains_any_globs(files, [
|
||||||
@ -1112,13 +1158,16 @@ groups:
|
|||||||
])
|
])
|
||||||
reviewers:
|
reviewers:
|
||||||
users:
|
users:
|
||||||
- alxhub
|
- AndrewKushnir
|
||||||
- IgorMinar
|
- IgorMinar
|
||||||
|
- alxhub
|
||||||
|
- atscott
|
||||||
- jelbourn
|
- jelbourn
|
||||||
|
- petebacondarwin
|
||||||
- pkozlowski-opensource
|
- pkozlowski-opensource
|
||||||
reviews:
|
reviews:
|
||||||
request: -1 # request reviews from everyone
|
request: 4 # Request reviews from four people
|
||||||
required: 3 # require at least 3 approvals
|
required: 3 # Require that three people approve
|
||||||
reviewed_for: required
|
reviewed_for: required
|
||||||
|
|
||||||
|
|
||||||
@ -1128,6 +1177,8 @@ groups:
|
|||||||
size-tracking:
|
size-tracking:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
conditions:
|
conditions:
|
||||||
|
- *no-groups-above-this-pending
|
||||||
|
- *no-groups-above-this-rejected
|
||||||
- *can-be-global-approved
|
- *can-be-global-approved
|
||||||
- >
|
- >
|
||||||
contains_any_globs(files, [
|
contains_any_globs(files, [
|
||||||
@ -1135,13 +1186,16 @@ groups:
|
|||||||
])
|
])
|
||||||
reviewers:
|
reviewers:
|
||||||
users:
|
users:
|
||||||
- alxhub
|
- AndrewKushnir
|
||||||
- IgorMinar
|
- IgorMinar
|
||||||
|
- alxhub
|
||||||
|
- atscott
|
||||||
- jelbourn
|
- jelbourn
|
||||||
|
- petebacondarwin
|
||||||
- pkozlowski-opensource
|
- pkozlowski-opensource
|
||||||
reviews:
|
reviews:
|
||||||
request: -1 # request reviews from everyone
|
request: 4 # Request reviews from four people
|
||||||
required: 2 # require at least 2 approvals
|
required: 2 # Require that two people approve
|
||||||
reviewed_for: required
|
reviewed_for: required
|
||||||
|
|
||||||
|
|
||||||
@ -1151,6 +1205,8 @@ groups:
|
|||||||
circular-dependencies:
|
circular-dependencies:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
conditions:
|
conditions:
|
||||||
|
- *no-groups-above-this-pending
|
||||||
|
- *no-groups-above-this-rejected
|
||||||
- *can-be-global-approved
|
- *can-be-global-approved
|
||||||
- >
|
- >
|
||||||
contains_any_globs(files, [
|
contains_any_globs(files, [
|
||||||
@ -1158,9 +1214,12 @@ groups:
|
|||||||
])
|
])
|
||||||
reviewers:
|
reviewers:
|
||||||
users:
|
users:
|
||||||
|
- AndrewKushnir
|
||||||
- IgorMinar
|
- IgorMinar
|
||||||
|
- alxhub
|
||||||
|
- atscott
|
||||||
- jelbourn
|
- jelbourn
|
||||||
- josephperrott
|
- petebacondarwin
|
||||||
- pkozlowski-opensource
|
- pkozlowski-opensource
|
||||||
|
|
||||||
|
|
||||||
@ -1181,7 +1240,13 @@ groups:
|
|||||||
])
|
])
|
||||||
reviewers:
|
reviewers:
|
||||||
users:
|
users:
|
||||||
|
- AndrewKushnir
|
||||||
- IgorMinar
|
- IgorMinar
|
||||||
|
- alxhub
|
||||||
|
- atscott
|
||||||
|
- jelbourn
|
||||||
|
- josephperrott
|
||||||
|
- mhevery
|
||||||
|
|
||||||
|
|
||||||
# ====================================================
|
# ====================================================
|
||||||
@ -1208,13 +1273,10 @@ groups:
|
|||||||
# `global-approvers` can still approve PRs that match this `fallback` rule,
|
# `global-approvers` can still approve PRs that match this `fallback` rule,
|
||||||
# but that should be an exception and not an expectation.
|
# but that should be an exception and not an expectation.
|
||||||
conditions:
|
conditions:
|
||||||
|
- *no-groups-above-this-active
|
||||||
|
# When any of the `global-*` groups is approved, they cause other groups to deactivate.
|
||||||
|
# In those cases, the condition above would evaluate to `true` while in reality, only a global
|
||||||
|
# approval has been provided. To ensure we don't activate the fallback group in such cases,
|
||||||
|
# ensure that no explicit global approval has been provided.
|
||||||
- *can-be-global-approved
|
- *can-be-global-approved
|
||||||
# The following groups have no conditions and will be `active` on all PRs
|
- *can-be-global-docs-approved
|
||||||
# - `global-approvers`
|
|
||||||
# - `global-docs-approvers`
|
|
||||||
#
|
|
||||||
# Since this means the minimum number of active groups a PR can have is 2, this
|
|
||||||
# `fallback` group should be matched anytime the number of active groups is at or
|
|
||||||
# below this minimum. This work as a protection to ensure that pullapprove does
|
|
||||||
# not incidently mark a PR as passing without meeting the review criteria.
|
|
||||||
- len(groups.active) <= 2
|
|
||||||
|
1
.vscode/recommended-settings.json
vendored
1
.vscode/recommended-settings.json
vendored
@ -26,6 +26,7 @@
|
|||||||
"**/bazel-out": true,
|
"**/bazel-out": true,
|
||||||
"**/dist": true,
|
"**/dist": true,
|
||||||
"**/aio/src/generated": true,
|
"**/aio/src/generated": true,
|
||||||
|
".history": true,
|
||||||
},
|
},
|
||||||
"git.ignoreLimitWarning": true,
|
"git.ignoreLimitWarning": true,
|
||||||
}
|
}
|
116
CHANGELOG.md
116
CHANGELOG.md
@ -1,3 +1,119 @@
|
|||||||
|
<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)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** Metadata should not include methods on Object.prototype ([#38292](https://github.com/angular/angular/issues/38292)) ([879ff08](https://github.com/angular/angular/commit/879ff08))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="10.0.6"></a>
|
||||||
|
## 10.0.6 (2020-07-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** share identical stylesheets between components in the same file ([#38213](https://github.com/angular/angular/issues/38213)) ([264950b](https://github.com/angular/angular/commit/264950b)), closes [#38204](https://github.com/angular/angular/issues/38204)
|
||||||
|
* **compiler-cli:** Add support for string literal class members ([#38226](https://github.com/angular/angular/issues/38226)) ([b1e7775](https://github.com/angular/angular/commit/b1e7775))
|
||||||
|
* **core:** `Attribute` decorator `attributeName` is mandatory ([#38131](https://github.com/angular/angular/issues/38131)) ([1c4fcce](https://github.com/angular/angular/commit/1c4fcce)), closes [#32658](https://github.com/angular/angular/issues/32658)
|
||||||
|
* **core:** unify the signature between ngZone and noopZone ([#37581](https://github.com/angular/angular/issues/37581)) ([d5264f5](https://github.com/angular/angular/commit/d5264f5))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="10.0.5"></a>
|
||||||
|
## 10.0.5 (2020-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** properly associate source spans for implicitly closed elements ([#38126](https://github.com/angular/angular/issues/38126)) ([e80278c](https://github.com/angular/angular/commit/e80278c)), closes [#36118](https://github.com/angular/angular/issues/36118)
|
||||||
|
* **compiler-cli:** ensure file_system handles mixed Windows drives ([#38030](https://github.com/angular/angular/issues/38030)) ([dba4023](https://github.com/angular/angular/commit/dba4023)), closes [#36777](https://github.com/angular/angular/issues/36777)
|
||||||
|
* **core:** Allow modification of lifecycle hooks any time before bootstrap ([#38119](https://github.com/angular/angular/issues/38119)) ([14b4718](https://github.com/angular/angular/commit/14b4718)), closes [#30497](https://github.com/angular/angular/issues/30497)
|
||||||
|
* **core:** error due to integer overflow when there are too many host bindings ([#38014](https://github.com/angular/angular/issues/38014)) ([7b6e73c](https://github.com/angular/angular/commit/7b6e73c)), closes [#37876](https://github.com/angular/angular/issues/37876) [#37876](https://github.com/angular/angular/issues/37876)
|
||||||
|
* **core:** incorrectly validating properties on ng-content and ng-container ([#37773](https://github.com/angular/angular/issues/37773)) ([17ddab9](https://github.com/angular/angular/commit/17ddab9))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="10.0.4"></a>
|
||||||
|
## 10.0.4 (2020-07-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bazel:** ng_module rule does not expose flat module information in Ivy ([#36971](https://github.com/angular/angular/issues/36971)) ([b76a2dc](https://github.com/angular/angular/commit/b76a2dc))
|
||||||
|
* **compiler:** check more cases for pipe usage inside host bindings ([#37883](https://github.com/angular/angular/issues/37883)) ([a94383f](https://github.com/angular/angular/commit/a94383f)), closes [#34655](https://github.com/angular/angular/issues/34655) [#37610](https://github.com/angular/angular/issues/37610)
|
||||||
|
* **language-service:** non-existent module format in package output ([#37778](https://github.com/angular/angular/issues/37778)) ([12f1773](https://github.com/angular/angular/commit/12f1773))
|
||||||
|
* **language-service:** remove completion for string ([#37983](https://github.com/angular/angular/issues/37983)) ([387e838](https://github.com/angular/angular/commit/387e838))
|
||||||
|
* **ngcc:** report a warning if ngcc tries to use a solution-style tsconfig ([#38003](https://github.com/angular/angular/issues/38003)) ([e3b8010](https://github.com/angular/angular/commit/e3b8010)), closes [#36386](https://github.com/angular/angular/issues/36386)
|
||||||
|
* **service-worker:** correctly handle relative base href ([#37922](https://github.com/angular/angular/issues/37922)) ([b186db7](https://github.com/angular/angular/commit/b186db7)), closes [#25055](https://github.com/angular/angular/issues/25055) [#25055](https://github.com/angular/angular/issues/25055)
|
||||||
|
* **service-worker:** correctly serve `ngsw/state` with a non-root SW scope ([#37922](https://github.com/angular/angular/issues/37922)) ([dc42c97](https://github.com/angular/angular/commit/dc42c97)), closes [#30505](https://github.com/angular/angular/issues/30505)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **bazel:** provide LinkablePackageInfo from ng_module ([#37778](https://github.com/angular/angular/issues/37778)) ([6cd10a1](https://github.com/angular/angular/commit/6cd10a1)), closes [/github.com/bazelbuild/rules_nodejs/blob/9a5de3728b05bf1647bbb87ad99f54e626604705/internal/linker/link_node_modules.bzl#L144-L146](https://github.com//github.com/bazelbuild/rules_nodejs/blob/9a5de3728b05bf1647bbb87ad99f54e626604705/internal/linker/link_node_modules.bzl/issues/L144-L146)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.0.3"></a>
|
<a name="10.0.3"></a>
|
||||||
## 10.0.3 (2020-07-08)
|
## 10.0.3 (2020-07-08)
|
||||||
|
|
||||||
|
297
CONTRIBUTING.md
297
CONTRIBUTING.md
@ -1,7 +1,7 @@
|
|||||||
# Contributing to Angular
|
# Contributing to Angular
|
||||||
|
|
||||||
We would love for you to contribute to Angular and help make it even better than it is
|
We would love for you to contribute to Angular and help make it even better than it is today!
|
||||||
today! As a contributor, here are the guidelines we would like you to follow:
|
As a contributor, here are the guidelines we would like you to follow:
|
||||||
|
|
||||||
- [Code of Conduct](#coc)
|
- [Code of Conduct](#coc)
|
||||||
- [Question or Problem?](#question)
|
- [Question or Problem?](#question)
|
||||||
@ -12,12 +12,17 @@ today! As a contributor, here are the guidelines we would like you to follow:
|
|||||||
- [Commit Message Guidelines](#commit)
|
- [Commit Message Guidelines](#commit)
|
||||||
- [Signing the CLA](#cla)
|
- [Signing the CLA](#cla)
|
||||||
|
|
||||||
|
|
||||||
## <a name="coc"></a> Code of Conduct
|
## <a name="coc"></a> Code of Conduct
|
||||||
Help us keep Angular open and inclusive. Please read and follow our [Code of Conduct][coc].
|
|
||||||
|
Help us keep Angular open and inclusive.
|
||||||
|
Please read and follow our [Code of Conduct][coc].
|
||||||
|
|
||||||
|
|
||||||
## <a name="question"></a> Got a Question or Problem?
|
## <a name="question"></a> Got a Question or Problem?
|
||||||
|
|
||||||
Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [Stack Overflow](https://stackoverflow.com/questions/tagged/angular) where the questions should be tagged with tag `angular`.
|
Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests.
|
||||||
|
Instead, we recommend using [Stack Overflow](https://stackoverflow.com/questions/tagged/angular) to ask support-related questions. When creating a new question on Stack Overflow, make sure to add the `angular` tag.
|
||||||
|
|
||||||
Stack Overflow is a much better place to ask questions since:
|
Stack Overflow is a much better place to ask questions since:
|
||||||
|
|
||||||
@ -29,35 +34,41 @@ To save your and our time, we will systematically close all issues that are requ
|
|||||||
|
|
||||||
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
|
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
|
||||||
|
|
||||||
|
|
||||||
## <a name="issue"></a> Found a Bug?
|
## <a name="issue"></a> Found a Bug?
|
||||||
If you find a bug in the source code, you can help us by
|
|
||||||
[submitting an issue](#submit-issue) to our [GitHub Repository][github]. Even better, you can
|
If you find a bug in the source code, you can help us by [submitting an issue](#submit-issue) to our [GitHub Repository][github].
|
||||||
[submit a Pull Request](#submit-pr) with a fix.
|
Even better, you can [submit a Pull Request](#submit-pr) with a fix.
|
||||||
|
|
||||||
|
|
||||||
## <a name="feature"></a> Missing a Feature?
|
## <a name="feature"></a> Missing a Feature?
|
||||||
You can *request* a new feature by [submitting an issue](#submit-issue) to our GitHub
|
You can *request* a new feature by [submitting an issue](#submit-issue) to our GitHub Repository.
|
||||||
Repository. If you would like to *implement* a new feature, please submit an issue with
|
If you would like to *implement* a new feature, please consider the size of the change in order to determine the right steps to proceed:
|
||||||
a proposal for your work first, to be sure that we can use it.
|
|
||||||
Please consider what kind of change it is:
|
* For a **Major Feature**, first open an issue and outline your proposal so that it can be discussed.
|
||||||
|
This process allows us to better coordinate our efforts, prevent duplication of work, and help you to craft the change so that it is successfully accepted into the project.
|
||||||
|
|
||||||
|
**Note**: Adding a new topic to the documentation, or significantly re-writing a topic, counts as a major feature.
|
||||||
|
|
||||||
* For a **Major Feature**, first open an issue and outline your proposal so that it can be
|
|
||||||
discussed. This will also allow us to better coordinate our efforts, prevent duplication of work,
|
|
||||||
and help you to craft the change so that it is successfully accepted into the project. **Note**:
|
|
||||||
Adding a new topic to the documentation, or significantly re-writing a topic, counts as a major
|
|
||||||
feature.
|
|
||||||
* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
|
* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
|
||||||
|
|
||||||
|
|
||||||
## <a name="submit"></a> Submission Guidelines
|
## <a name="submit"></a> Submission Guidelines
|
||||||
|
|
||||||
|
|
||||||
### <a name="submit-issue"></a> Submitting an Issue
|
### <a name="submit-issue"></a> Submitting an Issue
|
||||||
|
|
||||||
Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.
|
Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.
|
||||||
|
|
||||||
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs, we will systematically ask you to provide a minimal reproduction. Having a minimal reproducible scenario gives us a wealth of important information without going back & forth to you with additional questions.
|
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it.
|
||||||
|
In order to reproduce bugs, we require that you provide a minimal reproduction.
|
||||||
|
Having a minimal reproducible scenario gives us a wealth of important information without going back and forth to you with additional questions.
|
||||||
|
|
||||||
A minimal reproduction allows us to quickly confirm a bug (or point out a coding problem) as well as confirm that we are fixing the right problem.
|
A minimal reproduction allows us to quickly confirm a bug (or point out a coding problem) as well as confirm that we are fixing the right problem.
|
||||||
|
|
||||||
We will be insisting on a minimal reproduction scenario in order to save maintainers' time and ultimately be able to fix more bugs. Interestingly, from our experience, users often find coding problems themselves while preparing a minimal reproduction. We understand that sometimes it might be hard to extract essential bits of code from a larger codebase but we really need to isolate the problem before we can fix it.
|
We require a minimal reproduction to save maintainers' time and ultimately be able to fix more bugs.
|
||||||
|
Often, developers find coding problems themselves while preparing a minimal reproduction.
|
||||||
|
We understand that sometimes it might be hard to extract essential bits of code from a larger codebase but we really need to isolate the problem before we can fix it.
|
||||||
|
|
||||||
Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you, we are going to close an issue that doesn't have enough info to be reproduced.
|
Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you, we are going to close an issue that doesn't have enough info to be reproduced.
|
||||||
|
|
||||||
@ -65,56 +76,66 @@ You can file new issues by selecting from our [new issue templates](https://gith
|
|||||||
|
|
||||||
|
|
||||||
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
|
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
|
||||||
|
|
||||||
Before you submit your Pull Request (PR) consider the following guidelines:
|
Before you submit your Pull Request (PR) consider the following guidelines:
|
||||||
|
|
||||||
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
|
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR that relates to your submission.
|
||||||
that relates to your submission. You don't want to duplicate effort.
|
You don't want to duplicate existing efforts.
|
||||||
1. Be sure that an issue describes the problem you're fixing, or documents the design for the feature you'd like to add.
|
|
||||||
Discussing the design upfront helps to ensure that we're ready to accept your work.
|
2. Be sure that an issue describes the problem you're fixing, or documents the design for the feature you'd like to add.
|
||||||
1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
|
Discussing the design upfront helps to ensure that we're ready to accept your work.
|
||||||
We cannot accept code without this. Make sure you sign with the primary email address of the Git identity that has been granted access to the Angular repository.
|
|
||||||
1. Fork the angular/angular repo.
|
3. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
|
||||||
1. Make your changes in a new git branch:
|
We cannot accept code without a signed CLA.
|
||||||
|
Make sure you author all contributed Git commits with email address associated with your CLA signature.
|
||||||
|
|
||||||
|
4. Fork the angular/angular repo.
|
||||||
|
|
||||||
|
5. Make your changes in a new git branch:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git checkout -b my-fix-branch master
|
git checkout -b my-fix-branch master
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Create your patch, **including appropriate test cases**.
|
6. Create your patch, **including appropriate test cases**.
|
||||||
1. Follow our [Coding Rules](#rules).
|
|
||||||
1. Run the full Angular test suite, as described in the [developer documentation][dev-doc],
|
7. Follow our [Coding Rules](#rules).
|
||||||
and ensure that all tests pass.
|
|
||||||
1. Commit your changes using a descriptive commit message that follows our
|
8. Run the full Angular test suite, as described in the [developer documentation][dev-doc], and ensure that all tests pass.
|
||||||
[commit message conventions](#commit). Adherence to these conventions is necessary because release notes are automatically generated from these messages.
|
|
||||||
|
9. Commit your changes using a descriptive commit message that follows our [commit message conventions](#commit).
|
||||||
|
Adherence to these conventions is necessary because release notes are automatically generated from these messages.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git commit -a
|
git commit -a
|
||||||
```
|
```
|
||||||
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
||||||
|
|
||||||
1. Push your branch to GitHub:
|
10. Push your branch to GitHub:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git push origin my-fix-branch
|
git push origin my-fix-branch
|
||||||
```
|
```
|
||||||
|
|
||||||
1. In GitHub, send a pull request to `angular:master`.
|
11. In GitHub, send a pull request to `angular:master`.
|
||||||
* If we suggest changes then:
|
|
||||||
* Make the required updates.
|
|
||||||
* Re-run the Angular test suites to ensure tests are still passing.
|
|
||||||
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
|
||||||
|
|
||||||
```shell
|
If we ask for changes via code reviews then:
|
||||||
git rebase master -i
|
|
||||||
git push -f
|
* Make the required updates.
|
||||||
```
|
* Re-run the Angular test suites to ensure tests are still passing.
|
||||||
|
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git rebase master -i
|
||||||
|
git push -f
|
||||||
|
```
|
||||||
|
|
||||||
That's it! Thank you for your contribution!
|
That's it! Thank you for your contribution!
|
||||||
|
|
||||||
|
|
||||||
#### After your pull request is merged
|
#### After your pull request is merged
|
||||||
|
|
||||||
After your pull request is merged, you can safely delete your branch and pull the changes
|
After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository:
|
||||||
from the main (upstream) repository:
|
|
||||||
|
|
||||||
* Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:
|
* Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:
|
||||||
|
|
||||||
@ -140,55 +161,66 @@ from the main (upstream) repository:
|
|||||||
git pull --ff upstream master
|
git pull --ff upstream master
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## <a name="rules"></a> Coding Rules
|
## <a name="rules"></a> Coding Rules
|
||||||
To ensure consistency throughout the source code, keep these rules in mind as you are working:
|
To ensure consistency throughout the source code, keep these rules in mind as you are working:
|
||||||
|
|
||||||
* All features or bug fixes **must be tested** by one or more specs (unit-tests).
|
* All features or bug fixes **must be tested** by one or more specs (unit-tests).
|
||||||
* All public API methods **must be documented**. (Details TBC).
|
* All public API methods **must be documented**.
|
||||||
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at
|
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at **100 characters**.
|
||||||
**100 characters**. An automated formatter is available, see
|
|
||||||
[DEVELOPER.md](docs/DEVELOPER.md#clang-format).
|
|
||||||
|
|
||||||
## <a name="commit"></a> Commit Message Guidelines
|
An automated formatter is available, see [DEVELOPER.md](docs/DEVELOPER.md#clang-format).
|
||||||
|
|
||||||
We have very precise rules over how our git commit messages can be formatted. This leads to **more
|
|
||||||
readable messages** that are easy to follow when looking through the **project history**. But also,
|
|
||||||
we use the git commit messages to **generate the Angular change log**.
|
|
||||||
|
|
||||||
### Commit Message Format
|
## <a name="commit"></a> Commit Message Format
|
||||||
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
|
|
||||||
format that includes a **type**, a **scope** and a **subject**:
|
*This specification is inspired and supersedes the [AngularJS commit message format][commit-message-format].*
|
||||||
|
|
||||||
|
We have very precise rules over how our Git commit messages must be formatted.
|
||||||
|
This format leads to **easier to read commit history**.
|
||||||
|
|
||||||
|
Each commit message consists of a **header**, a **body**, and a **footer**.
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
<type>(<scope>): <subject>
|
<header>
|
||||||
<BLANK LINE>
|
<BLANK LINE>
|
||||||
<body>
|
<body>
|
||||||
<BLANK LINE>
|
<BLANK LINE>
|
||||||
<footer>
|
<footer>
|
||||||
```
|
```
|
||||||
|
|
||||||
The **header** is mandatory and the **scope** of the header is optional.
|
The `header` is mandatory and must conform to the [Commit Message Header](#commit-header) format.
|
||||||
|
|
||||||
Any line of the commit message cannot be longer than 100 characters! This allows the message to be easier
|
The `body` is mandatory for all commits except for those of scope "docs".
|
||||||
to read on GitHub as well as in various git tools.
|
When the body is required it must be at least 20 characters long.
|
||||||
|
|
||||||
The footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.
|
The `footer` is optional.
|
||||||
|
|
||||||
Samples: (even more [samples](https://github.com/angular/angular/commits/master))
|
Any line of the commit message cannot be longer than 100 characters.
|
||||||
|
|
||||||
|
|
||||||
|
#### <a href="commit-header"></a>Commit Message Header
|
||||||
|
|
||||||
```
|
```
|
||||||
docs(changelog): update changelog to beta.5
|
<type>(<scope>): <short summary>
|
||||||
```
|
│ │ │
|
||||||
```
|
│ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
|
||||||
fix(release): need to depend on the latest rxjs and zone.js
|
│ │
|
||||||
|
│ └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
|
||||||
The version in our package.json gets copied to the one we publish, and users need the latest of these.
|
│ elements|forms|http|language-service|localize|platform-browser|
|
||||||
|
│ platform-browser-dynamic|platform-server|platform-webworker|
|
||||||
|
│ platform-webworker-dynamic|router|service-worker|upgrade|zone.js|
|
||||||
|
│ packaging|changelog|dev-infra|docs-infra|migrations|ngcc|ve
|
||||||
|
│
|
||||||
|
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|style|test
|
||||||
```
|
```
|
||||||
|
|
||||||
### Revert
|
The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is optional.
|
||||||
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body, it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
|
|
||||||
|
|
||||||
|
##### Type
|
||||||
|
|
||||||
### Type
|
|
||||||
Must be one of the following:
|
Must be one of the following:
|
||||||
|
|
||||||
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
|
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
|
||||||
@ -201,67 +233,95 @@ Must be one of the following:
|
|||||||
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
|
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
|
||||||
* **test**: Adding missing tests or correcting existing tests
|
* **test**: Adding missing tests or correcting existing tests
|
||||||
|
|
||||||
### Scope
|
|
||||||
|
##### Scope
|
||||||
The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages).
|
The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages).
|
||||||
|
|
||||||
The following is the list of supported scopes:
|
The following is the list of supported scopes:
|
||||||
|
|
||||||
* **animations**
|
* `animations`
|
||||||
* **bazel**
|
* `bazel`
|
||||||
* **benchpress**
|
* `benchpress`
|
||||||
* **common**
|
* `common`
|
||||||
* **compiler**
|
* `compiler`
|
||||||
* **compiler-cli**
|
* `compiler-cli`
|
||||||
* **core**
|
* `core`
|
||||||
* **elements**
|
* `elements`
|
||||||
* **forms**
|
* `forms`
|
||||||
* **http**
|
* `http`
|
||||||
* **language-service**
|
* `language-service`
|
||||||
* **localize**
|
* `localize`
|
||||||
* **platform-browser**
|
* `platform-browser`
|
||||||
* **platform-browser-dynamic**
|
* `platform-browser-dynamic`
|
||||||
* **platform-server**
|
* `platform-server`
|
||||||
* **platform-webworker**
|
* `platform-webworker`
|
||||||
* **platform-webworker-dynamic**
|
* `platform-webworker-dynamic`
|
||||||
* **router**
|
* `router`
|
||||||
* **service-worker**
|
* `service-worker`
|
||||||
* **upgrade**
|
* `upgrade`
|
||||||
* **zone.js**
|
* `zone.js`
|
||||||
|
|
||||||
There are currently a few exceptions to the "use package name" rule:
|
There are currently a few exceptions to the "use package name" rule:
|
||||||
|
|
||||||
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g.
|
* `packaging`: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
|
||||||
public path changes, package.json changes done to all packages, d.ts file/format changes, changes
|
|
||||||
to bundles, etc.
|
|
||||||
* **changelog**: used for updating the release notes in CHANGELOG.md
|
|
||||||
* **docs-infra**: used for docs-app (angular.io) related changes within the /aio directory of the
|
|
||||||
repo
|
|
||||||
* **dev-infra**: used for dev-infra related changes within the directories /scripts, /tools and /dev-infra
|
|
||||||
* **migrations**: used for changes to the `ng update` migrations.
|
|
||||||
* **ngcc**: used for changes to the [Angular Compatibility Compiler](./packages/compiler-cli/ngcc/README.md)
|
|
||||||
* **ve**: used for changes specific to ViewEngine (legacy compiler/renderer).
|
|
||||||
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all
|
|
||||||
packages (e.g. `style: add missing semicolons`) and for docs changes that are not related to a
|
|
||||||
specific package (e.g. `docs: fix typo in tutorial`).
|
|
||||||
|
|
||||||
### Subject
|
* `changelog`: used for updating the release notes in CHANGELOG.md
|
||||||
The subject contains a succinct description of the change:
|
|
||||||
|
* `dev-infra`: used for dev-infra related changes within the directories /scripts, /tools and /dev-infra
|
||||||
|
|
||||||
|
* `docs-infra`: used for docs-app (angular.io) related changes within the /aio directory of the repo
|
||||||
|
|
||||||
|
* `migrations`: used for changes to the `ng update` migrations.
|
||||||
|
|
||||||
|
* `ngcc`: used for changes to the [Angular Compatibility Compiler](./packages/compiler-cli/ngcc/README.md)
|
||||||
|
|
||||||
|
* `ve`: used for changes specific to ViewEngine (legacy compiler/renderer).
|
||||||
|
|
||||||
|
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`) and for docs changes that are not related to a specific package (e.g. `docs: fix typo in tutorial`).
|
||||||
|
|
||||||
|
|
||||||
|
##### Summary
|
||||||
|
|
||||||
|
Use the summary field to provide a succinct description of the change:
|
||||||
|
|
||||||
* use the imperative, present tense: "change" not "changed" nor "changes"
|
* use the imperative, present tense: "change" not "changed" nor "changes"
|
||||||
* don't capitalize the first letter
|
* don't capitalize the first letter
|
||||||
* no dot (.) at the end
|
* no dot (.) at the end
|
||||||
|
|
||||||
### Body
|
|
||||||
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
|
|
||||||
The body should include the motivation for the change and contrast this with previous behavior.
|
|
||||||
|
|
||||||
### Footer
|
#### Commit Message Body
|
||||||
The footer should contain any information about **Breaking Changes** and is also the place to
|
|
||||||
reference GitHub issues that this commit **Closes**.
|
|
||||||
|
|
||||||
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
|
Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
|
||||||
|
|
||||||
|
Explain the motivation for the change in the commit message body. This commit message should explain _why_ you are making the change.
|
||||||
|
You can include a comparison of the previous behavior with the new behavior in order to illustrate the impact of the change.
|
||||||
|
|
||||||
|
|
||||||
|
#### Commit Message Footer
|
||||||
|
|
||||||
|
The footer can contain information about breaking changes and is also the place to reference GitHub issues, Jira tickets, and other PRs that this commit closes or is related to.
|
||||||
|
|
||||||
|
```
|
||||||
|
BREAKING CHANGE: <breaking change summary>
|
||||||
|
<BLANK LINE>
|
||||||
|
<breaking change description + migration instructions>
|
||||||
|
<BLANK LINE>
|
||||||
|
<BLANK LINE>
|
||||||
|
Fixes #<issue number>
|
||||||
|
```
|
||||||
|
|
||||||
|
Breaking Change section should start with the phrase "BREAKING CHANGE: " followed by a summary of the breaking change, a blank line, and a detailed description of the breaking change that also includes migration instructions.
|
||||||
|
|
||||||
|
|
||||||
|
### Revert commits
|
||||||
|
|
||||||
|
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit.
|
||||||
|
|
||||||
|
The content of the commit message body should contain:
|
||||||
|
|
||||||
|
- information about the SHA of the commit being reverted in the following format: `This reverts commit <SHA>`,
|
||||||
|
- a clear description of the reason for reverting the commit message.
|
||||||
|
|
||||||
A detailed explanation can be found in this [document][commit-message-format].
|
|
||||||
|
|
||||||
## <a name="cla"></a> Signing the CLA
|
## <a name="cla"></a> Signing the CLA
|
||||||
|
|
||||||
@ -272,18 +332,17 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
|
|||||||
* For corporations, we'll need you to
|
* For corporations, we'll need you to
|
||||||
[print, sign and one of scan+email, fax or mail the form][corporate-cla].
|
[print, sign and one of scan+email, fax or mail the form][corporate-cla].
|
||||||
|
|
||||||
<hr>
|
If you have more than one GitHub accounts, or multiple email addresses associated with a single GitHub account, you must sign the CLA using the primary email address of the GitHub account used to author Git commits and send pull requests.
|
||||||
|
|
||||||
If you have more than one Git identity, you must make sure that you sign the CLA using the primary email address associated with the ID that has been granted access to the Angular repository. Git identities can be associated with more than one email address, and only one is primary. Here are some links to help you sort out multiple Git identities and email addresses:
|
The following documents can help you sort out issues with GitHub accounts and multiple email addresses:
|
||||||
|
|
||||||
* https://help.github.com/articles/setting-your-commit-email-address-in-git/
|
* https://help.github.com/articles/setting-your-commit-email-address-in-git/
|
||||||
* https://stackoverflow.com/questions/37245303/what-does-usera-committed-with-userb-13-days-ago-on-github-mean
|
* https://stackoverflow.com/questions/37245303/what-does-usera-committed-with-userb-13-days-ago-on-github-mean
|
||||||
* https://help.github.com/articles/about-commit-email-addresses/
|
* https://help.github.com/articles/about-commit-email-addresses/
|
||||||
* https://help.github.com/articles/blocking-command-line-pushes-that-expose-your-personal-email-address/
|
* https://help.github.com/articles/blocking-command-line-pushes-that-expose-your-personal-email-address/
|
||||||
|
|
||||||
Note that if you have more than one Git identity, it is important to verify that you are logged in with the same ID with which you signed the CLA before you commit changes. If not, your PR will fail the CLA check.
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
[angular-group]: https://groups.google.com/forum/#!forum/angular
|
[angular-group]: https://groups.google.com/forum/#!forum/angular
|
||||||
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
|
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"src/styles.scss"
|
"src/styles/main.scss"
|
||||||
],
|
],
|
||||||
"scripts": [],
|
"scripts": [],
|
||||||
"budgets": [
|
"budgets": [
|
||||||
@ -158,7 +158,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"src/styles.scss"
|
"src/styles/main.scss"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# CLI Overview and Command Reference
|
# CLI Overview and Command Reference
|
||||||
|
|
||||||
The Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications. You can use the tool directly in a command shell, or indirectly through an interactive UI such as [Angular Console](https://angularconsole.com).
|
The Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications directly from a command shell.
|
||||||
|
|
||||||
## Installing Angular CLI
|
## Installing Angular CLI
|
||||||
|
|
||||||
|
1
aio/content/examples/.gitignore
vendored
1
aio/content/examples/.gitignore
vendored
@ -18,6 +18,7 @@
|
|||||||
**/src/karma.conf.js
|
**/src/karma.conf.js
|
||||||
**/.angular-cli.json
|
**/.angular-cli.json
|
||||||
**/.editorconfig
|
**/.editorconfig
|
||||||
|
**/.gitignore
|
||||||
**/angular.json
|
**/angular.json
|
||||||
**/tsconfig.json
|
**/tsconfig.json
|
||||||
**/bs-config.e2e.json
|
**/bs-config.e2e.json
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Accessibility example e2e tests', () => {
|
describe('Accessibility example e2e tests', () => {
|
||||||
@ -8,11 +6,11 @@ describe('Accessibility example e2e tests', () => {
|
|||||||
browser.get('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display Accessibility Example', function () {
|
it('should display Accessibility Example', () => {
|
||||||
expect(element(by.css('h1')).getText()).toEqual('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');
|
element(by.css('input')).sendKeys('16');
|
||||||
expect(element(by.css('input')).getAttribute('value')).toEqual('016');
|
expect(element(by.css('input')).getAttribute('value')).toEqual('016');
|
||||||
expect(element(by.css('app-example-progressbar div')).getCssValue('width')).toBe('48px');
|
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
|
// #docregion progressbar-component
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
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('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display no poster images after bootstrap', function () {
|
it('should display no poster images after bootstrap', () => {
|
||||||
testImagesAreDisplayed(false);
|
testImagesAreDisplayed(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display proper movie data', function () {
|
it('should display proper movie data', () => {
|
||||||
// We check only a few samples
|
// 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: 0, element: 'img', attr: 'src', value: 'images/hero.png', contains: true},
|
||||||
{row: 0, column: 2, value: 'Celeritas'},
|
{row: 0, column: 2, value: 'Celeritas'},
|
||||||
{row: 1, column: 3, matches: /Dec 1[678], 2015/}, // absorb timezone dif; we care about date format
|
{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
|
// Go through the samples
|
||||||
let movieRows = getMovieRows();
|
const movieRows = getMovieRows();
|
||||||
for (let i = 0; i < expectedSamples.length; i++) {
|
for (const sample of expectedSamples) {
|
||||||
let sample = expectedSamples[i];
|
const tableCell = movieRows.get(sample.row)
|
||||||
let tableCell = movieRows.get(sample.row)
|
|
||||||
.all(by.tagName('td')).get(sample.column);
|
.all(by.tagName('td')).get(sample.column);
|
||||||
// Check the cell or its nested element
|
// Check the cell or its nested element
|
||||||
let elementToCheck = sample.element
|
const elementToCheck = sample.element
|
||||||
? tableCell.element(by.tagName(sample.element))
|
? tableCell.element(by.tagName(sample.element))
|
||||||
: tableCell;
|
: tableCell;
|
||||||
|
|
||||||
// Check element attribute or text
|
// Check element attribute or text
|
||||||
let valueToCheck = sample.attr
|
const valueToCheck = sample.attr
|
||||||
? elementToCheck.getAttribute(sample.attr)
|
? elementToCheck.getAttribute(sample.attr)
|
||||||
: elementToCheck.getText();
|
: 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);
|
testPosterButtonClick('Show Poster', true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should hide images after Hide Poster', function () {
|
it('should hide images after Hide Poster', () => {
|
||||||
testPosterButtonClick('Hide Poster', false);
|
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.');
|
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!');
|
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!');
|
testFavoriteHero('Dr Nice', 'Excellent choice!');
|
||||||
});
|
});
|
||||||
|
|
||||||
function testImagesAreDisplayed(isDisplayed: boolean) {
|
function testImagesAreDisplayed(isDisplayed: boolean) {
|
||||||
let expectedMovieCount = 3;
|
const expectedMovieCount = 3;
|
||||||
|
|
||||||
let movieRows = getMovieRows();
|
const movieRows = getMovieRows();
|
||||||
expect(movieRows.count()).toBe(expectedMovieCount);
|
expect(movieRows.count()).toBe(expectedMovieCount);
|
||||||
for (let i = 0; i < expectedMovieCount; i++) {
|
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);
|
expect(movieImage.isDisplayed()).toBe(isDisplayed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function testPosterButtonClick(expectedButtonText: string, isDisplayed: boolean) {
|
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);
|
expect(posterButton.getText()).toBe(expectedButtonText);
|
||||||
|
|
||||||
posterButton.click().then(function () {
|
posterButton.click().then(() => {
|
||||||
testImagesAreDisplayed(isDisplayed);
|
testImagesAreDisplayed(isDisplayed);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -96,12 +93,12 @@ describe('AngularJS to Angular Quick Reference Tests', function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function testFavoriteHero(heroName: string, expectedLabel: string) {
|
function testFavoriteHero(heroName: string, expectedLabel: string) {
|
||||||
let movieListComp = element(by.tagName('app-movie-list'));
|
const movieListComp = element(by.tagName('app-movie-list'));
|
||||||
let heroInput = movieListComp.element(by.tagName('input'));
|
const heroInput = movieListComp.element(by.tagName('input'));
|
||||||
let favoriteHeroLabel = movieListComp.element(by.tagName('h3'));
|
const favoriteHeroLabel = movieListComp.element(by.tagName('h3'));
|
||||||
let resultLabel = movieListComp.element(by.css('span > p'));
|
const resultLabel = movieListComp.element(by.css('span > p'));
|
||||||
|
|
||||||
heroInput.clear().then(function () {
|
heroInput.clear().then(() => {
|
||||||
heroInput.sendKeys(heroName || '');
|
heroInput.sendKeys(heroName || '');
|
||||||
expect(resultLabel.getText()).toBe(expectedLabel);
|
expect(resultLabel.getText()).toBe(expectedLabel);
|
||||||
if (heroName) {
|
if (heroName) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
import { MovieListComponent } from './movie-list.component';
|
import { MovieListComponent } from './movie-list.component';
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [ BrowserModule ],
|
imports: [ BrowserModule ],
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
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 { MovieListComponent } from './movie-list.component';
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
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 { browser, ExpectedConditions as EC } from 'protractor';
|
||||||
import { logging } from 'selenium-webdriver';
|
import { logging } from 'selenium-webdriver';
|
||||||
import * as openClose from './open-close.po';
|
import * as openClose from './open-close.po';
|
||||||
|
@ -32,15 +32,15 @@ export const slideInAnimation =
|
|||||||
// #enddocregion style-view
|
// #enddocregion style-view
|
||||||
// #docregion query
|
// #docregion query
|
||||||
query(':enter', [
|
query(':enter', [
|
||||||
style({ left: '-100%'})
|
style({ left: '-100%' })
|
||||||
]),
|
]),
|
||||||
query(':leave', animateChild()),
|
query(':leave', animateChild()),
|
||||||
group([
|
group([
|
||||||
query(':leave', [
|
query(':leave', [
|
||||||
animate('300ms ease-out', style({ left: '100%'}))
|
animate('300ms ease-out', style({ left: '100%' }))
|
||||||
]),
|
]),
|
||||||
query(':enter', [
|
query(':enter', [
|
||||||
animate('300ms ease-out', style({ left: '0%'}))
|
animate('300ms ease-out', style({ left: '0%' }))
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
query(':enter', animateChild()),
|
query(':enter', animateChild()),
|
||||||
@ -56,15 +56,15 @@ export const slideInAnimation =
|
|||||||
})
|
})
|
||||||
]),
|
]),
|
||||||
query(':enter', [
|
query(':enter', [
|
||||||
style({ left: '-100%'})
|
style({ left: '-100%' })
|
||||||
]),
|
]),
|
||||||
query(':leave', animateChild()),
|
query(':leave', animateChild()),
|
||||||
group([
|
group([
|
||||||
query(':leave', [
|
query(':leave', [
|
||||||
animate('200ms ease-out', style({ left: '100%'}))
|
animate('200ms ease-out', style({ left: '100%' }))
|
||||||
]),
|
]),
|
||||||
query(':enter', [
|
query(':enter', [
|
||||||
animate('300ms ease-out', style({ left: '0%'}))
|
animate('300ms ease-out', style({ left: '0%' }))
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
query(':enter', animateChild()),
|
query(':enter', animateChild()),
|
||||||
|
@ -17,7 +17,7 @@ Toggle All Animations <input type="checkbox" [checked]="!animationsDisabled" (cl
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- #docregion route-animations-outlet -->
|
<!-- #docregion route-animations-outlet -->
|
||||||
<div [@routeAnimations]="prepareRoute(outlet)" >
|
<div [@routeAnimations]="prepareRoute(outlet)">
|
||||||
<router-outlet #outlet="outlet"></router-outlet>
|
<router-outlet #outlet="outlet"></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
<!-- #enddocregion route-animations-outlet -->
|
<!-- #enddocregion route-animations-outlet -->
|
||||||
|
@ -34,7 +34,7 @@ export class AppComponent {
|
|||||||
|
|
||||||
// #docregion prepare-router-outlet
|
// #docregion prepare-router-outlet
|
||||||
prepareRoute(outlet: RouterOutlet) {
|
prepareRoute(outlet: RouterOutlet) {
|
||||||
return outlet && outlet.activatedRouteData && outlet.activatedRouteData['animation'];
|
return outlet && outlet.activatedRouteData && outlet.activatedRouteData.animation;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #enddocregion prepare-router-outlet
|
// #enddocregion prepare-router-outlet
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
// tslint:disable: variable-name
|
||||||
// #docplaster
|
// #docplaster
|
||||||
|
// #docregion
|
||||||
import { Component, HostBinding, OnInit } from '@angular/core';
|
import { Component, HostBinding, OnInit } from '@angular/core';
|
||||||
import { trigger, transition, animate, style, query, stagger } from '@angular/animations';
|
import { trigger, transition, animate, style, query, stagger } from '@angular/animations';
|
||||||
import { HEROES } from './mock-heroes';
|
import { HEROES } from './mock-heroes';
|
||||||
@ -52,13 +54,11 @@ export class HeroListPageComponent implements OnInit {
|
|||||||
@HostBinding('@pageAnimations')
|
@HostBinding('@pageAnimations')
|
||||||
public animatePage = true;
|
public animatePage = true;
|
||||||
|
|
||||||
_heroes = [];
|
|
||||||
// #docregion filter-animations
|
// #docregion filter-animations
|
||||||
heroTotal = -1;
|
heroTotal = -1;
|
||||||
// #enddocregion filter-animations
|
// #enddocregion filter-animations
|
||||||
get heroes() {
|
get heroes() { return this._heroes; }
|
||||||
return this._heroes;
|
private _heroes = [];
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this._heroes = HEROES;
|
this._heroes = HEROES;
|
||||||
|
@ -8,8 +8,7 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
|
|||||||
// #docregion trigger, trigger-wildcard1, trigger-transition
|
// #docregion trigger, trigger-wildcard1, trigger-transition
|
||||||
animations: [
|
animations: [
|
||||||
trigger('openClose', [
|
trigger('openClose', [
|
||||||
// #enddocregion events1
|
// #docregion state1
|
||||||
// #docregion state1, events1
|
|
||||||
// ...
|
// ...
|
||||||
// #enddocregion events1
|
// #enddocregion events1
|
||||||
state('open', style({
|
state('open', style({
|
||||||
@ -34,8 +33,7 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
|
|||||||
transition('closed => open', [
|
transition('closed => open', [
|
||||||
animate('0.5s')
|
animate('0.5s')
|
||||||
]),
|
]),
|
||||||
// #enddocregion trigger, component
|
// #enddocregion transition2, trigger, component
|
||||||
// #enddocregion transition2
|
|
||||||
// #docregion trigger-wildcard1
|
// #docregion trigger-wildcard1
|
||||||
transition('* => closed', [
|
transition('* => closed', [
|
||||||
animate('1s')
|
animate('1s')
|
||||||
@ -70,7 +68,9 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
|
|||||||
})
|
})
|
||||||
// #docregion events
|
// #docregion events
|
||||||
export class OpenCloseComponent {
|
export class OpenCloseComponent {
|
||||||
// #enddocregion events1, events
|
// #enddocregion events1, events, component
|
||||||
|
@Input() logging = false;
|
||||||
|
// #docregion component
|
||||||
isOpen = true;
|
isOpen = true;
|
||||||
|
|
||||||
toggle() {
|
toggle() {
|
||||||
@ -78,9 +78,8 @@ export class OpenCloseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// #enddocregion component
|
// #enddocregion component
|
||||||
@Input() logging = false;
|
|
||||||
// #docregion events1, events
|
// #docregion events1, events
|
||||||
onAnimationEvent ( event: AnimationEvent ) {
|
onAnimationEvent( event: AnimationEvent ) {
|
||||||
// #enddocregion events1, events
|
// #enddocregion events1, events
|
||||||
if (!this.logging) {
|
if (!this.logging) {
|
||||||
return;
|
return;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { protractor, browser, element, by, ElementFinder } from 'protractor';
|
import { protractor, browser, element, by, ElementFinder } from 'protractor';
|
||||||
|
|
||||||
const nameSuffix = 'X';
|
const nameSuffix = 'X';
|
||||||
@ -21,7 +19,7 @@ describe('Architecture', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it(`has h2 '${expectedH2}'`, () => {
|
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);
|
expect(h2).toEqual(expectedH2);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -34,42 +32,42 @@ function heroTests() {
|
|||||||
const targetHero: Hero = { id: 2, name: 'Dr Nice' };
|
const targetHero: Hero = { id: 2, name: 'Dr Nice' };
|
||||||
|
|
||||||
it('has the right number of heroes', () => {
|
it('has the right number of heroes', () => {
|
||||||
let page = getPageElts();
|
const page = getPageElts();
|
||||||
expect(page.heroes.count()).toEqual(3);
|
expect(page.heroes.count()).toEqual(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has no hero details initially', function () {
|
it('has no hero details initially', () => {
|
||||||
let page = getPageElts();
|
const page = getPageElts();
|
||||||
expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail');
|
expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows selected hero details', async () => {
|
it('shows selected hero details', async () => {
|
||||||
await element(by.cssContainingText('li', targetHero.name)).click();
|
await element(by.cssContainingText('li', targetHero.name)).click();
|
||||||
let page = getPageElts();
|
const page = getPageElts();
|
||||||
let hero = await heroFromDetail(page.heroDetail);
|
const hero = await heroFromDetail(page.heroDetail);
|
||||||
expect(hero.id).toEqual(targetHero.id);
|
expect(hero.id).toEqual(targetHero.id);
|
||||||
expect(hero.name).toEqual(targetHero.name);
|
expect(hero.name).toEqual(targetHero.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`shows updated hero name in details`, async () => {
|
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);
|
input.sendKeys(nameSuffix);
|
||||||
let page = getPageElts();
|
const page = getPageElts();
|
||||||
let hero = await heroFromDetail(page.heroDetail);
|
const hero = await heroFromDetail(page.heroDetail);
|
||||||
let newName = targetHero.name + nameSuffix;
|
const newName = targetHero.name + nameSuffix;
|
||||||
expect(hero.id).toEqual(targetHero.id);
|
expect(hero.id).toEqual(targetHero.id);
|
||||||
expect(hero.name).toEqual(newName);
|
expect(hero.name).toEqual(newName);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function salesTaxTests() {
|
function salesTaxTests() {
|
||||||
it('has no sales tax initially', function () {
|
it('has no sales tax initially', () => {
|
||||||
let page = getPageElts();
|
const page = getPageElts();
|
||||||
expect(page.salesTaxDetail.isPresent()).toBeFalsy('no sales tax info');
|
expect(page.salesTaxDetail.isPresent()).toBeFalsy('no sales tax info');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows sales tax', async function () {
|
it('shows sales tax', async () => {
|
||||||
let page = getPageElts();
|
const page = getPageElts();
|
||||||
page.salesTaxAmountInput.sendKeys('10', protractor.Key.ENTER);
|
page.salesTaxAmountInput.sendKeys('10', protractor.Key.ENTER);
|
||||||
expect(page.salesTaxDetail.getText()).toEqual('The sales tax is $1.00');
|
expect(page.salesTaxDetail.getText()).toEqual('The sales tax is $1.00');
|
||||||
});
|
});
|
||||||
@ -88,13 +86,11 @@ function getPageElts() {
|
|||||||
|
|
||||||
async function heroFromDetail(detail: ElementFinder): Promise<Hero> {
|
async function heroFromDetail(detail: ElementFinder): Promise<Hero> {
|
||||||
// Get hero id from the first <div>
|
// Get hero id from the first <div>
|
||||||
// let _id = await detail.all(by.css('div')).first().getText();
|
const id = await detail.all(by.css('div')).first().getText();
|
||||||
let _id = await detail.all(by.css('div')).first().getText();
|
|
||||||
// Get name from the h2
|
// Get name from the h2
|
||||||
// let _name = await detail.element(by.css('h4')).getText();
|
const name = await detail.element(by.css('h4')).getText();
|
||||||
let _name = await detail.element(by.css('h4')).getText();
|
|
||||||
return {
|
return {
|
||||||
id: +_id.substr(_id.indexOf(' ') + 1),
|
id: +id.substr(id.indexOf(' ') + 1),
|
||||||
name: _name.substr(0, _name.lastIndexOf(' '))
|
name: name.substr(0, name.lastIndexOf(' ')),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
// #docregion imports
|
// #docregion imports
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
// #enddocregion imports
|
// #enddocregion imports
|
||||||
import { HeroDetailComponent } from './hero-detail.component';
|
import { HeroDetailComponent } from './hero-detail.component';
|
||||||
import { HeroListComponent } from './hero-list.component';
|
import { HeroListComponent } from './hero-list.component';
|
||||||
import { SalesTaxComponent } from './sales-tax.component';
|
import { SalesTaxComponent } from './sales-tax.component';
|
||||||
import { HeroService } from './hero.service';
|
import { HeroService } from './hero.service';
|
||||||
import { BackendService } from './backend.service';
|
import { BackendService } from './backend.service';
|
||||||
import { Logger } from './logger.service';
|
import { Logger } from './logger.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -18,7 +18,7 @@ export class BackendService {
|
|||||||
// TODO: get from the database
|
// TODO: get from the database
|
||||||
return Promise.resolve<Hero[]>(HEROES);
|
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);
|
this.logger.error(err);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
import { HeroService } from './hero.service';
|
import { HeroService } from './hero.service';
|
||||||
|
|
||||||
// #docregion metadata, providers
|
// #docregion metadata, providers
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -22,7 +22,7 @@ export class AppComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// #docregion module
|
// #docregion module
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
// #docregion import-browser-module
|
// #docregion import-browser-module
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
// #enddocregion import-browser-module
|
// #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 { SalesTaxService } from './sales-tax.service';
|
||||||
import { TaxRateService } from './tax-rate.service';
|
import { TaxRateService } from './tax-rate.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sales-tax',
|
selector: 'app-sales-tax',
|
||||||
|
@ -7,7 +7,7 @@ export class SalesTaxService {
|
|||||||
constructor(private rateService: TaxRateService) { }
|
constructor(private rateService: TaxRateService) { }
|
||||||
|
|
||||||
getVAT(value: string | number) {
|
getVAT(value: string | number) {
|
||||||
let amount = (typeof value === 'string') ?
|
const amount = (typeof value === 'string') ?
|
||||||
parseFloat(value) : value;
|
parseFloat(value) : value;
|
||||||
return (amount || 0) * this.rateService.getRate('VAT');
|
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';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Attribute binding example', function () {
|
describe('Attribute binding example', () => {
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(() => {
|
||||||
browser.get('');
|
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');
|
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);
|
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');
|
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)');
|
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)');
|
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('special');
|
||||||
expect(element.all(by.css('div')).get(1).getAttribute('class')).toContain('clearance');
|
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({
|
@Component({
|
||||||
selector: 'comp-with-host-binding',
|
selector: 'comp-with-host-binding',
|
||||||
template: 'I am a component!',
|
template: 'I am a component!',
|
||||||
host: {
|
|
||||||
'[class.special]': 'isSpecial',
|
|
||||||
'[style.color]': 'color',
|
|
||||||
'[style.width]': 'width'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
export class CompWithHostBindingComponent {
|
export class CompWithHostBindingComponent {
|
||||||
|
@HostBinding('class.special')
|
||||||
isSpecial = false;
|
isSpecial = false;
|
||||||
|
|
||||||
|
@HostBinding('style.color')
|
||||||
color = 'green';
|
color = 'green';
|
||||||
|
|
||||||
|
@HostBinding('style.width')
|
||||||
width = '200px';
|
width = '200px';
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Attribute directives', () => {
|
describe('Attribute directives', () => {
|
||||||
|
|
||||||
let _title = 'My First Attribute Directive';
|
const title = 'My First Attribute Directive';
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should display correct title: ${_title}`, () => {
|
it(`should display correct title: ${title}`, () => {
|
||||||
expect(element(by.css('h1')).getText()).toEqual(_title);
|
expect(element(by.css('h1')).getText()).toEqual(title);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to select green highlight', () => {
|
it('should be able to select green highlight', () => {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
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 HLD1 } from './highlight.directive.1';
|
||||||
import { HighlightDirective as HLD2 } from './highlight.directive.2';
|
import { HighlightDirective as HLD2 } from './highlight.directive.2';
|
||||||
import { HighlightDirective as HLD3 } from './highlight.directive.3';
|
import { HighlightDirective as HLD3 } from './highlight.directive.3';
|
||||||
|
@ -3,57 +3,55 @@ import { logging } from 'selenium-webdriver';
|
|||||||
|
|
||||||
describe('Binding syntax e2e tests', () => {
|
describe('Binding syntax e2e tests', () => {
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(() => browser.get(''));
|
||||||
browser.get('');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// helper function used to test what's logged to the console
|
// helper function used to test what's logged to the console
|
||||||
async function logChecker(button, contents) {
|
async function logChecker(button, contents) {
|
||||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||||
const message = logs.filter(({ message }) => message.indexOf(contents) !== -1 ? true : false);
|
const messages = logs.filter(({ message }) => message.indexOf(contents) !== -1 ? true : false);
|
||||||
expect(message.length).toBeGreaterThan(0);
|
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');
|
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');
|
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');
|
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');
|
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');
|
expect(element.all(by.css('h3')).get(0).getText()).toBe('Disabled property vs. attribute');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should log a message including Sarah', async () => {
|
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();
|
await attributeButton.click();
|
||||||
const contents = 'Sarah';
|
const contents = 'Sarah';
|
||||||
logChecker(attributeButton, contents);
|
logChecker(attributeButton, contents);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should log a message including Sarah for DOM property', async () => {
|
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();
|
await DOMPropertyButton.click();
|
||||||
const contents = 'Sarah';
|
const contents = 'Sarah';
|
||||||
logChecker(DOMPropertyButton, contents);
|
logChecker(DOMPropertyButton, contents);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should log a message including Sally for DOM property', async () => {
|
it('should log a message including Sally for DOM property', async () => {
|
||||||
let DOMPropertyButton = element.all(by.css('button')).get(2);
|
const DOMPropertyButton = element.all(by.css('button')).get(2);
|
||||||
let input = element(by.css('input'));
|
const input = element(by.css('input'));
|
||||||
input.sendKeys('Sally');
|
input.sendKeys('Sally');
|
||||||
await DOMPropertyButton.click();
|
await DOMPropertyButton.click();
|
||||||
const contents = 'Sally';
|
const contents = 'Sally';
|
||||||
@ -61,14 +59,14 @@ describe('Binding syntax e2e tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should log a message that Test Button works', async () => {
|
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();
|
await testButton.click();
|
||||||
const contents = 'Test';
|
const contents = 'Test';
|
||||||
logChecker(testButton, contents);
|
logChecker(testButton, contents);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should toggle Test Button disabled', async () => {
|
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();
|
await toggleButton.click();
|
||||||
const contents = 'true';
|
const contents = 'true';
|
||||||
logChecker(toggleButton, contents);
|
logChecker(toggleButton, contents);
|
||||||
|
@ -26,7 +26,7 @@ export class AppComponent {
|
|||||||
|
|
||||||
toggleDisabled(): any {
|
toggleDisabled(): any {
|
||||||
|
|
||||||
let testButton = <HTMLInputElement> document.getElementById('testButton');
|
const testButton = document.getElementById('testButton') as HTMLInputElement;
|
||||||
testButton.disabled = !testButton.disabled;
|
testButton.disabled = !testButton.disabled;
|
||||||
console.warn(testButton.disabled);
|
console.warn(testButton.disabled);
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Built-in Directives', function () {
|
describe('Built-in Directives', () => {
|
||||||
|
|
||||||
beforeAll(function () {
|
beforeAll(() => {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have title Built-in Directives', function () {
|
it('should have title Built-in Directives', () => {
|
||||||
let title = element.all(by.css('h1')).get(0);
|
const title = element.all(by.css('h1')).get(0);
|
||||||
expect(title.getText()).toEqual('Built-in Directives');
|
expect(title.getText()).toEqual('Built-in Directives');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should change first Teapot header', async () => {
|
it('should change first Teapot header', async () => {
|
||||||
let firstLabel = element.all(by.css('p')).get(0);
|
const firstLabel = element.all(by.css('p')).get(0);
|
||||||
let firstInput = element.all(by.css('input')).get(0);
|
const firstInput = element.all(by.css('input')).get(0);
|
||||||
|
|
||||||
expect(firstLabel.getText()).toEqual('Current item name: Teapot');
|
expect(firstLabel.getText()).toEqual('Current item name: Teapot');
|
||||||
firstInput.sendKeys('abc');
|
firstInput.sendKeys('abc');
|
||||||
@ -23,49 +21,49 @@ describe('Built-in Directives', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should modify sentence when modified checkbox checked', function () {
|
it('should modify sentence when modified checkbox checked', () => {
|
||||||
let modifiedChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(1);
|
const modifiedChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(1);
|
||||||
let modifiedSentence = element.all(by.css('div')).get(1);
|
const modifiedSentence = element.all(by.css('div')).get(1);
|
||||||
|
|
||||||
modifiedChkbxLabel.click();
|
modifiedChkbxLabel.click();
|
||||||
expect(modifiedSentence.getText()).toContain('modified');
|
expect(modifiedSentence.getText()).toContain('modified');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should modify sentence when normal checkbox checked', function () {
|
it('should modify sentence when normal checkbox checked', () => {
|
||||||
let normalChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(4);
|
const normalChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(4);
|
||||||
let normalSentence = element.all(by.css('div')).get(7);
|
const normalSentence = element.all(by.css('div')).get(7);
|
||||||
|
|
||||||
normalChkbxLabel.click();
|
normalChkbxLabel.click();
|
||||||
expect(normalSentence.getText()).toContain('normal weight and, extra large');
|
expect(normalSentence.getText()).toContain('normal weight and, extra large');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should toggle app-item-detail', function () {
|
it('should toggle app-item-detail', () => {
|
||||||
let toggleButton = element.all(by.css('button')).get(3);
|
const toggleButton = element.all(by.css('button')).get(3);
|
||||||
let toggledDiv = element.all(by.css('app-item-detail')).get(0);
|
const toggledDiv = element.all(by.css('app-item-detail')).get(0);
|
||||||
|
|
||||||
toggleButton.click();
|
toggleButton.click();
|
||||||
expect(toggledDiv.isDisplayed()).toBe(true);
|
expect(toggledDiv.isDisplayed()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should hide app-item-detail', function () {
|
it('should hide app-item-detail', () => {
|
||||||
let hiddenMessage = element.all(by.css('p')).get(11);
|
const hiddenMessage = element.all(by.css('p')).get(11);
|
||||||
let hiddenDiv = element.all(by.css('app-item-detail')).get(2);
|
const hiddenDiv = element.all(by.css('app-item-detail')).get(2);
|
||||||
|
|
||||||
expect(hiddenMessage.getText()).toContain('in the DOM');
|
expect(hiddenMessage.getText()).toContain('in the DOM');
|
||||||
expect(hiddenDiv.isDisplayed()).toBe(true);
|
expect(hiddenDiv.isDisplayed()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have 10 lists each containing the string Teapot', function () {
|
it('should have 10 lists each containing the string Teapot', () => {
|
||||||
let listDiv = element.all(by.cssContainingText('.box', 'Teapot'));
|
const listDiv = element.all(by.cssContainingText('.box', 'Teapot'));
|
||||||
expect(listDiv.count()).toBe(10);
|
expect(listDiv.count()).toBe(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should switch case', function () {
|
it('should switch case', () => {
|
||||||
let tvRadioButton = element.all(by.css('input[type="radio"]')).get(3);
|
const tvRadioButton = element.all(by.css('input[type="radio"]')).get(3);
|
||||||
let tvDiv = element(by.css('app-lost-item'));
|
const tvDiv = element(by.css('app-lost-item'));
|
||||||
|
|
||||||
let fishbowlRadioButton = element.all(by.css('input[type="radio"]')).get(4);
|
const fishbowlRadioButton = element.all(by.css('input[type="radio"]')).get(4);
|
||||||
let fishbowlDiv = element(by.css('app-unknown-item'));
|
const fishbowlDiv = element(by.css('app-unknown-item'));
|
||||||
|
|
||||||
tvRadioButton.click();
|
tvRadioButton.click();
|
||||||
expect(tvDiv.getText()).toContain('Television');
|
expect(tvDiv.getText()).toContain('Television');
|
||||||
|
@ -30,6 +30,14 @@ export class AppComponent implements OnInit {
|
|||||||
itemsWithTrackByCountReset = 0;
|
itemsWithTrackByCountReset = 0;
|
||||||
itemIdIncrement = 1;
|
itemIdIncrement = 1;
|
||||||
|
|
||||||
|
// #docregion setClasses
|
||||||
|
currentClasses: {};
|
||||||
|
// #enddocregion setClasses
|
||||||
|
|
||||||
|
// #docregion setStyles
|
||||||
|
currentStyles: {};
|
||||||
|
// #enddocregion setStyles
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.resetItems();
|
this.resetItems();
|
||||||
this.setCurrentClasses();
|
this.setCurrentClasses();
|
||||||
@ -41,20 +49,18 @@ export class AppComponent implements OnInit {
|
|||||||
this.currentItem.name = name.toUpperCase();
|
this.currentItem.name = name.toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
// #docregion setClasses
|
// #docregion setClasses
|
||||||
currentClasses: {};
|
|
||||||
setCurrentClasses() {
|
setCurrentClasses() {
|
||||||
// CSS classes: added/removed per current state of component properties
|
// CSS classes: added/removed per current state of component properties
|
||||||
this.currentClasses = {
|
this.currentClasses = {
|
||||||
'saveable': this.canSave,
|
saveable: this.canSave,
|
||||||
'modified': !this.isUnchanged,
|
modified: !this.isUnchanged,
|
||||||
'special': this.isSpecial
|
special: this.isSpecial
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// #enddocregion setClasses
|
// #enddocregion setClasses
|
||||||
|
|
||||||
// #docregion setStyles
|
// #docregion setStyles
|
||||||
currentStyles: {};
|
|
||||||
setCurrentStyles() {
|
setCurrentStyles() {
|
||||||
// CSS styles: set per current state of component properties
|
// CSS styles: set per current state of component properties
|
||||||
this.currentStyles = {
|
this.currentStyles = {
|
||||||
@ -70,11 +76,7 @@ export class AppComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
giveNullCustomerValue() {
|
giveNullCustomerValue() {
|
||||||
!(this.nullCustomer = null) ? (this.nullCustomer = 'Kelly') : (this.nullCustomer = null);
|
this.nullCustomer = 'Kelly';
|
||||||
}
|
|
||||||
|
|
||||||
resetNullItem() {
|
|
||||||
this.nullCustomer = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resetItems() {
|
resetItems() {
|
||||||
@ -84,7 +86,7 @@ export class AppComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resetList() {
|
resetList() {
|
||||||
this.resetItems()
|
this.resetItems();
|
||||||
this.itemsWithTrackByCountReset = 0;
|
this.itemsWithTrackByCountReset = 0;
|
||||||
this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
|
this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
|
||||||
}
|
}
|
||||||
@ -107,7 +109,7 @@ export class AppComponent implements OnInit {
|
|||||||
trackByItems(index: number, item: Item): number { return item.id; }
|
trackByItems(index: number, item: Item): number { return item.id; }
|
||||||
// #enddocregion trackByItems
|
// #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';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Built Template Functions Example', function () {
|
describe('Built Template Functions Example', () => {
|
||||||
beforeAll(function () {
|
beforeAll(() => {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have title Built-in Template Functions', function () {
|
it('should have title Built-in Template Functions', () => {
|
||||||
let title = element.all(by.css('h1')).get(0);
|
const title = element.all(by.css('h1')).get(0);
|
||||||
expect(title.getText()).toEqual('Built-in Template Functions');
|
expect(title.getText()).toEqual('Built-in Template Functions');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display $any( ) in h2', function () {
|
it('should display $any( ) in h2', () => {
|
||||||
let header = element(by.css('h2'));
|
const header = element(by.css('h2'));
|
||||||
expect(header.getText()).toContain('$any( )');
|
expect(header.getText()).toContain('$any( )');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,87 +1,85 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
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
|
// Note: '?e2e' which app can read to know it is running in protractor
|
||||||
// e.g. `if (!/e2e/.test(location.search)) { ...`
|
// e.g. `if (!/e2e/.test(location.search)) { ...`
|
||||||
beforeAll(function () {
|
beforeAll(() => {
|
||||||
browser.get('?e2e');
|
browser.get('?e2e');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Parent-to-child communication', function() {
|
describe('Parent-to-child communication', () => {
|
||||||
// #docregion parent-to-child
|
// #docregion parent-to-child
|
||||||
// ...
|
// ...
|
||||||
let _heroNames = ['Dr IQ', 'Magneta', 'Bombasto'];
|
const heroNames = ['Dr IQ', 'Magneta', 'Bombasto'];
|
||||||
let _masterName = 'Master';
|
const masterName = 'Master';
|
||||||
|
|
||||||
it('should pass properties to children properly', function () {
|
it('should pass properties to children properly', () => {
|
||||||
let parent = element.all(by.tagName('app-hero-parent')).get(0);
|
const parent = element.all(by.tagName('app-hero-parent')).get(0);
|
||||||
let heroes = parent.all(by.tagName('app-hero-child'));
|
const heroes = parent.all(by.tagName('app-hero-child'));
|
||||||
|
|
||||||
for (let i = 0; i < _heroNames.length; i++) {
|
for (let i = 0; i < heroNames.length; i++) {
|
||||||
let childTitle = heroes.get(i).element(by.tagName('h3')).getText();
|
const childTitle = heroes.get(i).element(by.tagName('h3')).getText();
|
||||||
let childDetail = heroes.get(i).element(by.tagName('p')).getText();
|
const childDetail = heroes.get(i).element(by.tagName('p')).getText();
|
||||||
expect(childTitle).toEqual(_heroNames[i] + ' says:');
|
expect(childTitle).toEqual(heroNames[i] + ' says:');
|
||||||
expect(childDetail).toContain(_masterName);
|
expect(childDetail).toContain(masterName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// ...
|
// ...
|
||||||
// #enddocregion parent-to-child
|
// #enddocregion parent-to-child
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Parent-to-child communication with setter', function() {
|
describe('Parent-to-child communication with setter', () => {
|
||||||
// #docregion parent-to-child-setter
|
// #docregion parent-to-child-setter
|
||||||
// ...
|
// ...
|
||||||
it('should display trimmed, non-empty names', function () {
|
it('should display trimmed, non-empty names', () => {
|
||||||
let _nonEmptyNameIndex = 0;
|
const nonEmptyNameIndex = 0;
|
||||||
let _nonEmptyName = '"Dr IQ"';
|
const nonEmptyName = '"Dr IQ"';
|
||||||
let parent = element.all(by.tagName('app-name-parent')).get(0);
|
const parent = element.all(by.tagName('app-name-parent')).get(0);
|
||||||
let hero = parent.all(by.tagName('app-name-child')).get(_nonEmptyNameIndex);
|
const hero = parent.all(by.tagName('app-name-child')).get(nonEmptyNameIndex);
|
||||||
|
|
||||||
let displayName = hero.element(by.tagName('h3')).getText();
|
const displayName = hero.element(by.tagName('h3')).getText();
|
||||||
expect(displayName).toEqual(_nonEmptyName);
|
expect(displayName).toEqual(nonEmptyName);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should replace empty name with default name', function () {
|
it('should replace empty name with default name', () => {
|
||||||
let _emptyNameIndex = 1;
|
const emptyNameIndex = 1;
|
||||||
let _defaultName = '"<no name set>"';
|
const defaultName = '"<no name set>"';
|
||||||
let parent = element.all(by.tagName('app-name-parent')).get(0);
|
const parent = element.all(by.tagName('app-name-parent')).get(0);
|
||||||
let hero = parent.all(by.tagName('app-name-child')).get(_emptyNameIndex);
|
const hero = parent.all(by.tagName('app-name-child')).get(emptyNameIndex);
|
||||||
|
|
||||||
let displayName = hero.element(by.tagName('h3')).getText();
|
const displayName = hero.element(by.tagName('h3')).getText();
|
||||||
expect(displayName).toEqual(_defaultName);
|
expect(displayName).toEqual(defaultName);
|
||||||
});
|
});
|
||||||
// ...
|
// ...
|
||||||
// #enddocregion parent-to-child-setter
|
// #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
|
// #docregion parent-to-child-onchanges
|
||||||
// ...
|
// ...
|
||||||
// Test must all execute in this exact order
|
// Test must all execute in this exact order
|
||||||
it('should set expected initial values', function () {
|
it('should set expected initial values', () => {
|
||||||
let actual = getActual();
|
const actual = getActual();
|
||||||
|
|
||||||
let initialLabel = 'Version 1.23';
|
const initialLabel = 'Version 1.23';
|
||||||
let initialLog = 'Initial value of major set to 1, Initial value of minor set to 23';
|
const initialLog = 'Initial value of major set to 1, Initial value of minor set to 23';
|
||||||
|
|
||||||
expect(actual.label).toBe(initialLabel);
|
expect(actual.label).toBe(initialLabel);
|
||||||
expect(actual.count).toBe(1);
|
expect(actual.count).toBe(1);
|
||||||
expect(actual.logs.get(0).getText()).toBe(initialLog);
|
expect(actual.logs.get(0).getText()).toBe(initialLog);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set expected values after clicking \'Minor\' twice', function () {
|
it('should set expected values after clicking \'Minor\' twice', () => {
|
||||||
let repoTag = element(by.tagName('app-version-parent'));
|
const repoTag = element(by.tagName('app-version-parent'));
|
||||||
let newMinorButton = repoTag.all(by.tagName('button')).get(0);
|
const newMinorButton = repoTag.all(by.tagName('button')).get(0);
|
||||||
|
|
||||||
newMinorButton.click().then(function() {
|
newMinorButton.click().then(() => {
|
||||||
newMinorButton.click().then(function() {
|
newMinorButton.click().then(() => {
|
||||||
let actual = getActual();
|
const actual = getActual();
|
||||||
|
|
||||||
let labelAfter2Minor = 'Version 1.25';
|
const labelAfter2Minor = 'Version 1.25';
|
||||||
let logAfter2Minor = 'minor changed from 24 to 25';
|
const logAfter2Minor = 'minor changed from 24 to 25';
|
||||||
|
|
||||||
expect(actual.label).toBe(labelAfter2Minor);
|
expect(actual.label).toBe(labelAfter2Minor);
|
||||||
expect(actual.count).toBe(3);
|
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 () {
|
it('should set expected values after clicking \'Major\' once', () => {
|
||||||
let repoTag = element(by.tagName('app-version-parent'));
|
const repoTag = element(by.tagName('app-version-parent'));
|
||||||
let newMajorButton = repoTag.all(by.tagName('button')).get(1);
|
const newMajorButton = repoTag.all(by.tagName('button')).get(1);
|
||||||
|
|
||||||
newMajorButton.click().then(function() {
|
newMajorButton.click().then(() => {
|
||||||
let actual = getActual();
|
const actual = getActual();
|
||||||
|
|
||||||
let labelAfterMajor = 'Version 2.0';
|
const labelAfterMajor = 'Version 2.0';
|
||||||
let logAfterMajor = 'major changed from 1 to 2, minor changed from 25 to 0';
|
const logAfterMajor = 'major changed from 1 to 2, minor changed from 25 to 0';
|
||||||
|
|
||||||
expect(actual.label).toBe(labelAfterMajor);
|
expect(actual.label).toBe(labelAfterMajor);
|
||||||
expect(actual.count).toBe(4);
|
expect(actual.count).toBe(4);
|
||||||
@ -107,14 +105,14 @@ describe('Component Communication Cookbook Tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function getActual() {
|
function getActual() {
|
||||||
let versionTag = element(by.tagName('app-version-child'));
|
const versionTag = element(by.tagName('app-version-child'));
|
||||||
let label = versionTag.element(by.tagName('h3')).getText();
|
const label = versionTag.element(by.tagName('h3')).getText();
|
||||||
let ul = versionTag.element((by.tagName('ul')));
|
const ul = versionTag.element((by.tagName('ul')));
|
||||||
let logs = ul.all(by.tagName('li'));
|
const logs = ul.all(by.tagName('li'));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
label: label,
|
label,
|
||||||
logs: logs,
|
logs,
|
||||||
count: logs.count()
|
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
|
// #docregion child-to-parent
|
||||||
// ...
|
// ...
|
||||||
it('should not emit the event initially', function () {
|
it('should not emit the event initially', () => {
|
||||||
let voteLabel = element(by.tagName('app-vote-taker'))
|
const voteLabel = element(by.tagName('app-vote-taker'))
|
||||||
.element(by.tagName('h3')).getText();
|
.element(by.tagName('h3')).getText();
|
||||||
expect(voteLabel).toBe('Agree: 0, Disagree: 0');
|
expect(voteLabel).toBe('Agree: 0, Disagree: 0');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should process Agree vote', function () {
|
it('should process Agree vote', () => {
|
||||||
let agreeButton1 = element.all(by.tagName('app-voter')).get(0)
|
const agreeButton1 = element.all(by.tagName('app-voter')).get(0)
|
||||||
.all(by.tagName('button')).get(0);
|
.all(by.tagName('button')).get(0);
|
||||||
agreeButton1.click().then(function() {
|
agreeButton1.click().then(() => {
|
||||||
let voteLabel = element(by.tagName('app-vote-taker'))
|
const voteLabel = element(by.tagName('app-vote-taker'))
|
||||||
.element(by.tagName('h3')).getText();
|
.element(by.tagName('h3')).getText();
|
||||||
expect(voteLabel).toBe('Agree: 1, Disagree: 0');
|
expect(voteLabel).toBe('Agree: 1, Disagree: 0');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should process Disagree vote', function () {
|
it('should process Disagree vote', () => {
|
||||||
let agreeButton1 = element.all(by.tagName('app-voter')).get(1)
|
const agreeButton1 = element.all(by.tagName('app-voter')).get(1)
|
||||||
.all(by.tagName('button')).get(1);
|
.all(by.tagName('button')).get(1);
|
||||||
agreeButton1.click().then(function() {
|
agreeButton1.click().then(() => {
|
||||||
let voteLabel = element(by.tagName('app-vote-taker'))
|
const voteLabel = element(by.tagName('app-vote-taker'))
|
||||||
.element(by.tagName('h3')).getText();
|
.element(by.tagName('h3')).getText();
|
||||||
expect(voteLabel).toBe('Agree: 1, Disagree: 1');
|
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
|
// Can't run timer tests in protractor because
|
||||||
// interaction w/ zones causes all tests to freeze & timeout.
|
// 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');
|
countDownTimerTests('countdown-parent-lv');
|
||||||
});
|
});
|
||||||
|
|
||||||
xdescribe('Parent calls ViewChild', function() {
|
xdescribe('Parent calls ViewChild', () => {
|
||||||
countDownTimerTests('countdown-parent-vc');
|
countDownTimerTests('countdown-parent-vc');
|
||||||
});
|
});
|
||||||
|
|
||||||
function countDownTimerTests(parentTag: string) {
|
function countDownTimerTests(parentTag: string) {
|
||||||
// #docregion countdown-timer-tests
|
// #docregion countdown-timer-tests
|
||||||
// ...
|
// ...
|
||||||
it('timer and parent seconds should match', function () {
|
it('timer and parent seconds should match', () => {
|
||||||
let parent = element(by.tagName(parentTag));
|
const parent = element(by.tagName(parentTag));
|
||||||
let message = parent.element(by.tagName('app-countdown-timer')).getText();
|
const message = parent.element(by.tagName('app-countdown-timer')).getText();
|
||||||
browser.sleep(10); // give `seconds` a chance to catchup with `message`
|
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);
|
expect(message).toContain(seconds);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should stop the countdown', function () {
|
it('should stop the countdown', () => {
|
||||||
let parent = element(by.tagName(parentTag));
|
const parent = element(by.tagName(parentTag));
|
||||||
let stopButton = parent.all(by.tagName('button')).get(1);
|
const stopButton = parent.all(by.tagName('button')).get(1);
|
||||||
|
|
||||||
stopButton.click().then(function() {
|
stopButton.click().then(() => {
|
||||||
let message = parent.element(by.tagName('app-countdown-timer')).getText();
|
const message = parent.element(by.tagName('app-countdown-timer')).getText();
|
||||||
expect(message).toContain('Holding');
|
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
|
// #docregion bidirectional-service
|
||||||
// ...
|
// ...
|
||||||
it('should announce a mission', function () {
|
it('should announce a mission', () => {
|
||||||
let missionControl = element(by.tagName('app-mission-control'));
|
const missionControl = element(by.tagName('app-mission-control'));
|
||||||
let announceButton = missionControl.all(by.tagName('button')).get(0);
|
const announceButton = missionControl.all(by.tagName('button')).get(0);
|
||||||
announceButton.click().then(function () {
|
announceButton.click().then(() => {
|
||||||
let history = missionControl.all(by.tagName('li'));
|
const history = missionControl.all(by.tagName('li'));
|
||||||
expect(history.count()).toBe(1);
|
expect(history.count()).toBe(1);
|
||||||
expect(history.get(0).getText()).toMatch(/Mission.* announced/);
|
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');
|
testConfirmMission(1, 2, 'Lovell');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should confirm the mission by Haise', function () {
|
it('should confirm the mission by Haise', () => {
|
||||||
testConfirmMission(3, 3, 'Haise');
|
testConfirmMission(3, 3, 'Haise');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should confirm the mission by Swigert', function () {
|
it('should confirm the mission by Swigert', () => {
|
||||||
testConfirmMission(2, 4, 'Swigert');
|
testConfirmMission(2, 4, 'Swigert');
|
||||||
});
|
});
|
||||||
|
|
||||||
function testConfirmMission(buttonIndex: number, expectedLogCount: number, astronaut: string) {
|
function testConfirmMission(buttonIndex: number, expectedLogCount: number, astronaut: string) {
|
||||||
let _confirmedLog = ' confirmed the mission';
|
const confirmedLog = ' confirmed the mission';
|
||||||
let missionControl = element(by.tagName('app-mission-control'));
|
const missionControl = element(by.tagName('app-mission-control'));
|
||||||
let confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex);
|
const confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex);
|
||||||
confirmButton.click().then(function () {
|
confirmButton.click().then(() => {
|
||||||
let history = missionControl.all(by.tagName('li'));
|
const history = missionControl.all(by.tagName('li'));
|
||||||
expect(history.count()).toBe(expectedLogCount);
|
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 { 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 { AppComponent } from './app.component';
|
||||||
import { AstronautComponent } from './astronaut.component';
|
import { AstronautComponent } from './astronaut.component';
|
||||||
@ -15,7 +15,7 @@ import { VersionParentComponent } from './version-parent.component';
|
|||||||
import { VoterComponent } from './voter.component';
|
import { VoterComponent } from './voter.component';
|
||||||
import { VoteTakerComponent } from './votetaker.component';
|
import { VoteTakerComponent } from './votetaker.component';
|
||||||
|
|
||||||
let directives: any[] = [
|
const directives: any[] = [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
AstronautComponent,
|
AstronautComponent,
|
||||||
CountdownTimerComponent,
|
CountdownTimerComponent,
|
||||||
@ -30,7 +30,7 @@ let directives: any[] = [
|
|||||||
VoteTakerComponent
|
VoteTakerComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
let schemas: any[] = [];
|
const schemas: any[] = [];
|
||||||
|
|
||||||
// Include Countdown examples
|
// Include Countdown examples
|
||||||
// unless in e2e tests which they break.
|
// unless in e2e tests which they break.
|
||||||
@ -49,6 +49,6 @@ if (!/e2e/.test(location.search)) {
|
|||||||
],
|
],
|
||||||
declarations: directives,
|
declarations: directives,
|
||||||
bootstrap: [ AppComponent ],
|
bootstrap: [ AppComponent ],
|
||||||
schemas: schemas
|
schemas
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { Component, Input, OnDestroy } from '@angular/core';
|
import { Component, Input, OnDestroy } from '@angular/core';
|
||||||
|
|
||||||
import { MissionService } from './mission.service';
|
import { MissionService } from './mission.service';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-astronaut',
|
selector: 'app-astronaut',
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
// #docregion vc
|
// #docregion vc
|
||||||
import { AfterViewInit, ViewChild } from '@angular/core';
|
import { AfterViewInit, ViewChild } from '@angular/core';
|
||||||
// #docregion lv
|
// #docregion lv
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { CountdownTimerComponent } from './countdown-timer.component';
|
import { CountdownTimerComponent } from './countdown-timer.component';
|
||||||
|
|
||||||
// #enddocregion lv
|
// #enddocregion lv
|
||||||
// #enddocregion vc
|
// #enddocregion vc
|
||||||
|
@ -12,6 +12,6 @@ import { Hero } from './hero';
|
|||||||
})
|
})
|
||||||
export class HeroChildComponent {
|
export class HeroChildComponent {
|
||||||
@Input() hero: Hero;
|
@Input() hero: Hero;
|
||||||
@Input('master') masterName: string;
|
@Input('master') masterName: string; // tslint:disable-line: no-input-rename
|
||||||
}
|
}
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MissionService {
|
export class MissionService {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
import { MissionService } from './mission.service';
|
import { MissionService } from './mission.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-mission-control',
|
selector: 'app-mission-control',
|
||||||
@ -34,7 +34,7 @@ export class MissionControlComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
announce() {
|
announce() {
|
||||||
let mission = this.missions[this.nextMission++];
|
const mission = this.missions[this.nextMission++];
|
||||||
this.missionService.announceMission(mission);
|
this.missionService.announceMission(mission);
|
||||||
this.history.push(`Mission "${mission}" announced`);
|
this.history.push(`Mission "${mission}" announced`);
|
||||||
if (this.nextMission >= this.missions.length) { this.nextMission = 0; }
|
if (this.nextMission >= this.missions.length) { this.nextMission = 0; }
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// tslint:disable: variable-name
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
@ -6,13 +7,11 @@ import { Component, Input } from '@angular/core';
|
|||||||
template: '<h3>"{{name}}"</h3>'
|
template: '<h3>"{{name}}"</h3>'
|
||||||
})
|
})
|
||||||
export class NameChildComponent {
|
export class NameChildComponent {
|
||||||
private _name = '';
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
|
get name(): string { return this._name; }
|
||||||
set name(name: string) {
|
set name(name: string) {
|
||||||
this._name = (name && name.trim()) || '<no name set>';
|
this._name = (name && name.trim()) || '<no name set>';
|
||||||
}
|
}
|
||||||
|
private _name = '';
|
||||||
get name(): string { return this._name; }
|
|
||||||
}
|
}
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
@ -18,14 +18,14 @@ export class VersionChildComponent implements OnChanges {
|
|||||||
changeLog: string[] = [];
|
changeLog: string[] = [];
|
||||||
|
|
||||||
ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
|
ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
|
||||||
let log: string[] = [];
|
const log: string[] = [];
|
||||||
for (let propName in changes) {
|
for (const propName in changes) {
|
||||||
let changedProp = changes[propName];
|
const changedProp = changes[propName];
|
||||||
let to = JSON.stringify(changedProp.currentValue);
|
const to = JSON.stringify(changedProp.currentValue);
|
||||||
if (changedProp.isFirstChange()) {
|
if (changedProp.isFirstChange()) {
|
||||||
log.push(`Initial value of ${propName} set to ${to}`);
|
log.push(`Initial value of ${propName} set to ${to}`);
|
||||||
} else {
|
} else {
|
||||||
let from = JSON.stringify(changedProp.previousValue);
|
const from = JSON.stringify(changedProp.previousValue);
|
||||||
log.push(`${propName} changed from ${from} to ${to}`);
|
log.push(`${propName} changed from ${from} to ${to}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-vote-taker',
|
selector: 'app-vote-taker',
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Component Style Tests', function () {
|
describe('Component Style Tests', () => {
|
||||||
|
|
||||||
beforeAll(function () {
|
beforeAll(() => {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('scopes component styles to component view', function() {
|
it('scopes component styles to component view', () => {
|
||||||
let componentH1 = element(by.css('app-root > h1'));
|
const componentH1 = element(by.css('app-root > h1'));
|
||||||
let externalH1 = element(by.css('body > h1'));
|
const externalH1 = element(by.css('body > h1'));
|
||||||
|
|
||||||
// Note: sometimes webdriver returns the fontWeight as "normal",
|
// Note: sometimes webdriver returns the fontWeight as "normal",
|
||||||
// other times as "400", both of which are equal in CSS terms.
|
// 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() {
|
it('allows styling :host element', () => {
|
||||||
let host = element(by.css('app-hero-details'));
|
const host = element(by.css('app-hero-details'));
|
||||||
|
|
||||||
expect(host.getCssValue('borderWidth')).toEqual('1px');
|
expect(host.getCssValue('borderWidth')).toEqual('1px');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('supports :host() in function form', function() {
|
it('supports :host() in function form', () => {
|
||||||
let host = element(by.css('app-hero-details'));
|
const host = element(by.css('app-hero-details'));
|
||||||
|
|
||||||
host.element(by.buttonText('Activate')).click();
|
host.element(by.buttonText('Activate')).click();
|
||||||
expect(host.getCssValue('borderWidth')).toEqual('3px');
|
expect(host.getCssValue('borderWidth')).toEqual('3px');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows conditional :host-context() styling', function() {
|
it('allows conditional :host-context() styling', () => {
|
||||||
let h2 = element(by.css('app-hero-details h2'));
|
const h2 = element(by.css('app-hero-details h2'));
|
||||||
|
|
||||||
expect(h2.getCssValue('backgroundColor')).toEqual('rgba(238, 238, 255, 1)'); // #eeeeff
|
expect(h2.getCssValue('backgroundColor')).toEqual('rgba(238, 238, 255, 1)'); // #eeeeff
|
||||||
});
|
});
|
||||||
|
|
||||||
it('styles both view and content children with /deep/', function() {
|
it('styles both view and content children with /deep/', () => {
|
||||||
let viewH3 = element(by.css('app-hero-team h3'));
|
const viewH3 = element(by.css('app-hero-team h3'));
|
||||||
let contentH3 = element(by.css('app-hero-controls h3'));
|
const contentH3 = element(by.css('app-hero-controls h3'));
|
||||||
|
|
||||||
expect(viewH3.getCssValue('fontStyle')).toEqual('italic');
|
expect(viewH3.getCssValue('fontStyle')).toEqual('italic');
|
||||||
expect(contentH3.getCssValue('fontStyle')).toEqual('italic');
|
expect(contentH3.getCssValue('fontStyle')).toEqual('italic');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('includes styles loaded with CSS @import', function() {
|
it('includes styles loaded with CSS @import', () => {
|
||||||
let host = element(by.css('app-hero-details'));
|
const host = element(by.css('app-hero-details'));
|
||||||
|
|
||||||
expect(host.getCssValue('padding')).toEqual('10px');
|
expect(host.getCssValue('padding')).toEqual('10px');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('processes template inline styles', function() {
|
it('processes template inline styles', () => {
|
||||||
let button = element(by.css('app-hero-controls button'));
|
const button = element(by.css('app-hero-controls button'));
|
||||||
let externalButton = element(by.css('body > button'));
|
const externalButton = element(by.css('body > button'));
|
||||||
expect(button.getCssValue('backgroundColor')).toEqual('rgba(255, 255, 255, 1)'); // #ffffff
|
expect(button.getCssValue('backgroundColor')).toEqual('rgba(255, 255, 255, 1)'); // #ffffff
|
||||||
expect(externalButton.getCssValue('backgroundColor')).not.toEqual('rgba(255, 255, 255, 1)');
|
expect(externalButton.getCssValue('backgroundColor')).not.toEqual('rgba(255, 255, 255, 1)');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('processes template <link>s', function() {
|
it('processes template <link>s', () => {
|
||||||
let li = element(by.css('app-hero-team li:first-child'));
|
const li = element(by.css('app-hero-team li:first-child'));
|
||||||
let externalLi = element(by.css('body > ul li'));
|
const externalLi = element(by.css('body > ul li'));
|
||||||
|
|
||||||
expect(li.getCssValue('listStyleType')).toEqual('square');
|
expect(li.getCssValue('listStyleType')).toEqual('square');
|
||||||
expect(externalLi.getCssValue('listStyleType')).not.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';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Dependency Injection Cookbook', function () {
|
describe('Dependency Injection Cookbook', () => {
|
||||||
|
|
||||||
beforeAll(function () {
|
beforeAll(() => {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render Logged in User example', function () {
|
it('should render Logged in User example', () => {
|
||||||
let loggedInUser = element.all(by.xpath('//h3[text()="Logged in user"]')).get(0);
|
const loggedInUser = element.all(by.xpath('//h3[text()="Logged in user"]')).get(0);
|
||||||
expect(loggedInUser).toBeDefined();
|
expect(loggedInUser).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('"Bombasto" should be the logged in user', function () {
|
it('"Bombasto" should be the logged in user', () => {
|
||||||
let loggedInUser = element.all(by.xpath('//div[text()="Name: Bombasto"]')).get(0);
|
const loggedInUser = element.all(by.xpath('//div[text()="Name: Bombasto"]')).get(0);
|
||||||
expect(loggedInUser).toBeDefined();
|
expect(loggedInUser).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render sorted heroes', function () {
|
it('should render sorted heroes', () => {
|
||||||
let sortedHeroes = element.all(by.xpath('//h3[text()="Sorted Heroes" and position()=1]')).get(0);
|
const sortedHeroes = element.all(by.xpath('//h3[text()="Sorted Heroes" and position()=1]')).get(0);
|
||||||
expect(sortedHeroes).toBeDefined();
|
expect(sortedHeroes).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Dr Nice should be in sorted heroes', function () {
|
it('Dr Nice should be in sorted heroes', () => {
|
||||||
let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Dr Nice" and position()=2]')).get(0);
|
const sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Dr Nice" and position()=2]')).get(0);
|
||||||
expect(sortedHero).toBeDefined();
|
expect(sortedHero).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('RubberMan should be in sorted heroes', function () {
|
it('RubberMan should be in sorted heroes', () => {
|
||||||
let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="RubberMan" and position()=3]')).get(0);
|
const sortedHero = element.all(by.xpath('//sorted-heroes/[text()="RubberMan" and position()=3]')).get(0);
|
||||||
expect(sortedHero).toBeDefined();
|
expect(sortedHero).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Magma should be in sorted heroes', function () {
|
it('Magma should be in sorted heroes', () => {
|
||||||
let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Magma"]')).get(0);
|
const sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Magma"]')).get(0);
|
||||||
expect(sortedHero).toBeDefined();
|
expect(sortedHero).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render Hero of the Month', function () {
|
it('should render Hero of the Month', () => {
|
||||||
let heroOfTheMonth = element.all(by.xpath('//h3[text()="Hero of the month"]')).get(0);
|
const heroOfTheMonth = element.all(by.xpath('//h3[text()="Hero of the month"]')).get(0);
|
||||||
expect(heroOfTheMonth).toBeDefined();
|
expect(heroOfTheMonth).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render Hero Bios', function () {
|
it('should render Hero Bios', () => {
|
||||||
let heroBios = element.all(by.xpath('//h3[text()="Hero Bios"]')).get(0);
|
const heroBios = element.all(by.xpath('//h3[text()="Hero Bios"]')).get(0);
|
||||||
expect(heroBios).toBeDefined();
|
expect(heroBios).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render Magma\'s description in Hero Bios', function () {
|
it('should render Magma\'s description in Hero Bios', () => {
|
||||||
let magmaText = element.all(by.xpath('//textarea[text()="Hero of all trades"]')).get(0);
|
const magmaText = element.all(by.xpath('//textarea[text()="Hero of all trades"]')).get(0);
|
||||||
expect(magmaText).toBeDefined();
|
expect(magmaText).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render Magma\'s phone in Hero Bios and Contacts', function () {
|
it('should render Magma\'s phone in Hero Bios and Contacts', () => {
|
||||||
let magmaPhone = element.all(by.xpath('//div[text()="Phone #: 555-555-5555"]')).get(0);
|
const magmaPhone = element.all(by.xpath('//div[text()="Phone #: 555-555-5555"]')).get(0);
|
||||||
expect(magmaPhone).toBeDefined();
|
expect(magmaPhone).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render Hero-of-the-Month runner-ups', function () {
|
it('should render Hero-of-the-Month runner-ups', () => {
|
||||||
let runnersUp = element(by.id('rups1')).getText();
|
const runnersUp = element(by.id('rups1')).getText();
|
||||||
expect(runnersUp).toContain('RubberMan, Dr Nice');
|
expect(runnersUp).toContain('RubberMan, Dr Nice');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render DateLogger log entry in Hero-of-the-Month', function () {
|
it('should render DateLogger log entry in Hero-of-the-Month', () => {
|
||||||
let logs = element.all(by.id('logs')).get(0).getText();
|
const logs = element.all(by.id('logs')).get(0).getText();
|
||||||
expect(logs).toContain('INFO: starting up at');
|
expect(logs).toContain('INFO: starting up at');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should highlight Hero Bios and Contacts container when mouseover', function () {
|
it('should highlight Hero Bios and Contacts container when mouseover', () => {
|
||||||
let target = element(by.css('div[appHighlight="yellow"]'));
|
const target = element(by.css('div[appHighlight="yellow"]'));
|
||||||
let yellow = 'rgba(255, 255, 0, 1)';
|
const yellow = 'rgba(255, 255, 0, 1)';
|
||||||
|
|
||||||
expect(target.getCssValue('background-color')).not.toEqual(yellow);
|
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);
|
browser.wait(() => target.getCssValue('background-color').then(c => c === yellow), 2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('in Parent Finder', function () {
|
describe('in Parent Finder', () => {
|
||||||
let cathy1 = element(by.css('alex cathy'));
|
const cathy1 = element(by.css('alex cathy'));
|
||||||
let craig1 = element(by.css('alex craig'));
|
const craig1 = element(by.css('alex craig'));
|
||||||
let carol1 = element(by.css('alex carol p'));
|
const carol1 = element(by.css('alex carol p'));
|
||||||
let carol2 = element(by.css('barry 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');
|
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');
|
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');
|
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');
|
expect(carol2.getText()).toContain('Barry');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
const routes: Routes = [];
|
const routes: Routes = [];
|
||||||
|
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
// #docregion import-services
|
// #docregion import-services
|
||||||
import { LoggerService } from './logger.service';
|
import { LoggerService } from './logger.service';
|
||||||
import { UserContextService } from './user-context.service';
|
import { UserContextService } from './user-context.service';
|
||||||
import { UserService } from './user.service';
|
import { UserService } from './user.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
|
||||||
// import { AppRoutingModule } from './app-routing.module';
|
// import { AppRoutingModule } from './app-routing.module';
|
||||||
import { LocationStrategy,
|
import { LocationStrategy,
|
||||||
HashLocationStrategy } from '@angular/common';
|
HashLocationStrategy } from '@angular/common';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
import { HeroData } from './hero-data';
|
import { HeroData } from './hero-data';
|
||||||
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
|
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
|
||||||
|
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { HeroBioComponent } from './hero-bio.component';
|
import { HeroBioComponent } from './hero-bio.component';
|
||||||
import { HeroBiosComponent,
|
import { HeroBiosComponent,
|
||||||
HeroBiosAndContactsComponent } from './hero-bios.component';
|
HeroBiosAndContactsComponent } from './hero-bios.component';
|
||||||
import { HeroOfTheMonthComponent } from './hero-of-the-month.component';
|
import { HeroOfTheMonthComponent } from './hero-of-the-month.component';
|
||||||
import { HeroContactComponent } from './hero-contact.component';
|
import { HeroContactComponent } from './hero-contact.component';
|
||||||
import { HeroesBaseComponent,
|
import { HeroesBaseComponent,
|
||||||
SortedHeroesComponent } from './sorted-heroes.component';
|
SortedHeroesComponent } from './sorted-heroes.component';
|
||||||
import { HighlightDirective } from './highlight.directive';
|
import { HighlightDirective } from './highlight.directive';
|
||||||
import { ParentFinderComponent,
|
import { ParentFinderComponent,
|
||||||
AlexComponent,
|
AlexComponent,
|
||||||
AliceComponent,
|
AliceComponent,
|
||||||
@ -30,8 +30,8 @@ import { ParentFinderComponent,
|
|||||||
CathyComponent,
|
CathyComponent,
|
||||||
BarryComponent,
|
BarryComponent,
|
||||||
BethComponent,
|
BethComponent,
|
||||||
BobComponent } from './parent-finder.component';
|
BobComponent } from './parent-finder.component';
|
||||||
import { StorageComponent } from './storage.component';
|
import { StorageComponent } from './storage.component';
|
||||||
|
|
||||||
const declarations = [
|
const declarations = [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
@ -42,11 +42,11 @@ const declarations = [
|
|||||||
ParentFinderComponent,
|
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,
|
CarolComponent, ChrisComponent, CraigComponent,
|
||||||
CathyComponent
|
CathyComponent
|
||||||
];
|
];
|
||||||
@ -61,9 +61,9 @@ const c_components = [
|
|||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
declarations,
|
declarations,
|
||||||
a_components,
|
componentListA,
|
||||||
b_components,
|
componentListB,
|
||||||
c_components,
|
componentListC,
|
||||||
StorageComponent,
|
StorageComponent,
|
||||||
],
|
],
|
||||||
bootstrap: [ AppComponent ],
|
bootstrap: [ AppComponent ],
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* tslint:disable:one-line*/
|
/* tslint:disable:one-line*/
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { LoggerService } from './logger.service';
|
import { LoggerService } from './logger.service';
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
|
||||||
import { HeroCacheService } from './hero-cache.service';
|
import { HeroCacheService } from './hero-cache.service';
|
||||||
|
|
||||||
// #docregion component
|
// #docregion component
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
import { HeroService } from './hero.service';
|
import { HeroService } from './hero.service';
|
||||||
import { LoggerService } from './logger.service';
|
import { LoggerService } from './logger.service';
|
||||||
|
|
||||||
//////// HeroBiosComponent ////
|
//////// HeroBiosComponent ////
|
||||||
// #docregion simple
|
// #docregion simple
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
import { HeroService } from './hero.service';
|
import { HeroService } from './hero.service';
|
||||||
|
|
||||||
// #docregion service
|
// #docregion service
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import { Component, Host, Optional } from '@angular/core';
|
import { Component, Host, Optional } from '@angular/core';
|
||||||
|
|
||||||
import { HeroCacheService } from './hero-cache.service';
|
import { HeroCacheService } from './hero-cache.service';
|
||||||
import { LoggerService } from './logger.service';
|
import { LoggerService } from './logger.service';
|
||||||
|
|
||||||
// #docregion component
|
// #docregion component
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -3,7 +3,7 @@ import { Hero } from './hero';
|
|||||||
|
|
||||||
export class HeroData {
|
export class HeroData {
|
||||||
createDb() {
|
createDb() {
|
||||||
let heroes = [
|
const heroes = [
|
||||||
new Hero(1, 'Windstorm'),
|
new Hero(1, 'Windstorm'),
|
||||||
new Hero(2, 'Bombasto'),
|
new Hero(2, 'Bombasto'),
|
||||||
new Hero(3, 'Magneta'),
|
new Hero(3, 'Magneta'),
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// Illustrative (not used), mini-version of the actual HeroOfTheMonthComponent
|
// Illustrative (not used), mini-version of the actual HeroOfTheMonthComponent
|
||||||
// Injecting with the MinimalLogger "interface-class"
|
// Injecting with the MinimalLogger "interface-class"
|
||||||
import { Component, NgModule } from '@angular/core';
|
import { Component, NgModule } from '@angular/core';
|
||||||
import { LoggerService } from './logger.service';
|
import { LoggerService } from './logger.service';
|
||||||
import { MinimalLogger } from './minimal-logger.service';
|
import { MinimalLogger } from './minimal-logger.service';
|
||||||
|
|
||||||
// #docregion
|
// #docregion
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -10,12 +10,12 @@ export const TITLE = new InjectionToken<string>('title');
|
|||||||
import { Component, Inject } from '@angular/core';
|
import { Component, Inject } from '@angular/core';
|
||||||
|
|
||||||
import { DateLoggerService } from './date-logger.service';
|
import { DateLoggerService } from './date-logger.service';
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
import { HeroService } from './hero.service';
|
import { HeroService } from './hero.service';
|
||||||
import { LoggerService } from './logger.service';
|
import { LoggerService } from './logger.service';
|
||||||
import { MinimalLogger } from './minimal-logger.service';
|
import { MinimalLogger } from './minimal-logger.service';
|
||||||
import { RUNNERS_UP,
|
import { RUNNERS_UP,
|
||||||
runnersUpFactory } from './runners-up';
|
runnersUpFactory } from './runners-up';
|
||||||
|
|
||||||
// #enddocregion hero-of-the-month
|
// #enddocregion hero-of-the-month
|
||||||
// #docregion some-hero
|
// #docregion some-hero
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
/* tslint:disable:no-unused-variable component-selector-name one-line check-open-brace */
|
// tslint:disable: component-selector space-before-function-paren
|
||||||
/* tslint:disable:*/
|
|
||||||
// #docplaster
|
// #docplaster
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component, forwardRef, Optional, SkipSelf } from '@angular/core';
|
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.
|
// The `parentType` defaults to `Parent` when omitting the second parameter.
|
||||||
// #docregion provide-the-parent
|
// #docregion provide-the-parent
|
||||||
export function provideParent
|
export function provideParent
|
||||||
// #enddocregion provide-parent, provide-the-parent
|
// #enddocregion provide-the-parent
|
||||||
// #docregion provide-parent
|
|
||||||
(component: any, parentType?: any) {
|
(component: any, parentType?: any) {
|
||||||
return { provide: parentType || Parent, useExisting: forwardRef(() => component) };
|
return { provide: parentType || Parent, useExisting: forwardRef(() => component) };
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { InjectionToken } from '@angular/core';
|
import { InjectionToken } from '@angular/core';
|
||||||
|
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
import { HeroService } from './hero.service';
|
import { HeroService } from './hero.service';
|
||||||
|
|
||||||
// #docregion runners-up
|
// #docregion runners-up
|
||||||
@ -22,5 +22,5 @@ export function runnersUpFactory(take: number) {
|
|||||||
.join(', ');
|
.join(', ');
|
||||||
// #docregion factory-synopsis
|
// #docregion factory-synopsis
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
// #enddocregion factory-synopsis
|
// #enddocregion factory-synopsis
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
import { HeroService } from './hero.service';
|
import { HeroService } from './hero.service';
|
||||||
|
|
||||||
/////// HeroesBaseComponent /////
|
/////// HeroesBaseComponent /////
|
||||||
// #docregion heroes-base, injection
|
// #docregion heroes-base, injection
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { LoggerService } from './logger.service';
|
import { LoggerService } from './logger.service';
|
||||||
import { UserService } from './user.service';
|
import { UserService } from './user.service';
|
||||||
|
|
||||||
// #docregion injectables, injectable
|
// #docregion injectables, injectable
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@ -24,7 +24,7 @@ export class UserContextService {
|
|||||||
// #enddocregion ctor, injectables
|
// #enddocregion ctor, injectables
|
||||||
|
|
||||||
loadUser(userId: number) {
|
loadUser(userId: number) {
|
||||||
let user = this.userService.getUserById(userId);
|
const user = this.userService.getUserById(userId);
|
||||||
this.name = user.name;
|
this.name = user.name;
|
||||||
this.role = user.role;
|
this.role = user.role;
|
||||||
|
|
||||||
|
@ -1,202 +1,196 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { browser, element, by, ElementFinder } from 'protractor';
|
import { browser, element, by, ElementFinder } from 'protractor';
|
||||||
|
|
||||||
describe('Dependency Injection Tests', function () {
|
describe('Dependency Injection Tests', () => {
|
||||||
|
|
||||||
let expectedMsg: string;
|
let expectedMsg: string;
|
||||||
let expectedMsgRx: RegExp;
|
let expectedMsgRx: RegExp;
|
||||||
|
|
||||||
beforeAll(function () {
|
beforeAll(() => {
|
||||||
browser.get('');
|
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.';
|
expectedMsg = 'DI car with 4 cylinders and Flintstone tires.';
|
||||||
expect(element(by.css('#di')).getText()).toEqual(expectedMsg);
|
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.';
|
expectedMsg = 'No DI car with 4 cylinders and Flintstone tires.';
|
||||||
expect(element(by.css('#nodi')).getText()).toEqual(expectedMsg);
|
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.';
|
expectedMsg = 'Injector car with 4 cylinders and Flintstone tires.';
|
||||||
expect(element(by.css('#injector')).getText()).toEqual(expectedMsg);
|
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.';
|
expectedMsg = 'Factory car with 4 cylinders and Flintstone tires.';
|
||||||
expect(element(by.css('#factory')).getText()).toEqual(expectedMsg);
|
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.';
|
expectedMsg = 'Simple car with 4 cylinders and Flintstone tires.';
|
||||||
expect(element(by.css('#simple')).getText()).toEqual(expectedMsg);
|
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.';
|
expectedMsg = 'Super car with 12 cylinders and Flintstone tires.';
|
||||||
expect(element(by.css('#super')).getText()).toEqual(expectedMsg);
|
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.';
|
expectedMsg = 'Test car with 8 cylinders and YokoGoodStone tires.';
|
||||||
expect(element(by.css('#test')).getText()).toEqual(expectedMsg);
|
expect(element(by.css('#test')).getText()).toEqual(expectedMsg);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Other Injections:', function() {
|
describe('Other Injections:', () => {
|
||||||
it('DI car displays as expected', function () {
|
it('DI car displays as expected', () => {
|
||||||
expectedMsg = 'DI car with 4 cylinders and Flintstone tires.';
|
expectedMsg = 'DI car with 4 cylinders and Flintstone tires.';
|
||||||
expect(element(by.css('#car')).getText()).toEqual(expectedMsg);
|
expect(element(by.css('#car')).getText()).toEqual(expectedMsg);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Hero displays as expected', function () {
|
it('Hero displays as expected', () => {
|
||||||
expectedMsg = 'Dr Nice';
|
expectedMsg = 'Dr Nice';
|
||||||
expect(element(by.css('#hero')).getText()).toEqual(expectedMsg);
|
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!';
|
expectedMsg = 'R.O.U.S.\'s? I don\'t think they exist!';
|
||||||
expect(element(by.css('#rodent')).getText()).toEqual(expectedMsg);
|
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/;
|
expectedMsgRx = /Tests passed/;
|
||||||
expect(element(by.css('#tests')).getText()).toMatch(expectedMsgRx);
|
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';
|
expectedMsg = 'Hello from logger provided with Logger class';
|
||||||
expect(element(by.css('#p1')).getText()).toEqual(expectedMsg);
|
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';
|
expectedMsg = 'Hello from logger provided with useClass:Logger';
|
||||||
expect(element(by.css('#p3')).getText()).toEqual(expectedMsg);
|
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';
|
expectedMsg = 'Hello from logger provided with useClass:BetterLogger';
|
||||||
expect(element(by.css('#p4')).getText()).toEqual(expectedMsg);
|
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';
|
expectedMsg = 'Message to Bob: Hello from EvenBetterlogger';
|
||||||
expect(element(by.css('#p5')).getText()).toEqual(expectedMsg);
|
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)';
|
expectedMsg = 'Hello OldLogger (but we want NewLogger)';
|
||||||
expect(element(by.css('#p6a')).getText()).toEqual(expectedMsg);
|
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)';
|
expectedMsg = 'Hello from NewLogger (via aliased OldLogger)';
|
||||||
expect(element(by.css('#p6b')).getText()).toEqual(expectedMsg);
|
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"';
|
expectedMsg = 'Silent logger says "Shhhhh!". Provided via "useValue"';
|
||||||
expect(element(by.css('#p7')).getText()).toEqual(expectedMsg);
|
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';
|
expectedMsg = 'Hero service injected successfully via heroServiceProvider';
|
||||||
expect(element(by.css('#p8')).getText()).toEqual(expectedMsg);
|
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';
|
expectedMsg = 'APP_CONFIG Application title is Dependency Injection';
|
||||||
expect(element(by.css('#p9')).getText()).toEqual(expectedMsg);
|
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';
|
expectedMsg = 'Optional logger was not available';
|
||||||
expect(element(by.css('#p10')).getText()).toEqual(expectedMsg);
|
expect(element(by.css('#p10')).getText()).toEqual(expectedMsg);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('User/Heroes:', function() {
|
describe('User/Heroes:', () => {
|
||||||
it('User is Bob - unauthorized', function () {
|
it('User is Bob - unauthorized', () => {
|
||||||
expectedMsgRx = /Bob, is not authorized/;
|
expectedMsgRx = /Bob, is not authorized/;
|
||||||
expect(element(by.css('#user')).getText()).toMatch(expectedMsgRx);
|
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'))
|
expect(element.all(by.cssContainingText('button', 'Next User'))
|
||||||
.get(0).isDisplayed()).toBe(true, '\'Next User\' button should be displayed');
|
.get(0).isDisplayed()).toBe(true, '\'Next User\' button should be displayed');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('unauthorized user should have multiple unauthorized heroes', function () {
|
it('unauthorized user should have multiple unauthorized heroes', () => {
|
||||||
let heroes = element.all(by.css('#unauthorized app-hero-list div'));
|
const heroes = element.all(by.css('#unauthorized app-hero-list div'));
|
||||||
expect(heroes.count()).toBeGreaterThan(0);
|
expect(heroes.count()).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('unauthorized user should have no secret heroes', function () {
|
it('unauthorized user should have no secret heroes', () => {
|
||||||
let heroes = element.all(by.css('#unauthorized app-hero-list div'));
|
const heroes = element.all(by.css('#unauthorized app-hero-list div'));
|
||||||
expect(heroes.count()).toBeGreaterThan(0);
|
expect(heroes.count()).toBeGreaterThan(0);
|
||||||
|
|
||||||
let filteredHeroes = heroes.filter((elem: ElementFinder, index: number) => {
|
const filteredHeroes = heroes.filter((elem: ElementFinder, index: number) => {
|
||||||
return elem.getText().then((text: string) => {
|
return elem.getText().then((text: string) => /secret/.test(text));
|
||||||
return /secret/.test(text);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(filteredHeroes.count()).toEqual(0);
|
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);
|
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) {
|
beforeAll((done: any) => {
|
||||||
let buttonEle = element.all(by.cssContainingText('button', 'Next User')).get(0);
|
const buttonEle = element.all(by.cssContainingText('button', 'Next User')).get(0);
|
||||||
buttonEle.click().then(done, done);
|
buttonEle.click().then(done, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('User is Alice - authorized', function () {
|
it('User is Alice - authorized', () => {
|
||||||
expectedMsgRx = /Alice, is authorized/;
|
expectedMsgRx = /Alice, is authorized/;
|
||||||
expect(element(by.css('#user')).getText()).toMatch(expectedMsgRx);
|
expect(element(by.css('#user')).getText()).toMatch(expectedMsgRx);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authorized user should have multiple authorized heroes ', function () {
|
it('authorized user should have multiple authorized heroes ', () => {
|
||||||
let heroes = element.all(by.css('#authorized app-hero-list div'));
|
const heroes = element.all(by.css('#authorized app-hero-list div'));
|
||||||
expect(heroes.count()).toBeGreaterThan(0);
|
expect(heroes.count()).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authorized user should have multiple authorized heroes with tree-shakeable HeroesService', function () {
|
it('authorized user should have multiple authorized heroes with tree-shakeable HeroesService', () => {
|
||||||
let heroes = element.all(by.css('#tspAuthorized app-hero-list div'));
|
const heroes = element.all(by.css('#tspAuthorized app-hero-list div'));
|
||||||
expect(heroes.count()).toBeGreaterThan(0);
|
expect(heroes.count()).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authorized user should have secret heroes', function () {
|
it('authorized user should have secret heroes', () => {
|
||||||
let heroes = element.all(by.css('#authorized app-hero-list div'));
|
const heroes = element.all(by.css('#authorized app-hero-list div'));
|
||||||
expect(heroes.count()).toBeGreaterThan(0);
|
expect(heroes.count()).toBeGreaterThan(0);
|
||||||
|
|
||||||
let filteredHeroes = heroes.filter(function(elem: ElementFinder, index: number) {
|
const filteredHeroes = heroes.filter((elem: ElementFinder, index: number) => {
|
||||||
return elem.getText().then(function(text: string) {
|
return elem.getText().then((text: string) => /secret/.test(text));
|
||||||
return /secret/.test(text);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(filteredHeroes.count()).toBeGreaterThan(0);
|
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);
|
expect(element.all(by.css('#unauthorized app-hero-list div')).count()).toEqual(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// #docregion imports
|
// #docregion imports
|
||||||
import { Component, Inject } from '@angular/core';
|
import { Component, Inject } from '@angular/core';
|
||||||
|
|
||||||
import { APP_CONFIG, AppConfig } from './app.config';
|
import { APP_CONFIG, AppConfig } from './app.config';
|
||||||
// #enddocregion imports
|
// #enddocregion imports
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
import { NgModule } from '@angular/core';
|
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 { AppComponent } from './app.component';
|
||||||
import { CarComponent } from './car/car.component';
|
import { CarComponent } from './car/car.component';
|
||||||
import { HeroesComponent } from './heroes/heroes.component';
|
import { HeroesComponent } from './heroes/heroes.component';
|
||||||
|
@ -7,7 +7,7 @@ import { Car, Engine, Tires } from './car';
|
|||||||
export function simpleCar() {
|
export function simpleCar() {
|
||||||
// #docregion car-ctor-instantiation
|
// #docregion car-ctor-instantiation
|
||||||
// Simple car with 4 cylinders and Flintstone tires.
|
// 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
|
// #enddocregion car-ctor-instantiation
|
||||||
car.description = 'Simple';
|
car.description = 'Simple';
|
||||||
return car;
|
return car;
|
||||||
@ -16,30 +16,31 @@ export function simpleCar() {
|
|||||||
|
|
||||||
///////// example 2 ////////////
|
///////// example 2 ////////////
|
||||||
// #docregion car-ctor-instantiation-with-param
|
// #docregion car-ctor-instantiation-with-param
|
||||||
class Engine2 {
|
class Engine2 {
|
||||||
constructor(public cylinders: number) { }
|
constructor(public cylinders: number) { }
|
||||||
}
|
}
|
||||||
// #enddocregion car-ctor-instantiation-with-param
|
// #enddocregion car-ctor-instantiation-with-param
|
||||||
|
|
||||||
export function superCar() {
|
export function superCar() {
|
||||||
// #docregion car-ctor-instantiation-with-param
|
// #docregion car-ctor-instantiation-with-param
|
||||||
// Super car with 12 cylinders and Flintstone tires.
|
// Super car with 12 cylinders and Flintstone tires.
|
||||||
let bigCylinders = 12;
|
const bigCylinders = 12;
|
||||||
let car = new Car(new Engine2(bigCylinders), new Tires());
|
const car = new Car(new Engine2(bigCylinders), new Tires());
|
||||||
// #enddocregion car-ctor-instantiation-with-param
|
// #enddocregion car-ctor-instantiation-with-param
|
||||||
car.description = 'Super';
|
car.description = 'Super';
|
||||||
return car;
|
return car;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////// example 3 //////////
|
/////////// example 3 //////////
|
||||||
// #docregion car-ctor-instantiation-with-mocks
|
// #docregion car-ctor-instantiation-with-mocks
|
||||||
class MockEngine extends Engine { cylinders = 8; }
|
class MockEngine extends Engine { cylinders = 8; }
|
||||||
class MockTires extends Tires { make = 'YokoGoodStone'; }
|
class MockTires extends Tires { make = 'YokoGoodStone'; }
|
||||||
|
|
||||||
// #enddocregion car-ctor-instantiation-with-mocks
|
// #enddocregion car-ctor-instantiation-with-mocks
|
||||||
export function testCar() {
|
export function testCar() {
|
||||||
// #docregion car-ctor-instantiation-with-mocks
|
// #docregion car-ctor-instantiation-with-mocks
|
||||||
// Test car with 8 cylinders and YokoGoodStone tires.
|
// 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
|
// #enddocregion car-ctor-instantiation-with-mocks
|
||||||
car.description = 'Test';
|
car.description = 'Test';
|
||||||
return car;
|
return car;
|
||||||
|
@ -4,7 +4,7 @@ import { Engine, Tires, Car } from './car';
|
|||||||
// BAD pattern!
|
// BAD pattern!
|
||||||
export class CarFactory {
|
export class CarFactory {
|
||||||
createCar() {
|
createCar() {
|
||||||
let car = new Car(this.createEngine(), this.createTires());
|
const car = new Car(this.createEngine(), this.createTires());
|
||||||
car.description = 'Factory';
|
car.description = 'Factory';
|
||||||
return car;
|
return car;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Injector } from '@angular/core';
|
import { Injector } from '@angular/core';
|
||||||
|
|
||||||
import { Car, Engine, Tires } from './car';
|
import { Car, Engine, Tires } from './car';
|
||||||
import { Logger } from '../logger.service';
|
import { Logger } from '../logger.service';
|
||||||
|
|
||||||
// #docregion injector
|
// #docregion injector
|
||||||
export function useInjector() {
|
export function useInjector() {
|
||||||
@ -26,14 +26,14 @@ export function useInjector() {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
// #docregion injector-call
|
// #docregion injector-call
|
||||||
let car = injector.get(Car);
|
const car = injector.get(Car);
|
||||||
// #enddocregion injector-call, injector-create-and-call
|
// #enddocregion injector-call, injector-create-and-call
|
||||||
car.description = 'Injector';
|
car.description = 'Injector';
|
||||||
|
|
||||||
injector = Injector.create({
|
injector = Injector.create({
|
||||||
providers: [{ provide: Logger, deps: [] }]
|
providers: [{ provide: Logger, deps: [] }]
|
||||||
});
|
});
|
||||||
let logger = injector.get(Logger);
|
const logger = injector.get(Logger);
|
||||||
logger.log('Injector car.drive() said: ' + car.drive());
|
logger.log('Injector car.drive() said: ' + car.drive());
|
||||||
return car;
|
return car;
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
import { Car, Engine, Tires } from './car';
|
import { Car, Engine, Tires } from './car';
|
||||||
import { Car as CarNoDi } from './car-no-di';
|
import { Car as CarNoDi } from './car-no-di';
|
||||||
import { CarFactory } from './car-factory';
|
import { CarFactory } from './car-factory';
|
||||||
|
|
||||||
import { testCar,
|
import { testCar,
|
||||||
simpleCar,
|
simpleCar,
|
||||||
superCar } from './car-creations';
|
superCar } from './car-creations';
|
||||||
|
|
||||||
import { useInjector } from './car-injector';
|
import { useInjector } from './car-injector';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -27,9 +27,9 @@ import { useInjector } from './car-injector';
|
|||||||
providers: [Car, Engine, Tires]
|
providers: [Car, Engine, Tires]
|
||||||
})
|
})
|
||||||
export class CarComponent {
|
export class CarComponent {
|
||||||
factoryCar = (new CarFactory).createCar();
|
factoryCar = (new CarFactory()).createCar();
|
||||||
injectorCar = useInjector();
|
injectorCar = useInjector();
|
||||||
noDiCar = new CarNoDi;
|
noDiCar = new CarNoDi();
|
||||||
simpleCar = simpleCar();
|
simpleCar = simpleCar();
|
||||||
superCar = superCar();
|
superCar = superCar();
|
||||||
testCar = testCar();
|
testCar = testCar();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { HEROES } from './mock-heroes';
|
import { HEROES } from './mock-heroes';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hero-list',
|
selector: 'app-hero-list',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
import { HeroService } from './hero.service.1';
|
import { HeroService } from './hero.service.1';
|
||||||
/*
|
/*
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* tslint:disable:one-line */
|
/* tslint:disable:one-line */
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
import { HeroService } from './hero.service';
|
import { HeroService } from './hero.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HEROES } from './mock-heroes';
|
import { HEROES } from './mock-heroes';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HEROES } from './mock-heroes';
|
import { HEROES } from './mock-heroes';
|
||||||
import { Logger } from '../logger.service';
|
import { Logger } from '../logger.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
/* tslint:disable:one-line */
|
/* tslint:disable:one-line */
|
||||||
// #docregion
|
// #docregion
|
||||||
import { HeroService } from './hero.service';
|
import { HeroService } from './hero.service';
|
||||||
import { Logger } from '../logger.service';
|
import { Logger } from '../logger.service';
|
||||||
import { UserService } from '../user.service';
|
import { UserService } from '../user.service';
|
||||||
|
|
||||||
// #docregion factory
|
// #docregion factory
|
||||||
let heroServiceFactory = (logger: Logger, userService: UserService) => {
|
const heroServiceFactory = (logger: Logger, userService: UserService) => {
|
||||||
return new HeroService(logger, userService.user.isAuthorized);
|
return new HeroService(logger, userService.user.isAuthorized);
|
||||||
};
|
};
|
||||||
// #enddocregion factory
|
// #enddocregion factory
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HEROES } from './mock-heroes';
|
import { HEROES } from './mock-heroes';
|
||||||
import { Logger } from '../logger.service';
|
import { Logger } from '../logger.service';
|
||||||
import { UserService } from '../user.service';
|
import { UserService } from '../user.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@ -17,7 +17,7 @@ export class HeroService {
|
|||||||
private isAuthorized: boolean) { }
|
private isAuthorized: boolean) { }
|
||||||
|
|
||||||
getHeroes() {
|
getHeroes() {
|
||||||
let auth = this.isAuthorized ? 'authorized ' : 'unauthorized';
|
const auth = this.isAuthorized ? 'authorized ' : 'unauthorized';
|
||||||
this.logger.log(`Getting heroes for ${auth} user.`);
|
this.logger.log(`Getting heroes for ${auth} user.`);
|
||||||
return HEROES.filter(hero => this.isAuthorized || !hero.isSecret);
|
return HEROES.filter(hero => this.isAuthorized || !hero.isSecret);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { heroServiceProvider } from './hero.service.provider';
|
import { heroServiceProvider } from './hero.service.provider';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component, Injector, OnInit } from '@angular/core';
|
import { Component, Injector, OnInit } from '@angular/core';
|
||||||
|
|
||||||
import { Car, Engine, Tires } from './car/car';
|
import { Car, Engine, Tires } from './car/car';
|
||||||
import { Hero } from './heroes/hero';
|
import { Hero } from './heroes/hero';
|
||||||
import { HeroService } from './heroes/hero.service';
|
import { HeroService } from './heroes/hero.service';
|
||||||
import { heroServiceProvider } from './heroes/hero.service.provider';
|
import { heroServiceProvider } from './heroes/hero.service.provider';
|
||||||
import { Logger } from './logger.service';
|
import { Logger } from './logger.service';
|
||||||
|
|
||||||
// #docregion injector
|
// #docregion injector
|
||||||
@Component({
|
@Component({
|
||||||
@ -36,7 +36,7 @@ export class InjectorComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get rodent() {
|
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);
|
return this.injector.get(ROUS, rousDontExist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ const template = '{{log}}';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'provider-1',
|
selector: 'provider-1',
|
||||||
template: template,
|
template,
|
||||||
// #docregion providers-1, providers-logger
|
// #docregion providers-1, providers-logger
|
||||||
providers: [Logger]
|
providers: [Logger]
|
||||||
// #enddocregion providers-1, providers-logger
|
// #enddocregion providers-1, providers-logger
|
||||||
@ -35,7 +35,7 @@ export class Provider1Component {
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'provider-3',
|
selector: 'provider-3',
|
||||||
template: template,
|
template,
|
||||||
providers:
|
providers:
|
||||||
// #docregion providers-3
|
// #docregion providers-3
|
||||||
[{ provide: Logger, useClass: Logger }]
|
[{ provide: Logger, useClass: Logger }]
|
||||||
@ -54,7 +54,7 @@ export class BetterLogger extends Logger {}
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'provider-4',
|
selector: 'provider-4',
|
||||||
template: template,
|
template,
|
||||||
providers:
|
providers:
|
||||||
// #docregion providers-4
|
// #docregion providers-4
|
||||||
[{ provide: Logger, useClass: BetterLogger }]
|
[{ provide: Logger, useClass: BetterLogger }]
|
||||||
@ -76,7 +76,7 @@ export class EvenBetterLogger extends Logger {
|
|||||||
constructor(private userService: UserService) { super(); }
|
constructor(private userService: UserService) { super(); }
|
||||||
|
|
||||||
log(message: string) {
|
log(message: string) {
|
||||||
let name = this.userService.user.name;
|
const name = this.userService.user.name;
|
||||||
super.log(`Message to ${name}: ${message}`);
|
super.log(`Message to ${name}: ${message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ export class EvenBetterLogger extends Logger {
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'provider-5',
|
selector: 'provider-5',
|
||||||
template: template,
|
template,
|
||||||
providers:
|
providers:
|
||||||
// #docregion providers-5
|
// #docregion providers-5
|
||||||
[ UserService,
|
[ UserService,
|
||||||
@ -107,12 +107,12 @@ export class OldLogger {
|
|||||||
logs: string[] = [];
|
logs: string[] = [];
|
||||||
log(message: string) {
|
log(message: string) {
|
||||||
throw new Error('Should not call the old logger!');
|
throw new Error('Should not call the old logger!');
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'provider-6a',
|
selector: 'provider-6a',
|
||||||
template: template,
|
template,
|
||||||
providers:
|
providers:
|
||||||
// #docregion providers-6a
|
// #docregion providers-6a
|
||||||
[ NewLogger,
|
[ NewLogger,
|
||||||
@ -135,7 +135,7 @@ export class Provider6aComponent {
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'provider-6b',
|
selector: 'provider-6b',
|
||||||
template: template,
|
template,
|
||||||
providers:
|
providers:
|
||||||
// #docregion providers-6b
|
// #docregion providers-6b
|
||||||
[ NewLogger,
|
[ NewLogger,
|
||||||
@ -168,7 +168,7 @@ export const SilentLogger = {
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'provider-7',
|
selector: 'provider-7',
|
||||||
template: template,
|
template,
|
||||||
providers:
|
providers:
|
||||||
// #docregion providers-7
|
// #docregion providers-7
|
||||||
[{ provide: Logger, useValue: SilentLogger }]
|
[{ provide: Logger, useValue: SilentLogger }]
|
||||||
@ -186,7 +186,7 @@ export class Provider7Component {
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'provider-8',
|
selector: 'provider-8',
|
||||||
template: template,
|
template,
|
||||||
providers: [heroServiceProvider, Logger, UserService]
|
providers: [heroServiceProvider, Logger, UserService]
|
||||||
})
|
})
|
||||||
export class Provider8Component {
|
export class Provider8Component {
|
||||||
@ -202,7 +202,7 @@ export class Provider8Component {
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'provider-9',
|
selector: 'provider-9',
|
||||||
template: template,
|
template,
|
||||||
/*
|
/*
|
||||||
// #docregion providers-9-interface
|
// #docregion providers-9-interface
|
||||||
// FAIL! Can't use interface as provider token
|
// FAIL! Can't use interface as provider token
|
||||||
@ -237,11 +237,11 @@ export class Provider9Component implements OnInit {
|
|||||||
import { Optional } from '@angular/core';
|
import { Optional } from '@angular/core';
|
||||||
// #enddocregion import-optional
|
// #enddocregion import-optional
|
||||||
|
|
||||||
let some_message = 'Hello from the injected logger';
|
const someMessage = 'Hello from the injected logger';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'provider-10',
|
selector: 'provider-10',
|
||||||
template: template,
|
template,
|
||||||
providers: [{ provide: Logger, useValue: null }]
|
providers: [{ provide: Logger, useValue: null }]
|
||||||
})
|
})
|
||||||
export class Provider10Component implements OnInit {
|
export class Provider10Component implements OnInit {
|
||||||
@ -249,7 +249,7 @@ export class Provider10Component implements OnInit {
|
|||||||
// #docregion provider-10-ctor
|
// #docregion provider-10-ctor
|
||||||
constructor(@Optional() private logger?: Logger) {
|
constructor(@Optional() private logger?: Logger) {
|
||||||
if (this.logger) {
|
if (this.logger) {
|
||||||
this.logger.log(some_message);
|
this.logger.log(someMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion provider-10-ctor
|
// #enddocregion provider-10-ctor
|
||||||
|
@ -43,7 +43,7 @@ var testResults: {pass: string; message: string};
|
|||||||
|
|
||||||
function expect(actual: any) {
|
function expect(actual: any) {
|
||||||
return {
|
return {
|
||||||
toEqual: function(expected: any){
|
toEqual: (expected: any) => {
|
||||||
testResults = actual === expected ?
|
testResults = actual === expected ?
|
||||||
{pass: 'passed', message: testName} :
|
{pass: 'passed', message: testName} :
|
||||||
{pass: 'failed', message: `${testName}; expected ${actual} to equal ${expected}.`};
|
{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 { BrowserModule } from '@angular/platform-browser';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { ServiceModule } from './service-and-module';
|
import { ServiceModule } from './service-and-module';
|
||||||
|
|
||||||
// #docregion
|
// #docregion
|
||||||
|
@ -8,8 +8,8 @@ export class User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: get the user; don't 'new' it.
|
// TODO: get the user; don't 'new' it.
|
||||||
let alice = new User('Alice', true);
|
const alice = new User('Alice', true);
|
||||||
let bob = new User('Bob', false);
|
const bob = new User('Bob', false);
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
|
@ -1,29 +1,27 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Displaying Data Tests', function () {
|
describe('Displaying Data Tests', () => {
|
||||||
let _title = 'Tour of Heroes';
|
const title = 'Tour of Heroes';
|
||||||
let _defaultHero = 'Windstorm';
|
const defaultHero = 'Windstorm';
|
||||||
|
|
||||||
beforeAll(function () {
|
beforeAll(() => {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display correct title: ' + _title, function () {
|
it('should display correct title: ' + title, () => {
|
||||||
expect(element(by.css('h1')).getText()).toEqual(_title);
|
expect(element(by.css('h1')).getText()).toEqual(title);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have correct default hero: ' + _defaultHero, function () {
|
it('should have correct default hero: ' + defaultHero, () => {
|
||||||
expect(element(by.css('h2')).getText()).toContain(_defaultHero);
|
expect(element(by.css('h2')).getText()).toContain(defaultHero);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have heroes', function () {
|
it('should have heroes', () => {
|
||||||
let heroEls = element.all(by.css('li'));
|
const heroEls = element.all(by.css('li'));
|
||||||
expect(heroEls.count()).not.toBe(0, 'should have heroes');
|
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!');
|
expect(element(by.css('ul ~ p')).getText()).toContain('There are many heroes!');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Docs Style Guide', function () {
|
describe('Docs Style Guide', () => {
|
||||||
let _title = 'Authors Style Guide Sample';
|
const title = 'Authors Style Guide Sample';
|
||||||
|
|
||||||
beforeAll(function () {
|
beforeAll(() => {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display correct title: ' + _title, function () {
|
it('should display correct title: ' + title, () => {
|
||||||
expect(element(by.css('h1')).getText()).toEqual(_title);
|
expect(element(by.css('h1')).getText()).toEqual(title);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
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
|
// #docregion class
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
/* tslint:disable:quotemark */
|
/* tslint:disable:quotemark */
|
||||||
describe('Dynamic Component Loader', function () {
|
describe('Dynamic Component Loader', () => {
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(() => {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load ad banner', function () {
|
it('should load ad banner', () => {
|
||||||
let headline = element(by.xpath("//h4[text()='Featured Hero Profile']"));
|
const headline = element(by.xpath("//h4[text()='Featured Hero Profile']"));
|
||||||
let name = element(by.xpath("//h3[text()='Bombasto']"));
|
const name = element(by.xpath("//h3[text()='Bombasto']"));
|
||||||
let bio = element(by.xpath("//p[text()='Brave as they come']"));
|
const bio = element(by.xpath("//p[text()='Brave as they come']"));
|
||||||
|
|
||||||
expect(name).toBeDefined();
|
expect(name).toBeDefined();
|
||||||
expect(headline).toBeDefined();
|
expect(headline).toBeDefined();
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user