Compare commits
504 Commits
11.0.0-nex
...
10.0.9
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 |
@ -653,23 +653,9 @@ jobs:
|
|||||||
name: Starting Saucelabs tunnel service
|
name: Starting Saucelabs tunnel service
|
||||||
command: ./tools/saucelabs/sauce-service.sh run
|
command: ./tools/saucelabs/sauce-service.sh run
|
||||||
background: true
|
background: true
|
||||||
# add module umd tsc compile option so the test can work
|
- run: yarn tsc -p packages
|
||||||
# properly in the legacy browsers
|
- run: yarn tsc -p modules
|
||||||
- run: yarn tsc -p packages --module UMD
|
|
||||||
- run: yarn tsc -p modules --module UMD
|
|
||||||
- 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
|
||||||
@ -745,12 +731,10 @@ 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
|
||||||
- run: yarn --cwd packages/zone.js/test/typings install --frozen-lockfile --non-interactive
|
|
||||||
- run: yarn --cwd packages/zone.js/test/typings test
|
|
||||||
|
|
||||||
# Windows jobs
|
# Windows jobs
|
||||||
# Docs: https://circleci.com/docs/2.0/hello-world-windows/
|
# Docs: https://circleci.com/docs/2.0/hello-world-windows/
|
||||||
|
2
.github/ISSUE_TEMPLATE/1-bug-report.md
vendored
2
.github/ISSUE_TEMPLATE/1-bug-report.md
vendored
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: "\U0001F41E Bug report"
|
name: "\U0001F41EBug report"
|
||||||
about: Report a bug in the Angular Framework
|
about: Report a bug in the Angular Framework
|
||||||
---
|
---
|
||||||
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
|
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
|
||||||
|
2
.github/ISSUE_TEMPLATE/2-feature-request.md
vendored
2
.github/ISSUE_TEMPLATE/2-feature-request.md
vendored
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: "\U0001F680 Feature request"
|
name: "\U0001F680Feature request"
|
||||||
about: Suggest a feature for Angular Framework
|
about: Suggest a feature for Angular Framework
|
||||||
|
|
||||||
---
|
---
|
||||||
|
2
.github/ISSUE_TEMPLATE/5-support-request.md
vendored
2
.github/ISSUE_TEMPLATE/5-support-request.md
vendored
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: "❓ Support request"
|
name: "❓Support request"
|
||||||
about: Questions and requests for support
|
about: Questions and requests for support
|
||||||
|
|
||||||
---
|
---
|
||||||
|
2
.github/ISSUE_TEMPLATE/6-angular-cli.md
vendored
2
.github/ISSUE_TEMPLATE/6-angular-cli.md
vendored
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: "\U0001F6E0️ Angular CLI"
|
name: "\U0001F6E0️Angular CLI"
|
||||||
about: Issues and feature requests for Angular CLI
|
about: Issues and feature requests for Angular CLI
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: "\U0001F48E Angular Components"
|
name: "\U0001F48EAngular Components"
|
||||||
about: Issues and feature requests for Angular Components
|
about: Issues and feature requests for Angular Components
|
||||||
|
|
||||||
---
|
---
|
||||||
|
28
.github/angular-robot.yml
vendored
28
.github/angular-robot.yml
vendored
@ -73,14 +73,15 @@ merge:
|
|||||||
- "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:
|
||||||
@ -93,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
|
||||||
@ -120,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:
|
||||||
@ -180,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"
|
||||||
|
2
.github/workflows/lock-closed.yml
vendored
2
.github/workflows/lock-closed.yml
vendored
@ -10,6 +10,6 @@ jobs:
|
|||||||
if: github.repository == 'angular/angular'
|
if: github.repository == 'angular/angular'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: angular/dev-infra/github-actions/lock-closed@414834b2b24dd2df37c6ed00808387ee6fd91b66
|
- uses: angular/dev-infra/github-actions/lock-closed@66462f6
|
||||||
with:
|
with:
|
||||||
lock-bot-key: ${{ secrets.LOCK_BOT_PRIVATE_KEY }}
|
lock-bot-key: ${{ secrets.LOCK_BOT_PRIVATE_KEY }}
|
||||||
|
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: 'Primary 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,4 +1,3 @@
|
|||||||
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';
|
||||||
@ -9,5 +8,4 @@ module.exports = {
|
|||||||
format,
|
format,
|
||||||
github,
|
github,
|
||||||
merge,
|
merge,
|
||||||
caretaker,
|
|
||||||
};
|
};
|
||||||
|
@ -1,25 +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';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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',
|
||||||
labels: await getDefaultTargetLabelConfiguration(api, github, '@angular/core'),
|
labels: [
|
||||||
|
{
|
||||||
|
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'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
# =========================================================
|
# =========================================================
|
||||||
@ -335,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/**',
|
||||||
@ -787,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
|
||||||
@ -1110,7 +1091,6 @@ 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',
|
||||||
|
@ -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.
|
||||||
|
441
CHANGELOG.md
441
CHANGELOG.md
@ -1,263 +1,3 @@
|
|||||||
<a name="11.0.0-next.2"></a>
|
|
||||||
# 11.0.0-next.2 (2020-09-16)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **common:** do not round up fractions of a millisecond in `DatePipe` ([#38009](https://github.com/angular/angular/issues/38009)) ([26f2820](https://github.com/angular/angular/commit/26f2820)), closes [/www.ecma-international.org/ecma-262/5.1/#sec-15](https://github.com//www.ecma-international.org/ecma-262/5.1//issues/sec-15) [#37989](https://github.com/angular/angular/issues/37989)
|
|
||||||
* **common:** mark locale data arrays as readonly ([#30397](https://github.com/angular/angular/issues/30397)) ([6acea54](https://github.com/angular/angular/commit/6acea54)), closes [#27003](https://github.com/angular/angular/issues/27003)
|
|
||||||
* **compiler:** source span for microsyntax text att should be key span ([#38766](https://github.com/angular/angular/issues/38766)) ([8f349b2](https://github.com/angular/angular/commit/8f349b2))
|
|
||||||
* **router:** Fix arguments order for call to shouldReuseRoute ([#26949](https://github.com/angular/angular/issues/26949)) ([3817e5f](https://github.com/angular/angular/commit/3817e5f)), closes [#16192](https://github.com/angular/angular/issues/16192) [#16192](https://github.com/angular/angular/issues/16192)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **compiler-cli:** `TemplateTypeChecker` operation to get `Symbol` from a template node ([#38618](https://github.com/angular/angular/issues/38618)) ([c4556db](https://github.com/angular/angular/commit/c4556db))
|
|
||||||
* **compiler-cli:** Add ability to get `Symbol` of `Template`s and `Element`s in component template ([#38618](https://github.com/angular/angular/issues/38618)) ([cf2e8b9](https://github.com/angular/angular/commit/cf2e8b9))
|
|
||||||
* **compiler-cli:** Add ability to get `Symbol` of AST expression in component template ([#38618](https://github.com/angular/angular/issues/38618)) ([f56ece4](https://github.com/angular/angular/commit/f56ece4))
|
|
||||||
* **compiler-cli:** add ability to get symbol of reference or variable ([#38618](https://github.com/angular/angular/issues/38618)) ([19598b4](https://github.com/angular/angular/commit/19598b4))
|
|
||||||
* **compiler-cli:** define interfaces to be used for TemplateTypeChecker ([#38618](https://github.com/angular/angular/issues/38618)) ([9e77bd3](https://github.com/angular/angular/commit/9e77bd3))
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* **compiler-cli:** only emit directive/pipe references that are used ([#38539](https://github.com/angular/angular/issues/38539)) ([077f516](https://github.com/angular/angular/commit/077f516))
|
|
||||||
* **compiler-cli:** optimize computation of type-check scope information ([#38539](https://github.com/angular/angular/issues/38539)) ([297c060](https://github.com/angular/angular/commit/297c060))
|
|
||||||
* **router:** use `ngDevMode` to tree-shake error messages in router ([#38674](https://github.com/angular/angular/issues/38674)) ([db21c4f](https://github.com/angular/angular/commit/db21c4f))
|
|
||||||
|
|
||||||
|
|
||||||
### BREAKING CHANGES
|
|
||||||
|
|
||||||
* **router:** This change corrects the argument order when calling
|
|
||||||
RouteReuseStrategy#shouldReuseRoute. Previously, when evaluating child
|
|
||||||
routes, they would be called with the future and current arguments would
|
|
||||||
be swapped. If your RouteReuseStrategy relies specifically on only the future
|
|
||||||
or current snapshot state, you may need to update the shouldReuseRoute
|
|
||||||
implementation's use of "future" and "current" ActivateRouteSnapshots.
|
|
||||||
* **common:** The locale data API has been marked as returning readonly arrays, rather
|
|
||||||
than mutable arrays, since these arrays are shared across calls to the
|
|
||||||
API. If you were mutating them (e.g. calling `sort()`, `push()`, `splice()`, etc)
|
|
||||||
then your code will not longer compile. If you need to mutate the array, you
|
|
||||||
should now take a copy (e.g. by calling `slice()`) and mutate the copy.
|
|
||||||
* **common:** When passing a date-time formatted string to the `DatePipe` in a format that contains
|
|
||||||
fractions of a millisecond, the milliseconds will now always be rounded down rather than
|
|
||||||
to the nearest millisecond.
|
|
||||||
|
|
||||||
Most applications will not be affected by this change. If this is not the desired behaviour
|
|
||||||
then consider pre-processing the string to round the millisecond part before passing
|
|
||||||
it to the `DatePipe`.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<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="11.0.0-next.1"></a>
|
|
||||||
# 11.0.0-next.1 (2020-09-09)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compiler-cli:** compute source-mappings for localized strings ([#38645](https://github.com/angular/angular/issues/38645)) ([7e0b3fd](https://github.com/angular/angular/commit/7e0b3fd)), closes [#38588](https://github.com/angular/angular/issues/38588)
|
|
||||||
* **core:** remove CollectionChangeRecord symbol ([#38668](https://github.com/angular/angular/issues/38668)) ([fdea180](https://github.com/angular/angular/commit/fdea180))
|
|
||||||
* **router:** support lazy loading for empty path named outlets ([#38379](https://github.com/angular/angular/issues/38379)) ([926ffcd](https://github.com/angular/angular/commit/926ffcd)), closes [#12842](https://github.com/angular/angular/issues/12842)
|
|
||||||
|
|
||||||
|
|
||||||
### BREAKING CHANGES
|
|
||||||
|
|
||||||
* **core:** CollectionChangeRecord has been removed, use IterableChangeRecord
|
|
||||||
instead
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<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="11.0.0-next.0"></a>
|
|
||||||
# 11.0.0-next.0 (2020-09-02)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **forms:** ensure to emit `statusChanges` on subsequent value update/validations ([#38354](https://github.com/angular/angular/issues/38354)) ([d9fea85](https://github.com/angular/angular/commit/d9fea85)), closes [#20424](https://github.com/angular/angular/issues/20424) [#14542](https://github.com/angular/angular/issues/14542)
|
|
||||||
* **service-worker:** fix condition to check for a cache-busted request ([#36847](https://github.com/angular/angular/issues/36847)) ([5be4edf](https://github.com/angular/angular/commit/5be4edf))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **service-worker:** add `UnrecoverableStateError` ([#36847](https://github.com/angular/angular/issues/36847)) ([036a2fa](https://github.com/angular/angular/commit/036a2fa)), closes [#36539](https://github.com/angular/angular/issues/36539)
|
|
||||||
|
|
||||||
|
|
||||||
### BREAKING CHANGES
|
|
||||||
|
|
||||||
* **forms:** Previously if FormControl, FormGroup and FormArray class instances had async validators
|
|
||||||
defined at initialization time, the status change event was not emitted once async validator
|
|
||||||
completed. After this change the status event is emitted into the `statusChanges` observable.
|
|
||||||
If your code relies on the old behavior, you can filter/ignore this additional status change
|
|
||||||
event.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<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)
|
||||||
|
|
||||||
@ -279,6 +19,7 @@ event.
|
|||||||
* **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)
|
||||||
|
|
||||||
@ -347,6 +88,7 @@ event.
|
|||||||
* **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)
|
||||||
|
|
||||||
@ -357,16 +99,6 @@ event.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<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)
|
||||||
|
|
||||||
@ -478,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))
|
||||||
@ -628,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.
|
||||||
@ -641,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.
|
||||||
|
|
||||||
@ -734,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)
|
||||||
|
|
||||||
@ -799,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)
|
||||||
|
|
||||||
@ -845,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)
|
||||||
|
|
||||||
@ -860,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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -882,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))
|
||||||
|
|
||||||
|
|
||||||
@ -902,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))
|
||||||
@ -979,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)
|
||||||
@ -990,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)
|
||||||
@ -1027,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))
|
||||||
@ -1058,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)
|
||||||
@ -1315,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)
|
||||||
@ -1446,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))
|
||||||
@ -1525,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)
|
||||||
@ -1555,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))
|
||||||
@ -1612,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))
|
||||||
@ -1721,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))
|
||||||
@ -1763,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))
|
||||||
@ -1979,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).
|
||||||
|
|
||||||
@ -2142,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))
|
||||||
|
|
||||||
@ -2171,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>
|
||||||
@ -2348,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))
|
||||||
@ -2464,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))
|
||||||
@ -2490,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))
|
||||||
@ -2552,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:
|
||||||
@ -2704,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>
|
||||||
@ -2800,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
|
||||||
|
|
||||||
|
|
||||||
@ -2947,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>
|
||||||
@ -3052,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
|
||||||
@ -3224,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))
|
||||||
@ -3235,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)
|
||||||
@ -3270,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))
|
||||||
@ -3470,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)
|
||||||
@ -3688,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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -4083,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)
|
||||||
@ -4118,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))
|
||||||
@ -4482,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)
|
||||||
@ -4590,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)
|
||||||
|
|
||||||
@ -4825,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))
|
||||||
@ -4841,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))
|
||||||
@ -4867,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))
|
||||||
@ -5604,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))
|
||||||
|
|
||||||
@ -6143,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))
|
||||||
|
|
||||||
|
@ -230,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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
@ -1,9 +0,0 @@
|
|||||||
/*
|
|
||||||
* This example project is special in that it is not a cli app. To run tests appropriate for this
|
|
||||||
* project, the test command is overwritten in `aio/content/examples/observables/example-config.json`.
|
|
||||||
*
|
|
||||||
* This is an empty placeholder file to ensure that `aio/tools/examples/run-example-e2e.js` runs
|
|
||||||
* tests for this project.
|
|
||||||
*
|
|
||||||
* TODO: Fix our infrastructure/tooling, so that this hack is not necessary.
|
|
||||||
*/
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"cmd": "yarn",
|
|
||||||
"args": ["tsc", "--project", "tsconfig.spec.json", "--module", "commonjs"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cmd": "yarn",
|
|
||||||
"args": ["jasmine", "out-tsc/**/*.spec.js"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
import { docRegionChain, docRegionObservable, docRegionUnsubscribe } from './observables';
|
|
||||||
|
|
||||||
describe('observables', () => {
|
|
||||||
it('should print 2', (doneFn: DoneFn) => {
|
|
||||||
const consoleLogSpy = spyOn(console, 'log');
|
|
||||||
const observable = docRegionObservable(console);
|
|
||||||
observable.subscribe(() => {
|
|
||||||
expect(consoleLogSpy).toHaveBeenCalledTimes(1);
|
|
||||||
expect(consoleLogSpy).toHaveBeenCalledWith(2);
|
|
||||||
doneFn();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should close the subscription', () => {
|
|
||||||
const subscription = docRegionUnsubscribe();
|
|
||||||
expect(subscription.closed).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should chain an observable', (doneFn: DoneFn) => {
|
|
||||||
const observable = docRegionChain();
|
|
||||||
observable.subscribe(value => {
|
|
||||||
expect(value).toBe(4);
|
|
||||||
doneFn();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,72 +1,40 @@
|
|||||||
// #docplaster
|
|
||||||
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
export function docRegionObservable(console: Console) {
|
// #docregion observable
|
||||||
// #docregion observable
|
|
||||||
|
|
||||||
// declare a publishing operation
|
// declare a publishing operation
|
||||||
const observable = new Observable<number>(observer => {
|
const observable = new Observable<number>(observer => {
|
||||||
// Subscriber fn...
|
// Subscriber fn...
|
||||||
// #enddocregion observable
|
});
|
||||||
// The below code is used for unit testing only
|
|
||||||
observer.next(2);
|
|
||||||
// #docregion observable
|
|
||||||
});
|
|
||||||
|
|
||||||
// initiate execution
|
// initiate execution
|
||||||
observable.subscribe(value => {
|
observable.subscribe(() => {
|
||||||
// observer handles notifications
|
// observer handles notifications
|
||||||
// #enddocregion observable
|
});
|
||||||
// The below code is used for unit testing only
|
|
||||||
console.log(value);
|
|
||||||
// #docregion observable
|
|
||||||
});
|
|
||||||
|
|
||||||
// #enddocregion observable
|
// #enddocregion observable
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function docRegionUnsubscribe() {
|
// #docregion unsubscribe
|
||||||
const observable = new Observable<number>(() => {
|
|
||||||
// Subscriber fn...
|
|
||||||
});
|
|
||||||
// #docregion unsubscribe
|
|
||||||
|
|
||||||
const subscription = observable.subscribe(() => {
|
const subscription = observable.subscribe(() => {
|
||||||
// observer handles notifications
|
// observer handles notifications
|
||||||
});
|
});
|
||||||
|
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
|
|
||||||
// #enddocregion unsubscribe
|
// #enddocregion unsubscribe
|
||||||
return subscription;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function docRegionError() {
|
// #docregion error
|
||||||
const observable = new Observable<number>(() => {
|
|
||||||
// Subscriber fn...
|
|
||||||
});
|
|
||||||
|
|
||||||
// #docregion error
|
observable.subscribe(() => {
|
||||||
observable.subscribe(() => {
|
throw Error('my error');
|
||||||
throw new Error('my error');
|
});
|
||||||
});
|
|
||||||
// #enddocregion error
|
|
||||||
}
|
|
||||||
|
|
||||||
export function docRegionChain() {
|
// #enddocregion error
|
||||||
let observable = new Observable<number>(observer => {
|
|
||||||
// Subscriber fn...
|
|
||||||
observer.next(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
observable =
|
// #docregion chain
|
||||||
// #docregion chain
|
|
||||||
|
|
||||||
observable.pipe(map(v => 2 * v));
|
observable.pipe(map(v => 2 * v));
|
||||||
|
|
||||||
// #enddocregion chain
|
// #enddocregion chain
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import { docRegionError, docRegionPromise } from './promises';
|
|
||||||
|
|
||||||
describe('promises', () => {
|
|
||||||
it('should print 2', (doneFn: DoneFn) => {
|
|
||||||
const consoleLogSpy = spyOn(console, 'log');
|
|
||||||
const pr = docRegionPromise(console, 2);
|
|
||||||
pr.then((value) => {
|
|
||||||
expect(consoleLogSpy).toHaveBeenCalledTimes(1);
|
|
||||||
expect(consoleLogSpy).toHaveBeenCalledWith(2);
|
|
||||||
expect(value).toBe(4);
|
|
||||||
doneFn();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error', (doneFn: DoneFn) => {
|
|
||||||
const promise = docRegionError();
|
|
||||||
promise
|
|
||||||
.then(() => {
|
|
||||||
throw new Error('Promise should be rejected.');
|
|
||||||
},
|
|
||||||
() => doneFn());
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,44 +1,25 @@
|
|||||||
// #docplaster
|
// #docregion promise
|
||||||
|
// initiate execution
|
||||||
|
const promise = new Promise<number>((resolve, reject) => {
|
||||||
|
// Executer fn...
|
||||||
|
});
|
||||||
|
|
||||||
export function docRegionPromise(console: Console, inputValue: number) {
|
promise.then(value => {
|
||||||
// #docregion promise
|
// handle result here
|
||||||
// initiate execution
|
});
|
||||||
let promise = new Promise<number>((resolve, reject) => {
|
|
||||||
// Executer fn...
|
|
||||||
// #enddocregion promise
|
|
||||||
// The below is used in the unit tests.
|
|
||||||
resolve(inputValue);
|
|
||||||
// #docregion promise
|
|
||||||
});
|
|
||||||
// #enddocregion promise
|
|
||||||
promise =
|
|
||||||
// #docregion promise
|
|
||||||
promise.then(value => {
|
|
||||||
// handle result here
|
|
||||||
// #enddocregion promise
|
|
||||||
// The below is used in the unit tests.
|
|
||||||
console.log(value);
|
|
||||||
return value;
|
|
||||||
// #docregion promise
|
|
||||||
});
|
|
||||||
// #enddocregion promise
|
|
||||||
promise =
|
|
||||||
// #docregion chain
|
|
||||||
promise.then(v => 2 * v);
|
|
||||||
// #enddocregion chain
|
|
||||||
|
|
||||||
return promise;
|
// #enddocregion promise
|
||||||
}
|
|
||||||
|
|
||||||
export function docRegionError() {
|
// #docregion chain
|
||||||
let promise = Promise.resolve();
|
|
||||||
promise =
|
|
||||||
// #docregion error
|
|
||||||
|
|
||||||
promise.then(() => {
|
promise.then(v => 2 * v);
|
||||||
throw new Error('my error');
|
|
||||||
});
|
|
||||||
|
|
||||||
// #enddocregion error
|
// #enddocregion chain
|
||||||
return promise;
|
|
||||||
}
|
// #docregion error
|
||||||
|
|
||||||
|
promise.then(() => {
|
||||||
|
throw Error('my error');
|
||||||
|
});
|
||||||
|
|
||||||
|
// #enddocregion error
|
||||||
|
@ -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
|
||||||
});
|
});
|
||||||
|
@ -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,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,17 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { SwUpdate } from '@angular/service-worker';
|
|
||||||
|
|
||||||
function notifyUser(message: string): void { }
|
|
||||||
|
|
||||||
// #docregion sw-unrecoverable-state
|
|
||||||
@Injectable()
|
|
||||||
export class HandleUnrecoverableStateService {
|
|
||||||
constructor(updates: SwUpdate) {
|
|
||||||
updates.unrecoverable.subscribe(event => {
|
|
||||||
notifyUser(
|
|
||||||
`An error occurred that we cannot recover from:\n${event.reason}\n\n` +
|
|
||||||
'Please reload the page.');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// #enddocregion sw-unrecoverable-state
|
|
@ -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, newEvent, 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';
|
||||||
|
|
||||||
@ -279,10 +278,10 @@ describe('demo (with TestBed):', () => {
|
|||||||
input.dispatchEvent(newEvent('input'));
|
input.dispatchEvent(newEvent('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
|
||||||
@ -328,9 +327,9 @@ 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;
|
||||||
@ -382,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
|
||||||
|
|
||||||
@ -401,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');
|
||||||
@ -414,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');
|
||||||
@ -437,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');
|
||||||
@ -454,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;
|
||||||
@ -490,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>
|
||||||
@ -502,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();
|
||||||
|
|
||||||
@ -616,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();
|
||||||
|
|
||||||
@ -626,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,5 +1,8 @@
|
|||||||
// #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 {
|
||||||
@ -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,32 +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
|
page.nameInput.dispatchEvent(newEvent('input')); // tell Angular
|
||||||
|
|
||||||
expect(component.hero.name).toBe(newName, 'component hero has new name');
|
expect(component.hero.name).toBe(newName, 'component hero has new name');
|
||||||
expect(hdsSpy.testHero.name).toBe(origName, 'service hero unchanged before save');
|
expect(hdsSpy.testHero.name).toBe(origName, 'service hero unchanged before save');
|
||||||
|
|
||||||
click(page.saveBtn);
|
click(page.saveBtn);
|
||||||
expect(hdsSpy.saveHero.calls.count()).toBe(1, 'saveHero called once');
|
expect(hdsSpy.saveHero.calls.count()).toBe(1, 'saveHero called once');
|
||||||
|
|
||||||
tick(); // wait for async save to complete
|
tick(); // wait for async save to complete
|
||||||
expect(hdsSpy.testHero.name).toBe(newName, 'service hero has new name after save');
|
expect(hdsSpy.testHero.name).toBe(newName, 'service hero has new name after save');
|
||||||
expect(page.navigateSpy.calls.any()).toBe(true, 'router.navigate called');
|
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');
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
@ -130,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
|
||||||
|
|
||||||
@ -153,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);
|
||||||
@ -182,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', () => {
|
||||||
@ -207,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);
|
||||||
@ -228,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();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -245,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);
|
||||||
@ -261,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);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@ -293,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 /////
|
||||||
@ -340,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';
|
||||||
@ -7,12 +7,13 @@ import { DebugElement } from '@angular/core';
|
|||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { addMatchers, newEvent } 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,35 +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'));
|
li.dispatchEvent(newEvent('click'));
|
||||||
tick();
|
tick();
|
||||||
// `.toEqual` because selectedHero is clone of expectedHero; see FakeHeroService
|
// `.toEqual` because selectedHero is clone of expectedHero; see FakeHeroService
|
||||||
expect(comp.selectedHero).toEqual(expectedHero);
|
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'));
|
li.dispatchEvent(newEvent('click'));
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
// should have navigated
|
// should have navigated
|
||||||
expect(page.navSpy.calls.any()).toBe(true, 'navigate called');
|
expect(page.navSpy.calls.any()).toBe(true, 'navigate called');
|
||||||
|
|
||||||
// composed hero detail will be URL like 'heroes/42'
|
// composed hero detail will be URL like 'heroes/42'
|
||||||
// expect link array with the route path and hero id
|
// expect link array with the route path and hero id
|
||||||
// first argument to router.navigate is link array
|
// first argument to router.navigate is link array
|
||||||
const navArgs = page.navSpy.calls.first().args[0];
|
const navArgs = page.navSpy.calls.first().args[0];
|
||||||
expect(navArgs[0]).toContain('heroes', 'nav to heroes detail URL');
|
expect(navArgs[0]).toContain('heroes', 'nav to heroes detail URL');
|
||||||
expect(navArgs[1]).toBe(expectedHero.id, 'expected hero.id');
|
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
|
||||||
|
@ -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
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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,
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<script src="phone-detail/phone-detail.module.js"></script>
|
<script src="phone-detail/phone-detail.module.js"></script>
|
||||||
|
|
||||||
<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.min.js"></script>
|
<script src="/node_modules/zone.js/dist/zone.min.js"></script>
|
||||||
|
|
||||||
<script>window.module = 'aot';</script>
|
<script>window.module = 'aot';</script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
// #docregion activatedroute
|
// #docregion activatedroute
|
||||||
import { TestBed, waitForAsync } from '@angular/core/testing';
|
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
// #enddocregion activatedroute
|
// #enddocregion activatedroute
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
|
|
||||||
|
import { async, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { PhoneDetailComponent } from './phone-detail.component';
|
import { PhoneDetailComponent } from './phone-detail.component';
|
||||||
import { Phone, PhoneData } from '../core/phone/phone.service';
|
import { Phone, PhoneData } from '../core/phone/phone.service';
|
||||||
import { CheckmarkPipe } from '../core/checkmark/checkmark.pipe';
|
import { CheckmarkPipe } from '../core/checkmark/checkmark.pipe';
|
||||||
|
|
||||||
function xyzPhoneData(): PhoneData {
|
function xyzPhoneData(): PhoneData {
|
||||||
return {name: 'phone xyz', snippet: '', images: ['image/url1.png', 'image/url2.png']};
|
return {
|
||||||
|
name: 'phone xyz',
|
||||||
|
snippet: '',
|
||||||
|
images: ['image/url1.png', 'image/url2.png']
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockPhone {
|
class MockPhone {
|
||||||
@ -28,9 +34,10 @@ class ActivatedRouteMock {
|
|||||||
// #enddocregion activatedroute
|
// #enddocregion activatedroute
|
||||||
|
|
||||||
describe('PhoneDetailComponent', () => {
|
describe('PhoneDetailComponent', () => {
|
||||||
|
|
||||||
// #docregion activatedroute
|
// #docregion activatedroute
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ CheckmarkPipe, PhoneDetailComponent ],
|
declarations: [ CheckmarkPipe, PhoneDetailComponent ],
|
||||||
providers: [
|
providers: [
|
||||||
@ -48,4 +55,5 @@ describe('PhoneDetailComponent', () => {
|
|||||||
const compiled = fixture.debugElement.nativeElement;
|
const compiled = fixture.debugElement.nativeElement;
|
||||||
expect(compiled.querySelector('h1').textContent).toContain(xyzPhoneData().name);
|
expect(compiled.querySelector('h1').textContent).toContain(xyzPhoneData().name);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
// #docregion
|
// #docregion
|
||||||
import {SpyLocation} from '@angular/common/testing';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import {NO_ERRORS_SCHEMA} from '@angular/core';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
|
import { Observable, of } from 'rxjs';
|
||||||
import {ActivatedRoute} from '@angular/router';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import {Observable, of} from 'rxjs';
|
import { SpyLocation } from '@angular/common/testing';
|
||||||
|
|
||||||
import {Phone, PhoneData} from '../core/phone/phone.service';
|
import { PhoneListComponent } from './phone-list.component';
|
||||||
|
import { Phone, PhoneData } from '../core/phone/phone.service';
|
||||||
import {PhoneListComponent} from './phone-list.component';
|
|
||||||
|
|
||||||
class ActivatedRouteMock {
|
class ActivatedRouteMock {
|
||||||
constructor(public snapshot: any) {}
|
constructor(public snapshot: any) {}
|
||||||
@ -17,7 +16,8 @@ class ActivatedRouteMock {
|
|||||||
class MockPhone {
|
class MockPhone {
|
||||||
query(): Observable<PhoneData[]> {
|
query(): Observable<PhoneData[]> {
|
||||||
return of([
|
return of([
|
||||||
{name: 'Nexus S', snippet: '', images: []}, {name: 'Motorola DROID', snippet: '', images: []}
|
{name: 'Nexus S', snippet: '', images: []},
|
||||||
|
{name: 'Motorola DROID', snippet: '', images: []}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25,18 +25,18 @@ class MockPhone {
|
|||||||
let fixture: ComponentFixture<PhoneListComponent>;
|
let fixture: ComponentFixture<PhoneListComponent>;
|
||||||
|
|
||||||
describe('PhoneList', () => {
|
describe('PhoneList', () => {
|
||||||
beforeEach(waitForAsync(() => {
|
|
||||||
TestBed
|
beforeEach(async(() => {
|
||||||
.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [PhoneListComponent],
|
declarations: [ PhoneListComponent ],
|
||||||
providers: [
|
providers: [
|
||||||
{provide: ActivatedRoute, useValue: new ActivatedRouteMock({params: {'phoneId': 1}})},
|
{ provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) },
|
||||||
{provide: Location, useClass: SpyLocation},
|
{ provide: Location, useClass: SpyLocation },
|
||||||
{provide: Phone, useClass: MockPhone},
|
{ provide: Phone, useClass: MockPhone },
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [ NO_ERRORS_SCHEMA ]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -47,15 +47,20 @@ describe('PhoneList', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let compiled = fixture.debugElement.nativeElement;
|
let compiled = fixture.debugElement.nativeElement;
|
||||||
expect(compiled.querySelectorAll('.phone-list-item').length).toBe(2);
|
expect(compiled.querySelectorAll('.phone-list-item').length).toBe(2);
|
||||||
expect(compiled.querySelector('.phone-list-item:nth-child(1)').textContent)
|
expect(
|
||||||
.toContain('Motorola DROID');
|
compiled.querySelector('.phone-list-item:nth-child(1)').textContent
|
||||||
expect(compiled.querySelector('.phone-list-item:nth-child(2)').textContent)
|
).toContain('Motorola DROID');
|
||||||
.toContain('Nexus S');
|
expect(
|
||||||
|
compiled.querySelector('.phone-list-item:nth-child(2)').textContent
|
||||||
|
).toContain('Nexus S');
|
||||||
});
|
});
|
||||||
|
|
||||||
xit('should set the default value of orderProp model', () => {
|
xit('should set the default value of orderProp model', () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let compiled = fixture.debugElement.nativeElement;
|
let compiled = fixture.debugElement.nativeElement;
|
||||||
expect(compiled.querySelector('select option:last-child').selected).toBe(true);
|
expect(
|
||||||
|
compiled.querySelector('select option:last-child').selected
|
||||||
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -3,7 +3,7 @@ var fsExtra = require('fs-extra');
|
|||||||
var resources = [
|
var resources = [
|
||||||
// polyfills
|
// polyfills
|
||||||
'node_modules/core-js/client/shim.min.js',
|
'node_modules/core-js/client/shim.min.js',
|
||||||
'node_modules/zone.js/bundles/zone.umd.min.js',
|
'node_modules/zone.js/dist/zone.min.js',
|
||||||
// css
|
// css
|
||||||
'app/app.css',
|
'app/app.css',
|
||||||
'app/app.animations.css',
|
'app/app.animations.css',
|
||||||
@ -20,7 +20,6 @@ var resources = [
|
|||||||
'app/phone-detail/phone-detail.module.js'
|
'app/phone-detail/phone-detail.module.js'
|
||||||
];
|
];
|
||||||
resources.map(function(sourcePath) {
|
resources.map(function(sourcePath) {
|
||||||
// Need to rename zone.umd.min.js to zone.min.js
|
var destPath = `aot/${sourcePath}`;
|
||||||
var destPath = `aot/${sourcePath}`.replace('.umd.min.js', '.min.js');
|
|
||||||
fsExtra.copySync(sourcePath, destPath);
|
fsExtra.copySync(sourcePath, destPath);
|
||||||
});
|
});
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
<!-- #docregion angular -->
|
<!-- #docregion angular -->
|
||||||
<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>
|
||||||
<!-- #enddocregion angular -->
|
<!-- #enddocregion angular -->
|
||||||
<script src="/systemjs.config.1.js"></script>
|
<script src="/systemjs.config.1.js"></script>
|
||||||
|
@ -21,8 +21,8 @@ module.exports = function(config) {
|
|||||||
'node_modules/core-js/client/shim.js',
|
'node_modules/core-js/client/shim.js',
|
||||||
|
|
||||||
// zone.js
|
// zone.js
|
||||||
'node_modules/zone.js/bundles/zone.umd.js',
|
'node_modules/zone.js/dist/zone.js',
|
||||||
'node_modules/zone.js/bundles/zone-testing.umd.js',
|
'node_modules/zone.js/dist/zone-testing.js',
|
||||||
|
|
||||||
// RxJs.
|
// RxJs.
|
||||||
{ pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
|
{ pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
|
||||||
|
@ -31,8 +31,8 @@ module.exports = function(config) {
|
|||||||
'node_modules/core-js/client/shim.js',
|
'node_modules/core-js/client/shim.js',
|
||||||
|
|
||||||
// zone.js
|
// zone.js
|
||||||
'node_modules/zone.js/bundles/zone.umd.js',
|
'node_modules/zone.js/dist/zone.js',
|
||||||
'node_modules/zone.js/bundles/zone-testing.umd.js',
|
'node_modules/zone.js/dist/zone-testing.js',
|
||||||
|
|
||||||
// RxJs
|
// RxJs
|
||||||
{ pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
|
{ pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
// #docregion activatedroute
|
// #docregion activatedroute
|
||||||
import { TestBed, waitForAsync } from '@angular/core/testing';
|
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
// #enddocregion activatedroute
|
// #enddocregion activatedroute
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
|
|
||||||
|
import { async, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { PhoneDetailComponent } from './phone-detail.component';
|
import { PhoneDetailComponent } from './phone-detail.component';
|
||||||
import { Phone, PhoneData } from '../core/phone/phone.service';
|
import { Phone, PhoneData } from '../core/phone/phone.service';
|
||||||
import { CheckmarkPipe } from '../core/checkmark/checkmark.pipe';
|
import { CheckmarkPipe } from '../core/checkmark/checkmark.pipe';
|
||||||
|
|
||||||
function xyzPhoneData(): PhoneData {
|
function xyzPhoneData(): PhoneData {
|
||||||
return {name: 'phone xyz', snippet: '', images: ['image/url1.png', 'image/url2.png']};
|
return {
|
||||||
|
name: 'phone xyz',
|
||||||
|
snippet: '',
|
||||||
|
images: ['image/url1.png', 'image/url2.png']
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockPhone {
|
class MockPhone {
|
||||||
@ -28,9 +34,10 @@ class ActivatedRouteMock {
|
|||||||
// #enddocregion activatedroute
|
// #enddocregion activatedroute
|
||||||
|
|
||||||
describe('PhoneDetailComponent', () => {
|
describe('PhoneDetailComponent', () => {
|
||||||
|
|
||||||
// #docregion activatedroute
|
// #docregion activatedroute
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ CheckmarkPipe, PhoneDetailComponent ],
|
declarations: [ CheckmarkPipe, PhoneDetailComponent ],
|
||||||
providers: [
|
providers: [
|
||||||
@ -48,4 +55,5 @@ describe('PhoneDetailComponent', () => {
|
|||||||
const compiled = fixture.debugElement.nativeElement;
|
const compiled = fixture.debugElement.nativeElement;
|
||||||
expect(compiled.querySelector('h1').textContent).toContain(xyzPhoneData().name);
|
expect(compiled.querySelector('h1').textContent).toContain(xyzPhoneData().name);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
// #docregion routestuff
|
// #docregion routestuff
|
||||||
import {SpyLocation} from '@angular/common/testing';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import {NO_ERRORS_SCHEMA} from '@angular/core';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
|
import { Observable, of } from 'rxjs';
|
||||||
import {ActivatedRoute} from '@angular/router';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import {Observable, of} from 'rxjs';
|
import { SpyLocation } from '@angular/common/testing';
|
||||||
|
|
||||||
import {Phone, PhoneData} from '../core/phone/phone.service';
|
import { PhoneListComponent } from './phone-list.component';
|
||||||
|
import { Phone, PhoneData } from '../core/phone/phone.service';
|
||||||
import {PhoneListComponent} from './phone-list.component';
|
|
||||||
|
|
||||||
// #enddocregion routestuff
|
// #enddocregion routestuff
|
||||||
|
|
||||||
@ -19,7 +18,8 @@ class ActivatedRouteMock {
|
|||||||
class MockPhone {
|
class MockPhone {
|
||||||
query(): Observable<PhoneData[]> {
|
query(): Observable<PhoneData[]> {
|
||||||
return of([
|
return of([
|
||||||
{name: 'Nexus S', snippet: '', images: []}, {name: 'Motorola DROID', snippet: '', images: []}
|
{name: 'Nexus S', snippet: '', images: []},
|
||||||
|
{name: 'Motorola DROID', snippet: '', images: []}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,20 +27,20 @@ class MockPhone {
|
|||||||
let fixture: ComponentFixture<PhoneListComponent>;
|
let fixture: ComponentFixture<PhoneListComponent>;
|
||||||
|
|
||||||
describe('PhoneList', () => {
|
describe('PhoneList', () => {
|
||||||
|
|
||||||
// #docregion routestuff
|
// #docregion routestuff
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(async(() => {
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
declarations: [ PhoneListComponent ],
|
||||||
declarations: [PhoneListComponent],
|
providers: [
|
||||||
providers: [
|
{ provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) },
|
||||||
{provide: ActivatedRoute, useValue: new ActivatedRouteMock({params: {'phoneId': 1}})},
|
{ provide: Location, useClass: SpyLocation },
|
||||||
{provide: Location, useClass: SpyLocation},
|
{ provide: Phone, useClass: MockPhone },
|
||||||
{provide: Phone, useClass: MockPhone},
|
],
|
||||||
],
|
schemas: [ NO_ERRORS_SCHEMA ]
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
})
|
||||||
})
|
.compileComponents();
|
||||||
.compileComponents();
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -52,15 +52,20 @@ describe('PhoneList', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let compiled = fixture.debugElement.nativeElement;
|
let compiled = fixture.debugElement.nativeElement;
|
||||||
expect(compiled.querySelectorAll('.phone-list-item').length).toBe(2);
|
expect(compiled.querySelectorAll('.phone-list-item').length).toBe(2);
|
||||||
expect(compiled.querySelector('.phone-list-item:nth-child(1)').textContent)
|
expect(
|
||||||
.toContain('Motorola DROID');
|
compiled.querySelector('.phone-list-item:nth-child(1)').textContent
|
||||||
expect(compiled.querySelector('.phone-list-item:nth-child(2)').textContent)
|
).toContain('Motorola DROID');
|
||||||
.toContain('Nexus S');
|
expect(
|
||||||
|
compiled.querySelector('.phone-list-item:nth-child(2)').textContent
|
||||||
|
).toContain('Nexus S');
|
||||||
});
|
});
|
||||||
|
|
||||||
xit('should set the default value of orderProp model', () => {
|
xit('should set the default value of orderProp model', () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let compiled = fixture.debugElement.nativeElement;
|
let compiled = fixture.debugElement.nativeElement;
|
||||||
expect(compiled.querySelector('select option:last-child').selected).toBe(true);
|
expect(
|
||||||
|
compiled.querySelector('select option:last-child').selected
|
||||||
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<link rel="stylesheet" href="app.css" />
|
<link rel="stylesheet" href="app.css" />
|
||||||
|
|
||||||
<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>
|
||||||
<!-- #enddocregion full -->
|
<!-- #enddocregion full -->
|
||||||
<script src="/systemjs.config.1.js"></script>
|
<script src="/systemjs.config.1.js"></script>
|
||||||
|
@ -31,8 +31,8 @@ module.exports = function(config) {
|
|||||||
'node_modules/core-js/client/shim.js',
|
'node_modules/core-js/client/shim.js',
|
||||||
|
|
||||||
// zone.js
|
// zone.js
|
||||||
'node_modules/zone.js/bundles/zone.umd.js',
|
'node_modules/zone.js/dist/zone.js',
|
||||||
'node_modules/zone.js/bundles/zone-testing.umd.js',
|
'node_modules/zone.js/dist/zone-testing.js',
|
||||||
|
|
||||||
// RxJs
|
// RxJs
|
||||||
{ pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
|
{ pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
|
||||||
|
@ -31,7 +31,7 @@ For example:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"extends": "../tsconfig.json",
|
"extends": "../tsconfig.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
...
|
...
|
||||||
|
@ -62,7 +62,7 @@ In the following example, the `@Component()` metadata object and the class const
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-typical',
|
selector: 'app-typical',
|
||||||
template: '<div>A typical component for {{data.name}}</div>'
|
template: '<div>A typical component for {{data.name}}</div>'
|
||||||
})
|
)}
|
||||||
export class TypicalComponent {
|
export class TypicalComponent {
|
||||||
@Input() data: TypicalData;
|
@Input() data: TypicalData;
|
||||||
constructor(private someService: SomeService) { ... }
|
constructor(private someService: SomeService) { ... }
|
||||||
|
@ -17,7 +17,7 @@ An NgModule is defined by a class decorated with `@NgModule()`. The `@NgModule()
|
|||||||
|
|
||||||
* `imports`: Other modules whose exported classes are needed by component templates declared in *this* NgModule.
|
* `imports`: Other modules whose exported classes are needed by component templates declared in *this* NgModule.
|
||||||
|
|
||||||
* `providers`: Creators of [services](guide/architecture-services) that this NgModule contributes to the global collection of services; they become accessible in all parts of the app. (You can also specify providers at the component level.)
|
* `providers`: Creators of [services](guide/architecture-services) that this NgModule contributes to the global collection of services; they become accessible in all parts of the app. (You can also specify providers at the component level, which is often preferred.)
|
||||||
|
|
||||||
* `bootstrap`: The main application view, called the *root component*, which hosts all other app views. Only the *root NgModule* should set the `bootstrap` property.
|
* `bootstrap`: The main application view, called the *root component*, which hosts all other app views. Only the *root NgModule* should set the `bootstrap` property.
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ Attributes can be changed by `setAttribute()`, which re-initializes correspondin
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
For more information, see the [MDN Interfaces documentation](https://developer.mozilla.org/en-US/docs/Web/API#Interfaces) which has API docs for all the standard DOM elements and their properties.
|
For more information, see the [MDN Interfaces documentation](https://developer.mozilla.org/en-US/docs/Web/API#Interfaces) which has API docs for all the standard DOM elements and their properties.
|
||||||
Comparing the [`<td>` attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td) to the [`<td>` properties](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement) provides a helpful example for differentiation.
|
Comparing the [`<td>` attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td) attributes to the [`<td>` properties](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement) provides a helpful example for differentiation.
|
||||||
In particular, you can navigate from the attributes page to the properties via "DOM interface" link, and navigate the inheritance hierarchy up to `HTMLTableCellElement`.
|
In particular, you can navigate from the attributes page to the properties via "DOM interface" link, and navigate the inheritance hierarchy up to `HTMLTableCellElement`.
|
||||||
|
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ To control the state of the button, set the `disabled` *property*,
|
|||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
Though you could technically set the `[attr.disabled]` attribute binding, the values are different in that the property binding requires to be a boolean value, while its corresponding attribute binding relies on whether the value is `null` or not. Consider the following:
|
Though you could technically set the `[attr.disabled]` attribute binding, the values are different in that the property binding requires to a boolean value, while its corresponding attribute binding relies on whether the value is `null` or not. Consider the following:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<input [disabled]="condition ? true : false">
|
<input [disabled]="condition ? true : false">
|
||||||
|
@ -12,7 +12,7 @@ Every application has at least one Angular module, the _root_ module,
|
|||||||
which must be present for bootstrapping the application on launch.
|
which must be present for bootstrapping the application on launch.
|
||||||
By convention and by default, this NgModule is named `AppModule`.
|
By convention and by default, this NgModule is named `AppModule`.
|
||||||
|
|
||||||
When you use the [Angular CLI](cli) command `ng new` to generate an app, the default `AppModule` looks like the following:
|
When you use the [Angular CLI](cli) command `ng new` to generate an app, the default `AppModule` is as follows.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/* JavaScript imports */
|
/* JavaScript imports */
|
||||||
@ -90,6 +90,8 @@ A declarable can only belong to one module, so only declare it in
|
|||||||
one `@NgModule`. When you need it elsewhere,
|
one `@NgModule`. When you need it elsewhere,
|
||||||
import the module that has the declarable you need in it.
|
import the module that has the declarable you need in it.
|
||||||
|
|
||||||
|
**Only `@NgModule` references** go in the `imports` array.
|
||||||
|
|
||||||
|
|
||||||
### Using directives with `@NgModule`
|
### Using directives with `@NgModule`
|
||||||
|
|
||||||
@ -131,7 +133,7 @@ The module's `imports` array appears exclusively in the `@NgModule` metadata obj
|
|||||||
It tells Angular about other NgModules that this particular module needs to function properly.
|
It tells Angular about other NgModules that this particular module needs to function properly.
|
||||||
|
|
||||||
This list of modules are those that export components, directives, or pipes
|
This list of modules are those that export components, directives, or pipes
|
||||||
that component templates in this module reference. In this case, the component is
|
that the component templates in this module reference. In this case, the component is
|
||||||
`AppComponent`, which references components, directives, or pipes in `BrowserModule`,
|
`AppComponent`, which references components, directives, or pipes in `BrowserModule`,
|
||||||
`FormsModule`, or `HttpClientModule`.
|
`FormsModule`, or `HttpClientModule`.
|
||||||
A component template can reference another component, directive,
|
A component template can reference another component, directive,
|
||||||
|
@ -526,7 +526,7 @@ For example:
|
|||||||
// __Zone_enable_cross_context_check = true;
|
// __Zone_enable_cross_context_check = true;
|
||||||
</script>
|
</script>
|
||||||
<!-- zone.js required by Angular -->
|
<!-- zone.js required by Angular -->
|
||||||
<script src="node_modules/zone.js/bundles/zone.umd.js"></script>
|
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||||
|
|
||||||
<!-- application polyfills -->
|
<!-- application polyfills -->
|
||||||
</code-example>
|
</code-example>
|
||||||
|
@ -125,7 +125,7 @@ Emulated is the default and most commonly used view encapsulation. For more info
|
|||||||
|
|
||||||
<div class="alert is-important">
|
<div class="alert is-important">
|
||||||
|
|
||||||
The shadow-piercing descendant combinator is deprecated and [support is being removed from major browsers](https://www.chromestatus.com/feature/6750456638341120) and tools.
|
The shadow-piercing descendant combinator is deprecated and [support is being removed from major browsers](https://www.chromestatus.com/features/6750456638341120) and tools.
|
||||||
As such we plan to drop support in Angular (for all 3 of `/deep/`, `>>>` and `::ng-deep`).
|
As such we plan to drop support in Angular (for all 3 of `/deep/`, `>>>` and `::ng-deep`).
|
||||||
Until then `::ng-deep` should be preferred for a broader compatibility with the tools.
|
Until then `::ng-deep` should be preferred for a broader compatibility with the tools.
|
||||||
|
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
# Creating libraries
|
# Creating libraries
|
||||||
|
|
||||||
This page provides a conceptual overview of how you can create and publish new libraries to extend Angular functionality.
|
You can create and publish new libraries to extend Angular functionality. If you find that you need to solve the same problem in more than one app (or want to share your solution with other developers), you have a candidate for a library.
|
||||||
|
|
||||||
If you find that you need to solve the same problem in more than one app (or want to share your solution with other developers), you have a candidate for a library.
|
|
||||||
A simple example might be a button that sends users to your company website, that would be included in all apps that your company builds.
|
A simple example might be a button that sends users to your company website, that would be included in all apps that your company builds.
|
||||||
|
|
||||||
|
<div class="alert is-helpful">
|
||||||
|
<p>For more details on how a library project is structured you can refer the <a href="guide/file-structure#library-project-files">Library Project Files</a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
Use the Angular CLI to generate a new library skeleton in a new workspace with the following commands.
|
Use the Angular CLI to generate a new library skeleton with the following command:
|
||||||
|
|
||||||
<code-example language="bash">
|
<code-example language="bash">
|
||||||
ng new my-workspace --create-application=false
|
ng new my-workspace --create-application=false
|
||||||
@ -15,18 +18,12 @@ Use the Angular CLI to generate a new library skeleton in a new workspace with t
|
|||||||
ng generate library my-lib
|
ng generate library my-lib
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The `ng generate` command creates the `projects/my-lib` folder in your workspace, which contains a component and a service inside an NgModule.
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
<p>You can use the monorepo model to use the same workspace for multiple projects. See <a href="guide/file-structure#multiple-projects">Setting up for a multi-project workspace</a>.</p>
|
||||||
For more details on how a library project is structured, refer to the [Library project files](guide/file-structure#library-project-files) section of the [Project File Structure guide](guide/file-structure).
|
|
||||||
|
|
||||||
You can use the monorepo model to use the same workspace for multiple projects.
|
|
||||||
See [Setting up for a multi-project workspace](guide/file-structure#multiple-projects).
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
When you generate a new library, the workspace configuration file, `angular.json`, is updated with a project of type `library`.
|
This creates the `projects/my-lib` folder in your workspace, which contains a component and a service inside an NgModule.
|
||||||
|
The workspace configuration file, `angular.json`, is updated with a project of type 'library'.
|
||||||
|
|
||||||
<code-example format="json">
|
<code-example format="json">
|
||||||
"projects": {
|
"projects": {
|
||||||
@ -72,30 +69,35 @@ Here are some things to consider in migrating application functionality to a lib
|
|||||||
|
|
||||||
* Components should expose their interactions through inputs for providing context, and outputs for communicating events to other components.
|
* Components should expose their interactions through inputs for providing context, and outputs for communicating events to other components.
|
||||||
|
|
||||||
|
* Services should declare their own providers (rather than declaring providers in the NgModule or a component), so that they are *tree-shakable*. This allows the compiler to leave the service out of the bundle if it never gets injected into the application that imports the library. For more about this, see [Tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers).
|
||||||
|
|
||||||
|
* If you register global service providers or share providers across multiple NgModules, use the [`forRoot()` and `forChild()` patterns](guide/singleton-services) provided by the [RouterModule](api/router/RouterModule).
|
||||||
|
|
||||||
* Check all internal dependencies.
|
* Check all internal dependencies.
|
||||||
* For custom classes or interfaces used in components or service, check whether they depend on additional classes or interfaces that also need to be migrated.
|
* For custom classes or interfaces used in components or service, check whether they depend on additional classes or interfaces that also need to be migrated.
|
||||||
* Similarly, if your library code depends on a service, that service needs to be migrated.
|
* Similarly, if your library code depends on a service, that service needs to be migrated.
|
||||||
* If your library code or its templates depend on other libraries (such as Angular Material, for instance), you must configure your library with those dependencies.
|
* If your library code or its templates depend on other libraries (such a Angular Material, for instance), you must configure your library with those dependencies.
|
||||||
|
|
||||||
* Consider how you provide services to client applications.
|
## Reusable code and schematics
|
||||||
|
|
||||||
* Services should declare their own providers (rather than declaring providers in the NgModule or a component), so that they are *tree-shakable*. This allows the compiler to leave the service out of the bundle if it never gets injected into the application that imports the library. For more about this, see [Tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers).
|
A library typically includes *reusable code* that defines components, services, and other Angular artifacts (pipes, directives, and so on) that you simply import into a project.
|
||||||
|
A library is packaged into an npm package for publishing and sharing, and this package can also include [schematics](guide/glossary#schematic) that provide instructions for generating or transforming code directly in your project, in the same way that the CLI creates a generic skeleton app with `ng generate component`.
|
||||||
|
A schematic that is combined with a library can, for example, provide the Angular CLI with the information it needs to generate a particular component defined in that library.
|
||||||
|
|
||||||
* If you register global service providers or share providers across multiple NgModules, use the [`forRoot()` and `forChild()` design patterns](guide/singleton-services) provided by the [RouterModule](api/router/RouterModule).
|
What you include in your library is determined by the kind of task you are trying to accomplish.
|
||||||
|
For example, if you want a dropdown with some canned data to show how to add it to your app, your library could define a schematic to create it.
|
||||||
|
For a component like a dropdown that would contain different passed-in values each time, you could provide it as a component in a shared library.
|
||||||
|
|
||||||
* If your library provides optional services that might not be used by all client applications, support proper tree-shaking for that case by using the [lightweight token design pattern](guide/lightweight-injection-tokens).
|
Suppose you want to read a configuration file and then generate a form based on that configuration.
|
||||||
|
If that form will need additional customization by the user, it might work best as a schematic.
|
||||||
|
However, if the forms will always be the same and not need much customization by developers, then you could create a dynamic component that takes the configuration and generates the form.
|
||||||
|
In general, the more complex the customization, the more useful the schematic approach.
|
||||||
|
|
||||||
{@a integrating-with-the-cli}
|
{@a integrating-with-the-cli}
|
||||||
|
|
||||||
## Integrating with the CLI using code-generation schematics
|
## Integrating with the CLI
|
||||||
|
|
||||||
A library typically includes *reusable code* that defines components, services, and other Angular artifacts (pipes, directives, and so on) that you simply import into a project.
|
A library can include [schematics](guide/glossary#schematic) that allow it to integrate with the Angular CLI.
|
||||||
A library is packaged into an npm package for publishing and sharing.
|
|
||||||
This package can also include [schematics](guide/glossary#schematic) that provide instructions for generating or transforming code directly in your project, in the same way that the CLI creates a generic new component with `ng generate component`.
|
|
||||||
A schematic that is packaged with a library can, for example, provide the Angular CLI with the information it needs to generate a component that configures and uses a particular feature, or set of features, defined in that library.
|
|
||||||
One example of this is Angular Material's navigation schematic which configures the CDK's `BreakpointObserver` and uses it with Material's `MatSideNav` and `MatToolbar` components.
|
|
||||||
|
|
||||||
You can create and include the following kinds of schematics.
|
|
||||||
|
|
||||||
* Include an installation schematic so that `ng add` can add your library to a project.
|
* Include an installation schematic so that `ng add` can add your library to a project.
|
||||||
|
|
||||||
@ -103,20 +105,11 @@ You can create and include the following kinds of schematics.
|
|||||||
|
|
||||||
* Include an update schematic so that `ng update` can update your library’s dependencies and provide migrations for breaking changes in new releases.
|
* Include an update schematic so that `ng update` can update your library’s dependencies and provide migrations for breaking changes in new releases.
|
||||||
|
|
||||||
What you include in your library depends on your task.
|
|
||||||
For example, you could define a schematic to create a dropdown that is pre-populated with canned data to show how to add it to an app.
|
|
||||||
If you want a dropdown that would contain different passed-in values each time, your library could define a schematic to create it with a given configuration. Developers could then use `ng generate` to configure an instance for their own app.
|
|
||||||
|
|
||||||
Suppose you want to read a configuration file and then generate a form based on that configuration.
|
|
||||||
If that form will need additional customization by the developer who is using your library, it might work best as a schematic.
|
|
||||||
However, if the form will always be the same and not need much customization by developers, then you could create a dynamic component that takes the configuration and generates the form.
|
|
||||||
In general, the more complex the customization, the more useful the schematic approach.
|
|
||||||
|
|
||||||
To learn more, see [Schematics Overview](guide/schematics) and [Schematics for Libraries](guide/schematics-for-libraries).
|
To learn more, see [Schematics Overview](guide/schematics) and [Schematics for Libraries](guide/schematics-for-libraries).
|
||||||
|
|
||||||
## Publishing your library
|
## Publishing your library
|
||||||
|
|
||||||
Use the Angular CLI and the npm package manager to build and publish your library as an npm package.
|
Use the Angular CLI and the npm package manager to build and publish your library as an npm package.
|
||||||
|
|
||||||
Before publishing a library to NPM, build it using the `--prod` flag which will use the older compiler and runtime known as View Engine instead of Ivy.
|
Before publishing a library to NPM, build it using the `--prod` flag which will use the older compiler and runtime known as View Engine instead of Ivy.
|
||||||
|
|
||||||
|
@ -448,13 +448,13 @@ When targeting older browsers, [polyfills](guide/browser-support#polyfills) can
|
|||||||
|
|
||||||
To maximize compatibility, you could ship a single bundle that includes all your compiled code, plus any polyfills that may be needed.
|
To maximize compatibility, you could ship a single bundle that includes all your compiled code, plus any polyfills that may be needed.
|
||||||
Users with modern browsers, however, shouldn't have to pay the price of increased bundle size that comes with polyfills they don't need.
|
Users with modern browsers, however, shouldn't have to pay the price of increased bundle size that comes with polyfills they don't need.
|
||||||
Differential loading, which is supported in Angular CLI version 8 and higher, can help solve this problem.
|
Differential loading, which is supported by default in Angular CLI version 8 and higher, solves this problem.
|
||||||
|
|
||||||
Differential loading is a strategy that allows your web application to support multiple browsers, but only load the necessary code that the browser needs. When differential loading is enabled the CLI builds two separate bundles as part of your deployed application.
|
Differential loading is a strategy that allows your web application to support multiple browsers, but only load the necessary code that the browser needs. When differential loading is enabled (which is the default) the CLI builds two separate bundles as part of your deployed application.
|
||||||
|
|
||||||
* The first bundle contains modern ES2015 syntax. This bundle takes advantage of built-in support in modern browsers, ships fewer polyfills, and results in a smaller bundle size.
|
* The first bundle contains modern ES2015 syntax, takes advantage of built-in support in modern browsers, ships fewer polyfills, and results in a smaller bundle size.
|
||||||
|
|
||||||
* The second bundle contains code in the old ES5 syntax, along with all necessary polyfills. This second bundle is larger, but supports older browsers.
|
* The second bundle contains code in the old ES5 syntax, along with all necessary polyfills. This results in a larger bundle size, but supports older browsers.
|
||||||
|
|
||||||
### Differential builds
|
### Differential builds
|
||||||
|
|
||||||
@ -463,9 +463,9 @@ The [`ng build` CLI command](cli/build) queries the browser configuration and th
|
|||||||
|
|
||||||
The following configurations determine your requirements.
|
The following configurations determine your requirements.
|
||||||
|
|
||||||
* Browserslist
|
* Browsers list
|
||||||
|
|
||||||
The Browserslist configuration file is included in your application [project structure](guide/file-structure#application-configuration-files) and provides the minimum browsers your application supports. See the [Browserslist spec](https://github.com/browserslist/browserslist) for complete configuration options.
|
The `browserslist` configuration file is included in your application [project structure](guide/file-structure#application-configuration-files) and provides the minimum browsers your application supports. See the [Browserslist spec](https://github.com/browserslist/browserslist) for complete configuration options.
|
||||||
|
|
||||||
* TypeScript configuration
|
* TypeScript configuration
|
||||||
|
|
||||||
@ -509,27 +509,16 @@ Each script tag has a `type="module"` or `nomodule` attribute. Browsers with nat
|
|||||||
|
|
||||||
### Configuring differential loading
|
### Configuring differential loading
|
||||||
|
|
||||||
To include differential loading in your application builds, you must configure the Browserslist and TypeScript configuration files in your application project.
|
Differential loading is supported by default with version 8 and later of the Angular CLI.
|
||||||
|
For each application project in your workspace, you can configure how builds are produced based on the `browserslist` and `tsconfig.json` configuration files in your application project.
|
||||||
|
|
||||||
The following examples show a `.browserslistrc` and `tsconfig.json` file for a newly created Angular application. In this configuration, legacy browsers such as IE 9-11 are ignored, and the compilation target is ES2015.
|
For a newly created Angular application, legacy browsers such as IE 9-11 are ignored, and the compilation target is ES2015.
|
||||||
|
|
||||||
<code-example language="none" header=".browserslistrc">
|
<code-example language="none" header="browserslist">
|
||||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
> 0.5%
|
||||||
# For additional information regarding the format and rule options, please see:
|
last 2 versions
|
||||||
# https://github.com/browserslist/browserslist#queries
|
|
||||||
|
|
||||||
# For the full list of supported browsers by the Angular framework, please see:
|
|
||||||
# https://angular.io/guide/browser-support
|
|
||||||
|
|
||||||
# You can see what browsers were selected by your queries by running:
|
|
||||||
# npx browserslist
|
|
||||||
|
|
||||||
last 1 Chrome version
|
|
||||||
last 1 Firefox version
|
|
||||||
last 2 Edge major versions
|
|
||||||
last 2 Safari major versions
|
|
||||||
last 2 iOS major versions
|
|
||||||
Firefox ESR
|
Firefox ESR
|
||||||
|
not dead
|
||||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
@ -560,24 +549,36 @@ not IE 9-11 # For IE 9-11 support, remove 'not'.
|
|||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
The default configuration creates two builds, with differential loading enabled.
|
||||||
|
|
||||||
<div class="alert is-important">
|
<div class="alert is-important">
|
||||||
|
|
||||||
To see which browsers are supported and determine which settings meet to your browser support requirements, see the [Browserslist compatibility page](https://browserl.ist/?q=%3E+0.5%25%2C+last+2+versions%2C+Firefox+ESR%2C+not+dead%2C+not+IE+9-11).
|
To see which browsers are supported with the default configuration and determine which settings meet to your browser support requirements, see the [Browserslist compatibility page](https://browserl.ist/?q=%3E+0.5%25%2C+last+2+versions%2C+Firefox+ESR%2C+not+dead%2C+not+IE+9-11).
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
The Browserslist configuration allows you to ignore browsers without ES2015 support. In this case, a single build is produced.
|
The `browserslist` configuration allows you to ignore browsers without ES2015 support. In this case, a single build is produced.
|
||||||
|
|
||||||
If your Browserslist configuration includes support for any legacy browsers, the build target in the TypeScript configuration determines whether the build will support differential loading.
|
If your `browserslist` configuration includes support for any legacy browsers, the build target in the TypeScript configuration determines whether the build will support differential loading.
|
||||||
|
|
||||||
{@a configuration-table }
|
{@a configuration-table }
|
||||||
|
|
||||||
| Browserslist | ES target | Build result |
|
| browserslist | ES target | Build result |
|
||||||
| -------- | -------- | -------- |
|
| -------- | -------- | -------- |
|
||||||
| ES5 support disabled | es2015 | Single build, ES5 not required |
|
| ES5 support disabled | es2015 | Single build, ES5 not required |
|
||||||
| ES5 support enabled | es5 | Single build w/conditional polyfills for ES5 only |
|
| ES5 support enabled | es5 | Single build w/conditional polyfills for ES5 only |
|
||||||
| ES5 support enabled | es2015 | Differential loading (two builds w/conditional polyfills) |
|
| ES5 support enabled | es2015 | Differential loading (two builds w/conditional polyfills) |
|
||||||
|
|
||||||
|
|
||||||
|
### Opting out of differential loading
|
||||||
|
|
||||||
|
Differential loading can be explicitly disabled if it causes unexpected issues, or if you need to target ES5 specifically for legacy browser support.
|
||||||
|
|
||||||
|
To explicitly disable differential loading and create an ES5 build:
|
||||||
|
|
||||||
|
- Enable the `dead` or `IE` browsers in the `browserslist` configuration file by removing the `not` keyword in front of them.
|
||||||
|
- To create a single ES5 build, set the target in the `compilerOptions` to `es5`.
|
||||||
|
|
||||||
{@a test-and-serve}
|
{@a test-and-serve}
|
||||||
|
|
||||||
## Local development in older browsers
|
## Local development in older browsers
|
||||||
|
@ -38,6 +38,7 @@ v9 - v12
|
|||||||
| `@angular/bazel` | [`Bazel builder and schematics`](#bazelbuilder) | v10 |
|
| `@angular/bazel` | [`Bazel builder and schematics`](#bazelbuilder) | v10 |
|
||||||
| `@angular/common` | [`ReflectiveInjector`](#reflectiveinjector) | <!--v8--> v11 |
|
| `@angular/common` | [`ReflectiveInjector`](#reflectiveinjector) | <!--v8--> v11 |
|
||||||
| `@angular/common` | [`CurrencyPipe` - `DEFAULT_CURRENCY_CODE`](api/common/CurrencyPipe#currency-code-deprecation) | <!--v9--> v11 |
|
| `@angular/common` | [`CurrencyPipe` - `DEFAULT_CURRENCY_CODE`](api/common/CurrencyPipe#currency-code-deprecation) | <!--v9--> v11 |
|
||||||
|
| `@angular/core` | [`CollectionChangeRecord`](#core) | <!--v7--> v11 |
|
||||||
| `@angular/core` | [`DefaultIterableDiffer`](#core) | <!--v7--> v11 |
|
| `@angular/core` | [`DefaultIterableDiffer`](#core) | <!--v7--> v11 |
|
||||||
| `@angular/core` | [`ReflectiveKey`](#core) | <!--v8--> v11 |
|
| `@angular/core` | [`ReflectiveKey`](#core) | <!--v8--> v11 |
|
||||||
| `@angular/core` | [`RenderComponentType`](#core) | <!--v7--> v11 |
|
| `@angular/core` | [`RenderComponentType`](#core) | <!--v7--> v11 |
|
||||||
@ -57,12 +58,12 @@ v9 - v12
|
|||||||
| `@angular/core` | [`ANALYZE_FOR_ENTRY_COMPONENTS`](api/core/ANALYZE_FOR_ENTRY_COMPONENTS) | <!--v9--> v11 |
|
| `@angular/core` | [`ANALYZE_FOR_ENTRY_COMPONENTS`](api/core/ANALYZE_FOR_ENTRY_COMPONENTS) | <!--v9--> v11 |
|
||||||
| `@angular/router` | [`loadChildren` string syntax](#loadChildren) | <!--v9--> v11 |
|
| `@angular/router` | [`loadChildren` string syntax](#loadChildren) | <!--v9--> v11 |
|
||||||
| `@angular/core/testing` | [`TestBed.get`](#testing) | <!--v9--> v12 |
|
| `@angular/core/testing` | [`TestBed.get`](#testing) | <!--v9--> v12 |
|
||||||
| `@angular/core/testing` | [`async`](#testing) | <!--v9--> v12 |
|
|
||||||
| `@angular/router` | [`ActivatedRoute` params and `queryParams` properties](#activatedroute-props) | unspecified |
|
| `@angular/router` | [`ActivatedRoute` params and `queryParams` properties](#activatedroute-props) | unspecified |
|
||||||
| template syntax | [`/deep/`, `>>>`, and `::ng-deep`](#deep-component-style-selector) | <!--v7--> unspecified |
|
| template syntax | [`/deep/`, `>>>`, and `::ng-deep`](#deep-component-style-selector) | <!--v7--> unspecified |
|
||||||
| browser support | [`IE 9 and 10, IE mobile`](#ie-9-10-and-mobile) | <!--v10--> v11 |
|
| browser support | [`IE 9 and 10, IE mobile`](#ie-9-10-and-mobile) | <!--v10--> v11 |
|
||||||
|
|
||||||
For information about Angular CDK and Angular Material deprecations, see the [changelog](https://github.com/angular/components/blob/master/CHANGELOG.md).
|
|
||||||
|
|
||||||
|
|
||||||
## Deprecated APIs
|
## Deprecated APIs
|
||||||
|
|
||||||
@ -88,6 +89,7 @@ Tip: In the [API reference section](api) of this doc site, deprecated APIs are i
|
|||||||
|
|
||||||
| API | Replacement | Deprecation announced | Notes |
|
| API | Replacement | Deprecation announced | Notes |
|
||||||
| --- | ----------- | --------------------- | ----- |
|
| --- | ----------- | --------------------- | ----- |
|
||||||
|
| [`CollectionChangeRecord`](api/core/CollectionChangeRecord) | [`IterableChangeRecord`](api/core/IterableChangeRecord) | v4 | none |
|
||||||
| [`DefaultIterableDiffer`](api/core/DefaultIterableDiffer) | n/a | v4 | Not part of public API. |
|
| [`DefaultIterableDiffer`](api/core/DefaultIterableDiffer) | n/a | v4 | Not part of public API. |
|
||||||
| [`ReflectiveInjector`](api/core/ReflectiveInjector) | [`Injector.create`](api/core/Injector#create) | v5 | See [`ReflectiveInjector`](#reflectiveinjector) |
|
| [`ReflectiveInjector`](api/core/ReflectiveInjector) | [`Injector.create`](api/core/Injector#create) | v5 | See [`ReflectiveInjector`](#reflectiveinjector) |
|
||||||
| [`ReflectiveKey`](api/core/ReflectiveKey) | none | v5 | none |
|
| [`ReflectiveKey`](api/core/ReflectiveKey) | none | v5 | none |
|
||||||
@ -107,7 +109,6 @@ Tip: In the [API reference section](api) of this doc site, deprecated APIs are i
|
|||||||
| API | Replacement | Deprecation announced | Notes |
|
| API | Replacement | Deprecation announced | Notes |
|
||||||
| --- | ----------- | --------------------- | ----- |
|
| --- | ----------- | --------------------- | ----- |
|
||||||
| [`TestBed.get`](api/core/testing/TestBed#get) | [`TestBed.inject`](api/core/testing/TestBed#inject) | v9 | Same behavior, but type safe. |
|
| [`TestBed.get`](api/core/testing/TestBed#get) | [`TestBed.inject`](api/core/testing/TestBed#inject) | v9 | Same behavior, but type safe. |
|
||||||
| [`async`](api/core/testing/async) | [`waitForAsync`](api/core/testing/waitForAsync) | v10 | Same behavior, but rename to avoid confusion. |
|
|
||||||
|
|
||||||
|
|
||||||
{@a forms}
|
{@a forms}
|
||||||
@ -477,7 +478,7 @@ The final decision was made on three key points:
|
|||||||
|
|
||||||
|
|
||||||
{@a wrapped-value}
|
{@a wrapped-value}
|
||||||
### `WrappedValue`
|
### `WrappedValue`
|
||||||
|
|
||||||
The purpose of `WrappedValue` is to allow the same object instance to be treated as different for the purposes of change detection.
|
The purpose of `WrappedValue` is to allow the same object instance to be treated as different for the purposes of change detection.
|
||||||
It is commonly used with the `async` pipe in the case where the `Observable` produces the same instance of the value.
|
It is commonly used with the `async` pipe in the case where the `Observable` produces the same instance of the value.
|
||||||
@ -487,7 +488,7 @@ No replacement is planned for this deprecation.
|
|||||||
|
|
||||||
If you rely on the behavior that the same object instance should cause change detection, you have two options:
|
If you rely on the behavior that the same object instance should cause change detection, you have two options:
|
||||||
- Clone the resulting value so that it has a new identity.
|
- Clone the resulting value so that it has a new identity.
|
||||||
- Explicitly call [`ChangeDetectorRef.detectChanges()`](api/core/ChangeDetectorRef#detectchanges) to force the update.
|
- Explicitly call [`ChangeDetectorRef.detectChanges()`](api/core/ChangeDetectorRef#detectchanges) to force the update.
|
||||||
|
|
||||||
{@a deprecated-cli-flags}
|
{@a deprecated-cli-flags}
|
||||||
## Deprecated CLI APIs and Options
|
## Deprecated CLI APIs and Options
|
||||||
|
@ -119,14 +119,7 @@ The recently-developed [custom elements](https://developer.mozilla.org/en-US/doc
|
|||||||
|
|
||||||
In browsers that support Custom Elements natively, the specification requires developers use ES2015 classes to define Custom Elements - developers can opt-in to this by setting the `target: "es2015"` property in their project's [TypeScript configuration file](/guide/typescript-configuration). As Custom Element and ES2015 support may not be available in all browsers, developers can instead choose to use a polyfill to support older browsers and ES5 code.
|
In browsers that support Custom Elements natively, the specification requires developers use ES2015 classes to define Custom Elements - developers can opt-in to this by setting the `target: "es2015"` property in their project's [TypeScript configuration file](/guide/typescript-configuration). As Custom Element and ES2015 support may not be available in all browsers, developers can instead choose to use a polyfill to support older browsers and ES5 code.
|
||||||
|
|
||||||
Use the [Angular CLI](cli) to automatically set up your project with the correct polyfill:
|
Use the [Angular CLI](cli) to automatically set up your project with the correct polyfill: `ng add @angular/elements --project=*your_project_name*`.
|
||||||
|
|
||||||
<code-example language="sh">
|
|
||||||
|
|
||||||
ng add @angular/elements --project=*your_project_name*
|
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
- For more information about polyfills, see [polyfill documentation](https://www.webcomponents.org/polyfills).
|
- For more information about polyfills, see [polyfill documentation](https://www.webcomponents.org/polyfills).
|
||||||
|
|
||||||
- For more information about Angular browser support, see [Browser Support](guide/browser-support).
|
- For more information about Angular browser support, see [Browser Support](guide/browser-support).
|
||||||
|
@ -76,12 +76,6 @@ All router components must be entry components. Because this would require you t
|
|||||||
|
|
||||||
## The `entryComponents` array
|
## The `entryComponents` array
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
|
||||||
|
|
||||||
Since 9.0.0 with Ivy, the `entryComponents` property is no longer necessary. See [deprecations guide](guide/deprecations#entryComponents).
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Though the `@NgModule` decorator has an `entryComponents` array, most of the time
|
Though the `@NgModule` decorator has an `entryComponents` array, most of the time
|
||||||
you won't have to explicitly set any entry components because Angular adds components listed in `@NgModule.bootstrap` and those in route definitions to entry components automatically. Though these two mechanisms account for most entry components, if your app happens to bootstrap or dynamically load a component by type imperatively,
|
you won't have to explicitly set any entry components because Angular adds components listed in `@NgModule.bootstrap` and those in route definitions to entry components automatically. Though these two mechanisms account for most entry components, if your app happens to bootstrap or dynamically load a component by type imperatively,
|
||||||
you must add it to `entryComponents` explicitly.
|
you must add it to `entryComponents` explicitly.
|
||||||
|
@ -79,7 +79,7 @@ To incorporate the feature module into your app, you have to let the root module
|
|||||||
<code-example path="feature-modules/src/app/app.module.ts" region="app-module" header="src/app/app.module.ts"></code-example>
|
<code-example path="feature-modules/src/app/app.module.ts" region="app-module" header="src/app/app.module.ts"></code-example>
|
||||||
|
|
||||||
|
|
||||||
Now the `AppModule` knows about the feature module. If you were to add any service providers to the feature module, `AppModule` would know about those too, as would any other feature modules. However, NgModules don’t expose their components by default.
|
Now the `AppModule` knows about the feature module. If you were to add any service providers to the feature module, `AppModule` would know about those too, as would any other feature modules. However, NgModules don’t expose their components.
|
||||||
|
|
||||||
|
|
||||||
## Rendering a feature module’s component template
|
## Rendering a feature module’s component template
|
||||||
|
@ -40,7 +40,8 @@ The top level of the workspace contains workspace-wide configuration files, conf
|
|||||||
| `package-lock.json` | Provides version information for all packages installed into `node_modules` by the npm client. See [npm documentation](https://docs.npmjs.com/files/package-lock.json) for details. If you use the yarn client, this file will be [yarn.lock](https://yarnpkg.com/lang/en/docs/yarn-lock/) instead. |
|
| `package-lock.json` | Provides version information for all packages installed into `node_modules` by the npm client. See [npm documentation](https://docs.npmjs.com/files/package-lock.json) for details. If you use the yarn client, this file will be [yarn.lock](https://yarnpkg.com/lang/en/docs/yarn-lock/) instead. |
|
||||||
| `src/` | Source files for the root-level application project. |
|
| `src/` | Source files for the root-level application project. |
|
||||||
| `node_modules/` | Provides [npm packages](guide/npm-packages) to the entire workspace. Workspace-wide `node_modules` dependencies are visible to all projects. |
|
| `node_modules/` | Provides [npm packages](guide/npm-packages) to the entire workspace. Workspace-wide `node_modules` dependencies are visible to all projects. |
|
||||||
| `tsconfig.json` | The base [TypeScript](https://www.typescriptlang.org/) configuration for projects in the workspace. All other configuration files inherit from this base file. For more information, see the [Configuration inheritance with extends](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#configuration-inheritance-with-extends) section of the TypeScript documentation.|
|
| `tsconfig.json` | The `tsconfig.json` file is a ["Solution Style"](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#support-for-solution-style-tsconfigjson-files) TypeScript configuration file. Code editors and TypeScript’s language server use this file to improve development experience. Compilers do not use this file. |
|
||||||
|
| `tsconfig.base.json` | The base [TypeScript](https://www.typescriptlang.org/) configuration for projects in the workspace. All other configuration files inherit from this base file. For more information, see the [Configuration inheritance with extends](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#configuration-inheritance-with-extends) section of the TypeScript documentation.|
|
||||||
| `tslint.json` | Default [TSLint](https://palantir.github.io/tslint/) configuration for projects in the workspace. |
|
| `tslint.json` | Default [TSLint](https://palantir.github.io/tslint/) configuration for projects in the workspace. |
|
||||||
|
|
||||||
|
|
||||||
@ -102,7 +103,7 @@ Angular components, templates, and styles go here.
|
|||||||
The application-specific configuration files for the root application reside at the workspace root level.
|
The application-specific configuration files for the root application reside at the workspace root level.
|
||||||
For a multi-project workspace, project-specific configuration files are in the project root, under `projects/project-name/`.
|
For a multi-project workspace, project-specific configuration files are in the project root, under `projects/project-name/`.
|
||||||
|
|
||||||
Project-specific [TypeScript](https://www.typescriptlang.org/) configuration files inherit from the workspace-wide `tsconfig.json`, and project-specific [TSLint](https://palantir.github.io/tslint/) configuration files inherit from the workspace-wide `tslint.json`.
|
Project-specific [TypeScript](https://www.typescriptlang.org/) configuration files inherit from the workspace-wide `tsconfig.base.json`, and project-specific [TSLint](https://palantir.github.io/tslint/) configuration files inherit from the workspace-wide `tslint.json`.
|
||||||
|
|
||||||
| APPLICATION-SPECIFIC CONFIG FILES | PURPOSE |
|
| APPLICATION-SPECIFIC CONFIG FILES | PURPOSE |
|
||||||
| :--------------------- | :------------------------------------------|
|
| :--------------------- | :------------------------------------------|
|
||||||
|
@ -627,11 +627,6 @@ The [npm package manager](https://docs.npmjs.com/getting-started/what-is-npm) is
|
|||||||
|
|
||||||
Learn more about how Angular uses [Npm Packages](guide/npm-packages).
|
Learn more about how Angular uses [Npm Packages](guide/npm-packages).
|
||||||
|
|
||||||
{@ ngc}
|
|
||||||
## ngc
|
|
||||||
`ngc` is a Typescript-to-Javascript transpiler that processes Angular decorators, metadata, and templates, and emits JavaScript code.
|
|
||||||
The most recent implementation is internally refered to as `ngtsc` because it's a minimalistic wrapper around the TypeScript compiler `tsc` that adds a transform for processing Angular code.
|
|
||||||
|
|
||||||
{@a O}
|
{@a O}
|
||||||
|
|
||||||
{@a observable}
|
{@a observable}
|
||||||
|
@ -766,10 +766,8 @@ The HTML `base` tag with the `href` attribute specifies the base URI, or URL, fo
|
|||||||
"i18n": {
|
"i18n": {
|
||||||
"sourceLocale": "en-US",
|
"sourceLocale": "en-US",
|
||||||
"locales": {
|
"locales": {
|
||||||
"fr": {
|
"fr": "src/locale/messages.fr.xlf"
|
||||||
"translation": "src/locale/messages.fr.xlf",
|
"baseHref": ""
|
||||||
"baseHref": ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"architect": {
|
"architect": {
|
||||||
|
@ -208,7 +208,7 @@ about the event and gives that data to the parent.
|
|||||||
The child's template has two controls. The first is an HTML `<input>` with a
|
The child's template has two controls. The first is an HTML `<input>` with a
|
||||||
[template reference variable](guide/template-reference-variables) , `#newItem`,
|
[template reference variable](guide/template-reference-variables) , `#newItem`,
|
||||||
where the user types in an item name. Whatever the user types
|
where the user types in an item name. Whatever the user types
|
||||||
into the `<input>` gets stored in the `value` property of the `#newItem` variable.
|
into the `<input>` gets stored in the `#newItem` variable.
|
||||||
|
|
||||||
<code-example path="inputs-outputs/src/app/item-output/item-output.component.html" region="child-output" header="src/app/item-output/item-output.component.html"></code-example>
|
<code-example path="inputs-outputs/src/app/item-output/item-output.component.html" region="child-output" header="src/app/item-output/item-output.component.html"></code-example>
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ an event binding because the part to the left of the equal
|
|||||||
sign is in parentheses, `(click)`.
|
sign is in parentheses, `(click)`.
|
||||||
|
|
||||||
The `(click)` event is bound to the `addNewItem()` method in the child component class which
|
The `(click)` event is bound to the `addNewItem()` method in the child component class which
|
||||||
takes as its argument whatever the value of `#newItem.value` property is.
|
takes as its argument whatever the value of `#newItem` is.
|
||||||
|
|
||||||
Now the child component has an `@Output()`
|
Now the child component has an `@Output()`
|
||||||
for sending data to the parent and a method for raising an event.
|
for sending data to the parent and a method for raising an event.
|
||||||
|
@ -11,11 +11,11 @@ That said, some applications will likely need to apply some manual updates.
|
|||||||
In version 10, [a few deprecated APIs have been removed](guide/updating-to-version-10#removals) and there are a [few breaking changes](guide/updating-to-version-10#breaking-changes) unrelated to Ivy.
|
In version 10, [a few deprecated APIs have been removed](guide/updating-to-version-10#removals) and there are a [few breaking changes](guide/updating-to-version-10#breaking-changes) unrelated to Ivy.
|
||||||
If you're seeing errors after updating to version 9, you'll first want to rule those changes out.
|
If you're seeing errors after updating to version 9, you'll first want to rule those changes out.
|
||||||
|
|
||||||
To do so, temporarily [turn off Ivy](guide/ivy#opting-out-of-angular-ivy) in your `tsconfig.json` and re-start your app.
|
To do so, temporarily [turn off Ivy](guide/ivy#opting-out-of-angular-ivy) in your `tsconfig.base.json` and re-start your app.
|
||||||
|
|
||||||
If you're still seeing the errors, they are not specific to Ivy. In this case, you may want to consult the [general version 10 guide](guide/updating-to-version-10). If you've opted into any of the new, stricter type-checking settings, you may also want to check out the [template type-checking guide](guide/template-typecheck).
|
If you're still seeing the errors, they are not specific to Ivy. In this case, you may want to consult the [general version 10 guide](guide/updating-to-version-10). If you've opted into any of the new, stricter type-checking settings, you may also want to check out the [template type-checking guide](guide/template-typecheck).
|
||||||
|
|
||||||
If the errors are gone, switch back to Ivy by removing the changes to the `tsconfig.json` and review the list of expected changes below.
|
If the errors are gone, switch back to Ivy by removing the changes to the `tsconfig.base.json` and review the list of expected changes below.
|
||||||
|
|
||||||
{@a payload-size-debugging}
|
{@a payload-size-debugging}
|
||||||
### Payload size debugging
|
### Payload size debugging
|
||||||
|
@ -87,7 +87,7 @@ To make one, enter the following command in the terminal, where `customers` is t
|
|||||||
ng generate module customers --route customers --module app.module
|
ng generate module customers --route customers --module app.module
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
This creates a `customers` folder having the new lazy-loadable feature module `CustomersModule` defined in the `customers.module.ts` file and the routing module `CustomersRoutingModule` defined in the `customers-routing.module.ts` file. The command automatically declares the `CustomersComponent` and imports `CustomersRoutingModule` inside the new feature module.
|
This creates a `customers` folder with the new lazy-loadable module `CustomersModule` defined in the `customers.module.ts` file. The command automatically declares the `CustomersComponent` inside the new feature module.
|
||||||
|
|
||||||
Because the new module is meant to be lazy-loaded, the command does NOT add a reference to the new feature module in the application's root module file, `app.module.ts`.
|
Because the new module is meant to be lazy-loaded, the command does NOT add a reference to the new feature module in the application's root module file, `app.module.ts`.
|
||||||
Instead, it adds the declared route, `customers` to the `routes` array declared in the module provided as the `--module` option.
|
Instead, it adds the declared route, `customers` to the `routes` array declared in the module provided as the `--module` option.
|
||||||
|
@ -62,8 +62,6 @@ Angular executes hook methods in the following sequence. You can use them to per
|
|||||||
|
|
||||||
Called before `ngOnInit()` and whenever one or more data-bound input properties change.
|
Called before `ngOnInit()` and whenever one or more data-bound input properties change.
|
||||||
|
|
||||||
Note that if your component has no inputs or you use it without providing any inputs, the framework will not call `ngOnChanges()`.
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr style='vertical-align:top'>
|
<tr style='vertical-align:top'>
|
||||||
|
@ -1,187 +0,0 @@
|
|||||||
# Optimizing client app size with lightweight injection tokens
|
|
||||||
|
|
||||||
This page provides a conceptual overview of a dependency injection technique that is recommended for library developers.
|
|
||||||
Designing your library with *lightweight injection tokens* helps optimize the bundle size of client applications that use your library.
|
|
||||||
|
|
||||||
You can manage the dependency structure among your components and injectable services to optimize bundle size by using [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers).
|
|
||||||
This normally ensures that if a provided component or service is never actually used by the app, the compiler can eliminate its code from the bundle.
|
|
||||||
|
|
||||||
However, due to the way Angular stores injection tokens, it is possible that such an unused component or service can end up in the bundle anyway.
|
|
||||||
This page describes a dependency-injection design pattern that supports proper tree-shaking by using lightweight injection tokens.
|
|
||||||
|
|
||||||
The lightweight injection token design pattern is especially important for library developers. It ensures that when an application uses only some of your library's capabilities, the unused code can be eliminated from the client's app bundle.
|
|
||||||
|
|
||||||
When an application uses your library, there might be some services that your library supplies which the client app doesn't use.
|
|
||||||
In this case, the app developer should expect that service to be tree-shaken, and not contribute to the size of the compiled app.
|
|
||||||
Because the application developer cannot know about or remedy a tree-shaking problem in the library, it is the responsibility of the library developer to do so.
|
|
||||||
To prevent the retention of unused components, your library should use the lightweight injection token design pattern.
|
|
||||||
|
|
||||||
## When tokens are retained
|
|
||||||
|
|
||||||
To better explain the condition under which token retention occurs, consider a library that provides a library-card component, which contains a body and can contain an optional header.
|
|
||||||
|
|
||||||
```
|
|
||||||
<lib-card>
|
|
||||||
<lib-header>...</lib-header>
|
|
||||||
</lib-card>
|
|
||||||
```
|
|
||||||
|
|
||||||
In a likely implementation, the `<lib-card>` component uses `@ContentChild()` or `@ContentChildren()` to obtain `<lib-header>` and `<lib-body>`, as in the following.
|
|
||||||
|
|
||||||
```
|
|
||||||
@Component({
|
|
||||||
selector: 'lib-header',
|
|
||||||
...,
|
|
||||||
})
|
|
||||||
class LibHeaderComponent {}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'lib-card',
|
|
||||||
...,
|
|
||||||
})
|
|
||||||
class LibCardComponent {
|
|
||||||
@ContentChild(LibHeaderComponent)
|
|
||||||
header: LibHeaderComponent|null = null;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Because `<lib-header>` is optional, the element can appear in the template in its minimal form,
|
|
||||||
`<lib-card></lib-card>`.
|
|
||||||
In this case, `<lib-header>` is not used and you would expect it to be tree-shaken, but that is not what happens.
|
|
||||||
This is because `LibCardComponent` actually contains two references to the `LibHeaderComponent`.
|
|
||||||
|
|
||||||
`@ContentChild(LibHeaderComponent) header: LibHeaderComponent;`
|
|
||||||
|
|
||||||
* One of these reference is in the *type position*-- that is, it specifies `LibHeaderComponent` as a type: `header: LibHeaderComponent;`.
|
|
||||||
|
|
||||||
* The other reference is in the *value position*-- that is, LibHeaderComponent is the value of the `@ContentChild()` parameter decorator: `@ContentChild(LibHeaderComponent)`.
|
|
||||||
|
|
||||||
The compiler handles token references in these positions differently.
|
|
||||||
|
|
||||||
* The compiler erases *type position* references after conversion from TypeScript, so they have no impact on tree-shaking.
|
|
||||||
|
|
||||||
* The compiler must retain *value position* references at runtime, which prevents the component from being tree-shaken.
|
|
||||||
|
|
||||||
In the example, the compiler retains the `LibHeaderComponent` token that occurs in the value position, which prevents the referenced component from being tree-shaken, even if the application developer does not actually use `<lib-header>` anywhere.
|
|
||||||
If `LibHeaderComponent` is large (code, template, and styles), including it unnecessarily can significantly increase the size of the client application.
|
|
||||||
|
|
||||||
## When to use the lightweight injection token pattern
|
|
||||||
|
|
||||||
The tree-shaking problem arises when a component is used as an injection token.
|
|
||||||
There are two cases when that can happen.
|
|
||||||
|
|
||||||
* The token is used in the value position of a [content query](guide/lifecycle-hooks#using-aftercontent-hooks "See more about using content queries.").
|
|
||||||
* The token is used as a type specifier for constructor injection.
|
|
||||||
|
|
||||||
In the following example, both uses of the `OtherComponent` token cause retention of `OtherComponent` (that is, prevent it from being tree-shaken when it is not used).
|
|
||||||
|
|
||||||
```
|
|
||||||
class MyComponent {
|
|
||||||
constructor(@Optional() other: OtherComponent) {}
|
|
||||||
|
|
||||||
@ContentChild(OtherComponent)
|
|
||||||
other: OtherComponent|null;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Although tokens used only as type specifiers are removed when converted to JavaScript, all tokens used for dependency injection are needed at runtime.
|
|
||||||
These effectively change `constructor(@Optional() other: OtherComponent)` to `constructor(@Optional() @Inject(OtherComponent) other)`. The token is now in a value position, and causes the tree shaker to retain the reference.
|
|
||||||
|
|
||||||
<div class="alert is helpful">
|
|
||||||
|
|
||||||
For all services, a library should use [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers), providing dependencies at the root level rather than in component constructors.
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Using lightweight injection tokens
|
|
||||||
|
|
||||||
The lightweight injection token design pattern consists of using a small abstract class as an injection token, and providing the actual implementation at a later stage.
|
|
||||||
The abstract class is retained (not tree-shaken), but it is small and has no material impact on the application size.
|
|
||||||
|
|
||||||
The following example shows how this works for the `LibHeaderComponent`.
|
|
||||||
|
|
||||||
```
|
|
||||||
abstract class LibHeaderToken {}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'lib-header',
|
|
||||||
providers: [
|
|
||||||
{provide: LibHeaderToken, useExisting: LibHeaderComponent}
|
|
||||||
]
|
|
||||||
...,
|
|
||||||
})
|
|
||||||
class LibHeaderComponent extends LibHeaderToken {}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'lib-card',
|
|
||||||
...,
|
|
||||||
})
|
|
||||||
class LibCardComponent {
|
|
||||||
@ContentChild(LibHeaderToken) header: LibHeaderToken|null = null;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In this example, the `LibCardComponent` implementation no longer refers to `LibHeaderComponent` in either the type position or the value position.
|
|
||||||
This allows full tree shaking of `LibHeaderComponent` to take place.
|
|
||||||
The `LibHeaderToken` is retained, but it is only a class declaration, with no concrete implementation. It is small and does not materially impact the application size when retained after compilation.
|
|
||||||
|
|
||||||
Instead, `LibHeaderComponent` itself implements the abstract `LibHeaderToken` class. You can safely use that token as the provider in the component definition, allowing Angular to correctly inject the concrete type.
|
|
||||||
|
|
||||||
To summarize, the lightweight injection token pattern consists of the following.
|
|
||||||
|
|
||||||
1. A lightweight injection token that is represented as an abstract class.
|
|
||||||
2. A component definition that implements the abstract class.
|
|
||||||
3. Injection of the lightweight pattern, using ` @ContentChild()` or `@ContentChildren()`.
|
|
||||||
4. A provider in the implementation of the lightweight injection token which associates the lightweight injection token with the implementation.
|
|
||||||
|
|
||||||
### Use the lightweight injection token for API definition
|
|
||||||
|
|
||||||
A component that injects a lightweight injection token might need to invoke a method in the injected class.
|
|
||||||
Because the token is now an abstract class, and the injectable component implements that class, you must also declare an abstract method in the abstract lightweight injection token class.
|
|
||||||
The implementation of the method (with all of its code overhead) resides in the injectable component that can be tree-shaken.
|
|
||||||
This allows the parent to communicate with the child (if it is present) in a type-safe manner.
|
|
||||||
|
|
||||||
For example, the `LibCardComponent` now queries `LibHeaderToken` rather than `LibHeaderComponent`.
|
|
||||||
The following example shows how the pattern allows `LibCardComponent` to communicate with the `LibHeaderComponent` without actually referring to `LibHeaderComponent`.
|
|
||||||
|
|
||||||
```
|
|
||||||
abstract class LibHeaderToken {
|
|
||||||
abstract doSomething(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'lib-header',
|
|
||||||
providers: [
|
|
||||||
{provide: LibHeaderToken, useExisting: LibHeader}
|
|
||||||
]
|
|
||||||
...,
|
|
||||||
})
|
|
||||||
class LibHeaderComponent extends LibHeaderToken {
|
|
||||||
doSomething(): void {
|
|
||||||
// Concrete implementation of `doSomething`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'lib-card',
|
|
||||||
...,
|
|
||||||
})
|
|
||||||
class LibCardComponent implement AfterContentInit {
|
|
||||||
@ContentChild(LibHeaderToken)
|
|
||||||
header: LibHeaderToken|null = null;
|
|
||||||
|
|
||||||
ngAfterContentInit(): void {
|
|
||||||
this.header && this.header.doSomething();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In this example the parent queries the token to obtain the child component, and stores the resulting component reference if it is present.
|
|
||||||
Before calling a method in the child, the parent component checks to see if the child component is present.
|
|
||||||
If the child component has been tree-shaken, there is no runtime reference to it, and no call to its method.
|
|
||||||
|
|
||||||
### Naming your lightweight injection token
|
|
||||||
|
|
||||||
Lightweight injection tokens are only useful with components. The Angular style guide suggests that you name components using the "Component" suffix. The example "LibHeaderComponent" follows this convention.
|
|
||||||
|
|
||||||
To maintain the relationship between the component and its token while still distinguishing between them, the recommended style is to use the component base name with the suffix "Token" to name your lightweight injection tokens: "LibHeaderToken".
|
|
55
aio/content/guide/migration-solution-style-tsconfig.md
Normal file
55
aio/content/guide/migration-solution-style-tsconfig.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Solution-style `tsconfig.json` migration
|
||||||
|
|
||||||
|
## What does this migration do?
|
||||||
|
|
||||||
|
This migration adds support to existing projects for TypeScript's new ["solution-style" tsconfig feature](https://devblogs.microsoft.com/typescript/announcing-typescript-3-9/#solution-style-tsconfig).
|
||||||
|
|
||||||
|
Support is added by making two changes:
|
||||||
|
|
||||||
|
1. Renaming the workspace-level `tsconfig.json` to `tsconfig.base.json`.
|
||||||
|
All project [TypeScript configuration files](guide/typescript-configuration) will extend from this base which contains the common options used throughout the workspace.
|
||||||
|
|
||||||
|
2. Adding the solution `tsconfig.json` file at the root of the workspace.
|
||||||
|
This `tsconfig.json` file will only contain references to project-level TypeScript configuration files and is only used by editors/IDEs.
|
||||||
|
|
||||||
|
As an example, the solution `tsconfig.json` for a new project is as follows:
|
||||||
|
```json
|
||||||
|
// This is a "Solution Style" tsconfig.json file, and is used by editors and TypeScript’s language server to improve development experience.
|
||||||
|
// It is not intended to be used to perform a compilation.
|
||||||
|
{
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./e2e/tsconfig.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why is this migration necessary?
|
||||||
|
|
||||||
|
Solution-style `tsconfig.json` files provide an improved editing experience and fix several long-standing defects when editing files in an IDE.
|
||||||
|
IDEs that leverage the TypeScript language service (for example, [Visual Studio Code](https://code.visualstudio.com)), will only use TypeScript configuration files that are named `tsconfig.json`.
|
||||||
|
In complex projects, there may be more than one compilation unit and each of these units may have different settings and options.
|
||||||
|
|
||||||
|
With the Angular CLI, a project will have application code that will target a browser.
|
||||||
|
It will also have unit tests that should not be included within the built application and that also need additional type information present (`jasmine` in this case).
|
||||||
|
Both parts of the project also share some but not all of the code within the project.
|
||||||
|
As a result, two separate TypeScript configuration files (`tsconfig.app.json` and `tsconfig.spec.json`) are needed to ensure that each part of the application is configured properly and that the right types are used for each part.
|
||||||
|
Also if web workers are used within a project, an additional tsconfig (`tsconfig.worker.json`) is needed.
|
||||||
|
Web workers use similar but incompatible types to the main browser application.
|
||||||
|
This requires the additional configuration file to ensure that the web worker files use the appropriate types and will build successfully.
|
||||||
|
|
||||||
|
While the Angular build system knows about all of these TypeScript configuration files, an IDE using TypeScript's language service does not.
|
||||||
|
Because of this, an IDE will not be able to properly analyze the code from each part of the project and may generate false errors or make suggestions that are incorrect for certain files.
|
||||||
|
By leveraging the new solution-style tsconfig, the IDE can now be aware of the configuration of each part of a project.
|
||||||
|
This allows each file to be treated appropriately based on its tsconfig.
|
||||||
|
IDE features such as error/warning reporting and auto-suggestion will operate more effectively as well.
|
||||||
|
|
||||||
|
The TypeScript 3.9 release [blog post](https://devblogs.microsoft.com/typescript/announcing-typescript-3-9/#solution-style-tsconfig) also contains some additional information regarding this new feature.
|
@ -9,7 +9,7 @@ This process helps ensure that intentional changes to the options are kept in pl
|
|||||||
|
|
||||||
TypeScript Configuration File(s) | Changed Property | Existing Value | New Value
|
TypeScript Configuration File(s) | Changed Property | Existing Value | New Value
|
||||||
------------- | ------------- | ------------- | ------------- | -------------
|
------------- | ------------- | ------------- | ------------- | -------------
|
||||||
`<workspace base>/tsconfig.json` | `"module"` | `"esnext"` | `"es2020"`
|
`<workspace base>/tsconfig.base.json` | `"module"` | `"esnext"` | `"es2020"`
|
||||||
Used in `browser` builder options (`ng build` for applications) | `"module"` | `"esnext"` | `"es2020"`
|
Used in `browser` builder options (`ng build` for applications) | `"module"` | `"esnext"` | `"es2020"`
|
||||||
Used in `ng-packgr` builder options (`ng build` for libraries) | `"module"` | `"esnext"` | `"es2020"`
|
Used in `ng-packgr` builder options (`ng build` for libraries) | `"module"` | `"esnext"` | `"es2020"`
|
||||||
Used in `karma` builder options (`ng test` for applications) | `"module"` | `"esnext"` | `"es2020"`
|
Used in `karma` builder options (`ng test` for applications) | `"module"` | `"esnext"` | `"es2020"`
|
||||||
|
@ -101,7 +101,7 @@ should import `BrowserModule` from `@angular/platform-browser`.
|
|||||||
`BrowserModule` provides services that are essential to launch and run a browser app.
|
`BrowserModule` provides services that are essential to launch and run a browser app.
|
||||||
|
|
||||||
`BrowserModule` also re-exports `CommonModule` from `@angular/common`,
|
`BrowserModule` also re-exports `CommonModule` from `@angular/common`,
|
||||||
which means that components in the `AppModule` also have access to
|
which means that components in the `AppModule` module also have access to
|
||||||
the Angular directives every app needs, such as `NgIf` and `NgFor`.
|
the Angular directives every app needs, such as `NgIf` and `NgFor`.
|
||||||
|
|
||||||
Do not import `BrowserModule` in any other module.
|
Do not import `BrowserModule` in any other module.
|
||||||
@ -140,7 +140,7 @@ declared in this NgModule.
|
|||||||
You _can_ export any declarable class—components, directives, and pipes—whether
|
You _can_ export any declarable class—components, directives, and pipes—whether
|
||||||
it's declared in this NgModule or in an imported NgModule.
|
it's declared in this NgModule or in an imported NgModule.
|
||||||
|
|
||||||
You _can_ re-export entire imported NgModules, which effectively re-export all of their exported classes.
|
You _can_ re-export entire imported NgModules, which effectively re-exports all of their exported classes.
|
||||||
An NgModule can even export a module that it doesn't import.
|
An NgModule can even export a module that it doesn't import.
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
@ -192,7 +192,7 @@ Its only purpose is to add http service providers to the application as a whole.
|
|||||||
|
|
||||||
The `forRoot()` static method is a convention that makes it easy for developers to configure services and providers that are intended to be singletons. A good example of `forRoot()` is the `RouterModule.forRoot()` method.
|
The `forRoot()` static method is a convention that makes it easy for developers to configure services and providers that are intended to be singletons. A good example of `forRoot()` is the `RouterModule.forRoot()` method.
|
||||||
|
|
||||||
Apps pass a `Routes` array to `RouterModule.forRoot()` in order to configure the app-wide `Router` service with routes.
|
Apps pass a `Routes` object to `RouterModule.forRoot()` in order to configure the app-wide `Router` service with routes.
|
||||||
`RouterModule.forRoot()` returns a [ModuleWithProviders](api/core/ModuleWithProviders).
|
`RouterModule.forRoot()` returns a [ModuleWithProviders](api/core/ModuleWithProviders).
|
||||||
You add that result to the `imports` list of the root `AppModule`.
|
You add that result to the `imports` list of the root `AppModule`.
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ NgModule metadata does the following:
|
|||||||
* Declares which components, directives, and pipes belong to the module.
|
* Declares which components, directives, and pipes belong to the module.
|
||||||
* Makes some of those components, directives, and pipes public so that other module's component templates can use them.
|
* Makes some of those components, directives, and pipes public so that other module's component templates can use them.
|
||||||
* Imports other modules with the components, directives, and pipes that components in the current module need.
|
* Imports other modules with the components, directives, and pipes that components in the current module need.
|
||||||
* Provides services that other application components can use.
|
* Provides services that the other application components can use.
|
||||||
|
|
||||||
Every Angular app has at least one module, the root module.
|
Every Angular app has at least one module, the root module.
|
||||||
You [bootstrap](guide/bootstrapping) that module to launch the application.
|
You [bootstrap](guide/bootstrapping) that module to launch the application.
|
||||||
|
@ -223,6 +223,6 @@ content harmlessly. The following is the browser output
|
|||||||
of the `evilTitle` examples.
|
of the `evilTitle` examples.
|
||||||
|
|
||||||
<code-example language="bash">
|
<code-example language="bash">
|
||||||
"Template <script>alert("evil never sleeps")</script> Syntax" is the interpolated evil title.
|
"Template <script>alert("evil never sleeps")</script> Syntax" is the interpolated evil title.
|
||||||
"Template Syntax" is the property bound evil title.
|
"Template alert("evil never sleeps")Syntax" is the property bound evil title.
|
||||||
</code-example>
|
</code-example>
|
||||||
|
@ -94,7 +94,7 @@ All of our major releases are supported for 18 months.
|
|||||||
|
|
||||||
* 6 months of *active support*, during which regularly-scheduled updates and patches are released.
|
* 6 months of *active support*, during which regularly-scheduled updates and patches are released.
|
||||||
|
|
||||||
* 12 months of *long-term support (LTS)*, during which only [critical fixes and security patches](#lts-fixes) are released.
|
* 12 months of *long-term support (LTS)*, during which only critical fixes and security patches are released.
|
||||||
|
|
||||||
The following table provides the status for Angular versions under support.
|
The following table provides the status for Angular versions under support.
|
||||||
|
|
||||||
@ -102,18 +102,11 @@ The following table provides the status for Angular versions under support.
|
|||||||
Version | Status | Released | Active Ends | LTS Ends
|
Version | Status | Released | Active Ends | LTS Ends
|
||||||
------- | ------ | ------------ | ------------ | ------------
|
------- | ------ | ------------ | ------------ | ------------
|
||||||
^10.0.0 | Active | Jun 24, 2020 | Dec 24, 2020 | Dec 24, 2021
|
^10.0.0 | Active | Jun 24, 2020 | Dec 24, 2020 | Dec 24, 2021
|
||||||
^9.0.0 | LTS | Feb 06, 2020 | Aug 06, 2020 | Aug 06, 2021
|
^9.0.0 | Active | Feb 06, 2020 | Aug 06, 2020 | Aug 06, 2021
|
||||||
^8.0.0 | LTS | May 28, 2019 | Nov 28, 2019 | Nov 28, 2020
|
^8.0.0 | LTS | May 28, 2019 | Nov 28, 2019 | Nov 28, 2020
|
||||||
|
|
||||||
Angular versions ^4.0.0, ^5.0.0, ^6.0.0 and ^7.0.0 are no longer under support.
|
Angular versions ^4.0.0, ^5.0.0, ^6.0.0 and ^7.0.0 are no longer under support.
|
||||||
|
|
||||||
### LTS fixes
|
|
||||||
|
|
||||||
As a general rule, a fix is considered for an LTS version if it resolves one of:
|
|
||||||
|
|
||||||
* a newly identified security vulnerability,
|
|
||||||
* a regression, since the start of LTS, caused by a 3rd party change, such as a new browser version.
|
|
||||||
|
|
||||||
{@a deprecation}
|
{@a deprecation}
|
||||||
## Deprecation practices
|
## Deprecation practices
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ RxJS provides many operators, but only a handful are used frequently. For a list
|
|||||||
|
|
||||||
| Area | Operators |
|
| Area | Operators |
|
||||||
| :------------| :----------|
|
| :------------| :----------|
|
||||||
| Creation | `from`, `fromEvent`, `of` |
|
| Creation | `from`,`fromEvent`, `of` |
|
||||||
| Combination | `combineLatest`, `concat`, `merge`, `startWith` , `withLatestFrom`, `zip` |
|
| Combination | `combineLatest`, `concat`, `merge`, `startWith` , `withLatestFrom`, `zip` |
|
||||||
| Filtering | `debounceTime`, `distinctUntilChanged`, `filter`, `take`, `takeUntil` |
|
| Filtering | `debounceTime`, `distinctUntilChanged`, `filter`, `take`, `takeUntil` |
|
||||||
| Transformation | `bufferTime`, `concatMap`, `map`, `mergeMap`, `scan`, `switchMap` |
|
| Transformation | `bufferTime`, `concatMap`, `map`, `mergeMap`, `scan`, `switchMap` |
|
||||||
|
@ -67,33 +67,6 @@ Therefore, it is recommended to reload the page once the promise returned by `ac
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
### Handling an unrecoverable state
|
|
||||||
|
|
||||||
In some cases, the version of the app used by the service worker to serve a client might be in a broken state that cannot be recovered from without a full page reload.
|
|
||||||
|
|
||||||
For example, imagine the following scenario:
|
|
||||||
- A user opens the app for the first time and the service worker caches the latest version of the app.
|
|
||||||
Let's assume the app's cached assets include `index.html`, `main.<main-hash-1>.js` and `lazy-chunk.<lazy-hash-1>.js`.
|
|
||||||
- The user closes the app and does not open it for a while.
|
|
||||||
- After some time, a new version of the app is deployed to the server.
|
|
||||||
This newer version includes the files `index.html`, `main.<main-hash-2>.js` and `lazy-chunk.<lazy-hash-2>.js` (note that the hashes are different now, because the content of the files has changed).
|
|
||||||
The old version is no longer available on the server.
|
|
||||||
- In the meantime, the user's browser decides to evict `lazy-chunk.<lazy-hash-1>.js` from its cache.
|
|
||||||
Browsers may decide to evict specific (or all) resources from a cache in order to reclaim disk space.
|
|
||||||
- The user opens the app again.
|
|
||||||
The service worker serves the latest version known to it at this point, namely the old version (`index.html` and `main.<main-hash-1>.js`).
|
|
||||||
- At some later point, the app requests the lazy bundle, `lazy-chunk.<lazy-hash-1>.js`.
|
|
||||||
- The service worker is unable to find the asset in the cache (remember that the browser evicted it).
|
|
||||||
Nor is it able to retrieve it from the server (since the server now only has `lazy-chunk.<lazy-hash-2>.js` from the newer version).
|
|
||||||
|
|
||||||
In the above scenario, the service worker is not able to serve an asset that would normally be cached.
|
|
||||||
That particular app version is broken and there is no way to fix the state of the client without reloading the page.
|
|
||||||
In such cases, the service worker notifies the client by sending an `UnrecoverableStateEvent` event.
|
|
||||||
You can subscribe to `SwUpdate#unrecoverable` to be notified and handle these errors.
|
|
||||||
|
|
||||||
<code-example path="service-worker-getting-started/src/app/handle-unrecoverable-state.service.ts" header="handle-unrecoverable-state.service.ts" region="sw-unrecoverable-state"></code-example>
|
|
||||||
|
|
||||||
|
|
||||||
## More on Angular service workers
|
## More on Angular service workers
|
||||||
|
|
||||||
You may also be interested in the following:
|
You may also be interested in the following:
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user