From 48b3094f5f5245b4ab87d35c75966a3bdfa17c4a Mon Sep 17 00:00:00 2001 From: Raven Avalon Date: Thu, 30 Mar 2017 13:48:14 -0400 Subject: [PATCH] chore(tests): Add unit tests for each component. --- karma.conf.js | 10 +- .../component-category-list.spec.ts | 43 +++++++++ .../component-category-list.ts | 2 +- .../component-list/component-list.spec.ts | 50 +++++++++- .../component-page-header.spec.ts | 41 +++++++++ .../component-page-header.ts | 2 +- .../component-sidenav.spec.ts | 66 +++++++++++++ .../component-viewer/component-viewer.spec.ts | 50 ++++++++++ .../component-viewer/component-viewer.ts | 2 +- src/app/pages/guide-list/guide-list.spec.ts | 41 +++++++++ .../pages/guide-viewer/guide-viewer.spec.ts | 42 +++++++++ src/app/pages/page-title/page-title.spec.ts | 12 +++ .../example-viewer/example-viewer.spec.ts | 92 +++++++++++++++++++ src/app/shared/footer/footer.spec.ts | 32 +++++++ src/app/shared/navbar/navbar.spec.ts | 31 +++++++ 15 files changed, 505 insertions(+), 11 deletions(-) create mode 100644 src/app/pages/component-category-list/component-category-list.spec.ts create mode 100644 src/app/pages/component-page-header/component-page-header.spec.ts create mode 100644 src/app/pages/component-sidenav/component-sidenav.spec.ts create mode 100644 src/app/pages/component-viewer/component-viewer.spec.ts create mode 100644 src/app/pages/guide-list/guide-list.spec.ts create mode 100644 src/app/pages/guide-viewer/guide-viewer.spec.ts create mode 100644 src/app/pages/page-title/page-title.spec.ts create mode 100644 src/app/shared/example-viewer/example-viewer.spec.ts create mode 100644 src/app/shared/footer/footer.spec.ts create mode 100644 src/app/shared/navbar/navbar.spec.ts diff --git a/karma.conf.js b/karma.conf.js index d34160d14..a97bab555 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -6,12 +6,12 @@ const path = require('path'); module.exports = function (config) { config.set({ basePath: '', - frameworks: ['jasmine', 'angular-cli'], + frameworks: ['jasmine', '@angular/cli'], plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), require('karma-remap-istanbul'), - require('angular-cli/plugins/karma'), + require('@angular/cli/plugins/karma'), require('karma-browserstack-launcher'), require('karma-sauce-launcher'), ], @@ -19,7 +19,7 @@ module.exports = function (config) { { pattern: './src/test.ts', watched: false } ], preprocessors: { - './src/test.ts': ['angular-cli'] + './src/test.ts': ['@angular/cli'] }, mime: { 'text/x-typescript': ['ts','tsx'] @@ -66,7 +66,7 @@ module.exports = function (config) { pollingTimeout: 20000 }, }); - + if (process.env['TRAVIS']) { let buildId = `TRAVIS #${process.env.TRAVIS_BUILD_NUMBER} (${process.env.TRAVIS_BUILD_ID})`; @@ -87,5 +87,5 @@ module.exports = function (config) { } config.browsers = platformMap[platformType]; - } + } }; diff --git a/src/app/pages/component-category-list/component-category-list.spec.ts b/src/app/pages/component-category-list/component-category-list.spec.ts new file mode 100644 index 000000000..87a617a10 --- /dev/null +++ b/src/app/pages/component-category-list/component-category-list.spec.ts @@ -0,0 +1,43 @@ +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {MaterialModule} from '@angular/material'; +import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; + +import {DocumentationItems} from '../../shared/documentation-items/documentation-items'; +import {ComponentPageTitle} from '../page-title/page-title'; +import {ComponentCategoryList} from './component-category-list'; + + +describe('ComponentCategoryList', () => { + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MaterialModule], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [ComponentCategoryList], + providers: [ + DocumentationItems, + ComponentPageTitle + ] + }); + + fixture = TestBed.createComponent(ComponentCategoryList) + })); + + it('should set page title on init', () => { + const component = fixture.componentInstance; + spyOn(component, 'ngOnInit').and.callThrough(); + fixture.detectChanges(); + expect(component.ngOnInit).toHaveBeenCalled(); + expect(component._componentPageTitle.title).toEqual('Component Library'); + }); + + it('should render a card for every category', () => { + const component = fixture.componentInstance; + fixture.detectChanges(); + const categories = component.docItems.getItemsInCategories(); + const cards = fixture + .nativeElement.querySelectorAll('.docs-component-category-list-card'); + expect(cards.length).toEqual(categories.length); + }); +}); diff --git a/src/app/pages/component-category-list/component-category-list.ts b/src/app/pages/component-category-list/component-category-list.ts index e913b8d2e..caf01b8e4 100644 --- a/src/app/pages/component-category-list/component-category-list.ts +++ b/src/app/pages/component-category-list/component-category-list.ts @@ -10,7 +10,7 @@ import {ComponentPageTitle} from '../page-title/page-title'; }) export class ComponentCategoryList { constructor(public docItems: DocumentationItems, - private _componentPageTitle: ComponentPageTitle) {} + public _componentPageTitle: ComponentPageTitle) {} ngOnInit() { this._componentPageTitle.title = 'Component Library'; diff --git a/src/app/pages/component-list/component-list.spec.ts b/src/app/pages/component-list/component-list.spec.ts index 31442dba4..36d21cda5 100644 --- a/src/app/pages/component-list/component-list.spec.ts +++ b/src/app/pages/component-list/component-list.spec.ts @@ -1,5 +1,49 @@ -describe('component list', () => { - it('should run', () => { - expect(1).toBe(1); +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; +import {MaterialModule} from '@angular/material'; +import {ActivatedRoute, Router} from '@angular/router'; +import {RouterTestingModule} from '@angular/router/testing'; +import {Observable} from 'rxjs/Observable'; + +import {DocumentationItems} from '../../shared/documentation-items/documentation-items'; +import {ComponentPageTitle} from '../page-title/page-title'; +import {ComponentList} from './component-list'; + +const CATEGORY_ID = 'forms'; +const mockActivatedRoute = { + params: Observable.create(observer => { + observer.next({id: CATEGORY_ID}); + observer.complete(); + }) +}; + +describe('ComponentList', () => { + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MaterialModule, RouterTestingModule], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [ComponentList], + providers: [ + {provide: ActivatedRoute, useValue: mockActivatedRoute}, + ComponentPageTitle, + DocumentationItems, + ] + }); + + fixture = TestBed.createComponent(ComponentList); + })); + + it('should set the category from router params', done => { + const component = fixture.componentInstance; + fixture.detectChanges(); + + fixture.whenStable().then(() => { + const actual = component.category; + const expected = component.docItems.getCategoryById(CATEGORY_ID); + expect(actual).toEqual(expected); + done(); + }); }); }); diff --git a/src/app/pages/component-page-header/component-page-header.spec.ts b/src/app/pages/component-page-header/component-page-header.spec.ts new file mode 100644 index 000000000..21a511c06 --- /dev/null +++ b/src/app/pages/component-page-header/component-page-header.spec.ts @@ -0,0 +1,41 @@ +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {MaterialModule} from '@angular/material'; +import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; + +import {ComponentPageTitle} from '../page-title/page-title'; +import {ComponentPageHeader} from './component-page-header'; + + +describe('ComponentPageHeader', () => { + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MaterialModule], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [ComponentPageHeader], + providers: [ComponentPageTitle], + }); + + fixture = TestBed.createComponent(ComponentPageHeader); + })); + + it('should return the title', () => { + const component = fixture.componentInstance; + const title = 'foobar'; + fixture.detectChanges(); + component._componentPageTitle.title = title; + expect(component.getTitle()).toEqual(title); + }); + + it('should emit a toggleSideNav event', () => { + const component = fixture.componentInstance; + fixture.detectChanges(); + spyOn(component.toggleSidenav, 'emit'); + fixture + .nativeElement + .querySelector('.sidenav-toggle') + .click(); + expect(component.toggleSidenav.emit).toHaveBeenCalled(); + }); +}); diff --git a/src/app/pages/component-page-header/component-page-header.ts b/src/app/pages/component-page-header/component-page-header.ts index dd5a06d9a..7b1f5cdc7 100644 --- a/src/app/pages/component-page-header/component-page-header.ts +++ b/src/app/pages/component-page-header/component-page-header.ts @@ -8,7 +8,7 @@ import {ComponentPageTitle} from '../page-title/page-title'; styleUrls: ['./component-page-header.scss'] }) export class ComponentPageHeader { - constructor(private _componentPageTitle: ComponentPageTitle) { } + constructor(public _componentPageTitle: ComponentPageTitle) { } @Output() toggleSidenav = new EventEmitter(); diff --git a/src/app/pages/component-sidenav/component-sidenav.spec.ts b/src/app/pages/component-sidenav/component-sidenav.spec.ts new file mode 100644 index 000000000..5b9022373 --- /dev/null +++ b/src/app/pages/component-sidenav/component-sidenav.spec.ts @@ -0,0 +1,66 @@ +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {MaterialModule, MdSidenav} from '@angular/material'; +import {RouterTestingModule} from '@angular/router/testing'; +import {Observable} from 'rxjs/Observable'; +import {Router} from '@angular/router'; +import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from '@angular/core'; + +import {DocumentationItems} from '../../shared/documentation-items/documentation-items'; +import {ComponentSidenav} from './component-sidenav'; + +const mockRouter = { + events: Observable.create(observer => { + observer.next(null); + observer.complete(); + }) +}; + + +describe('ComponentSidenav', () => { + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MaterialModule], + schemas: [NO_ERRORS_SCHEMA], + declarations: [ComponentSidenav], + providers: [ + {provide: Router, useValue: mockRouter}, + DocumentationItems + ], + }); + + fixture = TestBed.createComponent(ComponentSidenav); + })); + + it('should close the sidenav on init', () => { + const component = fixture.componentInstance; + + // Spy on window.mediaMatch and return stub + spyOn(window, 'matchMedia').and.returnValue({ + matches: true + }); + + // Spy on viewChild component's `close` method + spyOn(component.sidenav, 'close'); + + fixture.detectChanges(); + + expect(component.sidenav instanceof MdSidenav).toBeTruthy(); + expect(component.isScreenSmall()).toBeTruthy(); + expect(component.sidenav.close).toHaveBeenCalled(); + }); + + it('should show a link for each item in doc items categories', () => { + const component = fixture.componentInstance; + + fixture.detectChanges(); + + const totalItems = component.docItems.getAllItems().length; + const totalLinks = fixture + .nativeElement + .querySelectorAll('.docs-component-viewer-sidenav li a') + .length; + expect(totalLinks).toEqual(totalItems); + }); +}); diff --git a/src/app/pages/component-viewer/component-viewer.spec.ts b/src/app/pages/component-viewer/component-viewer.spec.ts new file mode 100644 index 000000000..bbe5a981b --- /dev/null +++ b/src/app/pages/component-viewer/component-viewer.spec.ts @@ -0,0 +1,50 @@ +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; +import {RouterTestingModule} from '@angular/router/testing'; +import {ActivatedRoute} from '@angular/router'; +import {MaterialModule} from '@angular/material'; +import {Observable} from 'rxjs/Observable'; + +import {DocumentationItems} from '../../shared/documentation-items/documentation-items'; +import {ComponentPageTitle} from '../page-title/page-title'; +import {ComponentViewer} from './component-viewer'; + +const docItemsID = 'button'; + +const mockActivatedRoute = { + params: Observable.create(observer => { + observer.next({id: docItemsID}); + observer.complete(); + }) +}; + + +describe('ComponentViewer', () => { + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + BrowserAnimationsModule, + MaterialModule, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [ComponentViewer], + providers: [ + {provide: ActivatedRoute, useValue: mockActivatedRoute}, + ComponentPageTitle, + DocumentationItems + ] + }); + + fixture = TestBed.createComponent(ComponentViewer); + })); + + it('should set page title correctly', () => { + const component = fixture.componentInstance; + fixture.detectChanges(); + const expected = `Component - ${component.docItems.getItemById(docItemsID).name}`; + expect(component._componentPageTitle.title).toEqual(expected); + }); +}); diff --git a/src/app/pages/component-viewer/component-viewer.ts b/src/app/pages/component-viewer/component-viewer.ts index 44b3e1acd..60df024f2 100644 --- a/src/app/pages/component-viewer/component-viewer.ts +++ b/src/app/pages/component-viewer/component-viewer.ts @@ -14,7 +14,7 @@ export class ComponentViewer { componentDocItem: DocItem; constructor(private _route: ActivatedRoute, - private _componentPageTitle: ComponentPageTitle, + public _componentPageTitle: ComponentPageTitle, public docItems: DocumentationItems) { _route.params.subscribe(p => { this.componentDocItem = docItems.getItemById(p['id']); diff --git a/src/app/pages/guide-list/guide-list.spec.ts b/src/app/pages/guide-list/guide-list.spec.ts new file mode 100644 index 000000000..2b3f1663b --- /dev/null +++ b/src/app/pages/guide-list/guide-list.spec.ts @@ -0,0 +1,41 @@ +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; +import {CommonModule} from '@angular/common'; +import {RouterTestingModule} from '@angular/router/testing'; +import {MaterialModule} from '@angular/material'; + +import {GuideItems} from '../../shared/guide-items/guide-items'; +import {GuideList} from './guide-list'; + + +describe('GuideList', () => { + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + BrowserAnimationsModule, + MaterialModule, + RouterTestingModule + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [GuideList], + providers: [GuideItems], + }); + + fixture = TestBed.createComponent(GuideList); + })); + + it('should display a link for each item in guide items', () => { + const component = fixture.componentInstance; + fixture.detectChanges(); + + const totalItems = component.guideItems.getAllItems().length; + const totalLinks = fixture + .nativeElement + .querySelectorAll('.docs-guide-item') + .length; + expect(totalLinks).toEqual(totalItems); + }); +}); diff --git a/src/app/pages/guide-viewer/guide-viewer.spec.ts b/src/app/pages/guide-viewer/guide-viewer.spec.ts new file mode 100644 index 000000000..f39ae4610 --- /dev/null +++ b/src/app/pages/guide-viewer/guide-viewer.spec.ts @@ -0,0 +1,42 @@ +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; +import {Observable} from 'rxjs/Observable'; +import {MaterialModule} from '@angular/material'; +import {ActivatedRoute} from '@angular/router'; + +import {GuideItems} from '../../shared/guide-items/guide-items'; +import {GuideViewer} from './guide-viewer'; + +const guideItemsID = 'getting-started'; +const mockActivatedRoute = { + params: Observable.create(observer => { + observer.next({id: guideItemsID}); + observer.complete(); + }) +}; + + +describe('GuideViewer', () => { + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MaterialModule], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [GuideViewer], + providers: [ + {provide: ActivatedRoute, useValue: mockActivatedRoute}, + GuideItems + ] + }); + + fixture = TestBed.createComponent(GuideViewer); + })); + + it('should set the guide based off route params', () => { + const component = fixture.componentInstance; + fixture.detectChanges(); + expect(component.guide) + .toEqual(component.guideItems.getItemById(guideItemsID)); + }); +}); diff --git a/src/app/pages/page-title/page-title.spec.ts b/src/app/pages/page-title/page-title.spec.ts new file mode 100644 index 000000000..d82c03a64 --- /dev/null +++ b/src/app/pages/page-title/page-title.spec.ts @@ -0,0 +1,12 @@ +import {async, inject, TestBed, ComponentFixture} from '@angular/core/testing'; +import {ComponentPageTitle} from './page-title'; + + +describe('ComponentPageTitle', () => { + const service: ComponentPageTitle = new ComponentPageTitle(); + + it('should initialize title to empty string', () => { + expect(service._title).toEqual(''); + expect(service.title).toEqual(''); + }); +}); diff --git a/src/app/shared/example-viewer/example-viewer.spec.ts b/src/app/shared/example-viewer/example-viewer.spec.ts new file mode 100644 index 000000000..ec5af76f5 --- /dev/null +++ b/src/app/shared/example-viewer/example-viewer.spec.ts @@ -0,0 +1,92 @@ +import {NgModule, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {CommonModule} from '@angular/common'; +import {ReactiveFormsModule} from '@angular/forms'; +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {Http} from '@angular/http'; +import {MaterialModule, ComponentPortal} from '@angular/material'; + +import {AutocompleteOverviewExample} from '../../examples/autocomplete-overview/autocomplete-overview-example'; +import {EXAMPLE_COMPONENTS} from '../../examples/example-module'; +import {ExampleViewer} from './example-viewer'; + +const exampleComponentString = 'autocomplete-overview'; + + +// Required for the set example function +@NgModule({ + imports: [ + BrowserAnimationsModule, + CommonModule, + MaterialModule, + ReactiveFormsModule, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [AutocompleteOverviewExample], + entryComponents: [AutocompleteOverviewExample] +}) +class TestAutocompleteOverviewModule { +} + + +class MockHTTP { +} + + +describe('ExampleViewer', () => { + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MaterialModule, ReactiveFormsModule, TestAutocompleteOverviewModule], + declarations: [ExampleViewer], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ + {provide: Http, useClass: MockHTTP} + ] + }); + + fixture = TestBed.createComponent(ExampleViewer); + })); + + it('should toggle showSource boolean', () => { + const component = fixture.componentInstance; + fixture.detectChanges(); + expect(component.showSource).toBe(false); + component.toggleSourceView(); + expect(component.showSource).toBe(true); + }); + + it('should set and return example properly', () => { + const component = fixture.componentInstance; + component.example = exampleComponentString; + fixture.detectChanges(); + const data = component.exampleData; + expect(data).toEqual(EXAMPLE_COMPONENTS[exampleComponentString]); + }); + + it('should log message about missing example', () => { + const component = fixture.componentInstance; + spyOn(console, 'log'); + component.example = 'foobar'; + fixture.detectChanges(); + expect(console.log).toHaveBeenCalled(); + expect(console.log).toHaveBeenCalledWith('MISSING EXAMPLE: ', 'foobar'); + }); + + it('should return assets path for example based on extension', () => { + // set example + const component = fixture.componentInstance; + component.example = exampleComponentString; + fixture.detectChanges(); + + // get example file path for each extension + const extensions = ['ts', 'css', 'html']; + const basePath = '/assets/examples/'; + extensions.forEach(ext => { + const expected = `${basePath}${exampleComponentString}-example-${ext}.html`; + const actual = component.exampleFileUrl(ext); + expect(actual).toEqual(expected); + }); + }); +}); diff --git a/src/app/shared/footer/footer.spec.ts b/src/app/shared/footer/footer.spec.ts new file mode 100644 index 000000000..fbe875e1d --- /dev/null +++ b/src/app/shared/footer/footer.spec.ts @@ -0,0 +1,32 @@ +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; +import {MaterialModule} from '@angular/material'; + +import {Footer} from './footer'; + + +describe('Footer', () => { + let fixture: ComponentFixture