Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,21 @@ jobs:

test_aio_local_ivy:
<<: *job_defaults
docker:
# Needed because the AIO tests and the PWA score test depend on Chrome being available.
- image: *browsers_docker_image
steps:
- *attach_workspace
- *init_environment
# Build aio with Ivy (using local Angular packages)
- 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:
<<: *job_defaults
Expand Down
2 changes: 1 addition & 1 deletion aio/scripts/switch-to-ivy.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function _main() {
const oldTsConfigStr = readFileSync(tsConfigPath, 'utf8');
const oldTsConfigObj = parse(oldTsConfigStr);
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}`);
writeFileSync(tsConfigPath, newTsConfigStr);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ describe('CodeExampleComponent', () => {
});

fixture = TestBed.createComponent(HostComponent);
fixture.detectChanges();

hostComponent = fixture.componentInstance;
codeExampleComponent = hostComponent.codeExampleComponent;

fixture.detectChanges();
});

it('should be able to capture the code snippet provided in content', () => {
Expand Down
4 changes: 2 additions & 2 deletions aio/src/app/custom-elements/code/code-tabs.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ describe('CodeTabsComponent', () => {
});

fixture = TestBed.createComponent(HostComponent);
fixture.detectChanges();

hostComponent = fixture.componentInstance;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's this a breaking change?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The componentInstance is still available before detectChanges(). It is the codeTabsComponent (which is a ViewChild query) that isn't.

This is related to the (known breaking) changes in ViewChild queries. We could have made the codeTabsComponent ViewChild static instead (and leave the test as is).

codeTabsComponent = hostComponent.codeTabsComponent;

fixture.detectChanges();
});

it('should get correct tab info', () => {
Expand Down
260 changes: 132 additions & 128 deletions aio/src/app/custom-elements/toc/toc.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,178 +63,182 @@ describe('TocComponent', () => {
expect(tocComponent.type).toEqual('None');
});

it('should not display anything when no h2 or h3 TocItems', () => {
tocService.tocList.next([tocItem('H1', 'h1')]);
fixture.detectChanges();
expect(tocComponentDe.children.length).toEqual(0);
});

it('should update when the TocItems are updated', () => {
tocService.tocList.next([tocItem('Heading A')]);
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());
describe('(once the lifecycle hooks have run)', () => {
beforeEach(() => fixture.detectChanges());

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')]);
it('should not display anything when no h2 or h3 TocItems', () => {
tocService.tocList.next([tocItem('H1', 'h1')]);
fixture.detectChanges();
page = setPage();
expect(tocComponentDe.children.length).toEqual(0);
});

it('should have four displayed items', () => {
expect(page.listItems.length).toEqual(4);
});

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(() => {
it('should update when the TocItems are updated', () => {
tocService.tocList.next([tocItem('Heading A')]);
fixture.detectChanges();
page = setPage();
scrollToTopSpy = TestBed.get(ScrollService).scrollToTop;
});
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);

it('should have more than 4 displayed items', () => {
expect(page.listItems.length).toBeGreaterThan(4);
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 not display the h1 item', () => {
expect(page.listItems.find(item => item.classes.h1)).toBeFalsy('should not find h1 item');
});
it('should only display H2 and H3 TocItems', () => {
tocService.tocList.next([tocItem('Heading A', 'h1'), tocItem('Heading B'), tocItem('Heading C', 'h3')]);
fixture.detectChanges();

it('should be in "collapsed" (not expanded) state at the start', () => {
expect(tocComponent.isCollapsed).toBeTruthy();
});
const tocItems = tocComponentDe.queryAll(By.css('li'));
const textContents = tocItems.map(item => item.nativeNode.textContent.trim());

it('should have "collapsed" class at the start', () => {
expect(tocComponentDe.children[0].classes.collapsed).toEqual(true);
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 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');
});
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);

// 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');
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('after click tocHeading button', () => {
describe('when fewer than `maxPrimary` TocItems', () => {

beforeEach(() => {
page.tocHeadingButtonEmbedded.nativeElement.click();
tocService.tocList.next([tocItem('Heading A'), tocItem('Heading B'), tocItem('Heading C'), tocItem('Heading D')]);
fixture.detectChanges();
page = setPage();
});

it('should not be "collapsed"', () => {
expect(tocComponent.isCollapsed).toEqual(false);
it('should have four displayed items', () => {
expect(page.listItems.length).toEqual(4);
});

it('should not have "collapsed" class', () => {
expect(tocComponentDe.children[0].classes.collapsed).toBeFalsy();
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 scroll', () => {
expect(scrollToTopSpy).not.toHaveBeenCalled();
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;

it('should be "collapsed" after clicking again', () => {
page.tocHeadingButtonEmbedded.nativeElement.click();
beforeEach(() => {
fixture.detectChanges();
expect(tocComponent.isCollapsed).toEqual(true);
page = setPage();
scrollToTopSpy = TestBed.get(ScrollService).scrollToTop;
});

it('should not scroll after clicking again', () => {
page.tocHeadingButtonEmbedded.nativeElement.click();
fixture.detectChanges();
expect(scrollToTopSpy).not.toHaveBeenCalled();
it('should have more than 4 displayed items', () => {
expect(page.listItems.length).toBeGreaterThan(4);
});
});

describe('after click tocMore button', () => {
it('should not display the h1 item', () => {
expect(page.listItems.find(item => item.classes.h1)).toBeFalsy('should not find h1 item');
});

beforeEach(() => {
page.tocMoreButton.nativeElement.click();
fixture.detectChanges();
it('should be in "collapsed" (not expanded) state at the start', () => {
expect(tocComponent.isCollapsed).toBeTruthy();
});

it('should not be "collapsed"', () => {
expect(tocComponent.isCollapsed).toEqual(false);
it('should have "collapsed" class at the start', () => {
expect(tocComponentDe.children[0].classes.collapsed).toEqual(true);
});

it('should not have "collapsed" class', () => {
expect(tocComponentDe.children[0].classes.collapsed).toBeFalsy();
it('should display expando buttons', () => {
expect(page.tocHeadingButtonEmbedded).toBeTruthy('top expand/collapse button');
expect(page.tocMoreButton).toBeTruthy('bottom more button');
});

it('should not scroll', () => {
expect(scrollToTopSpy).not.toHaveBeenCalled();
it('should have secondary items', () => {
expect(tocComponent.type).toEqual('EmbeddedExpandable');
});

it('should be "collapsed" after clicking again', () => {
page.tocMoreButton.nativeElement.click();
fixture.detectChanges();
expect(tocComponent.isCollapsed).toEqual(true);
// 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');
});

it('should be "collapsed" after clicking tocHeadingButton', () => {
page.tocMoreButton.nativeElement.click();
fixture.detectChanges();
expect(tocComponent.isCollapsed).toEqual(true);
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();
});
});

it('should scroll after clicking again', () => {
page.tocMoreButton.nativeElement.click();
fixture.detectChanges();
expect(scrollToTopSpy).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();
});
});
});
});
Expand Down
2 changes: 1 addition & 1 deletion aio/src/app/search/search-box/search-box.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('SearchBoxComponent', () => {
it('should get the current search query from the location service',
fakeAsync(inject([LocationService], (location: MockLocationService) => {
location.search.and.returnValue({ search: 'initial search' });
component.ngOnInit();
component.ngAfterViewInit();
expect(location.search).toHaveBeenCalled();
tick(300);
expect(host.searchHandler).toHaveBeenCalledWith('initial search');
Expand Down
Loading