Skip to content

Commit

Permalink
all unit tests working
Browse files Browse the repository at this point in the history
  • Loading branch information
lathonez committed Oct 15, 2016
1 parent 819caf5 commit 02b0901
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 88 deletions.
14 changes: 5 additions & 9 deletions src/app/app.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TestUtils } from '../test';
import { ClickerApp } from './app.component';
import { Page2 } from '../pages';
import { ClickerApp } from './app.component';
import { MenuMock, NavMock, PlatformMock } from '../../test/mocks';
import { Page2 } from '../pages';

let instance: ClickerApp = null;

describe('ClickerApp', () => {

beforeEach(() => {
TestUtils.configureIonicTestingModule(ClickerApp);
let fixture: ComponentFixture<ClickerApp> = TestBed.createComponent(ClickerApp);
instance = fixture.debugElement.componentInstance;
instance = new ClickerApp((<any> new PlatformMock), (<any> new MenuMock));
instance['nav'] = (<any>new NavMock());
});

it('initialises with two possible pages', () => {
Expand All @@ -27,8 +25,6 @@ describe('ClickerApp', () => {

it('opens a page', () => {
spyOn(instance['menu'], 'close');
// cant be bothered to set up DOM testing for app.ts to get access to @ViewChild (Nav)
instance['nav'] = (<any>instance['menu']);
spyOn(instance['nav'], 'setRoot');
instance.openPage(instance['pages'][1]);
expect(instance['menu']['close']).toHaveBeenCalled();
Expand Down
1 change: 1 addition & 0 deletions src/components/clickerButton/clickerButton.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ let instance: any = null;
describe('ClickerButton', () => {

beforeEach(() => {
TestUtils.configureIonicTestingModule([ClickerButton]);
fixture = TestBed.createComponent(ClickerButton);
instance = fixture.debugElement.componentInstance;
instance.clicker = { name: 'TEST CLICKER' };
Expand Down
22 changes: 12 additions & 10 deletions src/components/clickerForm/clickerForm.spec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { FormBuilder } from '@angular/forms';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TestUtils } from '../../test';
import { ClickerForm } from './clickerForm';

let fixture: ComponentFixture<ClickerForm> = null;
let instance: any = null;

declare var $: any;

describe('ClickerForm', () => {

beforeEach(() => {
TestUtils.configureIonicTestingModule([ClickerForm]);
fixture = TestBed.createComponent(ClickerForm);
instance = fixture.debugElement.componentInstance;
instance.clicker = { name: 'TEST CLICKER' };
instance.clicker.getCount = function(): number { return 10; };
fixture.autoDetectChanges(true);
});

it('initialises', () => {
Expand All @@ -21,21 +26,18 @@ describe('ClickerForm', () => {

it('passes new clicker through to service', () => {
let clickerName: string = 'dave';
let input: any = fixture.nativeElement.querySelectorAll('.text-input')[0];
let button: any = fixture.nativeElement.querySelectorAll('button')[1];
input.value = clickerName;
TestUtils.eventFire(input, 'input');
TestUtils.eventFire(button, 'click');
instance.form = new FormBuilder().group({clickerNameInput: [clickerName]});
spyOn(instance, 'newClicker').and.callThrough();
spyOn(instance['clickerService'], 'newClicker').and.callThrough();
fixture.detectChanges();
fixture.nativeElement.querySelectorAll('button')[1].click();
expect(instance.newClicker).toHaveBeenCalledWith(Object({ clickerNameInput: clickerName }));
expect(instance['clickerService'].newClicker).toHaveBeenCalledWith(clickerName);
});

it('doesn\'t try to add a clicker with no name', () => {
let button: any = fixture.nativeElement.querySelectorAll('button')[1];
instance.clickerName = '';
fixture.detectChanges();
TestUtils.eventFire(button, 'click');
expect(instance.newClicker).toHaveBeenCalled();
spyOn(instance['clickerService'], 'newClicker').and.callThrough();
instance.newClicker({});
expect(instance['clickerService'].newClicker).not.toHaveBeenCalled();
});
});
9 changes: 5 additions & 4 deletions src/pages/clickerList/clickerList.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TestUtils } from '../../test';
import { ClickerList } from './clickerList';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TestUtils } from '../../test';
import { ClickerList } from './clickerList';
import { ClickerButton, ClickerForm } from '../../components';

describe('ClickerList', () => {

beforeEach(() => {
TestUtils.configureIonicTestingModule(ClickerList);
TestUtils.configureIonicTestingModule([ClickerList, ClickerForm, ClickerButton]);
});

it('initialises', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/page2/page2.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Page2 } from './page2';
describe('Pages: Page2', () => {

beforeEach(() => {
TestUtils.configureIonicTestingModule(Page2);
TestUtils.configureIonicTestingModule([Page2]);
});

it('should create page2', async(() => {
Expand Down
58 changes: 26 additions & 32 deletions src/services/clickers.spec.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,74 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TestUtils } from '../test';
import { ClickersService } from './clickers';
import { ClickerList } from '../pages/clickerList/clickerList';
import { Clicker } from '../models';
import { StorageMock } from './mocks';
import { ClickersService } from './clickers';
import { Clicker } from '../models';
import { StorageMock } from './mocks';

let fixture: ComponentFixture<ClickerList> = null;
let instance: any = null;
let clickers: ClickersService = null;

describe('ClickersService', () => {

beforeEach(() => {
TestUtils.configureIonicTestingModule(ClickerList);
fixture = TestBed.createComponent(ClickerList);
instance = fixture.debugElement.componentInstance;
clickers = instance.clickerService;
clickers = new ClickersService(<any>new StorageMock());
spyOn(clickers['storage'], 'set').and.callThrough();
});

it('initialises', () => {
expect(this.clickers).not.toBeNull();
expect(this.instance).not.toBeNull();
expect(this.fixture).not.toBeNull();
expect(clickers).not.toBeNull();
});

it('initialises with clickers from mock storage', (done: Function) => {
this.clickers['initClickers']([])
clickers['init']()
.then(() => {
expect(this.clickers.getClickers().length).toEqual(StorageMock.CLICKER_IDS.length);
expect(clickers.getClickers().length).toEqual(StorageMock.CLICKER_IDS.length);
done();
});
});

it('can initialise a clicker from string', () => {
let clickerString: string = '{"id":"0g2vt8qtlm","name":"harold","clicks":[{"time":1450410168819,"location":"TODO"},{"time":1450410168945,"location":"TODO"}]}';
let clicker: Clicker = this.clickers.initClicker(clickerString);
let clicker: Clicker = clickers['initClicker'](clickerString);
expect(clicker.getName()).toEqual('harold');
expect(clicker.getCount()).toEqual(2);
});

it('returns undefined for a bad id', () => {
expect(this.clickers.getClicker('dave')).not.toBeDefined();
expect(clickers.getClicker('dave')).not.toBeDefined();
});

it('adds a new clicker with the correct name', () => {
let idAdded: string = this.clickers.newClicker('dave');
expect(this.clickers['storage'].set).toHaveBeenCalledWith(idAdded, jasmine.any(String));
expect(this.clickers.getClickers()[3].getName()).toEqual('dave');
it('adds a new clicker with the correct name', (done: Function) => {
clickers['init']()
.then(() => {
let idAdded: string = clickers.newClicker('dave');
expect(clickers['storage'].set).toHaveBeenCalledWith(idAdded, jasmine.any(String));
expect(clickers.getClickers()[3].getName()).toEqual('dave');
done();
});
});

it('removes a clicker by id', () => {
let idToRemove: string = this.clickers.newClicker('dave');
this.clickers.removeClicker(idToRemove);
expect(this.clickers['storage'].set).toHaveBeenCalledWith(idToRemove, jasmine.any(String));
let idToRemove: string = clickers.newClicker('dave');
clickers.removeClicker(idToRemove);
expect(clickers['storage'].set).toHaveBeenCalledWith(idToRemove, jasmine.any(String));
});

it('does a click', () => {
let idToClick: string = this.clickers.newClicker('dave');
let idToClick: string = clickers.newClicker('dave');
let clickedClicker: Clicker = null;
this.clickers.doClick(idToClick);
expect(this.clickers['storage'].set).toHaveBeenCalledWith(idToClick, jasmine.any(String));
clickedClicker = this.clickers.getClicker(idToClick);
clickers.doClick(idToClick);
expect(clickers['storage'].set).toHaveBeenCalledWith(idToClick, jasmine.any(String));
clickedClicker = clickers.getClicker(idToClick);
expect(clickedClicker.getCount()).toEqual(1);
});

it('loads IDs from storage', (done: Function) => {
this.clickers.initIds()
clickers['initIds']()
.then((ids: Array<string>) => {
expect(ids).toEqual(StorageMock.CLICKER_IDS);
done();
});
});

it('loads clickers from storage', (done: Function) => {
this.clickers.initClickers(StorageMock.CLICKER_IDS)
clickers['initClickers'](StorageMock.CLICKER_IDS)
.then((resolvedClickers: Array<Clicker>) => {
expect(resolvedClickers.length).toEqual(3);
expect(resolvedClickers[0].getId()).toEqual(StorageMock.CLICKER_IDS[0]);
Expand Down
43 changes: 18 additions & 25 deletions src/services/clickers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,36 @@ export class ClickersService {
this.storage = storage;
this.ids = [];
this.clickers = [];
this.initIds()
this.init();
}

// as init is async separate logic here so it's testable
private init(): Promise<void> {
return this.initIds()
.then((ids: Array<string>) => { this.ids = ids; })
.then(() => this.initClickers(this.ids))
.then((clickers: Array<Clicker>) => this.clickers = clickers);
}

// initialise Ids from SQL storage
private initIds(): Promise<{}> {
return new Promise((resolve: Function) => {
let ids: Array<string> = [];
this.storage.get('ids') // return the promise so we can chain initClickers
.then((rawIds: string) => {
if (rawIds) {
// ids are stored as stringified JSON array
ids = JSON.parse(rawIds);
} else {
ids = [];
}
})
.then(() => resolve(ids));
});
return this.storage.get('ids') // return the promise so we can chain initClickers
.then((rawIds: string) => {
if (!rawIds) return [];
// ids are stored as stringified JSON array
return JSON.parse(rawIds);
});
}

// initialise Clickers from SQL storage given an array of ids
private initClickers(ids: Array<string>): Promise<{}> {
// get all existing ids
return new Promise((resolve: Function) => {
let clickers: Array<Clicker> = [];
for (let id of ids) {
this.storage.get(id)
.then((clicker: string) => {
clickers.push(this.initClicker(clicker));
});
}
// TODO - this is a bug it will resolve before the loop has completed
resolve(clickers);
});
let proms: Array<Promise<string>> = [];

proms = ids.map(id => this.storage.get(id));

return Promise.all(proms)
.then(clickers => clickers.map(clicker => this.initClicker(clicker)));
}

// initialise a clicker from a raw JSON string out of the DB
Expand Down
23 changes: 16 additions & 7 deletions src/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';

import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TestBed } from '@angular/core/testing';
import { App, MenuController, NavController, Platform, Config, Keyboard, Form, IonicModule } from 'ionic-angular';
import { ConfigMock, FormMock, NavMock, PlatformMock } from '../test/mocks';
// import { PagesModule } from './pages';
import { ConfigMock, NavMock, PlatformMock } from '../test/mocks';
import { ClickersServiceMock } from './services/clickers.mock';
import { ClickersService } from './services';

// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare var __karma__: any;
Expand Down Expand Up @@ -38,21 +42,26 @@ Promise.all([

export class TestUtils {

public static configureIonicTestingModule(component: any): void {
public static configureIonicTestingModule(components: Array<any>): void {
TestBed.configureTestingModule({
declarations: [
component,
...components,
],
providers: [
{provide: App, useClass: ConfigMock},
{provide: Config, useClass: ConfigMock},
{provide: Form, useClass: FormMock},
Form,
{provide: Keyboard, useClass: ConfigMock},
{provide: MenuController, useClass: ConfigMock},
{provide: NavController, useValue: NavMock},
{provide: Platform, useValue: PlatformMock},
{provide: NavController, useClass: NavMock},
{provide: Platform, useClass: PlatformMock},
{provide: ClickersService, useClass: ClickersServiceMock},
],
imports: [
FormsModule,
IonicModule,
ReactiveFormsModule,
],
imports: [ IonicModule ],
});
}

Expand Down
8 changes: 8 additions & 0 deletions test/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,11 @@ export class PlatformMock {
});
}
}

export class MenuMock {
public close(): any {
return new Promise((resolve: Function) => {
resolve();
});
}
}

0 comments on commit 02b0901

Please sign in to comment.