Compare commits
504 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
f24972b1b1 | |||
d2886b3bb4 | |||
f296fea112 | |||
2605fc46e7 | |||
9d54b3a14b | |||
d09a6283ed | |||
1c168c3a44 | |||
0f74479c47 | |||
790bb949f6 | |||
2adcad6dd2 | |||
242ef1ace1 | |||
842b6a1247 | |||
98335529eb | |||
ca7ee794bf | |||
f9f2ba6faf | |||
aea1d211d4 | |||
57a518a36d | |||
29b83189b0 | |||
1d3df7885d | |||
fd06ffa2af | |||
36a1622dd1 | |||
7a91b23cb5 | |||
4b90b6a226 | |||
b13daa4cdf | |||
0c6f026828 | |||
a2520bd267 | |||
b928a209a4 | |||
89e16ed6a5 | |||
1a1f99af37 | |||
df2cd37ed2 | |||
12a71bc6bc | |||
7d270c235a | |||
b0b7248504 | |||
78460c1848 | |||
75b119eafc | |||
64b0ae93f7 | |||
7c0b25f5a6 | |||
07b5df3a19 | |||
e7023726f4 | |||
a9ccd9254c | |||
335f3271d2 | |||
7f93f7ef47 | |||
cf46a87fcd | |||
ad6680f602 | |||
5e287f67af | |||
ecfe6e0609 | |||
df9790dd11 | |||
67cfc4c9bc | |||
a68e623c80 | |||
9e3915ba48 | |||
ba2de61748 | |||
a9a4edebe2 | |||
64f2ffa166 | |||
13020b9cc2 | |||
96b96fba0f | |||
2cbe53a9ba | |||
48755114e5 | |||
a5d5f67be7 | |||
dfb58c44a2 | |||
69948ce919 | |||
3190ccf3b2 | |||
a8ea8173aa | |||
e13a49d1f0 | |||
2f0b8f675a | |||
c2aed033ba | |||
0f8a780b0d | |||
c5bc2e77c8 | |||
079310dc7c | |||
0d2cdf6165 | |||
436dde271f | |||
96891a076f | |||
9ce0067bdf | |||
345940bbc1 | |||
c49507b289 | |||
c730142508 | |||
27aa00b15f | |||
36a00a255b | |||
0e3249c89b | |||
920019ab70 | |||
82c8b44db7 | |||
bb3a307d5a | |||
dcb0ddaf5e | |||
4c1edd52c5 | |||
d512e27979 | |||
0619d82e0b | |||
a4038d5b94 | |||
e3d5e1fab7 | |||
035036308a | |||
0d29259d9b | |||
26b0f3dc96 | |||
5c9306b0fe | |||
3befb0e4b9 | |||
97bb88f10b | |||
6c7467a58b | |||
c579a85c12 | |||
400fdd08fd | |||
c1fe6c9c81 | |||
c58a0bea91 | |||
88a934b93c | |||
cde5cced69 | |||
472bedd3ea | |||
d8a06d03bd | |||
32020f9fb3 | |||
d574b14934 | |||
00c5d89e7d | |||
d2c8aefe64 | |||
ba796bbdd3 | |||
a0bb2ba7b7 | |||
f9fa3b5b6c | |||
f89d438116 | |||
1abe791d46 | |||
1502ae78b6 | |||
bad6e719de | |||
8c7129f3d2 | |||
dbff6f71e1 | |||
fcd934ccf6 | |||
45a8f340d9 | |||
5856513405 | |||
01fa3ee5c3 | |||
b8d69ffdf3 | |||
7ef60ec2a9 | |||
83f905c0e1 | |||
72ba3a3918 | |||
df10597da4 | |||
5db2e794a9 | |||
486aa06747 | |||
01ce1b32df | |||
c78b0b2c51 | |||
9ade1c3ea3 | |||
315a4cfcd4 | |||
11c04027ab | |||
eabe3b4c39 | |||
d471454675 | |||
bf57776b59 | |||
a32579ae5b | |||
780601d27a | |||
c909e731d7 | |||
9b8eb42354 | |||
0757174e8e | |||
3a43cdefe8 | |||
38c48beddd | |||
ad5749fb04 | |||
f6a838e9ee | |||
a6d1f4aaf1 | |||
eca8d11ee2 | |||
a195b7dbe4 | |||
083d7ec902 | |||
9d2d0cae6d | |||
c2f4a9bf71 | |||
231095fe8a | |||
28a532483a | |||
83853a215d | |||
8248307a99 | |||
67bd88b19a | |||
9f698b4de0 | |||
742f3d6787 | |||
323651bd38 | |||
9d397eb5a1 | |||
6114cd2bd4 | |||
d494f7bd5e | |||
ec6a7ab721 | |||
ad6d2b4619 | |||
c093390010 | |||
acd69f2be2 | |||
5d2f341653 | |||
420d1c35f5 | |||
08647267bb | |||
215d50d2f6 | |||
bf2cb6fa48 | |||
e97a2d4123 | |||
585e3f6adc | |||
7f77ce1a48 | |||
a1616ce181 | |||
1c22dff714 | |||
8d1d6e8f70 | |||
e7f4aba5a3 | |||
fdbe9f5d9f | |||
8bead6bfdd | |||
52dda73dbb | |||
31b3888a2f | |||
6f938470c2 | |||
776c4afc03 | |||
536dd647c6 | |||
51d581ab27 | |||
75294e7dad | |||
04bada7a9d | |||
2349143477 | |||
e9bff5fe9f | |||
411cb0cb92 | |||
53e1fb3554 | |||
2cb3b66640 | |||
5af3144330 | |||
e4043cbb3a | |||
fff424a35f | |||
b5d1c8b05a | |||
d713e33cc4 | |||
3d327d25f0 | |||
077283bf0f | |||
9ec25ea036 | |||
878cfe669c | |||
5f0be3cb2e | |||
9e28e14c08 | |||
954d002884 | |||
0a48591e53 | |||
d37c723951 | |||
9078ca557e | |||
2be1ef6ba0 | |||
47c02efccb | |||
d7ecfb432a | |||
59abf4a33f | |||
d6e715e726 | |||
fcfcd1037c | |||
f3ccd29e7b | |||
5c0bdae809 | |||
838902556b | |||
c6872c02d8 | |||
819982ea20 | |||
f9daa136c3 | |||
6a0d2ed6c8 | |||
2c1f35e794 | |||
5345e8da45 | |||
e35269dd87 | |||
60a03b7ef7 | |||
305b5a3887 | |||
bc549361d3 | |||
084b627f2e | |||
6755d00601 | |||
cba1da3e44 | |||
7be8bb1489 | |||
c7c0c1f626 | |||
3aa4629f92 | |||
2d86dbb090 | |||
91767ff0f9 | |||
078b004ecc | |||
930d204d83 | |||
8d82cdfc77 | |||
cb6996b5c3 | |||
a4f7740332 | |||
ba0faa2f77 | |||
3e68029522 | |||
b4e26b5828 | |||
15cf7fcac2 | |||
24ff0eb13b | |||
cf86f72eb7 | |||
61486f14f1 | |||
d16a7f3ecc | |||
82761ec50e | |||
235bfa77a9 | |||
299ae1bb1c | |||
80f7522dab | |||
028921e369 | |||
a4e11bb524 | |||
a4131752d2 | |||
060dcfbba1 | |||
4be7008f80 | |||
4a0d05515e | |||
83ab99c746 | |||
270da1f69f | |||
6b0e46e36c | |||
3642707145 | |||
0ea76edfd8 | |||
d493a83b2b | |||
f1721d5cef | |||
5b3fd6aa82 | |||
6f829180f7 | |||
27b95ba64a | |||
ef405b1e90 | |||
441073bad5 |
@ -1,3 +1,3 @@
|
|||||||
3.5.1
|
3.2.0
|
||||||
# [NB: this comment has to be after the first line, see https://github.com/bazelbuild/bazelisk/issues/117]
|
# [NB: this comment has to be after the first line, see https://github.com/bazelbuild/bazelisk/issues/117]
|
||||||
# When updating the Bazel version you also need to update the RBE toolchains version in package.bzl
|
# When updating the Bazel version you also need to update the RBE toolchains version in package.bzl
|
||||||
|
@ -14,8 +14,8 @@ build --repository_cache=/home/circleci/bazel_repository_cache
|
|||||||
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
|
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
|
||||||
# Limit Bazel to consuming resources that fit in CircleCI "xlarge" class
|
# Limit Bazel to consuming resources that fit in CircleCI "xlarge" class
|
||||||
# https://circleci.com/docs/2.0/configuration-reference/#resource_class
|
# https://circleci.com/docs/2.0/configuration-reference/#resource_class
|
||||||
build --local_cpu_resources=20
|
build --local_cpu_resources=8
|
||||||
build --local_ram_resources=32768
|
build --local_ram_resources=14336
|
||||||
|
|
||||||
# All build executed remotely should be done using our RBE configuration.
|
# All build executed remotely should be done using our RBE configuration.
|
||||||
build:remote --google_default_credentials
|
build:remote --google_default_credentials
|
||||||
|
@ -11,8 +11,8 @@ try-import %workspace%/.circleci/bazel.common.rc
|
|||||||
build --repository_cache=C:/Users/circleci/bazel_repository_cache
|
build --repository_cache=C:/Users/circleci/bazel_repository_cache
|
||||||
|
|
||||||
# Manually set the local resources used in windows CI runs
|
# Manually set the local resources used in windows CI runs
|
||||||
build --local_ram_resources=120000
|
build --local_ram_resources=13500
|
||||||
build --local_cpu_resources=32
|
build --local_cpu_resources=4
|
||||||
|
|
||||||
# All windows jobs run on master and should use http caching
|
# All windows jobs run on master and should use http caching
|
||||||
build --remote_http_cache=https://storage.googleapis.com/angular-team-cache
|
build --remote_http_cache=https://storage.googleapis.com/angular-team-cache
|
||||||
|
@ -80,7 +80,7 @@ executors:
|
|||||||
|
|
||||||
windows-executor:
|
windows-executor:
|
||||||
working_directory: ~/ng
|
working_directory: ~/ng
|
||||||
resource_class: windows.2xlarge
|
resource_class: windows.medium
|
||||||
# CircleCI windows VMs do have the GitBash shell available:
|
# CircleCI windows VMs do have the GitBash shell available:
|
||||||
# https://github.com/CircleCI-Public/windows-preview-docs#shells
|
# https://github.com/CircleCI-Public/windows-preview-docs#shells
|
||||||
# But in this specific case we really should not use it because Bazel must not be ran from
|
# But in this specific case we really should not use it because Bazel must not be ran from
|
||||||
@ -273,7 +273,6 @@ jobs:
|
|||||||
- run: yarn -s ng-dev format changed $CI_GIT_BASE_REVISION --check
|
- run: yarn -s ng-dev format changed $CI_GIT_BASE_REVISION --check
|
||||||
- run: yarn -s ts-circular-deps:check
|
- run: yarn -s ts-circular-deps:check
|
||||||
- run: yarn -s ng-dev pullapprove verify
|
- run: yarn -s ng-dev pullapprove verify
|
||||||
- run: yarn -s ng-dev ngbot verify
|
|
||||||
- run: yarn -s ng-dev commit-message validate-range --range $CI_COMMIT_RANGE
|
- run: yarn -s ng-dev commit-message validate-range --range $CI_COMMIT_RANGE
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@ -657,18 +656,6 @@ 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
|
||||||
@ -744,8 +731,8 @@ jobs:
|
|||||||
- run: yarn --cwd packages/zone.js promisetest
|
- run: yarn --cwd packages/zone.js promisetest
|
||||||
- run: yarn --cwd packages/zone.js promisefinallytest
|
- run: yarn --cwd packages/zone.js promisefinallytest
|
||||||
- run: yarn bazel build //packages/zone.js:npm_package &&
|
- run: yarn bazel build //packages/zone.js:npm_package &&
|
||||||
cp dist/bin/packages/zone.js/npm_package/bundles/zone-mix.umd.js ./packages/zone.js/test/extra/ &&
|
cp dist/bin/packages/zone.js/npm_package/dist/zone-mix.js ./packages/zone.js/test/extra/ &&
|
||||||
cp dist/bin/packages/zone.js/npm_package/bundles/zone-patch-electron.umd.js ./packages/zone.js/test/extra/ &&
|
cp dist/bin/packages/zone.js/npm_package/dist/zone-patch-electron.js ./packages/zone.js/test/extra/ &&
|
||||||
yarn --cwd packages/zone.js electrontest
|
yarn --cwd packages/zone.js electrontest
|
||||||
- run: yarn --cwd packages/zone.js jesttest
|
- run: yarn --cwd packages/zone.js jesttest
|
||||||
|
|
||||||
|
@ -41,8 +41,7 @@ copy .circleci\bazel.windows.rc ${Env:USERPROFILE}\.bazelrc
|
|||||||
####################################################################################################
|
####################################################################################################
|
||||||
# Install specific version of node.
|
# Install specific version of node.
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
nvm install 12.14.1
|
choco install nodejs --version 12.14.1 --no-progress
|
||||||
nvm use 12.14.1
|
|
||||||
|
|
||||||
# These Bazel prereqs aren't needed because the CircleCI image already includes them.
|
# These Bazel prereqs aren't needed because the CircleCI image already includes them.
|
||||||
# choco install yarn --version 1.16.0 --no-progress
|
# choco install yarn --version 1.16.0 --no-progress
|
||||||
|
55
.github/angular-robot.yml
vendored
55
.github/angular-robot.yml
vendored
@ -38,7 +38,6 @@ merge:
|
|||||||
- "modules/benchmarks/**"
|
- "modules/benchmarks/**"
|
||||||
- "modules/system.d.ts"
|
- "modules/system.d.ts"
|
||||||
- "packages/**"
|
- "packages/**"
|
||||||
- "dev-infra/benchmark/driver-utilities/**"
|
|
||||||
# list of patterns to ignore for the files changed by the PR
|
# list of patterns to ignore for the files changed by the PR
|
||||||
exclude:
|
exclude:
|
||||||
- "packages/*"
|
- "packages/*"
|
||||||
@ -48,10 +47,7 @@ merge:
|
|||||||
- "packages/bazel/src/ng_package/**"
|
- "packages/bazel/src/ng_package/**"
|
||||||
- "packages/bazel/src/protractor/**"
|
- "packages/bazel/src/protractor/**"
|
||||||
- "packages/bazel/src/schematics/**"
|
- "packages/bazel/src/schematics/**"
|
||||||
- "packages/compiler-cli/src/ngcc/**"
|
|
||||||
- "packages/compiler-cli/linker/**"
|
|
||||||
- "packages/compiler-cli/ngcc/**"
|
- "packages/compiler-cli/ngcc/**"
|
||||||
- "packages/compiler-cli/src/ngtsc/sourcemaps/**"
|
|
||||||
- "packages/docs/**"
|
- "packages/docs/**"
|
||||||
- "packages/elements/schematics/**"
|
- "packages/elements/schematics/**"
|
||||||
- "packages/examples/**"
|
- "packages/examples/**"
|
||||||
@ -59,8 +55,6 @@ merge:
|
|||||||
- "packages/localize/**"
|
- "packages/localize/**"
|
||||||
- "packages/private/**"
|
- "packages/private/**"
|
||||||
- "packages/service-worker/**"
|
- "packages/service-worker/**"
|
||||||
- "packages/common/locales/**"
|
|
||||||
- "packages/http/**"
|
|
||||||
- "**/.gitignore"
|
- "**/.gitignore"
|
||||||
- "**/.gitkeep"
|
- "**/.gitkeep"
|
||||||
- "**/yarn.lock"
|
- "**/yarn.lock"
|
||||||
@ -74,20 +68,20 @@ merge:
|
|||||||
- "packages/**/integrationtest/**"
|
- "packages/**/integrationtest/**"
|
||||||
- "packages/**/test/**"
|
- "packages/**/test/**"
|
||||||
- "packages/zone.js/*"
|
- "packages/zone.js/*"
|
||||||
- "packages/zone.js/dist/**"
|
|
||||||
- "packages/zone.js/doc/**"
|
- "packages/zone.js/doc/**"
|
||||||
- "packages/zone.js/example/**"
|
- "packages/zone.js/example/**"
|
||||||
- "packages/zone.js/scripts/**"
|
- "packages/zone.js/scripts/**"
|
||||||
|
|
||||||
# comment that will be added to a PR when there is a conflict, leave empty or set to false to disable
|
# comment that will be added to a PR when there is a conflict, leave empty or set to false to disable
|
||||||
mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges.\nPlease help to unblock it by resolving these conflicts. Thanks!"
|
mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges.
|
||||||
|
\nPlease help to unblock it by resolving these conflicts. Thanks!"
|
||||||
|
|
||||||
# label to monitor
|
# label to monitor
|
||||||
mergeLabel: "action: merge"
|
mergeLabel: "PR action: merge"
|
||||||
|
|
||||||
# adding any of these labels will also add the merge label
|
# adding any of these labels will also add the merge label
|
||||||
mergeLinkedLabels:
|
mergeLinkedLabels:
|
||||||
- "action: merge-assistance"
|
- "PR action: merge-assistance"
|
||||||
|
|
||||||
# list of checks that will determine if the merge label can be added
|
# list of checks that will determine if the merge label can be added
|
||||||
checks:
|
checks:
|
||||||
@ -100,17 +94,17 @@ merge:
|
|||||||
|
|
||||||
# whether the PR shouldn't have a conflict with the base branch
|
# whether the PR shouldn't have a conflict with the base branch
|
||||||
noConflict: true
|
noConflict: true
|
||||||
# list of labels that a PR needs to have, checked with a regexp (e.g. "target:" will work for the label "target: master")
|
# list of labels that a PR needs to have, checked with a regexp (e.g. "PR target:" will work for the label "PR target: master")
|
||||||
requiredLabels:
|
requiredLabels:
|
||||||
- "target: *"
|
- "PR target: *"
|
||||||
- "cla: yes"
|
- "cla: yes"
|
||||||
|
|
||||||
# list of labels that a PR shouldn't have, checked after the required labels with a regexp
|
# list of labels that a PR shouldn't have, checked after the required labels with a regexp
|
||||||
forbiddenLabels:
|
forbiddenLabels:
|
||||||
- "target: TBD"
|
- "PR target: TBD"
|
||||||
- "action: cleanup"
|
- "PR action: cleanup"
|
||||||
- "action: review"
|
- "PR action: review"
|
||||||
- "state: blocked"
|
- "PR state: blocked"
|
||||||
- "cla: no"
|
- "cla: no"
|
||||||
|
|
||||||
# list of PR statuses that need to be successful
|
# list of PR statuses that need to be successful
|
||||||
@ -127,7 +121,12 @@ merge:
|
|||||||
# the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable
|
# the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable
|
||||||
# {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option
|
# {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option
|
||||||
# {{PLACEHOLDER}} will be replaced by the list of failing checks
|
# {{PLACEHOLDER}} will be replaced by the list of failing checks
|
||||||
mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing:\n{{PLACEHOLDER}}\n\n**If you want your PR to be merged, it has to pass all the CI checks.**\n\nIf you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help."
|
mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing:
|
||||||
|
\n{{PLACEHOLDER}}
|
||||||
|
\n
|
||||||
|
\n**If you want your PR to be merged, it has to pass all the CI checks.**
|
||||||
|
\n
|
||||||
|
\nIf you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help."
|
||||||
|
|
||||||
# options for the triage plugin
|
# options for the triage plugin
|
||||||
triage:
|
triage:
|
||||||
@ -142,28 +141,24 @@ triage:
|
|||||||
# arrays of labels that determine if an issue has been fully triaged
|
# arrays of labels that determine if an issue has been fully triaged
|
||||||
l2TriageLabels:
|
l2TriageLabels:
|
||||||
-
|
-
|
||||||
- "P0"
|
- "type: bug/fix"
|
||||||
|
- "severity*"
|
||||||
|
- "freq*"
|
||||||
- "comp: *"
|
- "comp: *"
|
||||||
-
|
-
|
||||||
- "P1"
|
- "type: feature"
|
||||||
- "comp: *"
|
- "comp: *"
|
||||||
-
|
-
|
||||||
- "P2"
|
- "type: refactor"
|
||||||
- "comp: *"
|
- "comp: *"
|
||||||
-
|
-
|
||||||
- "P3"
|
- "type: RFC / Discussion / question"
|
||||||
- "comp: *"
|
- "comp: *"
|
||||||
-
|
-
|
||||||
- "P4"
|
- "type: confusing"
|
||||||
- "comp: *"
|
- "comp: *"
|
||||||
-
|
-
|
||||||
- "P5"
|
- "type: use-case"
|
||||||
- "comp: *"
|
|
||||||
-
|
|
||||||
- "feature"
|
|
||||||
- "comp: *"
|
|
||||||
-
|
|
||||||
- "discussion"
|
|
||||||
- "comp: *"
|
- "comp: *"
|
||||||
|
|
||||||
# options for the triage PR plugin
|
# options for the triage PR plugin
|
||||||
@ -191,4 +186,4 @@ rerunCircleCI:
|
|||||||
# set to true to disable
|
# set to true to disable
|
||||||
disabled: false
|
disabled: false
|
||||||
# the label which when added triggers a rerun of the default CircleCI workflow
|
# the label which when added triggers a rerun of the default CircleCI workflow
|
||||||
triggerRerunLabel: "action: rerun CI at HEAD"
|
triggerRerunLabel: "PR action: rerun CI at HEAD"
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -40,9 +40,6 @@ yarn-error.log
|
|||||||
# User specific bazel settings
|
# User specific bazel settings
|
||||||
.bazelrc.user
|
.bazelrc.user
|
||||||
|
|
||||||
# User specific ng-dev settings
|
|
||||||
.ng-dev.user*
|
|
||||||
|
|
||||||
.notes.md
|
.notes.md
|
||||||
baseline.json
|
baseline.json
|
||||||
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import {CaretakerConfig} from '../dev-infra/caretaker/config';
|
|
||||||
|
|
||||||
/** The configuration for `ng-dev caretaker` commands. */
|
|
||||||
export const caretaker: CaretakerConfig = {
|
|
||||||
githubQueries: [
|
|
||||||
{
|
|
||||||
name: 'Merge Queue',
|
|
||||||
query: `is:pr is:open status:success label:"action: merge"`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Merge Assistance Queue',
|
|
||||||
query: `is:pr is:open status:success label:"action: merge-assistance"`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Initial Triage Queue',
|
|
||||||
query: `is:open is:issue no:milestone`,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
@ -7,6 +7,18 @@ export const commitMessage: CommitMessageConfig = {
|
|||||||
maxLineLength: 120,
|
maxLineLength: 120,
|
||||||
minBodyLength: 20,
|
minBodyLength: 20,
|
||||||
minBodyLengthTypeExcludes: ['docs'],
|
minBodyLengthTypeExcludes: ['docs'],
|
||||||
|
types: [
|
||||||
|
'build',
|
||||||
|
'ci',
|
||||||
|
'docs',
|
||||||
|
'feat',
|
||||||
|
'fix',
|
||||||
|
'perf',
|
||||||
|
'refactor',
|
||||||
|
'release',
|
||||||
|
'style',
|
||||||
|
'test',
|
||||||
|
],
|
||||||
scopes: [
|
scopes: [
|
||||||
'animations',
|
'animations',
|
||||||
'bazel',
|
'bazel',
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
import {caretaker} from './caretaker';
|
|
||||||
import {commitMessage} from './commit-message';
|
import {commitMessage} from './commit-message';
|
||||||
import {format} from './format';
|
import {format} from './format';
|
||||||
import {github} from './github';
|
import {github} from './github';
|
||||||
import {merge} from './merge';
|
import {merge} from './merge';
|
||||||
import {release} from './release';
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
commitMessage,
|
commitMessage,
|
||||||
format,
|
format,
|
||||||
github,
|
github,
|
||||||
merge,
|
merge,
|
||||||
caretaker,
|
|
||||||
release,
|
|
||||||
};
|
};
|
||||||
|
@ -1,28 +1,38 @@
|
|||||||
import {DevInfraMergeConfig} from '../dev-infra/pr/merge/config';
|
import {MergeConfig} from '../dev-infra/pr/merge/config';
|
||||||
import {getDefaultTargetLabelConfiguration} from '../dev-infra/pr/merge/defaults';
|
|
||||||
import {github} from './github';
|
|
||||||
import {release} from './release';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for the merge tool in `ng-dev`. This sets up the labels which
|
* 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).
|
* are respected by the merge script (e.g. the target labels).
|
||||||
*/
|
*/
|
||||||
export const merge: DevInfraMergeConfig['merge'] = async api => {
|
export const merge = (): MergeConfig => {
|
||||||
|
// TODO: resume dynamically determining patch branch
|
||||||
|
const patch = '10.0.x';
|
||||||
return {
|
return {
|
||||||
githubApiMerge: false,
|
githubApiMerge: false,
|
||||||
claSignedLabel: 'cla: yes',
|
claSignedLabel: 'cla: yes',
|
||||||
mergeReadyLabel: /^action: merge(-assistance)?/,
|
mergeReadyLabel: /^PR action: merge(-assistance)?/,
|
||||||
caretakerNoteLabel: 'action: merge-assistance',
|
caretakerNoteLabel: 'PR action: merge-assistance',
|
||||||
commitMessageFixupLabel: 'commit message fixup',
|
commitMessageFixupLabel: 'commit message fixup',
|
||||||
// We can pick any of the NPM packages as we are in a monorepo where all packages are
|
labels: [
|
||||||
// published together with the same version and branching.
|
{
|
||||||
labels: await getDefaultTargetLabelConfiguration(api, github, release),
|
pattern: 'PR target: master-only',
|
||||||
|
branches: ['master'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: 'PR target: patch-only',
|
||||||
|
branches: [patch],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: 'PR target: master & patch',
|
||||||
|
branches: ['master', patch],
|
||||||
|
},
|
||||||
|
],
|
||||||
requiredBaseCommits: {
|
requiredBaseCommits: {
|
||||||
// PRs that target either `master` or the patch branch, need to be rebased
|
// PRs that target either `master` or the patch branch, need to be rebased
|
||||||
// on top of the latest commit message validation fix.
|
// on top of the latest commit message validation fix.
|
||||||
// These SHAs are the commits that update the required license text in the header.
|
// These SHAs are the commits that update the required license text in the header.
|
||||||
'master': '5aeb9a4124922d8ac08eb73b8f322905a32b0b3a',
|
'master': '5aeb9a4124922d8ac08eb73b8f322905a32b0b3a',
|
||||||
'10.0.x': '27b95ba64a5d99757f4042073fd1860e20e3ed24',
|
[patch]: '27b95ba64a5d99757f4042073fd1860e20e3ed24'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
import {join} from 'path';
|
|
||||||
import {exec} from 'shelljs';
|
|
||||||
import {ReleaseConfig} from '../dev-infra/release/config';
|
|
||||||
|
|
||||||
/** Configuration for the `ng-dev release` command. */
|
|
||||||
export const release: ReleaseConfig = {
|
|
||||||
npmPackages: [
|
|
||||||
'@angular/animations',
|
|
||||||
'@angular/bazel',
|
|
||||||
'@angular/common',
|
|
||||||
'@angular/compiler',
|
|
||||||
'@angular/compiler-cli',
|
|
||||||
'@angular/core',
|
|
||||||
'@angular/elements',
|
|
||||||
'@angular/forms',
|
|
||||||
'@angular/language-service',
|
|
||||||
'@angular/localize',
|
|
||||||
'@angular/platform-browser',
|
|
||||||
'@angular/platform-browser-dynamic',
|
|
||||||
'@angular/platform-server',
|
|
||||||
'@angular/platform-webworker',
|
|
||||||
'@angular/platform-webworker-dynamic',
|
|
||||||
'@angular/router',
|
|
||||||
'@angular/service-worker',
|
|
||||||
'@angular/upgrade',
|
|
||||||
],
|
|
||||||
// TODO: Implement release package building here.
|
|
||||||
buildPackages: async () => [],
|
|
||||||
// TODO: This can be removed once there is a org-wide tool for changelog generation.
|
|
||||||
generateReleaseNotesForHead: async () => {
|
|
||||||
exec('yarn -s gulp changelog', {cwd: join(__dirname, '../')});
|
|
||||||
},
|
|
||||||
};
|
|
116
.pullapprove.yml
116
.pullapprove.yml
@ -115,42 +115,6 @@ pullapprove_conditions:
|
|||||||
|
|
||||||
|
|
||||||
groups:
|
groups:
|
||||||
# =========================================================
|
|
||||||
# Global Approvers
|
|
||||||
#
|
|
||||||
# All reviews performed for global approvals require using
|
|
||||||
# the `Reviewed-for:` specifier to set the approval
|
|
||||||
# specificity as documented at:
|
|
||||||
# https://docs.pullapprove.com/reviewed-for/
|
|
||||||
# =========================================================
|
|
||||||
global-approvers:
|
|
||||||
type: optional
|
|
||||||
reviewers:
|
|
||||||
teams:
|
|
||||||
- framework-global-approvers
|
|
||||||
reviews:
|
|
||||||
request: 0
|
|
||||||
required: 1
|
|
||||||
reviewed_for: required
|
|
||||||
|
|
||||||
# =========================================================
|
|
||||||
# Global Approvers For Docs
|
|
||||||
#
|
|
||||||
# All reviews performed for global docs approvals require
|
|
||||||
# using the `Reviewed-for:` specifier to set the approval
|
|
||||||
# specificity as documented at:
|
|
||||||
# https://docs.pullapprove.com/reviewed-for/
|
|
||||||
# =========================================================
|
|
||||||
global-docs-approvers:
|
|
||||||
type: optional
|
|
||||||
reviewers:
|
|
||||||
teams:
|
|
||||||
- framework-global-approvers-for-docs-only-changes
|
|
||||||
reviews:
|
|
||||||
request: 0
|
|
||||||
required: 1
|
|
||||||
reviewed_for: required
|
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Require review on all PRs
|
# Require review on all PRs
|
||||||
#
|
#
|
||||||
@ -159,9 +123,6 @@ groups:
|
|||||||
# one review is provided before the group is satisfied.
|
# one review is provided before the group is satisfied.
|
||||||
# =========================================================
|
# =========================================================
|
||||||
required-minimum-review:
|
required-minimum-review:
|
||||||
conditions:
|
|
||||||
- *can-be-global-approved
|
|
||||||
- *can-be-global-docs-approved
|
|
||||||
reviews:
|
reviews:
|
||||||
request: 0 # Do not request any reviews from the reviewer group
|
request: 0 # Do not request any reviews from the reviewer group
|
||||||
required: 1 # Require that all PRs have approval from at least one of the users in the group
|
required: 1 # Require that all PRs have approval from at least one of the users in the group
|
||||||
@ -196,12 +157,48 @@ groups:
|
|||||||
- manughub # Manu Murthy
|
- manughub # Manu Murthy
|
||||||
- mgechev # Minko Gechev
|
- mgechev # Minko Gechev
|
||||||
- mhevery # Miško Hevery
|
- mhevery # Miško Hevery
|
||||||
|
- michaelprentice # Michael Prentice
|
||||||
- mmalerba # Miles Malerba
|
- mmalerba # Miles Malerba
|
||||||
- petebacondarwin # Pete Bacon Darwin
|
- petebacondarwin # Pete Bacon Darwin
|
||||||
- pkozlowski-opensource # Pawel Kozlowski
|
- pkozlowski-opensource # Pawel Kozlowski
|
||||||
- Splaktar # Michael Prentice
|
|
||||||
- StephenFluin # Stephen Fluin
|
- StephenFluin # Stephen Fluin
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# Global Approvers
|
||||||
|
#
|
||||||
|
# All reviews performed for global approvals require using
|
||||||
|
# the `Reviewed-for:` specifier to set the approval
|
||||||
|
# specificity as documented at:
|
||||||
|
# https://docs.pullapprove.com/reviewed-for/
|
||||||
|
# =========================================================
|
||||||
|
global-approvers:
|
||||||
|
type: optional
|
||||||
|
reviewers:
|
||||||
|
teams:
|
||||||
|
- framework-global-approvers
|
||||||
|
reviews:
|
||||||
|
request: 0
|
||||||
|
required: 1
|
||||||
|
reviewed_for: required
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# Global Approvers For Docs
|
||||||
|
#
|
||||||
|
# All reviews performed for global docs approvals require
|
||||||
|
# using the `Reviewed-for:` specifier to set the approval
|
||||||
|
# specificity as documented at:
|
||||||
|
# https://docs.pullapprove.com/reviewed-for/
|
||||||
|
# =========================================================
|
||||||
|
global-docs-approvers:
|
||||||
|
type: optional
|
||||||
|
reviewers:
|
||||||
|
teams:
|
||||||
|
- framework-global-approvers-for-docs-only-changes
|
||||||
|
reviews:
|
||||||
|
request: 0
|
||||||
|
required: 1
|
||||||
|
reviewed_for: required
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Framework: Animations
|
# Framework: Animations
|
||||||
# =========================================================
|
# =========================================================
|
||||||
@ -284,7 +281,7 @@ groups:
|
|||||||
users:
|
users:
|
||||||
- alxhub
|
- alxhub
|
||||||
- crisbeto
|
- crisbeto
|
||||||
# OOO as of 2020-09-28 - devversion
|
- devversion
|
||||||
|
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
@ -326,7 +323,6 @@ groups:
|
|||||||
'aio/content/examples/component-interaction/**',
|
'aio/content/examples/component-interaction/**',
|
||||||
'aio/content/images/guide/component-interaction/**',
|
'aio/content/images/guide/component-interaction/**',
|
||||||
'aio/content/guide/component-styles.md',
|
'aio/content/guide/component-styles.md',
|
||||||
'aio/content/guide/view-encapsulation.md',
|
|
||||||
'aio/content/examples/component-styles/**',
|
'aio/content/examples/component-styles/**',
|
||||||
'aio/content/guide/dependency-injection.md',
|
'aio/content/guide/dependency-injection.md',
|
||||||
'aio/content/examples/dependency-injection/**',
|
'aio/content/examples/dependency-injection/**',
|
||||||
@ -336,7 +332,6 @@ groups:
|
|||||||
'aio/content/images/guide/dependency-injection-in-action/**',
|
'aio/content/images/guide/dependency-injection-in-action/**',
|
||||||
'aio/content/guide/dependency-injection-navtree.md',
|
'aio/content/guide/dependency-injection-navtree.md',
|
||||||
'aio/content/guide/dependency-injection-providers.md',
|
'aio/content/guide/dependency-injection-providers.md',
|
||||||
'aio/content/guide/lightweight-injection-tokens.md',
|
|
||||||
'aio/content/guide/displaying-data.md',
|
'aio/content/guide/displaying-data.md',
|
||||||
'aio/content/examples/displaying-data/**',
|
'aio/content/examples/displaying-data/**',
|
||||||
'aio/content/images/guide/displaying-data/**',
|
'aio/content/images/guide/displaying-data/**',
|
||||||
@ -420,7 +415,7 @@ groups:
|
|||||||
- atscott
|
- atscott
|
||||||
- ~kara # do not request reviews from Kara, but allow her to approve PRs
|
- ~kara # do not request reviews from Kara, but allow her to approve PRs
|
||||||
- mhevery
|
- mhevery
|
||||||
# OOO as of 2020-09-28 - pkozlowski-opensource
|
- pkozlowski-opensource
|
||||||
|
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
@ -663,7 +658,7 @@ groups:
|
|||||||
users:
|
users:
|
||||||
- AndrewKushnir
|
- AndrewKushnir
|
||||||
- IgorMinar
|
- IgorMinar
|
||||||
# OOO as of 2020-09-28 - pkozlowski-opensource
|
- pkozlowski-opensource
|
||||||
|
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
@ -680,7 +675,7 @@ groups:
|
|||||||
reviewers:
|
reviewers:
|
||||||
users:
|
users:
|
||||||
- IgorMinar
|
- IgorMinar
|
||||||
# OOO as of 2020-09-28 - pkozlowski-opensource
|
- pkozlowski-opensource
|
||||||
|
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
@ -698,7 +693,7 @@ groups:
|
|||||||
users:
|
users:
|
||||||
- IgorMinar
|
- IgorMinar
|
||||||
- jelbourn
|
- jelbourn
|
||||||
# OOO as of 2020-09-28 - pkozlowski-opensource
|
- pkozlowski-opensource
|
||||||
|
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
@ -724,7 +719,7 @@ groups:
|
|||||||
- IgorMinar
|
- IgorMinar
|
||||||
- mhevery
|
- mhevery
|
||||||
- jelbourn
|
- jelbourn
|
||||||
# OOO as of 2020-09-28 - pkozlowski-opensource
|
- pkozlowski-opensource
|
||||||
reviews:
|
reviews:
|
||||||
request: -1 # request reviews from everyone
|
request: -1 # request reviews from everyone
|
||||||
required: 2 # require at least 2 approvals
|
required: 2 # require at least 2 approvals
|
||||||
@ -788,21 +783,6 @@ groups:
|
|||||||
- JiaLiPassion
|
- JiaLiPassion
|
||||||
- mhevery
|
- mhevery
|
||||||
|
|
||||||
# =========================================================
|
|
||||||
# in-memory-web-api
|
|
||||||
# =========================================================
|
|
||||||
in-memory-web-api:
|
|
||||||
conditions:
|
|
||||||
- *can-be-global-approved
|
|
||||||
- *can-be-global-docs-approved
|
|
||||||
- >
|
|
||||||
contains_any_globs(files, [
|
|
||||||
'packages/misc/angular-in-memory-web-api/**',
|
|
||||||
])
|
|
||||||
reviewers:
|
|
||||||
users:
|
|
||||||
- IgorMinar
|
|
||||||
- crisbeto
|
|
||||||
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# Benchpress
|
# Benchpress
|
||||||
@ -1111,12 +1091,10 @@ groups:
|
|||||||
'dev-infra/**',
|
'dev-infra/**',
|
||||||
'docs/BAZEL.md',
|
'docs/BAZEL.md',
|
||||||
'docs/CARETAKER.md',
|
'docs/CARETAKER.md',
|
||||||
'docs/CODING_STANDARDS.md',
|
|
||||||
'docs/COMMITTER.md',
|
'docs/COMMITTER.md',
|
||||||
'docs/DEBUG.md',
|
'docs/DEBUG.md',
|
||||||
'docs/DEBUG_COMPONENTS_REPO_IVY.md',
|
'docs/DEBUG_COMPONENTS_REPO_IVY.md',
|
||||||
'docs/DEVELOPER.md',
|
'docs/DEVELOPER.md',
|
||||||
'docs/FIXUP_COMMITS.md',
|
|
||||||
'docs/GITHUB_PROCESS.md',
|
'docs/GITHUB_PROCESS.md',
|
||||||
'docs/PR_REVIEW.md',
|
'docs/PR_REVIEW.md',
|
||||||
'docs/SAVED_REPLIES.md',
|
'docs/SAVED_REPLIES.md',
|
||||||
@ -1152,7 +1130,7 @@ groups:
|
|||||||
])
|
])
|
||||||
reviewers:
|
reviewers:
|
||||||
users:
|
users:
|
||||||
# OOO as of 2020-09-28 - devversion
|
- devversion
|
||||||
- filipesilva
|
- filipesilva
|
||||||
- gkalpak
|
- gkalpak
|
||||||
- IgorMinar
|
- IgorMinar
|
||||||
@ -1186,7 +1164,7 @@ groups:
|
|||||||
- atscott
|
- atscott
|
||||||
- jelbourn
|
- jelbourn
|
||||||
- petebacondarwin
|
- petebacondarwin
|
||||||
# OOO as of 2020-09-28 - pkozlowski-opensource
|
- pkozlowski-opensource
|
||||||
reviews:
|
reviews:
|
||||||
request: 4 # Request reviews from four people
|
request: 4 # Request reviews from four people
|
||||||
required: 3 # Require that three people approve
|
required: 3 # Require that three people approve
|
||||||
@ -1214,7 +1192,7 @@ groups:
|
|||||||
- atscott
|
- atscott
|
||||||
- jelbourn
|
- jelbourn
|
||||||
- petebacondarwin
|
- petebacondarwin
|
||||||
# OOO as of 2020-09-28 - pkozlowski-opensource
|
- pkozlowski-opensource
|
||||||
reviews:
|
reviews:
|
||||||
request: 4 # Request reviews from four people
|
request: 4 # Request reviews from four people
|
||||||
required: 2 # Require that two people approve
|
required: 2 # Require that two people approve
|
||||||
@ -1242,7 +1220,7 @@ groups:
|
|||||||
- atscott
|
- atscott
|
||||||
- jelbourn
|
- jelbourn
|
||||||
- petebacondarwin
|
- petebacondarwin
|
||||||
# OOO as of 2020-09-28 - pkozlowski-opensource
|
- pkozlowski-opensource
|
||||||
|
|
||||||
|
|
||||||
####################################################################################
|
####################################################################################
|
||||||
|
@ -44654,7 +44654,7 @@ const FOLDERS_IGNORE = [
|
|||||||
const DEFAULT_IGNORE = (0, (_filter || _load_filter()).ignoreLinesToRegex)([...FOLDERS_IGNORE,
|
const DEFAULT_IGNORE = (0, (_filter || _load_filter()).ignoreLinesToRegex)([...FOLDERS_IGNORE,
|
||||||
|
|
||||||
// ignore cruft
|
// ignore cruft
|
||||||
'yarn.lock', '.lock-wscript', '.wafpickle-{0..9}', '*.swp', '._*', 'npm-debug.log', 'yarn-error.log', '.npmrc', '.yarnrc', '.yarnrc.yml', '.npmignore', '.gitignore', '.DS_Store']);
|
'yarn.lock', '.lock-wscript', '.wafpickle-{0..9}', '*.swp', '._*', 'npm-debug.log', 'yarn-error.log', '.npmrc', '.yarnrc', '.npmignore', '.gitignore', '.DS_Store']);
|
||||||
|
|
||||||
const NEVER_IGNORE = (0, (_filter || _load_filter()).ignoreLinesToRegex)([
|
const NEVER_IGNORE = (0, (_filter || _load_filter()).ignoreLinesToRegex)([
|
||||||
// never ignore these files
|
// never ignore these files
|
||||||
@ -44663,7 +44663,6 @@ const NEVER_IGNORE = (0, (_filter || _load_filter()).ignoreLinesToRegex)([
|
|||||||
function packWithIgnoreAndHeaders(cwd, ignoreFunction, { mapHeader } = {}) {
|
function packWithIgnoreAndHeaders(cwd, ignoreFunction, { mapHeader } = {}) {
|
||||||
return tar.pack(cwd, {
|
return tar.pack(cwd, {
|
||||||
ignore: ignoreFunction,
|
ignore: ignoreFunction,
|
||||||
sort: true,
|
|
||||||
map: header => {
|
map: header => {
|
||||||
const suffix = header.name === '.' ? '' : `/${header.name}`;
|
const suffix = header.name === '.' ? '' : `/${header.name}`;
|
||||||
header.name = `package${suffix}`;
|
header.name = `package${suffix}`;
|
||||||
@ -46679,7 +46678,7 @@ function mkdirfix (name, opts, cb) {
|
|||||||
/* 194 */
|
/* 194 */
|
||||||
/***/ (function(module, exports) {
|
/***/ (function(module, exports) {
|
||||||
|
|
||||||
module.exports = {"name":"yarn","installationMethod":"unknown","version":"1.22.5","license":"BSD-2-Clause","preferGlobal":true,"description":"📦🐈 Fast, reliable, and secure dependency management.","dependencies":{"@zkochan/cmd-shim":"^3.1.0","babel-runtime":"^6.26.0","bytes":"^3.0.0","camelcase":"^4.0.0","chalk":"^2.1.0","cli-table3":"^0.4.0","commander":"^2.9.0","death":"^1.0.0","debug":"^3.0.0","deep-equal":"^1.0.1","detect-indent":"^5.0.0","dnscache":"^1.0.1","glob":"^7.1.1","gunzip-maybe":"^1.4.0","hash-for-dep":"^1.2.3","imports-loader":"^0.8.0","ini":"^1.3.4","inquirer":"^6.2.0","invariant":"^2.2.0","is-builtin-module":"^2.0.0","is-ci":"^1.0.10","is-webpack-bundle":"^1.0.0","js-yaml":"^3.13.1","leven":"^2.0.0","loud-rejection":"^1.2.0","micromatch":"^2.3.11","mkdirp":"^0.5.1","node-emoji":"^1.6.1","normalize-url":"^2.0.0","npm-logical-tree":"^1.2.1","object-path":"^0.11.2","proper-lockfile":"^2.0.0","puka":"^1.0.0","read":"^1.0.7","request":"^2.87.0","request-capture-har":"^1.2.2","rimraf":"^2.5.0","semver":"^5.1.0","ssri":"^5.3.0","strip-ansi":"^4.0.0","strip-bom":"^3.0.0","tar-fs":"^1.16.0","tar-stream":"^1.6.1","uuid":"^3.0.1","v8-compile-cache":"^2.0.0","validate-npm-package-license":"^3.0.4","yn":"^2.0.0"},"devDependencies":{"babel-core":"^6.26.0","babel-eslint":"^7.2.3","babel-loader":"^6.2.5","babel-plugin-array-includes":"^2.0.3","babel-plugin-inline-import":"^3.0.0","babel-plugin-transform-builtin-extend":"^1.1.2","babel-plugin-transform-inline-imports-commonjs":"^1.0.0","babel-plugin-transform-runtime":"^6.4.3","babel-preset-env":"^1.6.0","babel-preset-flow":"^6.23.0","babel-preset-stage-0":"^6.0.0","babylon":"^6.5.0","commitizen":"^2.9.6","cz-conventional-changelog":"^2.0.0","eslint":"^4.3.0","eslint-config-fb-strict":"^22.0.0","eslint-plugin-babel":"^5.0.0","eslint-plugin-flowtype":"^2.35.0","eslint-plugin-jasmine":"^2.6.2","eslint-plugin-jest":"^21.0.0","eslint-plugin-jsx-a11y":"^6.0.2","eslint-plugin-prefer-object-spread":"^1.2.1","eslint-plugin-prettier":"^2.1.2","eslint-plugin-react":"^7.1.0","eslint-plugin-relay":"^0.0.28","eslint-plugin-yarn-internal":"file:scripts/eslint-rules","execa":"^0.11.0","fancy-log":"^1.3.2","flow-bin":"^0.66.0","git-release-notes":"^3.0.0","gulp":"^4.0.0","gulp-babel":"^7.0.0","gulp-if":"^2.0.1","gulp-newer":"^1.0.0","gulp-plumber":"^1.0.1","gulp-sourcemaps":"^2.2.0","jest":"^22.4.4","jsinspect":"^0.12.6","minimatch":"^3.0.4","mock-stdin":"^0.3.0","prettier":"^1.5.2","string-replace-loader":"^2.1.1","temp":"^0.8.3","webpack":"^2.1.0-beta.25","yargs":"^6.3.0"},"resolutions":{"sshpk":"^1.14.2"},"engines":{"node":">=4.0.0"},"repository":"yarnpkg/yarn","bin":{"yarn":"./bin/yarn.js","yarnpkg":"./bin/yarn.js"},"scripts":{"build":"gulp build","build-bundle":"node ./scripts/build-webpack.js","build-chocolatey":"powershell ./scripts/build-chocolatey.ps1","build-deb":"./scripts/build-deb.sh","build-dist":"bash ./scripts/build-dist.sh","build-win-installer":"scripts\\build-windows-installer.bat","changelog":"git-release-notes $(git describe --tags --abbrev=0 $(git describe --tags --abbrev=0)^)..$(git describe --tags --abbrev=0) scripts/changelog.md","dupe-check":"yarn jsinspect ./src","lint":"eslint . && flow check","pkg-tests":"yarn --cwd packages/pkg-tests jest yarn.test.js","prettier":"eslint src __tests__ --fix","release-branch":"./scripts/release-branch.sh","test":"yarn lint && yarn test-only","test-only":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --verbose","test-only-debug":"node --inspect-brk --max_old_space_size=4096 node_modules/jest/bin/jest.js --runInBand --verbose","test-coverage":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --coverage --verbose","watch":"gulp watch","commit":"git-cz"},"jest":{"collectCoverageFrom":["src/**/*.js"],"testEnvironment":"node","modulePathIgnorePatterns":["__tests__/fixtures/","packages/pkg-tests/pkg-tests-fixtures","dist/"],"testPathIgnorePatterns":["__tests__/(fixtures|__mocks__)/","updates/","_(temp|mock|install|init|helpers).js$","packages/pkg-tests"]},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}}}
|
module.exports = {"name":"yarn","installationMethod":"unknown","version":"1.22.4","license":"BSD-2-Clause","preferGlobal":true,"description":"📦🐈 Fast, reliable, and secure dependency management.","dependencies":{"@zkochan/cmd-shim":"^3.1.0","babel-runtime":"^6.26.0","bytes":"^3.0.0","camelcase":"^4.0.0","chalk":"^2.1.0","cli-table3":"^0.4.0","commander":"^2.9.0","death":"^1.0.0","debug":"^3.0.0","deep-equal":"^1.0.1","detect-indent":"^5.0.0","dnscache":"^1.0.1","glob":"^7.1.1","gunzip-maybe":"^1.4.0","hash-for-dep":"^1.2.3","imports-loader":"^0.8.0","ini":"^1.3.4","inquirer":"^6.2.0","invariant":"^2.2.0","is-builtin-module":"^2.0.0","is-ci":"^1.0.10","is-webpack-bundle":"^1.0.0","js-yaml":"^3.13.1","leven":"^2.0.0","loud-rejection":"^1.2.0","micromatch":"^2.3.11","mkdirp":"^0.5.1","node-emoji":"^1.6.1","normalize-url":"^2.0.0","npm-logical-tree":"^1.2.1","object-path":"^0.11.2","proper-lockfile":"^2.0.0","puka":"^1.0.0","read":"^1.0.7","request":"^2.87.0","request-capture-har":"^1.2.2","rimraf":"^2.5.0","semver":"^5.1.0","ssri":"^5.3.0","strip-ansi":"^4.0.0","strip-bom":"^3.0.0","tar-fs":"^1.16.0","tar-stream":"^1.6.1","uuid":"^3.0.1","v8-compile-cache":"^2.0.0","validate-npm-package-license":"^3.0.4","yn":"^2.0.0"},"devDependencies":{"babel-core":"^6.26.0","babel-eslint":"^7.2.3","babel-loader":"^6.2.5","babel-plugin-array-includes":"^2.0.3","babel-plugin-inline-import":"^3.0.0","babel-plugin-transform-builtin-extend":"^1.1.2","babel-plugin-transform-inline-imports-commonjs":"^1.0.0","babel-plugin-transform-runtime":"^6.4.3","babel-preset-env":"^1.6.0","babel-preset-flow":"^6.23.0","babel-preset-stage-0":"^6.0.0","babylon":"^6.5.0","commitizen":"^2.9.6","cz-conventional-changelog":"^2.0.0","eslint":"^4.3.0","eslint-config-fb-strict":"^22.0.0","eslint-plugin-babel":"^5.0.0","eslint-plugin-flowtype":"^2.35.0","eslint-plugin-jasmine":"^2.6.2","eslint-plugin-jest":"^21.0.0","eslint-plugin-jsx-a11y":"^6.0.2","eslint-plugin-prefer-object-spread":"^1.2.1","eslint-plugin-prettier":"^2.1.2","eslint-plugin-react":"^7.1.0","eslint-plugin-relay":"^0.0.28","eslint-plugin-yarn-internal":"file:scripts/eslint-rules","execa":"^0.11.0","fancy-log":"^1.3.2","flow-bin":"^0.66.0","git-release-notes":"^3.0.0","gulp":"^4.0.0","gulp-babel":"^7.0.0","gulp-if":"^2.0.1","gulp-newer":"^1.0.0","gulp-plumber":"^1.0.1","gulp-sourcemaps":"^2.2.0","jest":"^22.4.4","jsinspect":"^0.12.6","minimatch":"^3.0.4","mock-stdin":"^0.3.0","prettier":"^1.5.2","string-replace-loader":"^2.1.1","temp":"^0.8.3","webpack":"^2.1.0-beta.25","yargs":"^6.3.0"},"resolutions":{"sshpk":"^1.14.2"},"engines":{"node":">=4.0.0"},"repository":"yarnpkg/yarn","bin":{"yarn":"./bin/yarn.js","yarnpkg":"./bin/yarn.js"},"scripts":{"build":"gulp build","build-bundle":"node ./scripts/build-webpack.js","build-chocolatey":"powershell ./scripts/build-chocolatey.ps1","build-deb":"./scripts/build-deb.sh","build-dist":"bash ./scripts/build-dist.sh","build-win-installer":"scripts\\build-windows-installer.bat","changelog":"git-release-notes $(git describe --tags --abbrev=0 $(git describe --tags --abbrev=0)^)..$(git describe --tags --abbrev=0) scripts/changelog.md","dupe-check":"yarn jsinspect ./src","lint":"eslint . && flow check","pkg-tests":"yarn --cwd packages/pkg-tests jest yarn.test.js","prettier":"eslint src __tests__ --fix","release-branch":"./scripts/release-branch.sh","test":"yarn lint && yarn test-only","test-only":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --verbose","test-only-debug":"node --inspect-brk --max_old_space_size=4096 node_modules/jest/bin/jest.js --runInBand --verbose","test-coverage":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --coverage --verbose","watch":"gulp watch","commit":"git-cz"},"jest":{"collectCoverageFrom":["src/**/*.js"],"testEnvironment":"node","modulePathIgnorePatterns":["__tests__/fixtures/","packages/pkg-tests/pkg-tests-fixtures","dist/"],"testPathIgnorePatterns":["__tests__/(fixtures|__mocks__)/","updates/","_(temp|mock|install|init|helpers).js$","packages/pkg-tests"]},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}}}
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
/* 195 */
|
/* 195 */
|
||||||
@ -98339,7 +98338,7 @@ var _buildSubCommands = (0, (_buildSubCommands2 || _load_buildSubCommands()).def
|
|||||||
|
|
||||||
const bundle = yield fetchBundle(config, bundleUrl);
|
const bundle = yield fetchBundle(config, bundleUrl);
|
||||||
|
|
||||||
const yarnPath = path.resolve(config.lockfileFolder, `.yarn/releases/yarn-${bundleVersion}.cjs`);
|
const yarnPath = path.resolve(config.lockfileFolder, `.yarn/releases/yarn-${bundleVersion}.js`);
|
||||||
reporter.log(`Saving it into ${chalk.magenta(yarnPath)}...`);
|
reporter.log(`Saving it into ${chalk.magenta(yarnPath)}...`);
|
||||||
yield (_fs || _load_fs()).mkdirp(path.dirname(yarnPath));
|
yield (_fs || _load_fs()).mkdirp(path.dirname(yarnPath));
|
||||||
yield (_fs || _load_fs()).writeFile(yarnPath, bundle);
|
yield (_fs || _load_fs()).writeFile(yarnPath, bundle);
|
||||||
@ -100191,7 +100190,7 @@ let main = exports.main = (() => {
|
|||||||
|
|
||||||
const config = new (_config || _load_config()).default(reporter);
|
const config = new (_config || _load_config()).default(reporter);
|
||||||
const outputWrapperEnabled = (0, (_conversion || _load_conversion()).boolifyWithDefault)(process.env.YARN_WRAP_OUTPUT, true);
|
const outputWrapperEnabled = (0, (_conversion || _load_conversion()).boolifyWithDefault)(process.env.YARN_WRAP_OUTPUT, true);
|
||||||
const shouldWrapOutput = outputWrapperEnabled && !(_commander || _load_commander()).default.json && command.hasWrapper((_commander || _load_commander()).default, (_commander || _load_commander()).default.args) && !(commandName === 'init' && (_commander || _load_commander()).default[`2`]);
|
const shouldWrapOutput = outputWrapperEnabled && !(_commander || _load_commander()).default.json && command.hasWrapper((_commander || _load_commander()).default, (_commander || _load_commander()).default.args);
|
||||||
|
|
||||||
if (shouldWrapOutput) {
|
if (shouldWrapOutput) {
|
||||||
reporter.header(commandName, { name: 'yarn', version: (_yarnVersion || _load_yarnVersion()).version });
|
reporter.header(commandName, { name: 'yarn', version: (_yarnVersion || _load_yarnVersion()).version });
|
||||||
@ -100605,7 +100604,7 @@ let start = (() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (/\.[cm]?js$/.test(yarnPath)) {
|
if (yarnPath.endsWith(`.js`)) {
|
||||||
exitCode = yield (0, (_child || _load_child()).spawnp)(process.execPath, [yarnPath, ...argv], opts);
|
exitCode = yield (0, (_child || _load_child()).spawnp)(process.execPath, [yarnPath, ...argv], opts);
|
||||||
} else {
|
} else {
|
||||||
exitCode = yield (0, (_child || _load_child()).spawnp)(yarnPath, argv, opts);
|
exitCode = yield (0, (_child || _load_child()).spawnp)(yarnPath, argv, opts);
|
2
.yarnrc
2
.yarnrc
@ -2,4 +2,4 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
yarn-path ".yarn/releases/yarn-1.22.5.js"
|
yarn-path ".yarn/releases/yarn-1.22.4.js"
|
||||||
|
@ -20,9 +20,9 @@ filegroup(
|
|||||||
# do not sort
|
# do not sort
|
||||||
srcs = [
|
srcs = [
|
||||||
"@npm//:node_modules/core-js/client/core.js",
|
"@npm//:node_modules/core-js/client/core.js",
|
||||||
"//packages/zone.js/bundles:zone.umd.js",
|
"//packages/zone.js/dist:zone.js",
|
||||||
"//packages/zone.js/bundles:zone-testing.umd.js",
|
"//packages/zone.js/dist:zone-testing.js",
|
||||||
"//packages/zone.js/bundles:task-tracking.umd.js",
|
"//packages/zone.js/dist:task-tracking.js",
|
||||||
"//:test-events.js",
|
"//:test-events.js",
|
||||||
"//:third_party/shims_for_IE.js",
|
"//:third_party/shims_for_IE.js",
|
||||||
# Including systemjs because it defines `__eval`, which produces correct stack traces.
|
# Including systemjs because it defines `__eval`, which produces correct stack traces.
|
||||||
@ -34,7 +34,7 @@ filegroup(
|
|||||||
filegroup(
|
filegroup(
|
||||||
name = "angularjs_scripts",
|
name = "angularjs_scripts",
|
||||||
srcs = [
|
srcs = [
|
||||||
# We also declare the unminified AngularJS files since these can be used for
|
# We also declare the unminfied AngularJS files since these can be used for
|
||||||
# local debugging (e.g. see: packages/upgrade/test/common/test_helpers.ts)
|
# local debugging (e.g. see: packages/upgrade/test/common/test_helpers.ts)
|
||||||
"@npm//:node_modules/angular/angular.js",
|
"@npm//:node_modules/angular/angular.js",
|
||||||
"@npm//:node_modules/angular/angular.min.js",
|
"@npm//:node_modules/angular/angular.min.js",
|
||||||
|
384
CHANGELOG.md
384
CHANGELOG.md
@ -1,206 +1,3 @@
|
|||||||
<a name="10.1.5"></a>
|
|
||||||
## 10.1.5 (2020-10-07)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **router:** update getRouteGuards to check if the context outlet is activated ([#39049](https://github.com/angular/angular/issues/39049)) ([771f731](https://github.com/angular/angular/commit/771f731)), closes [#39030](https://github.com/angular/angular/issues/39030)
|
|
||||||
* **compiler:** Recover on malformed keyed reads and keyed writes ([#39004](https://github.com/angular/angular/issues/39004)) ([f50313f](https://github.com/angular/angular/commit/f50313f)), closes [#38596](https://github.com/angular/angular/issues/38596)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.1.4"></a>
|
|
||||||
## 10.1.4 (2020-09-30)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compiler-cli:** enable [@types](https://github.com/types) discovery in incremental rebuilds ([#39011](https://github.com/angular/angular/issues/39011)) ([6e99427](https://github.com/angular/angular/commit/6e99427)), closes [#38979](https://github.com/angular/angular/issues/38979)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.1.3"></a>
|
|
||||||
## 10.1.3 (2020-09-23)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **http:** Fix error message when we call jsonp without importing HttpClientJsonpModule ([#38756](https://github.com/angular/angular/issues/38756)) ([3902ec0](https://github.com/angular/angular/commit/3902ec0))
|
|
||||||
* **ngcc:** fix compilation of `ChangeDetectorRef` in pipe constructors ([#38892](https://github.com/angular/angular/issues/38892)) ([093c3a1](https://github.com/angular/angular/commit/093c3a1)), closes [#38666](https://github.com/angular/angular/issues/38666) [#38883](https://github.com/angular/angular/issues/38883)
|
|
||||||
|
|
||||||
|
|
||||||
### Reverts
|
|
||||||
|
|
||||||
* feat(router): better warning message when a router outlet has not been instantiated ([#38920](https://github.com/angular/angular/issues/38920)) ([04d0aa6](https://github.com/angular/angular/commit/04d0aa6))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.1.2"></a>
|
|
||||||
## 10.1.2 (2020-09-16)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compiler:** detect pipes in ICUs in template binder ([#38810](https://github.com/angular/angular/issues/38810)) ([ec2dbe7](https://github.com/angular/angular/commit/ec2dbe7)), closes [#38539](https://github.com/angular/angular/issues/38539) [#38539](https://github.com/angular/angular/issues/38539) [#38539](https://github.com/angular/angular/issues/38539)
|
|
||||||
* **core:** clear the `RefreshTransplantedView` when detached ([#38768](https://github.com/angular/angular/issues/38768)) ([edb7f90](https://github.com/angular/angular/commit/edb7f90)), closes [#38619](https://github.com/angular/angular/issues/38619)
|
|
||||||
* **localize:** ensure that `formatOptions` is optional ([#38787](https://github.com/angular/angular/issues/38787)) ([a47383d](https://github.com/angular/angular/commit/a47383d))
|
|
||||||
* **router:** Ensure routes are processed in priority order and only if needed ([#38780](https://github.com/angular/angular/issues/38780)) ([9c51ba3](https://github.com/angular/angular/commit/9c51ba3)), closes [#38691](https://github.com/angular/angular/issues/38691)
|
|
||||||
* **upgrade:** add try/catch when downgrading injectables ([#38671](https://github.com/angular/angular/issues/38671)) ([5de2ac3](https://github.com/angular/angular/commit/5de2ac3)), closes [#37579](https://github.com/angular/angular/issues/37579)
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* **compiler-cli:** only emit directive/pipe references that are used ([#38843](https://github.com/angular/angular/issues/38843)) ([5658405](https://github.com/angular/angular/commit/5658405))
|
|
||||||
* **compiler-cli:** optimize computation of type-check scope information ([#38843](https://github.com/angular/angular/issues/38843)) ([ebede67](https://github.com/angular/angular/commit/ebede67))
|
|
||||||
* **ngcc:** introduce cache for sharing data across entry-points ([#38840](https://github.com/angular/angular/issues/38840)) ([58411e7](https://github.com/angular/angular/commit/58411e7))
|
|
||||||
* **ngcc:** reduce maximum worker count ([#38840](https://github.com/angular/angular/issues/38840)) ([ea36466](https://github.com/angular/angular/commit/ea36466))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.1.1"></a>
|
|
||||||
## 10.1.1 (2020-09-09)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compiler:** correct confusion between field and property names ([#38685](https://github.com/angular/angular/issues/38685)) ([a1c34c6](https://github.com/angular/angular/commit/a1c34c6))
|
|
||||||
* **compiler-cli:** compute source-mappings for localized strings ([#38747](https://github.com/angular/angular/issues/38747)) ([b4eb016](https://github.com/angular/angular/commit/b4eb016)), closes [#38588](https://github.com/angular/angular/issues/38588)
|
|
||||||
* **compiler-cli:** ensure that a declaration is available in type-to-value conversion ([#38684](https://github.com/angular/angular/issues/38684)) ([56d5ff2](https://github.com/angular/angular/commit/56d5ff2)), closes [#38670](https://github.com/angular/angular/issues/38670)
|
|
||||||
* **core:** reset `tView` between tests in Ivy TestBed ([#38659](https://github.com/angular/angular/issues/38659)) ([efc7606](https://github.com/angular/angular/commit/efc7606)), closes [#38600](https://github.com/angular/angular/issues/38600)
|
|
||||||
* **localize:** do not expose NodeJS typings in $localize runtime code ([#38700](https://github.com/angular/angular/issues/38700)) ([4de8dc3](https://github.com/angular/angular/commit/4de8dc3)), closes [#38692](https://github.com/angular/angular/issues/38692)
|
|
||||||
* **localize:** enable whitespace preservation marker in XLIFF files ([#38737](https://github.com/angular/angular/issues/38737)) ([190dca0](https://github.com/angular/angular/commit/190dca0)), closes [#38679](https://github.com/angular/angular/issues/38679)
|
|
||||||
* **localize:** install `[@angular](https://github.com/angular)/localize` in `devDependencies` by default ([#38680](https://github.com/angular/angular/issues/38680)) ([dbab744](https://github.com/angular/angular/commit/dbab744)), closes [#38329](https://github.com/angular/angular/issues/38329)
|
|
||||||
* **localize:** render context of translation file parse errors ([#38673](https://github.com/angular/angular/issues/38673)) ([32f33f0](https://github.com/angular/angular/commit/32f33f0)), closes [#38377](https://github.com/angular/angular/issues/38377)
|
|
||||||
* **localize:** render location in XLIFF 2 even if there is no metadata ([#38713](https://github.com/angular/angular/issues/38713)) ([ab4f953](https://github.com/angular/angular/commit/ab4f953)), closes [#38705](https://github.com/angular/angular/issues/38705)
|
|
||||||
* **ngcc:** use aliased exported types correctly ([#38666](https://github.com/angular/angular/issues/38666)) ([6a28675](https://github.com/angular/angular/commit/6a28675)), closes [#38238](https://github.com/angular/angular/issues/38238)
|
|
||||||
* **router:** If users are using the Alt key when clicking the router links, prioritize browser’s default behavior ([#38375](https://github.com/angular/angular/issues/38375)) ([309709d](https://github.com/angular/angular/commit/309709d))
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* **core:** use `ngDevMode` to tree-shake error messages ([#38612](https://github.com/angular/angular/issues/38612)) ([b084bff](https://github.com/angular/angular/commit/b084bff))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.1.0"></a>
|
|
||||||
# 10.1.0 (2020-09-02)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **bazel:** provide LinkablePackageInfo from ng_module ([#37623](https://github.com/angular/angular/issues/37623)) ([6898eab](https://github.com/angular/angular/commit/6898eab))
|
|
||||||
* **common:** add ReadonlyMap in place of Map in keyValuePipe ([#37311](https://github.com/angular/angular/issues/37311)) ([3373453](https://github.com/angular/angular/commit/3373453)), closes [#37308](https://github.com/angular/angular/issues/37308)
|
|
||||||
* **compiler-cli:** add `SourceFile.getOriginalLocation()` to sourcemaps package ([#32912](https://github.com/angular/angular/issues/32912)) ([6abb8d0](https://github.com/angular/angular/commit/6abb8d0))
|
|
||||||
* **compiler-cli:** Add compiler option to report errors when assigning to restricted input fields ([#38249](https://github.com/angular/angular/issues/38249)) ([71138f6](https://github.com/angular/angular/commit/71138f6))
|
|
||||||
* **compiler-cli:** add support for TypeScript 4.0 ([#38076](https://github.com/angular/angular/issues/38076)) ([0fc44e0](https://github.com/angular/angular/commit/0fc44e0))
|
|
||||||
* **compiler-cli:** explain why an expression cannot be used in AOT compilations ([#37587](https://github.com/angular/angular/issues/37587)) ([712f1bd](https://github.com/angular/angular/commit/712f1bd))
|
|
||||||
* **compiler:** support unary operators for more accurate type checking ([#37918](https://github.com/angular/angular/issues/37918)) ([874792d](https://github.com/angular/angular/commit/874792d)), closes [#20845](https://github.com/angular/angular/issues/20845) [#36178](https://github.com/angular/angular/issues/36178)
|
|
||||||
* **core:** rename async to waitForAsync to avoid confusing ([#37583](https://github.com/angular/angular/issues/37583)) ([8f07429](https://github.com/angular/angular/commit/8f07429))
|
|
||||||
* **core:** support injection token as predicate in queries ([#37506](https://github.com/angular/angular/issues/37506)) ([97dc85b](https://github.com/angular/angular/commit/97dc85b)), closes [#21152](https://github.com/angular/angular/issues/21152) [#36144](https://github.com/angular/angular/issues/36144)
|
|
||||||
* **core:** update reference and doc to change `async` to `waitAsync`. ([#37583](https://github.com/angular/angular/issues/37583)) ([8fbf40b](https://github.com/angular/angular/commit/8fbf40b))
|
|
||||||
* **forms:** AbstractControl to store raw validators in addition to combined validators function ([#37881](https://github.com/angular/angular/issues/37881)) ([ad7046b](https://github.com/angular/angular/commit/ad7046b))
|
|
||||||
* **localize:** allow duplicate messages to be handled during extraction ([#38082](https://github.com/angular/angular/issues/38082)) ([cf9a47b](https://github.com/angular/angular/commit/cf9a47b)), closes [#38077](https://github.com/angular/angular/issues/38077)
|
|
||||||
* **localize:** expose `canParse()` diagnostics ([#37909](https://github.com/angular/angular/issues/37909)) ([ec32eba](https://github.com/angular/angular/commit/ec32eba)), closes [#37901](https://github.com/angular/angular/issues/37901)
|
|
||||||
* **localize:** implement message extraction tool ([#32912](https://github.com/angular/angular/issues/32912)) ([190561d](https://github.com/angular/angular/commit/190561d))
|
|
||||||
* **platform-browser:** Allow `sms`-URLs ([#31463](https://github.com/angular/angular/issues/31463)) ([fc5c34d](https://github.com/angular/angular/commit/fc5c34d)), closes [#31462](https://github.com/angular/angular/issues/31462)
|
|
||||||
* **platform-server:** add option for absolute URL HTTP support ([#37539](https://github.com/angular/angular/issues/37539)) ([d37049a](https://github.com/angular/angular/commit/d37049a)), closes [#37071](https://github.com/angular/angular/issues/37071)
|
|
||||||
* **router:** better warning message when a router outlet has not been instantiated ([#30246](https://github.com/angular/angular/issues/30246)) ([1609815](https://github.com/angular/angular/commit/1609815))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **bazel:** fix integration test for bazel building ([#38629](https://github.com/angular/angular/issues/38629)) ([dd82f2f](https://github.com/angular/angular/commit/dd82f2f))
|
|
||||||
* **common:** date pipe gives wrong week number ([#37632](https://github.com/angular/angular/issues/37632)) ([ef1fb6d](https://github.com/angular/angular/commit/ef1fb6d)), closes [#33961](https://github.com/angular/angular/issues/33961)
|
|
||||||
* **common:** narrow `NgIf` context variables in template type checker ([#36627](https://github.com/angular/angular/issues/36627)) ([9c8bc4a](https://github.com/angular/angular/commit/9c8bc4a))
|
|
||||||
* **compiler-cli:** avoid creating value expressions for symbols from type-only imports ([#37912](https://github.com/angular/angular/issues/37912)) ([18098d3](https://github.com/angular/angular/commit/18098d3)), closes [#37900](https://github.com/angular/angular/issues/37900)
|
|
||||||
* **compiler-cli:** ensure source-maps can handle webpack:// protocol ([#32912](https://github.com/angular/angular/issues/32912)) ([decd95e](https://github.com/angular/angular/commit/decd95e))
|
|
||||||
* **compiler-cli:** only read source-map comment from last line ([#32912](https://github.com/angular/angular/issues/32912)) ([07a07e3](https://github.com/angular/angular/commit/07a07e3))
|
|
||||||
* **compiler-cli:** type-check inputs that include undefined when there's coercion members ([#38273](https://github.com/angular/angular/issues/38273)) ([7525f3a](https://github.com/angular/angular/commit/7525f3a))
|
|
||||||
* **compiler:** incorrectly inferring namespace for HTML nodes inside SVG ([#38477](https://github.com/angular/angular/issues/38477)) ([0dda97e](https://github.com/angular/angular/commit/0dda97e)), closes [#37218](https://github.com/angular/angular/issues/37218)
|
|
||||||
* **compiler:** mark `NgModuleFactory` construction as not side effectful ([#38147](https://github.com/angular/angular/issues/38147)) ([7f8c222](https://github.com/angular/angular/commit/7f8c222))
|
|
||||||
* **core:** Allow modification of lifecycle hooks any time before bootstrap ([#35464](https://github.com/angular/angular/issues/35464)) ([737506e](https://github.com/angular/angular/commit/737506e)), closes [#30497](https://github.com/angular/angular/issues/30497)
|
|
||||||
* **core:** detect DI parameters in JIT mode for downleveled ES2015 classes ([#38463](https://github.com/angular/angular/issues/38463)) ([ca07da4](https://github.com/angular/angular/commit/ca07da4)), closes [#38453](https://github.com/angular/angular/issues/38453)
|
|
||||||
* **core:** determine required DOMParser feature availability ([#36578](https://github.com/angular/angular/issues/36578)) ([#36578](https://github.com/angular/angular/issues/36578)) ([c509243](https://github.com/angular/angular/commit/c509243))
|
|
||||||
* **core:** do not trigger CSP alert/report in Firefox and Chrome ([#36578](https://github.com/angular/angular/issues/36578)) ([#36578](https://github.com/angular/angular/issues/36578)) ([b950d46](https://github.com/angular/angular/commit/b950d46)), closes [#25214](https://github.com/angular/angular/issues/25214)
|
|
||||||
* **core:** move generated i18n statements to the `consts` field of ComponentDef ([#38404](https://github.com/angular/angular/issues/38404)) ([cb05c01](https://github.com/angular/angular/commit/cb05c01))
|
|
||||||
* **elements:** run strategy methods in correct zone ([#37814](https://github.com/angular/angular/issues/37814)) ([8df888d](https://github.com/angular/angular/commit/8df888d)), closes [#24181](https://github.com/angular/angular/issues/24181)
|
|
||||||
* **forms:** handle form groups/arrays own pending async validation ([#22575](https://github.com/angular/angular/issues/22575)) ([77b62a5](https://github.com/angular/angular/commit/77b62a5)), closes [#10064](https://github.com/angular/angular/issues/10064)
|
|
||||||
* **language-service:** non-existent module format in package output ([#37623](https://github.com/angular/angular/issues/37623)) ([413a0fb](https://github.com/angular/angular/commit/413a0fb))
|
|
||||||
* **localize:** ensure required XLIFF parameters are serialized ([#38575](https://github.com/angular/angular/issues/38575)) ([f0af387](https://github.com/angular/angular/commit/f0af387)), closes [#38570](https://github.com/angular/angular/issues/38570)
|
|
||||||
* **localize:** extract the correct message ids ([#38498](https://github.com/angular/angular/issues/38498)) ([ac461e1](https://github.com/angular/angular/commit/ac461e1))
|
|
||||||
* **localize:** render ICU placeholders in extracted translation files ([#38484](https://github.com/angular/angular/issues/38484)) ([81c3e80](https://github.com/angular/angular/commit/81c3e80))
|
|
||||||
* **localize:** render text of extracted placeholders ([#38536](https://github.com/angular/angular/issues/38536)) ([14e90be](https://github.com/angular/angular/commit/14e90be))
|
|
||||||
* **ngcc:** detect synthesized delegate constructors for downleveled ES2015 classes ([#38463](https://github.com/angular/angular/issues/38463)) ([3b9c802](https://github.com/angular/angular/commit/3b9c802)), closes [#38453](https://github.com/angular/angular/issues/38453) [#38453](https://github.com/angular/angular/issues/38453)
|
|
||||||
* **router:** defer loading of wildcard module until needed ([#38348](https://github.com/angular/angular/issues/38348)) ([8f708b5](https://github.com/angular/angular/commit/8f708b5)), closes [#25494](https://github.com/angular/angular/issues/25494)
|
|
||||||
* **router:** fix navigation ignoring logic to compare to the browser url ([#37716](https://github.com/angular/angular/issues/37716)) ([a5ffca0](https://github.com/angular/angular/commit/a5ffca0)), closes [#16710](https://github.com/angular/angular/issues/16710) [#13586](https://github.com/angular/angular/issues/13586)
|
|
||||||
* **router:** properly compare array queryParams for equality ([#37709](https://github.com/angular/angular/issues/37709)) ([#37860](https://github.com/angular/angular/issues/37860)) ([1801d0c](https://github.com/angular/angular/commit/1801d0c))
|
|
||||||
* **router:** remove parenthesis for primary outlet segment after removing auxiliary outlet segment ([#24656](https://github.com/angular/angular/issues/24656)) ([#37163](https://github.com/angular/angular/issues/37163)) ([71f008f](https://github.com/angular/angular/commit/71f008f))
|
|
||||||
* **router:** restore 'history.state' object for navigations coming from Angular router ([#28108](https://github.com/angular/angular/issues/28108)) ([#28176](https://github.com/angular/angular/issues/28176)) ([df76a20](https://github.com/angular/angular/commit/df76a20))
|
|
||||||
|
|
||||||
### Code Refactoring
|
|
||||||
* **router:** export DefaultRouteReuseStrategy to Router public_api ([#31575](https://github.com/angular/angular/issues/31575)) ([ca79880](https://github.com/angular/angular/commit/ca79880))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
* **compiler-cli:** don't emit template guards when child scope is empty ([#38418](https://github.com/angular/angular/issues/38418)) ([1388c17](https://github.com/angular/angular/commit/1388c17))
|
|
||||||
* **compiler-cli:** fix regressions in incremental program reuse ([#37641](https://github.com/angular/angular/issues/37641)) ([5103d90](https://github.com/angular/angular/commit/5103d90))
|
|
||||||
* **compiler-cli:** only generate directive declarations when used ([#38418](https://github.com/angular/angular/issues/38418)) ([fb8f4b4](https://github.com/angular/angular/commit/fb8f4b4))
|
|
||||||
* **compiler-cli:** only generate type-check code for referenced DOM elements ([#38418](https://github.com/angular/angular/issues/38418)) ([f42e6ce](https://github.com/angular/angular/commit/f42e6ce))
|
|
||||||
* **forms:** use internal `ngDevMode` flag to tree-shake error messages in prod builds ([#37821](https://github.com/angular/angular/issues/37821)) ([201a546](https://github.com/angular/angular/commit/201a546)), closes [#37697](https://github.com/angular/angular/issues/37697)
|
|
||||||
* **ngcc:** shortcircuit tokenizing in ESM dependency host ([#37639](https://github.com/angular/angular/issues/37639)) ([bd7f440](https://github.com/angular/angular/commit/bd7f440))
|
|
||||||
* **ngcc:** use `EntryPointManifest` to speed up noop `ProgramBaseEntryPointFinder` ([#37665](https://github.com/angular/angular/issues/37665)) ([9318e23](https://github.com/angular/angular/commit/9318e23))
|
|
||||||
* **router:** apply prioritizedGuardValue operator to optimize CanLoad guards ([#37523](https://github.com/angular/angular/issues/37523)) ([d7dd295](https://github.com/angular/angular/commit/d7dd295))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.0.14"></a>
|
|
||||||
## 10.0.14 (2020-08-26)
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.0.12"></a>
|
|
||||||
## 10.0.12 (2020-08-24)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compiler-cli:** adding references to const enums in runtime code ([#38542](https://github.com/angular/angular/issues/38542)) ([814b436](https://github.com/angular/angular/commit/814b436)), closes [#38513](https://github.com/angular/angular/issues/38513)
|
|
||||||
* **core:** remove closing body tag from inert DOM builder ([#38454](https://github.com/angular/angular/issues/38454)) ([5528536](https://github.com/angular/angular/commit/5528536))
|
|
||||||
* **localize:** include the last placeholder in parsed translation text ([#38452](https://github.com/angular/angular/issues/38452)) ([57d1a48](https://github.com/angular/angular/commit/57d1a48))
|
|
||||||
* **localize:** parse all parts of a translation with nested HTML ([#38452](https://github.com/angular/angular/issues/38452)) ([07b99f5](https://github.com/angular/angular/commit/07b99f5)), closes [#38422](https://github.com/angular/angular/issues/38422)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **language-service:** introduce hybrid visitor to locate AST node ([#38540](https://github.com/angular/angular/issues/38540)) ([66d8c22](https://github.com/angular/angular/commit/66d8c22))
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.0.11"></a>
|
|
||||||
## 10.0.11 (2020-08-19)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **router:** ensure routerLinkActive updates when associated routerLinks change (resubmit of [#38349](https://github.com/angular/angular/issues/38349)) ([#38511](https://github.com/angular/angular/issues/38511)) ([0af9533](https://github.com/angular/angular/commit/0af9533)), closes [#18469](https://github.com/angular/angular/issues/18469)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.0.10"></a>
|
|
||||||
## 10.0.10 (2020-08-17)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **common:** Allow scrolling when browser supports scrollTo ([#38468](https://github.com/angular/angular/issues/38468)) ([b32126c](https://github.com/angular/angular/commit/b32126c)), closes [#30630](https://github.com/angular/angular/issues/30630)
|
|
||||||
* **core:** detect DI parameters in JIT mode for downleveled ES2015 classes ([#38500](https://github.com/angular/angular/issues/38500)) ([863acb6](https://github.com/angular/angular/commit/863acb6)), closes [#38453](https://github.com/angular/angular/issues/38453)
|
|
||||||
* **core:** error if CSS custom property in host binding has number in name ([#38432](https://github.com/angular/angular/issues/38432)) ([cb83b8a](https://github.com/angular/angular/commit/cb83b8a)), closes [#37292](https://github.com/angular/angular/issues/37292)
|
|
||||||
* **core:** fix multiple nested views removal from ViewContainerRef ([#38317](https://github.com/angular/angular/issues/38317)) ([d5e09f4](https://github.com/angular/angular/commit/d5e09f4)), closes [#38201](https://github.com/angular/angular/issues/38201)
|
|
||||||
* **ngcc:** detect synthesized delegate constructors for downleveled ES2015 classes ([#38500](https://github.com/angular/angular/issues/38500)) ([f3dd6c2](https://github.com/angular/angular/commit/f3dd6c2)), closes [#38453](https://github.com/angular/angular/issues/38453) [#38453](https://github.com/angular/angular/issues/38453)
|
|
||||||
* **router:** ensure routerLinkActive updates when associated routerLinks change ([#38349](https://github.com/angular/angular/issues/38349)) ([989e8a1](https://github.com/angular/angular/commit/989e8a1)), closes [#18469](https://github.com/angular/angular/issues/18469)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.0.9"></a>
|
<a name="10.0.9"></a>
|
||||||
## 10.0.9 (2020-08-12)
|
## 10.0.9 (2020-08-12)
|
||||||
|
|
||||||
@ -222,6 +19,7 @@
|
|||||||
* **service-worker:** fix the chrome debugger syntax highlighter ([#38332](https://github.com/angular/angular/issues/38332)) ([f5d5bac](https://github.com/angular/angular/commit/f5d5bac))
|
* **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>
|
<a name="10.0.8"></a>
|
||||||
## 10.0.8 (2020-08-04)
|
## 10.0.8 (2020-08-04)
|
||||||
|
|
||||||
@ -290,6 +88,7 @@
|
|||||||
* **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)
|
* **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)
|
||||||
|
|
||||||
@ -300,16 +99,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="9.1.12"></a>
|
|
||||||
## [9.1.12](https://github.com/angular/angular/compare/9.1.11...9.1.12) (2020-07-08)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **core:** infinite loop if injectable using inheritance has a custom decorator ([6c1ab47](https://github.com/angular/angular/commit/6c1ab47)), closes [#35733](https://github.com/angular/angular/issues/35733)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="10.0.2"></a>
|
<a name="10.0.2"></a>
|
||||||
## [10.0.2](https://github.com/angular/angular/compare/10.0.1...10.0.2) (2020-06-30)
|
## [10.0.2](https://github.com/angular/angular/compare/10.0.1...10.0.2) (2020-06-30)
|
||||||
|
|
||||||
@ -421,6 +210,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **compiler:** avoid undefined expressions in holey array ([#36343](https://github.com/angular/angular/issues/36343)) ([5516802](https://github.com/angular/angular/commit/5516802))
|
* **compiler:** avoid undefined expressions in holey array ([#36343](https://github.com/angular/angular/issues/36343)) ([5516802](https://github.com/angular/angular/commit/5516802))
|
||||||
* **compiler:** handle type references to namespaced symbols correctly ([#36106](https://github.com/angular/angular/issues/36106)) ([4aa4e6f](https://github.com/angular/angular/commit/4aa4e6f)), closes [#36006](https://github.com/angular/angular/issues/36006)
|
* **compiler:** handle type references to namespaced symbols correctly ([#36106](https://github.com/angular/angular/issues/36106)) ([4aa4e6f](https://github.com/angular/angular/commit/4aa4e6f)), closes [#36006](https://github.com/angular/angular/issues/36006)
|
||||||
* **compiler:** normalize line endings in ICU expansions ([#36741](https://github.com/angular/angular/issues/36741)) ([70dd27f](https://github.com/angular/angular/commit/70dd27f)), closes [#36725](https://github.com/angular/angular/issues/36725)
|
* **compiler:** normalize line endings in ICU expansions ([#36741](https://github.com/angular/angular/issues/36741)) ([70dd27f](https://github.com/angular/angular/commit/70dd27f)), closes [#36725](https://github.com/angular/angular/issues/36725)
|
||||||
|
* **compiler:** record correct end of expression ([#34690](https://github.com/angular/angular/issues/34690)) ([df890d7](https://github.com/angular/angular/commit/df890d7)), closes [#33477](https://github.com/angular/angular/issues/33477)
|
||||||
* **compiler:** remove outdated and invalid warning for unresolved DI parameters ([#36985](https://github.com/angular/angular/issues/36985)) ([d0280a0](https://github.com/angular/angular/commit/d0280a0))
|
* **compiler:** remove outdated and invalid warning for unresolved DI parameters ([#36985](https://github.com/angular/angular/issues/36985)) ([d0280a0](https://github.com/angular/angular/commit/d0280a0))
|
||||||
* **compiler:** resolve enum values in binary operations ([#36461](https://github.com/angular/angular/issues/36461)) ([64022f5](https://github.com/angular/angular/commit/64022f5)), closes [#35584](https://github.com/angular/angular/issues/35584)
|
* **compiler:** resolve enum values in binary operations ([#36461](https://github.com/angular/angular/issues/36461)) ([64022f5](https://github.com/angular/angular/commit/64022f5)), closes [#35584](https://github.com/angular/angular/issues/35584)
|
||||||
* **compiler:** switch to 'referencedFiles' for shim generation ([#36211](https://github.com/angular/angular/issues/36211)) ([4213e8d](https://github.com/angular/angular/commit/4213e8d))
|
* **compiler:** switch to 'referencedFiles' for shim generation ([#36211](https://github.com/angular/angular/issues/36211)) ([4213e8d](https://github.com/angular/angular/commit/4213e8d))
|
||||||
@ -571,12 +361,12 @@ https://github.com/microsoft/TypeScript/issues/38374 for more
|
|||||||
information and updates.
|
information and updates.
|
||||||
|
|
||||||
If you used Closure Compiler with Angular in the past, you will likely
|
If you used Closure Compiler with Angular in the past, you will likely
|
||||||
be better off consuming Angular packages built from sources directly
|
be better off consuming Angular packages built from sources directly
|
||||||
rather than consuming the version we publish on npm,
|
rather than consuming the version we publish on npm,
|
||||||
which is primarily optimized for Webpack/Rollup + Terser build pipeline.
|
which is primarily optimized for Webpack/Rollup + Terser build pipeline.
|
||||||
|
|
||||||
As a temporary workaround, you might consider using your current build
|
As a temporary workaround, you might consider using your current build
|
||||||
pipeline with Closure flag `--compilation_level=SIMPLE`. This flag
|
pipeline with Closure flag `--compilation_level=SIMPLE`. This flag
|
||||||
will ensure that your build pipeline produces buildable and
|
will ensure that your build pipeline produces buildable and
|
||||||
runnable artifacts, at the cost of increased payload size due to
|
runnable artifacts, at the cost of increased payload size due to
|
||||||
advanced optimizations being disabled.
|
advanced optimizations being disabled.
|
||||||
@ -584,17 +374,17 @@ advanced optimizations being disabled.
|
|||||||
If you were affected by this change, please help us understand your
|
If you were affected by this change, please help us understand your
|
||||||
needs by leaving a comment on https://github.com/angular/angular/issues/37234.
|
needs by leaving a comment on https://github.com/angular/angular/issues/37234.
|
||||||
|
|
||||||
* **core:** make generic mandatory for ModuleWithProviders
|
* **core:** make generic mandatory for ModuleWithProviders
|
||||||
|
|
||||||
A generic type parameter has always been required for the `ModuleWithProviders` pattern to work with Ivy, but prior to this commit, View Engine allowed the generic type to be omitted (though support was officially deprecated).
|
A generic type parameter has always been required for the `ModuleWithProviders` pattern to work with Ivy, but prior to this commit, View Engine allowed the generic type to be omitted (though support was officially deprecated).
|
||||||
If you're using `ModuleWithProviders` without a generic type in your application code, a v10 migration will update your code for you.
|
If you're using `ModuleWithProviders` without a generic type in your application code, a v10 migration will update your code for you.
|
||||||
|
|
||||||
However, if you are using View Engine and also depending on a library that omits the generic type, you will now get a build time error similar to:
|
However, if you are using View Engine and also depending on a library that omits the generic type, you will now get a build time error similar to:
|
||||||
|
|
||||||
```
|
```
|
||||||
error TS2314: Generic type 'ModuleWithProviders<T>' requires 1 type argument(s).
|
error TS2314: Generic type 'ModuleWithProviders<T>' requires 1 type argument(s).
|
||||||
```
|
```
|
||||||
|
|
||||||
In this case, ngcc won't help you (because it's Ivy-only) and the migration only covers application code.
|
In this case, ngcc won't help you (because it's Ivy-only) and the migration only covers application code.
|
||||||
You should contact the library author to fix their library to provide a type parameter when they use this class.
|
You should contact the library author to fix their library to provide a type parameter when they use this class.
|
||||||
|
|
||||||
@ -677,30 +467,6 @@ subscribe to the observable and call markForCheck as needed.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="9.1.11"></a>
|
|
||||||
## [9.1.11](https://github.com/angular/angular/compare/9.1.10...9.1.11) (2020-06-10)
|
|
||||||
|
|
||||||
### Reverts
|
|
||||||
|
|
||||||
* **elements:** fire custom element output events during component initialization ([dc9da17](https://github.com/angular/angular/commit/dc9da17))
|
|
||||||
|
|
||||||
|
|
||||||
<a name="9.1.10"></a>
|
|
||||||
## [9.1.10](https://github.com/angular/angular/compare/9.1.9...9.1.10) (2020-06-09)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **elements:** fire custom element output events during component initialization ([454e073](https://github.com/angular/angular/commit/454e073)), closes [/github.com/angular/angular/blob/c0143cb2abdd172de1b95fd1d2c4cfc738640e28/packages/elements/src/create-custom-element.ts#L167-L170](https://github.com/angular/angular/blob/c0143cb2abdd172de1b95fd1d2c4cfc738640e28/packages/elements/src/create-custom-element.ts/issues/L167-L170) [/github.com/angular/angular/blob/c0143cb2abdd172de1b95fd1d2c4cfc738640e28/packages/elements/src/create-custom-element.ts#L164](https://github.com/angular/angular/blob/c0143cb2abdd172de1b95fd1d2c4cfc738640e28/packages/elements/src/create-custom-element.ts/issues/L164) [/github.com/angular/angular/blob/c0143cb2abdd172de1b95fd1d2c4cfc738640e28/packages/elements/src/component-factory-strategy.ts#L158](https://github.com/angular/angular/blob/c0143cb2abdd172de1b95fd1d2c4cfc738640e28/packages/elements/src/component-factory-strategy.ts/issues/L158) [#36141](https://github.com/angular/angular/issues/36141)
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* **ngcc:** cache parsed tsconfig between runs ([1aae94a](https://github.com/angular/angular/commit/1aae94a)), closes [#37417](https://github.com/angular/angular/issues/37417) [#36882](https://github.com/angular/angular/issues/36882)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="9.1.9"></a>
|
<a name="9.1.9"></a>
|
||||||
## [9.1.9](https://github.com/angular/angular/compare/9.1.8...9.1.9) (2020-05-20)
|
## [9.1.9](https://github.com/angular/angular/compare/9.1.8...9.1.9) (2020-05-20)
|
||||||
|
|
||||||
@ -742,7 +508,6 @@ This release contains various API docs improvements.
|
|||||||
* **compiler-cli**: Revert "fix(compiler-cli): fix case-sensitivity issues in NgtscCompilerHost (#36968)" (#37003)
|
* **compiler-cli**: Revert "fix(compiler-cli): fix case-sensitivity issues in NgtscCompilerHost (#36968)" (#37003)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="9.1.5"></a>
|
<a name="9.1.5"></a>
|
||||||
## [9.1.5](https://github.com/angular/angular/compare/9.1.4...9.1.5) (2020-05-07)
|
## [9.1.5](https://github.com/angular/angular/compare/9.1.4...9.1.5) (2020-05-07)
|
||||||
|
|
||||||
@ -788,7 +553,6 @@ This release contains various API docs improvements.
|
|||||||
* **ngcc:** recognize enum declarations emitted in JavaScript ([#36550](https://github.com/angular/angular/issues/36550)) ([c440165](https://github.com/angular/angular/commit/c440165)), closes [#35584](https://github.com/angular/angular/issues/35584)
|
* **ngcc:** recognize enum declarations emitted in JavaScript ([#36550](https://github.com/angular/angular/issues/36550)) ([c440165](https://github.com/angular/angular/commit/c440165)), closes [#35584](https://github.com/angular/angular/issues/35584)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="9.1.3"></a>
|
<a name="9.1.3"></a>
|
||||||
## [9.1.3](https://github.com/angular/angular/compare/9.1.2...9.1.3) (2020-04-22)
|
## [9.1.3](https://github.com/angular/angular/compare/9.1.2...9.1.3) (2020-04-22)
|
||||||
|
|
||||||
@ -803,8 +567,8 @@ This release contains various API docs improvements.
|
|||||||
* **core:** prevent unknown property check for AOT-compiled components ([#36072](https://github.com/angular/angular/issues/36072)) ([fe1d9ba](https://github.com/angular/angular/commit/fe1d9ba)), closes [#35945](https://github.com/angular/angular/issues/35945)
|
* **core:** prevent unknown property check for AOT-compiled components ([#36072](https://github.com/angular/angular/issues/36072)) ([fe1d9ba](https://github.com/angular/angular/commit/fe1d9ba)), closes [#35945](https://github.com/angular/angular/issues/35945)
|
||||||
* **core:** properly identify modules affected by overrides in TestBed ([#36649](https://github.com/angular/angular/issues/36649)) ([9724169](https://github.com/angular/angular/commit/9724169)), closes [#36619](https://github.com/angular/angular/issues/36619)
|
* **core:** properly identify modules affected by overrides in TestBed ([#36649](https://github.com/angular/angular/issues/36649)) ([9724169](https://github.com/angular/angular/commit/9724169)), closes [#36619](https://github.com/angular/angular/issues/36619)
|
||||||
* **language-service:** properly evaluate types in comparable expressions ([#36529](https://github.com/angular/angular/issues/36529)) ([5bab498](https://github.com/angular/angular/commit/5bab498))
|
* **language-service:** properly evaluate types in comparable expressions ([#36529](https://github.com/angular/angular/issues/36529)) ([5bab498](https://github.com/angular/angular/commit/5bab498))
|
||||||
* **ngcc:** display unlocker process output in sync mode ([#36637](https://github.com/angular/angular/issues/36637)) ([da159bd](https://github.com/angular/angular/commit/da159bd)), closes [/github.com/nodejs/node/issues/3596#issuecomment-250890218](https://github.com/nodejs/node/issues/3596/issues/issuecomment-250890218)
|
* **ngcc:** display unlocker process output in sync mode ([#36637](https://github.com/angular/angular/issues/36637)) ([da159bd](https://github.com/angular/angular/commit/da159bd)), closes [/github.com/nodejs/node/issues/3596#issuecomment-250890218](https://github.com/nodejs/node/issues/3596#issuecomment-250890218)
|
||||||
* **ngcc:** do not use cached file-system ([#36687](https://github.com/angular/angular/issues/36687)) ([18be33a](https://github.com/angular/angular/commit/18be33a)), closes [/github.com/angular/angular-cli/issues/16860#issuecomment-614694269](https://github.com/angular/angular-cli/issues/16860/issues/issuecomment-614694269)
|
* **ngcc:** do not use cached file-system ([#36687](https://github.com/angular/angular/issues/36687)) ([18be33a](https://github.com/angular/angular/commit/18be33a)), closes [/github.com/angular/angular-cli/issues/16860#issuecomment-614694269](https://github.com/angular/angular-cli/issues/16860#issuecomment-614694269)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -825,7 +589,7 @@ This release contains various API docs improvements.
|
|||||||
* **upgrade:** update $locationShim to handle Location changes before initialization ([#36498](https://github.com/angular/angular/issues/36498)) ([a67afcc](https://github.com/angular/angular/commit/a67afcc)), closes [#36492](https://github.com/angular/angular/issues/36492)
|
* **upgrade:** update $locationShim to handle Location changes before initialization ([#36498](https://github.com/angular/angular/issues/36498)) ([a67afcc](https://github.com/angular/angular/commit/a67afcc)), closes [#36492](https://github.com/angular/angular/issues/36492)
|
||||||
|
|
||||||
### Performance Improvements
|
### Performance Improvements
|
||||||
* **ngcc:** only load if it is needed ([#36486](https://github.com/angular/angular/issues/36486)) ([e06512b](https://github.com/angular/angular/commit/e06512b)) * **ngcc:** read dependencies from entry-point manifest ([#36486](https://github.com/angular/angular/issues/36486)) ([918e628](https://github.com/angular/angular/commit/918e628)), closes [#issuecomment-608401834](https://github.com/angular/angular/issues/issuecomment-608401834)
|
* **ngcc:** only load if it is needed ([#36486](https://github.com/angular/angular/issues/36486)) ([e06512b](https://github.com/angular/angular/commit/e06512b)) * **ngcc:** read dependencies from entry-point manifest ([#36486](https://github.com/angular/angular/issues/36486)) ([918e628](https://github.com/angular/angular/commit/918e628)), closes [#issuecomment-608401834](https://github.com/angular/angular#issuecomment-608401834)
|
||||||
* **ngcc:** reduce the size of the entry-point manifest file ([#36486](https://github.com/angular/angular/issues/36486)) ([603b094](https://github.com/angular/angular/commit/603b094))
|
* **ngcc:** reduce the size of the entry-point manifest file ([#36486](https://github.com/angular/angular/issues/36486)) ([603b094](https://github.com/angular/angular/commit/603b094))
|
||||||
|
|
||||||
|
|
||||||
@ -845,7 +609,7 @@ This release contains various API docs improvements.
|
|||||||
* **core:** undecorated-classes migration should handle derived abstract classes ([#35339](https://github.com/angular/angular/issues/35339)) ([a631b99](https://github.com/angular/angular/commit/a631b99))
|
* **core:** undecorated-classes migration should handle derived abstract classes ([#35339](https://github.com/angular/angular/issues/35339)) ([a631b99](https://github.com/angular/angular/commit/a631b99))
|
||||||
* **language-service:** infer type of elements of array-like objects ([#36312](https://github.com/angular/angular/issues/36312)) ([ff523c9](https://github.com/angular/angular/commit/ff523c9)), closes [#36191](https://github.com/angular/angular/issues/36191)
|
* **language-service:** infer type of elements of array-like objects ([#36312](https://github.com/angular/angular/issues/36312)) ([ff523c9](https://github.com/angular/angular/commit/ff523c9)), closes [#36191](https://github.com/angular/angular/issues/36191)
|
||||||
* **language-service:** use the `HtmlAst` to get the span of HTML tag ([#36371](https://github.com/angular/angular/issues/36371)) ([ffa4e11](https://github.com/angular/angular/commit/ffa4e11))
|
* **language-service:** use the `HtmlAst` to get the span of HTML tag ([#36371](https://github.com/angular/angular/issues/36371)) ([ffa4e11](https://github.com/angular/angular/commit/ffa4e11))
|
||||||
* **ngcc:** add process title ([#36448](https://github.com/angular/angular/issues/36448)) ([136596d](https://github.com/angular/angular/commit/136596d)), closes [/github.com/angular/angular/issues/36414#issuecomment-609644282](https://github.com/angular/angular/issues/36414/issues/issuecomment-609644282)
|
* **ngcc:** add process title ([#36448](https://github.com/angular/angular/issues/36448)) ([136596d](https://github.com/angular/angular/commit/136596d)), closes [36414#issuecomment-609644282](https://github.com/angular/angular/issues/36414#issuecomment-609644282)
|
||||||
* **ngcc:** allow ngcc configuration to match pre-release versions of packages ([#36370](https://github.com/angular/angular/issues/36370)) ([cb0a2a0](https://github.com/angular/angular/commit/cb0a2a0))
|
* **ngcc:** allow ngcc configuration to match pre-release versions of packages ([#36370](https://github.com/angular/angular/issues/36370)) ([cb0a2a0](https://github.com/angular/angular/commit/cb0a2a0))
|
||||||
* **ngcc:** correctly detect imported TypeScript helpers ([#36284](https://github.com/angular/angular/issues/36284)) ([879457c](https://github.com/angular/angular/commit/879457c)), closes [#36089](https://github.com/angular/angular/issues/36089)
|
* **ngcc:** correctly detect imported TypeScript helpers ([#36284](https://github.com/angular/angular/issues/36284)) ([879457c](https://github.com/angular/angular/commit/879457c)), closes [#36089](https://github.com/angular/angular/issues/36089)
|
||||||
* **ngcc:** correctly identify relative Windows-style import paths ([#36372](https://github.com/angular/angular/issues/36372)) ([0daa488](https://github.com/angular/angular/commit/0daa488))
|
* **ngcc:** correctly identify relative Windows-style import paths ([#36372](https://github.com/angular/angular/issues/36372)) ([0daa488](https://github.com/angular/angular/commit/0daa488))
|
||||||
@ -922,9 +686,12 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **animations:** allow computeStyle to work on elements created in Node ([#35810](https://github.com/angular/angular/issues/35810)) ([17cf04e](https://github.com/angular/angular/commit/17cf04e))
|
* **animations:** allow computeStyle to work on elements created in Node ([#35810](https://github.com/angular/angular/issues/35810)) ([17cf04e](https://github.com/angular/angular/commit/17cf04e))
|
||||||
* **animations:** false positive when detecting Node in Webpack builds ([#35134](https://github.com/angular/angular/issues/35134)) ([dc4ae4b](https://github.com/angular/angular/commit/dc4ae4b)), closes [#35117](https://github.com/angular/angular/issues/35117)
|
* **animations:** false positive when detecting Node in Webpack builds ([#35134](https://github.com/angular/angular/issues/35134)) ([dc4ae4b](https://github.com/angular/angular/commit/dc4ae4b)), closes [#35117](https://github.com/angular/angular/issues/35117)
|
||||||
* **animations:** process shorthand `margin` and `padding` styles correctly ([#35701](https://github.com/angular/angular/issues/35701)) ([35c9f0d](https://github.com/angular/angular/commit/35c9f0d)), closes [#35463](https://github.com/angular/angular/issues/35463)
|
* **animations:** process shorthand `margin` and `padding` styles correctly ([#35701](https://github.com/angular/angular/issues/35701)) ([35c9f0d](https://github.com/angular/angular/commit/35c9f0d)), closes [#35463](https://github.com/angular/angular/issues/35463)
|
||||||
|
* **bazel:** devserver shows blank page in Windows ([#35159](https://github.com/angular/angular/issues/35159)) ([727f92f](https://github.com/angular/angular/commit/727f92f))
|
||||||
* **bazel:** do not use manifest paths for generated imports within compilation unit ([#35841](https://github.com/angular/angular/issues/35841)) ([9581658](https://github.com/angular/angular/commit/9581658))
|
* **bazel:** do not use manifest paths for generated imports within compilation unit ([#35841](https://github.com/angular/angular/issues/35841)) ([9581658](https://github.com/angular/angular/commit/9581658))
|
||||||
* **bazel:** ng_package rule creates incorrect UMD module exports ([#35792](https://github.com/angular/angular/issues/35792)) ([5c2a908](https://github.com/angular/angular/commit/5c2a908)), closes [angular/components#18652](https://github.com/angular/components/issues/18652)
|
* **bazel:** ng_package rule creates incorrect UMD module exports ([#35792](https://github.com/angular/angular/issues/35792)) ([5c2a908](https://github.com/angular/angular/commit/5c2a908)), closes [angular/components#18652](https://github.com/angular/components/issues/18652)
|
||||||
* **bazel:** prod server doesn't serve files in windows ([#35991](https://github.com/angular/angular/issues/35991)) ([96e3449](https://github.com/angular/angular/commit/96e3449))
|
* **bazel:** prod server doesn't serve files in windows ([#35991](https://github.com/angular/angular/issues/35991)) ([96e3449](https://github.com/angular/angular/commit/96e3449))
|
||||||
|
* **bazel:** spawn prod server using port 4200 ([#35160](https://github.com/angular/angular/issues/35160)) ([829f506](https://github.com/angular/angular/commit/829f506))
|
||||||
|
* **bazel:** update ibazel to 0.11.1 ([#35158](https://github.com/angular/angular/issues/35158)) ([4e6d237](https://github.com/angular/angular/commit/4e6d237))
|
||||||
* **bazel:** update several packages for better windows support ([#35991](https://github.com/angular/angular/issues/35991)) ([32f099a](https://github.com/angular/angular/commit/32f099a))
|
* **bazel:** update several packages for better windows support ([#35991](https://github.com/angular/angular/issues/35991)) ([32f099a](https://github.com/angular/angular/commit/32f099a))
|
||||||
* **bazel:** update typescript peer dependency range ([#36013](https://github.com/angular/angular/issues/36013)) ([5e3a898](https://github.com/angular/angular/commit/5e3a898))
|
* **bazel:** update typescript peer dependency range ([#36013](https://github.com/angular/angular/issues/36013)) ([5e3a898](https://github.com/angular/angular/commit/5e3a898))
|
||||||
* **common:** let `KeyValuePipe` accept type unions with `null` ([#36093](https://github.com/angular/angular/issues/36093)) ([407fa42](https://github.com/angular/angular/commit/407fa42)), closes [#35743](https://github.com/angular/angular/issues/35743)
|
* **common:** let `KeyValuePipe` accept type unions with `null` ([#36093](https://github.com/angular/angular/issues/36093)) ([407fa42](https://github.com/angular/angular/commit/407fa42)), closes [#35743](https://github.com/angular/angular/issues/35743)
|
||||||
@ -933,6 +700,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **compiler:** Propagate value span of ExpressionBinding to ParsedProperty ([#36133](https://github.com/angular/angular/issues/36133)) ([2ce5fa3](https://github.com/angular/angular/commit/2ce5fa3))
|
* **compiler:** Propagate value span of ExpressionBinding to ParsedProperty ([#36133](https://github.com/angular/angular/issues/36133)) ([2ce5fa3](https://github.com/angular/angular/commit/2ce5fa3))
|
||||||
* **compiler:** do not recurse to find static symbols of same module ([#35262](https://github.com/angular/angular/issues/35262)) ([e179c58](https://github.com/angular/angular/commit/e179c58))
|
* **compiler:** do not recurse to find static symbols of same module ([#35262](https://github.com/angular/angular/issues/35262)) ([e179c58](https://github.com/angular/angular/commit/e179c58))
|
||||||
* **compiler:** record correct end of expression ([#34690](https://github.com/angular/angular/issues/34690)) ([df890d7](https://github.com/angular/angular/commit/df890d7)), closes [#33477](https://github.com/angular/angular/issues/33477)
|
* **compiler:** record correct end of expression ([#34690](https://github.com/angular/angular/issues/34690)) ([df890d7](https://github.com/angular/angular/commit/df890d7)), closes [#33477](https://github.com/angular/angular/issues/33477)
|
||||||
|
* **compiler:** report errors for missing binding names ([#34595](https://github.com/angular/angular/issues/34595)) ([d13cab7](https://github.com/angular/angular/commit/d13cab7))
|
||||||
* **compiler:** support directive inputs with interpolations on `<ng-template>`s ([#35984](https://github.com/angular/angular/issues/35984)) ([79659ee](https://github.com/angular/angular/commit/79659ee)), closes [#35752](https://github.com/angular/angular/issues/35752)
|
* **compiler:** support directive inputs with interpolations on `<ng-template>`s ([#35984](https://github.com/angular/angular/issues/35984)) ([79659ee](https://github.com/angular/angular/commit/79659ee)), closes [#35752](https://github.com/angular/angular/issues/35752)
|
||||||
* **compiler:** support i18n attributes on `<ng-template>` tags ([#35681](https://github.com/angular/angular/issues/35681)) ([40da51f](https://github.com/angular/angular/commit/40da51f))
|
* **compiler:** support i18n attributes on `<ng-template>` tags ([#35681](https://github.com/angular/angular/issues/35681)) ([40da51f](https://github.com/angular/angular/commit/40da51f))
|
||||||
* **compiler:** type-checking error for duplicate variables in templates ([#35674](https://github.com/angular/angular/issues/35674)) ([2c41bb8](https://github.com/angular/angular/commit/2c41bb8)), closes [#35186](https://github.com/angular/angular/issues/35186)
|
* **compiler:** type-checking error for duplicate variables in templates ([#35674](https://github.com/angular/angular/issues/35674)) ([2c41bb8](https://github.com/angular/angular/commit/2c41bb8)), closes [#35186](https://github.com/angular/angular/issues/35186)
|
||||||
@ -970,13 +738,19 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **core:** workaround Terser inlining bug ([#36200](https://github.com/angular/angular/issues/36200)) ([f71d132](https://github.com/angular/angular/commit/f71d132))
|
* **core:** workaround Terser inlining bug ([#36200](https://github.com/angular/angular/issues/36200)) ([f71d132](https://github.com/angular/angular/commit/f71d132))
|
||||||
* **elements:** correctly handle setting inputs to `undefined` ([#36140](https://github.com/angular/angular/issues/36140)) ([e066bdd](https://github.com/angular/angular/commit/e066bdd))
|
* **elements:** correctly handle setting inputs to `undefined` ([#36140](https://github.com/angular/angular/issues/36140)) ([e066bdd](https://github.com/angular/angular/commit/e066bdd))
|
||||||
* **elements:** correctly set `SimpleChange#firstChange` for pre-existing inputs ([#36140](https://github.com/angular/angular/issues/36140)) ([447a600](https://github.com/angular/angular/commit/447a600)), closes [#36130](https://github.com/angular/angular/issues/36130)
|
* **elements:** correctly set `SimpleChange#firstChange` for pre-existing inputs ([#36140](https://github.com/angular/angular/issues/36140)) ([447a600](https://github.com/angular/angular/commit/447a600)), closes [#36130](https://github.com/angular/angular/issues/36130)
|
||||||
|
* **elements:** schematics fail with schema.json not found error ([#35211](https://github.com/angular/angular/issues/35211)) ([94d002b](https://github.com/angular/angular/commit/94d002b)), closes [#35154](https://github.com/angular/angular/issues/35154)
|
||||||
|
* **forms:** change Array.reduce usage to Array.forEach ([#35349](https://github.com/angular/angular/issues/35349)) ([554c2cb](https://github.com/angular/angular/commit/554c2cb))
|
||||||
* **ivy:** `LFrame` needs to release memory on `leaveView()` ([#35156](https://github.com/angular/angular/issues/35156)) ([b9b512f](https://github.com/angular/angular/commit/b9b512f)), closes [#35148](https://github.com/angular/angular/issues/35148)
|
* **ivy:** `LFrame` needs to release memory on `leaveView()` ([#35156](https://github.com/angular/angular/issues/35156)) ([b9b512f](https://github.com/angular/angular/commit/b9b512f)), closes [#35148](https://github.com/angular/angular/issues/35148)
|
||||||
* **ivy:** add attributes and classes to host elements based on selector ([#34481](https://github.com/angular/angular/issues/34481)) ([f95b8ce](https://github.com/angular/angular/commit/f95b8ce))
|
* **ivy:** add attributes and classes to host elements based on selector ([#34481](https://github.com/angular/angular/issues/34481)) ([f95b8ce](https://github.com/angular/angular/commit/f95b8ce))
|
||||||
|
* **ivy:** ensure module imports are instantiated before the module being declared ([#35172](https://github.com/angular/angular/issues/35172)) ([b6a3a73](https://github.com/angular/angular/commit/b6a3a73))
|
||||||
* **ivy:** error if directive with synthetic property binding is on same node as directive that injects ViewContainerRef ([#35343](https://github.com/angular/angular/issues/35343)) ([d6bc63f](https://github.com/angular/angular/commit/d6bc63f)), closes [#35342](https://github.com/angular/angular/issues/35342)
|
* **ivy:** error if directive with synthetic property binding is on same node as directive that injects ViewContainerRef ([#35343](https://github.com/angular/angular/issues/35343)) ([d6bc63f](https://github.com/angular/angular/commit/d6bc63f)), closes [#35342](https://github.com/angular/angular/issues/35342)
|
||||||
* **ivy:** narrow `NgIf` context variables in template type checker ([#35125](https://github.com/angular/angular/issues/35125)) ([40039d8](https://github.com/angular/angular/commit/40039d8)), closes [#34572](https://github.com/angular/angular/issues/34572)
|
* **ivy:** narrow `NgIf` context variables in template type checker ([#35125](https://github.com/angular/angular/issues/35125)) ([40039d8](https://github.com/angular/angular/commit/40039d8)), closes [#34572](https://github.com/angular/angular/issues/34572)
|
||||||
* **ivy:** queries should match elements inside ng-container with the descendants: false option ([#35384](https://github.com/angular/angular/issues/35384)) ([3f4e02b](https://github.com/angular/angular/commit/3f4e02b)), closes [#34768](https://github.com/angular/angular/issues/34768)
|
* **ivy:** queries should match elements inside ng-container with the descendants: false option ([#35384](https://github.com/angular/angular/issues/35384)) ([3f4e02b](https://github.com/angular/angular/commit/3f4e02b)), closes [#34768](https://github.com/angular/angular/issues/34768)
|
||||||
|
* **ivy:** repeat template guards to narrow types in event handlers ([#35193](https://github.com/angular/angular/issues/35193)) ([dea1b96](https://github.com/angular/angular/commit/dea1b96)), closes [#35073](https://github.com/angular/angular/issues/35073)
|
||||||
|
* **ivy:** set namespace for host elements of dynamically created components ([#35136](https://github.com/angular/angular/issues/35136)) ([480a4c3](https://github.com/angular/angular/commit/480a4c3))
|
||||||
* **ivy:** support dynamic query tokens in AOT mode ([#35307](https://github.com/angular/angular/issues/35307)) ([3e3a1ef](https://github.com/angular/angular/commit/3e3a1ef)), closes [#34267](https://github.com/angular/angular/issues/34267)
|
* **ivy:** support dynamic query tokens in AOT mode ([#35307](https://github.com/angular/angular/issues/35307)) ([3e3a1ef](https://github.com/angular/angular/commit/3e3a1ef)), closes [#34267](https://github.com/angular/angular/issues/34267)
|
||||||
* **ivy:** wrong context passed to ngOnDestroy when resolved multiple times ([#35249](https://github.com/angular/angular/issues/35249)) ([5fbfe69](https://github.com/angular/angular/commit/5fbfe69)), closes [#35167](https://github.com/angular/angular/issues/35167)
|
* **ivy:** wrong context passed to ngOnDestroy when resolved multiple times ([#35249](https://github.com/angular/angular/issues/35249)) ([5fbfe69](https://github.com/angular/angular/commit/5fbfe69)), closes [#35167](https://github.com/angular/angular/issues/35167)
|
||||||
|
* **language-service:** Suggest ? and ! operator on nullable receiver ([#35200](https://github.com/angular/angular/issues/35200)) ([3cc24a9](https://github.com/angular/angular/commit/3cc24a9))
|
||||||
* **language-service:** fix calculation of pipe spans ([#35986](https://github.com/angular/angular/issues/35986)) ([406419b](https://github.com/angular/angular/commit/406419b))
|
* **language-service:** fix calculation of pipe spans ([#35986](https://github.com/angular/angular/issues/35986)) ([406419b](https://github.com/angular/angular/commit/406419b))
|
||||||
* **language-service:** get the right 'ElementAst' in the nested HTML tag ([#35317](https://github.com/angular/angular/issues/35317)) ([8e354da](https://github.com/angular/angular/commit/8e354da))
|
* **language-service:** get the right 'ElementAst' in the nested HTML tag ([#35317](https://github.com/angular/angular/issues/35317)) ([8e354da](https://github.com/angular/angular/commit/8e354da))
|
||||||
* **language-service:** infer $implicit value for ngIf template contexts ([#35941](https://github.com/angular/angular/issues/35941)) ([18b1bd4](https://github.com/angular/angular/commit/18b1bd4))
|
* **language-service:** infer $implicit value for ngIf template contexts ([#35941](https://github.com/angular/angular/issues/35941)) ([18b1bd4](https://github.com/angular/angular/commit/18b1bd4))
|
||||||
@ -1001,6 +775,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **ngcc:** correctly detect outer aliased class identifiers in ES5 ([#35527](https://github.com/angular/angular/issues/35527)) ([fde8915](https://github.com/angular/angular/commit/fde8915)), closes [#35399](https://github.com/angular/angular/issues/35399)
|
* **ngcc:** correctly detect outer aliased class identifiers in ES5 ([#35527](https://github.com/angular/angular/issues/35527)) ([fde8915](https://github.com/angular/angular/commit/fde8915)), closes [#35399](https://github.com/angular/angular/issues/35399)
|
||||||
* **ngcc:** do not crash on entry-point that fails to compile ([#36083](https://github.com/angular/angular/issues/36083)) ([ff665b9](https://github.com/angular/angular/commit/ff665b9))
|
* **ngcc:** do not crash on entry-point that fails to compile ([#36083](https://github.com/angular/angular/issues/36083)) ([ff665b9](https://github.com/angular/angular/commit/ff665b9))
|
||||||
* **ngcc:** do not crash on overlapping entry-points ([#36083](https://github.com/angular/angular/issues/36083)) ([c9f554c](https://github.com/angular/angular/commit/c9f554c))
|
* **ngcc:** do not crash on overlapping entry-points ([#36083](https://github.com/angular/angular/issues/36083)) ([c9f554c](https://github.com/angular/angular/commit/c9f554c))
|
||||||
|
* **ngcc:** ensure that path-mapped secondary entry-points are processed correctly ([#35227](https://github.com/angular/angular/issues/35227)) ([c3c1140](https://github.com/angular/angular/commit/c3c1140)), closes [#35188](https://github.com/angular/angular/issues/35188)
|
||||||
* **ngcc:** handle imports in dts files when processing CommonJS ([#35191](https://github.com/angular/angular/issues/35191)) ([b6e8847](https://github.com/angular/angular/commit/b6e8847)), closes [#34356](https://github.com/angular/angular/issues/34356)
|
* **ngcc:** handle imports in dts files when processing CommonJS ([#35191](https://github.com/angular/angular/issues/35191)) ([b6e8847](https://github.com/angular/angular/commit/b6e8847)), closes [#34356](https://github.com/angular/angular/issues/34356)
|
||||||
* **ngcc:** handle mappings outside the content when flattening source-maps ([#35718](https://github.com/angular/angular/issues/35718)) ([73cf7d5](https://github.com/angular/angular/commit/73cf7d5)), closes [#35709](https://github.com/angular/angular/issues/35709)
|
* **ngcc:** handle mappings outside the content when flattening source-maps ([#35718](https://github.com/angular/angular/issues/35718)) ([73cf7d5](https://github.com/angular/angular/commit/73cf7d5)), closes [#35709](https://github.com/angular/angular/issues/35709)
|
||||||
* **ngcc:** handle missing sources when flattening source-maps ([#35718](https://github.com/angular/angular/issues/35718)) ([72c4fda](https://github.com/angular/angular/commit/72c4fda)), closes [#35709](https://github.com/angular/angular/issues/35709)
|
* **ngcc:** handle missing sources when flattening source-maps ([#35718](https://github.com/angular/angular/issues/35718)) ([72c4fda](https://github.com/angular/angular/commit/72c4fda)), closes [#35709](https://github.com/angular/angular/issues/35709)
|
||||||
@ -1258,7 +1033,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **compiler-cli:** require node 10 as runtime engine ([#34722](https://github.com/angular/angular/issues/34722)) ([7b77b3d](https://github.com/angular/angular/commit/7b77b3d))
|
* **compiler-cli:** require node 10 as runtime engine ([#34722](https://github.com/angular/angular/issues/34722)) ([7b77b3d](https://github.com/angular/angular/commit/7b77b3d))
|
||||||
* **language-service:** specific suggestions for template context diags ([#34751](https://github.com/angular/angular/issues/34751)) ([cc7fca4](https://github.com/angular/angular/commit/cc7fca4))
|
* **language-service:** specific suggestions for template context diags ([#34751](https://github.com/angular/angular/issues/34751)) ([cc7fca4](https://github.com/angular/angular/commit/cc7fca4))
|
||||||
* **language-service:** support multiple symbol definitions ([#34782](https://github.com/angular/angular/issues/34782)) ([2f2396c](https://github.com/angular/angular/commit/2f2396c))
|
* **language-service:** support multiple symbol definitions ([#34782](https://github.com/angular/angular/issues/34782)) ([2f2396c](https://github.com/angular/angular/commit/2f2396c))
|
||||||
* **ngcc:** lock ngcc when processing ([#34722](https://github.com/angular/angular/issues/34722)) ([6dd51f1](https://github.com/angular/angular/commit/6dd51f1)), closes [/github.com/angular/angular/issues/32431#issuecomment-571825781](https://github.com/angular/angular/issues/32431/issues/issuecomment-571825781)
|
* **ngcc:** lock ngcc when processing ([#34722](https://github.com/angular/angular/issues/34722)) ([6dd51f1](https://github.com/angular/angular/commit/6dd51f1)), closes [32431#issuecomment-571825781](https://github.com/angular/angular/issues/32431#issuecomment-571825781)
|
||||||
* work around 'noImplicityAny' incompatibility due to ts3.7 update ([#34798](https://github.com/angular/angular/issues/34798)) ([251d548](https://github.com/angular/angular/commit/251d548))
|
* work around 'noImplicityAny' incompatibility due to ts3.7 update ([#34798](https://github.com/angular/angular/issues/34798)) ([251d548](https://github.com/angular/angular/commit/251d548))
|
||||||
* **animations:** not waiting for child animations to finish when removing parent in Ivy ([#34702](https://github.com/angular/angular/issues/34702)) ([92c17fe](https://github.com/angular/angular/commit/92c17fe)), closes [#33597](https://github.com/angular/angular/issues/33597)
|
* **animations:** not waiting for child animations to finish when removing parent in Ivy ([#34702](https://github.com/angular/angular/issues/34702)) ([92c17fe](https://github.com/angular/angular/commit/92c17fe)), closes [#33597](https://github.com/angular/angular/issues/33597)
|
||||||
* **common:** ensure diffing in ngStyle/ngClass correctly emits value changes ([#34307](https://github.com/angular/angular/issues/34307)) ([93a035f](https://github.com/angular/angular/commit/93a035f)), closes [#34336](https://github.com/angular/angular/issues/34336) [#34444](https://github.com/angular/angular/issues/34444)
|
* **common:** ensure diffing in ngStyle/ngClass correctly emits value changes ([#34307](https://github.com/angular/angular/issues/34307)) ([93a035f](https://github.com/angular/angular/commit/93a035f)), closes [#34336](https://github.com/angular/angular/issues/34336) [#34444](https://github.com/angular/angular/issues/34444)
|
||||||
@ -1389,7 +1164,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **ngcc:** do not output duplicate ɵprov properties ([#34085](https://github.com/angular/angular/issues/34085)) ([5a8d25d](https://github.com/angular/angular/commit/5a8d25d))
|
* **ngcc:** do not output duplicate ɵprov properties ([#34085](https://github.com/angular/angular/issues/34085)) ([5a8d25d](https://github.com/angular/angular/commit/5a8d25d))
|
||||||
* **ngcc:** render localized strings when in ES5 format ([#33857](https://github.com/angular/angular/issues/33857)) ([c6695fa](https://github.com/angular/angular/commit/c6695fa))
|
* **ngcc:** render localized strings when in ES5 format ([#33857](https://github.com/angular/angular/issues/33857)) ([c6695fa](https://github.com/angular/angular/commit/c6695fa))
|
||||||
* **ngcc:** render UMD global imports correctly ([#34012](https://github.com/angular/angular/issues/34012)) ([83989b8](https://github.com/angular/angular/commit/83989b8))
|
* **ngcc:** render UMD global imports correctly ([#34012](https://github.com/angular/angular/issues/34012)) ([83989b8](https://github.com/angular/angular/commit/83989b8))
|
||||||
* **ngcc:** report errors from `analyze` and `resolve` processing ([#33964](https://github.com/angular/angular/issues/33964)) ([ca5d772](https://github.com/angular/angular/commit/ca5d772)), closes [/github.com/angular/angular/issues/33685#issuecomment-557091719](https://github.com/angular/angular/issues/33685/issues/issuecomment-557091719)
|
* **ngcc:** report errors from `analyze` and `resolve` processing ([#33964](https://github.com/angular/angular/issues/33964)) ([ca5d772](https://github.com/angular/angular/commit/ca5d772)), closes [33685#issuecomment-557091719](https://github.com/angular/angular/issues/33685#issuecomment-557091719)
|
||||||
* **router:** make routerLinkActive work with query params which contain arrays ([#22666](https://github.com/angular/angular/issues/22666)) ([f1bf5b2](https://github.com/angular/angular/commit/f1bf5b2)), closes [#22223](https://github.com/angular/angular/issues/22223)
|
* **router:** make routerLinkActive work with query params which contain arrays ([#22666](https://github.com/angular/angular/issues/22666)) ([f1bf5b2](https://github.com/angular/angular/commit/f1bf5b2)), closes [#22223](https://github.com/angular/angular/issues/22223)
|
||||||
* **service-worker:** allow creating post api requests after cache failure ([#33930](https://github.com/angular/angular/issues/33930)) ([63c9123](https://github.com/angular/angular/commit/63c9123)), closes [#33793](https://github.com/angular/angular/issues/33793)
|
* **service-worker:** allow creating post api requests after cache failure ([#33930](https://github.com/angular/angular/issues/33930)) ([63c9123](https://github.com/angular/angular/commit/63c9123)), closes [#33793](https://github.com/angular/angular/issues/33793)
|
||||||
* **service-worker:** throw when using the unsupported `versionedFiles` option in config ([#33903](https://github.com/angular/angular/issues/33903)) ([250e6fd](https://github.com/angular/angular/commit/250e6fd))
|
* **service-worker:** throw when using the unsupported `versionedFiles` option in config ([#33903](https://github.com/angular/angular/issues/33903)) ([250e6fd](https://github.com/angular/angular/commit/250e6fd))
|
||||||
@ -1468,7 +1243,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **language-service:** Should not crash if expr ends unexpectedly ([#33524](https://github.com/angular/angular/issues/33524)) ([9ebac71](https://github.com/angular/angular/commit/9ebac71))
|
* **language-service:** Should not crash if expr ends unexpectedly ([#33524](https://github.com/angular/angular/issues/33524)) ([9ebac71](https://github.com/angular/angular/commit/9ebac71))
|
||||||
* **ngcc:** handle new `__spreadArrays` tslib helper ([#33617](https://github.com/angular/angular/issues/33617)) ([d749dd3](https://github.com/angular/angular/commit/d749dd3)), closes [#33614](https://github.com/angular/angular/issues/33614)
|
* **ngcc:** handle new `__spreadArrays` tslib helper ([#33617](https://github.com/angular/angular/issues/33617)) ([d749dd3](https://github.com/angular/angular/commit/d749dd3)), closes [#33614](https://github.com/angular/angular/issues/33614)
|
||||||
* **ngcc:** override `getInternalNameOfClass()` and `getAdjacentNameOfClass()` for ES5 ([#33533](https://github.com/angular/angular/issues/33533)) ([93a23b9](https://github.com/angular/angular/commit/93a23b9))
|
* **ngcc:** override `getInternalNameOfClass()` and `getAdjacentNameOfClass()` for ES5 ([#33533](https://github.com/angular/angular/issues/33533)) ([93a23b9](https://github.com/angular/angular/commit/93a23b9))
|
||||||
* **ngcc:** render adjacent statements after static properties ([#33630](https://github.com/angular/angular/issues/33630)) ([fe12d0d](https://github.com/angular/angular/commit/fe12d0d)), closes [/github.com/angular/angular/pull/33337#issuecomment-545487737](https://github.com/angular/angular/pull/33337/issues/issuecomment-545487737)
|
* **ngcc:** render adjacent statements after static properties ([#33630](https://github.com/angular/angular/issues/33630)) ([fe12d0d](https://github.com/angular/angular/commit/fe12d0d)), closes [/github.com/angular/angular/pull/33337#issuecomment-545487737](https://github.com/angular/angular/pull/33337#issuecomment-545487737)
|
||||||
* **ngcc:** render new definitions using the inner name of the class ([#33533](https://github.com/angular/angular/issues/33533)) ([85298e3](https://github.com/angular/angular/commit/85298e3))
|
* **ngcc:** render new definitions using the inner name of the class ([#33533](https://github.com/angular/angular/issues/33533)) ([85298e3](https://github.com/angular/angular/commit/85298e3))
|
||||||
* **service-worker:** ensure initialization before handling messages ([#32525](https://github.com/angular/angular/issues/32525)) ([72eba77](https://github.com/angular/angular/commit/72eba77)), closes [#25611](https://github.com/angular/angular/issues/25611)
|
* **service-worker:** ensure initialization before handling messages ([#32525](https://github.com/angular/angular/issues/32525)) ([72eba77](https://github.com/angular/angular/commit/72eba77)), closes [#25611](https://github.com/angular/angular/issues/25611)
|
||||||
* **compiler:** i18n - ignore `alt-trans` tags in XLIFF 1.2 ([#33450](https://github.com/angular/angular/issues/33450)) ([936700a](https://github.com/angular/angular/commit/936700a)), closes [#33161](https://github.com/angular/angular/issues/33161)
|
* **compiler:** i18n - ignore `alt-trans` tags in XLIFF 1.2 ([#33450](https://github.com/angular/angular/issues/33450)) ([936700a](https://github.com/angular/angular/commit/936700a)), closes [#33161](https://github.com/angular/angular/issues/33161)
|
||||||
@ -1498,7 +1273,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **language-service:** Add directive selectors & banana-in-a-box to completions ([#33311](https://github.com/angular/angular/issues/33311)) ([49eec5d](https://github.com/angular/angular/commit/49eec5d))
|
* **language-service:** Add directive selectors & banana-in-a-box to completions ([#33311](https://github.com/angular/angular/issues/33311)) ([49eec5d](https://github.com/angular/angular/commit/49eec5d))
|
||||||
* **language-service:** Add global symbol for $any() ([#33245](https://github.com/angular/angular/issues/33245)) ([3f257e9](https://github.com/angular/angular/commit/3f257e9))
|
* **language-service:** Add global symbol for $any() ([#33245](https://github.com/angular/angular/issues/33245)) ([3f257e9](https://github.com/angular/angular/commit/3f257e9))
|
||||||
* **language-service:** Preserve CRLF in templates for language-service ([#33241](https://github.com/angular/angular/issues/33241)) ([65a0d2b](https://github.com/angular/angular/commit/65a0d2b))
|
* **language-service:** Preserve CRLF in templates for language-service ([#33241](https://github.com/angular/angular/issues/33241)) ([65a0d2b](https://github.com/angular/angular/commit/65a0d2b))
|
||||||
* **ngcc:** do not fail when multiple workers try to create the same directory ([#33237](https://github.com/angular/angular/issues/33237)) ([8017229](https://github.com/angular/angular/commit/8017229)), closes [/github.com/angular/angular/pull/33049#issuecomment-540485703](https://github.com/angular/angular/pull/33049/issues/issuecomment-540485703)
|
* **ngcc:** do not fail when multiple workers try to create the same directory ([#33237](https://github.com/angular/angular/issues/33237)) ([8017229](https://github.com/angular/angular/commit/8017229)), closes [/github.com/angular/angular/pull/33049#issuecomment-540485703](https://github.com/angular/angular/pull/33049#issuecomment-540485703)
|
||||||
* **bazel:** Remove angular devkit and restore ngc postinstall ([#32946](https://github.com/angular/angular/issues/32946)) ([f036684](https://github.com/angular/angular/commit/f036684))
|
* **bazel:** Remove angular devkit and restore ngc postinstall ([#32946](https://github.com/angular/angular/issues/32946)) ([f036684](https://github.com/angular/angular/commit/f036684))
|
||||||
* **common:** remove deprecated support for intl API ([#29250](https://github.com/angular/angular/issues/29250)) ([9e7668f](https://github.com/angular/angular/commit/9e7668f)), closes [#18284](https://github.com/angular/angular/issues/18284)
|
* **common:** remove deprecated support for intl API ([#29250](https://github.com/angular/angular/issues/29250)) ([9e7668f](https://github.com/angular/angular/commit/9e7668f)), closes [#18284](https://github.com/angular/angular/issues/18284)
|
||||||
* **compiler:** absolute source span for template attribute expressions ([#33189](https://github.com/angular/angular/issues/33189)) ([fd4fed1](https://github.com/angular/angular/commit/fd4fed1))
|
* **compiler:** absolute source span for template attribute expressions ([#33189](https://github.com/angular/angular/issues/33189)) ([fd4fed1](https://github.com/angular/angular/commit/fd4fed1))
|
||||||
@ -1555,7 +1330,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **language-service:** Turn on strict mode for test project ([#32783](https://github.com/angular/angular/issues/32783)) ([28358b6](https://github.com/angular/angular/commit/28358b6))
|
* **language-service:** Turn on strict mode for test project ([#32783](https://github.com/angular/angular/issues/32783)) ([28358b6](https://github.com/angular/angular/commit/28358b6))
|
||||||
* **ngcc:** ensure private exports are added for `ModuleWithProviders` ([#32902](https://github.com/angular/angular/issues/32902)) ([002a97d](https://github.com/angular/angular/commit/002a97d))
|
* **ngcc:** ensure private exports are added for `ModuleWithProviders` ([#32902](https://github.com/angular/angular/issues/32902)) ([002a97d](https://github.com/angular/angular/commit/002a97d))
|
||||||
* **ngcc:** handle presence of both `ctorParameters` and `__decorate` ([#32901](https://github.com/angular/angular/issues/32901)) ([747f0cf](https://github.com/angular/angular/commit/747f0cf))
|
* **ngcc:** handle presence of both `ctorParameters` and `__decorate` ([#32901](https://github.com/angular/angular/issues/32901)) ([747f0cf](https://github.com/angular/angular/commit/747f0cf))
|
||||||
* **ngcc:** make the build-marker error more clear ([#32712](https://github.com/angular/angular/issues/32712)) ([0ea4875](https://github.com/angular/angular/commit/0ea4875)), closes [/github.com/angular/angular/issues/31354#issuecomment-532080537](https://github.com/angular/angular/issues/31354/issues/issuecomment-532080537)
|
* **ngcc:** make the build-marker error more clear ([#32712](https://github.com/angular/angular/issues/32712)) ([0ea4875](https://github.com/angular/angular/commit/0ea4875)), closes [31354#issuecomment-532080537](https://github.com/angular/angular/issues/31354#issuecomment-532080537)
|
||||||
* **upgrade:** fix AngularJsUrlCodec to support Safari ([#32959](https://github.com/angular/angular/issues/32959)) ([39e8ceb](https://github.com/angular/angular/commit/39e8ceb))
|
* **upgrade:** fix AngularJsUrlCodec to support Safari ([#32959](https://github.com/angular/angular/issues/32959)) ([39e8ceb](https://github.com/angular/angular/commit/39e8ceb))
|
||||||
* **ivy:** ensure `window.ng.getDebugNode` returns debug info for component elements ([#32780](https://github.com/angular/angular/issues/32780)) ([5651fa3](https://github.com/angular/angular/commit/5651fa3))
|
* **ivy:** ensure `window.ng.getDebugNode` returns debug info for component elements ([#32780](https://github.com/angular/angular/issues/32780)) ([5651fa3](https://github.com/angular/angular/commit/5651fa3))
|
||||||
* **ivy:** ensure multiple map-based bindings do not skip intermediate values ([#32774](https://github.com/angular/angular/issues/32774)) ([86fd571](https://github.com/angular/angular/commit/86fd571))
|
* **ivy:** ensure multiple map-based bindings do not skip intermediate values ([#32774](https://github.com/angular/angular/issues/32774)) ([86fd571](https://github.com/angular/angular/commit/86fd571))
|
||||||
@ -1664,7 +1439,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **ivy:** graceful evaluation of unknown or invalid expressions ([#33453](https://github.com/angular/angular/issues/33453)) ([ce30888](https://github.com/angular/angular/commit/ce30888))
|
* **ivy:** graceful evaluation of unknown or invalid expressions ([#33453](https://github.com/angular/angular/issues/33453)) ([ce30888](https://github.com/angular/angular/commit/ce30888))
|
||||||
* **ivy:** implement unknown element detection in jit mode ([#33419](https://github.com/angular/angular/issues/33419)) ([c83f501](https://github.com/angular/angular/commit/c83f501))
|
* **ivy:** implement unknown element detection in jit mode ([#33419](https://github.com/angular/angular/issues/33419)) ([c83f501](https://github.com/angular/angular/commit/c83f501))
|
||||||
* add a flag in bootstrap to enable coalesce event change detection to improve performance ([#30533](https://github.com/angular/angular/issues/30533)) ([44623a1](https://github.com/angular/angular/commit/44623a1))
|
* add a flag in bootstrap to enable coalesce event change detection to improve performance ([#30533](https://github.com/angular/angular/issues/30533)) ([44623a1](https://github.com/angular/angular/commit/44623a1))
|
||||||
* **bazel:** update [@bazel](https://github.com/bazel)/schematics to Bazel 1.0.0 ([#33476](https://github.com/angular/angular/issues/33476)) ([540d104](https://github.com/angular/angular/commit/540d104)), closes [/github.com/angular/angular/pull/33367#issuecomment-547643246](https://github.com/angular/angular/pull/33367/issues/issuecomment-547643246)
|
* **bazel:** update [@bazel](https://github.com/bazel)/schematics to Bazel 1.0.0 ([#33476](https://github.com/angular/angular/issues/33476)) ([540d104](https://github.com/angular/angular/commit/540d104)), closes [/github.com/angular/angular/pull/33367#issuecomment-547643246](https://github.com/angular/angular/pull/33367#issuecomment-547643246)
|
||||||
* **bazel:** update bazel-schematics to use Ivy and new rollup_bundle ([#33435](https://github.com/angular/angular/issues/33435)) ([bf913cc](https://github.com/angular/angular/commit/bf913cc))
|
* **bazel:** update bazel-schematics to use Ivy and new rollup_bundle ([#33435](https://github.com/angular/angular/issues/33435)) ([bf913cc](https://github.com/angular/angular/commit/bf913cc))
|
||||||
* **ivy:** i18n - support inlining of XTB formatted translation files ([#33444](https://github.com/angular/angular/issues/33444)) ([2c623fd](https://github.com/angular/angular/commit/2c623fd))
|
* **ivy:** i18n - support inlining of XTB formatted translation files ([#33444](https://github.com/angular/angular/issues/33444)) ([2c623fd](https://github.com/angular/angular/commit/2c623fd))
|
||||||
* **language-service:** add support for text replacement ([#33091](https://github.com/angular/angular/issues/33091)) ([da4eb91](https://github.com/angular/angular/commit/da4eb91))
|
* **language-service:** add support for text replacement ([#33091](https://github.com/angular/angular/issues/33091)) ([da4eb91](https://github.com/angular/angular/commit/da4eb91))
|
||||||
@ -1706,7 +1481,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **ivy:** i18n - implement compile-time inlining ([#32881](https://github.com/angular/angular/issues/32881)) ([2cdb3a0](https://github.com/angular/angular/commit/2cdb3a0))
|
* **ivy:** i18n - implement compile-time inlining ([#32881](https://github.com/angular/angular/issues/32881)) ([2cdb3a0](https://github.com/angular/angular/commit/2cdb3a0))
|
||||||
* **ivy:** i18n - render legacy message ids in `$localize` if requested ([#32937](https://github.com/angular/angular/issues/32937)) ([bcbf3e4](https://github.com/angular/angular/commit/bcbf3e4))
|
* **ivy:** i18n - render legacy message ids in `$localize` if requested ([#32937](https://github.com/angular/angular/issues/32937)) ([bcbf3e4](https://github.com/angular/angular/commit/bcbf3e4))
|
||||||
* **language-service:** module definitions on directive hover ([#32763](https://github.com/angular/angular/issues/32763)) ([0d186dd](https://github.com/angular/angular/commit/0d186dd)), closes [#32565](https://github.com/angular/angular/issues/32565)
|
* **language-service:** module definitions on directive hover ([#32763](https://github.com/angular/angular/issues/32763)) ([0d186dd](https://github.com/angular/angular/commit/0d186dd)), closes [#32565](https://github.com/angular/angular/issues/32565)
|
||||||
* **ngcc:** expose `--create-ivy-entry-points` option on ivy-ngcc ([#33049](https://github.com/angular/angular/issues/33049)) ([b2b917d](https://github.com/angular/angular/commit/b2b917d)), closes [/github.com/angular/angular/pull/32999#issuecomment-539937368](https://github.com/angular/angular/pull/32999/issues/issuecomment-539937368)
|
* **ngcc:** expose `--create-ivy-entry-points` option on ivy-ngcc ([#33049](https://github.com/angular/angular/issues/33049)) ([b2b917d](https://github.com/angular/angular/commit/b2b917d)), closes [/github.com/angular/angular/pull/32999#issuecomment-539937368](https://github.com/angular/angular/pull/32999#issuecomment-539937368)
|
||||||
* update rxjs peerDependencies minimum requirment to 6.5.3 ([#32812](https://github.com/angular/angular/issues/32812)) ([66658c4](https://github.com/angular/angular/commit/66658c4))
|
* update rxjs peerDependencies minimum requirment to 6.5.3 ([#32812](https://github.com/angular/angular/issues/32812)) ([66658c4](https://github.com/angular/angular/commit/66658c4))
|
||||||
* **ivy:** support ng-add in localize package ([#32791](https://github.com/angular/angular/issues/32791)) ([e41cbfb](https://github.com/angular/angular/commit/e41cbfb))
|
* **ivy:** support ng-add in localize package ([#32791](https://github.com/angular/angular/issues/32791)) ([e41cbfb](https://github.com/angular/angular/commit/e41cbfb))
|
||||||
* **language-service:** allow retreiving synchronized analyzed NgModules ([#32779](https://github.com/angular/angular/issues/32779)) ([98feee7](https://github.com/angular/angular/commit/98feee7))
|
* **language-service:** allow retreiving synchronized analyzed NgModules ([#32779](https://github.com/angular/angular/issues/32779)) ([98feee7](https://github.com/angular/angular/commit/98feee7))
|
||||||
@ -1922,7 +1697,7 @@ API surface going forward.
|
|||||||
* **core:** Injector.get now accepts abstract classes to return
|
* **core:** Injector.get now accepts abstract classes to return
|
||||||
type-safe values. Previous implementation returned `any` through the
|
type-safe values. Previous implementation returned `any` through the
|
||||||
deprecated implementation.
|
deprecated implementation.
|
||||||
* Angular now compiles with Ivy by default ([#32219](https://github.com/angular/angular/issues/32219)) ([ec4381d](https://github.com/angular/angular/commit/ec4381d)).
|
* Angular now compiles with Ivy by default ([#32219](https://github.com/angular/angular/issues/32219)) ([ec4381d](https://github.com/angular/angular/commit/ec4381d)).
|
||||||
|
|
||||||
If you aren't familiar with Ivy, read our [blog post about the Ivy preview](https://blog.angular.io/its-time-for-the-compatibility-opt-in-preview-of-ivy-38f3542a282f?gi=8bfeb44b05c) and see the list of changes [here](https://docs.google.com/document/d/1Dije0AsJ0PxL3NaeNPxpYDeapj30b_QC0xfeIvIIzgg/preview).
|
If you aren't familiar with Ivy, read our [blog post about the Ivy preview](https://blog.angular.io/its-time-for-the-compatibility-opt-in-preview-of-ivy-38f3542a282f?gi=8bfeb44b05c) and see the list of changes [here](https://docs.google.com/document/d/1Dije0AsJ0PxL3NaeNPxpYDeapj30b_QC0xfeIvIIzgg/preview).
|
||||||
|
|
||||||
@ -2085,6 +1860,7 @@ This release contains various API docs improvements.
|
|||||||
* **language-service:** Eagarly initialize data members ([#31577](https://github.com/angular/angular/issues/31577)) ([0110de2](https://github.com/angular/angular/commit/0110de2))
|
* **language-service:** Eagarly initialize data members ([#31577](https://github.com/angular/angular/issues/31577)) ([0110de2](https://github.com/angular/angular/commit/0110de2))
|
||||||
* **bazel:** revert location of xi18n outputs to bazel-genfiles ([#31410](https://github.com/angular/angular/issues/31410)) ([1d3e227](https://github.com/angular/angular/commit/1d3e227))
|
* **bazel:** revert location of xi18n outputs to bazel-genfiles ([#31410](https://github.com/angular/angular/issues/31410)) ([1d3e227](https://github.com/angular/angular/commit/1d3e227))
|
||||||
* **compiler:** give ASTWithSource its own visit method ([#31347](https://github.com/angular/angular/issues/31347)) ([6aaca21](https://github.com/angular/angular/commit/6aaca21))
|
* **compiler:** give ASTWithSource its own visit method ([#31347](https://github.com/angular/angular/issues/31347)) ([6aaca21](https://github.com/angular/angular/commit/6aaca21))
|
||||||
|
* **core:** handle `undefined` meta in `injectArgs` ([#31333](https://github.com/angular/angular/issues/31333)) ([80ccd6c](https://github.com/angular/angular/commit/80ccd6c)), closes [CLI #14888](https://github.com/angular/angular-cli/issues/14888)
|
||||||
* **service-worker:** cache opaque responses in data groups with `freshness` strategy ([#30977](https://github.com/angular/angular/issues/30977)) ([d7be38f](https://github.com/angular/angular/commit/d7be38f)), closes [#30968](https://github.com/angular/angular/issues/30968)
|
* **service-worker:** cache opaque responses in data groups with `freshness` strategy ([#30977](https://github.com/angular/angular/issues/30977)) ([d7be38f](https://github.com/angular/angular/commit/d7be38f)), closes [#30968](https://github.com/angular/angular/issues/30968)
|
||||||
* **service-worker:** cache opaque responses when requests exceeds timeout threshold ([#30977](https://github.com/angular/angular/issues/30977)) ([93abc35](https://github.com/angular/angular/commit/93abc35))
|
* **service-worker:** cache opaque responses when requests exceeds timeout threshold ([#30977](https://github.com/angular/angular/issues/30977)) ([93abc35](https://github.com/angular/angular/commit/93abc35))
|
||||||
|
|
||||||
@ -2114,6 +1890,7 @@ This release contains various API docs improvements.
|
|||||||
|
|
||||||
* use the correct WTF array to iterate over ([#31208](https://github.com/angular/angular/issues/31208)) ([4aed480](https://github.com/angular/angular/commit/4aed480))
|
* use the correct WTF array to iterate over ([#31208](https://github.com/angular/angular/issues/31208)) ([4aed480](https://github.com/angular/angular/commit/4aed480))
|
||||||
* **compiler-cli:** Return original sourceFile instead of redirected sourceFile from getSourceFile ([#26036](https://github.com/angular/angular/issues/26036)) ([13dbb98](https://github.com/angular/angular/commit/13dbb98)), closes [#22524](https://github.com/angular/angular/issues/22524)
|
* **compiler-cli:** Return original sourceFile instead of redirected sourceFile from getSourceFile ([#26036](https://github.com/angular/angular/issues/26036)) ([13dbb98](https://github.com/angular/angular/commit/13dbb98)), closes [#22524](https://github.com/angular/angular/issues/22524)
|
||||||
|
* **core:** export provider interfaces that are part of the public API types ([#31377](https://github.com/angular/angular/issues/31377)) ([bebf089](https://github.com/angular/angular/commit/bebf089)), closes [/github.com/angular/angular/pull/31377#discussion_r299254408](https://github.com/angular/angular/pull/31377/issues/discussion_r299254408) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L365-L366](https://github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L365-L366) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L283-L284](https://github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L283-L284) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts#L23](https://github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts/issues/L23)
|
||||||
|
|
||||||
|
|
||||||
<a name="8.1.1"></a>
|
<a name="8.1.1"></a>
|
||||||
@ -2291,6 +2068,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
### Features
|
### Features
|
||||||
|
|
||||||
* add support for TypeScript 3.4 (and drop older versions) ([#29372](https://github.com/angular/angular/issues/29372)) ([ef85336](https://github.com/angular/angular/commit/ef85336))
|
* add support for TypeScript 3.4 (and drop older versions) ([#29372](https://github.com/angular/angular/issues/29372)) ([ef85336](https://github.com/angular/angular/commit/ef85336))
|
||||||
|
* **common:** add ability to watch for AngularJS URL updates through `onUrlChange` hook ([#30466](https://github.com/angular/angular/issues/30466)) ([8022d36](https://github.com/angular/angular/commit/8022d36))
|
||||||
* **common:** stricter types for `SlicePipe` ([#30156](https://github.com/angular/angular/issues/30156)) ([722b2fa](https://github.com/angular/angular/commit/722b2fa))
|
* **common:** stricter types for `SlicePipe` ([#30156](https://github.com/angular/angular/issues/30156)) ([722b2fa](https://github.com/angular/angular/commit/722b2fa))
|
||||||
* **bazel:** use `rbe_autoconfig()` and new container ([#29336](https://github.com/angular/angular/issues/29336)) ([e562acc](https://github.com/angular/angular/commit/e562acc))
|
* **bazel:** use `rbe_autoconfig()` and new container ([#29336](https://github.com/angular/angular/issues/29336)) ([e562acc](https://github.com/angular/angular/commit/e562acc))
|
||||||
* **common:** add @angular/common/upgrade package for `$location`-related APIs ([#30055](https://github.com/angular/angular/issues/30055)) ([152d99e](https://github.com/angular/angular/commit/152d99e))
|
* **common:** add @angular/common/upgrade package for `$location`-related APIs ([#30055](https://github.com/angular/angular/issues/30055)) ([152d99e](https://github.com/angular/angular/commit/152d99e))
|
||||||
@ -2407,6 +2185,8 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **bazel:** use `//:tsconfig.json` as the default for `ng_module` ([#29670](https://github.com/angular/angular/issues/29670)) ([b14537a](https://github.com/angular/angular/commit/b14537a))
|
* **bazel:** use `//:tsconfig.json` as the default for `ng_module` ([#29670](https://github.com/angular/angular/issues/29670)) ([b14537a](https://github.com/angular/angular/commit/b14537a))
|
||||||
* **compiler-cli:** ngcc - cope with processing entry-points multiple times ([#29657](https://github.com/angular/angular/issues/29657)) ([6b39c9c](https://github.com/angular/angular/commit/6b39c9c))
|
* **compiler-cli:** ngcc - cope with processing entry-points multiple times ([#29657](https://github.com/angular/angular/issues/29657)) ([6b39c9c](https://github.com/angular/angular/commit/6b39c9c))
|
||||||
* **core:** static-query schematic should detect static queries in getters. ([#29609](https://github.com/angular/angular/issues/29609)) ([33016b8](https://github.com/angular/angular/commit/33016b8))
|
* **core:** static-query schematic should detect static queries in getters. ([#29609](https://github.com/angular/angular/issues/29609)) ([33016b8](https://github.com/angular/angular/commit/33016b8))
|
||||||
|
* **common:** escape query selector used when anchor scrolling ([#29577](https://github.com/angular/angular/issues/29577)) ([7671c73](https://github.com/angular/angular/commit/7671c73)), closes [#28193](https://github.com/angular/angular/issues/28193)
|
||||||
|
* **router:** adjust setting navigationTransition when a new navigation cancels an existing one ([#29636](https://github.com/angular/angular/issues/29636)) ([e884c0c](https://github.com/angular/angular/commit/e884c0c)), closes [#29389](https://github.com/angular/angular/issues/29389) [#29590](https://github.com/angular/angular/issues/29590)
|
||||||
* **bazel:** allow `ng_module` users to set `createExternalSymbolFactoryReexports` ([#29459](https://github.com/angular/angular/issues/29459)) ([21be0fb](https://github.com/angular/angular/commit/21be0fb))
|
* **bazel:** allow `ng_module` users to set `createExternalSymbolFactoryReexports` ([#29459](https://github.com/angular/angular/issues/29459)) ([21be0fb](https://github.com/angular/angular/commit/21be0fb))
|
||||||
* **bazel:** workaround problem reading summary files from node_modules ([#29459](https://github.com/angular/angular/issues/29459)) ([769d960](https://github.com/angular/angular/commit/769d960))
|
* **bazel:** workaround problem reading summary files from node_modules ([#29459](https://github.com/angular/angular/issues/29459)) ([769d960](https://github.com/angular/angular/commit/769d960))
|
||||||
* **compiler:** inherit param types when class has a constructor which takes no declared parameters and delegates up ([#29232](https://github.com/angular/angular/issues/29232)) ([0007564](https://github.com/angular/angular/commit/0007564))
|
* **compiler:** inherit param types when class has a constructor which takes no declared parameters and delegates up ([#29232](https://github.com/angular/angular/issues/29232)) ([0007564](https://github.com/angular/angular/commit/0007564))
|
||||||
@ -2433,7 +2213,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
* **platform-server:** update minimum domino version to latest released ([#28893](https://github.com/angular/angular/issues/28893)) ([79e2ca0](https://github.com/angular/angular/commit/79e2ca0))
|
* **platform-server:** update minimum domino version to latest released ([#28893](https://github.com/angular/angular/issues/28893)) ([79e2ca0](https://github.com/angular/angular/commit/79e2ca0))
|
||||||
* **router:** removed obsolete TODO comment ([#29085](https://github.com/angular/angular/issues/29085)) ([72ecc45](https://github.com/angular/angular/commit/72ecc45))
|
* **router:** removed obsolete TODO comment ([#29085](https://github.com/angular/angular/issues/29085)) ([72ecc45](https://github.com/angular/angular/commit/72ecc45))
|
||||||
* **service-worker:** detect new version even if files are identical to an old one ([#26006](https://github.com/angular/angular/issues/26006)) ([586234b](https://github.com/angular/angular/commit/586234b)), closes [#24338](https://github.com/angular/angular/issues/24338)
|
* **service-worker:** detect new version even if files are identical to an old one ([#26006](https://github.com/angular/angular/issues/26006)) ([586234b](https://github.com/angular/angular/commit/586234b)), closes [#24338](https://github.com/angular/angular/issues/24338)
|
||||||
* **service-worker:** ignore passive mixed content requests ([#25994](https://github.com/angular/angular/issues/25994)) ([48214e2](https://github.com/angular/angular/commit/48214e2)), closes [/github.com/angular/angular/issues/23012#issuecomment-376430187](https://github.com/angular/angular/issues/23012/issues/issuecomment-376430187) [#23012](https://github.com/angular/angular/issues/23012)
|
* **service-worker:** ignore passive mixed content requests ([#25994](https://github.com/angular/angular/issues/25994)) ([48214e2](https://github.com/angular/angular/commit/48214e2)), closes [23012#issuecomment-376430187](https://github.com/angular/angular/issues/23012#issuecomment-376430187) [#23012](https://github.com/angular/angular/issues/23012)
|
||||||
* **bazel:** Pin browsers for schematics ([#28913](https://github.com/angular/angular/issues/28913)) ([1145bdb](https://github.com/angular/angular/commit/1145bdb))
|
* **bazel:** Pin browsers for schematics ([#28913](https://github.com/angular/angular/issues/28913)) ([1145bdb](https://github.com/angular/angular/commit/1145bdb))
|
||||||
* **bazel:** rxjs_umd_modules should always be present ([#28881](https://github.com/angular/angular/issues/28881)) ([9ae14db](https://github.com/angular/angular/commit/9ae14db))
|
* **bazel:** rxjs_umd_modules should always be present ([#28881](https://github.com/angular/angular/issues/28881)) ([9ae14db](https://github.com/angular/angular/commit/9ae14db))
|
||||||
* **compiler:** use correct variable in invalid function ([#28656](https://github.com/angular/angular/issues/28656)) ([f75acbd](https://github.com/angular/angular/commit/f75acbd))
|
* **compiler:** use correct variable in invalid function ([#28656](https://github.com/angular/angular/issues/28656)) ([f75acbd](https://github.com/angular/angular/commit/f75acbd))
|
||||||
@ -2495,6 +2275,7 @@ To learn about the release highlights and our CLI-powered automated update workf
|
|||||||
|
|
||||||
* **core:** deprecate integration with the Web Tracing Framework (WTF) ([#30642](https://github.com/angular/angular/issues/30642)) ([b408445](https://github.com/angular/angular/commit/b408445))
|
* **core:** deprecate integration with the Web Tracing Framework (WTF) ([#30642](https://github.com/angular/angular/issues/30642)) ([b408445](https://github.com/angular/angular/commit/b408445))
|
||||||
* **platform-webworker:** deprecate platform-webworker ([#30642](https://github.com/angular/angular/issues/30642)) ([361f181](https://github.com/angular/angular/commit/361f181))
|
* **platform-webworker:** deprecate platform-webworker ([#30642](https://github.com/angular/angular/issues/30642)) ([361f181](https://github.com/angular/angular/commit/361f181))
|
||||||
|
* `TestBed.get()` has two signatures, one which is typed and another which accepts and returns `any`. The signature for `any` is deprecated; all usage of `TestBed.get()` should go through the typed API. This mainly affects string tokens
|
||||||
(which aren't supported) and abstract class tokens.
|
(which aren't supported) and abstract class tokens.
|
||||||
|
|
||||||
Before:
|
Before:
|
||||||
@ -2647,7 +2428,7 @@ This release contains various API docs improvements.
|
|||||||
* **animations:** ensure `position` and `display` styles are handled outside of keyframes/web-animations ([#28911](https://github.com/angular/angular/issues/28911)) ([86981b3](https://github.com/angular/angular/commit/86981b3)), closes [#24923](https://github.com/angular/angular/issues/24923) [#25635](https://github.com/angular/angular/issues/25635)
|
* **animations:** ensure `position` and `display` styles are handled outside of keyframes/web-animations ([#28911](https://github.com/angular/angular/issues/28911)) ([86981b3](https://github.com/angular/angular/commit/86981b3)), closes [#24923](https://github.com/angular/angular/issues/24923) [#25635](https://github.com/angular/angular/issues/25635)
|
||||||
* **router:** removed obsolete TODO comment ([#29085](https://github.com/angular/angular/issues/29085)) ([2a25ac2](https://github.com/angular/angular/commit/2a25ac2))
|
* **router:** removed obsolete TODO comment ([#29085](https://github.com/angular/angular/issues/29085)) ([2a25ac2](https://github.com/angular/angular/commit/2a25ac2))
|
||||||
* **service-worker:** detect new version even if files are identical to an old one ([#26006](https://github.com/angular/angular/issues/26006)) ([5669333](https://github.com/angular/angular/commit/5669333)), closes [#24338](https://github.com/angular/angular/issues/24338)
|
* **service-worker:** detect new version even if files are identical to an old one ([#26006](https://github.com/angular/angular/issues/26006)) ([5669333](https://github.com/angular/angular/commit/5669333)), closes [#24338](https://github.com/angular/angular/issues/24338)
|
||||||
* **service-worker:** ignore passive mixed content requests ([#25994](https://github.com/angular/angular/issues/25994)) ([b598e88](https://github.com/angular/angular/commit/b598e88)), closes [/github.com/angular/angular/issues/23012#issuecomment-376430187](https://github.com/angular/angular/issues/23012/issues/issuecomment-376430187) [#23012](https://github.com/angular/angular/issues/23012)
|
* **service-worker:** ignore passive mixed content requests ([#25994](https://github.com/angular/angular/issues/25994)) ([b598e88](https://github.com/angular/angular/commit/b598e88)), closes [23012#issuecomment-376430187](https://github.com/angular/angular/issues/23012#issuecomment-376430187) [#23012](https://github.com/angular/angular/issues/23012)
|
||||||
|
|
||||||
|
|
||||||
<a name="7.2.7"></a>
|
<a name="7.2.7"></a>
|
||||||
@ -2743,6 +2524,14 @@ This release contains various API docs improvements.
|
|||||||
# [8.0.0-beta.0](https://github.com/angular/angular/compare/7.2.0...8.0.0-beta.0) (2019-01-16)
|
# [8.0.0-beta.0](https://github.com/angular/angular/compare/7.2.0...8.0.0-beta.0) (2019-01-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
### Performance Improvements
|
||||||
|
|
||||||
|
|
||||||
@ -2890,9 +2679,42 @@ This release contains various API docs improvements.
|
|||||||
# [7.1.0](https://github.com/angular/angular/compare/7.1.0-rc.0...7.1.0) (2018-11-21)
|
# [7.1.0](https://github.com/angular/angular/compare/7.1.0-rc.0...7.1.0) (2018-11-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **core:** allow null value for renderer setElement(…) ([#17065](https://github.com/angular/angular/issues/17065)) ([ff15043](https://github.com/angular/angular/commit/ff15043)), closes [#13686](https://github.com/angular/angular/issues/13686)
|
||||||
|
* **router:** fix regression where navigateByUrl promise didn't resolve on CanLoad failure ([#26455](https://github.com/angular/angular/issues/26455)) ([1c9b065](https://github.com/angular/angular/commit/1c9b065)), closes [#26284](https://github.com/angular/angular/issues/26284)
|
||||||
|
* **service-worker:** clean up caches from old SW versions ([#26319](https://github.com/angular/angular/issues/26319)) ([2326b9c](https://github.com/angular/angular/commit/2326b9c))
|
||||||
|
* **upgrade:** properly destroy upgraded component elements and descendants ([#26209](https://github.com/angular/angular/issues/26209)) ([071934e](https://github.com/angular/angular/commit/071934e)), closes [#26208](https://github.com/angular/angular/issues/26208)
|
||||||
|
* **compiler:** generate inputs with aliases properly ([#26774](https://github.com/angular/angular/issues/26774)) ([19fcfc3](https://github.com/angular/angular/commit/19fcfc3))
|
||||||
|
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([56f44be](https://github.com/angular/angular/commit/56f44be))
|
||||||
|
* **core:** ignore comment nodes under unsafe elements ([#25879](https://github.com/angular/angular/issues/25879)) ([d5cbcef](https://github.com/angular/angular/commit/d5cbcef))
|
||||||
|
* **core:** Remove static dependency from @angular/core to @angular/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([d042c4a](https://github.com/angular/angular/commit/d042c4a))
|
||||||
|
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([95743e3](https://github.com/angular/angular/commit/95743e3))
|
||||||
|
* **bazel:** unknown replay compiler error in windows ([#26711](https://github.com/angular/angular/issues/26711)) ([aed95fd](https://github.com/angular/angular/commit/aed95fd))
|
||||||
|
* **core:** ensure that `ɵdefineNgModule` is available in flat-file formats ([#26403](https://github.com/angular/angular/issues/26403)) ([a64859b](https://github.com/angular/angular/commit/a64859b))
|
||||||
|
* **router:** remove type bludgeoning of context and outlet when running CanDeactivate ([#26496](https://github.com/angular/angular/issues/26496)) ([496372d](https://github.com/angular/angular/commit/496372d)), closes [#18253](https://github.com/angular/angular/issues/18253)
|
||||||
|
* **service-worker:** add typing to public api guard and fix lint errors ([#25860](https://github.com/angular/angular/issues/25860)) ([1061875](https://github.com/angular/angular/commit/1061875))
|
||||||
|
* **upgrade:** improve downgrading-related error messages ([#26217](https://github.com/angular/angular/issues/26217)) ([7dbc103](https://github.com/angular/angular/commit/7dbc103))
|
||||||
|
* **upgrade:** make typings compatible with older AngularJS typings ([#26880](https://github.com/angular/angular/issues/26880)) ([64647af](https://github.com/angular/angular/commit/64647af)), closes [#26420](https://github.com/angular/angular/issues/26420)
|
||||||
|
* **compiler-cli:** add missing tslib dependency ([#27063](https://github.com/angular/angular/issues/27063)) ([c31e78f](https://github.com/angular/angular/commit/c31e78f))
|
||||||
|
* **compiler-cli:** only pass canonical genfile paths to compiler host ([#27062](https://github.com/angular/angular/issues/27062)) ([0ada23a](https://github.com/angular/angular/commit/0ada23a))
|
||||||
|
* **router:** add `relativeLinkResolution` to `recognize` operator ([#26990](https://github.com/angular/angular/issues/26990)) ([a752971](https://github.com/angular/angular/commit/a752971)), closes [#26983](https://github.com/angular/angular/issues/26983)
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* **bazel:** Bazel workspace schematics ([#26971](https://github.com/angular/angular/issues/26971)) ([b07bd30](https://github.com/angular/angular/commit/b07bd30))
|
* **bazel:** Bazel workspace schematics ([#26971](https://github.com/angular/angular/issues/26971)) ([b07bd30](https://github.com/angular/angular/commit/b07bd30))
|
||||||
|
* **router:** add prioritizedGuardValue operator optimization and allowing UrlTree return from guard ([#26478](https://github.com/angular/angular/issues/26478)) ([fdfedce](https://github.com/angular/angular/commit/fdfedce))
|
||||||
|
* **compiler:** ability to mark an InvokeFunctionExpr as pure ([#26860](https://github.com/angular/angular/issues/26860)) ([4dfa71f](https://github.com/angular/angular/commit/4dfa71f))
|
||||||
|
* **forms:** add updateOn option to FormBuilder ([#24599](https://github.com/angular/angular/issues/24599)) ([e9e804f](https://github.com/angular/angular/commit/e9e804f))
|
||||||
|
* **router:** allow guards to return UrlTree as well as boolean ([#26521](https://github.com/angular/angular/issues/26521)) ([081f95c](https://github.com/angular/angular/commit/081f95c))
|
||||||
|
* **router:** allow redirect from guards by returning UrlTree ([#26521](https://github.com/angular/angular/issues/26521)) ([152ca66](https://github.com/angular/angular/commit/152ca66))
|
||||||
|
* **router:** guard returning UrlTree cancels current navigation and redirects ([#26521](https://github.com/angular/angular/issues/26521)) ([4e9f2e5](https://github.com/angular/angular/commit/4e9f2e5)), closes [#24618](https://github.com/angular/angular/issues/24618)
|
||||||
|
* **service-worker:** add typing for messagesClicked in SwPush service ([#25860](https://github.com/angular/angular/issues/25860)) ([c78c221](https://github.com/angular/angular/commit/c78c221))
|
||||||
|
* **service-worker:** close notifications and focus window on click ([#25860](https://github.com/angular/angular/issues/25860)) ([f5d5a3d](https://github.com/angular/angular/commit/f5d5a3d))
|
||||||
|
* **service-worker:** handle 'notificationclick' events ([#25860](https://github.com/angular/angular/issues/25860)) ([cf6ea28](https://github.com/angular/angular/commit/cf6ea28)), closes [#20956](https://github.com/angular/angular/issues/20956) [#22311](https://github.com/angular/angular/issues/22311)
|
||||||
|
* **upgrade:** support downgrading multiple modules ([#26217](https://github.com/angular/angular/issues/26217)) ([93837e9](https://github.com/angular/angular/commit/93837e9)), closes [#26062](https://github.com/angular/angular/issues/26062)
|
||||||
|
* **router:** add pathParamsChange mode for runGuardsAndResolvers ([#26861](https://github.com/angular/angular/issues/26861)) ([bf6ac6c](https://github.com/angular/angular/commit/bf6ac6c)), closes [#18253](https://github.com/angular/angular/issues/18253)
|
||||||
|
|
||||||
|
|
||||||
<a name="7.1.0-rc.0"></a>
|
<a name="7.1.0-rc.0"></a>
|
||||||
@ -2995,7 +2817,10 @@ This release contains various API docs improvements.
|
|||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
* **core:** allow null value for renderer setElement(…) ([#17065](https://github.com/angular/angular/issues/17065)) ([ff15043](https://github.com/angular/angular/commit/ff15043)), closes [#13686](https://github.com/angular/angular/issues/13686)
|
||||||
|
* **router:** fix regression where navigateByUrl promise didn't resolve on CanLoad failure ([#26455](https://github.com/angular/angular/issues/26455)) ([1c9b065](https://github.com/angular/angular/commit/1c9b065)), closes [#26284](https://github.com/angular/angular/issues/26284)
|
||||||
* **service-worker:** clean up caches from old SW versions ([#26319](https://github.com/angular/angular/issues/26319)) ([2326b9c](https://github.com/angular/angular/commit/2326b9c))
|
* **service-worker:** clean up caches from old SW versions ([#26319](https://github.com/angular/angular/issues/26319)) ([2326b9c](https://github.com/angular/angular/commit/2326b9c))
|
||||||
|
* **upgrade:** properly destroy upgraded component elements and descendants ([#26209](https://github.com/angular/angular/issues/26209)) ([071934e](https://github.com/angular/angular/commit/071934e)), closes [#26208](https://github.com/angular/angular/issues/26208)
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
@ -3167,6 +2992,7 @@ Note: the 6.1.5 release on npm accidentally glitched-out midway, so we cut 6.1.6
|
|||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* **animations:** always render end-state styles for orphaned DOM nodes ([#24236](https://github.com/angular/angular/issues/24236)) ([dc4a3d0](https://github.com/angular/angular/commit/dc4a3d0))
|
* **animations:** always render end-state styles for orphaned DOM nodes ([#24236](https://github.com/angular/angular/issues/24236)) ([dc4a3d0](https://github.com/angular/angular/commit/dc4a3d0))
|
||||||
|
* **animations:** set animations styles properly on platform-server ([#24624](https://github.com/angular/angular/issues/24624)) ([0b356d4](https://github.com/angular/angular/commit/0b356d4))
|
||||||
* **animations:** do not throw errors when a destroyed component is animated ([#23836](https://github.com/angular/angular/issues/23836)) ([d2a8687](https://github.com/angular/angular/commit/d2a8687))
|
* **animations:** do not throw errors when a destroyed component is animated ([#23836](https://github.com/angular/angular/issues/23836)) ([d2a8687](https://github.com/angular/angular/commit/d2a8687))
|
||||||
* **animations:** Fix browser detection logic ([#24188](https://github.com/angular/angular/issues/24188)) ([b492b9e](https://github.com/angular/angular/commit/b492b9e))
|
* **animations:** Fix browser detection logic ([#24188](https://github.com/angular/angular/issues/24188)) ([b492b9e](https://github.com/angular/angular/commit/b492b9e))
|
||||||
* **animations:** properly clean up queried element styles in safari/edge ([#23633](https://github.com/angular/angular/issues/23633)) ([da9ff25](https://github.com/angular/angular/commit/da9ff25))
|
* **animations:** properly clean up queried element styles in safari/edge ([#23633](https://github.com/angular/angular/issues/23633)) ([da9ff25](https://github.com/angular/angular/commit/da9ff25))
|
||||||
@ -3178,6 +3004,7 @@ Note: the 6.1.5 release on npm accidentally glitched-out midway, so we cut 6.1.6
|
|||||||
* **common:** format fractional seconds ([#24844](https://github.com/angular/angular/issues/24844)) ([0b4d85e](https://github.com/angular/angular/commit/0b4d85e)), closes [#24831](https://github.com/angular/angular/issues/24831)
|
* **common:** format fractional seconds ([#24844](https://github.com/angular/angular/issues/24844)) ([0b4d85e](https://github.com/angular/angular/commit/0b4d85e)), closes [#24831](https://github.com/angular/angular/issues/24831)
|
||||||
* **common:** properly update collection reference in NgForOf ([#24684](https://github.com/angular/angular/issues/24684)) ([ff84c5c](https://github.com/angular/angular/commit/ff84c5c)), closes [#24155](https://github.com/angular/angular/issues/24155)
|
* **common:** properly update collection reference in NgForOf ([#24684](https://github.com/angular/angular/issues/24684)) ([ff84c5c](https://github.com/angular/angular/commit/ff84c5c)), closes [#24155](https://github.com/angular/angular/issues/24155)
|
||||||
* **common:** use correct currency format for locale de-AT ([#24658](https://github.com/angular/angular/issues/24658)) ([dcabb05](https://github.com/angular/angular/commit/dcabb05)), closes [#24609](https://github.com/angular/angular/issues/24609)
|
* **common:** use correct currency format for locale de-AT ([#24658](https://github.com/angular/angular/issues/24658)) ([dcabb05](https://github.com/angular/angular/commit/dcabb05)), closes [#24609](https://github.com/angular/angular/issues/24609)
|
||||||
|
* **common:** use correct ICU plural for locale mk ([#24659](https://github.com/angular/angular/issues/24659)) ([64a8584](https://github.com/angular/angular/commit/64a8584))
|
||||||
* **compiler:** fix a few non-tree-shakeable code patterns ([#24677](https://github.com/angular/angular/issues/24677)) ([50d4a4f](https://github.com/angular/angular/commit/50d4a4f))
|
* **compiler:** fix a few non-tree-shakeable code patterns ([#24677](https://github.com/angular/angular/issues/24677)) ([50d4a4f](https://github.com/angular/angular/commit/50d4a4f))
|
||||||
* **compiler:** i18n_extractor now outputs the correct source file name ([#24885](https://github.com/angular/angular/issues/24885)) ([c8ad965](https://github.com/angular/angular/commit/c8ad965)), closes [#24884](https://github.com/angular/angular/issues/24884)
|
* **compiler:** i18n_extractor now outputs the correct source file name ([#24885](https://github.com/angular/angular/issues/24885)) ([c8ad965](https://github.com/angular/angular/commit/c8ad965)), closes [#24884](https://github.com/angular/angular/issues/24884)
|
||||||
* **compiler:** support `.` in import statements. ([#20634](https://github.com/angular/angular/issues/20634)) ([d8f7b29](https://github.com/angular/angular/commit/d8f7b29)), closes [#20363](https://github.com/angular/angular/issues/20363)
|
* **compiler:** support `.` in import statements. ([#20634](https://github.com/angular/angular/issues/20634)) ([d8f7b29](https://github.com/angular/angular/commit/d8f7b29)), closes [#20363](https://github.com/angular/angular/issues/20363)
|
||||||
@ -3213,6 +3040,7 @@ Note: the 6.1.5 release on npm accidentally glitched-out midway, so we cut 6.1.6
|
|||||||
* **service-worker:** don't include sourceMappingURL in ngsw-worker ([#24877](https://github.com/angular/angular/issues/24877)) ([8620373](https://github.com/angular/angular/commit/8620373)), closes [#23596](https://github.com/angular/angular/issues/23596)
|
* **service-worker:** don't include sourceMappingURL in ngsw-worker ([#24877](https://github.com/angular/angular/issues/24877)) ([8620373](https://github.com/angular/angular/commit/8620373)), closes [#23596](https://github.com/angular/angular/issues/23596)
|
||||||
* **service-worker:** avoid network requests when looking up hashed resources in cache ([#24127](https://github.com/angular/angular/issues/24127)) ([52d43a9](https://github.com/angular/angular/commit/52d43a9))
|
* **service-worker:** avoid network requests when looking up hashed resources in cache ([#24127](https://github.com/angular/angular/issues/24127)) ([52d43a9](https://github.com/angular/angular/commit/52d43a9))
|
||||||
* **service-worker:** fix `SwPush.unsubscribe()` ([#24162](https://github.com/angular/angular/issues/24162)) ([3ed2d75](https://github.com/angular/angular/commit/3ed2d75)), closes [#24095](https://github.com/angular/angular/issues/24095)
|
* **service-worker:** fix `SwPush.unsubscribe()` ([#24162](https://github.com/angular/angular/issues/24162)) ([3ed2d75](https://github.com/angular/angular/commit/3ed2d75)), closes [#24095](https://github.com/angular/angular/issues/24095)
|
||||||
|
* **service-worker:** add badge to NOTIFICATION_OPTION_NAMES ([#23241](https://github.com/angular/angular/issues/23241)) ([fb59b2d](https://github.com/angular/angular/commit/fb59b2d)), closes [#23196](https://github.com/angular/angular/issues/23196)
|
||||||
* **service-worker:** check platformBrowser before accessing navigator.serviceWorker ([#21231](https://github.com/angular/angular/issues/21231)) ([0bdd30e](https://github.com/angular/angular/commit/0bdd30e))
|
* **service-worker:** check platformBrowser before accessing navigator.serviceWorker ([#21231](https://github.com/angular/angular/issues/21231)) ([0bdd30e](https://github.com/angular/angular/commit/0bdd30e))
|
||||||
* **service-worker:** correctly handle requests with empty `clientId` ([#23625](https://github.com/angular/angular/issues/23625)) ([e0ed59e](https://github.com/angular/angular/commit/e0ed59e)), closes [#23526](https://github.com/angular/angular/issues/23526)
|
* **service-worker:** correctly handle requests with empty `clientId` ([#23625](https://github.com/angular/angular/issues/23625)) ([e0ed59e](https://github.com/angular/angular/commit/e0ed59e)), closes [#23526](https://github.com/angular/angular/issues/23526)
|
||||||
* **service-worker:** deprecate `versionedFiles` in asset-group resources ([#23584](https://github.com/angular/angular/issues/23584)) ([1d378e2](https://github.com/angular/angular/commit/1d378e2))
|
* **service-worker:** deprecate `versionedFiles` in asset-group resources ([#23584](https://github.com/angular/angular/issues/23584)) ([1d378e2](https://github.com/angular/angular/commit/1d378e2))
|
||||||
@ -3413,6 +3241,8 @@ To learn about the release highlights and our new CLI-powered update workflow fo
|
|||||||
* **forms:** multiple validators for array method ([#20766](https://github.com/angular/angular/issues/20766)) ([941e88f](https://github.com/angular/angular/commit/941e88f)), closes [#20665](https://github.com/angular/angular/issues/20665)
|
* **forms:** multiple validators for array method ([#20766](https://github.com/angular/angular/issues/20766)) ([941e88f](https://github.com/angular/angular/commit/941e88f)), closes [#20665](https://github.com/angular/angular/issues/20665)
|
||||||
* **forms:** allow markAsPending to emit events ([#20212](https://github.com/angular/angular/issues/20212)) ([e86b64b](https://github.com/angular/angular/commit/e86b64b)), closes [#17958](https://github.com/angular/angular/issues/17958)
|
* **forms:** allow markAsPending to emit events ([#20212](https://github.com/angular/angular/issues/20212)) ([e86b64b](https://github.com/angular/angular/commit/e86b64b)), closes [#17958](https://github.com/angular/angular/issues/17958)
|
||||||
* **platform-browser:** add token marking which the type of animation module nearest in the injector tree ([#23075](https://github.com/angular/angular/issues/23075)) ([b551f84](https://github.com/angular/angular/commit/b551f84))
|
* **platform-browser:** add token marking which the type of animation module nearest in the injector tree ([#23075](https://github.com/angular/angular/issues/23075)) ([b551f84](https://github.com/angular/angular/commit/b551f84))
|
||||||
|
* **platform-browser:** do not throw error when Hammer.js not loaded ([#22257](https://github.com/angular/angular/issues/22257)) ([991300b](https://github.com/angular/angular/commit/991300b)), closes [#16992](https://github.com/angular/angular/issues/16992)
|
||||||
|
* **platform-browser:** fix [#19604](https://github.com/angular/angular/issues/19604), can config hammerOptions ([#21979](https://github.com/angular/angular/issues/21979)) ([1d571b2](https://github.com/angular/angular/commit/1d571b2))
|
||||||
* **platform-server:** bump Domino to v2.0 ([#22411](https://github.com/angular/angular/issues/22411)) ([d3827a0](https://github.com/angular/angular/commit/d3827a0))
|
* **platform-server:** bump Domino to v2.0 ([#22411](https://github.com/angular/angular/issues/22411)) ([d3827a0](https://github.com/angular/angular/commit/d3827a0))
|
||||||
* **router:** add navigationSource and restoredState to NavigationStart event ([#21728](https://github.com/angular/angular/issues/21728)) ([c40ae7f](https://github.com/angular/angular/commit/c40ae7f))
|
* **router:** add navigationSource and restoredState to NavigationStart event ([#21728](https://github.com/angular/angular/issues/21728)) ([c40ae7f](https://github.com/angular/angular/commit/c40ae7f))
|
||||||
* **service-worker:** add support for configuring navigations URLs ([#23339](https://github.com/angular/angular/issues/23339)) ([08325aa](https://github.com/angular/angular/commit/08325aa)), closes [#20404](https://github.com/angular/angular/issues/20404)
|
* **service-worker:** add support for configuring navigations URLs ([#23339](https://github.com/angular/angular/issues/23339)) ([08325aa](https://github.com/angular/angular/commit/08325aa)), closes [#20404](https://github.com/angular/angular/issues/20404)
|
||||||
@ -3631,7 +3461,12 @@ To learn about the release highlights and our new CLI-powered update workflow fo
|
|||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **platform-server:** generate correct stylings for camel case names ([#22263](https://github.com/angular/angular/issues/22263)) ([de02a7a](https://github.com/angular/angular/commit/de02a7a)), closes [#19235](https://github.com/angular/angular/issues/19235)
|
||||||
|
* **router:** don't mutate route configs ([#22358](https://github.com/angular/angular/issues/22358)) ([8f0a064](https://github.com/angular/angular/commit/8f0a064)), closes [#22203](https://github.com/angular/angular/issues/22203)
|
||||||
* **router:** fix URL serialization so special characters are only encoded where needed ([#22337](https://github.com/angular/angular/issues/22337)) ([789a47e](https://github.com/angular/angular/commit/789a47e)), closes [#10280](https://github.com/angular/angular/issues/10280)
|
* **router:** fix URL serialization so special characters are only encoded where needed ([#22337](https://github.com/angular/angular/issues/22337)) ([789a47e](https://github.com/angular/angular/commit/789a47e)), closes [#10280](https://github.com/angular/angular/issues/10280)
|
||||||
|
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([4aef9de](https://github.com/angular/angular/commit/4aef9de)), closes [#22392](https://github.com/angular/angular/issues/22392)
|
||||||
|
* **upgrade:** correctly handle `=` bindings in `@angular/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([6638390](https://github.com/angular/angular/commit/6638390))
|
||||||
|
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([a9a0e27](https://github.com/angular/angular/commit/a9a0e27)), closes [#22175](https://github.com/angular/angular/issues/22175)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -4026,6 +3861,15 @@ Note: Due to an animation fix back in 5.1.1 ([c2b3792](https://github.com/angula
|
|||||||
<a name="5.1.0-beta.0"></a>
|
<a name="5.1.0-beta.0"></a>
|
||||||
# [5.1.0-beta.0](https://github.com/angular/angular/compare/5.0.0-rc.4...5.1.0-beta.0) (2017-11-08)
|
# [5.1.0-beta.0](https://github.com/angular/angular/compare/5.0.0-rc.4...5.1.0-beta.0) (2017-11-08)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** don't overwrite missingTranslation's value in JIT ([#19952](https://github.com/angular/angular/issues/19952)) ([799cbb9](https://github.com/angular/angular/commit/799cbb9))
|
||||||
|
* **compiler:** report a reasonable error with invalid metadata ([#20062](https://github.com/angular/angular/issues/20062)) ([da22c48](https://github.com/angular/angular/commit/da22c48))
|
||||||
|
* **compiler-cli:** don't report emit diagnostics when `--noEmitOnError` is off ([#20063](https://github.com/angular/angular/issues/20063)) ([8639995](https://github.com/angular/angular/commit/8639995))
|
||||||
|
* **core:** `__symbol__` should return `__zone_symbol__` without zone.js loaded ([#19541](https://github.com/angular/angular/issues/19541)) ([678d1cf](https://github.com/angular/angular/commit/678d1cf))
|
||||||
|
* **core:** should support event.stopImmediatePropagation ([#19222](https://github.com/angular/angular/issues/19222)) ([7083791](https://github.com/angular/angular/commit/7083791))
|
||||||
|
* **platform-browser:** support Symbols in custom `jasmineToString()` method ([#19794](https://github.com/angular/angular/issues/19794)) ([5a6efa7](https://github.com/angular/angular/commit/5a6efa7))
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* **compiler:** introduce `TestBed.overrideTemplateUsingTestingModule` ([a460066](https://github.com/angular/angular/commit/a460066)), closes [#19815](https://github.com/angular/angular/issues/19815)
|
* **compiler:** introduce `TestBed.overrideTemplateUsingTestingModule` ([a460066](https://github.com/angular/angular/commit/a460066)), closes [#19815](https://github.com/angular/angular/issues/19815)
|
||||||
@ -4061,12 +3905,14 @@ Note: Due to an animation fix back in 5.1.1 ([c2b3792](https://github.com/angula
|
|||||||
* **compiler-cli:** add watch mode to `ngc` ([#18818](https://github.com/angular/angular/issues/18818)) ([06d01b2](https://github.com/angular/angular/commit/06d01b2))
|
* **compiler-cli:** add watch mode to `ngc` ([#18818](https://github.com/angular/angular/issues/18818)) ([06d01b2](https://github.com/angular/angular/commit/06d01b2))
|
||||||
* **compiler-cli:** lower metadata `useValue` and `data` literal fields ([#18905](https://github.com/angular/angular/issues/18905)) ([0e64261](https://github.com/angular/angular/commit/0e64261))
|
* **compiler-cli:** lower metadata `useValue` and `data` literal fields ([#18905](https://github.com/angular/angular/issues/18905)) ([0e64261](https://github.com/angular/angular/commit/0e64261))
|
||||||
* **compiler:** add representation of placeholders to xliff & xmb ([b3085e9](https://github.com/angular/angular/commit/b3085e9)), closes [#17345](https://github.com/angular/angular/issues/17345)
|
* **compiler:** add representation of placeholders to xliff & xmb ([b3085e9](https://github.com/angular/angular/commit/b3085e9)), closes [#17345](https://github.com/angular/angular/issues/17345)
|
||||||
|
* **compiler:** allow multiple exportAs names ([#18723](https://github.com/angular/angular/issues/18723)) ([7ec28fe](https://github.com/angular/angular/commit/7ec28fe))
|
||||||
* **compiler:** enabled strict checking of parameters to an `@Injectable` ([#19412](https://github.com/angular/angular/issues/19412)) ([dfb8d21](https://github.com/angular/angular/commit/dfb8d21))
|
* **compiler:** enabled strict checking of parameters to an `@Injectable` ([#19412](https://github.com/angular/angular/issues/19412)) ([dfb8d21](https://github.com/angular/angular/commit/dfb8d21))
|
||||||
* **compiler:** make `.ngsummary.json` files portable ([2572bf5](https://github.com/angular/angular/commit/2572bf5))
|
* **compiler:** make `.ngsummary.json` files portable ([2572bf5](https://github.com/angular/angular/commit/2572bf5))
|
||||||
* **compiler:** reuse the TypeScript typecheck for template typechecking. ([#19152](https://github.com/angular/angular/issues/19152)) ([996c7c2](https://github.com/angular/angular/commit/996c7c2))
|
* **compiler:** reuse the TypeScript typecheck for template typechecking. ([#19152](https://github.com/angular/angular/issues/19152)) ([996c7c2](https://github.com/angular/angular/commit/996c7c2))
|
||||||
* **compiler:** set `enableLegacyTemplate` to false by default ([#18756](https://github.com/angular/angular/issues/18756)) ([56238fe](https://github.com/angular/angular/commit/56238fe))
|
* **compiler:** set `enableLegacyTemplate` to false by default ([#18756](https://github.com/angular/angular/issues/18756)) ([56238fe](https://github.com/angular/angular/commit/56238fe))
|
||||||
* **compiler:** use typescript for resolving resource paths ([43226cb](https://github.com/angular/angular/commit/43226cb))
|
* **compiler:** use typescript for resolving resource paths ([43226cb](https://github.com/angular/angular/commit/43226cb))
|
||||||
* **core:** Create StaticInjector which does not depend on Reflect polyfill. ([d9d00bd](https://github.com/angular/angular/commit/d9d00bd))
|
* **core:** Create StaticInjector which does not depend on Reflect polyfill. ([d9d00bd](https://github.com/angular/angular/commit/d9d00bd))
|
||||||
|
* **core:** add option to remove blank text nodes from compiled templates ([#18823](https://github.com/angular/angular/issues/18823)) ([b8b551c](https://github.com/angular/angular/commit/b8b551c))
|
||||||
* **core:** support for bootstrap with custom zone ([#17672](https://github.com/angular/angular/issues/17672)) ([344a5ca](https://github.com/angular/angular/commit/344a5ca))
|
* **core:** support for bootstrap with custom zone ([#17672](https://github.com/angular/angular/issues/17672)) ([344a5ca](https://github.com/angular/angular/commit/344a5ca))
|
||||||
* **forms:** add default updateOn values for groups and arrays ([#18536](https://github.com/angular/angular/issues/18536)) ([ff5c58b](https://github.com/angular/angular/commit/ff5c58b))
|
* **forms:** add default updateOn values for groups and arrays ([#18536](https://github.com/angular/angular/issues/18536)) ([ff5c58b](https://github.com/angular/angular/commit/ff5c58b))
|
||||||
* **forms:** add options arg to abstract controls ([ebef5e6](https://github.com/angular/angular/commit/ebef5e6))
|
* **forms:** add options arg to abstract controls ([ebef5e6](https://github.com/angular/angular/commit/ebef5e6))
|
||||||
@ -4425,6 +4271,7 @@ Note: the 4.4.0 release on npm accidentally glitched-out midway, so we cut 4.4.1
|
|||||||
* **animations:** properly collect :enter nodes that exist within multi-level DOM trees ([40f77cb](https://github.com/angular/angular/commit/40f77cb)), closes [#17632](https://github.com/angular/angular/issues/17632)
|
* **animations:** properly collect :enter nodes that exist within multi-level DOM trees ([40f77cb](https://github.com/angular/angular/commit/40f77cb)), closes [#17632](https://github.com/angular/angular/issues/17632)
|
||||||
* **animations:** compute removal node height correctly ([185075d](https://github.com/angular/angular/commit/185075d))
|
* **animations:** compute removal node height correctly ([185075d](https://github.com/angular/angular/commit/185075d))
|
||||||
* **animations:** do not treat a `0` animation state as `void` ([451257a](https://github.com/angular/angular/commit/451257a))
|
* **animations:** do not treat a `0` animation state as `void` ([451257a](https://github.com/angular/angular/commit/451257a))
|
||||||
|
* **animations:** properly collect :enter nodes in a partially updated collection ([6ca4692](https://github.com/angular/angular/commit/6ca4692)), closes [#17440](https://github.com/angular/angular/issues/17440)
|
||||||
* **animations:** remove duplicate license header ([e096a85](https://github.com/angular/angular/commit/e096a85))
|
* **animations:** remove duplicate license header ([e096a85](https://github.com/angular/angular/commit/e096a85))
|
||||||
* **common/http:** document HttpClient, fixing a few other issues ([1855989](https://github.com/angular/angular/commit/1855989))
|
* **common/http:** document HttpClient, fixing a few other issues ([1855989](https://github.com/angular/angular/commit/1855989))
|
||||||
* **common/http:** don't guess Content-Type for FormData bodies ([#18104](https://github.com/angular/angular/issues/18104)) ([4f1e4ff](https://github.com/angular/angular/commit/4f1e4ff)), closes [#18096](https://github.com/angular/angular/issues/18096)
|
* **common/http:** don't guess Content-Type for FormData bodies ([#18104](https://github.com/angular/angular/issues/18104)) ([4f1e4ff](https://github.com/angular/angular/commit/4f1e4ff)), closes [#18096](https://github.com/angular/angular/issues/18096)
|
||||||
@ -4533,6 +4380,7 @@ Note: the 4.4.0 release on npm accidentally glitched-out midway, so we cut 4.4.1
|
|||||||
|
|
||||||
* **animations:** compute removal node height correctly ([185075d](https://github.com/angular/angular/commit/185075d))
|
* **animations:** compute removal node height correctly ([185075d](https://github.com/angular/angular/commit/185075d))
|
||||||
* **animations:** do not treat a `0` animation state as `void` ([451257a](https://github.com/angular/angular/commit/451257a))
|
* **animations:** do not treat a `0` animation state as `void` ([451257a](https://github.com/angular/angular/commit/451257a))
|
||||||
|
* **animations:** properly collect :enter nodes in a partially updated collection ([6ca4692](https://github.com/angular/angular/commit/6ca4692)), closes [#17440](https://github.com/angular/angular/issues/17440)
|
||||||
* **animations:** remove duplicate license header ([b192dd5](https://github.com/angular/angular/commit/b192dd5))
|
* **animations:** remove duplicate license header ([b192dd5](https://github.com/angular/angular/commit/b192dd5))
|
||||||
* **forms:** temp roll back breaking change with min/max directives ([b8c39cd](https://github.com/angular/angular/commit/b8c39cd)), closes [#17491](https://github.com/angular/angular/issues/17491)
|
* **forms:** temp roll back breaking change with min/max directives ([b8c39cd](https://github.com/angular/angular/commit/b8c39cd)), closes [#17491](https://github.com/angular/angular/issues/17491)
|
||||||
|
|
||||||
@ -4768,6 +4616,7 @@ Note: the 4.4.0 release on npm accidentally glitched-out midway, so we cut 4.4.1
|
|||||||
* **benchpress:** Update types for TypeScript nullability support ([14669f2](https://github.com/angular/angular/commit/14669f2))
|
* **benchpress:** Update types for TypeScript nullability support ([14669f2](https://github.com/angular/angular/commit/14669f2))
|
||||||
* **common:** Update types for TypeScript nullability support ([d8b73e4](https://github.com/angular/angular/commit/d8b73e4))
|
* **common:** Update types for TypeScript nullability support ([d8b73e4](https://github.com/angular/angular/commit/d8b73e4))
|
||||||
* **compiler:** fix build error in xliff2 ([bd704c9](https://github.com/angular/angular/commit/bd704c9))
|
* **compiler:** fix build error in xliff2 ([bd704c9](https://github.com/angular/angular/commit/bd704c9))
|
||||||
|
* **compiler:** fix inheritance for AOT with summaries ([#15583](https://github.com/angular/angular/issues/15583)) ([8ef621a](https://github.com/angular/angular/commit/8ef621a))
|
||||||
* **compiler:** ignore calls to unresolved symbols in metadata ([38a7e0d](https://github.com/angular/angular/commit/38a7e0d)), closes [#15969](https://github.com/angular/angular/issues/15969)
|
* **compiler:** ignore calls to unresolved symbols in metadata ([38a7e0d](https://github.com/angular/angular/commit/38a7e0d)), closes [#15969](https://github.com/angular/angular/issues/15969)
|
||||||
* **compiler:** ignore calls to unresolved symbols in metadata ([#15970](https://github.com/angular/angular/issues/15970)) ([ce47d33](https://github.com/angular/angular/commit/ce47d33)), closes [#15969](https://github.com/angular/angular/issues/15969)
|
* **compiler:** ignore calls to unresolved symbols in metadata ([#15970](https://github.com/angular/angular/issues/15970)) ([ce47d33](https://github.com/angular/angular/commit/ce47d33)), closes [#15969](https://github.com/angular/angular/issues/15969)
|
||||||
* **compiler:** Inform user where Quoted error was thrown ([a77b126](https://github.com/angular/angular/commit/a77b126))
|
* **compiler:** Inform user where Quoted error was thrown ([a77b126](https://github.com/angular/angular/commit/a77b126))
|
||||||
@ -4784,8 +4633,10 @@ Note: the 4.4.0 release on npm accidentally glitched-out midway, so we cut 4.4.1
|
|||||||
* **http:** Update types for TypeScript nullability support ([c36ec9b](https://github.com/angular/angular/commit/c36ec9b))
|
* **http:** Update types for TypeScript nullability support ([c36ec9b](https://github.com/angular/angular/commit/c36ec9b))
|
||||||
* **http:** Update types for TypeScript nullability support ([ec028b8](https://github.com/angular/angular/commit/ec028b8))
|
* **http:** Update types for TypeScript nullability support ([ec028b8](https://github.com/angular/angular/commit/ec028b8))
|
||||||
* **language-service:** avoid throwing exceptions when reporting metadata errors ([7764c5c](https://github.com/angular/angular/commit/7764c5c))
|
* **language-service:** avoid throwing exceptions when reporting metadata errors ([7764c5c](https://github.com/angular/angular/commit/7764c5c))
|
||||||
|
* **language-service:** detect when there isn't a tsconfig.json ([258d539](https://github.com/angular/angular/commit/258d539)), closes [#15874](https://github.com/angular/angular/issues/15874)
|
||||||
* **language-service:** improve resilience to incomplete information ([71a8627](https://github.com/angular/angular/commit/71a8627))
|
* **language-service:** improve resilience to incomplete information ([71a8627](https://github.com/angular/angular/commit/71a8627))
|
||||||
* **language-service:** infer correct type of `?.` expressions ([0a3a9af](https://github.com/angular/angular/commit/0a3a9af)), closes [#15885](https://github.com/angular/angular/issues/15885)
|
* **language-service:** infer correct type of `?.` expressions ([0a3a9af](https://github.com/angular/angular/commit/0a3a9af)), closes [#15885](https://github.com/angular/angular/issues/15885)
|
||||||
|
* **language-service:** initialize static reflector correctly ([fe0d02f](https://github.com/angular/angular/commit/fe0d02f)), closes [#15768](https://github.com/angular/angular/issues/15768)
|
||||||
* **language-service:** look for type constructors on canonical symbol ([2ddf3bc](https://github.com/angular/angular/commit/2ddf3bc))
|
* **language-service:** look for type constructors on canonical symbol ([2ddf3bc](https://github.com/angular/angular/commit/2ddf3bc))
|
||||||
* **language-service:** only use canonical symbols ([5a88d2f](https://github.com/angular/angular/commit/5a88d2f))
|
* **language-service:** only use canonical symbols ([5a88d2f](https://github.com/angular/angular/commit/5a88d2f))
|
||||||
* **language-service:** parse extended i18n forms ([bde9771](https://github.com/angular/angular/commit/bde9771))
|
* **language-service:** parse extended i18n forms ([bde9771](https://github.com/angular/angular/commit/bde9771))
|
||||||
@ -4810,6 +4661,7 @@ Note: the 4.4.0 release on npm accidentally glitched-out midway, so we cut 4.4.1
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
* **animations:** Update types for TypeScript nullability support ([38d75d4](https://github.com/angular/angular/commit/38d75d4)), closes [#15870](https://github.com/angular/angular/issues/15870)
|
||||||
* **compiler:** add source files to xmb/xliff translations ([#14705](https://github.com/angular/angular/issues/14705)) ([4054055](https://github.com/angular/angular/commit/4054055)), closes [#14190](https://github.com/angular/angular/issues/14190)
|
* **compiler:** add source files to xmb/xliff translations ([#14705](https://github.com/angular/angular/issues/14705)) ([4054055](https://github.com/angular/angular/commit/4054055)), closes [#14190](https://github.com/angular/angular/issues/14190)
|
||||||
* **compiler:** Implement i18n XLIFF 2.0 serializer ([#14185](https://github.com/angular/angular/issues/14185)) ([09c4cb2](https://github.com/angular/angular/commit/09c4cb2)), closes [#11735](https://github.com/angular/angular/issues/11735)
|
* **compiler:** Implement i18n XLIFF 2.0 serializer ([#14185](https://github.com/angular/angular/issues/14185)) ([09c4cb2](https://github.com/angular/angular/commit/09c4cb2)), closes [#11735](https://github.com/angular/angular/issues/11735)
|
||||||
* **upgrade:** allow setting the angularjs lib at runtime ([#15168](https://github.com/angular/angular/issues/15168)) ([e927aea](https://github.com/angular/angular/commit/e927aea))
|
* **upgrade:** allow setting the angularjs lib at runtime ([#15168](https://github.com/angular/angular/issues/15168)) ([e927aea](https://github.com/angular/angular/commit/e927aea))
|
||||||
@ -5547,18 +5399,27 @@ returned value being an array.
|
|||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **animations:** fix internal jscompiler issue and AOT quoting ([#13798](https://github.com/angular/angular/issues/13798)) ([c2aa981](https://github.com/angular/angular/commit/c2aa981))
|
||||||
|
* **common:** support numeric value as discrete cases for NgPlural ([#13876](https://github.com/angular/angular/issues/13876)) ([f364557](https://github.com/angular/angular/commit/f364557))
|
||||||
* **compiler:** [i18n] XMB/XTB placeholder names can contain only A-Z, 0-9, _n ([d02eab4](https://github.com/angular/angular/commit/d02eab4))
|
* **compiler:** [i18n] XMB/XTB placeholder names can contain only A-Z, 0-9, _n ([d02eab4](https://github.com/angular/angular/commit/d02eab4))
|
||||||
* **compiler:** fix regexp to support firefox 31 ([#14082](https://github.com/angular/angular/issues/14082)) ([b2f9d56](https://github.com/angular/angular/commit/b2f9d56)), closes [#14029](https://github.com/angular/angular/issues/14029) [#13900](https://github.com/angular/angular/issues/13900)
|
* **compiler:** fix regexp to support firefox 31 ([#14082](https://github.com/angular/angular/issues/14082)) ([b2f9d56](https://github.com/angular/angular/commit/b2f9d56)), closes [#14029](https://github.com/angular/angular/issues/14029) [#13900](https://github.com/angular/angular/issues/13900)
|
||||||
* **core:** export animation classes required for Renderer impl ([#14002](https://github.com/angular/angular/issues/14002)) ([83361d8](https://github.com/angular/angular/commit/83361d8)), closes [#14001](https://github.com/angular/angular/issues/14001)
|
* **core:** export animation classes required for Renderer impl ([#14002](https://github.com/angular/angular/issues/14002)) ([83361d8](https://github.com/angular/angular/commit/83361d8)), closes [#14001](https://github.com/angular/angular/issues/14001)
|
||||||
* **core:** fix not declared variable in view engine ([#14045](https://github.com/angular/angular/issues/14045)) ([d3a3a8e](https://github.com/angular/angular/commit/d3a3a8e))
|
* **core:** fix not declared variable in view engine ([#14045](https://github.com/angular/angular/issues/14045)) ([d3a3a8e](https://github.com/angular/angular/commit/d3a3a8e))
|
||||||
|
* **http:** don't create a blob out of ArrayBuffer when type is application/octet-stream ([#13992](https://github.com/angular/angular/issues/13992)) ([1200cf2](https://github.com/angular/angular/commit/1200cf2)), closes [#13973](https://github.com/angular/angular/issues/13973)
|
||||||
|
* **router:** enable loadChildren with function in aot ([#13909](https://github.com/angular/angular/issues/13909)) ([635bf02](https://github.com/angular/angular/commit/635bf02)), closes [#11075](https://github.com/angular/angular/issues/11075)
|
||||||
|
* **router:** routerLinkActive should not throw when not initialized ([#13273](https://github.com/angular/angular/issues/13273)) ([e8ea741](https://github.com/angular/angular/commit/e8ea741)), closes [#13270](https://github.com/angular/angular/issues/13270)
|
||||||
|
* **upgrade:** detect async downgrade component changes ([#13812](https://github.com/angular/angular/issues/13812)) ([d6382bf](https://github.com/angular/angular/commit/d6382bf)), closes [#6385](https://github.com/angular/angular/issues/6385) [#6385](https://github.com/angular/angular/issues/6385) [#10660](https://github.com/angular/angular/issues/10660) [#12318](https://github.com/angular/angular/issues/12318) [#12034](https://github.com/angular/angular/issues/12034)
|
||||||
* **upgrade/static:** ensure upgraded injector is initialized early enough ([#14065](https://github.com/angular/angular/issues/14065)) ([6152eb2](https://github.com/angular/angular/commit/6152eb2)), closes [#13811](https://github.com/angular/angular/issues/13811)
|
* **upgrade/static:** ensure upgraded injector is initialized early enough ([#14065](https://github.com/angular/angular/issues/14065)) ([6152eb2](https://github.com/angular/angular/commit/6152eb2)), closes [#13811](https://github.com/angular/angular/issues/13811)
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
* **build:** optionally build an ES2015 distro ([#13471](https://github.com/angular/angular/issues/13471)) ([be6c95a](https://github.com/angular/angular/commit/be6c95a))
|
||||||
* **core:** add event support to view engine ([0adb97b](https://github.com/angular/angular/commit/0adb97b))
|
* **core:** add event support to view engine ([0adb97b](https://github.com/angular/angular/commit/0adb97b))
|
||||||
* **core:** add initial view engine ([#14014](https://github.com/angular/angular/issues/14014)) ([2f87eb5](https://github.com/angular/angular/commit/2f87eb5))
|
* **core:** add initial view engine ([#14014](https://github.com/angular/angular/issues/14014)) ([2f87eb5](https://github.com/angular/angular/commit/2f87eb5))
|
||||||
* **core:** add pure expression support to view engine ([6541737](https://github.com/angular/angular/commit/6541737))
|
* **core:** add pure expression support to view engine ([6541737](https://github.com/angular/angular/commit/6541737))
|
||||||
|
* **core:** Add type information to injector.get() ([#13785](https://github.com/angular/angular/issues/13785)) ([d169c24](https://github.com/angular/angular/commit/d169c24))
|
||||||
|
* **security:** allow calc and gradient functions. ([#13943](https://github.com/angular/angular/issues/13943)) ([e19bf70](https://github.com/angular/angular/commit/e19bf70))
|
||||||
* **tsc-wrapped:** Support of vinyl like config file was added ([#13987](https://github.com/angular/angular/issues/13987)) ([0c7726d](https://github.com/angular/angular/commit/0c7726d))
|
* **tsc-wrapped:** Support of vinyl like config file was added ([#13987](https://github.com/angular/angular/issues/13987)) ([0c7726d](https://github.com/angular/angular/commit/0c7726d))
|
||||||
* **upgrade:** Support ng-model in downgraded components ([#10578](https://github.com/angular/angular/issues/10578)) ([e21e9c5](https://github.com/angular/angular/commit/e21e9c5))
|
* **upgrade:** Support ng-model in downgraded components ([#10578](https://github.com/angular/angular/issues/10578)) ([e21e9c5](https://github.com/angular/angular/commit/e21e9c5))
|
||||||
|
|
||||||
@ -6086,12 +5947,19 @@ Note: The 2.3.0-beta.0 release also contains all the changes present in the 2.2.
|
|||||||
|
|
||||||
### Features (summary of all features from 2.2.0-beta.0 - 2.2.0-rc.0 releases)
|
### Features (summary of all features from 2.2.0-beta.0 - 2.2.0-rc.0 releases)
|
||||||
|
|
||||||
|
* **common:** support narrow forms for month and weekdays in DatePipe ([#12297](https://github.com/angular/angular/issues/12297)) ([f77ab6a](https://github.com/angular/angular/commit/f77ab6a)), closes [#12294](https://github.com/angular/angular/issues/12294)
|
||||||
* **core:** map 'for' attribute to 'htmlFor' property ([#10546](https://github.com/angular/angular/issues/10546)) ([634b3bb](https://github.com/angular/angular/commit/634b3bb)), closes [#7516](https://github.com/angular/angular/issues/7516)
|
* **core:** map 'for' attribute to 'htmlFor' property ([#10546](https://github.com/angular/angular/issues/10546)) ([634b3bb](https://github.com/angular/angular/commit/634b3bb)), closes [#7516](https://github.com/angular/angular/issues/7516)
|
||||||
* **core:** add the find method to QueryList ([7c16ef9](https://github.com/angular/angular/commit/7c16ef9))
|
* **core:** add the find method to QueryList ([7c16ef9](https://github.com/angular/angular/commit/7c16ef9))
|
||||||
|
* **forms:** add hasError and getError to AbstractControlDirective ([#11985](https://github.com/angular/angular/issues/11985)) ([592f40a](https://github.com/angular/angular/commit/592f40a)), closes [#7255](https://github.com/angular/angular/issues/7255)
|
||||||
|
* **forms:** add ng-pending CSS class during async validation ([#11243](https://github.com/angular/angular/issues/11243)) ([97bc971](https://github.com/angular/angular/commit/97bc971)), closes [#10336](https://github.com/angular/angular/issues/10336)
|
||||||
* **forms:** add emitEvent to AbstractControl methods ([#11949](https://github.com/angular/angular/issues/11949)) ([b9fc090](https://github.com/angular/angular/commit/b9fc090))
|
* **forms:** add emitEvent to AbstractControl methods ([#11949](https://github.com/angular/angular/issues/11949)) ([b9fc090](https://github.com/angular/angular/commit/b9fc090))
|
||||||
|
* **forms:** make 'parent' a public property of 'AbstractControl' ([#11855](https://github.com/angular/angular/issues/11855)) ([445e592](https://github.com/angular/angular/commit/445e592))
|
||||||
|
* **forms:** Validator.pattern accepts a RegExp ([#12323](https://github.com/angular/angular/issues/12323)) ([bf60418](https://github.com/angular/angular/commit/bf60418))
|
||||||
* **router:** add a provider making angular1/angular2 integration easier ([#12769](https://github.com/angular/angular/issues/12769)) ([6e35d13](https://github.com/angular/angular/commit/6e35d13))
|
* **router:** add a provider making angular1/angular2 integration easier ([#12769](https://github.com/angular/angular/issues/12769)) ([6e35d13](https://github.com/angular/angular/commit/6e35d13))
|
||||||
* **router:** add support for custom url matchers ([7340735](https://github.com/angular/angular/commit/7340735)), closes [#12442](https://github.com/angular/angular/issues/12442) [#12772](https://github.com/angular/angular/issues/12772)
|
* **router:** add support for custom url matchers ([7340735](https://github.com/angular/angular/commit/7340735)), closes [#12442](https://github.com/angular/angular/issues/12442) [#12772](https://github.com/angular/angular/issues/12772)
|
||||||
* **router:** export routerLinkActive w/ isActive property ([c9f58cf](https://github.com/angular/angular/commit/c9f58cf))
|
* **router:** export routerLinkActive w/ isActive property ([c9f58cf](https://github.com/angular/angular/commit/c9f58cf))
|
||||||
|
* **router:** add support for ng1/ng2 migration ([#12160](https://github.com/angular/angular/issues/12160)) ([8b9ab44](https://github.com/angular/angular/commit/8b9ab44))
|
||||||
|
* **upgrade:** add support for AoT compiled upgrade applications ([d6791ff](https://github.com/angular/angular/commit/d6791ff)), closes [#12239](https://github.com/angular/angular/issues/12239)
|
||||||
* **upgrade:** add support for `require` in UpgradeComponent ([fe1d0e2](https://github.com/angular/angular/commit/fe1d0e2))
|
* **upgrade:** add support for `require` in UpgradeComponent ([fe1d0e2](https://github.com/angular/angular/commit/fe1d0e2))
|
||||||
* **upgrade:** add/improve support for lifecycle hooks in UpgradeComponent ([469010e](https://github.com/angular/angular/commit/469010e))
|
* **upgrade:** add/improve support for lifecycle hooks in UpgradeComponent ([469010e](https://github.com/angular/angular/commit/469010e))
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
|||||||
Adherence to these conventions is necessary because release notes are automatically generated from these messages.
|
Adherence to these conventions is necessary because release notes are automatically generated from these messages.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git commit --all
|
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.
|
||||||
|
|
||||||
@ -119,31 +119,16 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
|||||||
|
|
||||||
11. In GitHub, send a pull request to `angular:master`.
|
11. In GitHub, send a pull request to `angular:master`.
|
||||||
|
|
||||||
|
If we ask for changes via code reviews then:
|
||||||
|
|
||||||
#### Addressing review feedback
|
* 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):
|
||||||
|
|
||||||
If we ask for changes via code reviews then:
|
```shell
|
||||||
|
git rebase master -i
|
||||||
1. Make the required updates to the code.
|
git push -f
|
||||||
|
```
|
||||||
2. Re-run the Angular test suites to ensure tests are still passing.
|
|
||||||
|
|
||||||
3. Create a fixup commit and push to your GitHub repository (this will update your Pull Request):
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git commit --all --fixup HEAD
|
|
||||||
git push
|
|
||||||
```
|
|
||||||
|
|
||||||
For more info on working with fixup commits see [here](docs/FIXUP_COMMITS.md).
|
|
||||||
|
|
||||||
> Fixup commits (as shown above) are preferred when addressing review feedback, but in some cases you may need to amend the original commit instead of creating a fixup commit (for example, if you want to update the commit message).
|
|
||||||
> To amend the last commit and update the Pull Request:
|
|
||||||
>
|
|
||||||
> ```shell
|
|
||||||
> git commit --all --amend
|
|
||||||
> git push --force-with-lease
|
|
||||||
> ```
|
|
||||||
|
|
||||||
That's it! Thank you for your contribution!
|
That's it! Thank you for your contribution!
|
||||||
|
|
||||||
@ -245,6 +230,7 @@ Must be one of the following:
|
|||||||
* **fix**: A bug fix
|
* **fix**: A bug fix
|
||||||
* **perf**: A code change that improves performance
|
* **perf**: A code change that improves performance
|
||||||
* **refactor**: A code change that neither fixes a bug nor adds a feature
|
* **refactor**: A code change that neither fixes a bug nor adds a feature
|
||||||
|
* **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
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,8 +91,8 @@ rbe_autoconfig(
|
|||||||
# Need to specify a base container digest in order to ensure that we can use the checked-in
|
# Need to specify a base container digest in order to ensure that we can use the checked-in
|
||||||
# platform configurations for the "ubuntu16_04" image. Otherwise the autoconfig rule would
|
# platform configurations for the "ubuntu16_04" image. Otherwise the autoconfig rule would
|
||||||
# need to pull the image and run it in order determine the toolchain configuration. See:
|
# need to pull the image and run it in order determine the toolchain configuration. See:
|
||||||
# https://github.com/bazelbuild/bazel-toolchains/blob/3.5.1/configs/ubuntu16_04_clang/versions.bzl
|
# https://github.com/bazelbuild/bazel-toolchains/blob/3.2.0/configs/ubuntu16_04_clang/versions.bzl
|
||||||
base_container_digest = "sha256:f6568d8168b14aafd1b707019927a63c2d37113a03bcee188218f99bd0327ea1",
|
base_container_digest = "sha256:5e750dd878df9fcf4e185c6f52b9826090f6e532b097f286913a428290622332",
|
||||||
# Note that if you change the `digest`, you might also need to update the
|
# Note that if you change the `digest`, you might also need to update the
|
||||||
# `base_container_digest` to make sure marketplace.gcr.io/google/rbe-ubuntu16-04-webtest:<digest>
|
# `base_container_digest` to make sure marketplace.gcr.io/google/rbe-ubuntu16-04-webtest:<digest>
|
||||||
# and marketplace.gcr.io/google/rbe-ubuntu16-04:<base_container_digest> have
|
# and marketplace.gcr.io/google/rbe-ubuntu16-04:<base_container_digest> have
|
||||||
|
@ -6,7 +6,6 @@ Everything in this folder is part of the documentation project. This includes
|
|||||||
* the dgeni configuration for converting source files to rendered files that can be viewed in the web site.
|
* the dgeni configuration for converting source files to rendered files that can be viewed in the web site.
|
||||||
* the tooling for setting up examples for development; and generating live-example and zip files from the examples.
|
* the tooling for setting up examples for development; and generating live-example and zip files from the examples.
|
||||||
|
|
||||||
<a name="developer-tasks"></a>
|
|
||||||
## Developer tasks
|
## Developer tasks
|
||||||
|
|
||||||
We use [Yarn](https://yarnpkg.com) to manage the dependencies and to run build tasks.
|
We use [Yarn](https://yarnpkg.com) to manage the dependencies and to run build tasks.
|
||||||
|
@ -16,6 +16,13 @@ import {BuildNums, PrNums, SHA} from './constants';
|
|||||||
|
|
||||||
const logger = new Logger('mock-external-apis');
|
const logger = new Logger('mock-external-apis');
|
||||||
|
|
||||||
|
const log = (...args: any[]) => {
|
||||||
|
// Filter out non-matching URL checks
|
||||||
|
if (!/^matching.+: false$/.test(args[0])) {
|
||||||
|
logger.log(...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const AIO_CIRCLE_CI_TOKEN = getEnvVar('AIO_CIRCLE_CI_TOKEN');
|
const AIO_CIRCLE_CI_TOKEN = getEnvVar('AIO_CIRCLE_CI_TOKEN');
|
||||||
const AIO_GITHUB_TOKEN = getEnvVar('AIO_GITHUB_TOKEN');
|
const AIO_GITHUB_TOKEN = getEnvVar('AIO_GITHUB_TOKEN');
|
||||||
|
|
||||||
@ -84,8 +91,8 @@ const createArchive = (buildNum: number, prNum: number, sha: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create request scopes
|
// Create request scopes
|
||||||
const circleCiApi = nock(CIRCLE_CI_API_HOST).persist();
|
const circleCiApi = nock(CIRCLE_CI_API_HOST).log(log).persist();
|
||||||
const githubApi = nock(GITHUB_API_HOST).persist().matchHeader('Authorization', `token ${AIO_GITHUB_TOKEN}`);
|
const githubApi = nock(GITHUB_API_HOST).log(log).persist().matchHeader('Authorization', `token ${AIO_GITHUB_TOKEN}`);
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
|
@ -27,28 +27,28 @@
|
|||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"delete-empty": "^3.0.0",
|
"delete-empty": "^3.0.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"jasmine": "^3.6.1",
|
"jasmine": "^3.5.0",
|
||||||
"nock": "^13.0.4",
|
"nock": "^12.0.3",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.0",
|
||||||
"shelljs": "^0.8.4",
|
"shelljs": "^0.8.4",
|
||||||
"source-map-support": "^0.5.19",
|
"source-map-support": "^0.5.19",
|
||||||
"tar-stream": "^2.1.3",
|
"tar-stream": "^2.1.2",
|
||||||
"tslib": "^2.0.1"
|
"tslib": "^1.11.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/body-parser": "^1.19.0",
|
"@types/body-parser": "^1.19.0",
|
||||||
"@types/express": "^4.17.8",
|
"@types/express": "^4.17.6",
|
||||||
"@types/jasmine": "^3.5.14",
|
"@types/jasmine": "^3.5.10",
|
||||||
"@types/nock": "^11.1.0",
|
"@types/nock": "^11.1.0",
|
||||||
"@types/node": "^14.6.4",
|
"@types/node": "^13.13.2",
|
||||||
"@types/node-fetch": "^2.5.7",
|
"@types/node-fetch": "^2.5.7",
|
||||||
"@types/shelljs": "^0.8.8",
|
"@types/shelljs": "^0.8.7",
|
||||||
"@types/supertest": "^2.0.10",
|
"@types/supertest": "^2.0.8",
|
||||||
"nodemon": "^2.0.4",
|
"nodemon": "^2.0.3",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"supertest": "^4.0.2",
|
"supertest": "^4.0.2",
|
||||||
"tslint": "^6.1.3",
|
"tslint": "^6.1.1",
|
||||||
"tslint-jasmine-noSkipOrFocus": "^1.0.9",
|
"tslint-jasmine-noSkipOrFocus": "^1.0.9",
|
||||||
"typescript": "^4.0.2"
|
"typescript": "^3.8.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,24 +214,23 @@ describe('GithubApi', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should call \'https.request()\' with the correct options', async () => {
|
it('should call \'https.request()\' with the correct options', () => {
|
||||||
const requestHandler = nock('https://api.github.com')
|
const requestHandler = nock('https://api.github.com')
|
||||||
.intercept('/path', 'method')
|
.intercept('/path', 'method')
|
||||||
.reply(200);
|
.reply(200);
|
||||||
|
|
||||||
await (api as any).request('method', '/path');
|
(api as any).request('method', '/path');
|
||||||
requestHandler.done();
|
requestHandler.done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should add the \'Authorization\' header containing the \'githubToken\'', async () => {
|
it('should add the \'Authorization\' header containing the \'githubToken\'', () => {
|
||||||
const requestHandler = nock('https://api.github.com')
|
const requestHandler = nock('https://api.github.com')
|
||||||
.intercept('/path', 'method', undefined, {
|
.intercept('/path', 'method', undefined, {
|
||||||
reqheaders: {Authorization: 'token 12345'},
|
reqheaders: {Authorization: 'token 12345'},
|
||||||
})
|
})
|
||||||
.reply(200);
|
.reply(200);
|
||||||
|
(api as any).request('method', '/path');
|
||||||
await (api as any).request('method', '/path');
|
|
||||||
requestHandler.done();
|
requestHandler.done();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -245,13 +244,12 @@ describe('GithubApi', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should \'JSON.stringify\' and send the data along with the request', async () => {
|
it('should \'JSON.stringify\' and send the data along with the request', () => {
|
||||||
const data = {key: 'value'};
|
const data = {key: 'value'};
|
||||||
const requestHandler = nock('https://api.github.com')
|
const requestHandler = nock('https://api.github.com')
|
||||||
.intercept('/path', 'method', JSON.stringify(data))
|
.intercept('/path', 'method', JSON.stringify(data))
|
||||||
.reply(200);
|
.reply(200);
|
||||||
|
(api as any).request('method', '/path', data);
|
||||||
await (api as any).request('method', '/path', data);
|
|
||||||
requestHandler.done();
|
requestHandler.done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -22,7 +22,7 @@ you don't need to specify values for those.
|
|||||||
The domain name of the server.
|
The domain name of the server.
|
||||||
|
|
||||||
- `AIO_GITHUB_ORGANIZATION`:
|
- `AIO_GITHUB_ORGANIZATION`:
|
||||||
The GitHub organization whose teams are trusted for accepting build artifacts.
|
The GitHub organization whose teams are whitelisted for accepting build artifacts.
|
||||||
See also `AIO_GITHUB_TEAM_SLUGS`.
|
See also `AIO_GITHUB_TEAM_SLUGS`.
|
||||||
|
|
||||||
- `AIO_GITHUB_REPO`:
|
- `AIO_GITHUB_REPO`:
|
||||||
|
@ -98,7 +98,7 @@ This section describes how each of the aforementioned sub-tasks is accomplished:
|
|||||||
Such a label can only have been added by a maintainer (with the necessary rights) and
|
Such a label can only have been added by a maintainer (with the necessary rights) and
|
||||||
designates that they have manually verified the PR contents.
|
designates that they have manually verified the PR contents.
|
||||||
2. We can verify (again using the GitHub API) the author's membership in one of the
|
2. We can verify (again using the GitHub API) the author's membership in one of the
|
||||||
trusted GitHub teams. For this operation, we need a Personal Access Token with the
|
whitelisted/trusted GitHub teams. For this operation, we need a Personal Access Token with the
|
||||||
`read:org` scope issued by a user that can "see" the specified GitHub organization.
|
`read:org` scope issued by a user that can "see" the specified GitHub organization.
|
||||||
Here too, we use the token by @mary-poppins.
|
Here too, we use the token by @mary-poppins.
|
||||||
|
|
||||||
|
2
aio/content/examples/.gitignore
vendored
2
aio/content/examples/.gitignore
vendored
@ -17,7 +17,6 @@
|
|||||||
**/e2e/tsconfig.e2e.json
|
**/e2e/tsconfig.e2e.json
|
||||||
**/src/karma.conf.js
|
**/src/karma.conf.js
|
||||||
**/.angular-cli.json
|
**/.angular-cli.json
|
||||||
**/.browserslistrc
|
|
||||||
**/.editorconfig
|
**/.editorconfig
|
||||||
**/.gitignore
|
**/.gitignore
|
||||||
**/angular.json
|
**/angular.json
|
||||||
@ -31,6 +30,7 @@
|
|||||||
**/tslint.json
|
**/tslint.json
|
||||||
**/karma-test-shim.js
|
**/karma-test-shim.js
|
||||||
**/browser-test-shim.js
|
**/browser-test-shim.js
|
||||||
|
**/browserslist
|
||||||
**/node_modules
|
**/node_modules
|
||||||
|
|
||||||
# built files
|
# built files
|
||||||
|
@ -21,13 +21,11 @@ import { ItemDirective } from './item.directive';
|
|||||||
ItemDirective
|
ItemDirective
|
||||||
],
|
],
|
||||||
// #enddocregion declarations
|
// #enddocregion declarations
|
||||||
// #docregion imports
|
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
HttpClientModule
|
HttpClientModule
|
||||||
],
|
],
|
||||||
// #enddocregion imports
|
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
import { browser, by, element } from 'protractor';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Component Communication Cookbook Tests', () => {
|
describe('Component Communication Cookbook Tests', () => {
|
||||||
|
|
||||||
beforeEach(() => browser.get(browser.baseUrl));
|
// Note: '?e2e' which app can read to know it is running in protractor
|
||||||
|
// e.g. `if (!/e2e/.test(location.search)) { ...`
|
||||||
|
beforeAll(() => {
|
||||||
|
browser.get('?e2e');
|
||||||
|
});
|
||||||
|
|
||||||
describe('Parent-to-child communication', () => {
|
describe('Parent-to-child communication', () => {
|
||||||
// #docregion parent-to-child
|
// #docregion parent-to-child
|
||||||
@ -11,7 +15,7 @@ describe('Component Communication Cookbook Tests', () => {
|
|||||||
const masterName = 'Master';
|
const masterName = 'Master';
|
||||||
|
|
||||||
it('should pass properties to children properly', () => {
|
it('should pass properties to children properly', () => {
|
||||||
const parent = element(by.tagName('app-hero-parent'));
|
const parent = element.all(by.tagName('app-hero-parent')).get(0);
|
||||||
const 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++) {
|
||||||
@ -31,7 +35,7 @@ describe('Component Communication Cookbook Tests', () => {
|
|||||||
it('should display trimmed, non-empty names', () => {
|
it('should display trimmed, non-empty names', () => {
|
||||||
const nonEmptyNameIndex = 0;
|
const nonEmptyNameIndex = 0;
|
||||||
const nonEmptyName = '"Dr IQ"';
|
const nonEmptyName = '"Dr IQ"';
|
||||||
const parent = element(by.tagName('app-name-parent'));
|
const parent = element.all(by.tagName('app-name-parent')).get(0);
|
||||||
const hero = parent.all(by.tagName('app-name-child')).get(nonEmptyNameIndex);
|
const hero = parent.all(by.tagName('app-name-child')).get(nonEmptyNameIndex);
|
||||||
|
|
||||||
const displayName = hero.element(by.tagName('h3')).getText();
|
const displayName = hero.element(by.tagName('h3')).getText();
|
||||||
@ -41,7 +45,7 @@ describe('Component Communication Cookbook Tests', () => {
|
|||||||
it('should replace empty name with default name', () => {
|
it('should replace empty name with default name', () => {
|
||||||
const emptyNameIndex = 1;
|
const emptyNameIndex = 1;
|
||||||
const defaultName = '"<no name set>"';
|
const defaultName = '"<no name set>"';
|
||||||
const parent = element(by.tagName('app-name-parent'));
|
const parent = element.all(by.tagName('app-name-parent')).get(0);
|
||||||
const hero = parent.all(by.tagName('app-name-child')).get(emptyNameIndex);
|
const hero = parent.all(by.tagName('app-name-child')).get(emptyNameIndex);
|
||||||
|
|
||||||
const displayName = hero.element(by.tagName('h3')).getText();
|
const displayName = hero.element(by.tagName('h3')).getText();
|
||||||
@ -66,36 +70,38 @@ describe('Component Communication Cookbook Tests', () => {
|
|||||||
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', async () => {
|
it('should set expected values after clicking \'Minor\' twice', () => {
|
||||||
const repoTag = element(by.tagName('app-version-parent'));
|
const repoTag = element(by.tagName('app-version-parent'));
|
||||||
const newMinorButton = repoTag.all(by.tagName('button')).get(0);
|
const newMinorButton = repoTag.all(by.tagName('button')).get(0);
|
||||||
|
|
||||||
await newMinorButton.click();
|
newMinorButton.click().then(() => {
|
||||||
await newMinorButton.click();
|
newMinorButton.click().then(() => {
|
||||||
|
const actual = getActual();
|
||||||
|
|
||||||
const actual = getActual();
|
const labelAfter2Minor = 'Version 1.25';
|
||||||
|
const logAfter2Minor = 'minor changed from 24 to 25';
|
||||||
|
|
||||||
const labelAfter2Minor = 'Version 1.25';
|
expect(actual.label).toBe(labelAfter2Minor);
|
||||||
const logAfter2Minor = 'minor changed from 24 to 25';
|
expect(actual.count).toBe(3);
|
||||||
|
expect(actual.logs.get(2).getText()).toBe(logAfter2Minor);
|
||||||
expect(actual.label).toBe(labelAfter2Minor);
|
});
|
||||||
expect(actual.count).toBe(3);
|
});
|
||||||
expect(actual.logs.get(2).getText()).toBe(logAfter2Minor);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set expected values after clicking \'Major\' once', async () => {
|
it('should set expected values after clicking \'Major\' once', () => {
|
||||||
const repoTag = element(by.tagName('app-version-parent'));
|
const repoTag = element(by.tagName('app-version-parent'));
|
||||||
const newMajorButton = repoTag.all(by.tagName('button')).get(1);
|
const newMajorButton = repoTag.all(by.tagName('button')).get(1);
|
||||||
|
|
||||||
await newMajorButton.click();
|
newMajorButton.click().then(() => {
|
||||||
const actual = getActual();
|
const actual = getActual();
|
||||||
|
|
||||||
const labelAfterMajor = 'Version 2.0';
|
const labelAfterMajor = 'Version 2.0';
|
||||||
const logAfterMajor = 'major changed from 1 to 2, minor changed from 23 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(2);
|
expect(actual.count).toBe(4);
|
||||||
expect(actual.logs.get(1).getText()).toBe(logAfterMajor);
|
expect(actual.logs.get(3).getText()).toBe(logAfterMajor);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function getActual() {
|
function getActual() {
|
||||||
@ -112,125 +118,110 @@ describe('Component Communication Cookbook Tests', () => {
|
|||||||
}
|
}
|
||||||
// ...
|
// ...
|
||||||
// #enddocregion parent-to-child-onchanges
|
// #enddocregion parent-to-child-onchanges
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Child-to-parent communication', () => {
|
describe('Child-to-parent communication', () => {
|
||||||
// #docregion child-to-parent
|
// #docregion child-to-parent
|
||||||
// ...
|
// ...
|
||||||
it('should not emit the event initially', () => {
|
it('should not emit the event initially', () => {
|
||||||
const voteLabel = element(by.tagName('app-vote-taker')).element(by.tagName('h3'));
|
const voteLabel = element(by.tagName('app-vote-taker'))
|
||||||
expect(voteLabel.getText()).toBe('Agree: 0, Disagree: 0');
|
.element(by.tagName('h3')).getText();
|
||||||
|
expect(voteLabel).toBe('Agree: 0, Disagree: 0');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should process Agree vote', async () => {
|
it('should process Agree vote', () => {
|
||||||
const voteLabel = element(by.tagName('app-vote-taker')).element(by.tagName('h3'));
|
|
||||||
const 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(() => {
|
||||||
await agreeButton1.click();
|
const voteLabel = element(by.tagName('app-vote-taker'))
|
||||||
|
.element(by.tagName('h3')).getText();
|
||||||
expect(voteLabel.getText()).toBe('Agree: 1, Disagree: 0');
|
expect(voteLabel).toBe('Agree: 1, Disagree: 0');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should process Disagree vote', async () => {
|
it('should process Disagree vote', () => {
|
||||||
const voteLabel = element(by.tagName('app-vote-taker')).element(by.tagName('h3'));
|
|
||||||
const 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(() => {
|
||||||
await agreeButton1.click();
|
const voteLabel = element(by.tagName('app-vote-taker'))
|
||||||
|
.element(by.tagName('h3')).getText();
|
||||||
expect(voteLabel.getText()).toBe('Agree: 0, Disagree: 1');
|
expect(voteLabel).toBe('Agree: 1, Disagree: 1');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
// ...
|
// ...
|
||||||
// #enddocregion child-to-parent
|
// #enddocregion child-to-parent
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Parent calls child via local var', () => {
|
// Can't run timer tests in protractor because
|
||||||
countDownTimerTests('app-countdown-parent-lv');
|
// interaction w/ zones causes all tests to freeze & timeout.
|
||||||
|
xdescribe('Parent calls child via local var', () => {
|
||||||
|
countDownTimerTests('countdown-parent-lv');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Parent calls ViewChild', () => {
|
xdescribe('Parent calls ViewChild', () => {
|
||||||
countDownTimerTests('app-countdown-parent-vc');
|
countDownTimerTests('countdown-parent-vc');
|
||||||
});
|
});
|
||||||
|
|
||||||
function countDownTimerTests(parentTag: string) {
|
function countDownTimerTests(parentTag: string) {
|
||||||
// #docregion countdown-timer-tests
|
// #docregion countdown-timer-tests
|
||||||
// ...
|
// ...
|
||||||
// The tests trigger periodic asynchronous operations (via `setInterval()`), which will prevent
|
it('timer and parent seconds should match', () => {
|
||||||
// the app from stabilizing. See https://angular.io/api/core/ApplicationRef#is-stable-examples
|
|
||||||
// for more details.
|
|
||||||
// To allow the tests to complete, we will disable automatically waiting for the Angular app to
|
|
||||||
// stabilize.
|
|
||||||
beforeEach(() => browser.waitForAngularEnabled(false));
|
|
||||||
afterEach(() => browser.waitForAngularEnabled(true));
|
|
||||||
|
|
||||||
it('timer and parent seconds should match', async () => {
|
|
||||||
const parent = element(by.tagName(parentTag));
|
const parent = element(by.tagName(parentTag));
|
||||||
const startButton = parent.element(by.buttonText('Start'));
|
const message = parent.element(by.tagName('app-countdown-timer')).getText();
|
||||||
const seconds = parent.element(by.className('seconds'));
|
browser.sleep(10); // give `seconds` a chance to catchup with `message`
|
||||||
const timer = parent.element(by.tagName('app-countdown-timer'));
|
const seconds = parent.element(by.className('seconds')).getText();
|
||||||
|
expect(message).toContain(seconds);
|
||||||
await startButton.click();
|
|
||||||
|
|
||||||
// Wait for `<app-countdown-timer>` to be populated with any text.
|
|
||||||
await browser.wait(() => timer.getText(), 2000);
|
|
||||||
|
|
||||||
expect(await timer.getText()).toContain(await seconds.getText());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should stop the countdown', async () => {
|
it('should stop the countdown', () => {
|
||||||
const parent = element(by.tagName(parentTag));
|
const parent = element(by.tagName(parentTag));
|
||||||
const startButton = parent.element(by.buttonText('Start'));
|
const stopButton = parent.all(by.tagName('button')).get(1);
|
||||||
const stopButton = parent.element(by.buttonText('Stop'));
|
|
||||||
const timer = parent.element(by.tagName('app-countdown-timer'));
|
|
||||||
|
|
||||||
await startButton.click();
|
stopButton.click().then(() => {
|
||||||
expect(await timer.getText()).not.toContain('Holding');
|
const message = parent.element(by.tagName('app-countdown-timer')).getText();
|
||||||
|
expect(message).toContain('Holding');
|
||||||
await stopButton.click();
|
});
|
||||||
expect(await timer.getText()).toContain('Holding');
|
|
||||||
});
|
});
|
||||||
// ...
|
// ...
|
||||||
// #enddocregion countdown-timer-tests
|
// #enddocregion countdown-timer-tests
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
describe('Parent and children communicate via a service', () => {
|
describe('Parent and children communicate via a service', () => {
|
||||||
// #docregion bidirectional-service
|
// #docregion bidirectional-service
|
||||||
// ...
|
// ...
|
||||||
it('should announce a mission', async () => {
|
it('should announce a mission', () => {
|
||||||
const missionControl = element(by.tagName('app-mission-control'));
|
const missionControl = element(by.tagName('app-mission-control'));
|
||||||
const announceButton = missionControl.all(by.tagName('button')).get(0);
|
const announceButton = missionControl.all(by.tagName('button')).get(0);
|
||||||
const history = missionControl.all(by.tagName('li'));
|
announceButton.click().then(() => {
|
||||||
|
const history = missionControl.all(by.tagName('li'));
|
||||||
await announceButton.click();
|
expect(history.count()).toBe(1);
|
||||||
|
expect(history.get(0).getText()).toMatch(/Mission.* announced/);
|
||||||
expect(history.count()).toBe(1);
|
});
|
||||||
expect(history.get(0).getText()).toMatch(/Mission.* announced/);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should confirm the mission by Lovell', async () => {
|
it('should confirm the mission by Lovell', () => {
|
||||||
await testConfirmMission(1, 'Lovell');
|
testConfirmMission(1, 2, 'Lovell');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should confirm the mission by Haise', async () => {
|
it('should confirm the mission by Haise', () => {
|
||||||
await testConfirmMission(3, 'Haise');
|
testConfirmMission(3, 3, 'Haise');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should confirm the mission by Swigert', async () => {
|
it('should confirm the mission by Swigert', () => {
|
||||||
await testConfirmMission(2, 'Swigert');
|
testConfirmMission(2, 4, 'Swigert');
|
||||||
});
|
});
|
||||||
|
|
||||||
async function testConfirmMission(buttonIndex: number, astronaut: string) {
|
function testConfirmMission(buttonIndex: number, expectedLogCount: number, astronaut: string) {
|
||||||
|
const confirmedLog = ' confirmed the mission';
|
||||||
const missionControl = element(by.tagName('app-mission-control'));
|
const missionControl = element(by.tagName('app-mission-control'));
|
||||||
const announceButton = missionControl.all(by.tagName('button')).get(0);
|
|
||||||
const confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex);
|
const confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex);
|
||||||
const history = missionControl.all(by.tagName('li'));
|
confirmButton.click().then(() => {
|
||||||
|
const history = missionControl.all(by.tagName('li'));
|
||||||
await announceButton.click();
|
expect(history.count()).toBe(expectedLogCount);
|
||||||
await confirmButton.click();
|
expect(history.get(expectedLogCount - 1).getText()).toBe(astronaut + confirmedLog);
|
||||||
|
});
|
||||||
expect(history.count()).toBe(2);
|
|
||||||
expect(history.get(1).getText()).toBe(`${astronaut} confirmed the mission`);
|
|
||||||
}
|
}
|
||||||
// ...
|
// ...
|
||||||
// #enddocregion bidirectional-service
|
// #enddocregion bidirectional-service
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"cmd": "yarn",
|
||||||
|
"args": [
|
||||||
|
"e2e",
|
||||||
|
"--protractor-config=e2e/protractor-puppeteer.conf.js",
|
||||||
|
"--no-webdriver-update",
|
||||||
|
"--port={PORT}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
@ -30,21 +30,22 @@
|
|||||||
<app-vote-taker></app-vote-taker>
|
<app-vote-taker></app-vote-taker>
|
||||||
</div>
|
</div>
|
||||||
<a href="#top" class="to-top">Back to Top</a>
|
<a href="#top" class="to-top">Back to Top</a>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<div id="parent-to-child-local-var">
|
<div id="parent-to-child-local-var">
|
||||||
<app-countdown-parent-lv></app-countdown-parent-lv>
|
<app-countdown-parent-lv></app-countdown-parent-lv>
|
||||||
</div>
|
</div>
|
||||||
<a href="#top" class="to-top">Back to Top</a>
|
<a href="#top" class="to-top">Back to Top</a>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<div id="parent-to-view-child">
|
<div id="parent-to-view-child">
|
||||||
<app-countdown-parent-vc></app-countdown-parent-vc>
|
<app-countdown-parent-vc></app-countdown-parent-vc>
|
||||||
</div>
|
</div>
|
||||||
<a href="#top" class="to-top">Back to Top</a>
|
<a href="#top" class="to-top">Back to Top</a>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<div id="bidirectional-service">
|
<div id="bidirectional-service">
|
||||||
<app-mission-control></app-mission-control>
|
<app-mission-control></app-mission-control>
|
||||||
</div>
|
</div>
|
||||||
<a href="#top" class="to-top">Back to Top</a>
|
<a href="#top" class="to-top">Back to Top</a>
|
||||||
|
<hr>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { NgModule } 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';
|
||||||
@ -15,17 +15,10 @@ 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';
|
||||||
|
|
||||||
|
const directives: any[] = [
|
||||||
@NgModule({
|
|
||||||
imports: [
|
|
||||||
BrowserModule,
|
|
||||||
],
|
|
||||||
declarations: [
|
|
||||||
AppComponent,
|
AppComponent,
|
||||||
AstronautComponent,
|
AstronautComponent,
|
||||||
CountdownLocalVarParentComponent,
|
|
||||||
CountdownTimerComponent,
|
CountdownTimerComponent,
|
||||||
CountdownViewChildParentComponent,
|
|
||||||
HeroChildComponent,
|
HeroChildComponent,
|
||||||
HeroParentComponent,
|
HeroParentComponent,
|
||||||
MissionControlComponent,
|
MissionControlComponent,
|
||||||
@ -34,8 +27,28 @@ import { VoteTakerComponent } from './votetaker.component';
|
|||||||
VersionChildComponent,
|
VersionChildComponent,
|
||||||
VersionParentComponent,
|
VersionParentComponent,
|
||||||
VoterComponent,
|
VoterComponent,
|
||||||
VoteTakerComponent,
|
VoteTakerComponent
|
||||||
|
];
|
||||||
|
|
||||||
|
const schemas: any[] = [];
|
||||||
|
|
||||||
|
// Include Countdown examples
|
||||||
|
// unless in e2e tests which they break.
|
||||||
|
if (!/e2e/.test(location.search)) {
|
||||||
|
console.log('adding countdown timer examples');
|
||||||
|
directives.push(CountdownLocalVarParentComponent);
|
||||||
|
directives.push(CountdownViewChildParentComponent);
|
||||||
|
} else {
|
||||||
|
// In e2e test use CUSTOM_ELEMENTS_SCHEMA to suppress unknown element errors
|
||||||
|
schemas.push(CUSTOM_ELEMENTS_SCHEMA);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
BrowserModule
|
||||||
],
|
],
|
||||||
|
declarations: directives,
|
||||||
bootstrap: [ AppComponent ],
|
bootstrap: [ AppComponent ],
|
||||||
|
schemas
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component, OnDestroy } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-countdown-timer',
|
selector: 'app-countdown-timer',
|
||||||
template: '<p>{{message}}</p>'
|
template: '<p>{{message}}</p>'
|
||||||
})
|
})
|
||||||
export class CountdownTimerComponent implements OnDestroy {
|
export class CountdownTimerComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
intervalId = 0;
|
intervalId = 0;
|
||||||
message = '';
|
message = '';
|
||||||
seconds = 11;
|
seconds = 11;
|
||||||
|
|
||||||
|
clearTimer() { clearInterval(this.intervalId); }
|
||||||
|
|
||||||
|
ngOnInit() { this.start(); }
|
||||||
ngOnDestroy() { this.clearTimer(); }
|
ngOnDestroy() { this.clearTimer(); }
|
||||||
|
|
||||||
start() { this.countDown(); }
|
start() { this.countDown(); }
|
||||||
@ -19,8 +22,6 @@ export class CountdownTimerComponent implements OnDestroy {
|
|||||||
this.message = `Holding at T-${this.seconds} seconds`;
|
this.message = `Holding at T-${this.seconds} seconds`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private clearTimer() { clearInterval(this.intervalId); }
|
|
||||||
|
|
||||||
private countDown() {
|
private countDown() {
|
||||||
this.clearTimer();
|
this.clearTimer();
|
||||||
this.intervalId = window.setInterval(() => {
|
this.intervalId = window.setInterval(() => {
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
import { TestBed, waitForAsync } from '@angular/core/testing';
|
import { TestBed, async } from '@angular/core/testing';
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { ReactiveModule } from './reactive/reactive.module';
|
|
||||||
import { TemplateModule } from './template/template.module';
|
import { TemplateModule } from './template/template.module';
|
||||||
|
import { ReactiveModule } from './reactive/reactive.module';
|
||||||
|
|
||||||
describe('AppComponent', () => {
|
describe('AppComponent', () => {
|
||||||
beforeEach(waitForAsync(() => {
|
|
||||||
TestBed
|
beforeEach(async(() => {
|
||||||
.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [ReactiveModule, TemplateModule],
|
imports: [ReactiveModule, TemplateModule],
|
||||||
declarations: [AppComponent],
|
declarations: [
|
||||||
})
|
AppComponent
|
||||||
.compileComponents();
|
],
|
||||||
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should create the app', waitForAsync(() => {
|
it('should create the app', async(() => {
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
const app = fixture.componentInstance;
|
const app = fixture.componentInstance;
|
||||||
|
|
||||||
expect(app).toBeTruthy();
|
expect(app).toBeTruthy();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should render title', waitForAsync(() => {
|
it('should render title', async(() => {
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const compiled = fixture.debugElement.nativeElement;
|
const compiled = fixture.debugElement.nativeElement;
|
||||||
expect(compiled.querySelector('h1').textContent).toContain('Forms Overview');
|
expect(compiled.querySelector('h1').textContent).toContain('Forms Overview');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
import { createNewEvent } from '../../shared/utils';
|
|
||||||
import { FavoriteColorComponent } from './favorite-color.component';
|
import { FavoriteColorComponent } from './favorite-color.component';
|
||||||
|
import { createNewEvent } from '../../shared/utils';
|
||||||
|
|
||||||
describe('Favorite Color Component', () => {
|
describe('Favorite Color Component', () => {
|
||||||
let component: FavoriteColorComponent;
|
let component: FavoriteColorComponent;
|
||||||
let fixture: ComponentFixture<FavoriteColorComponent>;
|
let fixture: ComponentFixture<FavoriteColorComponent>;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule(
|
imports: [ ReactiveFormsModule ],
|
||||||
{imports: [ReactiveFormsModule], declarations: [FavoriteColorComponent]})
|
declarations: [ FavoriteColorComponent ]
|
||||||
.compileComponents();
|
})
|
||||||
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed, tick, fakeAsync } from '@angular/core/testing';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
|
|
||||||
import { createNewEvent } from '../../shared/utils';
|
|
||||||
import { FavoriteColorComponent } from './favorite-color.component';
|
import { FavoriteColorComponent } from './favorite-color.component';
|
||||||
|
import { createNewEvent } from '../../shared/utils';
|
||||||
|
|
||||||
describe('FavoriteColorComponent', () => {
|
describe('FavoriteColorComponent', () => {
|
||||||
let component: FavoriteColorComponent;
|
let component: FavoriteColorComponent;
|
||||||
let fixture: ComponentFixture<FavoriteColorComponent>;
|
let fixture: ComponentFixture<FavoriteColorComponent>;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({imports: [FormsModule], declarations: [FavoriteColorComponent]})
|
TestBed.configureTestingModule({
|
||||||
.compileComponents();
|
imports: [ FormsModule ],
|
||||||
|
declarations: [ FavoriteColorComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -25,29 +28,29 @@ describe('FavoriteColorComponent', () => {
|
|||||||
|
|
||||||
// #docregion model-to-view
|
// #docregion model-to-view
|
||||||
it('should update the favorite color on the input field', fakeAsync(() => {
|
it('should update the favorite color on the input field', fakeAsync(() => {
|
||||||
component.favoriteColor = 'Blue';
|
component.favoriteColor = 'Blue';
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
const input = fixture.nativeElement.querySelector('input');
|
const input = fixture.nativeElement.querySelector('input');
|
||||||
|
|
||||||
expect(input.value).toBe('Blue');
|
expect(input.value).toBe('Blue');
|
||||||
}));
|
}));
|
||||||
// #enddocregion model-to-view
|
// #enddocregion model-to-view
|
||||||
|
|
||||||
// #docregion view-to-model
|
// #docregion view-to-model
|
||||||
it('should update the favorite color in the component', fakeAsync(() => {
|
it('should update the favorite color in the component', fakeAsync(() => {
|
||||||
const input = fixture.nativeElement.querySelector('input');
|
const input = fixture.nativeElement.querySelector('input');
|
||||||
const event = createNewEvent('input');
|
const event = createNewEvent('input');
|
||||||
|
|
||||||
input.value = 'Red';
|
input.value = 'Red';
|
||||||
input.dispatchEvent(event);
|
input.dispatchEvent(event);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(component.favoriteColor).toEqual('Red');
|
expect(component.favoriteColor).toEqual('Red');
|
||||||
}));
|
}));
|
||||||
// #enddocregion view-to-model
|
// #enddocregion view-to-model
|
||||||
});
|
});
|
||||||
|
@ -24,7 +24,7 @@ export class UploaderService {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
upload(file: File) {
|
upload(file: File) {
|
||||||
if (!file) { return of<string>(); }
|
if (!file) { return; }
|
||||||
|
|
||||||
// COULD HAVE WRITTEN:
|
// COULD HAVE WRITTEN:
|
||||||
// return this.http.post('/upload/file', file, {
|
// return this.http.post('/upload/file', file, {
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
<!-- #enddocregion translated-plural -->
|
<!-- #enddocregion translated-plural -->
|
||||||
<!-- #docregion translated-select -->
|
<!-- #docregion translated-select -->
|
||||||
<!-- #docregion translate-select-1 -->
|
<!-- #docregion translate-select-1 -->
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="f99f34ac9bd4606345071bd813858dec29f3b7d1" datatype="html">
|
<trans-unit id="f99f34ac9bd4606345071bd813858dec29f3b7d1" datatype="html">
|
||||||
<source>The author is <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></source>
|
<source>The author is <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></source>
|
||||||
<target>L'auteur est <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></target>
|
<target>L'auteur est <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></target>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
// TODO: Add unit tests for this file.
|
|
||||||
// tslint:disable: no-output-native
|
// tslint:disable: no-output-native
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component, Output, OnInit, EventEmitter, NgModule } from '@angular/core';
|
import { Component, Output, OnInit, EventEmitter, NgModule } from '@angular/core';
|
||||||
|
@ -2,11 +2,7 @@
|
|||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"cmd": "yarn",
|
"cmd": "yarn",
|
||||||
"args": ["tsc", "--project", "tsconfig.spec.json", "--module", "commonjs"]
|
"args": [ "tsc", "--project", "./tsconfig.app.json" ]
|
||||||
},
|
|
||||||
{
|
|
||||||
"cmd": "yarn",
|
|
||||||
"args": ["jasmine", "out-tsc/**/*.spec.js"]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
import { docRegionFromEvent, docRegionSubscriber } from './creating';
|
|
||||||
|
|
||||||
describe('observables', () => {
|
|
||||||
it('should create an observable using the constructor', () => {
|
|
||||||
const console = {log: jasmine.createSpy('log')};
|
|
||||||
docRegionSubscriber(console);
|
|
||||||
expect(console.log).toHaveBeenCalledTimes(4);
|
|
||||||
expect(console.log.calls.allArgs()).toEqual([
|
|
||||||
[1],
|
|
||||||
[2],
|
|
||||||
[3],
|
|
||||||
['Finished sequence'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should listen to input changes', () => {
|
|
||||||
let triggerInputChange;
|
|
||||||
const input = {
|
|
||||||
value: 'Test',
|
|
||||||
addEventListener: jasmine
|
|
||||||
.createSpy('addEvent')
|
|
||||||
.and.callFake((eventName: string, cb: (e) => void) => {
|
|
||||||
if (eventName === 'keydown') {
|
|
||||||
triggerInputChange = cb;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
removeEventListener: jasmine.createSpy('removeEventListener'),
|
|
||||||
};
|
|
||||||
|
|
||||||
const document = { getElementById: () => input };
|
|
||||||
docRegionFromEvent(document);
|
|
||||||
triggerInputChange({keyCode: 65});
|
|
||||||
expect(input.value).toBe('Test');
|
|
||||||
|
|
||||||
triggerInputChange({keyCode: 27});
|
|
||||||
expect(input.value).toBe('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call removeEventListener when unsubscribing', (doneFn: DoneFn) => {
|
|
||||||
const input = {
|
|
||||||
addEventListener: jasmine.createSpy('addEvent'),
|
|
||||||
removeEventListener: jasmine
|
|
||||||
.createSpy('removeEvent')
|
|
||||||
.and.callFake((eventName: string, cb: (e) => void) => {
|
|
||||||
if (eventName === 'keydown') {
|
|
||||||
doneFn();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
const document = { getElementById: () => input };
|
|
||||||
const subscription = docRegionFromEvent(document);
|
|
||||||
subscription.unsubscribe();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,39 +1,38 @@
|
|||||||
// #docplaster
|
|
||||||
|
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
export function docRegionSubscriber(console) {
|
// #docregion subscriber
|
||||||
// #docregion subscriber
|
|
||||||
// This function runs when subscribe() is called
|
|
||||||
function sequenceSubscriber(observer) {
|
|
||||||
// synchronously deliver 1, 2, and 3, then complete
|
|
||||||
observer.next(1);
|
|
||||||
observer.next(2);
|
|
||||||
observer.next(3);
|
|
||||||
observer.complete();
|
|
||||||
|
|
||||||
// unsubscribe function doesn't need to do anything in this
|
// This function runs when subscribe() is called
|
||||||
// because values are delivered synchronously
|
function sequenceSubscriber(observer) {
|
||||||
return {unsubscribe() {}};
|
// synchronously deliver 1, 2, and 3, then complete
|
||||||
}
|
observer.next(1);
|
||||||
|
observer.next(2);
|
||||||
|
observer.next(3);
|
||||||
|
observer.complete();
|
||||||
|
|
||||||
// Create a new Observable that will deliver the above sequence
|
// unsubscribe function doesn't need to do anything in this
|
||||||
const sequence = new Observable(sequenceSubscriber);
|
// because values are delivered synchronously
|
||||||
|
return {unsubscribe() {}};
|
||||||
// execute the Observable and print the result of each notification
|
|
||||||
sequence.subscribe({
|
|
||||||
next(num) { console.log(num); },
|
|
||||||
complete() { console.log('Finished sequence'); }
|
|
||||||
});
|
|
||||||
|
|
||||||
// Logs:
|
|
||||||
// 1
|
|
||||||
// 2
|
|
||||||
// 3
|
|
||||||
// Finished sequence
|
|
||||||
// #enddocregion subscriber
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a new Observable that will deliver the above sequence
|
||||||
|
const sequence = new Observable(sequenceSubscriber);
|
||||||
|
|
||||||
|
// execute the Observable and print the result of each notification
|
||||||
|
sequence.subscribe({
|
||||||
|
next(num) { console.log(num); },
|
||||||
|
complete() { console.log('Finished sequence'); }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Logs:
|
||||||
|
// 1
|
||||||
|
// 2
|
||||||
|
// 3
|
||||||
|
// Finished sequence
|
||||||
|
|
||||||
|
// #enddocregion subscriber
|
||||||
|
|
||||||
// #docregion fromevent
|
// #docregion fromevent
|
||||||
|
|
||||||
function fromEvent(target, eventName) {
|
function fromEvent(target, eventName) {
|
||||||
@ -52,18 +51,16 @@ function fromEvent(target, eventName) {
|
|||||||
|
|
||||||
// #enddocregion fromevent
|
// #enddocregion fromevent
|
||||||
|
|
||||||
export function docRegionFromEvent(document) {
|
// #docregion fromevent_use
|
||||||
// #docregion fromevent_use
|
|
||||||
|
|
||||||
const ESC_KEY = 27;
|
const ESC_KEY = 27;
|
||||||
const nameInput = document.getElementById('name') as HTMLInputElement;
|
const nameInput = document.getElementById('name') as HTMLInputElement;
|
||||||
|
|
||||||
const subscription = fromEvent(nameInput, 'keydown').subscribe((e: KeyboardEvent) => {
|
const subscription = fromEvent(nameInput, 'keydown')
|
||||||
|
.subscribe((e: KeyboardEvent) => {
|
||||||
if (e.keyCode === ESC_KEY) {
|
if (e.keyCode === ESC_KEY) {
|
||||||
nameInput.value = '';
|
nameInput.value = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// #enddocregion fromevent_use
|
|
||||||
return subscription;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// #enddocregion fromevent_use
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// TODO: Add unit tests for this file.
|
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
// #docregion
|
// #docregion
|
||||||
|
|
||||||
// Create an Observable that will start listening to geolocation updates
|
// Create an Observable that will start listening to geolocation updates
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
import { docRegionDelaySequence, docRegionMulticastSequence } from './multicasting';
|
|
||||||
|
|
||||||
describe('multicasting', () => {
|
|
||||||
let console;
|
|
||||||
beforeEach(() => {
|
|
||||||
jasmine.clock().install();
|
|
||||||
console = {log: jasmine.createSpy('log')};
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jasmine.clock().uninstall();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create an observable and emit in sequence', () => {
|
|
||||||
docRegionDelaySequence(console);
|
|
||||||
jasmine.clock().tick(10000);
|
|
||||||
expect(console.log).toHaveBeenCalledTimes(12);
|
|
||||||
expect(console.log.calls.allArgs()).toEqual([
|
|
||||||
[1],
|
|
||||||
['1st subscribe: 1'],
|
|
||||||
['2nd subscribe: 1'],
|
|
||||||
[2],
|
|
||||||
['1st subscribe: 2'],
|
|
||||||
['2nd subscribe: 2'],
|
|
||||||
[3],
|
|
||||||
['Finished sequence'],
|
|
||||||
['1st subscribe: 3'],
|
|
||||||
['1st sequence finished.'],
|
|
||||||
['2nd subscribe: 3'],
|
|
||||||
['2nd sequence finished.']
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create an observable and multicast the emissions', () => {
|
|
||||||
docRegionMulticastSequence(console);
|
|
||||||
jasmine.clock().tick(10000);
|
|
||||||
expect(console.log).toHaveBeenCalledTimes(7);
|
|
||||||
expect(console.log.calls.allArgs()).toEqual([
|
|
||||||
['1st subscribe: 1'],
|
|
||||||
['1st subscribe: 2'],
|
|
||||||
['2nd subscribe: 2'],
|
|
||||||
['1st subscribe: 3'],
|
|
||||||
['2nd subscribe: 3'],
|
|
||||||
['1st sequence finished.'],
|
|
||||||
['2nd sequence finished.']
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,160 +1,155 @@
|
|||||||
// #docplaster
|
|
||||||
|
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
export function docRegionDelaySequence(console) {
|
// #docregion delay_sequence
|
||||||
// #docregion delay_sequence
|
|
||||||
function sequenceSubscriber(observer) {
|
|
||||||
const seq = [1, 2, 3];
|
|
||||||
let timeoutId;
|
|
||||||
|
|
||||||
// Will run through an array of numbers, emitting one value
|
function sequenceSubscriber(observer) {
|
||||||
// per second until it gets to the end of the array.
|
const seq = [1, 2, 3];
|
||||||
function doInSequence(arr, idx) {
|
let timeoutId;
|
||||||
timeoutId = setTimeout(() => {
|
|
||||||
observer.next(arr[idx]);
|
|
||||||
if (idx === arr.length - 1) {
|
|
||||||
observer.complete();
|
|
||||||
} else {
|
|
||||||
doInSequence(arr, ++idx);
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
doInSequence(seq, 0);
|
// Will run through an array of numbers, emitting one value
|
||||||
|
|
||||||
// Unsubscribe should clear the timeout to stop execution
|
|
||||||
return {
|
|
||||||
unsubscribe() {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new Observable that will deliver the above sequence
|
|
||||||
const sequence = new Observable(sequenceSubscriber);
|
|
||||||
|
|
||||||
sequence.subscribe({
|
|
||||||
next(num) { console.log(num); },
|
|
||||||
complete() { console.log('Finished sequence'); }
|
|
||||||
});
|
|
||||||
|
|
||||||
// Logs:
|
|
||||||
// (at 1 second): 1
|
|
||||||
// (at 2 seconds): 2
|
|
||||||
// (at 3 seconds): 3
|
|
||||||
// (at 3 seconds): Finished sequence
|
|
||||||
|
|
||||||
// #enddocregion delay_sequence
|
|
||||||
|
|
||||||
// #docregion subscribe_twice
|
|
||||||
|
|
||||||
// Subscribe starts the clock, and will emit after 1 second
|
|
||||||
sequence.subscribe({
|
|
||||||
next(num) { console.log('1st subscribe: ' + num); },
|
|
||||||
complete() { console.log('1st sequence finished.'); }
|
|
||||||
});
|
|
||||||
|
|
||||||
// After 1/2 second, subscribe again.
|
|
||||||
setTimeout(() => {
|
|
||||||
sequence.subscribe({
|
|
||||||
next(num) { console.log('2nd subscribe: ' + num); },
|
|
||||||
complete() { console.log('2nd sequence finished.'); }
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
// Logs:
|
|
||||||
// (at 1 second): 1st subscribe: 1
|
|
||||||
// (at 1.5 seconds): 2nd subscribe: 1
|
|
||||||
// (at 2 seconds): 1st subscribe: 2
|
|
||||||
// (at 2.5 seconds): 2nd subscribe: 2
|
|
||||||
// (at 3 seconds): 1st subscribe: 3
|
|
||||||
// (at 3 seconds): 1st sequence finished
|
|
||||||
// (at 3.5 seconds): 2nd subscribe: 3
|
|
||||||
// (at 3.5 seconds): 2nd sequence finished
|
|
||||||
|
|
||||||
// #enddocregion subscribe_twice
|
|
||||||
}
|
|
||||||
|
|
||||||
export function docRegionMulticastSequence(console) {
|
|
||||||
// #docregion multicast_sequence
|
|
||||||
function multicastSequenceSubscriber() {
|
|
||||||
const seq = [1, 2, 3];
|
|
||||||
// Keep track of each observer (one for every active subscription)
|
|
||||||
const observers = [];
|
|
||||||
// Still a single timeoutId because there will only ever be one
|
|
||||||
// set of values being generated, multicasted to each subscriber
|
|
||||||
let timeoutId;
|
|
||||||
|
|
||||||
// Return the subscriber function (runs when subscribe()
|
|
||||||
// function is invoked)
|
|
||||||
return observer => {
|
|
||||||
observers.push(observer);
|
|
||||||
// When this is the first subscription, start the sequence
|
|
||||||
if (observers.length === 1) {
|
|
||||||
timeoutId = doSequence({
|
|
||||||
next(val) {
|
|
||||||
// Iterate through observers and notify all subscriptions
|
|
||||||
observers.forEach(obs => obs.next(val));
|
|
||||||
},
|
|
||||||
complete() {
|
|
||||||
// Notify all complete callbacks
|
|
||||||
observers.slice(0).forEach(obs => obs.complete());
|
|
||||||
}
|
|
||||||
}, seq, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
unsubscribe() {
|
|
||||||
// Remove from the observers array so it's no longer notified
|
|
||||||
observers.splice(observers.indexOf(observer), 1);
|
|
||||||
// If there's no more listeners, do cleanup
|
|
||||||
if (observers.length === 0) {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run through an array of numbers, emitting one value
|
|
||||||
// per second until it gets to the end of the array.
|
// per second until it gets to the end of the array.
|
||||||
function doSequence(observer, arr, idx) {
|
function doInSequence(arr, idx) {
|
||||||
return setTimeout(() => {
|
timeoutId = setTimeout(() => {
|
||||||
observer.next(arr[idx]);
|
observer.next(arr[idx]);
|
||||||
if (idx === arr.length - 1) {
|
if (idx === arr.length - 1) {
|
||||||
observer.complete();
|
observer.complete();
|
||||||
} else {
|
} else {
|
||||||
doSequence(observer, arr, ++idx);
|
doInSequence(arr, ++idx);
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new Observable that will deliver the above sequence
|
doInSequence(seq, 0);
|
||||||
const multicastSequence = new Observable(multicastSequenceSubscriber());
|
|
||||||
|
|
||||||
// Subscribe starts the clock, and begins to emit after 1 second
|
// Unsubscribe should clear the timeout to stop execution
|
||||||
multicastSequence.subscribe({
|
return {unsubscribe() {
|
||||||
next(num) { console.log('1st subscribe: ' + num); },
|
clearTimeout(timeoutId);
|
||||||
complete() { console.log('1st sequence finished.'); }
|
}};
|
||||||
});
|
|
||||||
|
|
||||||
// After 1 1/2 seconds, subscribe again (should "miss" the first value).
|
|
||||||
setTimeout(() => {
|
|
||||||
multicastSequence.subscribe({
|
|
||||||
next(num) { console.log('2nd subscribe: ' + num); },
|
|
||||||
complete() { console.log('2nd sequence finished.'); }
|
|
||||||
});
|
|
||||||
}, 1500);
|
|
||||||
|
|
||||||
// Logs:
|
|
||||||
// (at 1 second): 1st subscribe: 1
|
|
||||||
// (at 2 seconds): 1st subscribe: 2
|
|
||||||
// (at 2 seconds): 2nd subscribe: 2
|
|
||||||
// (at 3 seconds): 1st subscribe: 3
|
|
||||||
// (at 3 seconds): 1st sequence finished
|
|
||||||
// (at 3 seconds): 2nd subscribe: 3
|
|
||||||
// (at 3 seconds): 2nd sequence finished
|
|
||||||
|
|
||||||
// #enddocregion multicast_sequence
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a new Observable that will deliver the above sequence
|
||||||
|
const sequence = new Observable(sequenceSubscriber);
|
||||||
|
|
||||||
|
sequence.subscribe({
|
||||||
|
next(num) { console.log(num); },
|
||||||
|
complete() { console.log('Finished sequence'); }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Logs:
|
||||||
|
// (at 1 second): 1
|
||||||
|
// (at 2 seconds): 2
|
||||||
|
// (at 3 seconds): 3
|
||||||
|
// (at 3 seconds): Finished sequence
|
||||||
|
|
||||||
|
// #enddocregion delay_sequence
|
||||||
|
|
||||||
|
// #docregion subscribe_twice
|
||||||
|
|
||||||
|
// Subscribe starts the clock, and will emit after 1 second
|
||||||
|
sequence.subscribe({
|
||||||
|
next(num) { console.log('1st subscribe: ' + num); },
|
||||||
|
complete() { console.log('1st sequence finished.'); }
|
||||||
|
});
|
||||||
|
|
||||||
|
// After 1/2 second, subscribe again.
|
||||||
|
setTimeout(() => {
|
||||||
|
sequence.subscribe({
|
||||||
|
next(num) { console.log('2nd subscribe: ' + num); },
|
||||||
|
complete() { console.log('2nd sequence finished.'); }
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
// Logs:
|
||||||
|
// (at 1 second): 1st subscribe: 1
|
||||||
|
// (at 1.5 seconds): 2nd subscribe: 1
|
||||||
|
// (at 2 seconds): 1st subscribe: 2
|
||||||
|
// (at 2.5 seconds): 2nd subscribe: 2
|
||||||
|
// (at 3 seconds): 1st subscribe: 3
|
||||||
|
// (at 3 seconds): 1st sequence finished
|
||||||
|
// (at 3.5 seconds): 2nd subscribe: 3
|
||||||
|
// (at 3.5 seconds): 2nd sequence finished
|
||||||
|
|
||||||
|
// #enddocregion subscribe_twice
|
||||||
|
|
||||||
|
// #docregion multicast_sequence
|
||||||
|
|
||||||
|
function multicastSequenceSubscriber() {
|
||||||
|
const seq = [1, 2, 3];
|
||||||
|
// Keep track of each observer (one for every active subscription)
|
||||||
|
const observers = [];
|
||||||
|
// Still a single timeoutId because there will only ever be one
|
||||||
|
// set of values being generated, multicasted to each subscriber
|
||||||
|
let timeoutId;
|
||||||
|
|
||||||
|
// Return the subscriber function (runs when subscribe()
|
||||||
|
// function is invoked)
|
||||||
|
return (observer) => {
|
||||||
|
observers.push(observer);
|
||||||
|
// When this is the first subscription, start the sequence
|
||||||
|
if (observers.length === 1) {
|
||||||
|
timeoutId = doSequence({
|
||||||
|
next(val) {
|
||||||
|
// Iterate through observers and notify all subscriptions
|
||||||
|
observers.forEach(obs => obs.next(val));
|
||||||
|
},
|
||||||
|
complete() {
|
||||||
|
// Notify all complete callbacks
|
||||||
|
observers.slice(0).forEach(obs => obs.complete());
|
||||||
|
}
|
||||||
|
}, seq, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
unsubscribe() {
|
||||||
|
// Remove from the observers array so it's no longer notified
|
||||||
|
observers.splice(observers.indexOf(observer), 1);
|
||||||
|
// If there's no more listeners, do cleanup
|
||||||
|
if (observers.length === 0) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run through an array of numbers, emitting one value
|
||||||
|
// per second until it gets to the end of the array.
|
||||||
|
function doSequence(observer, arr, idx) {
|
||||||
|
return setTimeout(() => {
|
||||||
|
observer.next(arr[idx]);
|
||||||
|
if (idx === arr.length - 1) {
|
||||||
|
observer.complete();
|
||||||
|
} else {
|
||||||
|
doSequence(observer, arr, ++idx);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new Observable that will deliver the above sequence
|
||||||
|
const multicastSequence = new Observable(multicastSequenceSubscriber());
|
||||||
|
|
||||||
|
// Subscribe starts the clock, and begins to emit after 1 second
|
||||||
|
multicastSequence.subscribe({
|
||||||
|
next(num) { console.log('1st subscribe: ' + num); },
|
||||||
|
complete() { console.log('1st sequence finished.'); }
|
||||||
|
});
|
||||||
|
|
||||||
|
// After 1 1/2 seconds, subscribe again (should "miss" the first value).
|
||||||
|
setTimeout(() => {
|
||||||
|
multicastSequence.subscribe({
|
||||||
|
next(num) { console.log('2nd subscribe: ' + num); },
|
||||||
|
complete() { console.log('2nd sequence finished.'); }
|
||||||
|
});
|
||||||
|
}, 1500);
|
||||||
|
|
||||||
|
// Logs:
|
||||||
|
// (at 1 second): 1st subscribe: 1
|
||||||
|
// (at 2 seconds): 1st subscribe: 2
|
||||||
|
// (at 2 seconds): 2nd subscribe: 2
|
||||||
|
// (at 3 seconds): 1st subscribe: 3
|
||||||
|
// (at 3 seconds): 1st sequence finished
|
||||||
|
// (at 3 seconds): 2nd subscribe: 3
|
||||||
|
// (at 3 seconds): 2nd sequence finished
|
||||||
|
|
||||||
|
// #enddocregion multicast_sequence
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import { docRegionObserver } from './subscribing';
|
|
||||||
|
|
||||||
describe('subscribing', () => {
|
|
||||||
it('should subscribe and emit', () => {
|
|
||||||
const console = {log: jasmine.createSpy('log')};
|
|
||||||
docRegionObserver(console);
|
|
||||||
expect(console.log).toHaveBeenCalledTimes(8);
|
|
||||||
expect(console.log.calls.allArgs()).toEqual([
|
|
||||||
['Observer got a next value: 1'],
|
|
||||||
['Observer got a next value: 2'],
|
|
||||||
['Observer got a next value: 3'],
|
|
||||||
['Observer got a complete notification'],
|
|
||||||
['Observer got a next value: 1'],
|
|
||||||
['Observer got a next value: 2'],
|
|
||||||
['Observer got a next value: 3'],
|
|
||||||
['Observer got a complete notification'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,35 +1,32 @@
|
|||||||
// #docplaster
|
|
||||||
import { of } from 'rxjs';
|
|
||||||
|
|
||||||
export function docRegionObserver(console) {
|
import { Observable, of } from 'rxjs';
|
||||||
// #docregion observer
|
|
||||||
|
|
||||||
// Create simple observable that emits three values
|
// #docregion observer
|
||||||
const myObservable = of(1, 2, 3);
|
|
||||||
|
|
||||||
// Create observer object
|
// Create simple observable that emits three values
|
||||||
const myObserver = {
|
const myObservable = of(1, 2, 3);
|
||||||
next: x => console.log('Observer got a next value: ' + x),
|
|
||||||
error: err => console.error('Observer got an error: ' + err),
|
|
||||||
complete: () => console.log('Observer got a complete notification'),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute with the observer object
|
// Create observer object
|
||||||
myObservable.subscribe(myObserver);
|
const myObserver = {
|
||||||
|
next: x => console.log('Observer got a next value: ' + x),
|
||||||
|
error: err => console.error('Observer got an error: ' + err),
|
||||||
|
complete: () => console.log('Observer got a complete notification'),
|
||||||
|
};
|
||||||
|
|
||||||
// Logs:
|
// Execute with the observer object
|
||||||
// Observer got a next value: 1
|
myObservable.subscribe(myObserver);
|
||||||
// Observer got a next value: 2
|
// Logs:
|
||||||
// Observer got a next value: 3
|
// Observer got a next value: 1
|
||||||
// Observer got a complete notification
|
// Observer got a next value: 2
|
||||||
|
// Observer got a next value: 3
|
||||||
|
// Observer got a complete notification
|
||||||
|
|
||||||
// #enddocregion observer
|
// #enddocregion observer
|
||||||
|
|
||||||
// #docregion sub_fn
|
// #docregion sub_fn
|
||||||
myObservable.subscribe(
|
myObservable.subscribe(
|
||||||
x => console.log('Observer got a next value: ' + x),
|
x => console.log('Observer got a next value: ' + x),
|
||||||
err => console.error('Observer got an error: ' + err),
|
err => console.error('Observer got an error: ' + err),
|
||||||
() => console.log('Observer got a complete notification')
|
() => console.log('Observer got a complete notification')
|
||||||
);
|
);
|
||||||
// #enddocregion sub_fn
|
// #enddocregion sub_fn
|
||||||
}
|
|
||||||
|
@ -2,11 +2,7 @@
|
|||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"cmd": "yarn",
|
"cmd": "yarn",
|
||||||
"args": ["tsc", "--project", "tsconfig.spec.json", "--module", "commonjs"]
|
"args": [ "tsc", "--project", "./tsconfig.app.json" ]
|
||||||
},
|
|
||||||
{
|
|
||||||
"cmd": "yarn",
|
|
||||||
"args": ["jasmine", "out-tsc/**/*.spec.js"]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
import { interval } from 'rxjs';
|
|
||||||
import { tap } from 'rxjs/operators';
|
|
||||||
import { backoff } from './backoff';
|
|
||||||
|
|
||||||
describe('backoff()', () => {
|
|
||||||
beforeEach(() => jasmine.clock().install());
|
|
||||||
afterEach(() => jasmine.clock().uninstall());
|
|
||||||
|
|
||||||
it('should retry in case of error', () => {
|
|
||||||
const mockConsole = {log: jasmine.createSpy('log')};
|
|
||||||
const source = interval(10).pipe(
|
|
||||||
tap(i => {
|
|
||||||
if (i > 0) {
|
|
||||||
throw new Error('Test error');
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
backoff(3, 100),
|
|
||||||
);
|
|
||||||
source.subscribe({
|
|
||||||
next: v => mockConsole.log(`Emitted: ${v}`),
|
|
||||||
error: e => mockConsole.log(`Errored: ${e.message || e}`),
|
|
||||||
complete: () => mockConsole.log('Completed'),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initial try:
|
|
||||||
// Errors on second emission and schedules retrying (with delay).
|
|
||||||
jasmine.clock().tick(10);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([['Emitted: 0']]);
|
|
||||||
|
|
||||||
jasmine.clock().tick(10);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([['Emitted: 0']]);
|
|
||||||
mockConsole.log.calls.reset();
|
|
||||||
|
|
||||||
// First re-attempt after 100ms:
|
|
||||||
// Errors again on second emission and schedules retrying (with larger delay).
|
|
||||||
jasmine.clock().tick(100);
|
|
||||||
expect(mockConsole.log).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
jasmine.clock().tick(10);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([['Emitted: 0']]);
|
|
||||||
|
|
||||||
jasmine.clock().tick(10);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([['Emitted: 0']]);
|
|
||||||
mockConsole.log.calls.reset();
|
|
||||||
|
|
||||||
// Second re-attempt after 400ms:
|
|
||||||
// Errors again on second emission and schedules retrying (with even larger delay).
|
|
||||||
jasmine.clock().tick(400);
|
|
||||||
expect(mockConsole.log).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
jasmine.clock().tick(10);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([['Emitted: 0']]);
|
|
||||||
|
|
||||||
jasmine.clock().tick(10);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([['Emitted: 0']]);
|
|
||||||
mockConsole.log.calls.reset();
|
|
||||||
|
|
||||||
// Third re-attempt after 900ms:
|
|
||||||
// Errors again on second emission and gives up (no retrying).
|
|
||||||
jasmine.clock().tick(900);
|
|
||||||
expect(mockConsole.log).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
jasmine.clock().tick(10);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([['Emitted: 0']]);
|
|
||||||
mockConsole.log.calls.reset();
|
|
||||||
|
|
||||||
jasmine.clock().tick(10);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([['Errored: Test error']]);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,32 +1,23 @@
|
|||||||
// #docplaster
|
|
||||||
// #docregion
|
|
||||||
import { of, pipe, range, throwError, timer, zip } from 'rxjs';
|
|
||||||
import { ajax } from 'rxjs/ajax';
|
|
||||||
import { map, mergeMap, retryWhen } from 'rxjs/operators';
|
|
||||||
|
|
||||||
export function backoff(maxTries, delay) {
|
import { pipe, range, timer, zip } from 'rxjs';
|
||||||
return pipe(
|
import { ajax } from 'rxjs/ajax';
|
||||||
retryWhen(attempts =>
|
import { retryWhen, map, mergeMap } from 'rxjs/operators';
|
||||||
zip(range(1, maxTries + 1), attempts).pipe(
|
|
||||||
mergeMap(([i, err]) => (i > maxTries) ? throwError(err) : of(i)),
|
function backoff(maxTries, ms) {
|
||||||
map(i => i * i),
|
return pipe(
|
||||||
mergeMap(v => timer(v * delay)),
|
retryWhen(attempts => zip(range(1, maxTries), attempts)
|
||||||
),
|
.pipe(
|
||||||
),
|
map(([i]) => i * i),
|
||||||
);
|
mergeMap(i => timer(i * ms))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #enddocregion
|
|
||||||
/*
|
|
||||||
This function declaration is necessary to ensure that it does not get called
|
|
||||||
when running the unit tests. It will not get rendered into the docs.
|
|
||||||
The indentation needs to start in the leftmost level position as well because of how
|
|
||||||
the docplaster combines the different regions together.
|
|
||||||
*/
|
|
||||||
function docRegionAjaxCall() {
|
|
||||||
// #docregion
|
|
||||||
ajax('/api/endpoint')
|
ajax('/api/endpoint')
|
||||||
.pipe(backoff(3, 250))
|
.pipe(backoff(3, 250))
|
||||||
.subscribe(function handleData(data) { /* ... */ });
|
.subscribe(data => handleData(data));
|
||||||
// #enddocregion
|
|
||||||
|
function handleData(data) {
|
||||||
|
// ...
|
||||||
}
|
}
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
import { of } from 'rxjs';
|
|
||||||
import { docRegionTypeahead } from './typeahead';
|
|
||||||
|
|
||||||
describe('typeahead', () => {
|
|
||||||
let document;
|
|
||||||
let ajax;
|
|
||||||
let triggertInputChange;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
jasmine.clock().install();
|
|
||||||
const input = {
|
|
||||||
addEventListener: jasmine
|
|
||||||
.createSpy('addEvent')
|
|
||||||
.and.callFake((eventName: string, cb: (e) => void) => {
|
|
||||||
if (eventName === 'input') {
|
|
||||||
triggertInputChange = cb;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
removeEventListener: jasmine.createSpy('removeEvent'),
|
|
||||||
};
|
|
||||||
|
|
||||||
document = { getElementById: (id: string) => input };
|
|
||||||
ajax = jasmine.createSpy('ajax').and.callFake((url: string) => of('foo bar'));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jasmine.clock().uninstall();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should make an ajax call to the corrent endpoint', () => {
|
|
||||||
docRegionTypeahead(document, ajax);
|
|
||||||
triggertInputChange({ target: { value: 'foo' } });
|
|
||||||
jasmine.clock().tick(11);
|
|
||||||
expect(ajax).toHaveBeenCalledWith('/api/endpoint?search=foo');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not make an ajax call, when the input length < 3', () => {
|
|
||||||
docRegionTypeahead(document, ajax);
|
|
||||||
triggertInputChange({ target: { value: '' } });
|
|
||||||
jasmine.clock().tick(11);
|
|
||||||
expect(ajax).not.toHaveBeenCalled();
|
|
||||||
triggertInputChange({ target: { value: 'fo' } });
|
|
||||||
jasmine.clock().tick(11);
|
|
||||||
expect(ajax).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not make an ajax call for intermediate values when debouncing', () => {
|
|
||||||
docRegionTypeahead(document, ajax);
|
|
||||||
triggertInputChange({ target: { value: 'foo' } });
|
|
||||||
jasmine.clock().tick(9);
|
|
||||||
triggertInputChange({ target: { value: 'bar' } });
|
|
||||||
jasmine.clock().tick(9);
|
|
||||||
triggertInputChange({ target: { value: 'baz' } });
|
|
||||||
jasmine.clock().tick(9);
|
|
||||||
triggertInputChange({ target: { value: 'qux' } });
|
|
||||||
expect(ajax).not.toHaveBeenCalled();
|
|
||||||
jasmine.clock().tick(10);
|
|
||||||
expect(ajax).toHaveBeenCalledTimes(1);
|
|
||||||
expect(ajax).toHaveBeenCalledWith('/api/endpoint?search=qux');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not make an ajax call, when the input value has not changed', () => {
|
|
||||||
docRegionTypeahead(document, ajax);
|
|
||||||
triggertInputChange({ target: { value: 'foo' } });
|
|
||||||
jasmine.clock().tick(11);
|
|
||||||
expect(ajax).toHaveBeenCalled();
|
|
||||||
ajax.calls.reset();
|
|
||||||
triggertInputChange({ target: { value: 'foo' } });
|
|
||||||
jasmine.clock().tick(11);
|
|
||||||
expect(ajax).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,32 +1,18 @@
|
|||||||
/*
|
import { fromEvent } from 'rxjs';
|
||||||
Because of how the code is merged together using the doc regions,
|
import { ajax } from 'rxjs/ajax';
|
||||||
we need to indent the imports with the function below.
|
import { debounceTime, distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators';
|
||||||
*/
|
|
||||||
// #docplaster
|
|
||||||
// #docregion
|
|
||||||
import { fromEvent } from 'rxjs';
|
|
||||||
import { ajax } from 'rxjs/ajax';
|
|
||||||
import { debounceTime, distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators';
|
|
||||||
|
|
||||||
// #enddocregion
|
|
||||||
/* tslint:disable:no-shadowed-variable */
|
|
||||||
/* tslint:disable:align */
|
|
||||||
export function docRegionTypeahead(document, ajax) {
|
|
||||||
// #docregion
|
|
||||||
const searchBox = document.getElementById('search-box');
|
|
||||||
|
|
||||||
const typeahead = fromEvent(searchBox, 'input').pipe(
|
const searchBox = document.getElementById('search-box');
|
||||||
map((e: KeyboardEvent) => (e.target as HTMLInputElement).value),
|
|
||||||
filter(text => text.length > 2),
|
|
||||||
debounceTime(10),
|
|
||||||
distinctUntilChanged(),
|
|
||||||
switchMap(searchTerm => ajax(`/api/endpoint?search=${searchTerm}`))
|
|
||||||
);
|
|
||||||
|
|
||||||
typeahead.subscribe(data => {
|
const typeahead = fromEvent(searchBox, 'input').pipe(
|
||||||
// Handle the data from the API
|
map((e: KeyboardEvent) => (e.target as HTMLInputElement).value),
|
||||||
});
|
filter(text => text.length > 2),
|
||||||
|
debounceTime(10),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
switchMap(() => ajax('/api/endpoint'))
|
||||||
|
);
|
||||||
|
|
||||||
// #enddocregion
|
typeahead.subscribe(data => {
|
||||||
return typeahead;
|
// Handle the data from the API
|
||||||
}
|
});
|
||||||
|
@ -2,11 +2,7 @@
|
|||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"cmd": "yarn",
|
"cmd": "yarn",
|
||||||
"args": ["tsc", "--project", "tsconfig.spec.json", "--module", "commonjs"]
|
"args": [ "tsc", "--project", "./tsconfig.app.json" ]
|
||||||
},
|
|
||||||
{
|
|
||||||
"cmd": "yarn",
|
|
||||||
"args": ["jasmine", "out-tsc/**/*.spec.js"]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
import { Subject, throwError } from 'rxjs';
|
|
||||||
import { docRegionDefault } from './error-handling';
|
|
||||||
|
|
||||||
describe('error-handling', () => {
|
|
||||||
let mockConsole;
|
|
||||||
let ajaxSubject;
|
|
||||||
let ajax;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockConsole = {log: jasmine.createSpy('log')};
|
|
||||||
ajaxSubject = new Subject();
|
|
||||||
ajax = jasmine
|
|
||||||
.createSpy('ajax')
|
|
||||||
.and.callFake((url: string) => ajaxSubject);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => ajaxSubject.unsubscribe());
|
|
||||||
|
|
||||||
it('should return the response object', () => {
|
|
||||||
docRegionDefault(mockConsole, ajax);
|
|
||||||
|
|
||||||
ajaxSubject.next({response: {foo: 'bar'}});
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([
|
|
||||||
['data: ', {foo: 'bar'}]
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return an empty array when using an object without a `response` property', () => {
|
|
||||||
docRegionDefault(mockConsole, ajax);
|
|
||||||
|
|
||||||
ajaxSubject.next({foo: 'bar'});
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([
|
|
||||||
['data: ', []]
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return an empty array when the ajax observable errors', () => {
|
|
||||||
ajax.and.returnValue(throwError('Test Error'));
|
|
||||||
|
|
||||||
docRegionDefault(mockConsole, ajax);
|
|
||||||
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([
|
|
||||||
['data: ', []]
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,36 +1,25 @@
|
|||||||
// #docplaster
|
|
||||||
/*
|
import { of } from 'rxjs';
|
||||||
Because of how the code is merged together using the doc regions,
|
|
||||||
we need to indent the imports with the function below.
|
|
||||||
*/
|
|
||||||
/* tslint:disable:no-shadowed-variable */
|
|
||||||
/* tslint:disable:align */
|
|
||||||
// #docregion
|
// #docregion
|
||||||
import { of } from 'rxjs';
|
|
||||||
import { ajax } from 'rxjs/ajax';
|
import { ajax } from 'rxjs/ajax';
|
||||||
import { map, catchError } from 'rxjs/operators';
|
import { map, catchError } from 'rxjs/operators';
|
||||||
|
// Return "response" from the API. If an error happens,
|
||||||
|
// return an empty array.
|
||||||
|
const apiData = ajax('/api/data').pipe(
|
||||||
|
map(res => {
|
||||||
|
if (!res.response) {
|
||||||
|
throw new Error('Value expected!');
|
||||||
|
}
|
||||||
|
return res.response;
|
||||||
|
}),
|
||||||
|
catchError(err => of([]))
|
||||||
|
);
|
||||||
|
|
||||||
|
apiData.subscribe({
|
||||||
|
next(x) { console.log('data: ', x); },
|
||||||
|
error(err) { console.log('errors already caught... will not run'); }
|
||||||
|
});
|
||||||
|
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
|
||||||
export function docRegionDefault(console, ajax) {
|
|
||||||
// #docregion
|
|
||||||
// Return "response" from the API. If an error happens,
|
|
||||||
// return an empty array.
|
|
||||||
const apiData = ajax('/api/data').pipe(
|
|
||||||
map((res: any) => {
|
|
||||||
if (!res.response) {
|
|
||||||
throw new Error('Value expected!');
|
|
||||||
}
|
|
||||||
return res.response;
|
|
||||||
}),
|
|
||||||
catchError(err => of([]))
|
|
||||||
);
|
|
||||||
|
|
||||||
apiData.subscribe({
|
|
||||||
next(x) { console.log('data: ', x); },
|
|
||||||
error(err) { console.log('errors already caught... will not run'); }
|
|
||||||
});
|
|
||||||
|
|
||||||
// #enddocregion
|
|
||||||
return apiData;
|
|
||||||
}
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import { docRegionDefault } from './operators.1';
|
|
||||||
|
|
||||||
describe('squareOdd - operators.1.ts', () => {
|
|
||||||
it('should return square odds', () => {
|
|
||||||
const console = {log: jasmine.createSpy('log')};
|
|
||||||
docRegionDefault(console);
|
|
||||||
expect(console.log).toHaveBeenCalledTimes(3);
|
|
||||||
expect(console.log.calls.allArgs()).toEqual([
|
|
||||||
[1],
|
|
||||||
[9],
|
|
||||||
[25],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,30 +1,23 @@
|
|||||||
// #docplaster
|
import { of, pipe } from 'rxjs';
|
||||||
/*
|
|
||||||
Because of how the code is merged together using the doc regions,
|
|
||||||
we need to indent the imports with the function below.
|
|
||||||
*/
|
|
||||||
/* tslint:disable:align */
|
|
||||||
// #docregion
|
// #docregion
|
||||||
import { of, pipe } from 'rxjs';
|
|
||||||
import { filter, map } from 'rxjs/operators';
|
import { filter, map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
const nums = of(1, 2, 3, 4, 5);
|
||||||
|
|
||||||
|
// Create a function that accepts an Observable.
|
||||||
|
const squareOddVals = pipe(
|
||||||
|
filter((n: number) => n % 2 !== 0),
|
||||||
|
map(n => n * n)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create an Observable that will run the filter and map functions
|
||||||
|
const squareOdd = squareOddVals(nums);
|
||||||
|
|
||||||
|
// Subscribe to run the combined functions
|
||||||
|
squareOdd.subscribe(x => console.log(x));
|
||||||
|
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
|
||||||
export function docRegionDefault(console) {
|
|
||||||
// #docregion
|
|
||||||
const nums = of(1, 2, 3, 4, 5);
|
|
||||||
|
|
||||||
// Create a function that accepts an Observable.
|
|
||||||
const squareOddVals = pipe(
|
|
||||||
filter((n: number) => n % 2 !== 0),
|
|
||||||
map(n => n * n)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create an Observable that will run the filter and map functions
|
|
||||||
const squareOdd = squareOddVals(nums);
|
|
||||||
|
|
||||||
// Subscribe to run the combined functions
|
|
||||||
squareOdd.subscribe(x => console.log(x));
|
|
||||||
|
|
||||||
// #enddocregion
|
|
||||||
}
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import { docRegionDefault } from './operators.2';
|
|
||||||
|
|
||||||
describe('squareOdd - operators.2.ts', () => {
|
|
||||||
it('should return square odds', () => {
|
|
||||||
const console = {log: jasmine.createSpy('log')};
|
|
||||||
docRegionDefault(console);
|
|
||||||
expect(console.log).toHaveBeenCalledTimes(3);
|
|
||||||
expect(console.log.calls.allArgs()).toEqual([
|
|
||||||
[1],
|
|
||||||
[9],
|
|
||||||
[25],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,25 +1,16 @@
|
|||||||
// #docplaster
|
import { Observable, of } from 'rxjs';
|
||||||
/*
|
|
||||||
Because of how the code is merged together using the doc regions,
|
|
||||||
we need to indent the imports with the function below.
|
|
||||||
*/
|
|
||||||
/* tslint:disable:align */
|
|
||||||
// #docregion
|
// #docregion
|
||||||
import { of } from 'rxjs';
|
|
||||||
import { filter, map } from 'rxjs/operators';
|
import { filter, map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
const squareOdd = of(1, 2, 3, 4, 5)
|
||||||
|
.pipe(
|
||||||
|
filter(n => n % 2 !== 0),
|
||||||
|
map(n => n * n)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Subscribe to get values
|
||||||
|
squareOdd.subscribe(x => console.log(x));
|
||||||
|
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
|
||||||
export function docRegionDefault(console) {
|
|
||||||
// #docregion
|
|
||||||
const squareOdd = of(1, 2, 3, 4, 5)
|
|
||||||
.pipe(
|
|
||||||
filter(n => n % 2 !== 0),
|
|
||||||
map(n => n * n)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Subscribe to get values
|
|
||||||
squareOdd.subscribe(x => console.log(x));
|
|
||||||
|
|
||||||
// #enddocregion
|
|
||||||
}
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import { docRegionDefault } from './operators';
|
|
||||||
|
|
||||||
describe('squaredNums - operators.ts', () => {
|
|
||||||
it('should return square odds', () => {
|
|
||||||
const console = {log: jasmine.createSpy('log')};
|
|
||||||
docRegionDefault(console);
|
|
||||||
expect(console.log).toHaveBeenCalledTimes(3);
|
|
||||||
expect(console.log.calls.allArgs()).toEqual([
|
|
||||||
[1],
|
|
||||||
[4],
|
|
||||||
[9],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,28 +1,20 @@
|
|||||||
// #docplaster
|
|
||||||
/*
|
import { Observable, of } from 'rxjs';
|
||||||
Because of how the code is merged together using the doc regions,
|
|
||||||
we need to indent the imports with the function below.
|
|
||||||
*/
|
|
||||||
/* tslint:disable:align */
|
|
||||||
// #docregion
|
// #docregion
|
||||||
import { of } from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
const nums = of(1, 2, 3);
|
||||||
|
|
||||||
|
const squareValues = map((val: number) => val * val);
|
||||||
|
const squaredNums = squareValues(nums);
|
||||||
|
|
||||||
|
squaredNums.subscribe(x => console.log(x));
|
||||||
|
|
||||||
|
// Logs
|
||||||
|
// 1
|
||||||
|
// 4
|
||||||
|
// 9
|
||||||
|
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
|
||||||
export function docRegionDefault(console) {
|
|
||||||
// #docregion
|
|
||||||
const nums = of(1, 2, 3);
|
|
||||||
|
|
||||||
const squareValues = map((val: number) => val * val);
|
|
||||||
const squaredNums = squareValues(nums);
|
|
||||||
|
|
||||||
squaredNums.subscribe(x => console.log(x));
|
|
||||||
|
|
||||||
// Logs
|
|
||||||
// 1
|
|
||||||
// 4
|
|
||||||
// 9
|
|
||||||
|
|
||||||
// #enddocregion
|
|
||||||
}
|
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
import { of, throwError } from 'rxjs';
|
|
||||||
import { mergeMap, tap } from 'rxjs/operators';
|
|
||||||
import { docRegionDefault } from './retry-on-error';
|
|
||||||
|
|
||||||
describe('retry-on-error', () => {
|
|
||||||
let mockConsole;
|
|
||||||
beforeEach(() => mockConsole = { log: jasmine.createSpy('log') });
|
|
||||||
|
|
||||||
it('should return the response object', () => {
|
|
||||||
const ajax = () => of({ response: { foo: 'bar' } });
|
|
||||||
|
|
||||||
docRegionDefault(mockConsole, ajax);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([
|
|
||||||
['data: ', { foo: 'bar' }],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return an empty array after 3 retries + 1 initial request', () => {
|
|
||||||
const ajax = () => {
|
|
||||||
return of({ noresponse: true }).pipe(tap(() => mockConsole.log('Subscribed to AJAX')));
|
|
||||||
};
|
|
||||||
|
|
||||||
docRegionDefault(mockConsole, ajax);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([
|
|
||||||
['Subscribed to AJAX'],
|
|
||||||
['Error occured.'],
|
|
||||||
['Subscribed to AJAX'],
|
|
||||||
['Error occured.'],
|
|
||||||
['Subscribed to AJAX'],
|
|
||||||
['Error occured.'],
|
|
||||||
['Subscribed to AJAX'],
|
|
||||||
['Error occured.'],
|
|
||||||
['data: ', []],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the response if the request succeeds upon retrying', () => {
|
|
||||||
// Fail on the first two requests, but succeed from the 3rd onwards.
|
|
||||||
let failCount = 2;
|
|
||||||
const ajax = () => of(null).pipe(
|
|
||||||
tap(() => mockConsole.log('Subscribed to AJAX')),
|
|
||||||
// Fail on the first 2 requests, but succeed from the 3rd onwards.
|
|
||||||
mergeMap(() => {
|
|
||||||
if (failCount > 0) {
|
|
||||||
failCount--;
|
|
||||||
return throwError('Test error');
|
|
||||||
}
|
|
||||||
return of({ response: { foo: 'bar' } });
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
docRegionDefault(mockConsole, ajax);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([
|
|
||||||
['Subscribed to AJAX'], // Initial request | 1st attempt overall
|
|
||||||
['Subscribed to AJAX'], // 1st retry attempt | 2nd attempt overall
|
|
||||||
['Subscribed to AJAX'], // 2nd retry attempt | 3rd attempt overall
|
|
||||||
['data: ', { foo: 'bar' }],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return an empty array when the ajax observable throws an error', () => {
|
|
||||||
const ajax = () => throwError('Test Error');
|
|
||||||
|
|
||||||
docRegionDefault(mockConsole, ajax);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([
|
|
||||||
['data: ', []],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,35 +1,26 @@
|
|||||||
// #docplaster
|
|
||||||
/*
|
import { Observable, of } from 'rxjs';
|
||||||
Because of how the code is merged together using the doc regions,
|
|
||||||
we need to indent the imports with the function below.
|
|
||||||
*/
|
|
||||||
/* tslint:disable:no-shadowed-variable */
|
|
||||||
/* tslint:disable:align */
|
|
||||||
// #docregion
|
// #docregion
|
||||||
import { of } from 'rxjs';
|
|
||||||
import { ajax } from 'rxjs/ajax';
|
import { ajax } from 'rxjs/ajax';
|
||||||
import { map, retry, catchError } from 'rxjs/operators';
|
import { map, retry, catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
|
const apiData = ajax('/api/data').pipe(
|
||||||
|
retry(3), // Retry up to 3 times before failing
|
||||||
|
map(res => {
|
||||||
|
if (!res.response) {
|
||||||
|
throw new Error('Value expected!');
|
||||||
|
}
|
||||||
|
return res.response;
|
||||||
|
}),
|
||||||
|
catchError(err => of([]))
|
||||||
|
);
|
||||||
|
|
||||||
|
apiData.subscribe({
|
||||||
|
next(x) { console.log('data: ', x); },
|
||||||
|
error(err) { console.log('errors already caught... will not run'); }
|
||||||
|
});
|
||||||
|
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
|
||||||
export function docRegionDefault(console, ajax) {
|
|
||||||
// #docregion
|
|
||||||
const apiData = ajax('/api/data').pipe(
|
|
||||||
map((res: any) => {
|
|
||||||
if (!res.response) {
|
|
||||||
console.log('Error occured.');
|
|
||||||
throw new Error('Value expected!');
|
|
||||||
}
|
|
||||||
return res.response;
|
|
||||||
}),
|
|
||||||
retry(3), // Retry up to 3 times before failing
|
|
||||||
catchError(err => of([]))
|
|
||||||
);
|
|
||||||
|
|
||||||
apiData.subscribe({
|
|
||||||
next(x) { console.log('data: ', x); },
|
|
||||||
error(err) { console.log('errors already caught... will not run'); }
|
|
||||||
});
|
|
||||||
|
|
||||||
// #enddocregion
|
|
||||||
}
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import { of } from 'rxjs';
|
|
||||||
import { docRegionPromise } from './simple-creation.1';
|
|
||||||
|
|
||||||
describe('simple-creation.1', () => {
|
|
||||||
it('should create a promise from an observable and return an empty object', () => {
|
|
||||||
const console = {log: jasmine.createSpy('log')};
|
|
||||||
const fetch = () => of({foo: 42});
|
|
||||||
docRegionPromise(console, fetch);
|
|
||||||
expect(console.log.calls.allArgs()).toEqual([
|
|
||||||
[{foo: 42}],
|
|
||||||
['Completed'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,24 +0,0 @@
|
|||||||
// #docplaster
|
|
||||||
/*
|
|
||||||
Because of how the code is merged together using the doc regions,
|
|
||||||
we need to indent the imports with the function below.
|
|
||||||
*/
|
|
||||||
/* tslint:disable:align */
|
|
||||||
// #docregion promise
|
|
||||||
import { from } from 'rxjs';
|
|
||||||
|
|
||||||
// #enddocregion promise
|
|
||||||
|
|
||||||
export function docRegionPromise(console, fetch) {
|
|
||||||
// #docregion promise
|
|
||||||
// Create an Observable out of a promise
|
|
||||||
const data = from(fetch('/api/endpoint'));
|
|
||||||
// Subscribe to begin listening for async result
|
|
||||||
data.subscribe({
|
|
||||||
next(response) { console.log(response); },
|
|
||||||
error(err) { console.error('Error: ' + err); },
|
|
||||||
complete() { console.log('Completed'); }
|
|
||||||
});
|
|
||||||
|
|
||||||
// #enddocregion promise
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
import { docRegionInterval } from './simple-creation.2';
|
|
||||||
|
|
||||||
describe('simple-creation.2', () => {
|
|
||||||
beforeEach(() => jasmine.clock().install());
|
|
||||||
afterEach(() => jasmine.clock().uninstall());
|
|
||||||
|
|
||||||
it('should create an Observable that will publish a value on an interval', () => {
|
|
||||||
const console = {log: jasmine.createSpy('log')};
|
|
||||||
const subscription = docRegionInterval(console);
|
|
||||||
jasmine.clock().tick(1000);
|
|
||||||
expect(console.log).toHaveBeenCalledWith('It\'s been 1 seconds since subscribing!');
|
|
||||||
console.log.calls.reset();
|
|
||||||
|
|
||||||
jasmine.clock().tick(999);
|
|
||||||
expect(console.log).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
jasmine.clock().tick(1);
|
|
||||||
expect(console.log).toHaveBeenCalledWith('It\'s been 2 seconds since subscribing!');
|
|
||||||
subscription.unsubscribe();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,22 +0,0 @@
|
|||||||
// #docplaster
|
|
||||||
/*
|
|
||||||
Because of how the code is merged together using the doc regions,
|
|
||||||
we need to indent the imports with the function below.
|
|
||||||
*/
|
|
||||||
/* tslint:disable:align */
|
|
||||||
// #docregion interval
|
|
||||||
import { interval } from 'rxjs';
|
|
||||||
|
|
||||||
// #enddocregion interval
|
|
||||||
|
|
||||||
export function docRegionInterval(console) {
|
|
||||||
// #docregion interval
|
|
||||||
// Create an Observable that will publish a value on an interval
|
|
||||||
const secondsCounter = interval(1000);
|
|
||||||
// Subscribe to begin publishing values
|
|
||||||
const subscription = secondsCounter.subscribe(n =>
|
|
||||||
console.log(`It's been ${n + 1} seconds since subscribing!`));
|
|
||||||
|
|
||||||
// #enddocregion interval
|
|
||||||
return subscription;
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
import { docRegionEvent } from './simple-creation.3';
|
|
||||||
|
|
||||||
describe('simple-creation.3', () => {
|
|
||||||
let triggerMousemove;
|
|
||||||
let mockConsole;
|
|
||||||
let input;
|
|
||||||
let mockDocument;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockConsole = {log: jasmine.createSpy('log')};
|
|
||||||
input = {
|
|
||||||
addEventListener: jasmine
|
|
||||||
.createSpy('addEventListener')
|
|
||||||
.and.callFake((eventName, cb) => {
|
|
||||||
if (eventName === 'mousemove') {
|
|
||||||
triggerMousemove = cb;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
removeEventListener: jasmine.createSpy('removeEventListener'),
|
|
||||||
};
|
|
||||||
mockDocument = { getElementById: () => input };
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should log coords when subscribing', () => {
|
|
||||||
docRegionEvent(mockConsole, mockDocument);
|
|
||||||
|
|
||||||
expect(mockConsole.log).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
triggerMousemove({ clientX: 50, clientY: 50 });
|
|
||||||
triggerMousemove({ clientX: 30, clientY: 50 });
|
|
||||||
triggerMousemove({ clientX: 50, clientY: 30 });
|
|
||||||
expect(mockConsole.log).toHaveBeenCalledTimes(3);
|
|
||||||
expect(mockConsole.log.calls.allArgs()).toEqual([
|
|
||||||
['Coords: 50 X 50'],
|
|
||||||
['Coords: 30 X 50'],
|
|
||||||
['Coords: 50 X 30']
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call unsubscribe when clientX and clientY are below < 40 ', () => {
|
|
||||||
docRegionEvent(mockConsole, mockDocument);
|
|
||||||
|
|
||||||
expect(mockConsole.log).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
// Ensure that we have unsubscribed.
|
|
||||||
triggerMousemove({ clientX: 30, clientY: 30 });
|
|
||||||
expect(input.removeEventListener).toHaveBeenCalledWith('mousemove', triggerMousemove, undefined);
|
|
||||||
mockConsole.log.calls.reset();
|
|
||||||
|
|
||||||
triggerMousemove({ clientX: 50, clientY: 50 });
|
|
||||||
expect(mockConsole.log).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,32 +0,0 @@
|
|||||||
// #docplaster
|
|
||||||
/*
|
|
||||||
Because of how the code is merged together using the doc regions,
|
|
||||||
we need to indent the imports with the function below.
|
|
||||||
*/
|
|
||||||
/* tslint:disable:align */
|
|
||||||
// #docregion event
|
|
||||||
import { fromEvent } from 'rxjs';
|
|
||||||
|
|
||||||
// #enddocregion event
|
|
||||||
|
|
||||||
export function docRegionEvent(console, document) {
|
|
||||||
// #docregion event
|
|
||||||
const el = document.getElementById('my-element');
|
|
||||||
|
|
||||||
// Create an Observable that will publish mouse movements
|
|
||||||
const mouseMoves = fromEvent(el, 'mousemove');
|
|
||||||
|
|
||||||
// Subscribe to start listening for mouse-move events
|
|
||||||
const subscription = mouseMoves.subscribe((evt: MouseEvent) => {
|
|
||||||
// Log coords of mouse movements
|
|
||||||
console.log(`Coords: ${evt.clientX} X ${evt.clientY}`);
|
|
||||||
|
|
||||||
// When the mouse is over the upper-left of the screen,
|
|
||||||
// unsubscribe to stop listening for mouse movements
|
|
||||||
if (evt.clientX < 40 && evt.clientY < 40) {
|
|
||||||
subscription.unsubscribe();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// #enddocregion event
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
import { of } from 'rxjs';
|
|
||||||
import { docRegionAjax } from './simple-creation';
|
|
||||||
|
|
||||||
describe('ajax', () => {
|
|
||||||
it('should make a request and console log the status and response', () => {
|
|
||||||
const console = {log: jasmine.createSpy('log')};
|
|
||||||
const ajax = jasmine.createSpy('ajax').and.callFake((url: string) => {
|
|
||||||
return of({status: 200, response: 'foo bar'});
|
|
||||||
});
|
|
||||||
|
|
||||||
docRegionAjax(console, ajax);
|
|
||||||
expect(console.log).toHaveBeenCalledWith(200, 'foo bar');
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,19 +1,65 @@
|
|||||||
// #docplaster
|
|
||||||
/*
|
// #docregion promise
|
||||||
Because of how the code is merged together using the doc regions,
|
|
||||||
we need to indent the imports with the function below.
|
import { from } from 'rxjs';
|
||||||
*/
|
|
||||||
/* tslint:disable:no-shadowed-variable */
|
// Create an Observable out of a promise
|
||||||
/* tslint:disable:align */
|
const data = from(fetch('/api/endpoint'));
|
||||||
|
// Subscribe to begin listening for async result
|
||||||
|
data.subscribe({
|
||||||
|
next(response) { console.log(response); },
|
||||||
|
error(err) { console.error('Error: ' + err); },
|
||||||
|
complete() { console.log('Completed'); }
|
||||||
|
});
|
||||||
|
|
||||||
|
// #enddocregion promise
|
||||||
|
|
||||||
|
// #docregion interval
|
||||||
|
|
||||||
|
import { interval } from 'rxjs';
|
||||||
|
|
||||||
|
// Create an Observable that will publish a value on an interval
|
||||||
|
const secondsCounter = interval(1000);
|
||||||
|
// Subscribe to begin publishing values
|
||||||
|
secondsCounter.subscribe(n =>
|
||||||
|
console.log(`It's been ${n} seconds since subscribing!`));
|
||||||
|
|
||||||
|
// #enddocregion interval
|
||||||
|
|
||||||
|
|
||||||
|
// #docregion event
|
||||||
|
|
||||||
|
import { fromEvent } from 'rxjs';
|
||||||
|
|
||||||
|
const el = document.getElementById('my-element');
|
||||||
|
|
||||||
|
// Create an Observable that will publish mouse movements
|
||||||
|
const mouseMoves = fromEvent(el, 'mousemove');
|
||||||
|
|
||||||
|
// Subscribe to start listening for mouse-move events
|
||||||
|
const subscription = mouseMoves.subscribe((evt: MouseEvent) => {
|
||||||
|
// Log coords of mouse movements
|
||||||
|
console.log(`Coords: ${evt.clientX} X ${evt.clientY}`);
|
||||||
|
|
||||||
|
// When the mouse is over the upper-left of the screen,
|
||||||
|
// unsubscribe to stop listening for mouse movements
|
||||||
|
if (evt.clientX < 40 && evt.clientY < 40) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// #enddocregion event
|
||||||
|
|
||||||
|
|
||||||
// #docregion ajax
|
// #docregion ajax
|
||||||
import { ajax } from 'rxjs/ajax';
|
|
||||||
|
import { ajax } from 'rxjs/ajax';
|
||||||
|
|
||||||
// Create an Observable that will create an AJAX request
|
// Create an Observable that will create an AJAX request
|
||||||
|
const apiData = ajax('/api/data');
|
||||||
|
// Subscribe to create the request
|
||||||
|
apiData.subscribe(res => console.log(res.status, res.response));
|
||||||
|
|
||||||
// #enddocregion ajax
|
// #enddocregion ajax
|
||||||
export function docRegionAjax(console, ajax) {
|
|
||||||
// #docregion ajax
|
|
||||||
const apiData = ajax('/api/data');
|
|
||||||
// Subscribe to create the request
|
|
||||||
apiData.subscribe(res => console.log(res.status, res.response));
|
|
||||||
// #enddocregion ajax
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { MyLibComponent } from './my-lib.component';
|
import { MyLibComponent } from './my-lib.component';
|
||||||
|
|
||||||
@ -6,8 +6,11 @@ describe('MyLibComponent', () => {
|
|||||||
let component: MyLibComponent;
|
let component: MyLibComponent;
|
||||||
let fixture: ComponentFixture<MyLibComponent>;
|
let fixture: ComponentFixture<MyLibComponent>;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({declarations: [MyLibComponent]}).compileComponents();
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MyLibComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
import { DebugElement } from '@angular/core';
|
|
||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|
||||||
import { By } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
describe('AppComponent', () => {
|
describe('AppComponent', () => {
|
||||||
let de: DebugElement;
|
let de: DebugElement;
|
||||||
let comp: AppComponent;
|
let comp: AppComponent;
|
||||||
let fixture: ComponentFixture<AppComponent>;
|
let fixture: ComponentFixture<AppComponent>;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({declarations: [AppComponent]}).compileComponents();
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ AppComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -19,11 +22,12 @@ describe('AppComponent', () => {
|
|||||||
de = fixture.debugElement.query(By.css('h1'));
|
de = fixture.debugElement.query(By.css('h1'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create component', () => expect(comp).toBeDefined());
|
it('should create component', () => expect(comp).toBeDefined() );
|
||||||
|
|
||||||
it('should have expected <h1> text', () => {
|
it('should have expected <h1> text', () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const h1 = de.nativeElement;
|
const h1 = de.nativeElement;
|
||||||
expect(h1.textContent).toMatch(/angular/i, '<h1> should say something about "Angular"');
|
expect(h1.textContent).toMatch(/angular/i,
|
||||||
|
'<h1> should say something about "Angular"');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<!-- Polyfills -->
|
<!-- Polyfills -->
|
||||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||||
|
|
||||||
<script src="node_modules/zone.js/bundles/zone.umd.js"></script>
|
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||||
<script src="systemjs.config.js"></script>
|
<script src="systemjs.config.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
@ -10,8 +10,8 @@ import { Hero } from '../shared/hero.model';
|
|||||||
template: `
|
template: `
|
||||||
<section>
|
<section>
|
||||||
Our list of heroes:
|
Our list of heroes:
|
||||||
<toh-hero *ngFor="let hero of heroes" [hero]="hero">
|
<hero-profile *ngFor="let hero of heroes" [hero]="hero">
|
||||||
</toh-hero>
|
</hero-profile>
|
||||||
Total powers: {{totalPowers}}<br>
|
Total powers: {{totalPowers}}<br>
|
||||||
Average power: {{totalPowers / heroes.length}}
|
Average power: {{totalPowers / heroes.length}}
|
||||||
</section>
|
</section>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
// #docregion
|
// #docregion
|
||||||
import { TestBed, waitForAsync } from '@angular/core/testing';
|
import { TestBed, async } from '@angular/core/testing';
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
import { AppComponent } from './app-initial.component';
|
import { AppComponent } from './app-initial.component';
|
||||||
/*
|
/*
|
||||||
@ -12,29 +12,29 @@ describe('AppComponent', () => {
|
|||||||
*/
|
*/
|
||||||
describe('AppComponent (initial CLI version)', () => {
|
describe('AppComponent (initial CLI version)', () => {
|
||||||
// #docregion
|
// #docregion
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
declarations: [
|
||||||
declarations: [AppComponent],
|
AppComponent
|
||||||
})
|
],
|
||||||
.compileComponents();
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
it('should create the app', async(() => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
}));
|
||||||
|
it(`should have as title 'app'`, async(() => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app.title).toEqual('app');
|
||||||
|
}));
|
||||||
|
it('should render title', async(() => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.nativeElement;
|
||||||
|
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
|
||||||
}));
|
}));
|
||||||
it('should create the app', waitForAsync(() => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
const app = fixture.componentInstance;
|
|
||||||
expect(app).toBeTruthy();
|
|
||||||
}));
|
|
||||||
it(`should have as title 'app'`, waitForAsync(() => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
const app = fixture.componentInstance;
|
|
||||||
expect(app.title).toEqual('app');
|
|
||||||
}));
|
|
||||||
it('should render title', waitForAsync(() => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
fixture.detectChanges();
|
|
||||||
const compiled = fixture.nativeElement;
|
|
||||||
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
|
||||||
@ -43,13 +43,16 @@ import { DebugElement } from '@angular/core';
|
|||||||
import { ComponentFixture } from '@angular/core/testing';
|
import { ComponentFixture } from '@angular/core/testing';
|
||||||
|
|
||||||
describe('AppComponent (initial CLI version - as it should be)', () => {
|
describe('AppComponent (initial CLI version - as it should be)', () => {
|
||||||
|
|
||||||
let app: AppComponent;
|
let app: AppComponent;
|
||||||
let de: DebugElement;
|
let de: DebugElement;
|
||||||
let fixture: ComponentFixture<AppComponent>;
|
let fixture: ComponentFixture<AppComponent>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [AppComponent],
|
declarations: [
|
||||||
|
AppComponent
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
fixture = TestBed.createComponent(AppComponent);
|
fixture = TestBed.createComponent(AppComponent);
|
||||||
@ -67,6 +70,7 @@ describe('AppComponent (initial CLI version - as it should be)', () => {
|
|||||||
|
|
||||||
it('should render title in an h1 tag', () => {
|
it('should render title in an h1 tag', () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(de.nativeElement.querySelector('h1').textContent).toContain('Welcome to app!');
|
expect(de.nativeElement.querySelector('h1').textContent)
|
||||||
|
.toContain('Welcome to app!');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// For more examples:
|
// For more examples:
|
||||||
// https://github.com/angular/angular/blob/master/modules/@angular/router/test/integration.spec.ts
|
// https://github.com/angular/angular/blob/master/modules/@angular/router/test/integration.spec.ts
|
||||||
|
|
||||||
import { waitForAsync, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||||
|
|
||||||
import { asyncData } from '../testing';
|
import { asyncData } from '../testing';
|
||||||
|
|
||||||
@ -21,9 +21,9 @@ import { AppModule } from './app.module';
|
|||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { AboutComponent } from './about/about.component';
|
import { AboutComponent } from './about/about.component';
|
||||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||||
|
import { TwainService } from './twain/twain.service';
|
||||||
|
|
||||||
import { HeroService, TestHeroService } from './model/testing/test-hero.service';
|
import { HeroService, TestHeroService } from './model/testing/test-hero.service';
|
||||||
import { TwainService } from './twain/twain.service';
|
|
||||||
|
|
||||||
let comp: AppComponent;
|
let comp: AppComponent;
|
||||||
let fixture: ComponentFixture<AppComponent>;
|
let fixture: ComponentFixture<AppComponent>;
|
||||||
@ -32,51 +32,54 @@ let router: Router;
|
|||||||
let location: SpyLocation;
|
let location: SpyLocation;
|
||||||
|
|
||||||
describe('AppComponent & RouterTestingModule', () => {
|
describe('AppComponent & RouterTestingModule', () => {
|
||||||
beforeEach(waitForAsync(() => {
|
|
||||||
TestBed
|
beforeEach(async(() => {
|
||||||
.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
AppModule,
|
AppModule,
|
||||||
RouterTestingModule.withRoutes(routes),
|
RouterTestingModule.withRoutes(routes),
|
||||||
],
|
],
|
||||||
providers: [{provide: HeroService, useClass: TestHeroService}]
|
providers: [
|
||||||
})
|
{ provide: HeroService, useClass: TestHeroService }
|
||||||
.compileComponents();
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should navigate to "Dashboard" immediately', fakeAsync(() => {
|
it('should navigate to "Dashboard" immediately', fakeAsync(() => {
|
||||||
createComponent();
|
createComponent();
|
||||||
tick(); // wait for async data to arrive
|
tick(); // wait for async data to arrive
|
||||||
expectPathToBe('/dashboard', 'after initialNavigation()');
|
expectPathToBe('/dashboard', 'after initialNavigation()');
|
||||||
expectElementOf(DashboardComponent);
|
expectElementOf(DashboardComponent);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should navigate to "About" on click', fakeAsync(() => {
|
it('should navigate to "About" on click', fakeAsync(() => {
|
||||||
createComponent();
|
createComponent();
|
||||||
click(page.aboutLinkDe);
|
click(page.aboutLinkDe);
|
||||||
// page.aboutLinkDe.nativeElement.click(); // ok but fails in phantom
|
// page.aboutLinkDe.nativeElement.click(); // ok but fails in phantom
|
||||||
|
|
||||||
advance();
|
advance();
|
||||||
expectPathToBe('/about');
|
expectPathToBe('/about');
|
||||||
expectElementOf(AboutComponent);
|
expectElementOf(AboutComponent);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should navigate to "About" w/ browser location URL change', fakeAsync(() => {
|
it('should navigate to "About" w/ browser location URL change', fakeAsync(() => {
|
||||||
createComponent();
|
createComponent();
|
||||||
location.simulateHashChange('/about');
|
location.simulateHashChange('/about');
|
||||||
// location.go('/about'); // also works ... except, perhaps, in Stackblitz
|
// location.go('/about'); // also works ... except, perhaps, in Stackblitz
|
||||||
advance();
|
advance();
|
||||||
expectPathToBe('/about');
|
expectPathToBe('/about');
|
||||||
expectElementOf(AboutComponent);
|
expectElementOf(AboutComponent);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Can't navigate to lazy loaded modules with this technique
|
// Can't navigate to lazy loaded modules with this technique
|
||||||
xit('should navigate to "Heroes" on click (not working yet)', fakeAsync(() => {
|
xit('should navigate to "Heroes" on click (not working yet)', fakeAsync(() => {
|
||||||
createComponent();
|
createComponent();
|
||||||
page.heroesLinkDe.nativeElement.click();
|
page.heroesLinkDe.nativeElement.click();
|
||||||
advance();
|
advance();
|
||||||
expectPathToBe('/heroes');
|
expectPathToBe('/heroes');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -91,37 +94,37 @@ let loader: SpyNgModuleFactoryLoader;
|
|||||||
|
|
||||||
///////// Can't get lazy loaded Heroes to work yet
|
///////// Can't get lazy loaded Heroes to work yet
|
||||||
xdescribe('AppComponent & Lazy Loading (not working yet)', () => {
|
xdescribe('AppComponent & Lazy Loading (not working yet)', () => {
|
||||||
beforeEach(waitForAsync(() => {
|
|
||||||
TestBed
|
beforeEach(async(() => {
|
||||||
.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
AppModule,
|
AppModule,
|
||||||
RouterTestingModule.withRoutes(routes),
|
RouterTestingModule.withRoutes(routes),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(fakeAsync(() => {
|
beforeEach(fakeAsync(() => {
|
||||||
createComponent();
|
createComponent();
|
||||||
loader = TestBed.inject(NgModuleFactoryLoader) as SpyNgModuleFactoryLoader;
|
loader = TestBed.inject(NgModuleFactoryLoader) as SpyNgModuleFactoryLoader;
|
||||||
loader.stubbedModules = {expected: HeroModule};
|
loader.stubbedModules = { expected: HeroModule };
|
||||||
router.resetConfig([{path: 'heroes', loadChildren: 'expected'}]);
|
router.resetConfig([{path: 'heroes', loadChildren: 'expected'}]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should navigate to "Heroes" on click', waitForAsync(() => {
|
it('should navigate to "Heroes" on click', async(() => {
|
||||||
page.heroesLinkDe.nativeElement.click();
|
page.heroesLinkDe.nativeElement.click();
|
||||||
advance();
|
advance();
|
||||||
expectPathToBe('/heroes');
|
expectPathToBe('/heroes');
|
||||||
expectElementOf(HeroListComponent);
|
expectElementOf(HeroListComponent);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('can navigate to "Heroes" w/ browser location URL change', fakeAsync(() => {
|
it('can navigate to "Heroes" w/ browser location URL change', fakeAsync(() => {
|
||||||
location.go('/heroes');
|
location.go('/heroes');
|
||||||
advance();
|
advance();
|
||||||
expectPathToBe('/heroes');
|
expectPathToBe('/heroes');
|
||||||
expectElementOf(HeroListComponent);
|
expectElementOf(HeroListComponent);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
////// Helpers /////////
|
////// Helpers /////////
|
||||||
@ -131,9 +134,9 @@ xdescribe('AppComponent & Lazy Loading (not working yet)', () => {
|
|||||||
* Wait a tick, then detect changes, and tick again
|
* Wait a tick, then detect changes, and tick again
|
||||||
*/
|
*/
|
||||||
function advance(): void {
|
function advance(): void {
|
||||||
tick(); // wait while navigating
|
tick(); // wait while navigating
|
||||||
fixture.detectChanges(); // update view
|
fixture.detectChanges(); // update view
|
||||||
tick(); // wait for async data to arrive
|
tick(); // wait for async data to arrive
|
||||||
}
|
}
|
||||||
|
|
||||||
function createComponent() {
|
function createComponent() {
|
||||||
@ -145,8 +148,8 @@ function createComponent() {
|
|||||||
router = injector.get(Router);
|
router = injector.get(Router);
|
||||||
router.initialNavigation();
|
router.initialNavigation();
|
||||||
spyOn(injector.get(TwainService), 'getQuote')
|
spyOn(injector.get(TwainService), 'getQuote')
|
||||||
// fake fast async observable
|
// fake fast async observable
|
||||||
.and.returnValue(asyncData('Test Quote'));
|
.and.returnValue(asyncData('Test Quote'));
|
||||||
advance();
|
advance();
|
||||||
|
|
||||||
page = new Page();
|
page = new Page();
|
||||||
@ -165,14 +168,14 @@ class Page {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const links = fixture.debugElement.queryAll(By.directive(RouterLinkWithHref));
|
const links = fixture.debugElement.queryAll(By.directive(RouterLinkWithHref));
|
||||||
this.aboutLinkDe = links[2];
|
this.aboutLinkDe = links[2];
|
||||||
this.dashboardLinkDe = links[0];
|
this.dashboardLinkDe = links[0];
|
||||||
this.heroesLinkDe = links[1];
|
this.heroesLinkDe = links[1];
|
||||||
|
|
||||||
// for debugging
|
// for debugging
|
||||||
this.comp = comp;
|
this.comp = comp;
|
||||||
this.fixture = fixture;
|
this.fixture = fixture;
|
||||||
this.router = router;
|
this.router = router;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,70 +1,66 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { Component, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
|
import { Component, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { RouterLinkDirectiveStub } from '../testing';
|
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
import { RouterLinkDirectiveStub } from '../testing';
|
||||||
|
|
||||||
// #docregion component-stubs
|
// #docregion component-stubs
|
||||||
@Component({selector: 'app-banner', template: ''})
|
@Component({selector: 'app-banner', template: ''})
|
||||||
class BannerStubComponent {
|
class BannerStubComponent {}
|
||||||
}
|
|
||||||
|
|
||||||
@Component({selector: 'router-outlet', template: ''})
|
@Component({selector: 'router-outlet', template: ''})
|
||||||
class RouterOutletStubComponent {
|
class RouterOutletStubComponent { }
|
||||||
}
|
|
||||||
|
|
||||||
@Component({selector: 'app-welcome', template: ''})
|
@Component({selector: 'app-welcome', template: ''})
|
||||||
class WelcomeStubComponent {
|
class WelcomeStubComponent {}
|
||||||
}
|
|
||||||
// #enddocregion component-stubs
|
// #enddocregion component-stubs
|
||||||
|
|
||||||
let comp: AppComponent;
|
let comp: AppComponent;
|
||||||
let fixture: ComponentFixture<AppComponent>;
|
let fixture: ComponentFixture<AppComponent>;
|
||||||
|
|
||||||
describe('AppComponent & TestModule', () => {
|
describe('AppComponent & TestModule', () => {
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
// #docregion testbed-stubs
|
// #docregion testbed-stubs
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
declarations: [
|
||||||
declarations: [
|
AppComponent,
|
||||||
AppComponent, RouterLinkDirectiveStub, BannerStubComponent, RouterOutletStubComponent,
|
RouterLinkDirectiveStub,
|
||||||
WelcomeStubComponent
|
BannerStubComponent,
|
||||||
]
|
RouterOutletStubComponent,
|
||||||
})
|
WelcomeStubComponent
|
||||||
// #enddocregion testbed-stubs
|
]
|
||||||
.compileComponents()
|
})
|
||||||
.then(() => {
|
// #enddocregion testbed-stubs
|
||||||
fixture = TestBed.createComponent(AppComponent);
|
.compileComponents().then(() => {
|
||||||
comp = fixture.componentInstance;
|
fixture = TestBed.createComponent(AppComponent);
|
||||||
});
|
comp = fixture.componentInstance;
|
||||||
|
});
|
||||||
}));
|
}));
|
||||||
tests();
|
tests();
|
||||||
});
|
});
|
||||||
|
|
||||||
//////// Testing w/ NO_ERRORS_SCHEMA //////
|
//////// Testing w/ NO_ERRORS_SCHEMA //////
|
||||||
describe('AppComponent & NO_ERRORS_SCHEMA', () => {
|
describe('AppComponent & NO_ERRORS_SCHEMA', () => {
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
// #docregion no-errors-schema, mixed-setup
|
// #docregion no-errors-schema, mixed-setup
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
declarations: [
|
||||||
declarations: [
|
AppComponent,
|
||||||
AppComponent,
|
// #enddocregion no-errors-schema
|
||||||
// #enddocregion no-errors-schema
|
BannerStubComponent,
|
||||||
BannerStubComponent,
|
// #docregion no-errors-schema
|
||||||
// #docregion no-errors-schema
|
RouterLinkDirectiveStub
|
||||||
RouterLinkDirectiveStub
|
],
|
||||||
],
|
schemas: [ NO_ERRORS_SCHEMA ]
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
})
|
||||||
})
|
// #enddocregion no-errors-schema, mixed-setup
|
||||||
// #enddocregion no-errors-schema, mixed-setup
|
.compileComponents().then(() => {
|
||||||
.compileComponents()
|
fixture = TestBed.createComponent(AppComponent);
|
||||||
.then(() => {
|
comp = fixture.componentInstance;
|
||||||
fixture = TestBed.createComponent(AppComponent);
|
});
|
||||||
comp = fixture.componentInstance;
|
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
tests();
|
tests();
|
||||||
});
|
});
|
||||||
@ -76,23 +72,30 @@ import { AppModule } from './app.module';
|
|||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
|
||||||
describe('AppComponent & AppModule', () => {
|
describe('AppComponent & AppModule', () => {
|
||||||
beforeEach(waitForAsync(() => {
|
|
||||||
TestBed
|
|
||||||
.configureTestingModule({imports: [AppModule]})
|
|
||||||
|
|
||||||
// Get rid of app's Router configuration otherwise many failures.
|
beforeEach(async(() => {
|
||||||
// Doing so removes Router declarations; add the Router stubs
|
|
||||||
.overrideModule(AppModule, {
|
|
||||||
remove: {imports: [AppRoutingModule]},
|
|
||||||
add: {declarations: [RouterLinkDirectiveStub, RouterOutletStubComponent]}
|
|
||||||
})
|
|
||||||
|
|
||||||
.compileComponents()
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ AppModule ]
|
||||||
|
})
|
||||||
|
|
||||||
.then(() => {
|
// Get rid of app's Router configuration otherwise many failures.
|
||||||
fixture = TestBed.createComponent(AppComponent);
|
// Doing so removes Router declarations; add the Router stubs
|
||||||
comp = fixture.componentInstance;
|
.overrideModule(AppModule, {
|
||||||
});
|
remove: {
|
||||||
|
imports: [ AppRoutingModule ]
|
||||||
|
},
|
||||||
|
add: {
|
||||||
|
declarations: [ RouterLinkDirectiveStub, RouterOutletStubComponent ]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.compileComponents()
|
||||||
|
|
||||||
|
.then(() => {
|
||||||
|
fixture = TestBed.createComponent(AppComponent);
|
||||||
|
comp = fixture.componentInstance;
|
||||||
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
tests();
|
tests();
|
||||||
@ -104,10 +107,11 @@ function tests() {
|
|||||||
|
|
||||||
// #docregion test-setup
|
// #docregion test-setup
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture.detectChanges(); // trigger initial data binding
|
fixture.detectChanges(); // trigger initial data binding
|
||||||
|
|
||||||
// find DebugElements with an attached RouterLinkStubDirective
|
// find DebugElements with an attached RouterLinkStubDirective
|
||||||
linkDes = fixture.debugElement.queryAll(By.directive(RouterLinkDirectiveStub));
|
linkDes = fixture.debugElement
|
||||||
|
.queryAll(By.directive(RouterLinkDirectiveStub));
|
||||||
|
|
||||||
// get attached link directive instances
|
// get attached link directive instances
|
||||||
// using each DebugElement's injector
|
// using each DebugElement's injector
|
||||||
@ -128,8 +132,8 @@ function tests() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('can click Heroes link in template', () => {
|
it('can click Heroes link in template', () => {
|
||||||
const heroesLinkDe = linkDes[1]; // heroes link DebugElement
|
const heroesLinkDe = linkDes[1]; // heroes link DebugElement
|
||||||
const heroesLink = routerLinks[1]; // heroes link directive
|
const heroesLink = routerLinks[1]; // heroes link directive
|
||||||
|
|
||||||
expect(heroesLink.navigatedTo).toBeNull('should not have navigated yet');
|
expect(heroesLink.navigatedTo).toBeNull('should not have navigated yet');
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
// #docregion import-async
|
// #docregion import-async
|
||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
// #enddocregion import-async
|
// #enddocregion import-async
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { DebugElement } from '@angular/core';
|
import { DebugElement } from '@angular/core';
|
||||||
@ -14,12 +14,11 @@ describe('BannerComponent (external files)', () => {
|
|||||||
|
|
||||||
describe('Two beforeEach', () => {
|
describe('Two beforeEach', () => {
|
||||||
// #docregion async-before-each
|
// #docregion async-before-each
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
declarations: [ BannerComponent ],
|
||||||
declarations: [BannerComponent],
|
})
|
||||||
})
|
.compileComponents(); // compile template and css
|
||||||
.compileComponents(); // compile template and css
|
|
||||||
}));
|
}));
|
||||||
// #enddocregion async-before-each
|
// #enddocregion async-before-each
|
||||||
|
|
||||||
@ -27,7 +26,7 @@ describe('BannerComponent (external files)', () => {
|
|||||||
// #docregion sync-before-each
|
// #docregion sync-before-each
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(BannerComponent);
|
fixture = TestBed.createComponent(BannerComponent);
|
||||||
component = fixture.componentInstance; // BannerComponent test instance
|
component = fixture.componentInstance; // BannerComponent test instance
|
||||||
h1 = fixture.nativeElement.querySelector('h1');
|
h1 = fixture.nativeElement.querySelector('h1');
|
||||||
});
|
});
|
||||||
// #enddocregion sync-before-each
|
// #enddocregion sync-before-each
|
||||||
@ -37,17 +36,16 @@ describe('BannerComponent (external files)', () => {
|
|||||||
|
|
||||||
describe('One beforeEach', () => {
|
describe('One beforeEach', () => {
|
||||||
// #docregion one-before-each
|
// #docregion one-before-each
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
declarations: [ BannerComponent ],
|
||||||
declarations: [BannerComponent],
|
})
|
||||||
})
|
.compileComponents()
|
||||||
.compileComponents()
|
.then(() => {
|
||||||
.then(() => {
|
fixture = TestBed.createComponent(BannerComponent);
|
||||||
fixture = TestBed.createComponent(BannerComponent);
|
component = fixture.componentInstance;
|
||||||
component = fixture.componentInstance;
|
h1 = fixture.nativeElement.querySelector('h1');
|
||||||
h1 = fixture.nativeElement.querySelector('h1');
|
});
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
// #enddocregion one-before-each
|
// #enddocregion one-before-each
|
||||||
|
|
||||||
@ -71,3 +69,4 @@ describe('BannerComponent (external files)', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
// #docregion import-by
|
// #docregion import-by
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
// #enddocregion import-by
|
// #enddocregion import-by
|
||||||
// #docregion import-debug-element
|
// #docregion import-debug-element
|
||||||
import { DebugElement } from '@angular/core';
|
import { DebugElement } from '@angular/core';
|
||||||
// #enddocregion import-debug-element
|
// #enddocregion import-debug-element
|
||||||
// #docregion v1
|
// #docregion v1
|
||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { By } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
// #enddocregion v1
|
// #enddocregion v1
|
||||||
import { BannerComponent } from './banner-initial.component';
|
import { BannerComponent } from './banner-initial.component';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// #docregion v1
|
// #docregion v1
|
||||||
import { BannerComponent } from './banner.component';
|
import { BannerComponent } from './banner.component';
|
||||||
@ -19,12 +17,15 @@ describe('BannerComponent', () => {
|
|||||||
// #enddocregion v1
|
// #enddocregion v1
|
||||||
*/
|
*/
|
||||||
describe('BannerComponent (initial CLI generated)', () => {
|
describe('BannerComponent (initial CLI generated)', () => {
|
||||||
// #docregion v1
|
// #docregion v1
|
||||||
let component: BannerComponent;
|
let component: BannerComponent;
|
||||||
let fixture: ComponentFixture<BannerComponent>;
|
let fixture: ComponentFixture<BannerComponent>;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({declarations: [BannerComponent]}).compileComponents();
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ BannerComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -43,7 +44,9 @@ describe('BannerComponent (initial CLI generated)', () => {
|
|||||||
describe('BannerComponent (minimal)', () => {
|
describe('BannerComponent (minimal)', () => {
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
// #docregion configureTestingModule
|
// #docregion configureTestingModule
|
||||||
TestBed.configureTestingModule({declarations: [BannerComponent]});
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ BannerComponent ]
|
||||||
|
});
|
||||||
// #enddocregion configureTestingModule
|
// #enddocregion configureTestingModule
|
||||||
// #docregion createComponent
|
// #docregion createComponent
|
||||||
const fixture = TestBed.createComponent(BannerComponent);
|
const fixture = TestBed.createComponent(BannerComponent);
|
||||||
@ -62,7 +65,9 @@ describe('BannerComponent (with beforeEach)', () => {
|
|||||||
let fixture: ComponentFixture<BannerComponent>;
|
let fixture: ComponentFixture<BannerComponent>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({declarations: [BannerComponent]});
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ BannerComponent ]
|
||||||
|
});
|
||||||
fixture = TestBed.createComponent(BannerComponent);
|
fixture = TestBed.createComponent(BannerComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
});
|
});
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
|
|
||||||
// #docplaster
|
// #docplaster
|
||||||
import { DebugElement } from '@angular/core';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
import { addMatchers, click } from '../../testing';
|
import { addMatchers, click } from '../../testing';
|
||||||
import { Hero } from '../model/hero';
|
|
||||||
|
|
||||||
|
import { Hero } from '../model/hero';
|
||||||
import { DashboardHeroComponent } from './dashboard-hero.component';
|
import { DashboardHeroComponent } from './dashboard-hero.component';
|
||||||
|
|
||||||
beforeEach(addMatchers);
|
beforeEach( addMatchers );
|
||||||
|
|
||||||
describe('DashboardHeroComponent class only', () => {
|
describe('DashboardHeroComponent class only', () => {
|
||||||
// #docregion class-only
|
// #docregion class-only
|
||||||
it('raises the selected event when clicked', () => {
|
it('raises the selected event when clicked', () => {
|
||||||
const comp = new DashboardHeroComponent();
|
const comp = new DashboardHeroComponent();
|
||||||
const hero: Hero = {id: 42, name: 'Test'};
|
const hero: Hero = { id: 42, name: 'Test' };
|
||||||
comp.hero = hero;
|
comp.hero = hero;
|
||||||
|
|
||||||
comp.selected.subscribe((selectedHero: Hero) => expect(selectedHero).toBe(hero));
|
comp.selected.subscribe((selectedHero: Hero) => expect(selectedHero).toBe(hero));
|
||||||
@ -25,31 +26,33 @@ describe('DashboardHeroComponent class only', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('DashboardHeroComponent when tested directly', () => {
|
describe('DashboardHeroComponent when tested directly', () => {
|
||||||
|
|
||||||
let comp: DashboardHeroComponent;
|
let comp: DashboardHeroComponent;
|
||||||
let expectedHero: Hero;
|
let expectedHero: Hero;
|
||||||
let fixture: ComponentFixture<DashboardHeroComponent>;
|
let fixture: ComponentFixture<DashboardHeroComponent>;
|
||||||
let heroDe: DebugElement;
|
let heroDe: DebugElement;
|
||||||
let heroEl: HTMLElement;
|
let heroEl: HTMLElement;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
// #docregion setup, config-testbed
|
// #docregion setup, config-testbed
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({declarations: [DashboardHeroComponent]})
|
declarations: [ DashboardHeroComponent ]
|
||||||
// #enddocregion setup, config-testbed
|
})
|
||||||
.compileComponents();
|
// #enddocregion setup, config-testbed
|
||||||
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// #docregion setup
|
// #docregion setup
|
||||||
fixture = TestBed.createComponent(DashboardHeroComponent);
|
fixture = TestBed.createComponent(DashboardHeroComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
|
|
||||||
// find the hero's DebugElement and element
|
// find the hero's DebugElement and element
|
||||||
heroDe = fixture.debugElement.query(By.css('.hero'));
|
heroDe = fixture.debugElement.query(By.css('.hero'));
|
||||||
heroEl = heroDe.nativeElement;
|
heroEl = heroDe.nativeElement;
|
||||||
|
|
||||||
// mock the hero supplied by the parent component
|
// mock the hero supplied by the parent component
|
||||||
expectedHero = {id: 42, name: 'Test Name'};
|
expectedHero = { id: 42, name: 'Test Name' };
|
||||||
|
|
||||||
// simulate the parent setting the input property with that hero
|
// simulate the parent setting the input property with that hero
|
||||||
comp.hero = expectedHero;
|
comp.hero = expectedHero;
|
||||||
@ -93,8 +96,8 @@ describe('DashboardHeroComponent when tested directly', () => {
|
|||||||
let selectedHero: Hero;
|
let selectedHero: Hero;
|
||||||
comp.selected.subscribe((hero: Hero) => selectedHero = hero);
|
comp.selected.subscribe((hero: Hero) => selectedHero = hero);
|
||||||
|
|
||||||
click(heroDe); // click helper with DebugElement
|
click(heroDe); // click helper with DebugElement
|
||||||
click(heroEl); // click helper with native element
|
click(heroEl); // click helper with native element
|
||||||
|
|
||||||
expect(selectedHero).toBe(expectedHero);
|
expect(selectedHero).toBe(expectedHero);
|
||||||
});
|
});
|
||||||
@ -108,21 +111,22 @@ describe('DashboardHeroComponent when inside a test host', () => {
|
|||||||
let fixture: ComponentFixture<TestHostComponent>;
|
let fixture: ComponentFixture<TestHostComponent>;
|
||||||
let heroEl: HTMLElement;
|
let heroEl: HTMLElement;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
// #docregion test-host-setup
|
// #docregion test-host-setup
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({declarations: [DashboardHeroComponent, TestHostComponent]})
|
declarations: [ DashboardHeroComponent, TestHostComponent ]
|
||||||
// #enddocregion test-host-setup
|
})
|
||||||
.compileComponents();
|
// #enddocregion test-host-setup
|
||||||
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// #docregion test-host-setup
|
// #docregion test-host-setup
|
||||||
// create TestHostComponent instead of DashboardHeroComponent
|
// create TestHostComponent instead of DashboardHeroComponent
|
||||||
fixture = TestBed.createComponent(TestHostComponent);
|
fixture = TestBed.createComponent(TestHostComponent);
|
||||||
testHost = fixture.componentInstance;
|
testHost = fixture.componentInstance;
|
||||||
heroEl = fixture.nativeElement.querySelector('.hero');
|
heroEl = fixture.nativeElement.querySelector('.hero');
|
||||||
fixture.detectChanges(); // trigger initial data binding
|
fixture.detectChanges(); // trigger initial data binding
|
||||||
// #enddocregion test-host-setup
|
// #enddocregion test-host-setup
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -151,10 +155,8 @@ import { Component } from '@angular/core';
|
|||||||
</dashboard-hero>`
|
</dashboard-hero>`
|
||||||
})
|
})
|
||||||
class TestHostComponent {
|
class TestHostComponent {
|
||||||
hero: Hero = {id: 42, name: 'Test Name'};
|
hero: Hero = {id: 42, name: 'Test Name' };
|
||||||
selectedHero: Hero;
|
selectedHero: Hero;
|
||||||
onSelected(hero: Hero) {
|
onSelected(hero: Hero) { this.selectedHero = hero; }
|
||||||
this.selectedHero = hero;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// #enddocregion test-host
|
// #enddocregion test-host
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing';
|
import { async, inject, ComponentFixture, TestBed
|
||||||
|
} from '@angular/core/testing';
|
||||||
|
|
||||||
import { addMatchers, asyncData, click } from '../../testing';
|
import { addMatchers, asyncData, click } from '../../testing';
|
||||||
import { HeroService } from '../model/hero.service';
|
import { HeroService } from '../model/hero.service';
|
||||||
@ -11,7 +12,7 @@ import { Router } from '@angular/router';
|
|||||||
import { DashboardComponent } from './dashboard.component';
|
import { DashboardComponent } from './dashboard.component';
|
||||||
import { DashboardModule } from './dashboard.module';
|
import { DashboardModule } from './dashboard.module';
|
||||||
|
|
||||||
beforeEach(addMatchers);
|
beforeEach ( addMatchers );
|
||||||
|
|
||||||
let comp: DashboardComponent;
|
let comp: DashboardComponent;
|
||||||
let fixture: ComponentFixture<DashboardComponent>;
|
let fixture: ComponentFixture<DashboardComponent>;
|
||||||
@ -20,7 +21,9 @@ let fixture: ComponentFixture<DashboardComponent>;
|
|||||||
|
|
||||||
describe('DashboardComponent (deep)', () => {
|
describe('DashboardComponent (deep)', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({imports: [DashboardModule]});
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ DashboardModule ]
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
compileAndCreate();
|
compileAndCreate();
|
||||||
@ -40,8 +43,10 @@ import { NO_ERRORS_SCHEMA } from '@angular/core';
|
|||||||
|
|
||||||
describe('DashboardComponent (shallow)', () => {
|
describe('DashboardComponent (shallow)', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule(
|
TestBed.configureTestingModule({
|
||||||
{declarations: [DashboardComponent], schemas: [NO_ERRORS_SCHEMA]});
|
declarations: [ DashboardComponent ],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
compileAndCreate();
|
compileAndCreate();
|
||||||
@ -58,26 +63,25 @@ describe('DashboardComponent (shallow)', () => {
|
|||||||
/** Add TestBed providers, compile, and create DashboardComponent */
|
/** Add TestBed providers, compile, and create DashboardComponent */
|
||||||
function compileAndCreate() {
|
function compileAndCreate() {
|
||||||
// #docregion compile-and-create-body
|
// #docregion compile-and-create-body
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
// #docregion router-spy
|
// #docregion router-spy
|
||||||
const routerSpy = jasmine.createSpyObj('Router', ['navigateByUrl']);
|
const routerSpy = jasmine.createSpyObj('Router', ['navigateByUrl']);
|
||||||
const heroServiceSpy = jasmine.createSpyObj('HeroService', ['getHeroes']);
|
const heroServiceSpy = jasmine.createSpyObj('HeroService', ['getHeroes']);
|
||||||
|
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
providers: [
|
||||||
providers: [
|
{ provide: HeroService, useValue: heroServiceSpy },
|
||||||
{provide: HeroService, useValue: heroServiceSpy}, {provide: Router, useValue: routerSpy}
|
{ provide: Router, useValue: routerSpy }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
// #enddocregion router-spy
|
// #enddocregion router-spy
|
||||||
.compileComponents()
|
.compileComponents().then(() => {
|
||||||
.then(() => {
|
fixture = TestBed.createComponent(DashboardComponent);
|
||||||
fixture = TestBed.createComponent(DashboardComponent);
|
comp = fixture.componentInstance;
|
||||||
comp = fixture.componentInstance;
|
|
||||||
|
|
||||||
// getHeroes spy returns observable of test heroes
|
// getHeroes spy returns observable of test heroes
|
||||||
heroServiceSpy.getHeroes.and.returnValue(asyncData(getTestHeroes()));
|
heroServiceSpy.getHeroes.and.returnValue(asyncData(getTestHeroes()));
|
||||||
});
|
});
|
||||||
// #enddocregion compile-and-create-body
|
// #enddocregion compile-and-create-body
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -89,20 +93,23 @@ function compileAndCreate() {
|
|||||||
function tests(heroClick: () => void) {
|
function tests(heroClick: () => void) {
|
||||||
|
|
||||||
it('should NOT have heroes before ngOnInit', () => {
|
it('should NOT have heroes before ngOnInit', () => {
|
||||||
expect(comp.heroes.length).toBe(0, 'should not have heroes before ngOnInit');
|
expect(comp.heroes.length).toBe(0,
|
||||||
|
'should not have heroes before ngOnInit');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT have heroes immediately after ngOnInit', () => {
|
it('should NOT have heroes immediately after ngOnInit', () => {
|
||||||
fixture.detectChanges(); // runs initial lifecycle hooks
|
fixture.detectChanges(); // runs initial lifecycle hooks
|
||||||
|
|
||||||
expect(comp.heroes.length).toBe(0, 'should not have heroes until service promise resolves');
|
expect(comp.heroes.length).toBe(0,
|
||||||
|
'should not have heroes until service promise resolves');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('after get dashboard heroes', () => {
|
describe('after get dashboard heroes', () => {
|
||||||
|
|
||||||
let router: Router;
|
let router: Router;
|
||||||
|
|
||||||
// Trigger component so it gets heroes and binds to them
|
// Trigger component so it gets heroes and binds to them
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
router = fixture.debugElement.injector.get(Router);
|
router = fixture.debugElement.injector.get(Router);
|
||||||
fixture.detectChanges(); // runs ngOnInit -> getHeroes
|
fixture.detectChanges(); // runs ngOnInit -> getHeroes
|
||||||
fixture.whenStable() // No need for the `lastPromise` hack!
|
fixture.whenStable() // No need for the `lastPromise` hack!
|
||||||
@ -110,8 +117,8 @@ function tests(heroClick: () => void) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should HAVE heroes', () => {
|
it('should HAVE heroes', () => {
|
||||||
expect(comp.heroes.length)
|
expect(comp.heroes.length).toBeGreaterThan(0,
|
||||||
.toBeGreaterThan(0, 'should have heroes after service promise resolves');
|
'should have heroes after service promise resolves');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should DISPLAY heroes', () => {
|
it('should DISPLAY heroes', () => {
|
||||||
@ -123,7 +130,8 @@ function tests(heroClick: () => void) {
|
|||||||
|
|
||||||
// #docregion navigate-test
|
// #docregion navigate-test
|
||||||
it('should tell ROUTER to navigate when hero clicked', () => {
|
it('should tell ROUTER to navigate when hero clicked', () => {
|
||||||
heroClick(); // trigger click on first inner <div class="hero">
|
|
||||||
|
heroClick(); // trigger click on first inner <div class="hero">
|
||||||
|
|
||||||
// args passed to router.navigateByUrl() spy
|
// args passed to router.navigateByUrl() spy
|
||||||
const spy = router.navigateByUrl as jasmine.Spy;
|
const spy = router.navigateByUrl as jasmine.Spy;
|
||||||
@ -131,8 +139,10 @@ function tests(heroClick: () => void) {
|
|||||||
|
|
||||||
// expecting to navigate to id of the component's first hero
|
// expecting to navigate to id of the component's first hero
|
||||||
const id = comp.heroes[0].id;
|
const id = comp.heroes[0].id;
|
||||||
expect(navArgs).toBe('/heroes/' + id, 'should nav to HeroDetail for first hero');
|
expect(navArgs).toBe('/heroes/' + id,
|
||||||
|
'should nav to HeroDetail for first hero');
|
||||||
});
|
});
|
||||||
// #enddocregion navigate-test
|
// #enddocregion navigate-test
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +1,18 @@
|
|||||||
// tslint:disable-next-line:no-unused-variable
|
// tslint:disable-next-line:no-unused-variable
|
||||||
import { fakeAsync, tick, waitForAsync } from '@angular/core/testing';
|
import { async, fakeAsync, tick } from '@angular/core/testing';
|
||||||
import { interval, of } from 'rxjs';
|
import { interval, of } from 'rxjs';
|
||||||
import { delay, take } from 'rxjs/operators';
|
import { delay, take } from 'rxjs/operators';
|
||||||
|
|
||||||
describe('Angular async helper', () => {
|
describe('Angular async helper', () => {
|
||||||
|
|
||||||
describe('async', () => {
|
describe('async', () => {
|
||||||
let actuallyDone = false;
|
let actuallyDone = false;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => { actuallyDone = false; });
|
||||||
actuallyDone = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => { expect(actuallyDone).toBe(true, 'actuallyDone should be true'); });
|
||||||
expect(actuallyDone).toBe(true, 'actuallyDone should be true');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should run normal test', () => {
|
it('should run normal test', () => { actuallyDone = true; });
|
||||||
actuallyDone = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should run normal async test', (done: DoneFn) => {
|
it('should run normal async test', (done: DoneFn) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -26,50 +21,39 @@ describe('Angular async helper', () => {
|
|||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should run async test with task', waitForAsync(() => {
|
it('should run async test with task',
|
||||||
setTimeout(() => {
|
async(() => { setTimeout(() => { actuallyDone = true; }, 0); }));
|
||||||
actuallyDone = true;
|
|
||||||
}, 0);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should run async test with task', waitForAsync(() => {
|
it('should run async test with task', async(() => {
|
||||||
const id = setInterval(() => {
|
const id = setInterval(() => {
|
||||||
actuallyDone = true;
|
actuallyDone = true;
|
||||||
clearInterval(id);
|
clearInterval(id);
|
||||||
}, 100);
|
}, 100);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should run async test with successful promise', waitForAsync(() => {
|
it('should run async test with successful promise', async(() => {
|
||||||
const p = new Promise(resolve => {
|
const p = new Promise(resolve => { setTimeout(resolve, 10); });
|
||||||
setTimeout(resolve, 10);
|
p.then(() => { actuallyDone = true; });
|
||||||
});
|
|
||||||
p.then(() => {
|
|
||||||
actuallyDone = true;
|
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should run async test with failed promise', waitForAsync(() => {
|
it('should run async test with failed promise', async(() => {
|
||||||
const p = new Promise((resolve, reject) => {
|
const p = new Promise((resolve, reject) => { setTimeout(reject, 10); });
|
||||||
setTimeout(reject, 10);
|
p.catch(() => { actuallyDone = true; });
|
||||||
});
|
|
||||||
p.catch(() => {
|
|
||||||
actuallyDone = true;
|
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Use done. Can also use async or fakeAsync.
|
// Use done. Can also use async or fakeAsync.
|
||||||
it('should run async test with successful delayed Observable', (done: DoneFn) => {
|
it('should run async test with successful delayed Observable', (done: DoneFn) => {
|
||||||
const source = of(true).pipe(delay(10));
|
const source = of (true).pipe(delay(10));
|
||||||
source.subscribe(val => actuallyDone = true, err => fail(err), done);
|
source.subscribe(val => actuallyDone = true, err => fail(err), done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should run async test with successful delayed Observable', waitForAsync(() => {
|
it('should run async test with successful delayed Observable', async(() => {
|
||||||
const source = of(true).pipe(delay(10));
|
const source = of (true).pipe(delay(10));
|
||||||
source.subscribe(val => actuallyDone = true, err => fail(err));
|
source.subscribe(val => actuallyDone = true, err => fail(err));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should run async test with successful delayed Observable', fakeAsync(() => {
|
it('should run async test with successful delayed Observable', fakeAsync(() => {
|
||||||
const source = of(true).pipe(delay(10));
|
const source = of (true).pipe(delay(10));
|
||||||
source.subscribe(val => actuallyDone = true, err => fail(err));
|
source.subscribe(val => actuallyDone = true, err => fail(err));
|
||||||
|
|
||||||
tick(10);
|
tick(10);
|
||||||
@ -80,9 +64,7 @@ describe('Angular async helper', () => {
|
|||||||
// #docregion fake-async-test-tick
|
// #docregion fake-async-test-tick
|
||||||
it('should run timeout callback with delay after call tick with millis', fakeAsync(() => {
|
it('should run timeout callback with delay after call tick with millis', fakeAsync(() => {
|
||||||
let called = false;
|
let called = false;
|
||||||
setTimeout(() => {
|
setTimeout(() => { called = true; }, 100);
|
||||||
called = true;
|
|
||||||
}, 100);
|
|
||||||
tick(100);
|
tick(100);
|
||||||
expect(called).toBe(true);
|
expect(called).toBe(true);
|
||||||
}));
|
}));
|
||||||
@ -91,9 +73,7 @@ describe('Angular async helper', () => {
|
|||||||
// #docregion fake-async-test-tick-new-macro-task-sync
|
// #docregion fake-async-test-tick-new-macro-task-sync
|
||||||
it('should run new macro task callback with delay after call tick with millis',
|
it('should run new macro task callback with delay after call tick with millis',
|
||||||
fakeAsync(() => {
|
fakeAsync(() => {
|
||||||
function nestedTimer(cb: () => any): void {
|
function nestedTimer(cb: () => any): void { setTimeout(() => setTimeout(() => cb())); }
|
||||||
setTimeout(() => setTimeout(() => cb()));
|
|
||||||
}
|
|
||||||
const callback = jasmine.createSpy('callback');
|
const callback = jasmine.createSpy('callback');
|
||||||
nestedTimer(callback);
|
nestedTimer(callback);
|
||||||
expect(callback).not.toHaveBeenCalled();
|
expect(callback).not.toHaveBeenCalled();
|
||||||
@ -106,9 +86,7 @@ describe('Angular async helper', () => {
|
|||||||
// #docregion fake-async-test-tick-new-macro-task-async
|
// #docregion fake-async-test-tick-new-macro-task-async
|
||||||
it('should not run new macro task callback with delay after call tick with millis',
|
it('should not run new macro task callback with delay after call tick with millis',
|
||||||
fakeAsync(() => {
|
fakeAsync(() => {
|
||||||
function nestedTimer(cb: () => any): void {
|
function nestedTimer(cb: () => any): void { setTimeout(() => setTimeout(() => cb())); }
|
||||||
setTimeout(() => setTimeout(() => cb()));
|
|
||||||
}
|
|
||||||
const callback = jasmine.createSpy('callback');
|
const callback = jasmine.createSpy('callback');
|
||||||
nestedTimer(callback);
|
nestedTimer(callback);
|
||||||
expect(callback).not.toHaveBeenCalled();
|
expect(callback).not.toHaveBeenCalled();
|
||||||
@ -134,9 +112,7 @@ describe('Angular async helper', () => {
|
|||||||
// need to add `import 'zone.js/dist/zone-patch-rxjs-fake-async'
|
// need to add `import 'zone.js/dist/zone-patch-rxjs-fake-async'
|
||||||
// to patch rxjs scheduler
|
// to patch rxjs scheduler
|
||||||
let result = null;
|
let result = null;
|
||||||
of('hello').pipe(delay(1000)).subscribe(v => {
|
of ('hello').pipe(delay(1000)).subscribe(v => { result = v; });
|
||||||
result = v;
|
|
||||||
});
|
|
||||||
expect(result).toBeNull();
|
expect(result).toBeNull();
|
||||||
tick(1000);
|
tick(1000);
|
||||||
expect(result).toBe('hello');
|
expect(result).toBe('hello');
|
||||||
@ -157,18 +133,12 @@ describe('Angular async helper', () => {
|
|||||||
describe('use jasmine.clock()', () => {
|
describe('use jasmine.clock()', () => {
|
||||||
// need to config __zone_symbol__fakeAsyncPatchLock flag
|
// need to config __zone_symbol__fakeAsyncPatchLock flag
|
||||||
// before loading zone.js/dist/zone-testing
|
// before loading zone.js/dist/zone-testing
|
||||||
beforeEach(() => {
|
beforeEach(() => { jasmine.clock().install(); });
|
||||||
jasmine.clock().install();
|
afterEach(() => { jasmine.clock().uninstall(); });
|
||||||
});
|
|
||||||
afterEach(() => {
|
|
||||||
jasmine.clock().uninstall();
|
|
||||||
});
|
|
||||||
it('should auto enter fakeAsync', () => {
|
it('should auto enter fakeAsync', () => {
|
||||||
// is in fakeAsync now, don't need to call fakeAsync(testFn)
|
// is in fakeAsync now, don't need to call fakeAsync(testFn)
|
||||||
let called = false;
|
let called = false;
|
||||||
setTimeout(() => {
|
setTimeout(() => { called = true; }, 100);
|
||||||
called = true;
|
|
||||||
}, 100);
|
|
||||||
jasmine.clock().tick(100);
|
jasmine.clock().tick(100);
|
||||||
expect(called).toBe(true);
|
expect(called).toBe(true);
|
||||||
});
|
});
|
||||||
@ -182,7 +152,7 @@ describe('Angular async helper', () => {
|
|||||||
}
|
}
|
||||||
// need to config __zone_symbol__supportWaitUnResolvedChainedPromise flag
|
// need to config __zone_symbol__supportWaitUnResolvedChainedPromise flag
|
||||||
// before loading zone.js/dist/zone-testing
|
// before loading zone.js/dist/zone-testing
|
||||||
it('should wait until promise.then is called', waitForAsync(() => {
|
it('should wait until promise.then is called', async(() => {
|
||||||
let finished = false;
|
let finished = false;
|
||||||
new Promise((res, rej) => {
|
new Promise((res, rej) => {
|
||||||
jsonp('localhost:8080/jsonp', () => {
|
jsonp('localhost:8080/jsonp', () => {
|
||||||
@ -198,4 +168,5 @@ describe('Angular async helper', () => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
// #enddocregion async-test-promise-then
|
// #enddocregion async-test-promise-then
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -24,18 +24,17 @@ import { FormsModule } from '@angular/forms';
|
|||||||
// Forms symbols imported only for a specific test below
|
// Forms symbols imported only for a specific test below
|
||||||
import { NgModel, NgControl } from '@angular/forms';
|
import { NgModel, NgControl } from '@angular/forms';
|
||||||
|
|
||||||
import {
|
import { async, ComponentFixture, fakeAsync, inject, TestBed, tick
|
||||||
ComponentFixture, fakeAsync, inject, TestBed, tick, waitForAsync
|
|
||||||
} from '@angular/core/testing';
|
} from '@angular/core/testing';
|
||||||
|
|
||||||
import { addMatchers, click } from '../../testing';
|
import { addMatchers, newEvent, click } from '../../testing';
|
||||||
|
|
||||||
export class NotProvided extends ValueService { /* example below */ }
|
export class NotProvided extends ValueService { /* example below */}
|
||||||
beforeEach(addMatchers);
|
beforeEach( addMatchers );
|
||||||
|
|
||||||
describe('demo (with TestBed):', () => {
|
describe('demo (with TestBed):', () => {
|
||||||
|
|
||||||
//////// Service Tests /////////////
|
//////// Service Tests /////////////
|
||||||
|
|
||||||
// #docregion ValueService
|
// #docregion ValueService
|
||||||
describe('ValueService', () => {
|
describe('ValueService', () => {
|
||||||
@ -65,13 +64,13 @@ describe('demo (with TestBed):', () => {
|
|||||||
// #enddocregion testbed-get-w-null
|
// #enddocregion testbed-get-w-null
|
||||||
});
|
});
|
||||||
|
|
||||||
it('test should wait for ValueService.getPromiseValue', waitForAsync(() => {
|
it('test should wait for ValueService.getPromiseValue', async(() => {
|
||||||
service.getPromiseValue().then(
|
service.getPromiseValue().then(
|
||||||
value => expect(value).toBe('promise value')
|
value => expect(value).toBe('promise value')
|
||||||
);
|
);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('test should wait for ValueService.getObservableValue', waitForAsync(() => {
|
it('test should wait for ValueService.getObservableValue', async(() => {
|
||||||
service.getObservableValue().subscribe(
|
service.getObservableValue().subscribe(
|
||||||
value => expect(value).toBe('observable value')
|
value => expect(value).toBe('observable value')
|
||||||
);
|
);
|
||||||
@ -151,7 +150,7 @@ describe('demo (with TestBed):', () => {
|
|||||||
TestBed.configureTestingModule({ providers: [ValueService] });
|
TestBed.configureTestingModule({ providers: [ValueService] });
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(waitForAsync(inject([ValueService], (service: ValueService) => {
|
beforeEach(async(inject([ValueService], (service: ValueService) => {
|
||||||
service.getPromiseValue().then(value => serviceValue = value);
|
service.getPromiseValue().then(value => serviceValue = value);
|
||||||
})));
|
})));
|
||||||
|
|
||||||
@ -160,11 +159,11 @@ describe('demo (with TestBed):', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/////////// Component Tests //////////////////
|
/////////// Component Tests //////////////////
|
||||||
|
|
||||||
describe('TestBed component tests', () => {
|
describe('TestBed component tests', () => {
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed
|
TestBed
|
||||||
.configureTestingModule({
|
.configureTestingModule({
|
||||||
imports: [DemoModule],
|
imports: [DemoModule],
|
||||||
@ -236,7 +235,7 @@ describe('demo (with TestBed):', () => {
|
|||||||
// #docregion ButtonComp
|
// #docregion ButtonComp
|
||||||
it('should support clicking a button', () => {
|
it('should support clicking a button', () => {
|
||||||
const fixture = TestBed.createComponent(LightswitchComponent);
|
const fixture = TestBed.createComponent(LightswitchComponent);
|
||||||
const btn = fixture.debugElement.query(By.css('button'));
|
const btn = fixture.debugElement.query(By.css('button'));
|
||||||
const span = fixture.debugElement.query(By.css('span')).nativeElement;
|
const span = fixture.debugElement.query(By.css('span')).nativeElement;
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@ -249,7 +248,7 @@ describe('demo (with TestBed):', () => {
|
|||||||
// #enddocregion ButtonComp
|
// #enddocregion ButtonComp
|
||||||
|
|
||||||
// ngModel is async so we must wait for it with promise-based `whenStable`
|
// ngModel is async so we must wait for it with promise-based `whenStable`
|
||||||
it('should support entering text in input box (ngModel)', waitForAsync(() => {
|
it('should support entering text in input box (ngModel)', async(() => {
|
||||||
const expectedOrigName = 'John';
|
const expectedOrigName = 'John';
|
||||||
const expectedNewName = 'Sally';
|
const expectedNewName = 'Sally';
|
||||||
|
|
||||||
@ -274,17 +273,15 @@ describe('demo (with TestBed):', () => {
|
|||||||
expect(comp.name).toBe(expectedOrigName,
|
expect(comp.name).toBe(expectedOrigName,
|
||||||
`comp.name should still be ${expectedOrigName} after value change, before binding happens`);
|
`comp.name should still be ${expectedOrigName} after value change, before binding happens`);
|
||||||
|
|
||||||
// Dispatch a DOM event so that Angular learns of input value change.
|
// dispatch a DOM event so that Angular learns of input value change.
|
||||||
// then wait while ngModel pushes input.box value to comp.name
|
// then wait while ngModel pushes input.box value to comp.name
|
||||||
// In older browsers, such as IE, you might need a CustomEvent instead. See
|
input.dispatchEvent(newEvent('input'));
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
|
|
||||||
input.dispatchEvent(new Event('input'));
|
|
||||||
return fixture.whenStable();
|
return fixture.whenStable();
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
expect(comp.name).toBe(expectedNewName,
|
expect(comp.name).toBe(expectedNewName,
|
||||||
`After ngModel updates the model, comp.name should be ${expectedNewName} `);
|
`After ngModel updates the model, comp.name should be ${expectedNewName} `);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// fakeAsync version of ngModel input test enables sync test style
|
// fakeAsync version of ngModel input test enables sync test style
|
||||||
@ -314,11 +311,9 @@ describe('demo (with TestBed):', () => {
|
|||||||
expect(comp.name).toBe(expectedOrigName,
|
expect(comp.name).toBe(expectedOrigName,
|
||||||
`comp.name should still be ${expectedOrigName} after value change, before binding happens`);
|
`comp.name should still be ${expectedOrigName} after value change, before binding happens`);
|
||||||
|
|
||||||
// Dispatch a DOM event so that Angular learns of input value change.
|
// dispatch a DOM event so that Angular learns of input value change.
|
||||||
// then wait a tick while ngModel pushes input.box value to comp.name
|
// then wait a tick while ngModel pushes input.box value to comp.name
|
||||||
// In older browsers, such as IE, you might need a CustomEvent instead. See
|
input.dispatchEvent(newEvent('input'));
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
|
|
||||||
input.dispatchEvent(new Event('input'));
|
|
||||||
tick();
|
tick();
|
||||||
expect(comp.name).toBe(expectedNewName,
|
expect(comp.name).toBe(expectedNewName,
|
||||||
`After ngModel updates the model, comp.name should be ${expectedNewName} `);
|
`After ngModel updates the model, comp.name should be ${expectedNewName} `);
|
||||||
@ -332,19 +327,17 @@ describe('demo (with TestBed):', () => {
|
|||||||
const fixture = TestBed.createComponent(ReversePipeComponent);
|
const fixture = TestBed.createComponent(ReversePipeComponent);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const comp = fixture.componentInstance;
|
const comp = fixture.componentInstance;
|
||||||
const input = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;
|
const input = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;
|
||||||
const span = fixture.debugElement.query(By.css('span')).nativeElement as HTMLElement;
|
const span = fixture.debugElement.query(By.css('span')).nativeElement as HTMLElement;
|
||||||
|
|
||||||
// simulate user entering new name in input
|
// simulate user entering new name in input
|
||||||
input.value = inputText;
|
input.value = inputText;
|
||||||
|
|
||||||
// Dispatch a DOM event so that Angular learns of input value change.
|
// dispatch a DOM event so that Angular learns of input value change.
|
||||||
// then wait a tick while ngModel pushes input.box value to comp.text
|
// then wait a tick while ngModel pushes input.box value to comp.text
|
||||||
// and Angular updates the output span
|
// and Angular updates the output span
|
||||||
// In older browsers, such as IE, you might need a CustomEvent instead. See
|
input.dispatchEvent(newEvent('input'));
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
|
|
||||||
input.dispatchEvent(new Event('input'));
|
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(span.textContent).toBe(expectedText, 'output span');
|
expect(span.textContent).toBe(expectedText, 'output span');
|
||||||
@ -388,12 +381,12 @@ describe('demo (with TestBed):', () => {
|
|||||||
|
|
||||||
expect(el.styles.color).toBe(comp.color, 'color style');
|
expect(el.styles.color).toBe(comp.color, 'color style');
|
||||||
expect(el.styles.width).toBe(comp.width + 'px', 'width style');
|
expect(el.styles.width).toBe(comp.width + 'px', 'width style');
|
||||||
// #enddocregion dom-attributes
|
// #enddocregion dom-attributes
|
||||||
|
|
||||||
// Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future?
|
// Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future?
|
||||||
// expect(el.properties['customProperty']).toBe(true, 'customProperty');
|
// expect(el.properties['customProperty']).toBe(true, 'customProperty');
|
||||||
|
|
||||||
// #docregion dom-attributes
|
// #docregion dom-attributes
|
||||||
});
|
});
|
||||||
// #enddocregion dom-attributes
|
// #enddocregion dom-attributes
|
||||||
|
|
||||||
@ -407,10 +400,10 @@ describe('demo (with TestBed):', () => {
|
|||||||
const fixture = TestBed.configureTestingModule({
|
const fixture = TestBed.configureTestingModule({
|
||||||
declarations: [Child1Component],
|
declarations: [Child1Component],
|
||||||
})
|
})
|
||||||
.overrideComponent(Child1Component, {
|
.overrideComponent(Child1Component, {
|
||||||
set: { template: '<span>Fake</span>' }
|
set: { template: '<span>Fake</span>' }
|
||||||
})
|
})
|
||||||
.createComponent(Child1Component);
|
.createComponent(Child1Component);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(fixture).toHaveText('Fake');
|
expect(fixture).toHaveText('Fake');
|
||||||
@ -420,14 +413,14 @@ describe('demo (with TestBed):', () => {
|
|||||||
const fixture = TestBed.configureTestingModule({
|
const fixture = TestBed.configureTestingModule({
|
||||||
declarations: [TestProvidersComponent],
|
declarations: [TestProvidersComponent],
|
||||||
})
|
})
|
||||||
.overrideComponent(TestProvidersComponent, {
|
.overrideComponent(TestProvidersComponent, {
|
||||||
remove: { providers: [ValueService] },
|
remove: { providers: [ValueService]},
|
||||||
add: { providers: [{ provide: ValueService, useClass: FakeValueService }] },
|
add: { providers: [{ provide: ValueService, useClass: FakeValueService }] },
|
||||||
|
|
||||||
// Or replace them all (this component has only one provider)
|
// Or replace them all (this component has only one provider)
|
||||||
// set: { providers: [{ provide: ValueService, useClass: FakeValueService }] },
|
// set: { providers: [{ provide: ValueService, useClass: FakeValueService }] },
|
||||||
})
|
})
|
||||||
.createComponent(TestProvidersComponent);
|
.createComponent(TestProvidersComponent);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(fixture).toHaveText('injected value: faked value', 'text');
|
expect(fixture).toHaveText('injected value: faked value', 'text');
|
||||||
@ -443,14 +436,14 @@ describe('demo (with TestBed):', () => {
|
|||||||
const fixture = TestBed.configureTestingModule({
|
const fixture = TestBed.configureTestingModule({
|
||||||
declarations: [TestViewProvidersComponent],
|
declarations: [TestViewProvidersComponent],
|
||||||
})
|
})
|
||||||
.overrideComponent(TestViewProvidersComponent, {
|
.overrideComponent(TestViewProvidersComponent, {
|
||||||
// remove: { viewProviders: [ValueService]},
|
// remove: { viewProviders: [ValueService]},
|
||||||
// add: { viewProviders: [{ provide: ValueService, useClass: FakeValueService }] },
|
// add: { viewProviders: [{ provide: ValueService, useClass: FakeValueService }] },
|
||||||
|
|
||||||
// Or replace them all (this component has only one viewProvider)
|
// Or replace them all (this component has only one viewProvider)
|
||||||
set: { viewProviders: [{ provide: ValueService, useClass: FakeValueService }] },
|
set: { viewProviders: [{ provide: ValueService, useClass: FakeValueService }] },
|
||||||
})
|
})
|
||||||
.createComponent(TestViewProvidersComponent);
|
.createComponent(TestViewProvidersComponent);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(fixture).toHaveText('injected value: faked value');
|
expect(fixture).toHaveText('injected value: faked value');
|
||||||
@ -460,20 +453,20 @@ describe('demo (with TestBed):', () => {
|
|||||||
|
|
||||||
// TestComponent is parent of TestProvidersComponent
|
// TestComponent is parent of TestProvidersComponent
|
||||||
@Component({ template: '<my-service-comp></my-service-comp>' })
|
@Component({ template: '<my-service-comp></my-service-comp>' })
|
||||||
class TestComponent { }
|
class TestComponent {}
|
||||||
|
|
||||||
// 3 levels of ValueService provider: module, TestCompomponent, TestProvidersComponent
|
// 3 levels of ValueService provider: module, TestCompomponent, TestProvidersComponent
|
||||||
const fixture = TestBed.configureTestingModule({
|
const fixture = TestBed.configureTestingModule({
|
||||||
declarations: [TestComponent, TestProvidersComponent],
|
declarations: [TestComponent, TestProvidersComponent],
|
||||||
providers: [ValueService]
|
providers: [ValueService]
|
||||||
})
|
})
|
||||||
.overrideComponent(TestComponent, {
|
.overrideComponent(TestComponent, {
|
||||||
set: { providers: [{ provide: ValueService, useValue: {} }] }
|
set: { providers: [{ provide: ValueService, useValue: {} }] }
|
||||||
})
|
})
|
||||||
.overrideComponent(TestProvidersComponent, {
|
.overrideComponent(TestProvidersComponent, {
|
||||||
set: { providers: [{ provide: ValueService, useClass: FakeValueService }] }
|
set: { providers: [{ provide: ValueService, useClass: FakeValueService }] }
|
||||||
})
|
})
|
||||||
.createComponent(TestComponent);
|
.createComponent(TestComponent);
|
||||||
|
|
||||||
let testBedProvider: ValueService;
|
let testBedProvider: ValueService;
|
||||||
let tcProvider: ValueService;
|
let tcProvider: ValueService;
|
||||||
@ -496,10 +489,10 @@ describe('demo (with TestBed):', () => {
|
|||||||
const fixture = TestBed.configureTestingModule({
|
const fixture = TestBed.configureTestingModule({
|
||||||
declarations: [ShellComponent, NeedsContentComponent, Child1Component, Child2Component, Child3Component],
|
declarations: [ShellComponent, NeedsContentComponent, Child1Component, Child2Component, Child3Component],
|
||||||
})
|
})
|
||||||
.overrideComponent(ShellComponent, {
|
.overrideComponent(ShellComponent, {
|
||||||
set: {
|
set: {
|
||||||
selector: 'test-shell',
|
selector: 'test-shell',
|
||||||
template: `
|
template: `
|
||||||
<needs-content #nc>
|
<needs-content #nc>
|
||||||
<child-1 #content text="My"></child-1>
|
<child-1 #content text="My"></child-1>
|
||||||
<child-2 #content text="dog"></child-2>
|
<child-2 #content text="dog"></child-2>
|
||||||
@ -508,9 +501,9 @@ describe('demo (with TestBed):', () => {
|
|||||||
<div #content>!</div>
|
<div #content>!</div>
|
||||||
</needs-content>
|
</needs-content>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.createComponent(ShellComponent);
|
.createComponent(ShellComponent);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@ -622,7 +615,7 @@ describe('demo (with TestBed):', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// must be async test to see child flow to parent
|
// must be async test to see child flow to parent
|
||||||
it('changed child value flows to parent', waitForAsync(() => {
|
it('changed child value flows to parent', async(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
getChild();
|
getChild();
|
||||||
|
|
||||||
@ -632,14 +625,14 @@ describe('demo (with TestBed):', () => {
|
|||||||
// Wait one JS engine turn!
|
// Wait one JS engine turn!
|
||||||
setTimeout(() => resolve(), 0);
|
setTimeout(() => resolve(), 0);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(child.ngOnChangesCounter).toBe(2,
|
expect(child.ngOnChangesCounter).toBe(2,
|
||||||
'expected 2 changes: initial value and changed value');
|
'expected 2 changes: initial value and changed value');
|
||||||
expect(parent.parentValue).toBe('bar',
|
expect(parent.parentValue).toBe('bar',
|
||||||
'parentValue should eq changed parent value');
|
'parentValue should eq changed parent value');
|
||||||
});
|
});
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
import { ComponentFixture, fakeAsync, inject, TestBed, tick, waitForAsync } from '@angular/core/testing';
|
import {
|
||||||
|
async, ComponentFixture, fakeAsync, inject, TestBed, tick
|
||||||
|
} from '@angular/core/testing';
|
||||||
|
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ActivatedRoute, ActivatedRouteStub, asyncData, click
|
ActivatedRoute, ActivatedRouteStub, asyncData, click, newEvent
|
||||||
} from '../../testing';
|
} from '../../testing';
|
||||||
|
|
||||||
import { Hero } from '../model/hero';
|
import { Hero } from '../model/hero';
|
||||||
@ -33,54 +36,59 @@ describe('HeroDetailComponent', () => {
|
|||||||
function overrideSetup() {
|
function overrideSetup() {
|
||||||
// #docregion hds-spy
|
// #docregion hds-spy
|
||||||
class HeroDetailServiceSpy {
|
class HeroDetailServiceSpy {
|
||||||
testHero: Hero = {id: 42, name: 'Test Hero'};
|
testHero: Hero = {id: 42, name: 'Test Hero' };
|
||||||
|
|
||||||
/* emit cloned test hero */
|
/* emit cloned test hero */
|
||||||
getHero = jasmine.createSpy('getHero').and.callFake(
|
getHero = jasmine.createSpy('getHero').and.callFake(
|
||||||
() => asyncData(Object.assign({}, this.testHero)));
|
() => asyncData(Object.assign({}, this.testHero))
|
||||||
|
);
|
||||||
|
|
||||||
/* emit clone of test hero, with changes merged in */
|
/* emit clone of test hero, with changes merged in */
|
||||||
saveHero = jasmine.createSpy('saveHero')
|
saveHero = jasmine.createSpy('saveHero').and.callFake(
|
||||||
.and.callFake((hero: Hero) => asyncData(Object.assign(this.testHero, hero)));
|
(hero: Hero) => asyncData(Object.assign(this.testHero, hero))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #enddocregion hds-spy
|
// #enddocregion hds-spy
|
||||||
|
|
||||||
// the `id` value is irrelevant because ignored by service stub
|
// the `id` value is irrelevant because ignored by service stub
|
||||||
beforeEach(() => activatedRoute.setParamMap({id: 99999}));
|
beforeEach(() => activatedRoute.setParamMap({ id: 99999 }));
|
||||||
|
|
||||||
// #docregion setup-override
|
// #docregion setup-override
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
const routerSpy = createRouterSpy();
|
const routerSpy = createRouterSpy();
|
||||||
|
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
imports: [ HeroModule ],
|
||||||
imports: [HeroModule],
|
providers: [
|
||||||
providers: [
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
{provide: ActivatedRoute, useValue: activatedRoute},
|
{ provide: Router, useValue: routerSpy},
|
||||||
{provide: Router, useValue: routerSpy},
|
|
||||||
// #enddocregion setup-override
|
// #enddocregion setup-override
|
||||||
// HeroDetailService at this level is IRRELEVANT!
|
// HeroDetailService at this level is IRRELEVANT!
|
||||||
{provide: HeroDetailService, useValue: {}}
|
{ provide: HeroDetailService, useValue: {} }
|
||||||
// #docregion setup-override
|
// #docregion setup-override
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
// Override component's own provider
|
// Override component's own provider
|
||||||
// #docregion override-component-method
|
// #docregion override-component-method
|
||||||
.overrideComponent(
|
.overrideComponent(HeroDetailComponent, {
|
||||||
HeroDetailComponent,
|
set: {
|
||||||
{set: {providers: [{provide: HeroDetailService, useClass: HeroDetailServiceSpy}]}})
|
providers: [
|
||||||
// #enddocregion override-component-method
|
{ provide: HeroDetailService, useClass: HeroDetailServiceSpy }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// #enddocregion override-component-method
|
||||||
|
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
// #enddocregion setup-override
|
// #enddocregion setup-override
|
||||||
|
|
||||||
// #docregion override-tests
|
// #docregion override-tests
|
||||||
let hdsSpy: HeroDetailServiceSpy;
|
let hdsSpy: HeroDetailServiceSpy;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
createComponent();
|
createComponent();
|
||||||
// get the component's injected HeroDetailServiceSpy
|
// get the component's injected HeroDetailServiceSpy
|
||||||
hdsSpy = fixture.debugElement.injector.get(HeroDetailService) as any;
|
hdsSpy = fixture.debugElement.injector.get(HeroDetailService) as any;
|
||||||
@ -95,35 +103,33 @@ function overrideSetup() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should save stub hero change', fakeAsync(() => {
|
it('should save stub hero change', fakeAsync(() => {
|
||||||
const origName = hdsSpy.testHero.name;
|
const origName = hdsSpy.testHero.name;
|
||||||
const newName = 'New Name';
|
const newName = 'New Name';
|
||||||
|
|
||||||
page.nameInput.value = newName;
|
page.nameInput.value = newName;
|
||||||
|
page.nameInput.dispatchEvent(newEvent('input')); // tell Angular
|
||||||
|
|
||||||
// In older browsers, such as IE, you might need a CustomEvent instead. See
|
expect(component.hero.name).toBe(newName, 'component hero has new name');
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
|
expect(hdsSpy.testHero.name).toBe(origName, 'service hero unchanged before save');
|
||||||
page.nameInput.dispatchEvent(new Event('input')); // tell Angular
|
|
||||||
|
|
||||||
expect(component.hero.name).toBe(newName, 'component hero has new name');
|
click(page.saveBtn);
|
||||||
expect(hdsSpy.testHero.name).toBe(origName, 'service hero unchanged before save');
|
expect(hdsSpy.saveHero.calls.count()).toBe(1, 'saveHero called once');
|
||||||
|
|
||||||
click(page.saveBtn);
|
tick(); // wait for async save to complete
|
||||||
expect(hdsSpy.saveHero.calls.count()).toBe(1, 'saveHero called once');
|
expect(hdsSpy.testHero.name).toBe(newName, 'service hero has new name after save');
|
||||||
|
expect(page.navigateSpy.calls.any()).toBe(true, 'router.navigate called');
|
||||||
tick(); // wait for async save to complete
|
}));
|
||||||
expect(hdsSpy.testHero.name).toBe(newName, 'service hero has new name after save');
|
|
||||||
expect(page.navigateSpy.calls.any()).toBe(true, 'router.navigate called');
|
|
||||||
}));
|
|
||||||
// #enddocregion override-tests
|
// #enddocregion override-tests
|
||||||
|
|
||||||
it('fixture injected service is not the component injected service',
|
it('fixture injected service is not the component injected service',
|
||||||
// inject gets the service from the fixture
|
// inject gets the service from the fixture
|
||||||
inject([HeroDetailService], (fixtureService: HeroDetailService) => {
|
inject([HeroDetailService], (fixtureService: HeroDetailService) => {
|
||||||
// use `fixture.debugElement.injector` to get service from component
|
|
||||||
const componentService = fixture.debugElement.injector.get(HeroDetailService);
|
|
||||||
|
|
||||||
expect(fixtureService).not.toBe(componentService, 'service injected from fixture');
|
// use `fixture.debugElement.injector` to get service from component
|
||||||
}));
|
const componentService = fixture.debugElement.injector.get(HeroDetailService);
|
||||||
|
|
||||||
|
expect(fixtureService).not.toBe(componentService, 'service injected from fixture');
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
@ -133,22 +139,21 @@ const firstHero = getTestHeroes()[0];
|
|||||||
|
|
||||||
function heroModuleSetup() {
|
function heroModuleSetup() {
|
||||||
// #docregion setup-hero-module
|
// #docregion setup-hero-module
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
const routerSpy = createRouterSpy();
|
const routerSpy = createRouterSpy();
|
||||||
|
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
imports: [ HeroModule ],
|
||||||
imports: [HeroModule],
|
// #enddocregion setup-hero-module
|
||||||
// #enddocregion setup-hero-module
|
// declarations: [ HeroDetailComponent ], // NO! DOUBLE DECLARATION
|
||||||
// declarations: [ HeroDetailComponent ], // NO! DOUBLE DECLARATION
|
// #docregion setup-hero-module
|
||||||
// #docregion setup-hero-module
|
providers: [
|
||||||
providers: [
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
{provide: ActivatedRoute, useValue: activatedRoute},
|
{ provide: HeroService, useClass: TestHeroService },
|
||||||
{provide: HeroService, useClass: TestHeroService},
|
{ provide: Router, useValue: routerSpy},
|
||||||
{provide: Router, useValue: routerSpy},
|
]
|
||||||
]
|
})
|
||||||
})
|
.compileComponents();
|
||||||
.compileComponents();
|
|
||||||
}));
|
}));
|
||||||
// #enddocregion setup-hero-module
|
// #enddocregion setup-hero-module
|
||||||
|
|
||||||
@ -156,17 +161,17 @@ function heroModuleSetup() {
|
|||||||
describe('when navigate to existing hero', () => {
|
describe('when navigate to existing hero', () => {
|
||||||
let expectedHero: Hero;
|
let expectedHero: Hero;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
expectedHero = firstHero;
|
expectedHero = firstHero;
|
||||||
activatedRoute.setParamMap({id: expectedHero.id});
|
activatedRoute.setParamMap({ id: expectedHero.id });
|
||||||
createComponent();
|
createComponent();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// #docregion selected-tests
|
// #docregion selected-tests
|
||||||
it('should display that hero\'s name', () => {
|
it('should display that hero\'s name', () => {
|
||||||
expect(page.nameDisplay.textContent).toBe(expectedHero.name);
|
expect(page.nameDisplay.textContent).toBe(expectedHero.name);
|
||||||
});
|
});
|
||||||
// #enddocregion route-good-id
|
// #enddocregion route-good-id
|
||||||
|
|
||||||
it('should navigate when click cancel', () => {
|
it('should navigate when click cancel', () => {
|
||||||
click(page.cancelBtn);
|
click(page.cancelBtn);
|
||||||
@ -185,10 +190,10 @@ function heroModuleSetup() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate when click save and save resolves', fakeAsync(() => {
|
it('should navigate when click save and save resolves', fakeAsync(() => {
|
||||||
click(page.saveBtn);
|
click(page.saveBtn);
|
||||||
tick(); // wait for async save to complete
|
tick(); // wait for async save to complete
|
||||||
expect(page.navigateSpy.calls.any()).toBe(true, 'router.navigate called');
|
expect(page.navigateSpy.calls.any()).toBe(true, 'router.navigate called');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// #docregion title-case-pipe
|
// #docregion title-case-pipe
|
||||||
it('should convert hero name to Title Case', () => {
|
it('should convert hero name to Title Case', () => {
|
||||||
@ -200,10 +205,9 @@ function heroModuleSetup() {
|
|||||||
// simulate user entering a new name into the input box
|
// simulate user entering a new name into the input box
|
||||||
nameInput.value = 'quick BROWN fOx';
|
nameInput.value = 'quick BROWN fOx';
|
||||||
|
|
||||||
// Dispatch a DOM event so that Angular learns of input value change.
|
// dispatch a DOM event so that Angular learns of input value change.
|
||||||
// In older browsers, such as IE, you might need a CustomEvent instead. See
|
// use newEvent utility function (not provided by Angular) for better browser compatibility
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
|
nameInput.dispatchEvent(newEvent('input'));
|
||||||
nameInput.dispatchEvent(new Event('input'));
|
|
||||||
|
|
||||||
// Tell Angular to update the display binding through the title pipe
|
// Tell Angular to update the display binding through the title pipe
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@ -211,14 +215,14 @@ function heroModuleSetup() {
|
|||||||
expect(nameDisplay.textContent).toBe('Quick Brown Fox');
|
expect(nameDisplay.textContent).toBe('Quick Brown Fox');
|
||||||
});
|
});
|
||||||
// #enddocregion title-case-pipe
|
// #enddocregion title-case-pipe
|
||||||
// #enddocregion selected-tests
|
// #enddocregion selected-tests
|
||||||
// #docregion route-good-id
|
// #docregion route-good-id
|
||||||
});
|
});
|
||||||
// #enddocregion route-good-id
|
// #enddocregion route-good-id
|
||||||
|
|
||||||
// #docregion route-no-id
|
// #docregion route-no-id
|
||||||
describe('when navigate with no hero id', () => {
|
describe('when navigate with no hero id', () => {
|
||||||
beforeEach(waitForAsync(createComponent));
|
beforeEach(async( createComponent ));
|
||||||
|
|
||||||
it('should have hero.id === 0', () => {
|
it('should have hero.id === 0', () => {
|
||||||
expect(component.hero.id).toBe(0);
|
expect(component.hero.id).toBe(0);
|
||||||
@ -232,8 +236,8 @@ function heroModuleSetup() {
|
|||||||
|
|
||||||
// #docregion route-bad-id
|
// #docregion route-bad-id
|
||||||
describe('when navigate to non-existent hero id', () => {
|
describe('when navigate to non-existent hero id', () => {
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
activatedRoute.setParamMap({id: 99999});
|
activatedRoute.setParamMap({ id: 99999 });
|
||||||
createComponent();
|
createComponent();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -249,10 +253,11 @@ function heroModuleSetup() {
|
|||||||
let service: HeroDetailService;
|
let service: HeroDetailService;
|
||||||
fixture = TestBed.createComponent(HeroDetailComponent);
|
fixture = TestBed.createComponent(HeroDetailComponent);
|
||||||
expect(
|
expect(
|
||||||
// Throws because `inject` only has access to TestBed's injector
|
// Throws because `inject` only has access to TestBed's injector
|
||||||
// which is an ancestor of the component's injector
|
// which is an ancestor of the component's injector
|
||||||
inject([HeroDetailService], (hds: HeroDetailService) => service = hds))
|
inject([HeroDetailService], (hds: HeroDetailService) => service = hds )
|
||||||
.toThrowError(/No provider for HeroDetailService/);
|
)
|
||||||
|
.toThrowError(/No provider for HeroDetailService/);
|
||||||
|
|
||||||
// get `HeroDetailService` with component's own injector
|
// get `HeroDetailService` with component's own injector
|
||||||
service = fixture.debugElement.injector.get(HeroDetailService);
|
service = fixture.debugElement.injector.get(HeroDetailService);
|
||||||
@ -265,31 +270,30 @@ import { FormsModule } from '@angular/forms';
|
|||||||
import { TitleCasePipe } from '../shared/title-case.pipe';
|
import { TitleCasePipe } from '../shared/title-case.pipe';
|
||||||
|
|
||||||
function formsModuleSetup() {
|
function formsModuleSetup() {
|
||||||
// #docregion setup-forms-module
|
// #docregion setup-forms-module
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
const routerSpy = createRouterSpy();
|
const routerSpy = createRouterSpy();
|
||||||
|
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
imports: [ FormsModule ],
|
||||||
imports: [FormsModule],
|
declarations: [ HeroDetailComponent, TitleCasePipe ],
|
||||||
declarations: [HeroDetailComponent, TitleCasePipe],
|
providers: [
|
||||||
providers: [
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
{provide: ActivatedRoute, useValue: activatedRoute},
|
{ provide: HeroService, useClass: TestHeroService },
|
||||||
{provide: HeroService, useClass: TestHeroService},
|
{ provide: Router, useValue: routerSpy},
|
||||||
{provide: Router, useValue: routerSpy},
|
]
|
||||||
]
|
})
|
||||||
})
|
.compileComponents();
|
||||||
.compileComponents();
|
|
||||||
}));
|
}));
|
||||||
// #enddocregion setup-forms-module
|
// #enddocregion setup-forms-module
|
||||||
|
|
||||||
it('should display 1st hero\'s name', waitForAsync(() => {
|
it('should display 1st hero\'s name', async(() => {
|
||||||
const expectedHero = firstHero;
|
const expectedHero = firstHero;
|
||||||
activatedRoute.setParamMap({id: expectedHero.id});
|
activatedRoute.setParamMap({ id: expectedHero.id });
|
||||||
createComponent().then(() => {
|
createComponent().then(() => {
|
||||||
expect(page.nameDisplay.textContent).toBe(expectedHero.name);
|
expect(page.nameDisplay.textContent).toBe(expectedHero.name);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@ -297,30 +301,29 @@ import { SharedModule } from '../shared/shared.module';
|
|||||||
|
|
||||||
function sharedModuleSetup() {
|
function sharedModuleSetup() {
|
||||||
// #docregion setup-shared-module
|
// #docregion setup-shared-module
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
const routerSpy = createRouterSpy();
|
const routerSpy = createRouterSpy();
|
||||||
|
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
imports: [ SharedModule ],
|
||||||
imports: [SharedModule],
|
declarations: [ HeroDetailComponent ],
|
||||||
declarations: [HeroDetailComponent],
|
providers: [
|
||||||
providers: [
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
{provide: ActivatedRoute, useValue: activatedRoute},
|
{ provide: HeroService, useClass: TestHeroService },
|
||||||
{provide: HeroService, useClass: TestHeroService},
|
{ provide: Router, useValue: routerSpy},
|
||||||
{provide: Router, useValue: routerSpy},
|
]
|
||||||
]
|
})
|
||||||
})
|
.compileComponents();
|
||||||
.compileComponents();
|
|
||||||
}));
|
}));
|
||||||
// #enddocregion setup-shared-module
|
// #enddocregion setup-shared-module
|
||||||
|
|
||||||
it('should display 1st hero\'s name', waitForAsync(() => {
|
it('should display 1st hero\'s name', async(() => {
|
||||||
const expectedHero = firstHero;
|
const expectedHero = firstHero;
|
||||||
activatedRoute.setParamMap({id: expectedHero.id});
|
activatedRoute.setParamMap({ id: expectedHero.id });
|
||||||
createComponent().then(() => {
|
createComponent().then(() => {
|
||||||
expect(page.nameDisplay.textContent).toBe(expectedHero.name);
|
expect(page.nameDisplay.textContent).toBe(expectedHero.name);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////// Helpers /////
|
/////////// Helpers /////
|
||||||
@ -344,21 +347,11 @@ function createComponent() {
|
|||||||
// #docregion page
|
// #docregion page
|
||||||
class Page {
|
class Page {
|
||||||
// getter properties wait to query the DOM until called.
|
// getter properties wait to query the DOM until called.
|
||||||
get buttons() {
|
get buttons() { return this.queryAll<HTMLButtonElement>('button'); }
|
||||||
return this.queryAll<HTMLButtonElement>('button');
|
get saveBtn() { return this.buttons[0]; }
|
||||||
}
|
get cancelBtn() { return this.buttons[1]; }
|
||||||
get saveBtn() {
|
get nameDisplay() { return this.query<HTMLElement>('span'); }
|
||||||
return this.buttons[0];
|
get nameInput() { return this.query<HTMLInputElement>('input'); }
|
||||||
}
|
|
||||||
get cancelBtn() {
|
|
||||||
return this.buttons[1];
|
|
||||||
}
|
|
||||||
get nameDisplay() {
|
|
||||||
return this.query<HTMLElement>('span');
|
|
||||||
}
|
|
||||||
get nameInput() {
|
|
||||||
return this.query<HTMLInputElement>('input');
|
|
||||||
}
|
|
||||||
|
|
||||||
gotoListSpy: jasmine.Spy;
|
gotoListSpy: jasmine.Spy;
|
||||||
navigateSpy: jasmine.Spy;
|
navigateSpy: jasmine.Spy;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync
|
import { async, ComponentFixture, fakeAsync, TestBed, tick
|
||||||
} from '@angular/core/testing';
|
} from '@angular/core/testing';
|
||||||
|
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
@ -6,13 +6,14 @@ import { DebugElement } from '@angular/core';
|
|||||||
|
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { addMatchers } from '../../testing';
|
import { addMatchers, newEvent } from '../../testing';
|
||||||
import { HeroService } from '../model/hero.service';
|
|
||||||
import { getTestHeroes, TestHeroService } from '../model/testing/test-hero.service';
|
import { getTestHeroes, TestHeroService } from '../model/testing/test-hero.service';
|
||||||
|
|
||||||
import { HeroModule } from './hero.module';
|
import { HeroModule } from './hero.module';
|
||||||
import { HeroListComponent } from './hero-list.component';
|
import { HeroListComponent } from './hero-list.component';
|
||||||
import { HighlightDirective } from '../shared/highlight.directive';
|
import { HighlightDirective } from '../shared/highlight.directive';
|
||||||
|
import { HeroService } from '../model/hero.service';
|
||||||
|
|
||||||
const HEROES = getTestHeroes();
|
const HEROES = getTestHeroes();
|
||||||
|
|
||||||
@ -23,20 +24,20 @@ let page: Page;
|
|||||||
/////// Tests //////
|
/////// Tests //////
|
||||||
|
|
||||||
describe('HeroListComponent', () => {
|
describe('HeroListComponent', () => {
|
||||||
beforeEach(waitForAsync(() => {
|
|
||||||
|
beforeEach(async(() => {
|
||||||
addMatchers();
|
addMatchers();
|
||||||
const routerSpy = jasmine.createSpyObj('Router', ['navigate']);
|
const routerSpy = jasmine.createSpyObj('Router', ['navigate']);
|
||||||
|
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
imports: [HeroModule],
|
||||||
imports: [HeroModule],
|
providers: [
|
||||||
providers: [
|
{ provide: HeroService, useClass: TestHeroService },
|
||||||
{provide: HeroService, useClass: TestHeroService},
|
{ provide: Router, useValue: routerSpy}
|
||||||
{provide: Router, useValue: routerSpy}
|
]
|
||||||
]
|
})
|
||||||
})
|
.compileComponents()
|
||||||
.compileComponents()
|
.then(createComponent);
|
||||||
.then(createComponent);
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should display heroes', () => {
|
it('should display heroes', () => {
|
||||||
@ -51,41 +52,36 @@ describe('HeroListComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should select hero on click', fakeAsync(() => {
|
it('should select hero on click', fakeAsync(() => {
|
||||||
const expectedHero = HEROES[1];
|
const expectedHero = HEROES[1];
|
||||||
const li = page.heroRows[1];
|
const li = page.heroRows[1];
|
||||||
|
li.dispatchEvent(newEvent('click'));
|
||||||
// In older browsers, such as IE, you might need a CustomEvent instead. See
|
tick();
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
|
// `.toEqual` because selectedHero is clone of expectedHero; see FakeHeroService
|
||||||
li.dispatchEvent(new Event('click'));
|
expect(comp.selectedHero).toEqual(expectedHero);
|
||||||
tick();
|
}));
|
||||||
// `.toEqual` because selectedHero is clone of expectedHero; see FakeHeroService
|
|
||||||
expect(comp.selectedHero).toEqual(expectedHero);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should navigate to selected hero detail on click', fakeAsync(() => {
|
it('should navigate to selected hero detail on click', fakeAsync(() => {
|
||||||
const expectedHero = HEROES[1];
|
const expectedHero = HEROES[1];
|
||||||
const li = page.heroRows[1];
|
const li = page.heroRows[1];
|
||||||
|
li.dispatchEvent(newEvent('click'));
|
||||||
|
tick();
|
||||||
|
|
||||||
// In older browsers, such as IE, you might need a CustomEvent instead. See
|
// should have navigated
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
|
expect(page.navSpy.calls.any()).toBe(true, 'navigate called');
|
||||||
li.dispatchEvent(new Event('click'));
|
|
||||||
tick();
|
|
||||||
|
|
||||||
// should have navigated
|
// composed hero detail will be URL like 'heroes/42'
|
||||||
expect(page.navSpy.calls.any()).toBe(true, 'navigate called');
|
// expect link array with the route path and hero id
|
||||||
|
// first argument to router.navigate is link array
|
||||||
|
const navArgs = page.navSpy.calls.first().args[0];
|
||||||
|
expect(navArgs[0]).toContain('heroes', 'nav to heroes detail URL');
|
||||||
|
expect(navArgs[1]).toBe(expectedHero.id, 'expected hero.id');
|
||||||
|
|
||||||
// composed hero detail will be URL like 'heroes/42'
|
}));
|
||||||
// expect link array with the route path and hero id
|
|
||||||
// first argument to router.navigate is link array
|
|
||||||
const navArgs = page.navSpy.calls.first().args[0];
|
|
||||||
expect(navArgs[0]).toContain('heroes', 'nav to heroes detail URL');
|
|
||||||
expect(navArgs[1]).toBe(expectedHero.id, 'expected hero.id');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should find `HighlightDirective` with `By.directive', () => {
|
it('should find `HighlightDirective` with `By.directive', () => {
|
||||||
// #docregion by
|
// #docregion by
|
||||||
// Can find DebugElement either by css selector or by directive
|
// Can find DebugElement either by css selector or by directive
|
||||||
const h2 = fixture.debugElement.query(By.css('h2'));
|
const h2 = fixture.debugElement.query(By.css('h2'));
|
||||||
const directive = fixture.debugElement.query(By.directive(HighlightDirective));
|
const directive = fixture.debugElement.query(By.directive(HighlightDirective));
|
||||||
// #enddocregion by
|
// #enddocregion by
|
||||||
expect(h2).toBe(directive);
|
expect(h2).toBe(directive);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
// #docregion without-toBlob-macrotask
|
// #docregion without-toBlob-macrotask
|
||||||
import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
|
import { TestBed, async, tick, fakeAsync } from '@angular/core/testing';
|
||||||
|
|
||||||
import { CanvasComponent } from './canvas.component';
|
import { CanvasComponent } from './canvas.component';
|
||||||
|
|
||||||
describe('CanvasComponent', () => {
|
describe('CanvasComponent', () => {
|
||||||
@ -11,29 +10,29 @@ describe('CanvasComponent', () => {
|
|||||||
(window as any).__zone_symbol__FakeAsyncTestMacroTask = [
|
(window as any).__zone_symbol__FakeAsyncTestMacroTask = [
|
||||||
{
|
{
|
||||||
source: 'HTMLCanvasElement.toBlob',
|
source: 'HTMLCanvasElement.toBlob',
|
||||||
callbackArgs: [{size: 200}],
|
callbackArgs: [{ size: 200 }],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
// #enddocregion enable-toBlob-macrotask
|
// #enddocregion enable-toBlob-macrotask
|
||||||
// #docregion without-toBlob-macrotask
|
// #docregion without-toBlob-macrotask
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
declarations: [
|
||||||
declarations: [CanvasComponent],
|
CanvasComponent
|
||||||
})
|
],
|
||||||
.compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should be able to generate blob data from canvas', fakeAsync(() => {
|
it('should be able to generate blob data from canvas', fakeAsync(() => {
|
||||||
const fixture = TestBed.createComponent(CanvasComponent);
|
const fixture = TestBed.createComponent(CanvasComponent);
|
||||||
const canvasComp = fixture.componentInstance;
|
const canvasComp = fixture.componentInstance;
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(canvasComp.blobSize).toBe(0);
|
expect(canvasComp.blobSize).toBe(0);
|
||||||
|
|
||||||
tick();
|
tick();
|
||||||
expect(canvasComp.blobSize).toBeGreaterThan(0);
|
expect(canvasComp.blobSize).toBeGreaterThan(0);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
// #enddocregion without-toBlob-macrotask
|
// #enddocregion without-toBlob-macrotask
|
||||||
|
@ -3,6 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { HighlightDirective } from './highlight.directive';
|
import { HighlightDirective } from './highlight.directive';
|
||||||
|
import { newEvent } from '../../testing';
|
||||||
|
|
||||||
// #docregion test-component
|
// #docregion test-component
|
||||||
@Component({
|
@Component({
|
||||||
@ -58,12 +59,9 @@ describe('HighlightDirective', () => {
|
|||||||
const input = des[2].nativeElement as HTMLInputElement;
|
const input = des[2].nativeElement as HTMLInputElement;
|
||||||
expect(input.style.backgroundColor).toBe('cyan', 'initial backgroundColor');
|
expect(input.style.backgroundColor).toBe('cyan', 'initial backgroundColor');
|
||||||
|
|
||||||
|
// dispatch a DOM event so that Angular responds to the input value change.
|
||||||
input.value = 'green';
|
input.value = 'green';
|
||||||
|
input.dispatchEvent(newEvent('input'));
|
||||||
// Dispatch a DOM event so that Angular responds to the input value change.
|
|
||||||
// In older browsers, such as IE, you might need a CustomEvent instead. See
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
|
|
||||||
input.dispatchEvent(new Event('input'));
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(input.style.backgroundColor).toBe('green', 'changed backgroundColor');
|
expect(input.style.backgroundColor).toBe('green', 'changed backgroundColor');
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
import { fakeAsync, ComponentFixture, TestBed, tick, waitForAsync } from '@angular/core/testing';
|
import { async, fakeAsync, ComponentFixture, TestBed, tick } from '@angular/core/testing';
|
||||||
|
|
||||||
import { asyncData, asyncError } from '../../testing';
|
import { asyncData, asyncError } from '../../testing';
|
||||||
|
|
||||||
import { of, throwError } from 'rxjs';
|
import { of, throwError } from 'rxjs';
|
||||||
|
|
||||||
import { last } from 'rxjs/operators';
|
import { last } from 'rxjs/operators';
|
||||||
|
|
||||||
import { TwainComponent } from './twain.component';
|
|
||||||
import { TwainService } from './twain.service';
|
import { TwainService } from './twain.service';
|
||||||
|
import { TwainComponent } from './twain.component';
|
||||||
|
|
||||||
describe('TwainComponent', () => {
|
describe('TwainComponent', () => {
|
||||||
let component: TwainComponent;
|
let component: TwainComponent;
|
||||||
@ -31,12 +32,14 @@ describe('TwainComponent', () => {
|
|||||||
// Create a fake TwainService object with a `getQuote()` spy
|
// Create a fake TwainService object with a `getQuote()` spy
|
||||||
const twainService = jasmine.createSpyObj('TwainService', ['getQuote']);
|
const twainService = jasmine.createSpyObj('TwainService', ['getQuote']);
|
||||||
// Make the spy return a synchronous Observable with the test data
|
// Make the spy return a synchronous Observable with the test data
|
||||||
getQuoteSpy = twainService.getQuote.and.returnValue(of(testQuote));
|
getQuoteSpy = twainService.getQuote.and.returnValue( of(testQuote) );
|
||||||
// #enddocregion spy
|
// #enddocregion spy
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [TwainComponent],
|
declarations: [ TwainComponent ],
|
||||||
providers: [{provide: TwainService, useValue: twainService}]
|
providers: [
|
||||||
|
{ provide: TwainService, useValue: twainService }
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
fixture = TestBed.createComponent(TwainComponent);
|
fixture = TestBed.createComponent(TwainComponent);
|
||||||
@ -55,7 +58,7 @@ describe('TwainComponent', () => {
|
|||||||
// The quote would not be immediately available if the service were truly async.
|
// The quote would not be immediately available if the service were truly async.
|
||||||
// #docregion sync-test
|
// #docregion sync-test
|
||||||
it('should show quote after component initialized', () => {
|
it('should show quote after component initialized', () => {
|
||||||
fixture.detectChanges(); // onInit()
|
fixture.detectChanges(); // onInit()
|
||||||
|
|
||||||
// sync spy result shows testQuote immediately after init
|
// sync spy result shows testQuote immediately after init
|
||||||
expect(quoteEl.textContent).toBe(testQuote);
|
expect(quoteEl.textContent).toBe(testQuote);
|
||||||
@ -68,19 +71,20 @@ describe('TwainComponent', () => {
|
|||||||
// Use `fakeAsync` because the component error calls `setTimeout`
|
// Use `fakeAsync` because the component error calls `setTimeout`
|
||||||
// #docregion error-test
|
// #docregion error-test
|
||||||
it('should display error when TwainService fails', fakeAsync(() => {
|
it('should display error when TwainService fails', fakeAsync(() => {
|
||||||
// tell spy to return an error observable
|
// tell spy to return an error observable
|
||||||
getQuoteSpy.and.returnValue(throwError('TwainService test failure'));
|
getQuoteSpy.and.returnValue(
|
||||||
|
throwError('TwainService test failure'));
|
||||||
|
|
||||||
fixture.detectChanges(); // onInit()
|
fixture.detectChanges(); // onInit()
|
||||||
// sync spy errors immediately after init
|
// sync spy errors immediately after init
|
||||||
|
|
||||||
tick(); // flush the component's setTimeout()
|
tick(); // flush the component's setTimeout()
|
||||||
|
|
||||||
fixture.detectChanges(); // update errorMessage within setTimeout()
|
fixture.detectChanges(); // update errorMessage within setTimeout()
|
||||||
|
|
||||||
expect(errorMessage()).toMatch(/test failure/, 'should display error');
|
expect(errorMessage()).toMatch(/test failure/, 'should display error');
|
||||||
expect(quoteEl.textContent).toBe('...', 'should show placeholder');
|
expect(quoteEl.textContent).toBe('...', 'should show placeholder');
|
||||||
}));
|
}));
|
||||||
// #enddocregion error-test
|
// #enddocregion error-test
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -109,28 +113,28 @@ describe('TwainComponent', () => {
|
|||||||
|
|
||||||
// #docregion fake-async-test
|
// #docregion fake-async-test
|
||||||
it('should show quote after getQuote (fakeAsync)', fakeAsync(() => {
|
it('should show quote after getQuote (fakeAsync)', fakeAsync(() => {
|
||||||
fixture.detectChanges(); // ngOnInit()
|
fixture.detectChanges(); // ngOnInit()
|
||||||
expect(quoteEl.textContent).toBe('...', 'should show placeholder');
|
expect(quoteEl.textContent).toBe('...', 'should show placeholder');
|
||||||
|
|
||||||
tick(); // flush the observable to get the quote
|
tick(); // flush the observable to get the quote
|
||||||
fixture.detectChanges(); // update view
|
fixture.detectChanges(); // update view
|
||||||
|
|
||||||
expect(quoteEl.textContent).toBe(testQuote, 'should show quote');
|
expect(quoteEl.textContent).toBe(testQuote, 'should show quote');
|
||||||
expect(errorMessage()).toBeNull('should not show error');
|
expect(errorMessage()).toBeNull('should not show error');
|
||||||
}));
|
}));
|
||||||
// #enddocregion fake-async-test
|
// #enddocregion fake-async-test
|
||||||
|
|
||||||
// #docregion async-test
|
// #docregion async-test
|
||||||
it('should show quote after getQuote (async)', waitForAsync(() => {
|
it('should show quote after getQuote (async)', async(() => {
|
||||||
fixture.detectChanges(); // ngOnInit()
|
fixture.detectChanges(); // ngOnInit()
|
||||||
expect(quoteEl.textContent).toBe('...', 'should show placeholder');
|
expect(quoteEl.textContent).toBe('...', 'should show placeholder');
|
||||||
|
|
||||||
fixture.whenStable().then(() => { // wait for async getQuote
|
fixture.whenStable().then(() => { // wait for async getQuote
|
||||||
fixture.detectChanges(); // update view with quote
|
fixture.detectChanges(); // update view with quote
|
||||||
expect(quoteEl.textContent).toBe(testQuote);
|
expect(quoteEl.textContent).toBe(testQuote);
|
||||||
expect(errorMessage()).toBeNull('should not show error');
|
expect(errorMessage()).toBeNull('should not show error');
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
// #enddocregion async-test
|
// #enddocregion async-test
|
||||||
|
|
||||||
|
|
||||||
@ -138,8 +142,8 @@ describe('TwainComponent', () => {
|
|||||||
it('should show last quote (quote done)', (done: DoneFn) => {
|
it('should show last quote (quote done)', (done: DoneFn) => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
component.quote.pipe(last()).subscribe(() => {
|
component.quote.pipe( last() ).subscribe(() => {
|
||||||
fixture.detectChanges(); // update view with quote
|
fixture.detectChanges(); // update view with quote
|
||||||
expect(quoteEl.textContent).toBe(testQuote);
|
expect(quoteEl.textContent).toBe(testQuote);
|
||||||
expect(errorMessage()).toBeNull('should not show error');
|
expect(errorMessage()).toBeNull('should not show error');
|
||||||
done();
|
done();
|
||||||
@ -153,7 +157,7 @@ describe('TwainComponent', () => {
|
|||||||
|
|
||||||
// the spy's most recent call returns the observable with the test quote
|
// the spy's most recent call returns the observable with the test quote
|
||||||
getQuoteSpy.calls.mostRecent().returnValue.subscribe(() => {
|
getQuoteSpy.calls.mostRecent().returnValue.subscribe(() => {
|
||||||
fixture.detectChanges(); // update view with quote
|
fixture.detectChanges(); // update view with quote
|
||||||
expect(quoteEl.textContent).toBe(testQuote);
|
expect(quoteEl.textContent).toBe(testQuote);
|
||||||
expect(errorMessage()).toBeNull('should not show error');
|
expect(errorMessage()).toBeNull('should not show error');
|
||||||
done();
|
done();
|
||||||
@ -163,16 +167,16 @@ describe('TwainComponent', () => {
|
|||||||
|
|
||||||
// #docregion async-error-test
|
// #docregion async-error-test
|
||||||
it('should display error when TwainService fails', fakeAsync(() => {
|
it('should display error when TwainService fails', fakeAsync(() => {
|
||||||
// tell spy to return an async error observable
|
// tell spy to return an async error observable
|
||||||
getQuoteSpy.and.returnValue(asyncError<string>('TwainService test failure'));
|
getQuoteSpy.and.returnValue(asyncError<string>('TwainService test failure'));
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
tick(); // component shows error after a setTimeout()
|
tick(); // component shows error after a setTimeout()
|
||||||
fixture.detectChanges(); // update error message
|
fixture.detectChanges(); // update error message
|
||||||
|
|
||||||
expect(errorMessage()).toMatch(/test failure/, 'should display error');
|
expect(errorMessage()).toMatch(/test failure/, 'should display error');
|
||||||
expect(quoteEl.textContent).toBe('...', 'should show placeholder');
|
expect(quoteEl.textContent).toBe('...', 'should show placeholder');
|
||||||
}));
|
}));
|
||||||
// #enddocregion async-error-test
|
// #enddocregion async-error-test
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -14,6 +14,18 @@ export function advance(f: ComponentFixture<any>): void {
|
|||||||
f.detectChanges();
|
f.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create custom DOM event the old fashioned way
|
||||||
|
*
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/API/Event/initEvent
|
||||||
|
* Although officially deprecated, some browsers (phantom) don't accept the preferred "new Event(eventName)"
|
||||||
|
*/
|
||||||
|
export function newEvent(eventName: string, bubbles = false, cancelable = false) {
|
||||||
|
const evt = document.createEvent('CustomEvent'); // MUST be 'CustomEvent'
|
||||||
|
evt.initCustomEvent(eventName, bubbles, cancelable, null);
|
||||||
|
return evt;
|
||||||
|
}
|
||||||
|
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
|
// See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
|
||||||
// #docregion click-event
|
// #docregion click-event
|
||||||
/** Button events to pass to `DebugElement.triggerEventHandler` for RouterLink event handler */
|
/** Button events to pass to `DebugElement.triggerEventHandler` for RouterLink event handler */
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
|
||||||
import { of } from 'rxjs';
|
|
||||||
|
|
||||||
import { HeroSearchComponent } from '../hero-search/hero-search.component';
|
|
||||||
import { HeroService } from '../hero.service';
|
|
||||||
import { HEROES } from '../mock-heroes';
|
|
||||||
|
|
||||||
import { DashboardComponent } from './dashboard.component';
|
import { DashboardComponent } from './dashboard.component';
|
||||||
|
import { HeroSearchComponent } from '../hero-search/hero-search.component';
|
||||||
|
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { HEROES } from '../mock-heroes';
|
||||||
|
import { HeroService } from '../hero.service';
|
||||||
|
|
||||||
describe('DashboardComponent', () => {
|
describe('DashboardComponent', () => {
|
||||||
let component: DashboardComponent;
|
let component: DashboardComponent;
|
||||||
@ -14,16 +14,23 @@ describe('DashboardComponent', () => {
|
|||||||
let heroService;
|
let heroService;
|
||||||
let getHeroesSpy;
|
let getHeroesSpy;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
heroService = jasmine.createSpyObj('HeroService', ['getHeroes']);
|
heroService = jasmine.createSpyObj('HeroService', ['getHeroes']);
|
||||||
getHeroesSpy = heroService.getHeroes.and.returnValue(of(HEROES));
|
getHeroesSpy = heroService.getHeroes.and.returnValue( of(HEROES) );
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
declarations: [
|
||||||
declarations: [DashboardComponent, HeroSearchComponent],
|
DashboardComponent,
|
||||||
imports: [RouterTestingModule.withRoutes([])],
|
HeroSearchComponent
|
||||||
providers: [{provide: HeroService, useValue: heroService}]
|
],
|
||||||
})
|
imports: [
|
||||||
.compileComponents();
|
RouterTestingModule.withRoutes([])
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: HeroService, useValue: heroService }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -40,11 +47,12 @@ describe('DashboardComponent', () => {
|
|||||||
expect(fixture.nativeElement.querySelector('h3').textContent).toEqual('Top Heroes');
|
expect(fixture.nativeElement.querySelector('h3').textContent).toEqual('Top Heroes');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call heroService', waitForAsync(() => {
|
it('should call heroService', async(() => {
|
||||||
expect(getHeroesSpy.calls.any()).toBe(true);
|
expect(getHeroesSpy.calls.any()).toBe(true);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should display 4 links', async(() => {
|
||||||
|
expect(fixture.nativeElement.querySelectorAll('a').length).toEqual(4);
|
||||||
|
}));
|
||||||
|
|
||||||
it('should display 4 links', waitForAsync(() => {
|
|
||||||
expect(fixture.nativeElement.querySelectorAll('a').length).toEqual(4);
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ import { HeroService } from '../hero.service';
|
|||||||
styleUrls: [ './hero-detail.component.css' ]
|
styleUrls: [ './hero-detail.component.css' ]
|
||||||
})
|
})
|
||||||
export class HeroDetailComponent implements OnInit {
|
export class HeroDetailComponent implements OnInit {
|
||||||
hero: Hero;
|
@Input() hero: Hero;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
{
|
{
|
||||||
"extends": "tslint:recommended",
|
"extends": "tslint:recommended",
|
||||||
"rulesDirectory": [
|
|
||||||
"codelyzer"
|
|
||||||
],
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"align": {
|
"align": {
|
||||||
"options": [
|
"options": [
|
||||||
@ -16,6 +13,22 @@
|
|||||||
"deprecation": {
|
"deprecation": {
|
||||||
"severity": "warning"
|
"severity": "warning"
|
||||||
},
|
},
|
||||||
|
"component-class-suffix": true,
|
||||||
|
"component-selector": [
|
||||||
|
true,
|
||||||
|
"element",
|
||||||
|
// TODO: Fix the code and change the prefix to `"app"` (or whatever makes sense).
|
||||||
|
"",
|
||||||
|
"kebab-case"
|
||||||
|
],
|
||||||
|
"contextual-lifecycle": true,
|
||||||
|
"directive-class-suffix": true,
|
||||||
|
"directive-selector": [
|
||||||
|
true,
|
||||||
|
"attribute",
|
||||||
|
["app", "toh"],
|
||||||
|
"camelCase"
|
||||||
|
],
|
||||||
"eofline": true,
|
"eofline": true,
|
||||||
"import-blacklist": [
|
"import-blacklist": [
|
||||||
true,
|
true,
|
||||||
@ -43,8 +56,6 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
// TODO(gkalpak): Fix the code and enable this.
|
|
||||||
// "no-any": true,
|
|
||||||
"no-console": [
|
"no-console": [
|
||||||
true,
|
true,
|
||||||
"debug",
|
"debug",
|
||||||
@ -84,11 +95,6 @@
|
|||||||
"named": "never"
|
"named": "never"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// TODO(gkalpak): Fix the code and enable this.
|
|
||||||
// "typedef": [
|
|
||||||
// true,
|
|
||||||
// "call-signature"
|
|
||||||
// ],
|
|
||||||
"typedef-whitespace": {
|
"typedef-whitespace": {
|
||||||
"options": [
|
"options": [
|
||||||
{
|
{
|
||||||
@ -124,9 +130,6 @@
|
|||||||
"check-typecast"
|
"check-typecast"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"component-class-suffix": true,
|
|
||||||
"contextual-lifecycle": true,
|
|
||||||
"directive-class-suffix": true,
|
|
||||||
"no-conflicting-lifecycle": true,
|
"no-conflicting-lifecycle": true,
|
||||||
"no-host-metadata-property": true,
|
"no-host-metadata-property": true,
|
||||||
"no-input-rename": true,
|
"no-input-rename": true,
|
||||||
@ -138,19 +141,9 @@
|
|||||||
"template-banana-in-box": true,
|
"template-banana-in-box": true,
|
||||||
"template-no-negated-async": true,
|
"template-no-negated-async": true,
|
||||||
"use-lifecycle-interface": true,
|
"use-lifecycle-interface": true,
|
||||||
"use-pipe-transform-interface": true,
|
"use-pipe-transform-interface": true
|
||||||
"directive-selector": [
|
},
|
||||||
true,
|
"rulesDirectory": [
|
||||||
"attribute",
|
"codelyzer"
|
||||||
["app", "toh"],
|
]
|
||||||
"camelCase"
|
|
||||||
],
|
|
||||||
"component-selector": [
|
|
||||||
true,
|
|
||||||
"element",
|
|
||||||
// TODO: Fix the code and change the prefix to `"app"` (or whatever makes sense).
|
|
||||||
"",
|
|
||||||
"kebab-case"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import * as angular from 'angular';
|
import * as angular from 'angular';
|
||||||
import 'angular-route';
|
import 'angular-route';
|
||||||
|
|
||||||
const appModule = angular.module('myApp', [
|
const appName = 'myApp';
|
||||||
|
|
||||||
|
angular.module(appName, [
|
||||||
'ngRoute'
|
'ngRoute'
|
||||||
])
|
])
|
||||||
.config(['$routeProvider', '$locationProvider',
|
.config(['$routeProvider', '$locationProvider',
|
||||||
@ -23,5 +25,5 @@ const appModule = angular.module('myApp', [
|
|||||||
);
|
);
|
||||||
|
|
||||||
export function bootstrap(el: HTMLElement) {
|
export function bootstrap(el: HTMLElement) {
|
||||||
return angular.bootstrap(el, [appModule.name]);
|
return angular.bootstrap(el, [appName]);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<!-- Polyfills -->
|
<!-- Polyfills -->
|
||||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||||
|
|
||||||
<script src="node_modules/zone.js/bundles/zone.umd.js"></script>
|
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||||
|
|
||||||
<script src="systemjs.config.1.js"></script>
|
<script src="systemjs.config.1.js"></script>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<!-- Polyfills -->
|
<!-- Polyfills -->
|
||||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||||
|
|
||||||
<script src="node_modules/zone.js/bundles/zone.umd.js"></script>
|
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||||
|
|
||||||
<script src="systemjs.config.1.js"></script>
|
<script src="systemjs.config.1.js"></script>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<!-- Polyfills -->
|
<!-- Polyfills -->
|
||||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||||
|
|
||||||
<script src="node_modules/zone.js/bundles/zone.umd.js"></script>
|
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||||
|
|
||||||
<script src="systemjs.config.1.js"></script>
|
<script src="systemjs.config.1.js"></script>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<!-- Polyfills -->
|
<!-- Polyfills -->
|
||||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||||
|
|
||||||
<script src="node_modules/zone.js/bundles/zone.umd.js"></script>
|
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||||
|
|
||||||
<script src="systemjs.config.1.js"></script>
|
<script src="systemjs.config.1.js"></script>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<!-- Polyfills -->
|
<!-- Polyfills -->
|
||||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||||
|
|
||||||
<script src="node_modules/zone.js/bundles/zone.umd.js"></script>
|
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||||
|
|
||||||
<script src="systemjs.config.1.js"></script>
|
<script src="systemjs.config.1.js"></script>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<!-- Polyfills -->
|
<!-- Polyfills -->
|
||||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||||
|
|
||||||
<script src="node_modules/zone.js/bundles/zone.umd.js"></script>
|
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||||
|
|
||||||
<script src="systemjs.config.1.js"></script>
|
<script src="systemjs.config.1.js"></script>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user