Repository: ionic-team/ionic-unit-testing-example
Branch: master
Commit: b4ee3f57d908
Files: 37
Total size: 31.9 KB
Directory structure:
gitextract_xporx_uk/
├── .editorconfig
├── .gitignore
├── LICENSE
├── README.md
├── config.xml
├── e2e/
│ ├── app.e2e-spec.ts
│ ├── app.po.ts
│ └── tsconfig.e2e.json
├── ionic.config.json
├── package.json
├── src/
│ ├── app/
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.html
│ │ ├── app.module.ts
│ │ ├── app.scss
│ │ └── main.ts
│ ├── index.html
│ ├── manifest.json
│ ├── pages/
│ │ ├── page1/
│ │ │ ├── page1.html
│ │ │ ├── page1.module.ts
│ │ │ ├── page1.scss
│ │ │ ├── page1.spec.ts
│ │ │ └── page1.ts
│ │ └── page2/
│ │ ├── page2.html
│ │ ├── page2.module.ts
│ │ ├── page2.scss
│ │ └── page2.ts
│ ├── service-worker.js
│ └── theme/
│ └── variables.scss
├── test-config/
│ ├── karma-test-shim.js
│ ├── karma.conf.js
│ ├── mocks-ionic.ts
│ ├── protractor.conf.js
│ └── webpack.test.js
├── tsconfig.json
├── tslint.json
└── typings/
└── cordova-typings.d.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
# EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
================================================
FILE: .gitignore
================================================
# Specifies intentionally untracked files to ignore when using Git
# http://git-scm.com/docs/gitignore
*~
*.sw[mnpcod]
*.log
*.tmp
*.tmp.*
log.txt
*.sublime-project
*.sublime-workspace
.vscode/
npm-debug.log*
.idea/
.sass-cache/
.tmp/
.versions/
coverage/
dist/
node_modules/
tmp/
temp/
hooks/
platforms/
plugins/
plugins/android.json
plugins/ios.json
www/
$RECYCLE.BIN/
.DS_Store
Thumbs.db
UserInterfaceState.xcuserstate
\.sourcemaps/
================================================
FILE: LICENSE
================================================
Copyright 2015-present Drifty Co.
http://drifty.com/
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
> **2018-03-28:** We have a [pull request for updating to Karma 2](https://github.com/ionic-team/ionic-unit-testing-example/pull/87) awaiting review. If you can take the time to install this update and let us know if it works for you, that would be very helpful. Comments are welcome!
# Ionic Unit Testing Example
**This repository is an example project that gives guidance on setting up your Ionic application for unit testing and end-to-end (E2E) testing.** We have been told the folks at Ionic will be adding testing features to new projects in the future. But until then, feel free to borrow from this project as needed.
Special thanks to all of the contributors. With the exception of the Ionic team's updates to the framework, this project is stable. If you have a suggestion, feel free to update code and make a pull request. Find a problem or bug, feel free to file a detailed issue.
## How to Configure Your Ionic Application for Testing
Read [this tutorial](https://leifwells.github.io/2017/08/27/testing-in-ionic-configure-existing-projects-for-testing/) for instructions on how to apply the testing configuration in this project to your own project.
## Mocking Classes for Ionic
When a developer unit tests a component, the objective is to isolate that component as much as possible. In the case of an Ionic page, you may have Ionic components like `NavController`, `LoadingContoller`, or `Platform`. Adding these components means adding pieces of the Ionic framework to your test, thus not isolating the component. As part of this example, the file `test-config/mocks-ionic.ts` is provided for creating simple mocks for many of the classes in Ionic that you may need. You may use the classes from this file in test files inside the `TestBed.configureComponent()` method argument's `provider` array as seen in our [example unit test file](https://github.com/ionic-team/ionic-unit-testing-example/blob/master/src/app/app.component.spec.ts).
There are other mocking options that should be mentioned:
**[ionic-mocks](https://github.com/stonelasley/ionic-mocks)**
**[ionic-test-doubles](https://github.com/DomesticApp/ionic-test-doubles)**
Also worth mentioning is [ionic-native-mocks](https://github.com/chrisgriffith/ionic-native-mocks) which can be helpful when mocks for Ionic Native classes used in your project are needed.
Getting Started with this Project
-----------
To get started, clone this repo, and run `npm install` in the root directory.
```sh
git clone https://github.com/ionic-team/ionic-unit-testing-example.git
cd ionic-unit-testing-example
npm install
```
Then, you should run `ionic serve` to make sure the project loads.
### Unit Tests
To run the tests, run `npm run test`.
See the example test in `src/app/app.component.spec.ts` for an example of a component test.
### End-To-End Tests (Browser-Only)
To serve the app, run `ionic serve`.
To run the end-to-end tests, run (while the app is being served) `npm run e2e`.
See the example end-to-end test in `e2e/app.e2e-spec.ts`.
UPDATES:
--------
### **2018-02-25: Updated to Ionic 3.9.2**
Updated project to use the latest version Ionic and dependencies. Take a look at the [`package.json`](https://github.com/ionic-team/ionic-unit-testing-example/blob/master/package.json) for more details.
### **2017-09-05: Added Code Coverage Functionality**
Thanks to @lathonez, we now have functioning code coverage functionality. With this update, developers can run `npm run test-coverage` which will run the project's unit tests with Karma and produce documentation that gives guidance on how well the project's tests cover the code.

The documentation is created inside the `/coverage` folder (ignored by git).
## Looking for Version 2?
If you are using Ionic v2, please see our [ionic-v2-branch](https://github.com/ionic-team/ionic-unit-testing-example/tree/ionic-v2-branch).
## Credits
This repository is based on the awesome [unit testing example](https://github.com/roblouie/unit-testing-demo) from [@roblouie](https://github.com/roblouie/) :thumbsup:
Past Updates
==========
### **2017-08-26: Update to `ionic-angular` version 3.6.0**
We updated the project to `ionic-angular` version `3.6.0`. Developers wishing to use this should also update Ionic CLI for a better experience. With today's update, this project is now at version `0.0.5`.
## **Added: Fix for assets not being found by Karma**
Thanks to [@datencia](https://github.com/datencia) for providing an update to our Karma configuration that properly sets the Karma base path so that image assets can be found during testing. This fix should also work any JSON data files you might want to use for testing. He also provided an image and updated our sample unit test spec file that tests that the image is found.
#### **Added: Update code to match Ionic templates**
Thanks (again) to [@danielsogl](https://github.com/danielsogl/) for providing a code update to the project so that our code matches code created by using the `ionic start` command. Having this code properly match is important as it provides the best practice guidance for handling application start up.
#### *2017-05-28: Update to Version 3.3.0*
Thanks to [@danielsogl](https://github.com/danielsogl/) for getting us up-to-date with Ionic 3.3.0, Angular 4.1.2 and Ionic Native 3.10.2.
Thanks to [@johnstonbl01](https://github.com/johnstonbl01/) for adding a couple of mocks that prevent us from seeing some unnecessary warning messages.
#### *2017-05-12: Update to Version 3*
We've updated this repo to use Ionic v3.2.1 and Ionic CLI v3.0.0.
If you already have this repository downloaded on your system, after you sync with our Master branch make certain you delete your `node_modules` folder and then run `npm install`.
Also, since we've updated to Ionic CLI v3.0.0, you will need to update your version as well:
```
npm remove -g ionic
npm install -g ionic
```
If you run `ionic -v` it should return `3.0.0` (or better, depending on what has been released.
================================================
FILE: config.xml
================================================
Ionic Unit and E2E TestsAn awesome Ionic/Cordova app.Ionic Framework Team
================================================
FILE: e2e/app.e2e-spec.ts
================================================
import { Page } from './app.po';
describe('App', () => {
let page: Page;
beforeEach(() => {
page = new Page();
});
describe('default screen', () => {
beforeEach(() => {
page.navigateTo('/');
});
it('should have a title saying Page One', () => {
page.getPageOneTitleText().then(title => {
expect(title).toEqual('Page One');
});
});
})
});
================================================
FILE: e2e/app.po.ts
================================================
import { browser, by, element } from 'protractor';
export class Page {
navigateTo(destination) {
return browser.get(destination);
}
getTitle() {
return browser.getTitle();
}
getPageOneTitleText() {
return element(by.tagName('page-page1')).element(by.tagName('ion-title')).element(by.css('.toolbar-title')).getText();
}
}
================================================
FILE: e2e/tsconfig.e2e.json
================================================
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"typeRoots": [
"../node_modules/@types"
]
}
}
================================================
FILE: ionic.config.json
================================================
{
"name": "ionic-unit-testing-example",
"app_id": "",
"type": "ionic-angular",
"integrations": {}
}
================================================
FILE: package.json
================================================
{
"name": "ionic-unit-testing-example",
"author": "Ionic Framework",
"homepage": "https://ionicframework.com/",
"private": true,
"scripts": {
"clean": "ionic-app-scripts clean",
"build": "ionic-app-scripts build",
"ionic:build": "ionic-app-scripts build",
"ionic:serve": "ionic-app-scripts serve",
"test": "karma start ./test-config/karma.conf.js",
"test-ci": "karma start ./test-config/karma.conf.js --single-run",
"test-coverage": "karma start ./test-config/karma.conf.js --coverage",
"e2e": "npm run e2e-update && npm run e2e-test",
"e2e-test": "protractor ./test-config/protractor.conf.js",
"e2e-update": "webdriver-manager update --standalone false --gecko false"
},
"dependencies": {
"@angular/common": "5.0.3",
"@angular/compiler": "5.0.3",
"@angular/compiler-cli": "5.0.3",
"@angular/core": "5.0.3",
"@angular/forms": "5.0.3",
"@angular/http": "5.0.3",
"@angular/platform-browser": "5.0.3",
"@angular/platform-browser-dynamic": "5.0.3",
"@ionic-native/core": "4.4.0",
"@ionic-native/splash-screen": "4.4.0",
"@ionic-native/status-bar": "4.4.0",
"@ionic/storage": "2.1.3",
"ionic-angular": "3.9.2",
"ionicons": "3.0.0",
"rxjs": "5.5.2",
"sw-toolbox": "3.6.0",
"zone.js": "0.8.18"
},
"devDependencies": {
"@angular/cli": "1.4.8",
"@ionic/app-scripts": "3.1.8",
"@types/jasmine": "^2.5.41",
"@types/node": "^8.0.45",
"angular2-template-loader": "^0.6.2",
"html-loader": "^0.5.1",
"istanbul-instrumenter-loader": "^3.0.0",
"jasmine": "^2.5.3",
"jasmine-spec-reporter": "^4.1.0",
"karma": "^1.5.0",
"karma-chrome-launcher": "^2.0.0",
"karma-coverage-istanbul-reporter": "^1.3.0",
"karma-jasmine": "^1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^2.0.3",
"null-loader": "^0.1.1",
"protractor": "^5.1.1",
"ts-loader": "^3.0.3",
"ts-node": "^3.0.2",
"typescript": "2.4.2"
},
"version": "0.0.7",
"description": "An Ionic project"
}
================================================
FILE: src/app/app.component.spec.ts
================================================
import { async, TestBed } from '@angular/core/testing';
import { IonicModule, Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { MyApp } from './app.component';
import {
PlatformMock,
StatusBarMock,
SplashScreenMock
} from '../../test-config/mocks-ionic';
describe('MyApp Component', () => {
let fixture;
let component;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [MyApp],
imports: [
IonicModule.forRoot(MyApp)
],
providers: [
{ provide: StatusBar, useClass: StatusBarMock },
{ provide: SplashScreen, useClass: SplashScreenMock },
{ provide: Platform, useClass: PlatformMock }
]
})
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyApp);
component = fixture.componentInstance;
});
it('should be created', () => {
expect(component instanceof MyApp).toBe(true);
});
it('should have two pages', () => {
expect(component.pages.length).toBe(2);
});
});
================================================
FILE: src/app/app.component.ts
================================================
import { Component, ViewChild } from '@angular/core';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';
import { Nav, Platform } from 'ionic-angular';
@Component({
templateUrl: 'app.html'
})
export class MyApp {
@ViewChild(Nav) nav: Nav;
rootPage: any = 'Page1';
pages: Array<{ title: string, component: any }>;
constructor(public platform: Platform, public statusBar: StatusBar, public splashScreen: SplashScreen) {
// used for an example of ngFor and navigation
this.pages = [
{ title: 'Page One', component: 'Page1' },
{ title: 'Page Two', component: 'Page2' }
];
}
ionViewDidLoad() {
this.platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
this.statusBar.styleDefault();
this.splashScreen.hide();
});
}
openPage(page) {
// Reset the content nav to have just this page
// we wouldn't want the back button to show in this scenario
this.nav.setRoot(page.component);
}
}
================================================
FILE: src/app/app.html
================================================
Menu
================================================
FILE: src/app/app.module.ts
================================================
import { ErrorHandler, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
@NgModule({
declarations: [
MyApp
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp
],
providers: [
StatusBar,
SplashScreen,
{ provide: ErrorHandler, useClass: IonicErrorHandler }
]
})
export class AppModule { }
================================================
FILE: src/app/app.scss
================================================
// http://ionicframework.com/docs/v2/theming/
// App Global Sass
// --------------------------------------------------
// Put style rules here that you want to apply globally. These
// styles are for the entire app and not just one component.
// Additionally, this file can be also used as an entry point
// to import other Sass files to be included in the output CSS.
//
// Shared Sass variables, which can be used to adjust Ionic's
// default Sass variables, belong in "theme/variables.scss".
//
// To declare rules for a specific mode, create a child rule
// for the .md, .ios, or .wp mode classes. The mode class is
// automatically applied to the
element in the app.
================================================
FILE: src/app/main.ts
================================================
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
================================================
FILE: src/index.html
================================================
Ionic App
================================================
FILE: src/manifest.json
================================================
{
"name": "Ionic",
"short_name": "Ionic",
"start_url": "index.html",
"display": "standalone",
"icons": [{
"src": "assets/imgs/logo.png",
"sizes": "512x512",
"type": "image/png"
}],
"background_color": "#4e8ef7",
"theme_color": "#4e8ef7"
}
================================================
FILE: src/pages/page1/page1.html
================================================
Page One