Compare commits
64 Commits
6.0.0-rc.5
...
mprobst-ng
Author | SHA1 | Date | |
---|---|---|---|
ab41920e30 | |||
ca776c59dd | |||
f2563ca800 | |||
9757347e71 | |||
a19e018439 | |||
6ff164be0e | |||
84f024309a | |||
c6b206ee4b | |||
1d1e75ee2b | |||
acf6781ccc | |||
fd48e53986 | |||
fe312ccb4c | |||
764f471dc0 | |||
8b02c0e769 | |||
5a2ee7a6f5 | |||
529d4fc9ee | |||
fac7dde5b1 | |||
1f005908a4 | |||
2278fe8f0e | |||
aad3444a58 | |||
44377adbcc | |||
b28b3acb83 | |||
7493435911 | |||
937f7cea37 | |||
7d1990e4d1 | |||
76f8ae31ad | |||
103846a51d | |||
0a536af093 | |||
4f29287399 | |||
62e6c1f43a | |||
c3c513ed9e | |||
ed495bc9f1 | |||
a3de5f8f20 | |||
2491b7249a | |||
a851ba3781 | |||
0468a649af | |||
47d3acdc49 | |||
acbfb9eb4d | |||
d35f84a167 | |||
87e9f333d4 | |||
08fc4f3ad8 | |||
c6c79ab5dc | |||
6837491f08 | |||
fc5af69fb2 | |||
81ccb718b1 | |||
0c56dfadef | |||
7be7abdebd | |||
5a1ddee88c | |||
99f8e10809 | |||
d665d9a18c | |||
8b2101be9f | |||
0d56cee9e1 | |||
7f612fc828 | |||
010a4efa8c | |||
c3280b2c2f | |||
d11b249d36 | |||
9c29127723 | |||
43615604d1 | |||
d9792309ec | |||
fd1c39ce42 | |||
896811df64 | |||
fb59b2dd97 | |||
b64a276d4b | |||
815ae29b83 |
@ -162,7 +162,7 @@ groups:
|
||||
files:
|
||||
- "packages/compiler/*"
|
||||
users:
|
||||
- chuckjaz #primary
|
||||
- alxhub #primary
|
||||
- vicb
|
||||
- mhevery
|
||||
- IgorMinar #fallback
|
||||
|
43
CHANGELOG.md
43
CHANGELOG.md
@ -1,5 +1,36 @@
|
||||
<a name="5.2.10"></a>
|
||||
## [5.2.10](https://github.com/angular/angular/compare/5.2.9...5.2.10) (2018-04-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animations:** avoid animation insertions during router back/refresh ([#21977](https://github.com/angular/angular/issues/21977)) ([641cc49](https://github.com/angular/angular/commit/641cc49)), closes [#19712](https://github.com/angular/angular/issues/19712)
|
||||
* **common:** properly take className changes into account ([#21937](https://github.com/angular/angular/issues/21937)) ([54e9108](https://github.com/angular/angular/commit/54e9108)), closes [#21932](https://github.com/angular/angular/issues/21932)
|
||||
* **compiler:** fix support for html-like text in translatable attributes ([#23053](https://github.com/angular/angular/issues/23053)) ([4f7c369](https://github.com/angular/angular/commit/4f7c369))
|
||||
* **compiler-cli:** emit correct css string escape sequences ([#22776](https://github.com/angular/angular/issues/22776)) ([db0afa9](https://github.com/angular/angular/commit/db0afa9))
|
||||
* **forms:** improve error message for invalid value accessors ([#22731](https://github.com/angular/angular/issues/22731)) ([dd61595](https://github.com/angular/angular/commit/dd61595))
|
||||
* **service-worker:** add badge to NOTIFICATION_OPTION_NAMES ([#23241](https://github.com/angular/angular/issues/23241)) ([7b23983](https://github.com/angular/angular/commit/7b23983)), closes [#23196](https://github.com/angular/angular/issues/23196)
|
||||
* **service-worker:** do not enter degraded mode when offline ([#22883](https://github.com/angular/angular/issues/22883)) ([ae9c25f](https://github.com/angular/angular/commit/ae9c25f)), closes [#21636](https://github.com/angular/angular/issues/21636)
|
||||
* **service-worker:** fix LruList bugs ([#22769](https://github.com/angular/angular/issues/22769)) ([65f8943](https://github.com/angular/angular/commit/65f8943)), closes [#22218](https://github.com/angular/angular/issues/22218) [#22768](https://github.com/angular/angular/issues/22768)
|
||||
* **service-worker:** ignore invalid `only-if-cached` requests ([#22883](https://github.com/angular/angular/issues/22883)) ([0d4fe38](https://github.com/angular/angular/commit/0d4fe38)), closes [#22362](https://github.com/angular/angular/issues/22362)
|
||||
* **upgrade:** correctly handle downgraded `OnPush` components ([#22209](https://github.com/angular/angular/issues/22209)) ([f43fba6](https://github.com/angular/angular/commit/f43fba6)), closes [#14286](https://github.com/angular/angular/issues/14286)
|
||||
* **upgrade:** propagate return value of resumeBootstrap ([#22754](https://github.com/angular/angular/issues/22754)) ([ae76eec](https://github.com/angular/angular/commit/ae76eec)), closes [#22723](https://github.com/angular/angular/issues/22723)
|
||||
* **upgrade:** two-way binding and listening for event ([#22772](https://github.com/angular/angular/issues/22772)) ([5391f96](https://github.com/angular/angular/commit/5391f96)), closes [#22734](https://github.com/angular/angular/issues/22734)
|
||||
|
||||
|
||||
|
||||
<a name="4.4.7"></a>
|
||||
## [4.4.7](https://github.com/angular/angular/compare/4.4.6...4.4.7) (2018-04-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** use appropriate inert document strategy for Firefox & Safari ([#22077](https://github.com/angular/angular/issues/22077)) ([2c5cf19](https://github.com/angular/angular/commit/2c5cf19))
|
||||
|
||||
|
||||
|
||||
<a name="6.0.0-rc.5"></a>
|
||||
# [6.0.0-rc.5](https://github.com/angular/angular/compare/6.0.0-rc.4...6.0.0-rc.5) (2018-04-14)
|
||||
## [6.0.0-rc.5](https://github.com/angular/angular/compare/6.0.0-rc.4...6.0.0-rc.5) (2018-04-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
@ -18,7 +49,7 @@
|
||||
|
||||
|
||||
<a name="6.0.0-rc.4"></a>
|
||||
# [6.0.0-rc.4](https://github.com/angular/angular/compare/6.0.0-rc.3...6.0.0-rc.4) (2018-04-12)
|
||||
## [6.0.0-rc.4](https://github.com/angular/angular/compare/6.0.0-rc.3...6.0.0-rc.4) (2018-04-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
@ -39,7 +70,7 @@
|
||||
|
||||
|
||||
<a name="6.0.0-rc.3"></a>
|
||||
# [6.0.0-rc.3](https://github.com/angular/angular/compare/6.0.0-rc.2...6.0.0-rc.3) (2018-04-06)
|
||||
## [6.0.0-rc.3](https://github.com/angular/angular/compare/6.0.0-rc.2...6.0.0-rc.3) (2018-04-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
@ -50,7 +81,7 @@
|
||||
|
||||
|
||||
<a name="6.0.0-rc.2"></a>
|
||||
# [6.0.0-rc.2](https://github.com/angular/angular/compare/6.0.0-rc.1...6.0.0-rc.2) (2018-04-05)
|
||||
## [6.0.0-rc.2](https://github.com/angular/angular/compare/6.0.0-rc.1...6.0.0-rc.2) (2018-04-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
@ -71,7 +102,7 @@
|
||||
|
||||
|
||||
<a name="6.0.0-rc.1"></a>
|
||||
# [6.0.0-rc.1](https://github.com/angular/angular/compare/6.0.0-rc.0...6.0.0-rc.1) (2018-03-30)
|
||||
## [6.0.0-rc.1](https://github.com/angular/angular/compare/6.0.0-rc.0...6.0.0-rc.1) (2018-03-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
@ -131,7 +162,7 @@ possible, and ideally also a include a good reproduction of the problem.
|
||||
|
||||
|
||||
<a name="6.0.0-beta.8"></a>
|
||||
# [6.0.0-beta.8](https://github.com/angular/angular/compare/6.0.0-beta.7...6.0.0-beta.8) (2018-03-16)
|
||||
## [6.0.0-beta.8](https://github.com/angular/angular/compare/6.0.0-beta.7...6.0.0-beta.8) (2018-03-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
@ -1,73 +0,0 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"project": {
|
||||
"name": "site"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"root": "src",
|
||||
"outDir": "dist",
|
||||
"assets": [
|
||||
"assets",
|
||||
"generated",
|
||||
"app/search/search-worker.js",
|
||||
"favicon.ico",
|
||||
"pwa-manifest.json",
|
||||
"google385281288605d160.html",
|
||||
{ "glob": "custom-elements.min.js", "input": "../node_modules/@webcomponents/custom-elements", "output": "./assets/js" },
|
||||
{ "glob": "native-shim.js", "input": "../node_modules/@webcomponents/custom-elements/src", "output": "./assets/js" }
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
"polyfills": "polyfills.ts",
|
||||
"test": "test.ts",
|
||||
"tsconfig": "tsconfig.app.json",
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "aio",
|
||||
"serviceWorker": false,
|
||||
"styles": [
|
||||
"styles.scss"
|
||||
],
|
||||
"scripts": [
|
||||
],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"next": "environments/environment.next.ts",
|
||||
"stable": "environments/environment.stable.ts",
|
||||
"archive": "environments/environment.archive.ts"
|
||||
}
|
||||
}
|
||||
],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "tests/e2e/protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json"
|
||||
},
|
||||
{
|
||||
"project": "tests/e2e/tsconfig.e2e.json"
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "src/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"styleExt": "scss",
|
||||
"component": {
|
||||
"inlineStyle": true
|
||||
},
|
||||
"build": {
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn"
|
||||
}
|
@ -22,7 +22,8 @@ Here are the most important tasks you might need to use:
|
||||
* `yarn start` - run a development web server that watches the files; then builds the doc-viewer and reloads the page, as necessary.
|
||||
* `yarn serve-and-sync` - run both the `docs-watch` and `start` in the same console.
|
||||
* `yarn lint` - check that the doc-viewer code follows our style rules.
|
||||
* `yarn test` - watch all the source files, for the doc-viewer, and run all the unit tests when any change.
|
||||
* `yarn test` - run all the unit tests once.
|
||||
* `yarn test --watch` - watch all the source files, for the doc-viewer, and run all the unit tests when any change.
|
||||
* `yarn e2e` - run all the e2e tests for the doc-viewer.
|
||||
|
||||
* `yarn docs` - generate all the docs from the source files.
|
||||
|
235
aio/angular.json
Normal file
235
aio/angular.json
Normal file
@ -0,0 +1,235 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular-devkit/core/src/workspace/workspace-schema.json",
|
||||
"version": 1,
|
||||
"cli": {
|
||||
"packageManager": "yarn"
|
||||
},
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"site": {
|
||||
"root": "",
|
||||
"projectType": "application",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"tsConfig": "src/tsconfig.app.json",
|
||||
"aot": true,
|
||||
"optimization": true,
|
||||
"buildOptimizer": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": true,
|
||||
"statsJson": true,
|
||||
"extractCss": true,
|
||||
"extractLicenses": true,
|
||||
"namedChunks": true,
|
||||
"vendorChunk": false,
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "src/assets",
|
||||
"output": "/assets"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "src/generated",
|
||||
"output": "/generated"
|
||||
},
|
||||
{
|
||||
"glob": "app/search/search-worker.js",
|
||||
"input": "src",
|
||||
"output": "/"
|
||||
},
|
||||
{
|
||||
"glob": "favicon.ico",
|
||||
"input": "src",
|
||||
"output": "/"
|
||||
},
|
||||
{
|
||||
"glob": "pwa-manifest.json",
|
||||
"input": "src",
|
||||
"output": "/"
|
||||
},
|
||||
{
|
||||
"glob": "google385281288605d160.html",
|
||||
"input": "src",
|
||||
"output": "/"
|
||||
},
|
||||
{
|
||||
"glob": "custom-elements.min.js",
|
||||
"input": "node_modules/@webcomponents/custom-elements",
|
||||
"output": "/assets/js"
|
||||
},
|
||||
{
|
||||
"glob": "native-shim.js",
|
||||
"input": "node_modules/@webcomponents/custom-elements/src",
|
||||
"output": "/assets/js"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
{
|
||||
"input": "src/styles.scss"
|
||||
}
|
||||
],
|
||||
"scripts": [],
|
||||
|
||||
},
|
||||
"configurations": {
|
||||
"next": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"src": "src/environments/environment.ts",
|
||||
"replaceWith": "src/environments/environment.next.ts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"stable": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"src": "src/environments/environment.ts",
|
||||
"replaceWith": "src/environments/environment.stable.ts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"archive": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"src": "src/environments/environment.ts",
|
||||
"replaceWith": "src/environments/environment.archive.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "site:build"
|
||||
},
|
||||
"configurations": {
|
||||
"next": {
|
||||
"browserTarget": "site:build:next"
|
||||
},
|
||||
"stable": {
|
||||
"browserTarget": "site:build:stable"
|
||||
},
|
||||
"archive": {
|
||||
"browserTarget": "site:build:archive"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "site:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"karmaConfig": "src/karma.conf.js",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "src/tsconfig.spec.json",
|
||||
"scripts": [],
|
||||
"styles": [
|
||||
{
|
||||
"input": "src/styles.scss"
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "src/assets",
|
||||
"output": "/assets"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "src/generated",
|
||||
"output": "/generated"
|
||||
},
|
||||
{
|
||||
"glob": "app/search/search-worker.js",
|
||||
"input": "src",
|
||||
"output": "/"
|
||||
},
|
||||
{
|
||||
"glob": "favicon.ico",
|
||||
"input": "src",
|
||||
"output": "/"
|
||||
},
|
||||
{
|
||||
"glob": "pwa-manifest.json",
|
||||
"input": "src",
|
||||
"output": "/"
|
||||
},
|
||||
{
|
||||
"glob": "google385281288605d160.html",
|
||||
"input": "src",
|
||||
"output": "/"
|
||||
},
|
||||
{
|
||||
"glob": "custom-elements.min.js",
|
||||
"input": "node_modules/@webcomponents/custom-elements",
|
||||
"output": "/assets/js"
|
||||
},
|
||||
{
|
||||
"glob": "native-shim.js",
|
||||
"input": "node_modules/@webcomponents/custom-elements/src",
|
||||
"output": "/assets/js"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"src/tsconfig.app.json",
|
||||
"src/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"site-e2e": {
|
||||
"root": "",
|
||||
"projectType": "application",
|
||||
"cli": {},
|
||||
"schematics": {},
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "tests/e2e/protractor.conf.js",
|
||||
"devServerTarget": "site:serve"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"tests/e2e/tsconfig.e2e.json"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"inlineStyle": true,
|
||||
"prefix": "aio",
|
||||
"styleext": "scss"
|
||||
},
|
||||
"@schematics/angular:directive": {
|
||||
"prefix": "aio"
|
||||
}
|
||||
}
|
||||
}
|
6
aio/content/examples/.gitignore
vendored
6
aio/content/examples/.gitignore
vendored
@ -13,18 +13,20 @@
|
||||
**/src/tsconfig.app.json
|
||||
**/src/tsconfig.spec.json
|
||||
**/src/typings.d.ts
|
||||
**/e2e/app.po.ts
|
||||
**/e2e/src/app.po.ts
|
||||
**/e2e/tsconfig.e2e.json
|
||||
**/src/karma.conf.js
|
||||
**/.angular-cli.json
|
||||
**/.editorconfig
|
||||
**/angular.json
|
||||
**/tsconfig.json
|
||||
**/bs-config.e2e.json
|
||||
**/bs-config.json
|
||||
**/package.json
|
||||
**/tslint.json
|
||||
**/karma.conf.js
|
||||
**/karma-test-shim.js
|
||||
**/browser-test-shim.js
|
||||
**/browserslist
|
||||
**/node_modules
|
||||
|
||||
# built files
|
||||
|
@ -50,7 +50,7 @@ const templateC = `
|
||||
})
|
||||
// #docregion carol-class
|
||||
export class CarolComponent {
|
||||
name= 'Carol';
|
||||
name = 'Carol';
|
||||
// #docregion carol-ctor
|
||||
constructor( @Optional() public parent: Parent ) { }
|
||||
// #enddocregion carol-ctor
|
||||
@ -63,7 +63,7 @@ export class CarolComponent {
|
||||
template: templateC
|
||||
})
|
||||
export class ChrisComponent {
|
||||
name= 'Chris';
|
||||
name = 'Chris';
|
||||
constructor( @Optional() public parent: Parent ) { }
|
||||
}
|
||||
|
||||
@ -116,7 +116,7 @@ export class BarryComponent implements Parent {
|
||||
providers: [ provideParent(BobComponent) ]
|
||||
})
|
||||
export class BobComponent implements Parent {
|
||||
name= 'Bob';
|
||||
name = 'Bob';
|
||||
constructor( @SkipSelf() @Optional() public parent: Parent ) { }
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ export class BobComponent implements Parent {
|
||||
// #enddocregion beth-providers
|
||||
})
|
||||
export class BethComponent implements Parent {
|
||||
name= 'Beth';
|
||||
name = 'Beth';
|
||||
constructor( @SkipSelf() @Optional() public parent: Parent ) { }
|
||||
}
|
||||
|
||||
@ -157,7 +157,7 @@ export class BethComponent implements Parent {
|
||||
export class AlexComponent extends Base
|
||||
// #enddocregion alex-class-signature
|
||||
{
|
||||
name= 'Alex';
|
||||
name = 'Alex';
|
||||
}
|
||||
// #enddocregion alex, alex-1
|
||||
|
||||
@ -182,7 +182,7 @@ export class AlexComponent extends Base
|
||||
export class AliceComponent implements Parent
|
||||
// #enddocregion alice-class-signature
|
||||
{
|
||||
name= 'Alice';
|
||||
name = 'Alice';
|
||||
}
|
||||
// #enddocregion alice
|
||||
|
||||
|
@ -187,7 +187,7 @@ describe('Dependency Injection Tests', function () {
|
||||
let heroes = element.all(by.css('#authorized app-hero-list div'));
|
||||
expect(heroes.count()).toBeGreaterThan(0);
|
||||
|
||||
let filteredHeroes = heroes.filter(function(elem: ElementFinder, index: number){
|
||||
let filteredHeroes = heroes.filter(function(elem: ElementFinder, index: number) {
|
||||
return elem.getText().then(function(text: string) {
|
||||
return /secret/.test(text);
|
||||
});
|
@ -19,7 +19,7 @@ import { AdComponent } from './ad.component';
|
||||
// #docregion class
|
||||
export class AdBannerComponent implements OnInit, OnDestroy {
|
||||
@Input() ads: AdItem[];
|
||||
currentAdIndex: number = -1;
|
||||
currentAdIndex = -1;
|
||||
@ViewChild(AdDirective) adHost: AdDirective;
|
||||
interval: any;
|
||||
|
||||
|
@ -6,8 +6,8 @@ import { AdComponent } from './ad.component';
|
||||
@Component({
|
||||
template: `
|
||||
<div class="job-ad">
|
||||
<h4>{{data.headline}}</h4>
|
||||
|
||||
<h4>{{data.headline}}</h4>
|
||||
|
||||
{{data.body}}
|
||||
</div>
|
||||
`
|
||||
|
@ -8,7 +8,7 @@ import { AdComponent } from './ad.component';
|
||||
<div class="hero-profile">
|
||||
<h3>Featured Hero Profile</h3>
|
||||
<h4>{{data.name}}</h4>
|
||||
|
||||
|
||||
<p>{{data.bio}}</p>
|
||||
|
||||
<strong>Hire this hero today!</strong>
|
||||
|
@ -21,7 +21,7 @@ describe('Dynamic Form', function () {
|
||||
element(by.css('select option[value="solid"]')).click();
|
||||
|
||||
let saveButton = element.all(by.css('button')).get(0);
|
||||
saveButton.click().then(function(){
|
||||
saveButton.click().then(function() {
|
||||
expect(element(by.xpath("//strong[contains(text(),'Saved the following values')]")).isPresent()).toBe(true);
|
||||
});
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
// #docregion
|
||||
export class QuestionBase<T>{
|
||||
export class QuestionBase<T> {
|
||||
value: T;
|
||||
key: string;
|
||||
label: string;
|
||||
|
@ -88,7 +88,8 @@ describe('Router', () => {
|
||||
await crisisCenterEdit(2, true);
|
||||
});
|
||||
|
||||
it('can cancel changed crisis details', async () => {
|
||||
// TODO: Figure out why this test is failing now
|
||||
xit('can cancel changed crisis details', async () => {
|
||||
const page = getPageStruct();
|
||||
await page.crisisHref.click();
|
||||
await crisisCenterEdit(3, false);
|
@ -44,10 +44,7 @@ class Hero {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(i): temorarily disable these tests because angular-in-memory-web-api is not compatible with rxjs v6 yet
|
||||
// and we don't have the backwards compatibility package yet.
|
||||
// Reenable after rxjs v6 compatibility package is out or angular-in-memory-web-api is compatible with rxjs v6
|
||||
xdescribe('Tutorial part 6', () => {
|
||||
describe('Tutorial part 6', () => {
|
||||
|
||||
beforeAll(() => browser.get(''));
|
||||
|
@ -36,10 +36,6 @@
|
||||
'rxjs/operators': {main: 'index.js', defaultExtension: 'js' },
|
||||
'rxjs/testing': {main: 'index.js', defaultExtension: 'js' },
|
||||
'rxjs/websocket': {main: 'index.js', defaultExtension: 'js' },
|
||||
'rxjs/ajax': {main: 'index.js', defaultExtension: 'js' },
|
||||
'rxjs/operators': {main: 'index.js', defaultExtension: 'js' },
|
||||
'rxjs/testing': {main: 'index.js', defaultExtension: 'js' },
|
||||
'rxjs/websocket': {main: 'index.js', defaultExtension: 'js' },
|
||||
'rxjs': { main: 'index.js', defaultExtension: 'js' },
|
||||
}
|
||||
});
|
||||
|
@ -22,7 +22,7 @@ Angular creates, updates, and destroys components as the user moves through the
|
||||
|
||||
<img src="generated/images/guide/architecture/metadata.png" alt="Metadata" class="left">
|
||||
|
||||
The `@Component` decorator identifies the class immediately below it as a component class, and specifies its metadata. In the example code below, you can see that `HeroListComponent` is just a class, with no special Angular notation or syntax at all. It's not a component until mark it as one with the `@Component` decorator.
|
||||
The `@Component` decorator identifies the class immediately below it as a component class, and specifies its metadata. In the example code below, you can see that `HeroListComponent` is just a class, with no special Angular notation or syntax at all. It's not a component until you mark it as one with the `@Component` decorator.
|
||||
|
||||
The metadata for a component tells Angular where to get the major building blocks it needs to create and present the component and its view. In particular, it associates a _template_ with the component, either directly with inline code, or by reference. Together, the component and its template describe a _view_.
|
||||
|
||||
@ -76,7 +76,7 @@ This template uses typical HTML elements like `<h2>` and `<p>`, and also includ
|
||||
|
||||
Without a framework, you would be responsible for pushing data values into the HTML controls and turning user responses into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone, and a nightmare to read, as any experienced jQuery programmer can attest.
|
||||
|
||||
Angular supports *two-way data binding*, a mechanism for coordinating parts of a template with parts of a component. Add binding markup to the template HTML to tell Angular how to connect both sides.
|
||||
Angular supports *two-way data binding*, a mechanism for coordinating parts of a template with parts of a component. Add binding markup to the template HTML to tell Angular how to connect both sides.
|
||||
|
||||
The following diagram shows the four forms of data binding markup. Each form has a direction—to the DOM, from the DOM, or in both directions.
|
||||
|
||||
|
@ -311,11 +311,11 @@ so the <code>@Directive</code> configuration applies to components as well</p>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td><code><b>ngAfterViewInit()</b> { ... }</code></td>
|
||||
<td><p>Called after <code>ngAfterContentInit</code> when the component's view has been initialized. Applies to components only.</p>
|
||||
<td><p>Called after <code>ngAfterContentInit</code> when the component's views and child views / the view that a directive is in has been initialized.</p>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td><code><b>ngAfterViewChecked()</b> { ... }</code></td>
|
||||
<td><p>Called after every check of the component's view. Applies to components only.</p>
|
||||
<td><p>Called after every check of the component's views and child views / the view that a directive is in.</p>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td><code><b>ngOnDestroy()</b> { ... }</code></td>
|
||||
|
@ -249,7 +249,7 @@ An observable produces values over time. An array is created as a static set of
|
||||
<pre>➞5</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre>arr.find((v) => v>10)</pre>
|
||||
<pre>arr.find((v) => v>3)</pre>
|
||||
<pre>5</pre>
|
||||
</td>
|
||||
</tr>
|
||||
@ -273,8 +273,8 @@ An observable produces values over time. An array is created as a static set of
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5</pre>
|
||||
5
|
||||
7</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre>arr.forEach((v) => {
|
||||
@ -283,8 +283,8 @@ An observable produces values over time. An array is created as a static set of
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5</pre>
|
||||
5
|
||||
7</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -61,7 +61,7 @@ The running application displays three heroes:
|
||||
E2E test that all children were instantiated and displayed as expected:
|
||||
|
||||
|
||||
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="parent-to-child" title="component-interaction/e2e/app.e2e-spec.ts">
|
||||
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child" title="component-interaction/e2e/src/app.e2e-spec.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
@ -105,7 +105,7 @@ Here's the `NameParentComponent` demonstrating name variations including a name
|
||||
E2E tests of input property setter with empty and non-empty names:
|
||||
|
||||
|
||||
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="parent-to-child-setter" title="component-interaction/e2e/app.e2e-spec.ts">
|
||||
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-setter" title="component-interaction/e2e/src/app.e2e-spec.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
@ -164,7 +164,7 @@ Test that ***both*** input properties are set initially and that button clicks t
|
||||
the expected `ngOnChanges` calls and values:
|
||||
|
||||
|
||||
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="parent-to-child-onchanges" title="component-interaction/e2e/app.e2e-spec.ts">
|
||||
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-onchanges" title="component-interaction/e2e/src/app.e2e-spec.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
@ -217,7 +217,7 @@ and the method processes it:
|
||||
Test that clicking the *Agree* and *Disagree* buttons update the appropriate counters:
|
||||
|
||||
|
||||
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="child-to-parent" title="component-interaction/e2e/app.e2e-spec.ts">
|
||||
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="child-to-parent" title="component-interaction/e2e/src/app.e2e-spec.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
@ -284,7 +284,7 @@ match the seconds displayed in the child's status message.
|
||||
Test also that clicking the *Stop* button pauses the countdown timer:
|
||||
|
||||
|
||||
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="countdown-timer-tests" title="component-interaction/e2e/app.e2e-spec.ts">
|
||||
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="countdown-timer-tests" title="component-interaction/e2e/src/app.e2e-spec.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
@ -433,7 +433,7 @@ Tests click buttons of both the parent `MissionControlComponent` and the `Astron
|
||||
and verify that the history meets expectations:
|
||||
|
||||
|
||||
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="bidirectional-service" title="component-interaction/e2e/app.e2e-spec.ts">
|
||||
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="bidirectional-service" title="component-interaction/e2e/src/app.e2e-spec.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
@ -1,87 +1,35 @@
|
||||
# Getting started with service workers
|
||||
|
||||
|
||||
This document explains how to enable Angular service worker support in your CLI projects. It then uses a simple example to show you a service worker in action, demonstrating loading and basic caching.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
A basic understanding of the following:
|
||||
* [Introduction to Angular service workers](guide/service-worker-intro).
|
||||
* Angular v6, including Angular CLI v6.
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
Beginning in Angular 5.0.0, you can easily enable Angular service worker support in any CLI project. This document explains how to enable Angular service worker support in new and existing projects. It then uses a simple example to show you a service worker in action, demonstrating loading and basic caching.
|
||||
## Adding a service worker to your project
|
||||
|
||||
## Adding a service worker to a new application
|
||||
|
||||
If you're generating a new CLI project, you can use the CLI to set up the Angular service worker as part of creating the project. To do so, add the `--service-worker` flag to the `ng new` command:
|
||||
To set up the Angular service worker in your project, use the CLI command `ng add @angular/pwa`. It takes care of configuring your app to use service workers by adding the `service-worker` package along
|
||||
with setting up the necessary support files.
|
||||
|
||||
```sh
|
||||
ng new my-project --service-worker
|
||||
ng add @angular/pwa --project *project-name*
|
||||
```
|
||||
|
||||
The `--service-worker` flag takes care of configuring your app to
|
||||
use service workers by adding the `service-worker` package along
|
||||
with setting up the necessary files to support service workers.
|
||||
For information on the details, see the following section
|
||||
which covers the process in detail as it shows you how to add a
|
||||
service worker manually to an existing app.
|
||||
The above command completes the following actions:
|
||||
|
||||
1. Adds the `@angular/service-worker` package.
|
||||
2. Enables service worker build support in the CLI.
|
||||
3. Imports and registers the service worker in the app module.
|
||||
4. Creates the service worker configuration file called `ngsw-config.json` which specifies the caching behaviors and other settings.
|
||||
|
||||
|
||||
|
||||
## Adding a service worker to an existing app
|
||||
|
||||
To add a service worker to an existing app:
|
||||
|
||||
1. Add the service worker package.
|
||||
2. Enable service worker build support in the CLI.
|
||||
3. Import and register the service worker.
|
||||
4. Create the service worker configuration file, which specifies the caching behaviors and other settings.
|
||||
5. Build the project.
|
||||
|
||||
### Step 1: Add the service worker package
|
||||
|
||||
Add the package `@angular/service-worker`, using the yarn utility as shown here:
|
||||
|
||||
```sh
|
||||
yarn add @angular/service-worker
|
||||
```
|
||||
|
||||
### Step 2: Enable service worker build support in the CLI
|
||||
|
||||
To enable the Angular service worker, the CLI must generate an Angular service worker manifest at build time. To cause the CLI to generate the manifest for an existing project, set the `serviceWorker` flag to `true` in the project's `.angular-cli.json` file as shown here:
|
||||
|
||||
```sh
|
||||
ng set apps.0.serviceWorker=true
|
||||
```
|
||||
|
||||
### Step 3: Import and register the service worker
|
||||
|
||||
To import and register the Angular service worker:
|
||||
|
||||
At the top of the root module, `src/app/app.module.ts`, import `ServiceWorkerModule` and `environment`.
|
||||
|
||||
<code-example path="service-worker-getting-started/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts" region="sw-import"> </code-example>
|
||||
|
||||
|
||||
Add `ServiceWorkerModule` to the `@NgModule` `imports` array. Use the `register()` helper to take care of registering the service worker, taking care to disable the service worker when not running in production mode.
|
||||
|
||||
<code-example path="service-worker-getting-started/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts" region="sw-module"> </code-example>
|
||||
|
||||
The file `ngsw-worker.js` is the name of the prebuilt service worker script, which the CLI copies into `dist/` to deploy along with your server.
|
||||
|
||||
### Step 4: Create the configuration file, `ngsw-config.json`
|
||||
|
||||
The Angular CLI needs a service worker configuration file, called `ngsw-config.json`. The configuration file controls how the service worker caches files and data
|
||||
resources.
|
||||
|
||||
You can begin with the boilerplate version from the CLI, which configures sensible defaults for most applications.
|
||||
|
||||
Alternately, save the following as `src/ngsw-config.json`:
|
||||
|
||||
<code-example path="service-worker-getting-started/src/ngsw-config.json" linenums="false" title="src/ngsw-config.json"> </code-example>
|
||||
|
||||
### Step 5: Build the project
|
||||
|
||||
Finally, build the project:
|
||||
Now, build the project:
|
||||
|
||||
```sh
|
||||
ng build --prod
|
||||
@ -92,17 +40,18 @@ The CLI project is now set up to use the Angular service worker.
|
||||
|
||||
## Service worker in action: a tour
|
||||
|
||||
This section demonstrates a service worker in action,
|
||||
using an example application.
|
||||
This section demonstrates a service worker in action,
|
||||
using an example application.
|
||||
|
||||
### Serving with `http-server`
|
||||
|
||||
Because `ng serve` does not work with service workers, you must use a separate HTTP server to test your project locally. You can use any HTTP server. The example below uses the [http-server](https://www.npmjs.com/package/http-server) package from npm. To reduce the possibility of conflicts, test on a dedicated port.
|
||||
|
||||
To serve the app, start `http-server` and specify the directory containing your web files and the port:
|
||||
To serve with `http-server`, change to the directory containing your web files and start the web server:
|
||||
|
||||
```sh
|
||||
http-server dist -p 8080
|
||||
cd dist
|
||||
http-server -p 8080
|
||||
```
|
||||
|
||||
### Initial load
|
||||
@ -113,7 +62,7 @@ With the server running, you can point your browser at http://localhost:8080/. Y
|
||||
|
||||
### Simulating a network issue
|
||||
|
||||
To simulate a network issue, disable network interaction for your application. In Chrome:
|
||||
To simulate a network issue, disable network interaction for your application. In Chrome:
|
||||
|
||||
1. Select **Tools** > **Developer Tools** (from the Chrome menu located at the top right corner).
|
||||
2. Go to the **Network tab**.
|
||||
@ -125,9 +74,9 @@ To simulate a network issue, disable network interaction for your application. I
|
||||
|
||||
Now the app has no access to network interaction.
|
||||
|
||||
For applications that do not use the Angular service worker, refreshing now would display Chrome's Internet disconnected page that says "There is no Internet connection".
|
||||
For applications that do not use the Angular service worker, refreshing now would display Chrome's Internet disconnected page that says "There is no Internet connection".
|
||||
|
||||
With the addition of an Angular service worker, the application behavior changes. On a refresh, the page loads normally.
|
||||
With the addition of an Angular service worker, the application behavior changes. On a refresh, the page loads normally.
|
||||
|
||||
If you look at the Network tab, you can verify that the service worker is active.
|
||||
|
||||
@ -149,12 +98,12 @@ Notice that all of the files the browser needs to render this application are ca
|
||||
|
||||
### Making changes to your application
|
||||
|
||||
Now that you've seen how service workers cache your application, the
|
||||
next step is understanding how updates work.
|
||||
Now that you've seen how service workers cache your application, the
|
||||
next step is understanding how updates work.
|
||||
|
||||
1. If you're testing in an incognito window, open a second blank tab. This will keep the incognito and the cache state alive during your test.
|
||||
|
||||
2. Close the application tab, but not the window. This should also close the Developer Tools.
|
||||
2. Close the application tab, but not the window. This should also close the Developer Tools.
|
||||
|
||||
3. Shut down `http-server`.
|
||||
|
||||
@ -168,7 +117,8 @@ next step is understanding how updates work.
|
||||
|
||||
```sh
|
||||
ng build --prod
|
||||
http-server dist -p 8080
|
||||
cd dist
|
||||
http-server -p 8080
|
||||
```
|
||||
|
||||
### Updating your application in the browser
|
||||
|
@ -25,17 +25,12 @@ The Angular service worker's behavior follows that design goal:
|
||||
* Updates happen in the background, relatively quickly after changes are published. The previous version of the application is served until an update is installed and ready.
|
||||
* The service worker conserves bandwidth when possible. Resources are only downloaded if they've changed.
|
||||
|
||||
To support these behaviors, the Angular service worker loads a *manifest* file from the server. The manifest describes the resources to cache and includes hashes of every file's contents. When an update to the application is deployed, the contents of the manifest change, informing the service worker that a new version of the application should be downloaded and cached. This manifest is generated from a user-provided configuration file called `ngsw-config.json`, by using a build tool such as the Angular CLI.
|
||||
To support these behaviors, the Angular service worker loads a *manifest* file from the server. The manifest describes the resources to cache and includes hashes of every file's contents. When an update to the application is deployed, the contents of the manifest change, informing the service worker that a new version of the application should be downloaded and cached. This manifest is generated from a CLI-generated configuration file called `ngsw-config.json`.
|
||||
|
||||
Installing the Angular service worker is as simple as including an `NgModule`. In addition to registering the Angular service worker with the browser, this also makes a few services available for injection which interact with the service worker and can be used to control it. For example, an application can ask to be notified when a new update becomes available, or an application can ask the service worker to check the server for available updates.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
To use Angular service workers, you must have the following Angular and CLI versions:
|
||||
|
||||
* Angular 5.0.0 or later.
|
||||
* Angular CLI 1.6.0 or later.
|
||||
|
||||
Your application must run in a web browser that supports service workers. Currently, the latest versions of Chrome and Firefox are supported. To learn about other browsers that are service worker ready, see the [Can I Use](http://caniuse.com/#feat=serviceworkers) page.
|
||||
|
||||
## Related resources
|
||||
|
@ -1,9 +1,16 @@
|
||||
[
|
||||
{
|
||||
"startDate": "2018-02-14",
|
||||
"endDate": "2018-04-22",
|
||||
"endDate": "2018-04-18",
|
||||
"message": "Join us for ng-conf<br/>Apr 18th-20th, 2018",
|
||||
"imageUrl": "generated/images/marketing/home/ng-conf.png",
|
||||
"linkUrl": "http://ng-conf.org/"
|
||||
},
|
||||
{
|
||||
"startDate": "2018-04-18",
|
||||
"endDate": "2018-04-22",
|
||||
"message": "Watch ng-conf live stream <br/>Apr 18th-20th, 2018",
|
||||
"imageUrl": "generated/images/marketing/home/ng-conf.png",
|
||||
"linkUrl": "https://www.ng-conf.org/livestream/"
|
||||
}
|
||||
]
|
||||
|
@ -5,10 +5,10 @@ At the moment, the `HeroesComponent` displays both the list of heroes and the se
|
||||
Keeping all features in one component as the application grows will not be maintainable.
|
||||
You'll want to split up large components into smaller sub-components, each focused on a specific task or workflow.
|
||||
|
||||
In this page, you'll take the first step in that direction by moving the hero details into a separate, reusable `HeroDetailsComponent`.
|
||||
In this page, you'll take the first step in that direction by moving the hero details into a separate, reusable `HeroDetailComponent`.
|
||||
|
||||
The `HeroesComponent` will only present the list of heroes.
|
||||
The `HeroDetailsComponent` will present details of a selected hero.
|
||||
The `HeroDetailComponent` will present details of a selected hero.
|
||||
|
||||
## Make the `HeroDetailComponent`
|
||||
|
||||
|
@ -348,7 +348,7 @@ Open `MessagesComponent` and import the `MessageService`.
|
||||
|
||||
Modify the constructor with a parameter that declares a **public** `messageService` property.
|
||||
Angular will inject the singleton `MessageService` into that property
|
||||
when it creates the `HeroService`.
|
||||
when it creates the `MessagesComponent`.
|
||||
|
||||
<code-example
|
||||
path="toh-pt4/src/app/messages/messages.component.ts" region="ctor">
|
||||
|
@ -12,7 +12,7 @@
|
||||
"aio-use-npm": "node tools/ng-packages-installer restore .",
|
||||
"aio-check-local": "node tools/ng-packages-installer check .",
|
||||
"ng": "yarn check-env && ng",
|
||||
"start": "yarn check-env && ng serve --aot",
|
||||
"start": "yarn check-env && ng serve",
|
||||
"prebuild": "yarn setup",
|
||||
"build": "yarn ~~build",
|
||||
"prebuild-local": "yarn setup-local",
|
||||
@ -21,7 +21,6 @@
|
||||
"test": "yarn check-env && ng test",
|
||||
"pree2e": "yarn check-env && yarn update-webdriver",
|
||||
"e2e": "ng e2e --no-webdriver-update",
|
||||
"e2e-prod": "yarn e2e --environment=dev --target=production",
|
||||
"presetup": "yarn install --frozen-lockfile && yarn ~~check-env && yarn boilerplate:remove",
|
||||
"setup": "yarn aio-use-npm && yarn example-use-npm",
|
||||
"postsetup": "yarn boilerplate:add && yarn build-ie-polyfills && yarn docs",
|
||||
@ -45,7 +44,7 @@
|
||||
"docs-watch": "node tools/transforms/authors-package/watchr.js",
|
||||
"docs-lint": "eslint --ignore-path=\"tools/transforms/.eslintignore\" tools/transforms",
|
||||
"docs-test": "node tools/transforms/test.js",
|
||||
"deployment-config-test": "jasmine-ts tests/deployment-config/unit/**/*.spec.ts",
|
||||
"redirects-test": "jasmine-ts tests/deployment/unit/**/*.spec.ts",
|
||||
"firebase-utils-test": "jasmine-ts tools/firebase-test-utils/*.spec.ts",
|
||||
"tools-lint": "tslint -c \"tools/tslint.json\" \"tools/firebase-test-utils/**/*.ts\"",
|
||||
"tools-test": "./scripts/deploy-to-firebase.test.sh && yarn docs-test && yarn boilerplate:test && jasmine tools/ng-packages-installer/index.spec.js && yarn firebase-utils-test",
|
||||
@ -58,10 +57,10 @@
|
||||
"generate-zips": "node ./tools/example-zipper/generateZips",
|
||||
"sw-manifest": "ngu-sw-manifest --dist dist --in ngsw-manifest.json --out dist/ngsw-manifest.json",
|
||||
"sw-copy": "cp node_modules/@angular/service-worker/bundles/worker-basic.min.js dist/",
|
||||
"build-ie-polyfills": "node node_modules/webpack/bin/webpack.js -p src/ie-polyfills.js src/generated/ie-polyfills.min.js",
|
||||
"build-ie-polyfills": "yarn webpack-cli src/ie-polyfills.js -o src/generated/ie-polyfills.min.js --mode production",
|
||||
"update-webdriver": "webdriver-manager update --standalone false --gecko false $CHROMEDRIVER_VERSION_ARG",
|
||||
"~~check-env": "node scripts/check-environment",
|
||||
"~~build": "ng build --target=production --environment=stable -sm",
|
||||
"~~build": "ng build --configuration=stable",
|
||||
"post~~build": "yarn sw-manifest && yarn sw-copy"
|
||||
},
|
||||
"engines": {
|
||||
@ -70,34 +69,36 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^6.0.0-rc.1",
|
||||
"@angular/cdk": "^5.0.0-rc.1",
|
||||
"@angular/common": "^6.0.0-rc.1",
|
||||
"@angular/compiler": "^6.0.0-rc.1",
|
||||
"@angular/core": "^6.0.0-rc.1",
|
||||
"@angular/elements": "^6.0.0-rc.1",
|
||||
"@angular/forms": "^6.0.0-rc.1",
|
||||
"@angular/http": "^6.0.0-rc.1",
|
||||
"@angular/material": "^5.0.0-rc.1",
|
||||
"@angular/platform-browser": "^6.0.0-rc.1",
|
||||
"@angular/platform-browser-dynamic": "^6.0.0-rc.1",
|
||||
"@angular/platform-server": "^6.0.0-rc.1",
|
||||
"@angular/router": "^6.0.0-rc.1",
|
||||
"@angular/animations": "6.0.0-rc.5",
|
||||
"@angular/cdk": "6.0.0-rc.11",
|
||||
"@angular/common": "6.0.0-rc.5",
|
||||
"@angular/core": "6.0.0-rc.5",
|
||||
"@angular/elements": "6.0.0-rc.5",
|
||||
"@angular/forms": "6.0.0-rc.5",
|
||||
"@angular/http": "6.0.0-rc.5",
|
||||
"@angular/material": "6.0.0-rc.11",
|
||||
"@angular/platform-browser": "6.0.0-rc.5",
|
||||
"@angular/platform-browser-dynamic": "6.0.0-rc.5",
|
||||
"@angular/platform-server": "6.0.0-rc.5",
|
||||
"@angular/router": "6.0.0-rc.5",
|
||||
"@angular/service-worker": "^1.0.0-beta.16",
|
||||
"@webcomponents/custom-elements": "^1.0.8",
|
||||
"classlist.js": "^1.1.20150312",
|
||||
"core-js": "^2.4.1",
|
||||
"jasmine": "^2.6.0",
|
||||
"ng-pwa-tools": "^0.0.10",
|
||||
"rxjs": "6.0.0-rc.0",
|
||||
"rxjs-compat": "6.0.0-rc.0",
|
||||
"rxjs": "6.0.0-uncanny-rc.7",
|
||||
"rxjs-compat": "6.0.0-uncanny-rc.7",
|
||||
"tslib": "^1.9.0",
|
||||
"web-animations-js": "^2.2.5",
|
||||
"zone.js": "^0.8.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "^1.7.3",
|
||||
"@angular/compiler-cli": "^6.0.0-rc.1",
|
||||
"@angular-devkit/build-angular": "^0.5.6",
|
||||
"@angular/cli": "^6.0.0-rc.4",
|
||||
"@angular/compiler": "6.0.0-rc.5",
|
||||
"@angular/compiler-cli": "6.0.0-rc.5",
|
||||
"@angular/language-service": "6.0.0-rc.5",
|
||||
"@types/jasmine": "^2.5.52",
|
||||
"@types/jasminewd2": "^2.0.3",
|
||||
"@types/node": "~6.0.60",
|
||||
@ -105,7 +106,7 @@
|
||||
"canonical-path": "^0.0.2",
|
||||
"chalk": "^2.1.0",
|
||||
"cjson": "^0.5.0",
|
||||
"codelyzer": "~2.0.0",
|
||||
"codelyzer": "~4.2.1",
|
||||
"concurrently": "^3.4.0",
|
||||
"cross-spawn": "^5.1.0",
|
||||
"css-selector-parser": "^1.3.0",
|
||||
@ -146,16 +147,17 @@
|
||||
"shelljs": "^0.7.7",
|
||||
"tree-kill": "^1.1.0",
|
||||
"ts-node": "^3.3.0",
|
||||
"tslint": "~4.5.0",
|
||||
"tslint": "~5.9.1",
|
||||
"typescript": "~2.7.2",
|
||||
"uglify-js": "^3.0.15",
|
||||
"unist-util-filter": "^0.2.1",
|
||||
"unist-util-source": "^1.0.1",
|
||||
"unist-util-visit": "^1.1.1",
|
||||
"unist-util-visit-parents": "^1.1.1",
|
||||
"vrsource-tslint-rules": "^4.0.1",
|
||||
"vrsource-tslint-rules": "^5.8.2",
|
||||
"watchr": "^3.0.1",
|
||||
"webpack-cli": "^2.0.14",
|
||||
"xregexp": "^4.0.0",
|
||||
"yargs": "^7.0.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,10 @@
|
||||
"aio": {
|
||||
"master": {
|
||||
"uncompressed": {
|
||||
"inline": 1971,
|
||||
"main": 565539,
|
||||
"polyfills": 38514,
|
||||
"prettify": 14886
|
||||
"runtime": 2689,
|
||||
"main": 478529,
|
||||
"polyfills": 38453,
|
||||
"prettify": 14913
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ fi
|
||||
if [[ $TRAVIS_BRANCH == master ]]; then
|
||||
readonly deployEnv=next
|
||||
elif [[ $TRAVIS_BRANCH == $STABLE_BRANCH ]]; then
|
||||
readonly deployEnv=stable
|
||||
readonly deployEnv=stable
|
||||
else
|
||||
# Extract the major versions from the branches, e.g. the 4 from 4.3.x
|
||||
readonly majorVersion=${TRAVIS_BRANCH%%.*}
|
||||
@ -87,7 +87,7 @@ fi
|
||||
cd "`dirname $0`/.."
|
||||
|
||||
# Build the app
|
||||
yarn build --env=$deployEnv
|
||||
yarn build --configuration=$deployEnv
|
||||
|
||||
# Include any mode-specific files
|
||||
cp -rf src/extra-files/$deployEnv/. dist/
|
||||
|
@ -5,12 +5,11 @@ set +x -eu -o pipefail
|
||||
readonly thisDir="$(cd $(dirname ${BASH_SOURCE[0]}); pwd)"
|
||||
readonly aioDir="$(realpath $thisDir/..)"
|
||||
|
||||
readonly appPtorConf="$aioDir/tests/e2e/protractor.conf.js"
|
||||
readonly cfgPtorConf="$aioDir/tests/deployment-config/e2e/protractor.conf.js"
|
||||
readonly protractorConf="$aioDir/tests/deployment/e2e/protractor.conf.js"
|
||||
readonly minPwaScore="95"
|
||||
readonly urls=(
|
||||
"https://angular.io/"
|
||||
"https://next.angular.io"
|
||||
"https://next.angular.io/"
|
||||
)
|
||||
|
||||
cd "$aioDir"
|
||||
@ -24,11 +23,8 @@ set +x -eu -o pipefail
|
||||
for url in "${urls[@]}"; do
|
||||
echo -e "\nChecking '$url'...\n-----"
|
||||
|
||||
# Run e2e tests.
|
||||
yarn protractor "$appPtorConf" --baseUrl "$url"
|
||||
|
||||
# Run deployment config tests.
|
||||
yarn protractor "$cfgPtorConf" --baseUrl "$url"
|
||||
# Run basic e2e and deployment config tests.
|
||||
yarn protractor "$protractorConf" --baseUrl "$url"
|
||||
|
||||
# Run PWA-score tests.
|
||||
yarn test-pwa-score "$url" "$minPwaScore"
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
<mat-sidenav-container class="sidenav-container" [class.starting]="isStarting" [class.has-floating-toc]="hasFloatingToc" role="main">
|
||||
|
||||
<mat-sidenav [ngClass]="{'collapsed': !isSideBySide}" #sidenav class="sidenav" [opened]="isOpened" [mode]="mode" (open)="updateHostClasses()" (close)="updateHostClasses()">
|
||||
<mat-sidenav [ngClass]="{'collapsed': !isSideBySide}" #sidenav class="sidenav" [mode]="mode" [opened]="isOpened" (openedChange)="updateHostClasses()">
|
||||
<aio-nav-menu *ngIf="!isSideBySide" [nodes]="topMenuNarrowNodes" [currentNode]="currentNodes?.TopBarNarrow" [isWide]="false"></aio-nav-menu>
|
||||
<aio-nav-menu [nodes]="sideNavNodes" [currentNode]="currentNodes?.SideNav" [isWide]="isSideBySide"></aio-nav-menu>
|
||||
|
||||
|
@ -6,8 +6,8 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { MatProgressBar, MatSidenav } from '@angular/material';
|
||||
import { By } from '@angular/platform-browser';
|
||||
|
||||
import { Observable, timer } from 'rxjs';
|
||||
import { mapTo } from 'rxjs/operators';
|
||||
import { timer } from 'rxjs';
|
||||
import { first, mapTo } from 'rxjs/operators';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppModule } from './app.module';
|
||||
@ -64,13 +64,13 @@ describe('AppComponent', () => {
|
||||
const de = fixture.debugElement;
|
||||
const docViewerDe = de.query(By.css('aio-doc-viewer'));
|
||||
|
||||
documentService = de.injector.get(DocumentService) as DocumentService;
|
||||
documentService = de.injector.get<DocumentService>(DocumentService);
|
||||
docViewer = docViewerDe.nativeElement;
|
||||
docViewerComponent = docViewerDe.componentInstance;
|
||||
hamburger = de.query(By.css('.hamburger')).nativeElement;
|
||||
locationService = de.injector.get(LocationService) as any;
|
||||
locationService = de.injector.get<any>(LocationService);
|
||||
sidenav = de.query(By.directive(MatSidenav)).componentInstance;
|
||||
tocService = de.injector.get(TocService);
|
||||
tocService = de.injector.get<TocService>(TocService);
|
||||
|
||||
return waitForDoc && awaitDocRendered();
|
||||
};
|
||||
@ -463,7 +463,7 @@ describe('AppComponent', () => {
|
||||
let scrollToTopSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(() => {
|
||||
scrollService = fixture.debugElement.injector.get(ScrollService);
|
||||
scrollService = fixture.debugElement.injector.get<ScrollService>(ScrollService);
|
||||
scrollSpy = spyOn(scrollService, 'scroll');
|
||||
scrollToTopSpy = spyOn(scrollService, 'scrollToTop');
|
||||
});
|
||||
@ -1114,20 +1114,23 @@ describe('AppComponent', () => {
|
||||
checkHostClass('sidenav', 'open');
|
||||
|
||||
sidenav.close();
|
||||
await waitForEmit(sidenav.onClose);
|
||||
await waitForSidenavOpenedChange();
|
||||
fixture.detectChanges();
|
||||
checkHostClass('sidenav', 'closed');
|
||||
|
||||
sidenav.open();
|
||||
await waitForEmit(sidenav.onOpen);
|
||||
await waitForSidenavOpenedChange();
|
||||
fixture.detectChanges();
|
||||
checkHostClass('sidenav', 'open');
|
||||
|
||||
function waitForEmit(emitter: Observable<void>): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
emitter.subscribe(resolve);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
async function waitForSidenavOpenedChange() {
|
||||
const promise = new Promise(resolve => sidenav.openedChange.pipe(first()).subscribe(resolve));
|
||||
|
||||
await Promise.resolve(); // Wait for `MatSidenav.openedChange.emit()` to be called.
|
||||
jasmine.clock().tick(0); // Notify `MatSidenav.openedChange` observers.
|
||||
// (It is an async `EventEmitter`, thus uses `setTimeout()`.)
|
||||
|
||||
await promise;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -97,11 +97,11 @@ describe('ApiListComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('initial critera from location', () => {
|
||||
describe('initial criteria from location', () => {
|
||||
let locationService: TestLocationService;
|
||||
|
||||
beforeEach(() => {
|
||||
locationService = <any> fixture.componentRef.injector.get(LocationService);
|
||||
locationService = fixture.componentRef.injector.get<any>(LocationService);
|
||||
});
|
||||
|
||||
function expectOneItem(name: string, section: string, type: string, stability: string) {
|
||||
@ -110,7 +110,7 @@ describe('ApiListComponent', () => {
|
||||
component.filteredSections.subscribe(filtered => {
|
||||
expect(filtered.length).toBe(1, 'sections');
|
||||
expect(filtered[0].name).toBe(section, 'section name');
|
||||
const items = filtered[0].items.filter(item => item.show);
|
||||
const items = filtered[0].items.filter(i => i.show);
|
||||
expect(items.length).toBe(1, 'items');
|
||||
|
||||
const item = items[0];
|
||||
@ -168,7 +168,7 @@ describe('ApiListComponent', () => {
|
||||
let locationService: TestLocationService;
|
||||
|
||||
beforeEach(() => {
|
||||
locationService = <any> fixture.componentRef.injector.get(LocationService);
|
||||
locationService = fixture.componentRef.injector.get<any>(LocationService);
|
||||
});
|
||||
|
||||
it('should have query', () => {
|
||||
|
@ -16,9 +16,9 @@ import { ApiSection, ApiService } from './api.service';
|
||||
import { Option } from 'app/shared/select/select.component';
|
||||
|
||||
class SearchCriteria {
|
||||
query? = '';
|
||||
status? = 'all';
|
||||
type? = 'all';
|
||||
query ? = '';
|
||||
status ? = 'all';
|
||||
type ? = 'all';
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
@ -21,7 +21,7 @@ describe('ApiService', () => {
|
||||
]
|
||||
});
|
||||
|
||||
service = injector.get(ApiService);
|
||||
service = injector.get<ApiService>(ApiService);
|
||||
httpMock = injector.get(HttpTestingController);
|
||||
});
|
||||
|
||||
|
@ -15,18 +15,18 @@ import { CodeComponent } from './code.component';
|
||||
*/
|
||||
@Component({
|
||||
selector: 'code-example',
|
||||
template: `
|
||||
template: `
|
||||
<!-- Content projection is used to get the content HTML provided to this component -->
|
||||
<div #content style="display: none"><ng-content></ng-content></div>
|
||||
|
||||
|
||||
<header *ngIf="title">{{title}}</header>
|
||||
|
||||
<aio-code [ngClass]="classes"
|
||||
[language]="language"
|
||||
[linenums]="linenums"
|
||||
[path]="path"
|
||||
[region]="region"
|
||||
[hideCopy]="hidecopy"
|
||||
<aio-code [ngClass]="classes"
|
||||
[language]="language"
|
||||
[linenums]="linenums"
|
||||
[path]="path"
|
||||
[region]="region"
|
||||
[hideCopy]="hidecopy"
|
||||
[title]="title">
|
||||
</aio-code>
|
||||
`,
|
||||
|
@ -87,7 +87,7 @@ describe('CodeTabsComponent', () => {
|
||||
region="region-B"
|
||||
title="title-B">
|
||||
Code example 2
|
||||
</code-pane>
|
||||
</code-pane>
|
||||
</code-tabs>
|
||||
`
|
||||
})
|
||||
|
@ -24,7 +24,7 @@ export interface TabInfo {
|
||||
template: `
|
||||
<!-- Use content projection so that the provided HTML's code-panes can be split into tabs -->
|
||||
<div #content style="display: none"><ng-content></ng-content></div>
|
||||
|
||||
|
||||
<mat-tab-group class="code-tab-group" disableRipple>
|
||||
<mat-tab style="overflow-y: hidden;" *ngFor="let tab of tabs">
|
||||
<ng-template mat-tab-label>
|
||||
@ -37,7 +37,7 @@ export interface TabInfo {
|
||||
[region]="tab.region"
|
||||
[title]="tab.title">
|
||||
</aio-code>
|
||||
</mat-tab>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
`,
|
||||
})
|
||||
|
@ -19,7 +19,7 @@ describe('ContributorService', () => {
|
||||
]
|
||||
});
|
||||
|
||||
contribService = injector.get(ContributorService);
|
||||
contribService = injector.get<ContributorService>(ContributorService);
|
||||
httpMock = injector.get(HttpTestingController);
|
||||
});
|
||||
|
||||
|
@ -11,5 +11,5 @@ export class Contributor {
|
||||
website?: string;
|
||||
twitter?: string;
|
||||
bio?: string;
|
||||
isFlipped? = false;
|
||||
isFlipped ? = false;
|
||||
}
|
||||
|
@ -366,13 +366,18 @@ describe('TocComponent', () => {
|
||||
let parentScrollTop: number;
|
||||
|
||||
beforeEach(() => {
|
||||
const hostElem = fixture.nativeElement;
|
||||
const firstItem = page.listItems[0].nativeElement;
|
||||
const offsetParent = firstItem.offsetParent;
|
||||
|
||||
offsetParent.style.maxHeight = `${offsetParent.clientHeight - firstItem.clientHeight}px`;
|
||||
Object.defineProperty(offsetParent, 'scrollTop', {
|
||||
Object.assign(hostElem.style, {
|
||||
display: 'block',
|
||||
maxHeight: `${hostElem.clientHeight - firstItem.clientHeight}px`,
|
||||
overflow: 'auto',
|
||||
position: 'relative',
|
||||
});
|
||||
Object.defineProperty(hostElem, 'scrollTop', {
|
||||
get: () => parentScrollTop,
|
||||
set: v => parentScrollTop = v
|
||||
set: v => parentScrollTop = v,
|
||||
});
|
||||
|
||||
parentScrollTop = 0;
|
||||
@ -461,7 +466,7 @@ class TestTocService {
|
||||
activeItemIndex = new BehaviorSubject<number | null>(null);
|
||||
setActiveIndex(index: number|null) {
|
||||
this.activeItemIndex.next(index);
|
||||
if (asap.scheduled) {
|
||||
if (asap.scheduled !== undefined) {
|
||||
asap.flush();
|
||||
}
|
||||
}
|
||||
|
@ -90,5 +90,5 @@ export class TocComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
function count<T>(array: T[], fn: (item: T) => boolean) {
|
||||
return array.reduce((count, item) => fn(item) ? count + 1 : count, 0);
|
||||
return array.reduce((result, item) => fn(item) ? result + 1 : result, 0);
|
||||
}
|
||||
|
@ -5,12 +5,13 @@ describe('CustomIconRegistry', () => {
|
||||
it('should get the SVG element for a preloaded icon from the cache', () => {
|
||||
const mockHttp: any = {};
|
||||
const mockSanitizer: any = {};
|
||||
const mockDocument: any = {};
|
||||
const svgSrc = '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" ' +
|
||||
'viewBox="0 0 24 24"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"/></svg>';
|
||||
const svgIcons: SvgIconInfo[] = [
|
||||
{ name: 'test_icon', svgSource: svgSrc }
|
||||
];
|
||||
const registry = new CustomIconRegistry(mockHttp, mockSanitizer, svgIcons);
|
||||
const registry = new CustomIconRegistry(mockHttp, mockSanitizer, mockDocument, svgIcons);
|
||||
let svgElement: SVGElement|undefined;
|
||||
registry.getNamedSvgIcon('test_icon').subscribe(el => svgElement = el);
|
||||
expect(svgElement).toEqual(createSvg(svgSrc));
|
||||
@ -19,6 +20,7 @@ describe('CustomIconRegistry', () => {
|
||||
it('should call through to the MdIconRegistry if the icon name is not in the preloaded cache', () => {
|
||||
const mockHttp: any = {};
|
||||
const mockSanitizer: any = {};
|
||||
const mockDocument: any = {};
|
||||
const svgSrc = '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" ' +
|
||||
'viewBox="0 0 24 24"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"/></svg>';
|
||||
const svgIcons: SvgIconInfo[] = [
|
||||
@ -26,7 +28,7 @@ describe('CustomIconRegistry', () => {
|
||||
];
|
||||
spyOn(MatIconRegistry.prototype, 'getNamedSvgIcon');
|
||||
|
||||
const registry = new CustomIconRegistry(mockHttp, mockSanitizer, svgIcons);
|
||||
const registry = new CustomIconRegistry(mockHttp, mockSanitizer, mockDocument, svgIcons);
|
||||
|
||||
registry.getNamedSvgIcon('other_icon');
|
||||
expect(MatIconRegistry.prototype.getNamedSvgIcon).toHaveBeenCalledWith('other_icon', undefined);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { InjectionToken, Inject, Injectable } from '@angular/core';
|
||||
import { InjectionToken, Inject, Injectable, Optional } from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { of } from 'rxjs';
|
||||
import { MatIconRegistry } from '@angular/material/icon';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
@ -35,8 +36,9 @@ interface SvgIconMap {
|
||||
export class CustomIconRegistry extends MatIconRegistry {
|
||||
private preloadedSvgElements: SvgIconMap = {};
|
||||
|
||||
constructor(http: HttpClient, sanitizer: DomSanitizer, @Inject(SVG_ICONS) svgIcons: SvgIconInfo[]) {
|
||||
super(http, sanitizer);
|
||||
constructor(http: HttpClient, sanitizer: DomSanitizer, @Optional() @Inject(DOCUMENT) document,
|
||||
@Inject(SVG_ICONS) svgIcons: SvgIconInfo[]) {
|
||||
super(http, sanitizer, document);
|
||||
this.loadSvgElements(svgIcons);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/platform-browser';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { fromEvent, Observable, ReplaySubject, Subject } from 'rxjs';
|
||||
import { auditTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { ReflectiveInjector } from '@angular/core';
|
||||
import { DOCUMENT, DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
import { ScrollItem, ScrollSpyInfo, ScrollSpyService } from 'app/shared/scroll-spy.service';
|
||||
@ -33,8 +34,8 @@ describe('TocService', () => {
|
||||
|
||||
describe('tocList', () => {
|
||||
it('should emit the latest value to new subscribers', () => {
|
||||
const expectedValue1 = tocItem('Heading A');
|
||||
const expectedValue2 = tocItem('Heading B');
|
||||
const expectedValue1 = createTocItem('Heading A');
|
||||
const expectedValue2 = createTocItem('Heading B');
|
||||
let value1: TocItem[]|undefined;
|
||||
let value2: TocItem[]|undefined;
|
||||
|
||||
@ -48,8 +49,8 @@ describe('TocService', () => {
|
||||
});
|
||||
|
||||
it('should emit the same values to all subscribers', () => {
|
||||
const expectedValue1 = tocItem('Heading A');
|
||||
const expectedValue2 = tocItem('Heading B');
|
||||
const expectedValue1 = createTocItem('Heading A');
|
||||
const expectedValue2 = createTocItem('Heading B');
|
||||
const emittedValues: TocItem[][] = [];
|
||||
|
||||
tocService.tocList.subscribe(v => emittedValues.push(v));
|
||||
@ -149,8 +150,8 @@ describe('TocService', () => {
|
||||
describe('should clear tocList', () => {
|
||||
beforeEach(() => {
|
||||
// Start w/ dummy data from previous usage
|
||||
const expectedValue1 = tocItem('Heading A');
|
||||
const expectedValue2 = tocItem('Heading B');
|
||||
const expectedValue1 = createTocItem('Heading A');
|
||||
const expectedValue2 = createTocItem('Heading B');
|
||||
tocService.tocList.next([expectedValue1, expectedValue2]);
|
||||
expect(lastTocList).not.toEqual([]);
|
||||
});
|
||||
@ -369,7 +370,7 @@ class MockScrollSpyService {
|
||||
}
|
||||
}
|
||||
|
||||
function tocItem(title: string, level = 'h2', href = '', content = title) {
|
||||
function createTocItem(title: string, level = 'h2', href = '', content = title) {
|
||||
return { title, href, level, content };
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { DOCUMENT, DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import { ScrollSpyInfo, ScrollSpyService } from 'app/shared/scroll-spy.service';
|
||||
|
||||
|
@ -4,12 +4,10 @@
|
||||
// The list of which env maps to which file can be found in `angular-cli.json`.
|
||||
|
||||
|
||||
// Reflect.metadata polyfill is only needed in the JIT/dev mode.
|
||||
//
|
||||
// In order to load these polyfills early enough (before app code), polyfill.ts imports this file to
|
||||
// to change the order in the final bundle.
|
||||
import 'core-js/es6/reflect';
|
||||
import 'core-js/es7/reflect';
|
||||
// Reflect.metadata polyfill is only needed in the JIT, which use use only for tests
|
||||
// to make the unit tests work we load these polyfills in tests.ts instead
|
||||
// import 'core-js/es6/reflect';
|
||||
// import 'core-js/es7/reflect';
|
||||
|
||||
|
||||
export const environment = {
|
||||
|
@ -1,22 +1,23 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/0.13/config/configuration-file.html
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular/cli'],
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
dir: require('path').join(__dirname, 'coverage'),
|
||||
reports: ['html', 'lcovonly'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
|
@ -27,9 +27,6 @@
|
||||
* and executed before the rest of the application files are executed.
|
||||
*/
|
||||
|
||||
/** HACK: force import of environment.ts/environment.prod.ts to load env specific polyfills */
|
||||
import './environments/environment';
|
||||
|
||||
/** ALL Firefox browsers require the following to support `@angular/animation`. **/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
|
@ -3,25 +3,22 @@
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
|
||||
declare const __karma__: any;
|
||||
declare const require: any;
|
||||
|
||||
// Prevent Karma from running prematurely.
|
||||
__karma__.loaded = function () {};
|
||||
// Reflect.metadata polyfill is only needed in the JIT mode which we use only for unit tests
|
||||
import 'core-js/es6/reflect';
|
||||
import 'core-js/es7/reflect';
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
// Finally, start Karma to run the tests.
|
||||
__karma__.start();
|
||||
|
@ -3,19 +3,18 @@
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"baseUrl": "",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts"
|
||||
"test.ts",
|
||||
"polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"testing/**/*.ts",
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
}
|
17
aio/src/tslint.json
Normal file
17
aio/src/tslint.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"aio",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"aio",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
import { browser } from 'protractor';
|
||||
|
||||
describe(browser.baseUrl, () => {
|
||||
const sitemapUrls = browser.params.sitemapUrls;
|
||||
const legacyUrls = browser.params.legacyUrls;
|
||||
const goTo = async url => {
|
||||
// Go to the specified URL and then unregister the ServiceWorker
|
||||
// to ensure subsequent requests are passed through to the server.
|
||||
await browser.get(url);
|
||||
await browser.executeAsyncScript(cb => navigator.serviceWorker
|
||||
.getRegistrations()
|
||||
.then(regs => Promise.all(regs.map(reg => reg.unregister())))
|
||||
.then(cb));
|
||||
};
|
||||
|
||||
beforeAll(async done => {
|
||||
// Make an initial request to unregister the ServiceWorker.
|
||||
await goTo(browser.baseUrl);
|
||||
done();
|
||||
});
|
||||
|
||||
beforeEach(() => browser.waitForAngularEnabled(false));
|
||||
afterEach(() => browser.waitForAngularEnabled(true));
|
||||
|
||||
describe('(with sitemap URLs)', () => {
|
||||
sitemapUrls.forEach((url, i) => {
|
||||
it(`should not redirect '${url}' (${i + 1}/${sitemapUrls.length})`, async () => {
|
||||
await goTo(url);
|
||||
|
||||
const expectedUrl = browser.baseUrl + url;
|
||||
const actualUrl = (await browser.getCurrentUrl()).replace(/\?.*$/, '');
|
||||
|
||||
expect(actualUrl).toBe(expectedUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('(with legacy URLs)', () => {
|
||||
legacyUrls.forEach(([fromUrl, toUrl], i) => {
|
||||
it(`should redirect '${fromUrl}' to '${toUrl}' (${i + 1}/${legacyUrls.length})`, async () => {
|
||||
await goTo(fromUrl);
|
||||
|
||||
const expectedUrl = (/^http/.test(toUrl) ? '' : browser.baseUrl.replace(/\/$/, '')) + toUrl;
|
||||
const actualUrl = (await browser.getCurrentUrl()).replace(/\?.*$/, '');
|
||||
|
||||
expect(actualUrl).toBe(expectedUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
37
aio/tests/deployment/e2e/redirection.e2e-spec.ts
Normal file
37
aio/tests/deployment/e2e/redirection.e2e-spec.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { browser } from 'protractor';
|
||||
import { SitePage } from './site.po';
|
||||
|
||||
describe(browser.baseUrl, () => {
|
||||
const page = new SitePage();
|
||||
|
||||
beforeAll(done => page.init().then(done));
|
||||
|
||||
beforeEach(() => browser.waitForAngularEnabled(false));
|
||||
afterEach(() => browser.waitForAngularEnabled(true));
|
||||
|
||||
describe('(with sitemap URLs)', () => {
|
||||
page.sitemapUrls.forEach((url, i) => {
|
||||
it(`should not redirect '${url}' (${i + 1}/${page.sitemapUrls.length})`, async () => {
|
||||
await page.goTo(url);
|
||||
|
||||
const expectedUrl = browser.baseUrl + url;
|
||||
const actualUrl = (await browser.getCurrentUrl()).replace(/\?.*$/, '');
|
||||
|
||||
expect(actualUrl).toBe(expectedUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('(with legacy URLs)', () => {
|
||||
page.legacyUrls.forEach(([fromUrl, toUrl], i) => {
|
||||
it(`should redirect '${fromUrl}' to '${toUrl}' (${i + 1}/${page.legacyUrls.length})`, async () => {
|
||||
await page.goTo(fromUrl);
|
||||
|
||||
const expectedUrl = (/^http/.test(toUrl) ? '' : browser.baseUrl.replace(/\/$/, '')) + toUrl;
|
||||
const actualUrl = (await browser.getCurrentUrl()).replace(/\?.*$/, '');
|
||||
|
||||
expect(actualUrl).toBe(expectedUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
60
aio/tests/deployment/e2e/site.po.ts
Normal file
60
aio/tests/deployment/e2e/site.po.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { browser, by, element, ExpectedConditions } from 'protractor';
|
||||
|
||||
export class SitePage {
|
||||
/** All URLs found in the app's `sitemap.xml` (i.e. valid URLs tha should not be redirected). */
|
||||
sitemapUrls: string[] = browser.params.sitemapUrls;
|
||||
|
||||
/** A list of legacy URLs that should be redirected to new URLs (in the form `[fromUrl, toUrl]`). */
|
||||
legacyUrls: string[][] = browser.params.legacyUrls;
|
||||
|
||||
/**
|
||||
* Enter a query into the search field.
|
||||
*/
|
||||
async enterSearch(query: string) {
|
||||
const searchInput = element(by.css('input[type=search]'));
|
||||
await searchInput.clear();
|
||||
await searchInput.sendKeys(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text content of the `aio-doc-viewer` element (in lowercase).
|
||||
*/
|
||||
async getDocViewerText() {
|
||||
const docViewer = element(by.css('aio-doc-viewer'));
|
||||
const text = await docViewer.getText();
|
||||
return text.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of text contents for all search result items found on the page.
|
||||
*/
|
||||
async getSearchResults() {
|
||||
const results = element.all(by.css('.search-results li'));
|
||||
await browser.wait(ExpectedConditions.presenceOf(results.first()), 8000);
|
||||
return await results.map<string>(link => link!.getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a URL, disable animations, unregister the ServiceWorker, and wait for Angular.
|
||||
* (The SW is unregistered to ensure that subsequent requests are passed through to the server.)
|
||||
*/
|
||||
async goTo(url: string) {
|
||||
const unregisterServiceWorker = (cb: () => void) => navigator.serviceWorker
|
||||
.getRegistrations()
|
||||
.then(regs => Promise.all(regs.map(reg => reg.unregister())))
|
||||
.then(cb);
|
||||
|
||||
await browser.get(url || browser.baseUrl);
|
||||
await browser.executeScript('document.body.classList.add(\'no-animations\')');
|
||||
await browser.executeAsyncScript(unregisterServiceWorker);
|
||||
await browser.waitForAngular();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the page object and get it ready for further requests.
|
||||
*/
|
||||
async init() {
|
||||
// Make an initial request to unregister the ServiceWorker.
|
||||
await this.goTo('');
|
||||
}
|
||||
}
|
103
aio/tests/deployment/e2e/smoke-tests.e2e-spec.ts
Normal file
103
aio/tests/deployment/e2e/smoke-tests.e2e-spec.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import { browser } from 'protractor';
|
||||
import { SitePage } from './site.po';
|
||||
|
||||
describe(browser.baseUrl, () => {
|
||||
const page = new SitePage();
|
||||
|
||||
beforeAll(done => page.init().then(done));
|
||||
|
||||
beforeEach(() => browser.waitForAngularEnabled(false));
|
||||
afterEach(() => browser.waitForAngularEnabled(true));
|
||||
|
||||
describe('(smoke tests)', () => {
|
||||
it('should show the home page', () => {
|
||||
page.goTo('');
|
||||
const text = page.getDocViewerText();
|
||||
|
||||
expect(text).toContain('one framework');
|
||||
expect(text).toContain('mobile & desktop');
|
||||
});
|
||||
|
||||
describe('(marketing pages)', () => {
|
||||
const textPerUrl = {
|
||||
features: 'features & benefits',
|
||||
docs: 'what is angular?',
|
||||
events: 'events',
|
||||
resources: 'explore angular resources',
|
||||
};
|
||||
|
||||
Object.keys(textPerUrl).forEach(url => {
|
||||
it(`should show the page at '${url}'`, () => {
|
||||
page.goTo(url);
|
||||
expect(page.getDocViewerText()).toContain(textPerUrl[url]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('(docs pages)', () => {
|
||||
const textPerUrl = {
|
||||
api: 'api list',
|
||||
'guide/architecture': 'architecture',
|
||||
'guide/http': 'httpclient',
|
||||
'guide/quickstart': 'quickstart',
|
||||
'guide/security': 'security',
|
||||
tutorial: 'tutorial',
|
||||
};
|
||||
|
||||
Object.keys(textPerUrl).forEach(url => {
|
||||
it(`should show the page at '${url}'`, () => {
|
||||
page.goTo(url);
|
||||
expect(page.getDocViewerText()).toContain(textPerUrl[url]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('(api docs pages)', () => {
|
||||
const textPerUrl = {
|
||||
/* Class */ 'api/core/Injector': 'class injector',
|
||||
/* Const */ 'api/forms/NG_VALIDATORS': 'const ng_validators',
|
||||
/* Decorator */ 'api/core/Component': '@component',
|
||||
/* Directive */ 'api/common/NgIf': 'class ngif',
|
||||
/* Enum */ 'api/core/ChangeDetectionStrategy': 'enum changedetectionstrategy',
|
||||
/* Function */ 'api/animations/animate': 'animate(',
|
||||
/* Interface */ 'api/core/OnDestroy': 'interface ondestroy',
|
||||
/* Pipe */ 'api/common/JsonPipe': '| json',
|
||||
/* Type-Alias */ 'api/common/http/HttpEvent': 'type httpevent',
|
||||
};
|
||||
|
||||
Object.keys(textPerUrl).forEach(url => {
|
||||
it(`should show the page at '${url}'`, () => {
|
||||
page.goTo(url);
|
||||
expect(page.getDocViewerText()).toContain(textPerUrl[url]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('(search results)', () => {
|
||||
beforeEach(() => page.goTo(''));
|
||||
|
||||
it('should find pages when searching by a partial word in the title', () => {
|
||||
page.enterSearch('ngCont');
|
||||
expect(page.getSearchResults()).toContain('NgControl');
|
||||
});
|
||||
|
||||
it('should find API docs when searching for an instance member name', () => {
|
||||
page.enterSearch('writeValue');
|
||||
expect(page.getSearchResults()).toContain('ControlValueAccessor');
|
||||
});
|
||||
|
||||
it('should find API docs when searching for a static member name', () => {
|
||||
page.enterSearch('compose');
|
||||
expect(page.getSearchResults()).toContain('Validators');
|
||||
});
|
||||
});
|
||||
|
||||
it('should show relevant results on 404', () => {
|
||||
page.goTo('http/router');
|
||||
const results = page.getSearchResults();
|
||||
|
||||
expect(results).toContain('HttpClient');
|
||||
expect(results).toContain('Router');
|
||||
});
|
||||
});
|
||||
});
|
@ -39,14 +39,14 @@ describe('site App', function() {
|
||||
navItemHeadings.each(heading => testNavItemHeading(heading!, 1));
|
||||
|
||||
// Helpers
|
||||
function expectToBeCollapsed(element: ElementFinder) {
|
||||
expect(element.getAttribute('class')).toMatch(/\bcollapsed\b/);
|
||||
expect(element.getAttribute('class')).not.toMatch(/\bexpanded\b/);
|
||||
function expectToBeCollapsed(elementFinder: ElementFinder) {
|
||||
expect(elementFinder.getAttribute('class')).toMatch(/\bcollapsed\b/);
|
||||
expect(elementFinder.getAttribute('class')).not.toMatch(/\bexpanded\b/);
|
||||
}
|
||||
|
||||
function expectToBeExpanded(element: ElementFinder) {
|
||||
expect(element.getAttribute('class')).not.toMatch(/\bcollapsed\b/);
|
||||
expect(element.getAttribute('class')).toMatch(/\bexpanded\b/);
|
||||
function expectToBeExpanded(elementFinder: ElementFinder) {
|
||||
expect(elementFinder.getAttribute('class')).not.toMatch(/\bcollapsed\b/);
|
||||
expect(elementFinder.getAttribute('class')).toMatch(/\bexpanded\b/);
|
||||
}
|
||||
|
||||
function testNavItemHeading(heading: ElementFinder, level: number) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user