build(aio): switch from `@angular/http` to `@angular/common/http`
``` $ ls -l dist/*.js 14942 dist/0.b19e913fbdd6507d346b.chunk.js 1535 dist/inline.a1b446562b36eebb766d.bundle.js 524385 (+ 682) dist/main.19fec4390ff7837ee6ef.bundle.js 37402 dist/polyfills.9f7e0e53bce2a6c8326e.bundle.js 54001 dist/worker-basic.min.js 632265 (+ 682) total ```
This commit is contained in:
parent
3efd4a15d6
commit
38addacda0
|
@ -2,7 +2,7 @@ import { NO_ERRORS_SCHEMA, DebugElement } from '@angular/core';
|
||||||
import { async, inject, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
import { async, inject, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { APP_BASE_HREF } from '@angular/common';
|
import { APP_BASE_HREF } from '@angular/common';
|
||||||
import { Http } from '@angular/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { MdProgressBar, MdSidenav } from '@angular/material';
|
import { MdProgressBar, MdSidenav } from '@angular/material';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
@ -650,7 +650,7 @@ describe('AppComponent', () => {
|
||||||
describe('footer', () => {
|
describe('footer', () => {
|
||||||
it('should have version number', () => {
|
it('should have version number', () => {
|
||||||
const versionEl: HTMLElement = fixture.debugElement.query(By.css('aio-footer')).nativeElement;
|
const versionEl: HTMLElement = fixture.debugElement.query(By.css('aio-footer')).nativeElement;
|
||||||
expect(versionEl.textContent).toContain(TestHttp.versionInfo.full);
|
expect(versionEl.textContent).toContain(TestHttpClient.versionInfo.full);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1027,7 +1027,7 @@ function createTestingModule(initialUrl: string, mode: string = 'stable') {
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: APP_BASE_HREF, useValue: '/' },
|
{ provide: APP_BASE_HREF, useValue: '/' },
|
||||||
{ provide: GaService, useClass: TestGaService },
|
{ provide: GaService, useClass: TestGaService },
|
||||||
{ provide: Http, useClass: TestHttp },
|
{ provide: HttpClient, useClass: TestHttpClient },
|
||||||
{ provide: LocationService, useFactory: () => mockLocationService },
|
{ provide: LocationService, useFactory: () => mockLocationService },
|
||||||
{ provide: Logger, useClass: MockLogger },
|
{ provide: Logger, useClass: MockLogger },
|
||||||
{ provide: SearchService, useClass: MockSearchService },
|
{ provide: SearchService, useClass: MockSearchService },
|
||||||
|
@ -1049,7 +1049,7 @@ class TestSearchService {
|
||||||
loadIndex = jasmine.createSpy('loadIndex');
|
loadIndex = jasmine.createSpy('loadIndex');
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestHttp {
|
class TestHttpClient {
|
||||||
|
|
||||||
static versionInfo = {
|
static versionInfo = {
|
||||||
raw: '4.0.0-rc.6',
|
raw: '4.0.0-rc.6',
|
||||||
|
@ -1105,9 +1105,9 @@ class TestHttp {
|
||||||
"tooltip": "Details of the Angular classes and values."
|
"tooltip": "Details of the Angular classes and values."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"docVersions": TestHttp.docVersions,
|
"docVersions": TestHttpClient.docVersions,
|
||||||
|
|
||||||
"__versionInfo": TestHttp.versionInfo,
|
"__versionInfo": TestHttpClient.versionInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
get(url: string) {
|
get(url: string) {
|
||||||
|
@ -1123,6 +1123,6 @@ class TestHttp {
|
||||||
const contents = `${h1}<h2 id="#somewhere">Some heading</h2>`;
|
const contents = `${h1}<h2 id="#somewhere">Some heading</h2>`;
|
||||||
data = { id, contents };
|
data = { id, contents };
|
||||||
}
|
}
|
||||||
return of({ json: () => data });
|
return of(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { HttpModule } from '@angular/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
import { Location, LocationStrategy, PathLocationStrategy } from '@angular/common';
|
import { Location, LocationStrategy, PathLocationStrategy } from '@angular/common';
|
||||||
|
@ -75,7 +75,7 @@ export const svgIconProviders = [
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
EmbeddedModule,
|
EmbeddedModule,
|
||||||
HttpModule,
|
HttpClientModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
MdButtonModule,
|
MdButtonModule,
|
||||||
MdIconModule,
|
MdIconModule,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { ReflectiveInjector } from '@angular/core';
|
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||||
import { Http, ConnectionBackend, RequestOptions, BaseRequestOptions, Response, ResponseOptions } from '@angular/http';
|
import { Injector } from '@angular/core';
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||||
|
|
||||||
import { MockBackend } from '@angular/http/testing';
|
|
||||||
import { LocationService } from 'app/shared/location.service';
|
import { LocationService } from 'app/shared/location.service';
|
||||||
import { MockLocationService } from 'testing/location.service';
|
import { MockLocationService } from 'testing/location.service';
|
||||||
import { Logger } from 'app/shared/logger.service';
|
import { Logger } from 'app/shared/logger.service';
|
||||||
|
@ -16,113 +16,123 @@ import { DocumentService, DocumentContents,
|
||||||
|
|
||||||
const CONTENT_URL_PREFIX = 'generated/docs/';
|
const CONTENT_URL_PREFIX = 'generated/docs/';
|
||||||
|
|
||||||
function createResponse(body: any) {
|
|
||||||
return new Response(new ResponseOptions({ body: JSON.stringify(body) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
function createInjector(initialUrl: string) {
|
|
||||||
return ReflectiveInjector.resolveAndCreate([
|
|
||||||
DocumentService,
|
|
||||||
{ provide: LocationService, useFactory: () => new MockLocationService(initialUrl) },
|
|
||||||
{ provide: ConnectionBackend, useClass: MockBackend },
|
|
||||||
{ provide: RequestOptions, useClass: BaseRequestOptions },
|
|
||||||
{ provide: Logger, useClass: MockLogger },
|
|
||||||
Http,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getServices(initialUrl: string = '') {
|
|
||||||
const injector = createInjector(initialUrl);
|
|
||||||
return {
|
|
||||||
backend: injector.get(ConnectionBackend) as MockBackend,
|
|
||||||
locationService: injector.get(LocationService) as MockLocationService,
|
|
||||||
docService: injector.get(DocumentService) as DocumentService,
|
|
||||||
logger: injector.get(Logger) as MockLogger
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('DocumentService', () => {
|
describe('DocumentService', () => {
|
||||||
|
|
||||||
it('should be creatable', () => {
|
let httpMock: HttpTestingController;
|
||||||
const { docService } = getServices();
|
|
||||||
expect(docService).toBeTruthy();
|
function createInjector(initialUrl: string) {
|
||||||
});
|
return TestBed.configureTestingModule({
|
||||||
|
imports: [HttpClientTestingModule],
|
||||||
|
providers: [
|
||||||
|
DocumentService,
|
||||||
|
{ provide: LocationService, useFactory: () => new MockLocationService(initialUrl) },
|
||||||
|
{ provide: Logger, useClass: MockLogger },
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getServices(initialUrl: string = '') {
|
||||||
|
const injector = createInjector(initialUrl);
|
||||||
|
httpMock = injector.get(HttpTestingController) as HttpTestingController;
|
||||||
|
return {
|
||||||
|
locationService: injector.get(LocationService) as MockLocationService,
|
||||||
|
docService: injector.get(DocumentService) as DocumentService,
|
||||||
|
logger: injector.get(Logger) as MockLogger
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => httpMock.verify());
|
||||||
|
|
||||||
describe('currentDocument', () => {
|
describe('currentDocument', () => {
|
||||||
|
|
||||||
it('should fetch a document for the initial location', () => {
|
it('should fetch a document for the initial location', () => {
|
||||||
const { docService, backend } = getServices('initial/doc');
|
const { docService } = getServices('initial/doc');
|
||||||
const connections = backend.connectionsArray;
|
|
||||||
docService.currentDocument.subscribe();
|
docService.currentDocument.subscribe();
|
||||||
|
|
||||||
expect(connections.length).toEqual(1);
|
httpMock.expectOne(CONTENT_URL_PREFIX + 'initial/doc.json');
|
||||||
expect(connections[0].request.url).toEqual(CONTENT_URL_PREFIX + 'initial/doc.json');
|
|
||||||
expect(backend.connectionsArray[0].request.url).toEqual(CONTENT_URL_PREFIX + 'initial/doc.json');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit a document each time the location changes', () => {
|
it('should emit a document each time the location changes', () => {
|
||||||
let latestDocument: DocumentContents;
|
let latestDocument: DocumentContents;
|
||||||
const doc0 = { contents: 'doc 0', id: 'initial/doc' };
|
const doc0 = { contents: 'doc 0', id: 'initial/doc' };
|
||||||
const doc1 = { contents: 'doc 1', id: 'new/doc' };
|
const doc1 = { contents: 'doc 1', id: 'new/doc' };
|
||||||
const { docService, backend, locationService } = getServices('initial/doc');
|
const { docService, locationService } = getServices('initial/doc');
|
||||||
const connections = backend.connectionsArray;
|
|
||||||
|
|
||||||
docService.currentDocument.subscribe(doc => latestDocument = doc);
|
docService.currentDocument.subscribe(doc => latestDocument = doc);
|
||||||
expect(latestDocument).toBeUndefined();
|
expect(latestDocument).toBeUndefined();
|
||||||
|
|
||||||
connections[0].mockRespond(createResponse(doc0));
|
httpMock.expectOne({}).flush(doc0);
|
||||||
expect(latestDocument).toEqual(doc0);
|
expect(latestDocument).toEqual(doc0);
|
||||||
|
|
||||||
locationService.go('new/doc');
|
locationService.go('new/doc');
|
||||||
connections[1].mockRespond(createResponse(doc1));
|
httpMock.expectOne({}).flush(doc1);
|
||||||
expect(latestDocument).toEqual(doc1);
|
expect(latestDocument).toEqual(doc1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit the not-found document if the document is not found on the server', () => {
|
it('should emit the not-found document if the document is not found on the server', () => {
|
||||||
const { docService, backend } = getServices('missing/doc');
|
|
||||||
const connections = backend.connectionsArray;
|
|
||||||
let currentDocument: DocumentContents;
|
let currentDocument: DocumentContents;
|
||||||
|
const notFoundDoc = { id: FILE_NOT_FOUND_ID, contents: '<h1>Page Not Found</h1>' };
|
||||||
|
const { docService } = getServices('missing/doc');
|
||||||
docService.currentDocument.subscribe(doc => currentDocument = doc);
|
docService.currentDocument.subscribe(doc => currentDocument = doc);
|
||||||
|
|
||||||
connections[0].mockError(new Response(new ResponseOptions({ status: 404, statusText: 'NOT FOUND'})) as any);
|
// Initial request return 404.
|
||||||
expect(connections.length).toEqual(2);
|
httpMock.expectOne({}).flush(null, {status: 404, statusText: 'NOT FOUND'});
|
||||||
expect(connections[1].request.url).toEqual(CONTENT_URL_PREFIX + 'file-not-found.json');
|
|
||||||
const fileNotFoundDoc = { id: FILE_NOT_FOUND_ID, contents: '<h1>Page Not Found</h1>' };
|
// Subsequent request for not-found document.
|
||||||
connections[1].mockRespond(createResponse(fileNotFoundDoc));
|
httpMock.expectOne(CONTENT_URL_PREFIX + 'file-not-found.json').flush(notFoundDoc);
|
||||||
expect(currentDocument).toEqual(fileNotFoundDoc);
|
|
||||||
|
expect(currentDocument).toEqual(notFoundDoc);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit a hard-coded not-found document if the not-found document is not found on the server', () => {
|
it('should emit a hard-coded not-found document if the not-found document is not found on the server', () => {
|
||||||
let currentDocument: DocumentContents;
|
let currentDocument: DocumentContents;
|
||||||
const notFoundDoc: DocumentContents = { contents: 'Document not found', id: FILE_NOT_FOUND_ID };
|
const hardCodedNotFoundDoc = { contents: 'Document not found', id: FILE_NOT_FOUND_ID };
|
||||||
const nextDoc = { contents: 'Next Doc', id: 'new/doc' };
|
const nextDoc = { contents: 'Next Doc', id: 'new/doc' };
|
||||||
const { docService, backend, locationService } = getServices(FILE_NOT_FOUND_ID);
|
const { docService, locationService } = getServices(FILE_NOT_FOUND_ID);
|
||||||
const connections = backend.connectionsArray;
|
|
||||||
docService.currentDocument.subscribe(doc => currentDocument = doc);
|
docService.currentDocument.subscribe(doc => currentDocument = doc);
|
||||||
|
|
||||||
connections[0].mockError(new Response(new ResponseOptions({ status: 404, statusText: 'NOT FOUND'})) as any);
|
httpMock.expectOne({}).flush(null, { status: 404, statusText: 'NOT FOUND'});
|
||||||
expect(connections.length).toEqual(1);
|
expect(currentDocument).toEqual(hardCodedNotFoundDoc);
|
||||||
expect(currentDocument).toEqual(notFoundDoc);
|
|
||||||
|
|
||||||
// now check that we haven't killed the currentDocument observable sequence
|
// now check that we haven't killed the currentDocument observable sequence
|
||||||
locationService.go('new/doc');
|
locationService.go('new/doc');
|
||||||
connections[1].mockRespond(createResponse(nextDoc));
|
httpMock.expectOne({}).flush(nextDoc);
|
||||||
expect(currentDocument).toEqual(nextDoc);
|
expect(currentDocument).toEqual(nextDoc);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should use a hard-coded error doc if the request fails (but not cache it)', () => {
|
||||||
|
let latestDocument: DocumentContents;
|
||||||
|
const doc1 = { contents: 'doc 1' };
|
||||||
|
const doc2 = { contents: 'doc 2' };
|
||||||
|
const { docService, locationService } = getServices('initial/doc');
|
||||||
|
|
||||||
|
docService.currentDocument.subscribe(doc => latestDocument = doc);
|
||||||
|
|
||||||
|
httpMock.expectOne({}).flush(null, {status: 500, statusText: 'Server Error'});
|
||||||
|
expect(latestDocument.id).toEqual(FETCHING_ERROR_ID);
|
||||||
|
|
||||||
|
locationService.go('new/doc');
|
||||||
|
httpMock.expectOne({}).flush(doc1);
|
||||||
|
expect(latestDocument).toEqual(jasmine.objectContaining(doc1));
|
||||||
|
|
||||||
|
locationService.go('initial/doc');
|
||||||
|
httpMock.expectOne({}).flush(doc2);
|
||||||
|
expect(latestDocument).toEqual(jasmine.objectContaining(doc2));
|
||||||
|
});
|
||||||
|
|
||||||
it('should not crash the app if the response is invalid JSON', () => {
|
it('should not crash the app if the response is invalid JSON', () => {
|
||||||
let latestDocument: DocumentContents;
|
let latestDocument: DocumentContents;
|
||||||
const { docService, backend, locationService} = getServices('initial/doc');
|
const doc1 = { contents: 'doc 1' };
|
||||||
const connections = backend.connectionsArray;
|
const { docService, locationService } = getServices('initial/doc');
|
||||||
|
|
||||||
docService.currentDocument.subscribe(doc => latestDocument = doc);
|
docService.currentDocument.subscribe(doc => latestDocument = doc);
|
||||||
|
|
||||||
connections[0].mockRespond(new Response(new ResponseOptions({ body: 'this is invalid JSON' })));
|
httpMock.expectOne({}).flush('this is invalid JSON');
|
||||||
expect(latestDocument.id).toEqual(FETCHING_ERROR_ID);
|
expect(latestDocument.id).toEqual(FETCHING_ERROR_ID);
|
||||||
|
|
||||||
const doc1 = { contents: 'doc 1' };
|
|
||||||
locationService.go('new/doc');
|
locationService.go('new/doc');
|
||||||
connections[1].mockRespond(createResponse(doc1));
|
httpMock.expectOne({}).flush(doc1);
|
||||||
expect(latestDocument).toEqual(jasmine.objectContaining(doc1));
|
expect(latestDocument).toEqual(jasmine.objectContaining(doc1));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -132,37 +142,30 @@ describe('DocumentService', () => {
|
||||||
|
|
||||||
const doc0 = { contents: 'doc 0' };
|
const doc0 = { contents: 'doc 0' };
|
||||||
const doc1 = { contents: 'doc 1' };
|
const doc1 = { contents: 'doc 1' };
|
||||||
const { docService, backend, locationService} = getServices('url/0');
|
const { docService, locationService } = getServices('url/0');
|
||||||
const connections = backend.connectionsArray;
|
|
||||||
|
|
||||||
subscription = docService.currentDocument.subscribe(doc => latestDocument = doc);
|
subscription = docService.currentDocument.subscribe(doc => latestDocument = doc);
|
||||||
expect(connections.length).toEqual(1);
|
httpMock.expectOne({}).flush(doc0);
|
||||||
connections[0].mockRespond(createResponse(doc0));
|
|
||||||
expect(latestDocument).toEqual(jasmine.objectContaining(doc0));
|
expect(latestDocument).toEqual(jasmine.objectContaining(doc0));
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
|
|
||||||
// modify the response so we can check that future subscriptions do not trigger another request
|
|
||||||
connections[0].response.next(createResponse({ contents: 'error 0' }));
|
|
||||||
|
|
||||||
subscription = docService.currentDocument.subscribe(doc => latestDocument = doc);
|
subscription = docService.currentDocument.subscribe(doc => latestDocument = doc);
|
||||||
locationService.go('url/1');
|
locationService.go('url/1');
|
||||||
expect(connections.length).toEqual(2);
|
httpMock.expectOne({}).flush(doc1);
|
||||||
connections[1].mockRespond(createResponse(doc1));
|
|
||||||
expect(latestDocument).toEqual(jasmine.objectContaining(doc1));
|
expect(latestDocument).toEqual(jasmine.objectContaining(doc1));
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
|
|
||||||
// modify the response so we can check that future subscriptions do not trigger another request
|
// This should not trigger a new request.
|
||||||
connections[1].response.next(createResponse({ contents: 'error 1' }));
|
|
||||||
|
|
||||||
subscription = docService.currentDocument.subscribe(doc => latestDocument = doc);
|
subscription = docService.currentDocument.subscribe(doc => latestDocument = doc);
|
||||||
locationService.go('url/0');
|
locationService.go('url/0');
|
||||||
expect(connections.length).toEqual(2);
|
httpMock.expectNone({});
|
||||||
expect(latestDocument).toEqual(jasmine.objectContaining(doc0));
|
expect(latestDocument).toEqual(jasmine.objectContaining(doc0));
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
|
|
||||||
|
// This should not trigger a new request.
|
||||||
subscription = docService.currentDocument.subscribe(doc => latestDocument = doc);
|
subscription = docService.currentDocument.subscribe(doc => latestDocument = doc);
|
||||||
locationService.go('url/1');
|
locationService.go('url/1');
|
||||||
expect(connections.length).toEqual(2);
|
httpMock.expectNone({});
|
||||||
expect(latestDocument).toEqual(jasmine.objectContaining(doc1));
|
expect(latestDocument).toEqual(jasmine.objectContaining(doc1));
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
});
|
});
|
||||||
|
@ -171,17 +174,18 @@ describe('DocumentService', () => {
|
||||||
describe('computeMap', () => {
|
describe('computeMap', () => {
|
||||||
it('should map the "empty" location to the correct document request', () => {
|
it('should map the "empty" location to the correct document request', () => {
|
||||||
let latestDocument: DocumentContents;
|
let latestDocument: DocumentContents;
|
||||||
const { docService, backend } = getServices();
|
const { docService } = getServices();
|
||||||
|
|
||||||
docService.currentDocument.subscribe(doc => latestDocument = doc);
|
docService.currentDocument.subscribe(doc => latestDocument = doc);
|
||||||
|
|
||||||
expect(backend.connectionsArray[0].request.url).toEqual(CONTENT_URL_PREFIX + 'index.json');
|
httpMock.expectOne(CONTENT_URL_PREFIX + 'index.json');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should map the "folder" locations to the correct document request', () => {
|
it('should map the "folder" locations to the correct document request', () => {
|
||||||
const { docService, backend, locationService} = getServices('guide');
|
const { docService } = getServices('guide');
|
||||||
docService.currentDocument.subscribe();
|
docService.currentDocument.subscribe();
|
||||||
|
|
||||||
expect(backend.connectionsArray[0].request.url).toEqual(CONTENT_URL_PREFIX + 'guide.json');
|
httpMock.expectOne(CONTENT_URL_PREFIX + 'guide.json');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Http, Response } from '@angular/http';
|
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { AsyncSubject } from 'rxjs/AsyncSubject';
|
import { AsyncSubject } from 'rxjs/AsyncSubject';
|
||||||
import { of } from 'rxjs/observable/of';
|
import { of } from 'rxjs/observable/of';
|
||||||
import 'rxjs/add/operator/catch';
|
import 'rxjs/add/operator/catch';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
import 'rxjs/add/operator/switchMap';
|
import 'rxjs/add/operator/switchMap';
|
||||||
|
|
||||||
import { DocumentContents } from './document-contents';
|
import { DocumentContents } from './document-contents';
|
||||||
|
@ -41,7 +40,7 @@ export class DocumentService {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private logger: Logger,
|
private logger: Logger,
|
||||||
private http: Http,
|
private http: HttpClient,
|
||||||
location: LocationService) {
|
location: LocationService) {
|
||||||
// Whenever the URL changes we try to get the appropriate doc
|
// Whenever the URL changes we try to get the appropriate doc
|
||||||
this.currentDocument = location.currentPath.switchMap(path => this.getDocument(path));
|
this.currentDocument = location.currentPath.switchMap(path => this.getDocument(path));
|
||||||
|
@ -58,15 +57,22 @@ export class DocumentService {
|
||||||
|
|
||||||
private fetchDocument(id: string): Observable<DocumentContents> {
|
private fetchDocument(id: string): Observable<DocumentContents> {
|
||||||
const requestPath = `${DOC_CONTENT_URL_PREFIX}${id}.json`;
|
const requestPath = `${DOC_CONTENT_URL_PREFIX}${id}.json`;
|
||||||
|
const subject = new AsyncSubject<DocumentContents>();
|
||||||
|
|
||||||
this.logger.log('fetching document from', requestPath);
|
this.logger.log('fetching document from', requestPath);
|
||||||
const subject = new AsyncSubject();
|
|
||||||
this.http
|
this.http
|
||||||
.get(requestPath)
|
.get<DocumentContents>(requestPath, {responseType: 'json'})
|
||||||
.map(response => response.json())
|
.do(data => {
|
||||||
.catch((error: Response) => {
|
if (!data || typeof data !== 'object') {
|
||||||
|
this.logger.log('received invalid data:', data);
|
||||||
|
throw Error('Invalid data');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error: HttpErrorResponse) => {
|
||||||
return error.status === 404 ? this.getFileNotFoundDoc(id) : this.getErrorDoc(id, error);
|
return error.status === 404 ? this.getFileNotFoundDoc(id) : this.getErrorDoc(id, error);
|
||||||
})
|
})
|
||||||
.subscribe(subject);
|
.subscribe(subject);
|
||||||
|
|
||||||
return subject.asObservable();
|
return subject.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +89,7 @@ export class DocumentService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getErrorDoc(id: string, error: Response): Observable<DocumentContents> {
|
private getErrorDoc(id: string, error: HttpErrorResponse): Observable<DocumentContents> {
|
||||||
this.logger.error('Error fetching document', error);
|
this.logger.error('Error fetching document', error);
|
||||||
this.cache.delete(id);
|
this.cache.delete(id);
|
||||||
return Observable.of({
|
return Observable.of({
|
||||||
|
|
|
@ -26,10 +26,6 @@ describe('ApiListComponent', () => {
|
||||||
sections = getApiSections();
|
sections = getApiSections();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be creatable', () => {
|
|
||||||
expect(component).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expectation Utility: Assert that filteredSections has the expected result for this test
|
* Expectation Utility: Assert that filteredSections has the expected result for this test
|
||||||
* @param itemTest - return true if the item passes the match test
|
* @param itemTest - return true if the item passes the match test
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { ReflectiveInjector } from '@angular/core';
|
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||||
import { Http, ConnectionBackend, RequestOptions, BaseRequestOptions, Response, ResponseOptions } from '@angular/http';
|
import { Injector } from '@angular/core';
|
||||||
import { MockBackend, MockConnection } from '@angular/http/testing';
|
import { TestBed, inject } from '@angular/core/testing';
|
||||||
|
|
||||||
import { Logger } from 'app/shared/logger.service';
|
import { Logger } from 'app/shared/logger.service';
|
||||||
|
|
||||||
|
@ -8,35 +8,27 @@ import { ApiService } from './api.service';
|
||||||
|
|
||||||
describe('ApiService', () => {
|
describe('ApiService', () => {
|
||||||
|
|
||||||
let injector: ReflectiveInjector;
|
let injector: Injector;
|
||||||
let service: ApiService;
|
let service: ApiService;
|
||||||
let backend: MockBackend;
|
let httpMock: HttpTestingController;
|
||||||
|
|
||||||
function createResponse(body: any) {
|
|
||||||
return new Response(new ResponseOptions({ body: JSON.stringify(body) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
injector = ReflectiveInjector.resolveAndCreate([
|
injector = TestBed.configureTestingModule({
|
||||||
ApiService,
|
imports: [HttpClientTestingModule],
|
||||||
{ provide: ConnectionBackend, useClass: MockBackend },
|
providers: [
|
||||||
{ provide: RequestOptions, useClass: BaseRequestOptions },
|
ApiService,
|
||||||
Http,
|
{ provide: Logger, useClass: TestLogger }
|
||||||
{ provide: Logger, useClass: TestLogger }
|
]
|
||||||
]);
|
});
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
backend = injector.get(ConnectionBackend);
|
|
||||||
service = injector.get(ApiService);
|
service = injector.get(ApiService);
|
||||||
|
httpMock = injector.get(HttpTestingController);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be creatable', () => {
|
afterEach(() => httpMock.verify());
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not immediately connect to the server', () => {
|
it('should not immediately connect to the server', () => {
|
||||||
expect(backend.connectionsArray.length).toEqual(0);
|
httpMock.expectNone({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('subscribers should be completed/unsubscribed when service destroyed', () => {
|
it('subscribers should be completed/unsubscribed when service destroyed', () => {
|
||||||
|
@ -50,9 +42,13 @@ describe('ApiService', () => {
|
||||||
|
|
||||||
service.ngOnDestroy();
|
service.ngOnDestroy();
|
||||||
expect(completed).toBe(true);
|
expect(completed).toBe(true);
|
||||||
|
|
||||||
|
// Stop `httpMock.verify()` from complaining.
|
||||||
|
httpMock.expectOne({});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#sections', () => {
|
describe('#sections', () => {
|
||||||
|
|
||||||
it('first subscriber should fetch sections', () => {
|
it('first subscriber should fetch sections', () => {
|
||||||
const data = [{name: 'a', title: 'A', items: []}, {name: 'b', title: 'B', items: []}];
|
const data = [{name: 'a', title: 'A', items: []}, {name: 'b', title: 'B', items: []}];
|
||||||
|
|
||||||
|
@ -60,7 +56,7 @@ describe('ApiService', () => {
|
||||||
expect(sections).toEqual(data);
|
expect(sections).toEqual(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
backend.connectionsArray[0].mockRespond(createResponse(data));
|
httpMock.expectOne({}).flush(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('second subscriber should get previous sections and NOT trigger refetch', () => {
|
it('second subscriber should get previous sections and NOT trigger refetch', () => {
|
||||||
|
@ -77,27 +73,20 @@ describe('ApiService', () => {
|
||||||
expect(sections).toEqual(data);
|
expect(sections).toEqual(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
backend.connectionsArray[0].mockRespond(createResponse(data));
|
httpMock.expectOne({}).flush(data);
|
||||||
|
|
||||||
expect(backend.connectionsArray.length).toBe(1, 'server connections');
|
|
||||||
expect(subscriptions).toBe(2, 'subscriptions');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#fetchSections', () => {
|
describe('#fetchSections', () => {
|
||||||
|
|
||||||
it('should connect to the server w/ expected URL', () => {
|
it('should connect to the server w/ expected URL', () => {
|
||||||
service.fetchSections();
|
service.fetchSections();
|
||||||
expect(backend.connectionsArray.length).toEqual(1);
|
httpMock.expectOne('generated/docs/api/api-list.json');
|
||||||
expect(backend.connectionsArray[0].request.url).toEqual('generated/docs/api/api-list.json');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should refresh the #sections observable w/ new content on second call', () => {
|
it('should refresh the #sections observable w/ new content on second call', () => {
|
||||||
|
|
||||||
let call = 0;
|
let call = 0;
|
||||||
let connection: MockConnection;
|
|
||||||
backend.connections.subscribe(c => connection = c);
|
|
||||||
|
|
||||||
let data = [{name: 'a', title: 'A', items: []}, {name: 'b', title: 'B', items: []}];
|
let data = [{name: 'a', title: 'A', items: []}, {name: 'b', title: 'B', items: []}];
|
||||||
|
|
||||||
|
@ -107,12 +96,13 @@ describe('ApiService', () => {
|
||||||
// (2) after refresh
|
// (2) after refresh
|
||||||
expect(sections).toEqual(data, 'call ' + call++);
|
expect(sections).toEqual(data, 'call ' + call++);
|
||||||
});
|
});
|
||||||
connection.mockRespond(createResponse(data));
|
|
||||||
|
httpMock.expectOne({}).flush(data);
|
||||||
|
|
||||||
// refresh/refetch
|
// refresh/refetch
|
||||||
data = [{name: 'c', title: 'C', items: []}];
|
data = [{name: 'c', title: 'C', items: []}];
|
||||||
service.fetchSections();
|
service.fetchSections();
|
||||||
connection.mockRespond(createResponse(data));
|
httpMock.expectOne({}).flush(data);
|
||||||
|
|
||||||
expect(call).toBe(2, 'should be called twice');
|
expect(call).toBe(2, 'should be called twice');
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Injectable, OnDestroy } from '@angular/core';
|
import { Injectable, OnDestroy } from '@angular/core';
|
||||||
import { Http } from '@angular/http';
|
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||||
|
|
||||||
import { ReplaySubject } from 'rxjs/ReplaySubject';
|
import { ReplaySubject } from 'rxjs/ReplaySubject';
|
||||||
import { Subject } from 'rxjs/Subject';
|
import { Subject } from 'rxjs/Subject';
|
||||||
|
@ -54,7 +54,7 @@ export class ApiService implements OnDestroy {
|
||||||
return this._sections;
|
return this._sections;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private http: Http, private logger: Logger) { }
|
constructor(private http: HttpClient, private logger: Logger) { }
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.onDestroy.next();
|
this.onDestroy.next();
|
||||||
|
@ -70,13 +70,12 @@ export class ApiService implements OnDestroy {
|
||||||
fetchSections(src?: string) {
|
fetchSections(src?: string) {
|
||||||
// TODO: get URL by configuration?
|
// TODO: get URL by configuration?
|
||||||
const url = this.apiBase + (src || this.apiListJsonDefault);
|
const url = this.apiBase + (src || this.apiListJsonDefault);
|
||||||
this.http.get(url)
|
this.http.get<ApiSection[]>(url)
|
||||||
.takeUntil(this.onDestroy)
|
.takeUntil(this.onDestroy)
|
||||||
.map(response => response.json())
|
|
||||||
.do(() => this.logger.log(`Got API sections from ${url}`))
|
.do(() => this.logger.log(`Got API sections from ${url}`))
|
||||||
.subscribe(
|
.subscribe(
|
||||||
sections => this.sectionsSubject.next(sections),
|
sections => this.sectionsSubject.next(sections),
|
||||||
err => {
|
(err: HttpErrorResponse) => {
|
||||||
// Todo: handle error
|
// Todo: handle error
|
||||||
this.logger.error(err);
|
this.logger.error(err);
|
||||||
throw err; // rethrow for now.
|
throw err; // rethrow for now.
|
||||||
|
|
|
@ -1,39 +1,33 @@
|
||||||
import { ReflectiveInjector } from '@angular/core';
|
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||||
import { Http, ConnectionBackend, RequestOptions, BaseRequestOptions, Response, ResponseOptions } from '@angular/http';
|
import { Injector } from '@angular/core';
|
||||||
import { MockBackend } from '@angular/http/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { ContributorService } from './contributor.service';
|
import { ContributorService } from './contributor.service';
|
||||||
import { Contributor, ContributorGroup } from './contributors.model';
|
import { Contributor, ContributorGroup } from './contributors.model';
|
||||||
|
|
||||||
describe('ContributorService', () => {
|
describe('ContributorService', () => {
|
||||||
|
|
||||||
let injector: ReflectiveInjector;
|
let injector: Injector;
|
||||||
let backend: MockBackend;
|
|
||||||
let contribService: ContributorService;
|
let contribService: ContributorService;
|
||||||
|
let httpMock: HttpTestingController;
|
||||||
function createResponse(body: any) {
|
|
||||||
return new Response(new ResponseOptions({ body: JSON.stringify(body) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
injector = ReflectiveInjector.resolveAndCreate([
|
injector = TestBed.configureTestingModule({
|
||||||
ContributorService,
|
imports: [HttpClientTestingModule],
|
||||||
{ provide: ConnectionBackend, useClass: MockBackend },
|
providers: [
|
||||||
{ provide: RequestOptions, useClass: BaseRequestOptions },
|
ContributorService
|
||||||
Http
|
]
|
||||||
]);
|
});
|
||||||
|
|
||||||
backend = injector.get(ConnectionBackend);
|
|
||||||
contribService = injector.get(ContributorService);
|
contribService = injector.get(ContributorService);
|
||||||
|
httpMock = injector.get(HttpTestingController);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be creatable', () => {
|
afterEach(() => httpMock.verify());
|
||||||
expect(contribService).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should make a single connection to the server', () => {
|
it('should make a single connection to the server', () => {
|
||||||
expect(backend.connectionsArray.length).toEqual(1);
|
const req = httpMock.expectOne({});
|
||||||
expect(backend.connectionsArray[0].request.url).toEqual('generated/contributors.json');
|
expect(req.request.url).toBe('generated/contributors.json');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#contributors', () => {
|
describe('#contributors', () => {
|
||||||
|
@ -43,7 +37,7 @@ describe('ContributorService', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
testData = getTestContribs();
|
testData = getTestContribs();
|
||||||
backend.connectionsArray[0].mockRespond(createResponse(testData));
|
httpMock.expectOne({}).flush(testData);
|
||||||
contribService.contributors.subscribe(results => contribs = results);
|
contribService.contributors.subscribe(results => contribs = results);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -70,55 +64,54 @@ describe('ContributorService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function getTestContribs() {
|
function getTestContribs() {
|
||||||
// tslint:disable:quotemark
|
|
||||||
return {
|
return {
|
||||||
"kapunahelewong": {
|
kapunahelewong: {
|
||||||
"name": "Kapunahele Wong",
|
name: 'Kapunahele Wong',
|
||||||
"picture": "kapunahelewong.jpg",
|
picture: 'kapunahelewong.jpg',
|
||||||
"website": " https://github.com/kapunahelewong",
|
website: 'https://github.com/kapunahelewong',
|
||||||
"twitter": "kapunahele",
|
twitter: 'kapunahele',
|
||||||
"bio": "Kapunahele is a front-end developer and contributor to angular.io",
|
bio: 'Kapunahele is a front-end developer and contributor to angular.io',
|
||||||
"group": "GDE"
|
group: 'GDE'
|
||||||
},
|
},
|
||||||
"misko": {
|
misko: {
|
||||||
"name": "Miško Hevery",
|
name: 'Miško Hevery',
|
||||||
"picture": "misko.jpg",
|
picture: 'misko.jpg',
|
||||||
"twitter": "mhevery",
|
twitter: 'mhevery',
|
||||||
"website": "http://misko.hevery.com",
|
website: 'http://misko.hevery.com',
|
||||||
"bio": "Miško Hevery is the creator of AngularJS framework.",
|
bio: 'Miško Hevery is the creator of AngularJS framework.',
|
||||||
"group": "Angular"
|
group: 'Angular'
|
||||||
},
|
},
|
||||||
"igor": {
|
igor: {
|
||||||
"name": "Igor Minar",
|
name: 'Igor Minar',
|
||||||
"picture": "igor-minar.jpg",
|
picture: 'igor-minar.jpg',
|
||||||
"twitter": "IgorMinar",
|
twitter: 'IgorMinar',
|
||||||
"website": "https://google.com/+IgorMinar",
|
website: 'https://google.com/+IgorMinar',
|
||||||
"bio": "Igor is a software engineer at Angular.",
|
bio: 'Igor is a software engineer at Angular.',
|
||||||
"group": "Angular"
|
group: 'Angular'
|
||||||
},
|
},
|
||||||
"kara": {
|
kara: {
|
||||||
"name": "Kara Erickson",
|
name: 'Kara Erickson',
|
||||||
"picture": "kara-erickson.jpg",
|
picture: 'kara-erickson.jpg',
|
||||||
"twitter": "karaforthewin",
|
twitter: 'karaforthewin',
|
||||||
"website": "https://github.com/kara",
|
website: 'https://github.com/kara',
|
||||||
"bio": "Kara is a software engineer on the Angular team at Angular and a co-organizer of the Angular-SF Meetup. ",
|
bio: 'Kara is a software engineer on the Angular team at Angular and a co-organizer of the Angular-SF Meetup. ',
|
||||||
"group": "Angular"
|
group: 'Angular'
|
||||||
},
|
},
|
||||||
"jeffcross": {
|
jeffcross: {
|
||||||
"name": "Jeff Cross",
|
name: 'Jeff Cross',
|
||||||
"picture": "jeff-cross.jpg",
|
picture: 'jeff-cross.jpg',
|
||||||
"twitter": "jeffbcross",
|
twitter: 'jeffbcross',
|
||||||
"website": "https://twitter.com/jeffbcross",
|
website: 'https://twitter.com/jeffbcross',
|
||||||
"bio": "Jeff was one of the earliest core team members on AngularJS.",
|
bio: 'Jeff was one of the earliest core team members on AngularJS.',
|
||||||
"group": "GDE"
|
group: 'GDE'
|
||||||
},
|
},
|
||||||
"naomi": {
|
naomi: {
|
||||||
"name": "Naomi Black",
|
name: 'Naomi Black',
|
||||||
"picture": "naomi.jpg",
|
picture: 'naomi.jpg',
|
||||||
"twitter": "naomitraveller",
|
twitter: 'naomitraveller',
|
||||||
"website": "http://google.com/+NaomiBlack",
|
website: 'http://google.com/+NaomiBlack',
|
||||||
"bio": "Naomi is Angular's TPM generalist and jack-of-all-trades.",
|
bio: 'Naomi is Angular\'s TPM generalist and jack-of-all-trades.',
|
||||||
"group": "Angular"
|
group: 'Angular'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Http } from '@angular/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import 'rxjs/add/operator/map';
|
import 'rxjs/add/operator/map';
|
||||||
|
@ -15,14 +15,12 @@ const knownGroups = ['Angular', 'GDE'];
|
||||||
export class ContributorService {
|
export class ContributorService {
|
||||||
contributors: Observable<ContributorGroup[]>;
|
contributors: Observable<ContributorGroup[]>;
|
||||||
|
|
||||||
constructor(private http: Http) {
|
constructor(private http: HttpClient) {
|
||||||
this.contributors = this.getContributors();
|
this.contributors = this.getContributors();
|
||||||
}
|
}
|
||||||
|
|
||||||
private getContributors() {
|
private getContributors() {
|
||||||
const contributors = this.http.get(contributorsPath)
|
const contributors = this.http.get<{[key: string]: Contributor}>(contributorsPath)
|
||||||
.map(res => res.json())
|
|
||||||
|
|
||||||
// Create group map
|
// Create group map
|
||||||
.map(contribs => {
|
.map(contribs => {
|
||||||
const contribMap = new Map<string, Contributor[]>();
|
const contribMap = new Map<string, Contributor[]>();
|
||||||
|
|
|
@ -1,39 +1,33 @@
|
||||||
import { ReflectiveInjector } from '@angular/core';
|
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||||
import { Http, ConnectionBackend, RequestOptions, BaseRequestOptions, Response, ResponseOptions } from '@angular/http';
|
import { Injector } from '@angular/core';
|
||||||
import { MockBackend } from '@angular/http/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { ResourceService } from './resource.service';
|
import { ResourceService } from './resource.service';
|
||||||
import { Category, SubCategory, Resource } from './resource.model';
|
import { Category, SubCategory, Resource } from './resource.model';
|
||||||
|
|
||||||
describe('ResourceService', () => {
|
describe('ResourceService', () => {
|
||||||
|
|
||||||
let injector: ReflectiveInjector;
|
let injector: Injector;
|
||||||
let backend: MockBackend;
|
|
||||||
let resourceService: ResourceService;
|
let resourceService: ResourceService;
|
||||||
|
let httpMock: HttpTestingController;
|
||||||
function createResponse(body: any) {
|
|
||||||
return new Response(new ResponseOptions({ body: JSON.stringify(body) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
injector = ReflectiveInjector.resolveAndCreate([
|
injector = TestBed.configureTestingModule({
|
||||||
ResourceService,
|
imports: [HttpClientTestingModule],
|
||||||
{ provide: ConnectionBackend, useClass: MockBackend },
|
providers: [
|
||||||
{ provide: RequestOptions, useClass: BaseRequestOptions },
|
ResourceService
|
||||||
Http
|
]
|
||||||
]);
|
});
|
||||||
|
|
||||||
backend = injector.get(ConnectionBackend);
|
|
||||||
resourceService = injector.get(ResourceService);
|
resourceService = injector.get(ResourceService);
|
||||||
|
httpMock = injector.get(HttpTestingController);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be creatable', () => {
|
afterEach(() => httpMock.verify());
|
||||||
expect(resourceService).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should make a single connection to the server', () => {
|
it('should make a single connection to the server', () => {
|
||||||
expect(backend.connectionsArray.length).toEqual(1);
|
const req = httpMock.expectOne({});
|
||||||
expect(backend.connectionsArray[0].request.url).toEqual('generated/resources.json');
|
expect(req.request.url).toBe('generated/resources.json');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#categories', () => {
|
describe('#categories', () => {
|
||||||
|
@ -43,7 +37,7 @@ describe('ResourceService', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
testData = getTestResources();
|
testData = getTestResources();
|
||||||
backend.connectionsArray[0].mockRespond(createResponse(testData));
|
httpMock.expectOne({}).flush(testData);
|
||||||
resourceService.categories.subscribe(results => categories = results);
|
resourceService.categories.subscribe(results => categories = results);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Http } from '@angular/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import 'rxjs/add/operator/map';
|
import 'rxjs/add/operator/map';
|
||||||
|
@ -14,14 +14,13 @@ const resourcesPath = CONTENT_URL_PREFIX + 'resources.json';
|
||||||
export class ResourceService {
|
export class ResourceService {
|
||||||
categories: Observable<Category[]>;
|
categories: Observable<Category[]>;
|
||||||
|
|
||||||
constructor(private http: Http) {
|
constructor(private http: HttpClient) {
|
||||||
this.categories = this.getCategories();
|
this.categories = this.getCategories();
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCategories(): Observable<Category[]> {
|
private getCategories(): Observable<Category[]> {
|
||||||
|
|
||||||
const categories = this.http.get(resourcesPath)
|
const categories = this.http.get<any>(resourcesPath)
|
||||||
.map(res => res.json())
|
|
||||||
.map(data => mkCategories(data))
|
.map(data => mkCategories(data))
|
||||||
.publishLast();
|
.publishLast();
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,37 @@
|
||||||
import { ReflectiveInjector } from '@angular/core';
|
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||||
import { Http, ConnectionBackend, RequestOptions, BaseRequestOptions, Response, ResponseOptions } from '@angular/http';
|
import { Injector } from '@angular/core';
|
||||||
import { MockBackend } from '@angular/http/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { CurrentNodes, NavigationService, NavigationViews, NavigationNode, VersionInfo } from 'app/navigation/navigation.service';
|
import { CurrentNodes, NavigationService, NavigationViews, NavigationNode, VersionInfo } from 'app/navigation/navigation.service';
|
||||||
import { LocationService } from 'app/shared/location.service';
|
import { LocationService } from 'app/shared/location.service';
|
||||||
import { MockLocationService } from 'testing/location.service';
|
import { MockLocationService } from 'testing/location.service';
|
||||||
|
|
||||||
describe('NavigationService', () => {
|
describe('NavigationService', () => {
|
||||||
|
|
||||||
let injector: ReflectiveInjector;
|
let injector: Injector;
|
||||||
let backend: MockBackend;
|
|
||||||
let navService: NavigationService;
|
let navService: NavigationService;
|
||||||
|
let httpMock: HttpTestingController;
|
||||||
function createResponse(body: any) {
|
|
||||||
return new Response(new ResponseOptions({ body: JSON.stringify(body) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
injector = ReflectiveInjector.resolveAndCreate([
|
injector = TestBed.configureTestingModule({
|
||||||
|
imports: [HttpClientTestingModule],
|
||||||
|
providers: [
|
||||||
NavigationService,
|
NavigationService,
|
||||||
{ provide: LocationService, useFactory: () => new MockLocationService('a') },
|
{ provide: LocationService, useFactory: () => new MockLocationService('a') }
|
||||||
{ provide: ConnectionBackend, useClass: MockBackend },
|
]
|
||||||
{ provide: RequestOptions, useClass: BaseRequestOptions },
|
});
|
||||||
Http
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
backend = injector.get(ConnectionBackend);
|
|
||||||
navService = injector.get(NavigationService);
|
navService = injector.get(NavigationService);
|
||||||
|
httpMock = injector.get(HttpTestingController);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be creatable', () => {
|
afterEach(() => httpMock.verify());
|
||||||
expect(navService).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('navigationViews', () => {
|
describe('navigationViews', () => {
|
||||||
|
|
||||||
it('should make a single connection to the server', () => {
|
it('should make a single connection to the server', () => {
|
||||||
expect(backend.connectionsArray.length).toEqual(1);
|
const req = httpMock.expectOne({});
|
||||||
expect(backend.connectionsArray[0].request.url).toEqual('generated/navigation.json');
|
expect(req.request.url).toBe('generated/navigation.json');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should expose the server response', () => {
|
it('should expose the server response', () => {
|
||||||
|
@ -46,7 +39,7 @@ describe('NavigationService', () => {
|
||||||
navService.navigationViews.subscribe(views => viewsEvents.push(views));
|
navService.navigationViews.subscribe(views => viewsEvents.push(views));
|
||||||
|
|
||||||
expect(viewsEvents).toEqual([]);
|
expect(viewsEvents).toEqual([]);
|
||||||
backend.connectionsArray[0].mockRespond(createResponse({ TopBar: [ { url: 'a' }] }));
|
httpMock.expectOne({}).flush({ TopBar: [ { url: 'a' }] });
|
||||||
expect(viewsEvents).toEqual([{ TopBar: [ { url: 'a' }] }]);
|
expect(viewsEvents).toEqual([{ TopBar: [ { url: 'a' }] }]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -54,6 +47,9 @@ describe('NavigationService', () => {
|
||||||
let completed = false;
|
let completed = false;
|
||||||
navService.navigationViews.subscribe(null, null, () => completed = true);
|
navService.navigationViews.subscribe(null, null, () => completed = true);
|
||||||
expect(true).toBe(true, 'observable completed');
|
expect(true).toBe(true, 'observable completed');
|
||||||
|
|
||||||
|
// Stop `$httpMock.verify()` from complaining.
|
||||||
|
httpMock.expectOne({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the same object to all subscribers', () => {
|
it('should return the same object to all subscribers', () => {
|
||||||
|
@ -63,16 +59,16 @@ describe('NavigationService', () => {
|
||||||
let views2: NavigationViews;
|
let views2: NavigationViews;
|
||||||
navService.navigationViews.subscribe(views => views2 = views);
|
navService.navigationViews.subscribe(views => views2 = views);
|
||||||
|
|
||||||
backend.connectionsArray[0].mockRespond(createResponse({ TopBar: [{ url: 'a' }] }));
|
httpMock.expectOne({}).flush({ TopBar: [{ url: 'a' }] });
|
||||||
|
|
||||||
// modify the response so we can check that future subscriptions do not trigger another request
|
|
||||||
backend.connectionsArray[0].response.next(createResponse({ TopBar: [{ url: 'error 1' }] }));
|
|
||||||
|
|
||||||
let views3: NavigationViews;
|
let views3: NavigationViews;
|
||||||
navService.navigationViews.subscribe(views => views3 = views);
|
navService.navigationViews.subscribe(views => views3 = views);
|
||||||
|
|
||||||
expect(views2).toBe(views1);
|
expect(views2).toBe(views1);
|
||||||
expect(views3).toBe(views1);
|
expect(views3).toBe(views1);
|
||||||
|
|
||||||
|
// Verfy that subsequent subscriptions did not trigger another request.
|
||||||
|
httpMock.expectNone({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should do WHAT(?) if the request fails');
|
it('should do WHAT(?) if the request fails');
|
||||||
|
@ -90,7 +86,7 @@ describe('NavigationService', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
navService.navigationViews.subscribe(views => view = views['sideNav']);
|
navService.navigationViews.subscribe(views => view = views['sideNav']);
|
||||||
backend.connectionsArray[0].mockRespond(createResponse({sideNav}));
|
httpMock.expectOne({}).flush({sideNav});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have the supplied tooltip', () => {
|
it('should have the supplied tooltip', () => {
|
||||||
|
@ -135,9 +131,9 @@ describe('NavigationService', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
locationService = injector.get(LocationService);
|
locationService = injector.get(LocationService) as any as MockLocationService;
|
||||||
navService.currentNodes.subscribe(selected => currentNodes = selected);
|
navService.currentNodes.subscribe(selected => currentNodes = selected);
|
||||||
backend.connectionsArray[0].mockRespond(createResponse(navJson));
|
httpMock.expectOne({}).flush(navJson);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should list the side navigation node that matches the current location, and all its ancestors', () => {
|
it('should list the side navigation node that matches the current location, and all its ancestors', () => {
|
||||||
|
@ -231,9 +227,9 @@ describe('NavigationService', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
navService.versionInfo.subscribe(info => versionInfo = info);
|
navService.versionInfo.subscribe(info => versionInfo = info);
|
||||||
backend.connectionsArray[0].mockRespond(createResponse({
|
httpMock.expectOne({}).flush({
|
||||||
__versionInfo: expectedVersionInfo
|
__versionInfo: expectedVersionInfo
|
||||||
}));
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should extract the version info', () => {
|
it('should extract the version info', () => {
|
||||||
|
@ -261,7 +257,7 @@ describe('NavigationService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should extract the docVersions', () => {
|
it('should extract the docVersions', () => {
|
||||||
backend.connectionsArray[0].mockRespond(createResponse({ docVersions }));
|
httpMock.expectOne({}).flush({ docVersions });
|
||||||
expect(actualDocVersions).toEqual(expectedDocVersions);
|
expect(actualDocVersions).toEqual(expectedDocVersions);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Http } from '@angular/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { AsyncSubject } from 'rxjs/AsyncSubject';
|
import { AsyncSubject } from 'rxjs/AsyncSubject';
|
||||||
|
@ -36,7 +36,7 @@ export class NavigationService {
|
||||||
*/
|
*/
|
||||||
currentNodes: Observable<CurrentNodes>;
|
currentNodes: Observable<CurrentNodes>;
|
||||||
|
|
||||||
constructor(private http: Http, private location: LocationService) {
|
constructor(private http: HttpClient, private location: LocationService) {
|
||||||
const navigationInfo = this.fetchNavigationInfo();
|
const navigationInfo = this.fetchNavigationInfo();
|
||||||
this.navigationViews = this.getNavigationViews(navigationInfo);
|
this.navigationViews = this.getNavigationViews(navigationInfo);
|
||||||
|
|
||||||
|
@ -57,8 +57,7 @@ export class NavigationService {
|
||||||
* We are not storing the subscription from connecting as we do not expect this service to be destroyed.
|
* We are not storing the subscription from connecting as we do not expect this service to be destroyed.
|
||||||
*/
|
*/
|
||||||
private fetchNavigationInfo(): Observable<NavigationResponse> {
|
private fetchNavigationInfo(): Observable<NavigationResponse> {
|
||||||
const navigationInfo = this.http.get(navigationPath)
|
const navigationInfo = this.http.get<NavigationResponse>(navigationPath)
|
||||||
.map(res => res.json() as NavigationResponse)
|
|
||||||
.publishLast();
|
.publishLast();
|
||||||
navigationInfo.connect();
|
navigationInfo.connect();
|
||||||
return navigationInfo;
|
return navigationInfo;
|
||||||
|
|
|
@ -12,7 +12,7 @@ describe('CustomMdIconRegistry', () => {
|
||||||
];
|
];
|
||||||
const registry = new CustomMdIconRegistry(mockHttp, mockSanitizer, svgIcons);
|
const registry = new CustomMdIconRegistry(mockHttp, mockSanitizer, svgIcons);
|
||||||
let svgElement: SVGElement;
|
let svgElement: SVGElement;
|
||||||
registry.getNamedSvgIcon('test_icon', null).subscribe(el => svgElement = el as SVGElement);
|
registry.getNamedSvgIcon('test_icon').subscribe(el => svgElement = el);
|
||||||
expect(svgElement).toEqual(createSvg(svgSrc));
|
expect(svgElement).toEqual(createSvg(svgSrc));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -27,8 +27,12 @@ describe('CustomMdIconRegistry', () => {
|
||||||
spyOn(MdIconRegistry.prototype, 'getNamedSvgIcon');
|
spyOn(MdIconRegistry.prototype, 'getNamedSvgIcon');
|
||||||
|
|
||||||
const registry = new CustomMdIconRegistry(mockHttp, mockSanitizer, svgIcons);
|
const registry = new CustomMdIconRegistry(mockHttp, mockSanitizer, svgIcons);
|
||||||
registry.getNamedSvgIcon('other_icon', null);
|
|
||||||
expect(MdIconRegistry.prototype.getNamedSvgIcon).toHaveBeenCalledWith('other_icon', null);
|
registry.getNamedSvgIcon('other_icon');
|
||||||
|
expect(MdIconRegistry.prototype.getNamedSvgIcon).toHaveBeenCalledWith('other_icon', undefined);
|
||||||
|
|
||||||
|
registry.getNamedSvgIcon('other_icon', 'foo');
|
||||||
|
expect(MdIconRegistry.prototype.getNamedSvgIcon).toHaveBeenCalledWith('other_icon', 'foo');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { InjectionToken, Inject, Injectable } from '@angular/core';
|
import { InjectionToken, Inject, Injectable } from '@angular/core';
|
||||||
import { of } from 'rxjs/observable/of';
|
import { of } from 'rxjs/observable/of';
|
||||||
import { MdIconRegistry } from '@angular/material';
|
import { MdIconRegistry } from '@angular/material';
|
||||||
import { Http } from '@angular/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { DomSanitizer } from '@angular/platform-browser';
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,6 +27,19 @@ interface SvgIconMap {
|
||||||
[iconName: string]: SVGElement;
|
[iconName: string]: SVGElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// <hack-alert>
|
||||||
|
// @angular/material's `MdIconRegitry` currently (v2.0.0-beta.8) requires an instance of `Http`
|
||||||
|
// (from @angular/http). It is only used to [get some text content][1], so we can create a wrapper
|
||||||
|
// around `HttpClient` and pretend it is `Http`.
|
||||||
|
// [1]: https://github.com/angular/material2/blob/2.0.0-beta.8/src/lib/icon/icon-registry.ts#L465-L466
|
||||||
|
// </hack-alert>
|
||||||
|
function createFakeHttp(http: HttpClient): any {
|
||||||
|
return {
|
||||||
|
get: (url: string) => http.get(url, {responseType: 'text'})
|
||||||
|
.map(data => ({text: () => data}))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom replacement for Angular Material's `MdIconRegistry`, which allows
|
* A custom replacement for Angular Material's `MdIconRegistry`, which allows
|
||||||
* us to provide preloaded icon SVG sources.
|
* us to provide preloaded icon SVG sources.
|
||||||
|
@ -35,14 +48,14 @@ interface SvgIconMap {
|
||||||
export class CustomMdIconRegistry extends MdIconRegistry {
|
export class CustomMdIconRegistry extends MdIconRegistry {
|
||||||
private preloadedSvgElements: SvgIconMap = {};
|
private preloadedSvgElements: SvgIconMap = {};
|
||||||
|
|
||||||
constructor(http: Http, sanitizer: DomSanitizer, @Inject(SVG_ICONS) svgIcons: SvgIconInfo[]) {
|
constructor(http: HttpClient, sanitizer: DomSanitizer, @Inject(SVG_ICONS) svgIcons: SvgIconInfo[]) {
|
||||||
super(http, sanitizer);
|
super(createFakeHttp(http), sanitizer);
|
||||||
this.loadSvgElements(svgIcons);
|
this.loadSvgElements(svgIcons);
|
||||||
}
|
}
|
||||||
|
|
||||||
getNamedSvgIcon(iconName, namespace) {
|
getNamedSvgIcon(iconName: string, namespace?: string) {
|
||||||
if (this.preloadedSvgElements[iconName]) {
|
if (this.preloadedSvgElements[iconName]) {
|
||||||
return of(this.preloadedSvgElements[iconName].cloneNode(true));
|
return of(this.preloadedSvgElements[iconName].cloneNode(true) as SVGElement);
|
||||||
}
|
}
|
||||||
return super.getNamedSvgIcon(iconName, namespace);
|
return super.getNamedSvgIcon(iconName, namespace);
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,10 +160,6 @@ describe('ScrollSpyService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should be creatable', () => {
|
|
||||||
expect(scrollSpyService).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#spyOn()', () => {
|
describe('#spyOn()', () => {
|
||||||
let getSpiedElemGroups: () => ScrollSpiedElementGroup[];
|
let getSpiedElemGroups: () => ScrollSpiedElementGroup[];
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,6 @@ describe('TocService', () => {
|
||||||
tocService.tocList.subscribe(tocList => lastTocList = tocList);
|
tocService.tocList.subscribe(tocList => lastTocList = tocList);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be creatable', () => {
|
|
||||||
expect(tocService).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('tocList', () => {
|
describe('tocList', () => {
|
||||||
it('should emit the latest value to new subscribers', () => {
|
it('should emit the latest value to new subscribers', () => {
|
||||||
const expectedValue1 = tocItem('Heading A');
|
const expectedValue1 = tocItem('Heading A');
|
||||||
|
|
|
@ -14,19 +14,19 @@ import {
|
||||||
} from '@angular/platform-browser-dynamic/testing';
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
// List vendors here to increase test rebuild performance.
|
// List vendors here to increase test rebuild performance.
|
||||||
|
import '@angular/animations';
|
||||||
import '@angular/common';
|
import '@angular/common';
|
||||||
import '@angular/common/testing';
|
import '@angular/common/testing';
|
||||||
|
import '@angular/common/http';
|
||||||
|
import '@angular/common/http/testing';
|
||||||
import '@angular/core/';
|
import '@angular/core/';
|
||||||
import '@angular/core/testing';
|
import '@angular/core/testing';
|
||||||
|
import '@angular/material';
|
||||||
import '@angular/platform-browser';
|
import '@angular/platform-browser';
|
||||||
import '@angular/platform-browser/testing';
|
import '@angular/platform-browser/testing';
|
||||||
import '@angular/platform-browser/animations';
|
import '@angular/platform-browser/animations';
|
||||||
import '@angular/platform-browser-dynamic';
|
import '@angular/platform-browser-dynamic';
|
||||||
import '@angular/platform-browser-dynamic/testing';
|
import '@angular/platform-browser-dynamic/testing';
|
||||||
import '@angular/http';
|
|
||||||
import '@angular/http/testing';
|
|
||||||
import '@angular/animations';
|
|
||||||
import '@angular/material';
|
|
||||||
import '@angular/service-worker';
|
import '@angular/service-worker';
|
||||||
import 'rxjs'; // tslint:disable-line
|
import 'rxjs'; // tslint:disable-line
|
||||||
|
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
import { Response } from '@angular/http';
|
|
||||||
|
|
||||||
// tslint:disable:quotemark
|
|
||||||
export function getTestNavMapResponse(): Response {
|
|
||||||
|
|
||||||
const navMapJson = { "nodes": [
|
|
||||||
{
|
|
||||||
"docId": "guide/quickstart",
|
|
||||||
"navTitle": "Quickstart",
|
|
||||||
"tooltip": "A quick look at an Angular app."
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"docId": "guide/cli-quickstart",
|
|
||||||
"navTitle": "CLI Quickstart",
|
|
||||||
"tooltip": "A quick look at an Angular app built with the Angular CLI.",
|
|
||||||
"hide": true // <----- SHOULD BE FILTERED OUT
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"navTitle": "Tutorial",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"docId": " tutorial/",
|
|
||||||
"navTitle": "Introduction",
|
|
||||||
"tooltip": "Introduction to the Tour of Heroes tutorial"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"docId": "tutorial/toh-pt1",
|
|
||||||
"navTitle": "The Hero Editor",
|
|
||||||
"tooltip": "Build a simple hero editor."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"navTitle": "Getting started",
|
|
||||||
"tooltip": "A gentle introduction to Angular",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"docId": "guide/docs-overview",
|
|
||||||
"navTitle": "Overview",
|
|
||||||
"tooltip": "How to read and use this documentation."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"docId": "guide/setup",
|
|
||||||
"navTitle": "Setup",
|
|
||||||
"tooltip": "Install the Angular QuickStart seed for faster, more efficient development on your machine."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"navTitle": "Core",
|
|
||||||
"tooltip": "Learn the core capabilities of Angular",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"docId": "guide/NgModule",
|
|
||||||
"navTitle": "Angular Modules (NgModule)",
|
|
||||||
"tooltip": "Define application modules with @NgModule."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"docId": "guide/directives",
|
|
||||||
"navTitle": "Directives",
|
|
||||||
"tooltip": "Learn how directives modify the layout and behavior of elements.",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"docId": "guide/attribute-directives",
|
|
||||||
"navTitle": "Attribute directives",
|
|
||||||
"tooltip": "Attribute directives attach behavior to elements."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"docId": "guide/structural-directives",
|
|
||||||
"navTitle": "Structural directives",
|
|
||||||
"tooltip": "Structural directives manipulate the layout of the page."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"navTitle": "Empty Heading",
|
|
||||||
"children": [ ]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"navTitle": "External",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"url": "https://gitter.im/angular/angular",
|
|
||||||
"navTitle": "Gitter",
|
|
||||||
"tooltip": "Chat about Angular with other birds of a feather"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]};
|
|
||||||
|
|
||||||
// tslint:enable:quotemark
|
|
||||||
return {
|
|
||||||
status: 200,
|
|
||||||
json: () => navMapJson
|
|
||||||
} as Response;
|
|
||||||
}
|
|
|
@ -168,7 +168,7 @@
|
||||||
base64-js "^1.1.2"
|
base64-js "^1.1.2"
|
||||||
jshashes "^1.0.5"
|
jshashes "^1.0.5"
|
||||||
|
|
||||||
"@angular/tsc-wrapped@^5.0.0-beta.3":
|
"@angular/tsc-wrapped@5.0.0-beta.3":
|
||||||
version "5.0.0-beta.3"
|
version "5.0.0-beta.3"
|
||||||
resolved "https://registry.yarnpkg.com/@angular/tsc-wrapped/-/tsc-wrapped-5.0.0-beta.3.tgz#d71c607b02eb6fe7091b908ef2ec97180ec52618"
|
resolved "https://registry.yarnpkg.com/@angular/tsc-wrapped/-/tsc-wrapped-5.0.0-beta.3.tgz#d71c607b02eb6fe7091b908ef2ec97180ec52618"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
Loading…
Reference in New Issue