2017-05-02 10:13:10 -07:00
|
|
|
import { NO_ERRORS_SCHEMA, DebugElement } from '@angular/core';
|
2017-10-11 22:04:50 +01:00
|
|
|
import { inject, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
2017-04-16 22:11:00 +01:00
|
|
|
import { Title } from '@angular/platform-browser';
|
2017-03-02 13:28:28 +00:00
|
|
|
import { APP_BASE_HREF } from '@angular/common';
|
2017-08-11 20:16:55 +03:00
|
|
|
import { HttpClient } from '@angular/common/http';
|
2017-10-13 13:02:27 -07:00
|
|
|
import { MatProgressBar, MatSidenav } from '@angular/material';
|
2017-03-12 15:20:55 +00:00
|
|
|
import { By } from '@angular/platform-browser';
|
2017-03-29 14:13:40 -07:00
|
|
|
|
2017-11-24 15:18:09 +02:00
|
|
|
import { Observable } from 'rxjs/Observable';
|
2017-03-29 14:13:40 -07:00
|
|
|
import { of } from 'rxjs/observable/of';
|
|
|
|
|
2017-02-02 23:02:23 -08:00
|
|
|
import { AppComponent } from './app.component';
|
|
|
|
import { AppModule } from './app.module';
|
2017-04-27 15:32:46 -07:00
|
|
|
import { DocViewerComponent } from 'app/layout/doc-viewer/doc-viewer.component';
|
2017-07-26 18:36:00 +01:00
|
|
|
import { Deployment } from 'app/shared/deployment.service';
|
2017-07-31 15:45:18 +03:00
|
|
|
import { EmbedComponentsService } from 'app/embed-components/embed-components.service';
|
2017-04-27 15:32:46 -07:00
|
|
|
import { GaService } from 'app/shared/ga.service';
|
2017-03-13 21:06:15 +00:00
|
|
|
import { LocationService } from 'app/shared/location.service';
|
2017-03-21 06:33:21 +00:00
|
|
|
import { Logger } from 'app/shared/logger.service';
|
2017-04-27 15:32:46 -07:00
|
|
|
import { MockLocationService } from 'testing/location.service';
|
2017-04-25 14:48:01 -07:00
|
|
|
import { MockLogger } from 'testing/logger.service';
|
2017-04-27 15:32:46 -07:00
|
|
|
import { MockSearchService } from 'testing/search.service';
|
2017-05-08 16:42:38 -07:00
|
|
|
import { NavigationNode } from 'app/navigation/navigation.service';
|
|
|
|
import { ScrollService } from 'app/shared/scroll.service';
|
|
|
|
import { SearchBoxComponent } from 'app/search/search-box/search-box.component';
|
2017-10-12 08:48:27 +01:00
|
|
|
import { SearchResultsComponent } from 'app/shared/search-results/search-results.component';
|
2017-05-08 16:42:38 -07:00
|
|
|
import { SearchService } from 'app/search/search.service';
|
2017-10-11 22:04:50 +01:00
|
|
|
import { SelectComponent } from 'app/shared/select/select.component';
|
2017-07-31 15:45:18 +03:00
|
|
|
import { TocComponent } from 'app/layout/toc/toc.component';
|
2017-06-07 16:51:21 +03:00
|
|
|
import { TocItem, TocService } from 'app/shared/toc.service';
|
2017-02-02 23:02:23 -08:00
|
|
|
|
2017-05-24 23:08:21 -04:00
|
|
|
const sideBySideBreakPoint = 992;
|
|
|
|
const hideToCBreakPoint = 800;
|
|
|
|
|
2017-01-27 00:20:51 -08:00
|
|
|
describe('AppComponent', () => {
|
2017-02-02 23:02:23 -08:00
|
|
|
let component: AppComponent;
|
|
|
|
let fixture: ComponentFixture<AppComponent>;
|
2017-04-11 16:08:53 -07:00
|
|
|
|
|
|
|
let docViewer: HTMLElement;
|
|
|
|
let hamburger: HTMLButtonElement;
|
|
|
|
let locationService: MockLocationService;
|
2017-10-24 09:51:23 +01:00
|
|
|
let sidenav: MatSidenav;
|
2017-06-07 16:51:21 +03:00
|
|
|
let tocService: TocService;
|
2017-04-11 16:08:53 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
const initializeTest = () => {
|
2017-02-02 23:02:23 -08:00
|
|
|
fixture = TestBed.createComponent(AppComponent);
|
|
|
|
component = fixture.componentInstance;
|
2017-04-11 16:08:53 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
fixture.detectChanges();
|
2017-05-24 23:08:21 -04:00
|
|
|
component.onResize(sideBySideBreakPoint + 1); // wide by default
|
2017-05-19 01:52:37 -07:00
|
|
|
|
2017-06-07 16:51:21 +03:00
|
|
|
const de = fixture.debugElement;
|
|
|
|
docViewer = de.query(By.css('aio-doc-viewer')).nativeElement;
|
|
|
|
hamburger = de.query(By.css('.hamburger')).nativeElement;
|
|
|
|
locationService = de.injector.get(LocationService) as any as MockLocationService;
|
2017-10-24 09:51:23 +01:00
|
|
|
sidenav = de.query(By.directive(MatSidenav)).componentInstance;
|
2017-06-07 16:51:21 +03:00
|
|
|
tocService = de.injector.get(TocService);
|
2017-05-19 01:52:37 -07:00
|
|
|
};
|
2017-03-02 13:28:28 +00:00
|
|
|
|
2017-11-23 15:04:29 +02:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('with proper DocViewer', () => {
|
2017-03-30 09:55:03 +03:00
|
|
|
|
2017-06-14 11:00:03 +01:00
|
|
|
beforeEach(() => {
|
2017-11-23 15:04:29 +02:00
|
|
|
DocViewerComponent.animationsEnabled = false;
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
createTestingModule('a/b');
|
|
|
|
initializeTest();
|
2017-03-02 13:28:28 +00:00
|
|
|
});
|
|
|
|
|
2017-11-23 15:04:29 +02:00
|
|
|
afterEach(() => DocViewerComponent.animationsEnabled = true);
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should create', () => {
|
|
|
|
expect(component).toBeDefined();
|
2017-05-02 10:13:10 -07:00
|
|
|
});
|
2017-03-29 14:13:40 -07:00
|
|
|
|
2017-06-07 16:51:21 +03:00
|
|
|
describe('hasFloatingToc', () => {
|
|
|
|
it('should initially be true', () => {
|
|
|
|
const fixture2 = TestBed.createComponent(AppComponent);
|
|
|
|
const component2 = fixture2.componentInstance;
|
|
|
|
|
|
|
|
expect(component2.hasFloatingToc).toBe(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should be false on narrow screens', () => {
|
|
|
|
component.onResize(hideToCBreakPoint - 1);
|
|
|
|
|
|
|
|
tocService.tocList.next([{}, {}, {}] as TocItem[]);
|
|
|
|
expect(component.hasFloatingToc).toBe(false);
|
|
|
|
|
|
|
|
tocService.tocList.next([]);
|
|
|
|
expect(component.hasFloatingToc).toBe(false);
|
|
|
|
|
|
|
|
tocService.tocList.next([{}, {}, {}] as TocItem[]);
|
|
|
|
expect(component.hasFloatingToc).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should be true on wide screens unless the toc is empty', () => {
|
|
|
|
component.onResize(hideToCBreakPoint + 1);
|
|
|
|
|
|
|
|
tocService.tocList.next([{}, {}, {}] as TocItem[]);
|
|
|
|
expect(component.hasFloatingToc).toBe(true);
|
|
|
|
|
|
|
|
tocService.tocList.next([]);
|
|
|
|
expect(component.hasFloatingToc).toBe(false);
|
|
|
|
|
|
|
|
tocService.tocList.next([{}, {}, {}] as TocItem[]);
|
|
|
|
expect(component.hasFloatingToc).toBe(true);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
2017-05-24 21:09:55 +01:00
|
|
|
|
2017-06-07 16:51:21 +03:00
|
|
|
it('should be false when toc is empty', () => {
|
|
|
|
tocService.tocList.next([]);
|
|
|
|
|
2017-05-24 23:08:21 -04:00
|
|
|
component.onResize(hideToCBreakPoint + 1);
|
2017-06-07 16:51:21 +03:00
|
|
|
expect(component.hasFloatingToc).toBe(false);
|
|
|
|
|
2017-05-24 23:08:21 -04:00
|
|
|
component.onResize(hideToCBreakPoint - 1);
|
2017-06-07 16:51:21 +03:00
|
|
|
expect(component.hasFloatingToc).toBe(false);
|
|
|
|
|
|
|
|
component.onResize(hideToCBreakPoint + 1);
|
|
|
|
expect(component.hasFloatingToc).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should be true when toc is not empty unless the screen is narrow', () => {
|
|
|
|
tocService.tocList.next([{}, {}, {}] as TocItem[]);
|
|
|
|
|
|
|
|
component.onResize(hideToCBreakPoint + 1);
|
|
|
|
expect(component.hasFloatingToc).toBe(true);
|
|
|
|
|
|
|
|
component.onResize(hideToCBreakPoint - 1);
|
|
|
|
expect(component.hasFloatingToc).toBe(false);
|
|
|
|
|
|
|
|
component.onResize(hideToCBreakPoint + 1);
|
|
|
|
expect(component.hasFloatingToc).toBe(true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('isSideBySide', () => {
|
|
|
|
it('should be updated on resize', () => {
|
|
|
|
component.onResize(sideBySideBreakPoint - 1);
|
|
|
|
expect(component.isSideBySide).toBe(false);
|
|
|
|
|
|
|
|
component.onResize(sideBySideBreakPoint + 1);
|
|
|
|
expect(component.isSideBySide).toBe(true);
|
2017-05-24 21:09:55 +01:00
|
|
|
});
|
2017-03-29 14:13:40 -07:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('onScroll', () => {
|
|
|
|
it('should update `tocMaxHeight` accordingly', () => {
|
|
|
|
expect(component.tocMaxHeight).toBeUndefined();
|
2017-03-29 14:13:40 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
component.onScroll();
|
|
|
|
expect(component.tocMaxHeight).toBeGreaterThan(0);
|
|
|
|
});
|
2017-04-10 12:44:54 -07:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('SideNav when side-by-side (wide)', () => {
|
2017-04-10 12:44:54 -07:00
|
|
|
|
|
|
|
beforeEach(() => {
|
2017-05-24 23:08:21 -04:00
|
|
|
component.onResize(sideBySideBreakPoint + 1); // side-by-side
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should open when nav to a guide page (guide/pipes)', () => {
|
2017-04-11 16:08:53 -07:00
|
|
|
locationService.go('guide/pipes');
|
2017-04-10 12:44:54 -07:00
|
|
|
fixture.detectChanges();
|
2017-10-24 09:51:23 +01:00
|
|
|
expect(sidenav.opened).toBe(true);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should open when nav to an api page', () => {
|
|
|
|
locationService.go('api/a/b/c/d');
|
2017-04-10 12:44:54 -07:00
|
|
|
fixture.detectChanges();
|
2017-10-24 09:51:23 +01:00
|
|
|
expect(sidenav.opened).toBe(true);
|
2017-04-10 12:44:54 -07:00
|
|
|
});
|
2017-03-29 14:13:40 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should be closed when nav to a marketing page (features)', () => {
|
|
|
|
locationService.go('features');
|
|
|
|
fixture.detectChanges();
|
2017-10-24 09:51:23 +01:00
|
|
|
expect(sidenav.opened).toBe(false);
|
2017-04-10 12:44:54 -07:00
|
|
|
});
|
2017-04-11 16:08:53 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('when manually closed', () => {
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
locationService.go('guide/pipes');
|
|
|
|
fixture.detectChanges();
|
|
|
|
hamburger.click();
|
|
|
|
fixture.detectChanges();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should be closed', () => {
|
2017-10-24 09:51:23 +01:00
|
|
|
expect(sidenav.opened).toBe(false);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should stay closed when nav from one guide page to another', () => {
|
|
|
|
locationService.go('guide/bags');
|
|
|
|
fixture.detectChanges();
|
2017-10-24 09:51:23 +01:00
|
|
|
expect(sidenav.opened).toBe(false);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should stay closed when nav from a guide page to api page', () => {
|
|
|
|
locationService.go('api');
|
|
|
|
fixture.detectChanges();
|
2017-10-24 09:51:23 +01:00
|
|
|
expect(sidenav.opened).toBe(false);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should reopen when nav to market page and back to guide page', () => {
|
|
|
|
locationService.go('features');
|
|
|
|
fixture.detectChanges();
|
|
|
|
locationService.go('guide/bags');
|
|
|
|
fixture.detectChanges();
|
2017-10-24 09:51:23 +01:00
|
|
|
expect(sidenav.opened).toBe(true);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('SideNav when NOT side-by-side (narrow)', () => {
|
|
|
|
|
|
|
|
beforeEach(() => {
|
2017-05-24 23:08:21 -04:00
|
|
|
component.onResize(sideBySideBreakPoint - 1); // NOT side-by-side
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should be closed when nav to a guide page (guide/pipes)', () => {
|
|
|
|
locationService.go('guide/pipes');
|
2017-04-11 16:08:53 -07:00
|
|
|
fixture.detectChanges();
|
2017-10-24 09:51:23 +01:00
|
|
|
expect(sidenav.opened).toBe(false);
|
2017-04-11 16:08:53 -07:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should be closed when nav to an api page', () => {
|
|
|
|
locationService.go('api/a/b/c/d');
|
2017-04-11 16:08:53 -07:00
|
|
|
fixture.detectChanges();
|
2017-10-24 09:51:23 +01:00
|
|
|
expect(sidenav.opened).toBe(false);
|
2017-04-11 16:08:53 -07:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should be closed when nav to a marketing page (features)', () => {
|
2017-04-11 16:08:53 -07:00
|
|
|
locationService.go('features');
|
|
|
|
fixture.detectChanges();
|
2017-10-24 09:51:23 +01:00
|
|
|
expect(sidenav.opened).toBe(false);
|
2017-04-11 16:08:53 -07:00
|
|
|
});
|
2017-04-10 12:44:54 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('when manually opened', () => {
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
locationService.go('guide/pipes');
|
|
|
|
fixture.detectChanges();
|
|
|
|
hamburger.click();
|
|
|
|
fixture.detectChanges();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should be open', () => {
|
2017-10-24 09:51:23 +01:00
|
|
|
expect(sidenav.opened).toBe(true);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should close when click in gray content area overlay', () => {
|
2017-10-24 09:51:23 +01:00
|
|
|
const sidenavBackdrop = fixture.debugElement.query(By.css('.mat-drawer-backdrop')).nativeElement;
|
2017-05-19 01:52:37 -07:00
|
|
|
sidenavBackdrop.click();
|
|
|
|
fixture.detectChanges();
|
2017-11-27 23:06:09 +02:00
|
|
|
expect(sidenav.opened).toBe(false);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should close when nav to another guide page', () => {
|
|
|
|
locationService.go('guide/bags');
|
|
|
|
fixture.detectChanges();
|
2017-11-27 23:06:09 +02:00
|
|
|
expect(sidenav.opened).toBe(false);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should close when nav to api page', () => {
|
|
|
|
locationService.go('api');
|
|
|
|
fixture.detectChanges();
|
2017-11-27 23:06:09 +02:00
|
|
|
expect(sidenav.opened).toBe(false);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should close again when nav to market page', () => {
|
|
|
|
locationService.go('features');
|
|
|
|
fixture.detectChanges();
|
2017-11-27 23:06:09 +02:00
|
|
|
expect(sidenav.opened).toBe(false);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
2017-04-10 12:44:54 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
2017-04-10 12:44:54 -07:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('SideNav version selector', () => {
|
2017-06-06 10:09:46 +01:00
|
|
|
let selectElement: DebugElement;
|
|
|
|
let selectComponent: SelectComponent;
|
2017-07-26 20:24:59 +01:00
|
|
|
|
|
|
|
function setupSelectorForTesting(mode?: string) {
|
|
|
|
createTestingModule('a/b', mode);
|
|
|
|
initializeTest();
|
2017-05-24 23:08:21 -04:00
|
|
|
component.onResize(sideBySideBreakPoint + 1); // side-by-side
|
2017-06-06 10:09:46 +01:00
|
|
|
selectElement = fixture.debugElement.query(By.directive(SelectComponent));
|
|
|
|
selectComponent = selectElement.componentInstance;
|
2017-07-26 20:24:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
it('should select the version that matches the deploy mode', () => {
|
|
|
|
setupSelectorForTesting();
|
|
|
|
expect(selectComponent.selected.title).toContain('stable');
|
|
|
|
setupSelectorForTesting('next');
|
|
|
|
expect(selectComponent.selected.title).toContain('next');
|
|
|
|
setupSelectorForTesting('archive');
|
|
|
|
expect(selectComponent.selected.title).toContain('v4');
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
2017-04-10 12:44:54 -07:00
|
|
|
|
2017-07-26 20:24:59 +01:00
|
|
|
it('should add the current raw version string to the selected version', () => {
|
|
|
|
setupSelectorForTesting();
|
|
|
|
expect(selectComponent.selected.title).toContain(`(v${component.versionInfo.raw})`);
|
|
|
|
setupSelectorForTesting('next');
|
|
|
|
expect(selectComponent.selected.title).toContain(`(v${component.versionInfo.raw})`);
|
|
|
|
setupSelectorForTesting('archive');
|
|
|
|
expect(selectComponent.selected.title).toContain(`(v${component.versionInfo.raw})`);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
// Older docs versions have an href
|
2017-07-26 20:24:59 +01:00
|
|
|
it('should navigate when change to a version with a url', () => {
|
|
|
|
setupSelectorForTesting();
|
|
|
|
const versionWithUrlIndex = component.docVersions.findIndex(v => !!v.url);
|
|
|
|
const versionWithUrl = component.docVersions[versionWithUrlIndex];
|
|
|
|
selectElement.triggerEventHandler('change', { option: versionWithUrl, index: versionWithUrlIndex});
|
|
|
|
expect(locationService.go).toHaveBeenCalledWith(versionWithUrl.url);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
2017-04-10 12:44:54 -07:00
|
|
|
|
2017-07-26 20:24:59 +01:00
|
|
|
it('should not navigate when change to a version without a url', () => {
|
|
|
|
setupSelectorForTesting();
|
2017-08-12 01:51:59 +03:00
|
|
|
const versionWithoutUrlIndex = component.docVersions.length;
|
|
|
|
const versionWithoutUrl = component.docVersions[versionWithoutUrlIndex] = { title: 'foo', url: null };
|
|
|
|
selectElement.triggerEventHandler('change', { option: versionWithoutUrl, index: versionWithoutUrlIndex });
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(locationService.go).not.toHaveBeenCalled();
|
|
|
|
});
|
2017-03-29 14:13:40 -07:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('pageId', () => {
|
|
|
|
|
|
|
|
it('should set the id of the doc viewer container based on the current doc', () => {
|
|
|
|
const container = fixture.debugElement.query(By.css('section.sidenav-content'));
|
2017-04-11 16:08:53 -07:00
|
|
|
|
|
|
|
locationService.go('guide/pipes');
|
|
|
|
fixture.detectChanges();
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(component.pageId).toEqual('guide-pipes');
|
|
|
|
expect(container.properties['id']).toEqual('guide-pipes');
|
|
|
|
|
|
|
|
locationService.go('news');
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(component.pageId).toEqual('news');
|
|
|
|
expect(container.properties['id']).toEqual('news');
|
|
|
|
|
|
|
|
locationService.go('');
|
2017-04-11 16:08:53 -07:00
|
|
|
fixture.detectChanges();
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(component.pageId).toEqual('home');
|
|
|
|
expect(container.properties['id']).toEqual('home');
|
2017-04-11 16:08:53 -07:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should not be affected by changes to the query', () => {
|
|
|
|
const container = fixture.debugElement.query(By.css('section.sidenav-content'));
|
|
|
|
|
|
|
|
locationService.go('guide/pipes');
|
|
|
|
fixture.detectChanges();
|
|
|
|
|
|
|
|
locationService.go('guide/other?search=http');
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(component.pageId).toEqual('guide-other');
|
|
|
|
expect(container.properties['id']).toEqual('guide-other');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('hostClasses', () => {
|
2017-04-11 16:08:53 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should set the css classes of the host container based on the current doc and navigation view', () => {
|
|
|
|
locationService.go('guide/pipes');
|
2017-04-11 16:08:53 -07:00
|
|
|
fixture.detectChanges();
|
2017-05-19 01:52:37 -07:00
|
|
|
|
|
|
|
checkHostClass('page', 'guide-pipes');
|
|
|
|
checkHostClass('folder', 'guide');
|
|
|
|
checkHostClass('view', 'SideNav');
|
|
|
|
|
|
|
|
locationService.go('features');
|
|
|
|
fixture.detectChanges();
|
|
|
|
checkHostClass('page', 'features');
|
|
|
|
checkHostClass('folder', 'features');
|
|
|
|
checkHostClass('view', 'TopBar');
|
|
|
|
|
|
|
|
locationService.go('');
|
|
|
|
fixture.detectChanges();
|
|
|
|
checkHostClass('page', 'home');
|
|
|
|
checkHostClass('folder', 'home');
|
|
|
|
checkHostClass('view', '');
|
2017-04-11 16:08:53 -07:00
|
|
|
});
|
|
|
|
|
2017-11-24 15:18:09 +02:00
|
|
|
it('should set the css class of the host container based on the open/closed state of the side nav', async () => {
|
2017-05-19 01:52:37 -07:00
|
|
|
locationService.go('guide/pipes');
|
2017-04-11 16:08:53 -07:00
|
|
|
fixture.detectChanges();
|
2017-05-19 01:52:37 -07:00
|
|
|
checkHostClass('sidenav', 'open');
|
|
|
|
|
2017-10-24 09:51:23 +01:00
|
|
|
sidenav.close();
|
2017-11-24 15:18:09 +02:00
|
|
|
await waitForEmit(sidenav.onClose);
|
2017-05-19 01:52:37 -07:00
|
|
|
fixture.detectChanges();
|
|
|
|
checkHostClass('sidenav', 'closed');
|
|
|
|
|
2017-10-24 09:51:23 +01:00
|
|
|
sidenav.open();
|
2017-11-24 15:18:09 +02:00
|
|
|
await waitForEmit(sidenav.onOpen);
|
2017-05-19 01:52:37 -07:00
|
|
|
fixture.detectChanges();
|
|
|
|
checkHostClass('sidenav', 'open');
|
2017-11-24 15:18:09 +02:00
|
|
|
|
|
|
|
function waitForEmit(emitter: Observable<void>): Promise<void> {
|
|
|
|
return new Promise(resolve => {
|
|
|
|
emitter.subscribe(resolve);
|
|
|
|
fixture.detectChanges();
|
|
|
|
});
|
|
|
|
}
|
2017-04-11 16:08:53 -07:00
|
|
|
});
|
|
|
|
|
2017-07-26 18:36:00 +01:00
|
|
|
it('should set the css class of the host container based on the initial deployment mode', () => {
|
|
|
|
createTestingModule('a/b', 'archive');
|
|
|
|
initializeTest();
|
|
|
|
checkHostClass('mode', 'archive');
|
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
function checkHostClass(type, value) {
|
2017-07-26 18:36:00 +01:00
|
|
|
const host = fixture.debugElement;
|
2017-05-19 01:52:37 -07:00
|
|
|
const classes = host.properties['className'];
|
|
|
|
const classArray = classes.split(' ').filter(c => c.indexOf(`${type}-`) === 0);
|
|
|
|
expect(classArray.length).toBeLessThanOrEqual(1, `"${classes}" should have only one class matching ${type}-*`);
|
|
|
|
expect(classArray).toEqual([`${type}-${value}`], `"${classes}" should contain ${type}-${value}`);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('currentDocument', () => {
|
|
|
|
it('should display a guide page (guide/pipes)', () => {
|
|
|
|
locationService.go('guide/pipes');
|
|
|
|
fixture.detectChanges();
|
2017-06-18 12:29:48 +03:00
|
|
|
expect(docViewer.textContent).toMatch(/Pipes/i);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should display the api page', () => {
|
2017-04-11 16:08:53 -07:00
|
|
|
locationService.go('api');
|
|
|
|
fixture.detectChanges();
|
2017-06-18 12:29:48 +03:00
|
|
|
expect(docViewer.textContent).toMatch(/API/i);
|
2017-04-11 16:08:53 -07:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should display a marketing page', () => {
|
2017-04-11 16:08:53 -07:00
|
|
|
locationService.go('features');
|
|
|
|
fixture.detectChanges();
|
2017-06-18 12:29:48 +03:00
|
|
|
expect(docViewer.textContent).toMatch(/Features/i);
|
2017-04-11 16:08:53 -07:00
|
|
|
});
|
2017-04-01 09:58:19 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should update the document title', () => {
|
|
|
|
const titleService = TestBed.get(Title);
|
|
|
|
spyOn(titleService, 'setTitle');
|
|
|
|
locationService.go('guide/pipes');
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(titleService.setTitle).toHaveBeenCalledWith('Angular - Pipes');
|
|
|
|
});
|
2017-04-11 16:08:53 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should update the document title, with a default value if the document has no title', () => {
|
|
|
|
const titleService = TestBed.get(Title);
|
|
|
|
spyOn(titleService, 'setTitle');
|
|
|
|
locationService.go('no-title');
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(titleService.setTitle).toHaveBeenCalledWith('Angular');
|
|
|
|
});
|
2017-04-25 14:48:01 -07:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('auto-scrolling', () => {
|
|
|
|
const scrollDelay = 500;
|
|
|
|
let scrollService: ScrollService;
|
|
|
|
let scrollSpy: jasmine.Spy;
|
2017-11-27 23:06:09 +02:00
|
|
|
let scrollToTopSpy: jasmine.Spy;
|
2017-04-25 14:48:01 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
beforeEach(() => {
|
|
|
|
scrollService = fixture.debugElement.injector.get(ScrollService);
|
|
|
|
scrollSpy = spyOn(scrollService, 'scroll');
|
2017-11-27 23:06:09 +02:00
|
|
|
scrollToTopSpy = spyOn(scrollService, 'scrollToTop');
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
2017-04-25 14:48:01 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should not scroll immediately when the docId (path) changes', () => {
|
|
|
|
locationService.go('guide/pipes');
|
2017-11-27 23:06:09 +02:00
|
|
|
// deliberately not calling `fixture.detectChanges` because don't want `onDocInserted`
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(scrollSpy).not.toHaveBeenCalled();
|
2017-11-27 23:06:09 +02:00
|
|
|
expect(scrollToTopSpy).not.toHaveBeenCalled();
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
2017-04-25 14:48:01 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should scroll when just the hash changes (# alone)', () => {
|
|
|
|
locationService.go('guide/pipes');
|
|
|
|
locationService.go('guide/pipes#somewhere');
|
|
|
|
expect(scrollSpy).toHaveBeenCalled();
|
|
|
|
});
|
2017-04-01 09:58:19 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should scroll when just the hash changes (/#)', () => {
|
|
|
|
locationService.go('guide/pipes');
|
|
|
|
locationService.go('guide/pipes/#somewhere');
|
|
|
|
expect(scrollSpy).toHaveBeenCalled();
|
|
|
|
});
|
2017-04-01 09:58:19 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should scroll again when nav to the same hash twice in succession', () => {
|
|
|
|
locationService.go('guide/pipes');
|
|
|
|
locationService.go('guide/pipes#somewhere');
|
|
|
|
locationService.go('guide/pipes#somewhere');
|
|
|
|
expect(scrollSpy.calls.count()).toBe(2);
|
|
|
|
});
|
2017-04-01 09:58:19 +01:00
|
|
|
|
2017-05-26 02:43:34 +03:00
|
|
|
it('should scroll when nav to the same path', () => {
|
|
|
|
locationService.go('guide/pipes');
|
|
|
|
scrollSpy.calls.reset();
|
|
|
|
|
|
|
|
locationService.go('guide/pipes');
|
|
|
|
expect(scrollSpy).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
|
|
|
|
2017-11-27 23:06:09 +02:00
|
|
|
it('should scroll when re-nav to the empty path', () => {
|
2017-05-26 02:43:34 +03:00
|
|
|
locationService.go('');
|
|
|
|
scrollSpy.calls.reset();
|
|
|
|
|
|
|
|
locationService.go('');
|
|
|
|
expect(scrollSpy).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
|
|
|
|
2017-11-27 23:06:09 +02:00
|
|
|
it('should scroll to top when call `onDocRemoved` directly', () => {
|
|
|
|
scrollToTopSpy.calls.reset();
|
|
|
|
|
|
|
|
component.onDocRemoved();
|
|
|
|
expect(scrollToTopSpy).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should scroll after a delay when call `onDocInserted` directly', fakeAsync(() => {
|
|
|
|
component.onDocInserted();
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(scrollSpy).not.toHaveBeenCalled();
|
2017-11-27 23:06:09 +02:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(scrollDelay);
|
|
|
|
expect(scrollSpy).toHaveBeenCalled();
|
|
|
|
}));
|
2017-04-01 09:58:19 +01:00
|
|
|
|
2017-11-27 23:06:09 +02:00
|
|
|
it('should scroll (via `onDocInserted`) when finish navigating to a new doc', fakeAsync(() => {
|
|
|
|
expect(scrollToTopSpy).not.toHaveBeenCalled();
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
locationService.go('guide/pipes');
|
2017-11-27 23:06:09 +02:00
|
|
|
fixture.detectChanges(); // triggers the event that calls `onDocInserted`
|
|
|
|
expect(scrollToTopSpy).toHaveBeenCalled();
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(scrollSpy).not.toHaveBeenCalled();
|
2017-11-27 23:06:09 +02:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(scrollDelay);
|
|
|
|
expect(scrollSpy).toHaveBeenCalled();
|
|
|
|
}));
|
2017-04-01 09:58:19 +01:00
|
|
|
});
|
2017-04-02 10:14:57 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('click intercepting', () => {
|
|
|
|
it('should intercept clicks on anchors and call `location.handleAnchorClick()`',
|
|
|
|
inject([LocationService], (location: LocationService) => {
|
2017-04-02 10:14:57 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
const el = fixture.nativeElement as Element;
|
|
|
|
el.innerHTML = '<a href="some/local/url">click me</a>';
|
|
|
|
const anchorElement = el.getElementsByTagName('a')[0];
|
|
|
|
anchorElement.click();
|
|
|
|
expect(location.handleAnchorClick).toHaveBeenCalledWith(anchorElement, 0, false, false);
|
|
|
|
}));
|
2017-04-02 10:14:57 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should intercept clicks on elements deep within an anchor tag',
|
|
|
|
inject([LocationService], (location: LocationService) => {
|
2017-04-01 09:58:19 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
const el = fixture.nativeElement as Element;
|
|
|
|
el.innerHTML = '<a href="some/local/url"><div><img></div></a>';
|
|
|
|
const imageElement = el.getElementsByTagName('img')[0];
|
|
|
|
const anchorElement = el.getElementsByTagName('a')[0];
|
|
|
|
imageElement.click();
|
|
|
|
expect(location.handleAnchorClick).toHaveBeenCalledWith(anchorElement, 0, false, false);
|
|
|
|
}));
|
2017-05-05 10:02:33 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should ignore clicks on elements without an anchor ancestor',
|
|
|
|
inject([LocationService], (location: LocationService) => {
|
|
|
|
|
|
|
|
const el = fixture.nativeElement as Element;
|
|
|
|
el.innerHTML = '<div><p><div><img></div></p></div>';
|
|
|
|
const imageElement = el.getElementsByTagName('img')[0];
|
|
|
|
imageElement.click();
|
|
|
|
expect(location.handleAnchorClick).not.toHaveBeenCalled();
|
|
|
|
}));
|
2017-05-05 10:02:33 +01:00
|
|
|
});
|
2017-05-17 19:01:42 +01:00
|
|
|
|
2017-06-08 12:51:43 +03:00
|
|
|
describe('restrainScrolling()', () => {
|
|
|
|
const preventedScrolling = (currentTarget: object, deltaY: number) => {
|
|
|
|
const evt = {
|
|
|
|
deltaY,
|
|
|
|
currentTarget,
|
|
|
|
defaultPrevented: false,
|
|
|
|
preventDefault() { this.defaultPrevented = true; }
|
|
|
|
} as any as WheelEvent;
|
|
|
|
|
|
|
|
component.restrainScrolling(evt);
|
|
|
|
|
|
|
|
return evt.defaultPrevented;
|
|
|
|
};
|
|
|
|
|
|
|
|
it('should prevent scrolling up if already at the top', () => {
|
|
|
|
const elem = {scrollTop: 0};
|
|
|
|
|
|
|
|
expect(preventedScrolling(elem, -100)).toBe(true);
|
|
|
|
expect(preventedScrolling(elem, +100)).toBe(false);
|
|
|
|
expect(preventedScrolling(elem, -10)).toBe(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should prevent scrolling down if already at the bottom', () => {
|
|
|
|
const elem = {scrollTop: 100, scrollHeight: 150, clientHeight: 50};
|
|
|
|
|
|
|
|
expect(preventedScrolling(elem, +10)).toBe(true);
|
|
|
|
expect(preventedScrolling(elem, -10)).toBe(false);
|
|
|
|
expect(preventedScrolling(elem, +5)).toBe(true);
|
|
|
|
|
|
|
|
elem.clientHeight -= 10;
|
|
|
|
expect(preventedScrolling(elem, +5)).toBe(false);
|
|
|
|
|
|
|
|
elem.scrollHeight -= 20;
|
|
|
|
expect(preventedScrolling(elem, +5)).toBe(true);
|
|
|
|
|
|
|
|
elem.scrollTop -= 30;
|
|
|
|
expect(preventedScrolling(elem, +5)).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not prevent scrolling if neither at the top nor at the bottom', () => {
|
|
|
|
const elem = {scrollTop: 50, scrollHeight: 150, clientHeight: 50};
|
|
|
|
|
|
|
|
expect(preventedScrolling(elem, +100)).toBe(false);
|
|
|
|
expect(preventedScrolling(elem, -100)).toBe(false);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('aio-toc', () => {
|
|
|
|
let tocDebugElement: DebugElement;
|
|
|
|
let tocContainer: DebugElement;
|
2017-05-17 19:01:42 +01:00
|
|
|
|
2017-06-07 16:51:21 +03:00
|
|
|
const setHasFloatingToc = hasFloatingToc => {
|
|
|
|
component.hasFloatingToc = hasFloatingToc;
|
|
|
|
fixture.detectChanges();
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tocDebugElement = fixture.debugElement.query(By.directive(TocComponent));
|
2017-06-07 16:51:21 +03:00
|
|
|
tocContainer = tocDebugElement && tocDebugElement.parent;
|
|
|
|
};
|
2017-05-17 19:01:42 +01:00
|
|
|
|
2017-06-07 16:51:21 +03:00
|
|
|
beforeEach(() => setHasFloatingToc(true));
|
|
|
|
|
|
|
|
|
|
|
|
it('should show/hide `<aio-toc>` based on `hasFloatingToc`', () => {
|
|
|
|
expect(tocDebugElement).toBeTruthy();
|
|
|
|
expect(tocContainer).toBeTruthy();
|
|
|
|
|
|
|
|
setHasFloatingToc(false);
|
|
|
|
expect(tocDebugElement).toBeFalsy();
|
|
|
|
expect(tocContainer).toBeFalsy();
|
|
|
|
|
|
|
|
setHasFloatingToc(true);
|
|
|
|
expect(tocDebugElement).toBeTruthy();
|
|
|
|
expect(tocContainer).toBeTruthy();
|
|
|
|
});
|
2017-05-17 19:01:42 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should have a non-embedded `<aio-toc>` element', () => {
|
|
|
|
expect(tocDebugElement.classes['embedded']).toBeFalsy();
|
|
|
|
});
|
2017-05-17 19:01:42 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should update the TOC container\'s `maxHeight` based on `tocMaxHeight`', () => {
|
|
|
|
expect(tocContainer.styles['max-height']).toBeNull();
|
2017-05-05 10:02:33 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
component.tocMaxHeight = '100';
|
|
|
|
fixture.detectChanges();
|
2017-03-02 13:28:28 +00:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(tocContainer.styles['max-height']).toBe('100px');
|
|
|
|
});
|
2017-06-08 12:51:43 +03:00
|
|
|
|
|
|
|
it('should restrain scrolling inside the ToC container', () => {
|
|
|
|
const restrainScrolling = spyOn(component, 'restrainScrolling');
|
|
|
|
const evt = {};
|
|
|
|
|
|
|
|
expect(restrainScrolling).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
tocContainer.triggerEventHandler('mousewheel', evt);
|
|
|
|
expect(restrainScrolling).toHaveBeenCalledWith(evt);
|
|
|
|
});
|
2017-04-11 16:08:53 -07:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('footer', () => {
|
|
|
|
it('should have version number', () => {
|
|
|
|
const versionEl: HTMLElement = fixture.debugElement.query(By.css('aio-footer')).nativeElement;
|
2017-08-11 20:16:55 +03:00
|
|
|
expect(versionEl.textContent).toContain(TestHttpClient.versionInfo.full);
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
2017-04-11 16:08:53 -07:00
|
|
|
});
|
|
|
|
|
2017-07-26 18:36:00 +01:00
|
|
|
describe('deployment banner', () => {
|
|
|
|
it('should show a message if the deployment mode is "archive"', () => {
|
|
|
|
createTestingModule('a/b', 'archive');
|
|
|
|
initializeTest();
|
|
|
|
fixture.detectChanges();
|
|
|
|
const banner: HTMLElement = fixture.debugElement.query(By.css('aio-mode-banner')).nativeElement;
|
|
|
|
expect(banner.textContent).toContain('archived documentation for Angular v4');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should show no message if the deployment mode is not "archive"', () => {
|
|
|
|
createTestingModule('a/b', 'stable');
|
|
|
|
initializeTest();
|
|
|
|
fixture.detectChanges();
|
|
|
|
const banner: HTMLElement = fixture.debugElement.query(By.css('aio-mode-banner')).nativeElement;
|
|
|
|
expect(banner.textContent.trim()).toEqual('');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('search', () => {
|
|
|
|
describe('initialization', () => {
|
|
|
|
it('should initialize the search worker', inject([SearchService], (searchService: SearchService) => {
|
|
|
|
fixture.detectChanges(); // triggers ngOnInit
|
|
|
|
expect(searchService.initWorker).toHaveBeenCalled();
|
|
|
|
}));
|
|
|
|
});
|
2017-04-11 16:08:53 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('click handling', () => {
|
|
|
|
it('should intercept clicks not on the search elements and hide the search results', () => {
|
|
|
|
component.showSearchResults = true;
|
|
|
|
fixture.detectChanges();
|
|
|
|
// docViewer is a commonly-clicked, non-search element
|
|
|
|
docViewer.click();
|
|
|
|
expect(component.showSearchResults).toBe(false);
|
|
|
|
});
|
2017-04-19 09:56:39 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should not intercept clicks on the searchResults', () => {
|
|
|
|
component.showSearchResults = true;
|
|
|
|
fixture.detectChanges();
|
2017-03-02 13:28:28 +00:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
const searchResults = fixture.debugElement.query(By.directive(SearchResultsComponent));
|
|
|
|
searchResults.nativeElement.click();
|
|
|
|
fixture.detectChanges();
|
2017-04-24 14:34:31 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(component.showSearchResults).toBe(true);
|
|
|
|
});
|
2017-04-24 14:34:31 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should not intercept clicks om the searchBox', () => {
|
|
|
|
component.showSearchResults = true;
|
|
|
|
fixture.detectChanges();
|
2017-03-13 09:20:09 +00:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
const searchBox = fixture.debugElement.query(By.directive(SearchBoxComponent));
|
|
|
|
searchBox.nativeElement.click();
|
|
|
|
fixture.detectChanges();
|
2017-04-24 14:34:31 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(component.showSearchResults).toBe(true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('keyup handling', () => {
|
|
|
|
it('should grab focus when the / key is pressed', () => {
|
|
|
|
const searchBox: SearchBoxComponent = fixture.debugElement.query(By.directive(SearchBoxComponent)).componentInstance;
|
|
|
|
spyOn(searchBox, 'focus');
|
|
|
|
window.document.dispatchEvent(new KeyboardEvent('keyup', { 'key': '/' }));
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(searchBox.focus).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set focus back to the search box when the search results are displayed and the escape key is pressed', () => {
|
|
|
|
const searchBox: SearchBoxComponent = fixture.debugElement.query(By.directive(SearchBoxComponent)).componentInstance;
|
|
|
|
spyOn(searchBox, 'focus');
|
|
|
|
component.showSearchResults = true;
|
|
|
|
window.document.dispatchEvent(new KeyboardEvent('keyup', { 'key': 'Escape' }));
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(searchBox.focus).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|
2017-04-24 14:34:31 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('showing search results', () => {
|
|
|
|
it('should not display search results when query is empty', () => {
|
|
|
|
const searchService: MockSearchService = TestBed.get(SearchService);
|
|
|
|
searchService.searchResults.next({ query: '', results: [] });
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(component.showSearchResults).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should hide the results when a search result is selected', () => {
|
|
|
|
const searchService: MockSearchService = TestBed.get(SearchService);
|
|
|
|
|
|
|
|
const results = [
|
|
|
|
{ path: 'news', title: 'News', type: 'marketing', keywords: '', titleWords: '' }
|
|
|
|
];
|
|
|
|
|
|
|
|
searchService.searchResults.next({ query: 'something', results: results });
|
|
|
|
component.showSearchResults = true;
|
|
|
|
fixture.detectChanges();
|
|
|
|
|
|
|
|
const searchResultsComponent = fixture.debugElement.query(By.directive(SearchResultsComponent));
|
|
|
|
searchResultsComponent.triggerEventHandler('resultSelected', {});
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(component.showSearchResults).toBe(false);
|
|
|
|
});
|
2017-06-12 23:12:28 +01:00
|
|
|
|
|
|
|
it('should re-run the search when the search box regains focus', () => {
|
|
|
|
const doSearchSpy = spyOn(component, 'doSearch');
|
|
|
|
const searchBox = fixture.debugElement.query(By.directive(SearchBoxComponent));
|
|
|
|
searchBox.triggerEventHandler('onFocus', 'some query');
|
|
|
|
expect(doSearchSpy).toHaveBeenCalledWith('some query');
|
|
|
|
});
|
2017-05-19 01:52:37 -07:00
|
|
|
});
|
2017-04-24 14:34:31 -07:00
|
|
|
});
|
|
|
|
|
2017-07-26 18:30:38 +01:00
|
|
|
describe('archive redirection', () => {
|
|
|
|
it('should redirect to `docs` if deployment mode is `archive` and not at a docs page', () => {
|
|
|
|
createTestingModule('', 'archive');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
|
|
|
|
|
|
|
|
createTestingModule('resources', 'archive');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
|
|
|
|
|
|
|
|
createTestingModule('guide/aot-compiler', 'archive');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('tutorial', 'archive');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('tutorial/toh-pt1', 'archive');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('docs', 'archive');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('api', 'archive');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
2017-08-19 11:02:02 +01:00
|
|
|
|
|
|
|
createTestingModule('api/core/getPlatform', 'archive');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
2017-07-26 18:30:38 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should redirect to `docs` if deployment mode is `next` and not at a docs page', () => {
|
|
|
|
createTestingModule('', 'next');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
|
|
|
|
|
|
|
|
createTestingModule('resources', 'next');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
|
|
|
|
|
|
|
|
createTestingModule('guide/aot-compiler', 'next');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('tutorial', 'next');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('tutorial/toh-pt1', 'next');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('docs', 'next');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('api', 'next');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
2017-08-19 11:02:02 +01:00
|
|
|
|
|
|
|
createTestingModule('api/core/getPlatform', 'next');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
2017-07-26 18:30:38 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should not redirect to `docs` if deployment mode is `stable` and not at a docs page', () => {
|
|
|
|
createTestingModule('', 'stable');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('resources', 'stable');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('guide/aot-compiler', 'stable');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('tutorial', 'stable');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('tutorial/toh-pt1', 'stable');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('docs', 'stable');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
createTestingModule('api', 'stable');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
2017-08-19 11:02:02 +01:00
|
|
|
|
|
|
|
createTestingModule('api/core/getPlatform', 'stable');
|
|
|
|
initializeTest();
|
|
|
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
2017-07-26 18:30:38 +01:00
|
|
|
});
|
|
|
|
});
|
2017-03-13 09:20:09 +00:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('with mocked DocViewer', () => {
|
|
|
|
const getDocViewer = () => fixture.debugElement.query(By.css('aio-doc-viewer'));
|
2017-11-27 23:06:09 +02:00
|
|
|
const triggerDocReady = () => getDocViewer().triggerEventHandler('docReady', undefined);
|
2017-05-19 01:52:37 -07:00
|
|
|
|
2017-05-15 10:44:06 -07:00
|
|
|
beforeEach(() => {
|
2017-04-25 11:04:25 +01:00
|
|
|
createTestingModule('a/b');
|
|
|
|
// Remove the DocViewer for this test and hide the missing component message
|
|
|
|
TestBed.overrideModule(AppModule, {
|
|
|
|
remove: { declarations: [DocViewerComponent] },
|
|
|
|
add: { schemas: [NO_ERRORS_SCHEMA] }
|
|
|
|
});
|
2017-05-15 10:44:06 -07:00
|
|
|
});
|
2017-04-25 11:04:25 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('initial rendering', () => {
|
2017-11-27 23:06:09 +02:00
|
|
|
it('should initially add the starting class until the first document is ready', fakeAsync(() => {
|
2017-10-13 13:02:27 -07:00
|
|
|
const getSidenavContainer = () => fixture.debugElement.query(By.css('mat-sidenav-container'));
|
2017-04-25 11:04:25 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
initializeTest();
|
2017-04-25 11:04:25 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(component.isStarting).toBe(true);
|
|
|
|
expect(getSidenavContainer().classes['starting']).toBe(true);
|
2017-04-25 11:04:25 +01:00
|
|
|
|
2017-11-27 23:06:09 +02:00
|
|
|
triggerDocReady();
|
2017-05-19 01:52:37 -07:00
|
|
|
fixture.detectChanges();
|
|
|
|
expect(component.isStarting).toBe(true);
|
|
|
|
expect(getSidenavContainer().classes['starting']).toBe(true);
|
2017-03-29 14:13:40 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(499);
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(component.isStarting).toBe(true);
|
|
|
|
expect(getSidenavContainer().classes['starting']).toBe(true);
|
2017-05-02 10:13:10 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(2);
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(component.isStarting).toBe(false);
|
|
|
|
expect(getSidenavContainer().classes['starting']).toBe(false);
|
|
|
|
}));
|
2017-05-02 10:13:10 -07:00
|
|
|
});
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
describe('progress bar', () => {
|
|
|
|
const SHOW_DELAY = 200;
|
|
|
|
const HIDE_DELAY = 500;
|
2017-10-13 13:02:27 -07:00
|
|
|
const getProgressBar = () => fixture.debugElement.query(By.directive(MatProgressBar));
|
2017-05-19 01:52:37 -07:00
|
|
|
const initializeAndCompleteNavigation = () => {
|
|
|
|
initializeTest();
|
2017-11-27 23:06:09 +02:00
|
|
|
triggerDocReady();
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(HIDE_DELAY);
|
|
|
|
};
|
2017-05-02 10:13:10 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should initially be hidden', () => {
|
|
|
|
initializeTest();
|
|
|
|
expect(getProgressBar()).toBeFalsy();
|
|
|
|
});
|
2017-05-02 10:13:10 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should be shown (after a delay) when the path changes', fakeAsync(() => {
|
|
|
|
initializeAndCompleteNavigation();
|
|
|
|
locationService.urlSubject.next('c/d');
|
2017-05-02 10:13:10 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
fixture.detectChanges();
|
|
|
|
expect(getProgressBar()).toBeFalsy();
|
2017-05-02 10:13:10 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(SHOW_DELAY - 1);
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(getProgressBar()).toBeFalsy();
|
2017-03-29 14:13:40 -07:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(1);
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(getProgressBar()).toBeTruthy();
|
2017-05-13 15:07:25 +01:00
|
|
|
}));
|
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should not be shown when the URL changes but the path remains the same', fakeAsync(() => {
|
|
|
|
initializeAndCompleteNavigation();
|
|
|
|
locationService.urlSubject.next('a/b');
|
2017-05-13 15:07:25 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(SHOW_DELAY);
|
2017-05-13 15:07:25 +01:00
|
|
|
fixture.detectChanges();
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(getProgressBar()).toBeFalsy();
|
|
|
|
}));
|
2017-05-13 15:07:25 +01:00
|
|
|
|
2017-05-26 02:43:34 +03:00
|
|
|
it('should not be shown when re-navigating to the empty path', fakeAsync(() => {
|
|
|
|
initializeAndCompleteNavigation();
|
|
|
|
locationService.urlSubject.next('');
|
2017-11-27 23:06:09 +02:00
|
|
|
triggerDocReady();
|
2017-05-26 02:43:34 +03:00
|
|
|
|
|
|
|
locationService.urlSubject.next('');
|
|
|
|
|
|
|
|
tick(SHOW_DELAY);
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(getProgressBar()).toBeFalsy();
|
|
|
|
|
|
|
|
tick(HIDE_DELAY); // Fire the remaining timer or `fakeAsync()` complains.
|
|
|
|
}));
|
|
|
|
|
2017-11-27 23:06:09 +02:00
|
|
|
it('should not be shown if the doc is prepared quickly', fakeAsync(() => {
|
2017-05-19 01:52:37 -07:00
|
|
|
initializeAndCompleteNavigation();
|
|
|
|
locationService.urlSubject.next('c/d');
|
2017-05-13 15:07:25 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(SHOW_DELAY - 1);
|
2017-11-27 23:06:09 +02:00
|
|
|
triggerDocReady();
|
2017-05-13 15:07:25 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(1);
|
2017-05-13 15:07:25 +01:00
|
|
|
fixture.detectChanges();
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(getProgressBar()).toBeFalsy();
|
|
|
|
|
|
|
|
tick(HIDE_DELAY); // Fire the remaining timer or `fakeAsync()` complains.
|
|
|
|
}));
|
|
|
|
|
2017-11-27 23:06:09 +02:00
|
|
|
it('should be shown if preparing the doc takes too long', fakeAsync(() => {
|
2017-05-19 01:52:37 -07:00
|
|
|
initializeAndCompleteNavigation();
|
|
|
|
locationService.urlSubject.next('c/d');
|
|
|
|
|
|
|
|
tick(SHOW_DELAY);
|
2017-11-27 23:06:09 +02:00
|
|
|
triggerDocReady();
|
2017-05-13 15:07:25 +01:00
|
|
|
|
|
|
|
fixture.detectChanges();
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(getProgressBar()).toBeTruthy();
|
2017-05-13 15:07:25 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(HIDE_DELAY); // Fire the remaining timer or `fakeAsync()` complains.
|
|
|
|
}));
|
|
|
|
|
2017-11-27 23:06:09 +02:00
|
|
|
it('should be hidden (after a delay) once the doc has been prepared', fakeAsync(() => {
|
2017-05-19 01:52:37 -07:00
|
|
|
initializeAndCompleteNavigation();
|
|
|
|
locationService.urlSubject.next('c/d');
|
|
|
|
|
|
|
|
tick(SHOW_DELAY);
|
2017-11-27 23:06:09 +02:00
|
|
|
triggerDocReady();
|
2017-05-13 15:07:25 +01:00
|
|
|
|
|
|
|
fixture.detectChanges();
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(getProgressBar()).toBeTruthy();
|
2017-05-12 15:04:28 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(HIDE_DELAY - 1);
|
2017-05-12 15:04:28 +01:00
|
|
|
fixture.detectChanges();
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(getProgressBar()).toBeTruthy();
|
2017-05-13 15:07:25 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(1);
|
2017-05-13 15:07:25 +01:00
|
|
|
fixture.detectChanges();
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(getProgressBar()).toBeFalsy();
|
|
|
|
}));
|
2017-05-13 15:07:25 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
it('should only take the latest request into account', fakeAsync(() => {
|
|
|
|
initializeAndCompleteNavigation();
|
|
|
|
locationService.urlSubject.next('c/d'); // The URL changes.
|
2017-11-27 23:06:09 +02:00
|
|
|
locationService.urlSubject.next('e/f'); // The URL changes again before `onDocReady()`.
|
2017-05-13 15:07:25 +01:00
|
|
|
|
2017-11-27 23:06:09 +02:00
|
|
|
tick(SHOW_DELAY - 1); // `onDocReady()` is triggered (for the last doc),
|
|
|
|
triggerDocReady(); // before the progress bar is shown.
|
2017-05-13 15:07:25 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(1);
|
2017-05-13 15:07:25 +01:00
|
|
|
fixture.detectChanges();
|
2017-05-19 01:52:37 -07:00
|
|
|
expect(getProgressBar()).toBeFalsy();
|
2017-05-13 15:07:25 +01:00
|
|
|
|
2017-05-19 01:52:37 -07:00
|
|
|
tick(HIDE_DELAY); // Fire the remaining timer or `fakeAsync()` complains.
|
|
|
|
}));
|
2017-05-13 15:07:25 +01:00
|
|
|
});
|
2017-05-19 01:52:37 -07:00
|
|
|
|
2017-05-13 15:07:25 +01:00
|
|
|
});
|
|
|
|
|
2017-02-02 23:02:23 -08:00
|
|
|
});
|
2017-03-13 18:08:23 -07:00
|
|
|
|
2017-04-11 16:08:53 -07:00
|
|
|
//// test helpers ////
|
|
|
|
|
2017-07-26 18:36:00 +01:00
|
|
|
function createTestingModule(initialUrl: string, mode: string = 'stable') {
|
2017-07-26 22:36:25 +01:00
|
|
|
const mockLocationService = new MockLocationService(initialUrl);
|
2017-04-25 11:04:25 +01:00
|
|
|
TestBed.resetTestingModule();
|
|
|
|
TestBed.configureTestingModule({
|
|
|
|
imports: [ AppModule ],
|
|
|
|
providers: [
|
|
|
|
{ provide: APP_BASE_HREF, useValue: '/' },
|
2017-07-31 15:45:18 +03:00
|
|
|
{ provide: EmbedComponentsService, useClass: TestEmbedComponentsService },
|
2017-04-25 11:04:25 +01:00
|
|
|
{ provide: GaService, useClass: TestGaService },
|
2017-08-11 20:16:55 +03:00
|
|
|
{ provide: HttpClient, useClass: TestHttpClient },
|
2017-07-26 22:36:25 +01:00
|
|
|
{ provide: LocationService, useFactory: () => mockLocationService },
|
2017-04-25 11:04:25 +01:00
|
|
|
{ provide: Logger, useClass: MockLogger },
|
|
|
|
{ provide: SearchService, useClass: MockSearchService },
|
2017-07-26 18:36:00 +01:00
|
|
|
{ provide: Deployment, useFactory: () => {
|
2017-07-26 22:36:25 +01:00
|
|
|
const deployment = new Deployment(mockLocationService as any);
|
2017-07-26 18:36:00 +01:00
|
|
|
deployment.mode = mode;
|
|
|
|
return deployment;
|
|
|
|
}},
|
2017-04-25 11:04:25 +01:00
|
|
|
]
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-07-31 15:45:18 +03:00
|
|
|
class TestEmbedComponentsService {
|
|
|
|
embedInto = jasmine.createSpy('embedInto').and.returnValue(of([]));
|
|
|
|
}
|
|
|
|
|
2017-03-13 18:08:23 -07:00
|
|
|
class TestGaService {
|
|
|
|
locationChanged = jasmine.createSpy('locationChanged');
|
|
|
|
}
|
2017-03-29 14:13:40 -07:00
|
|
|
|
2017-08-11 20:16:55 +03:00
|
|
|
class TestHttpClient {
|
2017-07-26 20:24:59 +01:00
|
|
|
|
|
|
|
static versionInfo = {
|
|
|
|
raw: '4.0.0-rc.6',
|
|
|
|
major: 4,
|
|
|
|
minor: 0,
|
|
|
|
patch: 0,
|
|
|
|
prerelease: [ 'local' ],
|
|
|
|
build: 'sha.73808dd',
|
|
|
|
version: '4.0.0-local',
|
|
|
|
codeName: 'snapshot',
|
|
|
|
isSnapshot: true,
|
|
|
|
full: '4.0.0-local+sha.73808dd',
|
|
|
|
branch: 'master',
|
|
|
|
commitSHA: '73808dd38b5ccd729404936834d1568bd066de81'
|
|
|
|
};
|
2017-03-29 14:13:40 -07:00
|
|
|
|
2017-04-25 14:48:01 -07:00
|
|
|
static docVersions: NavigationNode[] = [
|
|
|
|
{ title: 'v2', url: 'https://v2.angular.io' }
|
|
|
|
];
|
|
|
|
|
2017-03-29 14:13:40 -07:00
|
|
|
// tslint:disable:quotemark
|
|
|
|
navJson = {
|
|
|
|
"TopBar": [
|
|
|
|
{
|
|
|
|
"url": "features",
|
|
|
|
"title": "Features"
|
2017-04-27 15:32:46 -07:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"url": "no-title",
|
|
|
|
"title": "No Title"
|
|
|
|
},
|
2017-03-29 14:13:40 -07:00
|
|
|
],
|
|
|
|
"SideNav": [
|
|
|
|
{
|
|
|
|
"title": "Core",
|
|
|
|
"tooltip": "Learn the core capabilities of Angular",
|
|
|
|
"children": [
|
|
|
|
{
|
|
|
|
"url": "guide/pipes",
|
|
|
|
"title": "Pipes",
|
|
|
|
"tooltip": "Pipes transform displayed values within a template."
|
2017-04-11 16:08:53 -07:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"url": "guide/bags",
|
|
|
|
"title": "Bags",
|
|
|
|
"tooltip": "Pack your bags for a code adventure."
|
2017-04-27 15:32:46 -07:00
|
|
|
}
|
2017-03-29 14:13:40 -07:00
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"url": "api",
|
|
|
|
"title": "API",
|
|
|
|
"tooltip": "Details of the Angular classes and values."
|
|
|
|
}
|
|
|
|
],
|
2017-08-11 20:16:55 +03:00
|
|
|
"docVersions": TestHttpClient.docVersions,
|
2017-04-25 14:48:01 -07:00
|
|
|
|
2017-08-11 20:16:55 +03:00
|
|
|
"__versionInfo": TestHttpClient.versionInfo,
|
2017-03-29 14:13:40 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
get(url: string) {
|
2017-04-20 14:16:36 +01:00
|
|
|
let data;
|
|
|
|
if (/navigation\.json/.test(url)) {
|
|
|
|
data = this.navJson;
|
|
|
|
} else {
|
2017-05-03 13:55:00 +01:00
|
|
|
const match = /generated\/docs\/(.+)\.json/.exec(url);
|
2017-04-20 14:16:36 +01:00
|
|
|
const id = match[1];
|
2017-04-27 15:32:46 -07:00
|
|
|
// Make up a title for test purposes
|
2017-04-20 14:16:36 +01:00
|
|
|
const title = id.split('/').pop().replace(/^([a-z])/, (_, letter) => letter.toUpperCase());
|
2017-04-27 15:32:46 -07:00
|
|
|
const h1 = (id === 'no-title') ? '' : `<h1>${title}</h1>`;
|
|
|
|
const contents = `${h1}<h2 id="#somewhere">Some heading</h2>`;
|
|
|
|
data = { id, contents };
|
2017-04-20 14:16:36 +01:00
|
|
|
}
|
2017-08-11 20:16:55 +03:00
|
|
|
return of(data);
|
2017-03-29 14:13:40 -07:00
|
|
|
}
|
|
|
|
}
|