scaffold top-level pages

This commit is contained in:
Jason Dreyzehner 2017-07-05 14:36:31 -04:00
parent 60d9d546a2
commit d784be5d7e
36 changed files with 221 additions and 376 deletions

View File

@ -1,6 +1,6 @@
import { browser, element, by } from 'protractor';
describe('ClickerApp', () => {
describe('InsightApp', () => {
beforeEach(() => {
browser.get('');

View File

@ -2,12 +2,17 @@ import { Component, ViewChild } from '@angular/core';
import { Platform, MenuController, Nav } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { ClickerList, Page2 } from '../pages';
import {
BlocksPage,
BroadcastTxPage,
NodeStatusPage,
VerifyMessagePage,
} from '../pages';
@Component({
templateUrl: './app.html',
})
export class ClickerApp {
export class InsightApp {
@ViewChild(Nav) public nav: Nav;
@ -26,15 +31,15 @@ export class ClickerApp {
this.splash = splash;
this.status = status;
this.rootPage = ClickerList;
this.rootPage = BlocksPage;
this.initializeApp();
// set our app's pages
this.pages = [
{ title: 'Blocks', component: ClickerList },
{ title: 'Broadcast Transaction', component: Page2 },
{ title: 'Verify Message', component: Page2 },
{ title: 'Node Status', component: Page2 },
{ title: 'Blocks', component: BlocksPage },
{ title: 'Broadcast Transaction', component: BroadcastTxPage },
{ title: 'Verify Message', component: VerifyMessagePage },
{ title: 'Node Status', component: NodeStatusPage },
];
}
@ -52,5 +57,5 @@ export class ClickerApp {
this.menu.close();
// navigate to the new page if it is not the current page
this.nav.setRoot(page.component);
};
}
}

View File

@ -1,11 +1,5 @@
<ion-menu [content]="content">
<!--<ion-header>
<ion-toolbar>
<ion-title>Pages</ion-title>
</ion-toolbar>
</ion-header>-->
<ion-content>
<ion-list>
<button ion-item *ngFor="let p of pages" (click)="openPage(p)">

View File

@ -3,24 +3,32 @@ import { BrowserModule } from '@angular/platform-brow
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { ClickerApp } from './app.component';
import { ClickerList, PagesModule, Page2 } from '../pages';
import { InsightApp } from './app.component';
import {
PagesModule,
BlocksPage,
BroadcastTxPage,
NodeStatusPage,
VerifyMessagePage,
} from '../pages';
import { ClickersService, StorageService } from '../services';
@NgModule({
declarations: [
ClickerApp,
InsightApp,
],
imports: [
BrowserModule,
PagesModule,
IonicModule.forRoot(ClickerApp),
IonicModule.forRoot(InsightApp),
],
bootstrap: [IonicApp],
entryComponents: [
ClickerApp,
ClickerList,
Page2,
InsightApp,
BlocksPage,
BroadcastTxPage,
NodeStatusPage,
VerifyMessagePage,
],
providers: [
StatusBar,

View File

@ -1,21 +1,21 @@
import { ClickerApp } from './app.component';
import { InsightApp } from './app.component';
import { MenuMock, NavMock, PlatformMock, SplashMock, StatusMock } from '../mocks';
import { Page2 } from '../pages';
import { BroadcastTxPage } from '../pages';
let instance: ClickerApp = null;
let instance: InsightApp = null;
describe('ClickerApp', () => {
describe('InsightApp', () => {
beforeEach(() => {
instance = new ClickerApp((<any> new PlatformMock), (<any> new MenuMock), (<any>new SplashMock()), (<any>new StatusMock()));
instance = new InsightApp((<any> new PlatformMock), (<any> new MenuMock), (<any>new SplashMock()), (<any>new StatusMock()));
instance['nav'] = (<any>new NavMock());
});
it('initialises with two possible pages', () => {
expect(instance['pages'].length).toEqual(2);
it('initializes with four possible pages', () => {
expect(instance['pages'].length).toEqual(4);
});
it('initialises with a root page', () => {
it('initializes with a root page', () => {
expect(instance['rootPage']).not.toBe(null);
});
@ -24,6 +24,6 @@ describe('ClickerApp', () => {
spyOn(instance['nav'], 'setRoot');
instance.openPage(instance['pages'][1]);
expect(instance['menu']['close']).toHaveBeenCalled();
expect(instance['nav'].setRoot).toHaveBeenCalledWith(Page2);
expect(instance['nav'].setRoot).toHaveBeenCalledWith(BroadcastTxPage);
});
});

View File

@ -1 +0,0 @@
<button ion-button block outline (click)="clickerService.doClick(clicker.getId())">{{clicker.getName()}} ({{clicker.getCount()}})</button>

View File

@ -1,36 +0,0 @@
import { ComponentFixture, async } from '@angular/core/testing';
import { TestUtils } from '../../test';
import { ClickerButton } from './clickerButton';
import { ClickerMock } from '../../models/clicker.mock';
let fixture: ComponentFixture<ClickerButton> = null;
let instance: any = null;
describe('ClickerButton', () => {
beforeEach(async(() => TestUtils.beforeEachCompiler([ClickerButton]).then(compiled => {
fixture = compiled.fixture;
instance = compiled.instance;
instance.clicker = new ClickerMock();
})));
afterEach(() => {
fixture.destroy();
});
it('initialises', () => {
expect(instance).not.toBeNull();
});
it('displays the clicker name and count', () => {
fixture.detectChanges();
expect(fixture.nativeElement.querySelectorAll('.button-inner')[0].innerHTML).toEqual('TEST CLICKER (10)');
});
it('does a click', () => {
fixture.detectChanges();
spyOn(instance['clickerService'], 'doClick');
TestUtils.eventFire(fixture.nativeElement.querySelectorAll('button')[0], 'click');
expect(instance['clickerService'].doClick).toHaveBeenCalled();
});
});

View File

@ -1,20 +0,0 @@
'use strict';
import { Component, Input } from '@angular/core';
import { ClickersService } from '../../services';
import { Clicker } from '../../models';
@Component({
selector: 'clicker-button',
templateUrl: './clickerButton.html',
})
export class ClickerButton {
@Input() public clicker: Clicker;
public clickerService: ClickersService;
constructor(clickerService: ClickersService) {
this.clickerService = clickerService;
}
}

View File

@ -1,14 +0,0 @@
<form [formGroup]="form" (submit)="newClicker(form.value)">
<ion-row>
<ion-col width-80>
<ion-item >
<ion-input block formControlName="clickerNameInput" type="text" placeholder="New Clicker"></ion-input>
</ion-item>
</ion-col>
<ion-col>
<button ion-button type="submit" block secondary outline>
<ion-icon name="add-circle"></ion-icon>
</button>
</ion-col>
</ion-row>
</form>

View File

@ -1,44 +0,0 @@
import { FormBuilder } from '@angular/forms';
import { ComponentFixture, async } from '@angular/core/testing';
import { TestUtils } from '../../test';
import { ClickerForm } from './clickerForm';
let fixture: ComponentFixture<ClickerForm> = null;
let instance: any = null;
describe('ClickerForm', () => {
beforeEach(async(() => TestUtils.beforeEachCompiler([ClickerForm]).then(compiled => {
fixture = compiled.fixture;
instance = compiled.instance;
instance.clicker = { name: 'TEST CLICKER' };
instance.clicker.getCount = function(): number { return 10; };
fixture.autoDetectChanges(true);
})));
afterEach(() => {
fixture.destroy();
});
it('initialises', () => {
expect(fixture).not.toBeNull();
expect(instance).not.toBeNull();
});
it('passes new clicker through to service', () => {
let clickerName: string = 'dave';
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', () => {
spyOn(instance['clickerService'], 'newClicker').and.callThrough();
instance.newClicker({});
expect(instance['clickerService'].newClicker).not.toHaveBeenCalled();
});
});

View File

@ -1,41 +0,0 @@
'use strict';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Component } from '@angular/core';
import { ClickersService } from '../../services';
@Component({
selector: 'clicker-form',
templateUrl: './clickerForm.html',
})
export class ClickerForm {
private clickerService: ClickersService;
public form: FormGroup;
constructor(clickerService: ClickersService, fb: FormBuilder) {
this.clickerService = clickerService;
this.form = fb.group({
clickerNameInput: ['', Validators.required],
});
}
public newClicker(formValue: Object): boolean {
// need to mark the clickerName control as touched so validation
// will apply after the user has tried to add a clicker
this.form.controls['clickerNameInput'].markAsTouched();
if (!this.form.controls['clickerNameInput'].valid) {
return false;
}
this.clickerService.newClicker(formValue['clickerNameInput']);
this.form.reset();
return true;
}
}

View File

@ -1,13 +1,9 @@
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from 'ionic-angular';
import { ClickerButton } from './clickerButton/clickerButton';
import { ClickerForm } from './clickerForm/clickerForm';
@NgModule({
declarations: [
ClickerForm,
ClickerButton,
],
imports: [
FormsModule,
@ -15,8 +11,6 @@ import { ClickerForm } from './clickerForm/clickerForm';
ReactiveFormsModule,
],
exports: [
ClickerButton,
ClickerForm,
],
entryComponents: [],
providers: [ ],

View File

@ -1,3 +1 @@
export * from './clickerButton/clickerButton';
export * from './clickerForm/clickerForm';
export * from './components.module';

View File

@ -0,0 +1,3 @@
.blocksPage {
}

View File

@ -1,14 +1,13 @@
import { ComponentFixture, async } from '@angular/core/testing';
import { TestUtils } from '../../test';
import { ClickerList } from './clickerList';
import { ClickerButton, ClickerForm } from '../../components';
import { BlocksPage } from './blocksPage';
let fixture: ComponentFixture<ClickerList> = null;
let fixture: ComponentFixture<BlocksPage> = null;
let instance: any = null;
describe('ClickerList', () => {
describe('Blocks', () => {
beforeEach(async(() => TestUtils.beforeEachCompiler([ClickerList, ClickerForm, ClickerButton]).then(compiled => {
beforeEach(async(() => TestUtils.beforeEachCompiler([BlocksPage]).then(compiled => {
fixture = compiled.fixture;
instance = compiled.instance;
fixture.detectChanges();
@ -18,7 +17,7 @@ describe('ClickerList', () => {
fixture.destroy();
});
it('initialises', () => {
it('initializes', () => {
expect(instance).toBeTruthy();
});
});

View File

@ -1,21 +1,18 @@
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { ClickersService } from '../../services';
@Component({
templateUrl: './clickerList.html',
templateUrl: './blocksPage.html',
})
export class ClickerList {
export class BlocksPage {
public clickerService: ClickersService;
public title: string;
private nav: NavController;
private blocks: any;
constructor(nav: NavController, clickerService: ClickersService) {
constructor(nav: NavController) {
this.nav = nav;
this.clickerService = clickerService;
this.title = 'Blocks';
this.blocks = [{"height":471569,"size":999095,"hash":"00000000000000000007bf61c6cf9efbb1353b919621768b553bd1ffb2948240","time":1497633772,"txlength":2561,"poolInfo":{}},{"height":471568,"size":999994,"hash":"000000000000000000fc2c10f1b4e55c9b86b8f9e804dc66683312b7d7d955dd","time":1497632268,"txlength":2011,"poolInfo":{}},{"height":471567,"size":989172,"hash":"000000000000000000d70effc2ec625999960bd7929d7a4298124456ecb29c23","time":1497632133,"txlength":1651,"poolInfo":{"poolName":"BTCC Pool","url":"https://pool.btcc.com/"}},{"height":471566,"size":998155,"hash":"00000000000000000127cbc53d017400eb9d17122a8ae36986c077ac7eea25fe","time":1497629915,"txlength":1130,"poolInfo":{"poolName":"AntMiner","url":"https://bitmaintech.com/"}},{"height":471565,"size":998103,"hash":"00000000000000000045844f32f6e9fc6e7575bb96eb71a9ce9fba2849892d5e","time":1497629731,"txlength":1986,"poolInfo":{}},{"height":471564,"size":998101,"hash":"0000000000000000009a5b3fc7ac517f8a275be73f4492adb0cb88943f5c1b9e","time":1497629348,"txlength":2378,"poolInfo":{}},{"height":471563,"size":998258,"hash":"00000000000000000048a5506f3415fcf790106a838953e04d86d8f2583ebd6a","time":1497628552,"txlength":1481,"poolInfo":{"poolName":"AntMiner","url":"https://bitmaintech.com/"}},{"height":471562,"size":998257,"hash":"0000000000000000016f6a483730bd9c1c48c8345782b8365762592a475aa330","time":1497628159,"txlength":646,"poolInfo":{"poolName":"AntMiner","url":"https://bitmaintech.com/"}},{"height":471561,"size":999016,"hash":"000000000000000001434fb0e5cc5e521de59bff70c325185a5c67bd5418c61a","time":1497627986,"txlength":1831,"poolInfo":{}},{"height":471560,"size":998229,"hash":"000000000000000000a1782a9d78672672e4291347c47ac3206ed8716bb4952b","time":1497627524,"txlength":791,"poolInfo":{"poolName":"SlushPool","url":"https://slushpool.com/"}},{"height":471559,"size":999152,"hash":"000000000000000000d58ba85b2ddedc1f467b1e1c49c47cf62d4d970dad7ab5","time":1497627347,"txlength":87,"poolInfo":{}},{"height":471558,"size":778220,"hash":"0000000000000000009a4e72a1863e42fdfe1e08e6d547d4528049065d69454c","time":1497627287,"txlength":1685,"poolInfo":{"poolName":"BTCC Pool","url":"https://pool.btcc.com/"}},{"height":471557,"size":707456,"hash":"00000000000000000068a8adc72fc41299105053e6059a3f6dcd2e0dc2fd2fcb","time":1497626859,"txlength":1661,"poolInfo":{"poolName":"BTCC Pool","url":"https://pool.btcc.com/"}}];
}

View File

@ -7,7 +7,6 @@
</ion-navbar>
</ion-header>
<ion-content padding class="message">
<button ion-button (click)="showSimpleAlert()">Show Simple Alert</button>
<button ion-button (click)="showMoreAdvancedAlert()">Show More Advanced Alert</button>
<ion-content padding>
<h1>Broadcast Transaction</h1>
</ion-content>

View File

@ -0,0 +1,3 @@
.broadcastTxPage {
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, async } from '@angular/core/testing';
import { TestUtils } from '../../test';
import { BroadcastTxPage } from './broadcastTxPage';
let fixture: ComponentFixture<BroadcastTxPage> = null;
let instance: any = null;
describe('BroadcastTxPage', () => {
beforeEach(async(() => TestUtils.beforeEachCompiler([BroadcastTxPage]).then(compiled => {
fixture = compiled.fixture;
instance = compiled.instance;
fixture.detectChanges();
})));
afterEach(() => {
fixture.destroy();
});
it('initializes', () => {
expect(instance).toBeTruthy();
});
});

View File

@ -0,0 +1,17 @@
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
@Component({
templateUrl: './broadcastTxPage.html',
})
export class BroadcastTxPage {
public title: string;
private nav: NavController;
constructor(nav: NavController) {
this.nav = nav;
this.title = 'Broadcast Transaction';
}
}

View File

@ -1,3 +0,0 @@
.clickerList {
}

View File

@ -1,3 +1,5 @@
export * from './clickerList/clickerList';
export * from './page2/page2';
export * from './blocksPage/blocksPage';
export * from './broadcastTxPage/broadcastTxPage';
export * from './nodeStatusPage/nodeStatusPage';
export * from './verifyMessagePage/verifyMessagePage';
export * from './pages.module';

View File

@ -0,0 +1,12 @@
<ion-header>
<ion-navbar color="primary">
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>{{title}}</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<h1>Node Status</h1>
</ion-content>

View File

@ -0,0 +1,3 @@
.nodeStatusPage {
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, async } from '@angular/core/testing';
import { TestUtils } from '../../test';
import { NodeStatusPage } from './nodeStatusPage';
let fixture: ComponentFixture<NodeStatusPage> = null;
let instance: any = null;
describe('NodeStatusPage', () => {
beforeEach(async(() => TestUtils.beforeEachCompiler([NodeStatusPage]).then(compiled => {
fixture = compiled.fixture;
instance = compiled.instance;
fixture.detectChanges();
})));
afterEach(() => {
fixture.destroy();
});
it('initializes', () => {
expect(instance).toBeTruthy();
});
});

View File

@ -0,0 +1,17 @@
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
@Component({
templateUrl: './nodeStatusPage.html',
})
export class NodeStatusPage {
public title: string;
private nav: NavController;
constructor(nav: NavController) {
this.nav = nav;
this.title = 'Node Status';
}
}

View File

@ -1,3 +0,0 @@
.page2 {
}

View File

@ -1,95 +0,0 @@
import { async, fakeAsync, tick, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { App, Config, Form, IonicModule, Keyboard, DomController, MenuController, NavController, Platform, AlertController } from 'ionic-angular';
import { ConfigMock, PlatformMock, AlertControllerMock } from '../../mocks';
import { Page2 } from './page2';
const alertControllerMock: AlertController = AlertControllerMock.instance();
let fixture: ComponentFixture<Page2> = null;
let instance: any = null;
let alertSpy: any;
let alertControllerSpy: any;
describe('Pages: Page2', () => {
// demonstration on how to manually compile the test bed (as opposed to calling TestUtils)
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [Page2],
providers: [
App, DomController, Form, Keyboard, MenuController, NavController,
{provide: Config, useClass: ConfigMock},
{provide: Platform, useClass: PlatformMock},
{provide: AlertController, useValue: alertControllerMock},
],
imports: [
FormsModule,
IonicModule,
ReactiveFormsModule,
],
})
.compileComponents().then(() => {
fixture = TestBed.createComponent(Page2);
instance = fixture;
fixture.detectChanges();
fixture.componentInstance.onGainChange();
alertSpy = fixture.componentInstance.alertController;
alertControllerSpy = fixture.componentInstance.alertController.create();
});
}));
afterEach(() => {
fixture.destroy();
});
it('should create page2', () => {
expect(fixture).toBeTruthy();
expect(instance).toBeTruthy();
});
it('should fire the simple alert', fakeAsync(() => {
alertSpy.create.calls.reset();
alertControllerSpy.present.calls.reset();
expect(alertSpy.create).not.toHaveBeenCalledTimes(1);
expect(alertControllerSpy.present).not.toHaveBeenCalledTimes(1);
expect(alertSpy.create).not.toHaveBeenCalled();
expect(alertControllerSpy.present).not.toHaveBeenCalled();
fixture.componentInstance.showSimpleAlert();
tick();
expect(alertSpy.create).toHaveBeenCalledTimes(1);
expect(alertControllerSpy.present).toHaveBeenCalledTimes(1);
expect(alertSpy.create).toHaveBeenCalled();
expect(alertControllerSpy.present).toHaveBeenCalled();
}));
it('should fire the more advanced alert', fakeAsync(() => {
alertSpy.create.calls.reset();
alertControllerSpy.present.calls.reset();
fixture.componentInstance.okEd = false;
expect(fixture.componentInstance.okEd).toBeFalsy();
fixture.componentInstance.showMoreAdvancedAlert();
tick();
fixture.componentInstance.OK();
expect(fixture.componentInstance.okEd).toBeTruthy();
}));
});

View File

@ -1,55 +0,0 @@
'use strict';
import { Component } from '@angular/core';
import { Alert, AlertController } from 'ionic-angular';
@Component({
templateUrl: './page2.html',
})
export class Page2 {
public okEd: boolean;
public alert1: Alert;
public alertController: AlertController;
constructor(alertController: AlertController) {
this.alertController = alertController;
};
public title: string = 'Page 2';
public onGainChange(): void {
return;
}
public showSimpleAlert(): any {
this.alert1 = this.alertController.create({
title: 'This is an example for an alert',
buttons: ['Ok', 'Dismiss'],
});
this.alert1.present();
}
public showMoreAdvancedAlert(): any {
this.alert1 = this.alertController.create({
title: 'This is an example for an alert',
buttons: [{
text: 'More Advanced Ok',
handler: this.OK,
}
, 'Dismiss'],
});
this.alert1.present();
}
public OK = () => {
this.okEd = true;
}
}

View File

@ -1,18 +1,23 @@
import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { ComponentsModule } from '../components';
import { ClickerList } from './clickerList/clickerList';
import { Page2 } from './page2/page2';
import {
BlocksPage,
BroadcastTxPage,
NodeStatusPage,
VerifyMessagePage,
} from './index';
@NgModule({
declarations: [
ClickerList,
Page2,
BlocksPage,
BroadcastTxPage,
NodeStatusPage,
VerifyMessagePage,
],
imports: [ IonicModule, ComponentsModule ],
exports: [
ClickerList,
// Page2,
// CustomComponent,
],
entryComponents: [],
providers: [ ],

View File

@ -0,0 +1,12 @@
<ion-header>
<ion-navbar color="primary">
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>{{title}}</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<h1>Verify Signed Message</h1>
</ion-content>

View File

@ -0,0 +1,3 @@
.verifyMessagePage {
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, async } from '@angular/core/testing';
import { TestUtils } from '../../test';
import { VerifyMessagePage } from './verifyMessagePage';
let fixture: ComponentFixture<VerifyMessagePage> = null;
let instance: any = null;
describe('VerifyMessagePage', () => {
beforeEach(async(() => TestUtils.beforeEachCompiler([VerifyMessagePage]).then(compiled => {
fixture = compiled.fixture;
instance = compiled.instance;
fixture.detectChanges();
})));
afterEach(() => {
fixture.destroy();
});
it('initializes', () => {
expect(instance).toBeTruthy();
});
});

View File

@ -0,0 +1,17 @@
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
@Component({
templateUrl: './verifyMessagePage.html',
})
export class VerifyMessagePage {
public title: string;
private nav: NavController;
constructor(nav: NavController) {
this.nav = nav;
this.title = 'Verify Message';
}
}

View File

@ -10,7 +10,7 @@ import 'zone.js/dist/fake-async-test';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { getTestBed, TestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
import { App, Config, Form, IonicModule, Keyboard, DomController, MenuController, NavController, Platform } from 'ionic-angular';
import { App, Config, Form, IonicModule, Keyboard, DomController, MenuController, NavController, Platform, GestureController } from 'ionic-angular';
import { ConfigMock, PlatformMock } from './mocks';
import { ClickersServiceMock } from './services/clickers.mock';
import { ClickersService } from './services';
@ -55,7 +55,7 @@ export class TestUtils {
...components,
],
providers: [
App, Form, Keyboard, DomController, MenuController, NavController,
App, Form, Keyboard, DomController, MenuController, NavController, GestureController,
{provide: Platform, useClass: PlatformMock},
{provide: Config, useClass: ConfigMock},
{provide: ClickersService, useClass: ClickersServiceMock},