fix(docs-infra): update app code to work with Ivy (#28530)

This commit also enables more tests to be run on CI with Ivy.

PR Close #28530
This commit is contained in:
George Kalpakas 2019-05-01 02:24:13 +03:00 committed by Kara Erickson
parent 066ec33342
commit b70d20b510
8 changed files with 160 additions and 144 deletions

View File

@ -292,11 +292,21 @@ jobs:
test_aio_local_ivy: test_aio_local_ivy:
<<: *job_defaults <<: *job_defaults
docker:
# Needed because the AIO tests and the PWA score test depend on Chrome being available.
- image: *browsers_docker_image
steps: steps:
- *attach_workspace - *attach_workspace
- *init_environment - *init_environment
# Build aio with Ivy (using local Angular packages) # Build aio with Ivy (using local Angular packages)
- run: yarn --cwd aio build-with-ivy --progress=false - run: yarn --cwd aio build-with-ivy --progress=false
# Run PWA-score tests
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
# Run unit tests
- run: yarn --cwd aio test --progress=false --watch=false
# Run e2e tests
- run: yarn --cwd aio e2e --configuration=ci
test_aio_tools: test_aio_tools:
<<: *job_defaults <<: *job_defaults

View File

@ -33,7 +33,7 @@ function _main() {
const oldTsConfigStr = readFileSync(tsConfigPath, 'utf8'); const oldTsConfigStr = readFileSync(tsConfigPath, 'utf8');
const oldTsConfigObj = parse(oldTsConfigStr); const oldTsConfigObj = parse(oldTsConfigStr);
const newTsConfigObj = extend(true, oldTsConfigObj, NG_COMPILER_OPTS); const newTsConfigObj = extend(true, oldTsConfigObj, NG_COMPILER_OPTS);
const newTsConfigStr = JSON.stringify(newTsConfigObj, null, 2); const newTsConfigStr = `${JSON.stringify(newTsConfigObj, null, 2)}\n`;
console.log(`\nNew config: ${newTsConfigStr}`); console.log(`\nNew config: ${newTsConfigStr}`);
writeFileSync(tsConfigPath, newTsConfigStr); writeFileSync(tsConfigPath, newTsConfigStr);

View File

@ -23,10 +23,10 @@ describe('CodeExampleComponent', () => {
}); });
fixture = TestBed.createComponent(HostComponent); fixture = TestBed.createComponent(HostComponent);
fixture.detectChanges();
hostComponent = fixture.componentInstance; hostComponent = fixture.componentInstance;
codeExampleComponent = hostComponent.codeExampleComponent; codeExampleComponent = hostComponent.codeExampleComponent;
fixture.detectChanges();
}); });
it('should be able to capture the code snippet provided in content', () => { it('should be able to capture the code snippet provided in content', () => {

View File

@ -23,10 +23,10 @@ describe('CodeTabsComponent', () => {
}); });
fixture = TestBed.createComponent(HostComponent); fixture = TestBed.createComponent(HostComponent);
fixture.detectChanges();
hostComponent = fixture.componentInstance; hostComponent = fixture.componentInstance;
codeTabsComponent = hostComponent.codeTabsComponent; codeTabsComponent = hostComponent.codeTabsComponent;
fixture.detectChanges();
}); });
it('should get correct tab info', () => { it('should get correct tab info', () => {

View File

@ -63,178 +63,182 @@ describe('TocComponent', () => {
expect(tocComponent.type).toEqual('None'); expect(tocComponent.type).toEqual('None');
}); });
it('should not display anything when no h2 or h3 TocItems', () => { describe('(once the lifecycle hooks have run)', () => {
tocService.tocList.next([tocItem('H1', 'h1')]); beforeEach(() => fixture.detectChanges());
fixture.detectChanges();
expect(tocComponentDe.children.length).toEqual(0);
});
it('should update when the TocItems are updated', () => { it('should not display anything when no h2 or h3 TocItems', () => {
tocService.tocList.next([tocItem('Heading A')]); tocService.tocList.next([tocItem('H1', 'h1')]);
fixture.detectChanges();
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
tocService.tocList.next([tocItem('Heading A'), tocItem('Heading B'), tocItem('Heading C')]);
fixture.detectChanges();
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(3);
});
it('should only display H2 and H3 TocItems', () => {
tocService.tocList.next([tocItem('Heading A', 'h1'), tocItem('Heading B'), tocItem('Heading C', 'h3')]);
fixture.detectChanges();
const tocItems = tocComponentDe.queryAll(By.css('li'));
const textContents = tocItems.map(item => item.nativeNode.textContent.trim());
expect(tocItems.length).toBe(2);
expect(textContents.find(text => text === 'Heading A')).toBeFalsy();
expect(textContents.find(text => text === 'Heading B')).toBeTruthy();
expect(textContents.find(text => text === 'Heading C')).toBeTruthy();
expect(setPage().tocH1Heading).toBeFalsy();
});
it('should stop listening for TocItems once destroyed', () => {
tocService.tocList.next([tocItem('Heading A')]);
fixture.detectChanges();
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
tocComponent.ngOnDestroy();
tocService.tocList.next([tocItem('Heading A', 'h1'), tocItem('Heading B'), tocItem('Heading C')]);
fixture.detectChanges();
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
});
describe('when fewer than `maxPrimary` TocItems', () => {
beforeEach(() => {
tocService.tocList.next([tocItem('Heading A'), tocItem('Heading B'), tocItem('Heading C'), tocItem('Heading D')]);
fixture.detectChanges(); fixture.detectChanges();
page = setPage(); expect(tocComponentDe.children.length).toEqual(0);
}); });
it('should have four displayed items', () => { it('should update when the TocItems are updated', () => {
expect(page.listItems.length).toEqual(4); tocService.tocList.next([tocItem('Heading A')]);
});
it('should not have secondary items', () => {
expect(tocComponent.type).toEqual('EmbeddedSimple');
const aSecond = page.listItems.find(item => item.classes.secondary);
expect(aSecond).toBeFalsy('should not find a secondary');
});
it('should not display expando buttons', () => {
expect(page.tocHeadingButtonEmbedded).toBeFalsy('top expand/collapse button');
expect(page.tocMoreButton).toBeFalsy('bottom more button');
});
});
describe('when many TocItems', () => {
let scrollToTopSpy: jasmine.Spy;
beforeEach(() => {
fixture.detectChanges(); fixture.detectChanges();
page = setPage(); expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
scrollToTopSpy = TestBed.get(ScrollService).scrollToTop;
tocService.tocList.next([tocItem('Heading A'), tocItem('Heading B'), tocItem('Heading C')]);
fixture.detectChanges();
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(3);
}); });
it('should have more than 4 displayed items', () => { it('should only display H2 and H3 TocItems', () => {
expect(page.listItems.length).toBeGreaterThan(4); tocService.tocList.next([tocItem('Heading A', 'h1'), tocItem('Heading B'), tocItem('Heading C', 'h3')]);
fixture.detectChanges();
const tocItems = tocComponentDe.queryAll(By.css('li'));
const textContents = tocItems.map(item => item.nativeNode.textContent.trim());
expect(tocItems.length).toBe(2);
expect(textContents.find(text => text === 'Heading A')).toBeFalsy();
expect(textContents.find(text => text === 'Heading B')).toBeTruthy();
expect(textContents.find(text => text === 'Heading C')).toBeTruthy();
expect(setPage().tocH1Heading).toBeFalsy();
}); });
it('should not display the h1 item', () => { it('should stop listening for TocItems once destroyed', () => {
expect(page.listItems.find(item => item.classes.h1)).toBeFalsy('should not find h1 item'); tocService.tocList.next([tocItem('Heading A')]);
fixture.detectChanges();
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
tocComponent.ngOnDestroy();
tocService.tocList.next([tocItem('Heading A', 'h1'), tocItem('Heading B'), tocItem('Heading C')]);
fixture.detectChanges();
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
}); });
it('should be in "collapsed" (not expanded) state at the start', () => { describe('when fewer than `maxPrimary` TocItems', () => {
expect(tocComponent.isCollapsed).toBeTruthy();
});
it('should have "collapsed" class at the start', () => {
expect(tocComponentDe.children[0].classes.collapsed).toEqual(true);
});
it('should display expando buttons', () => {
expect(page.tocHeadingButtonEmbedded).toBeTruthy('top expand/collapse button');
expect(page.tocMoreButton).toBeTruthy('bottom more button');
});
it('should have secondary items', () => {
expect(tocComponent.type).toEqual('EmbeddedExpandable');
});
// CSS will hide items with the secondary class when collapsed
it('should have secondary item with a secondary class', () => {
const aSecondary = page.listItems.find(item => item.classes.secondary);
expect(aSecondary).toBeTruthy('should find a secondary');
});
describe('after click tocHeading button', () => {
beforeEach(() => { beforeEach(() => {
page.tocHeadingButtonEmbedded.nativeElement.click(); tocService.tocList.next([tocItem('Heading A'), tocItem('Heading B'), tocItem('Heading C'), tocItem('Heading D')]);
fixture.detectChanges(); fixture.detectChanges();
page = setPage();
}); });
it('should not be "collapsed"', () => { it('should have four displayed items', () => {
expect(tocComponent.isCollapsed).toEqual(false); expect(page.listItems.length).toEqual(4);
}); });
it('should not have "collapsed" class', () => { it('should not have secondary items', () => {
expect(tocComponentDe.children[0].classes.collapsed).toBeFalsy(); expect(tocComponent.type).toEqual('EmbeddedSimple');
const aSecond = page.listItems.find(item => item.classes.secondary);
expect(aSecond).toBeFalsy('should not find a secondary');
}); });
it('should not scroll', () => { it('should not display expando buttons', () => {
expect(scrollToTopSpy).not.toHaveBeenCalled(); expect(page.tocHeadingButtonEmbedded).toBeFalsy('top expand/collapse button');
}); expect(page.tocMoreButton).toBeFalsy('bottom more button');
it('should be "collapsed" after clicking again', () => {
page.tocHeadingButtonEmbedded.nativeElement.click();
fixture.detectChanges();
expect(tocComponent.isCollapsed).toEqual(true);
});
it('should not scroll after clicking again', () => {
page.tocHeadingButtonEmbedded.nativeElement.click();
fixture.detectChanges();
expect(scrollToTopSpy).not.toHaveBeenCalled();
}); });
}); });
describe('after click tocMore button', () => { describe('when many TocItems', () => {
let scrollToTopSpy: jasmine.Spy;
beforeEach(() => { beforeEach(() => {
page.tocMoreButton.nativeElement.click();
fixture.detectChanges(); fixture.detectChanges();
page = setPage();
scrollToTopSpy = TestBed.get(ScrollService).scrollToTop;
}); });
it('should not be "collapsed"', () => { it('should have more than 4 displayed items', () => {
expect(tocComponent.isCollapsed).toEqual(false); expect(page.listItems.length).toBeGreaterThan(4);
}); });
it('should not have "collapsed" class', () => { it('should not display the h1 item', () => {
expect(tocComponentDe.children[0].classes.collapsed).toBeFalsy(); expect(page.listItems.find(item => item.classes.h1)).toBeFalsy('should not find h1 item');
}); });
it('should not scroll', () => { it('should be in "collapsed" (not expanded) state at the start', () => {
expect(scrollToTopSpy).not.toHaveBeenCalled(); expect(tocComponent.isCollapsed).toBeTruthy();
}); });
it('should be "collapsed" after clicking again', () => { it('should have "collapsed" class at the start', () => {
page.tocMoreButton.nativeElement.click(); expect(tocComponentDe.children[0].classes.collapsed).toEqual(true);
fixture.detectChanges();
expect(tocComponent.isCollapsed).toEqual(true);
}); });
it('should be "collapsed" after clicking tocHeadingButton', () => { it('should display expando buttons', () => {
page.tocMoreButton.nativeElement.click(); expect(page.tocHeadingButtonEmbedded).toBeTruthy('top expand/collapse button');
fixture.detectChanges(); expect(page.tocMoreButton).toBeTruthy('bottom more button');
expect(tocComponent.isCollapsed).toEqual(true);
}); });
it('should scroll after clicking again', () => { it('should have secondary items', () => {
page.tocMoreButton.nativeElement.click(); expect(tocComponent.type).toEqual('EmbeddedExpandable');
fixture.detectChanges(); });
expect(scrollToTopSpy).toHaveBeenCalled();
// CSS will hide items with the secondary class when collapsed
it('should have secondary item with a secondary class', () => {
const aSecondary = page.listItems.find(item => item.classes.secondary);
expect(aSecondary).toBeTruthy('should find a secondary');
});
describe('after click tocHeading button', () => {
beforeEach(() => {
page.tocHeadingButtonEmbedded.nativeElement.click();
fixture.detectChanges();
});
it('should not be "collapsed"', () => {
expect(tocComponent.isCollapsed).toEqual(false);
});
it('should not have "collapsed" class', () => {
expect(tocComponentDe.children[0].classes.collapsed).toBeFalsy();
});
it('should not scroll', () => {
expect(scrollToTopSpy).not.toHaveBeenCalled();
});
it('should be "collapsed" after clicking again', () => {
page.tocHeadingButtonEmbedded.nativeElement.click();
fixture.detectChanges();
expect(tocComponent.isCollapsed).toEqual(true);
});
it('should not scroll after clicking again', () => {
page.tocHeadingButtonEmbedded.nativeElement.click();
fixture.detectChanges();
expect(scrollToTopSpy).not.toHaveBeenCalled();
});
});
describe('after click tocMore button', () => {
beforeEach(() => {
page.tocMoreButton.nativeElement.click();
fixture.detectChanges();
});
it('should not be "collapsed"', () => {
expect(tocComponent.isCollapsed).toEqual(false);
});
it('should not have "collapsed" class', () => {
expect(tocComponentDe.children[0].classes.collapsed).toBeFalsy();
});
it('should not scroll', () => {
expect(scrollToTopSpy).not.toHaveBeenCalled();
});
it('should be "collapsed" after clicking again', () => {
page.tocMoreButton.nativeElement.click();
fixture.detectChanges();
expect(tocComponent.isCollapsed).toEqual(true);
});
it('should be "collapsed" after clicking tocHeadingButton', () => {
page.tocMoreButton.nativeElement.click();
fixture.detectChanges();
expect(tocComponent.isCollapsed).toEqual(true);
});
it('should scroll after clicking again', () => {
page.tocMoreButton.nativeElement.click();
fixture.detectChanges();
expect(scrollToTopSpy).toHaveBeenCalled();
});
}); });
}); });
}); });

View File

@ -38,7 +38,7 @@ describe('SearchBoxComponent', () => {
it('should get the current search query from the location service', it('should get the current search query from the location service',
fakeAsync(inject([LocationService], (location: MockLocationService) => { fakeAsync(inject([LocationService], (location: MockLocationService) => {
location.search.and.returnValue({ search: 'initial search' }); location.search.and.returnValue({ search: 'initial search' });
component.ngOnInit(); component.ngAfterViewInit();
expect(location.search).toHaveBeenCalled(); expect(location.search).toHaveBeenCalled();
tick(300); tick(300);
expect(host.searchHandler).toHaveBeenCalledWith('initial search'); expect(host.searchHandler).toHaveBeenCalledWith('initial search');

View File

@ -1,4 +1,4 @@
import { Component, OnInit, ViewChild, ElementRef, EventEmitter, Output } from '@angular/core'; import { AfterViewInit, Component, ViewChild, ElementRef, EventEmitter, Output } from '@angular/core';
import { LocationService } from 'app/shared/location.service'; import { LocationService } from 'app/shared/location.service';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
@ -24,7 +24,7 @@ import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
(focus)="doFocus()" (focus)="doFocus()"
(click)="doSearch()">` (click)="doSearch()">`
}) })
export class SearchBoxComponent implements OnInit { export class SearchBoxComponent implements AfterViewInit {
private searchDebounce = 300; private searchDebounce = 300;
private searchSubject = new Subject<string>(); private searchSubject = new Subject<string>();
@ -40,7 +40,7 @@ export class SearchBoxComponent implements OnInit {
/** /**
* When we first show this search box we trigger a search if there is a search query in the URL * When we first show this search box we trigger a search if there is a search query in the URL
*/ */
ngOnInit() { ngAfterViewInit() {
const query = this.locationService.search()['search']; const query = this.locationService.search()['search'];
if (query) { if (query) {
this.query = query; this.query = query;

View File

@ -239,7 +239,9 @@ describe('site App', function() {
/* tslint:disable:max-line-length */ /* tslint:disable:max-line-length */
expect(page.ghLinks.get(0).getAttribute('href')) expect(page.ghLinks.get(0).getAttribute('href'))
.toMatch(/https:\/\/github\.com\/angular\/angular\/edit\/master\/aio\/content\/guide\/http\.md\?message=docs%3A%20describe%20your%20change\.\.\./); .toMatch(/https:\/\/github\.com\/angular\/angular\/edit\/master\/aio\/content\/guide\/http\.md\?message=docs%3A%20describe%20your%20change\.\.\./);
}); // TODO(gkalpak): This test often times out with Ivy (because loading `guide/http` takes a lot of time).
// Remove the timeout once the performance issues have been fixed.
}, 60000);
it('should not be present on top level pages', () => { it('should not be present on top level pages', () => {
page.navigateTo('features'); page.navigateTo('features');