Testing ionic 2 apps

@swarner answer referencing the angular2-webpack-starter is good, you could just copy and paste the configs into Ionic and start writing the tests with the examples in that repo, i would just like to understand how that webpack.test.config.js was made.

Someone give this guy a cookie

5 Likes

be sure to change the package.json and set the dependencies to the exact version (remove the ^ from the version), otherwise npm install will complain about unmet dependancies :slightly_smiling:

I’ve written a tutorial http://lathonez.com/2016/ionic-2-unit-testing/ based on the clicker repo.

3 Likes

Thanks for your tutorial, @lathonez. I’m going through it, trying to add testing to a new ionic (beta3) app.

I get to the “Install Dependencies and Typings” section and run the command “node_modules/gulp/bin/gulp.js --gulpfile test/gulpfile.ts --cwd ./ test.build”.

But the following errors happen (note: this is a clean install of the “blank” template). Any suggestions?

$ node_modules/gulp/bin/gulp.js --gulpfile test/gulpfile.ts --cwd ./ test.build
[09:59:36] Requiring external module ts-node/register
TSError: ⨯ Unable to compile TypeScript
node_modules/angular2/src/facade/promise.d.ts (1,10): Cannot re-export name that is not defined in the module. (2661)
typings/browser/ambient/es6-shim/es6-shim.d.ts (8,14): Duplicate identifier 'PropertyKey'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (11,5): Duplicate identifier 'done'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (12,5): Duplicate identifier 'value'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (250,5): Duplicate identifier 'EPSILON'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (285,5): Duplicate identifier 'MAX_SAFE_INTEGER'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (292,5): Duplicate identifier 'MIN_SAFE_INTEGER'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (348,5): Duplicate identifier 'flags'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (500,5): Duplicate identifier 'prototype'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (563,5): Duplicate identifier 'size'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (572,5): Duplicate identifier 'prototype'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (583,5): Duplicate identifier 'size'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (592,5): Duplicate identifier 'prototype'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (607,5): Duplicate identifier 'prototype'. (2300)
typings/browser/ambient/es6-shim/es6-shim.d.ts (621,5): Duplicate identifier 'prototype'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (8,14): Duplicate identifier 'PropertyKey'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (11,5): Duplicate identifier 'done'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (12,5): Duplicate identifier 'value'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (250,5): Duplicate identifier 'EPSILON'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (285,5): Duplicate identifier 'MAX_SAFE_INTEGER'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (292,5): Duplicate identifier 'MIN_SAFE_INTEGER'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (348,5): Duplicate identifier 'flags'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (500,5): Duplicate identifier 'prototype'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (563,5): Duplicate identifier 'size'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (572,5): Duplicate identifier 'prototype'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (583,5): Duplicate identifier 'size'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (592,5): Duplicate identifier 'prototype'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (607,5): Duplicate identifier 'prototype'. (2300)
typings/browser/ambient/es6-shim/index.d.ts (621,5): Duplicate identifier 'prototype'. (2300)
    at getOutput (/Users/lehresman/Projects/gazelle-mobile/node_modules/ts-node/src/ts-node.ts:209:13)
    at Object.loader (/Users/lehresman/Projects/gazelle-mobile/node_modules/ts-node/src/ts-node.ts:235:23)
    at Module.load (module.js:345:32)
    at Function.Module._load (module.js:302:12)
    at Module.require (module.js:355:17)
    at require (internal/module.js:13:17)
    at Liftoff.handleArguments (/Users/lehresman/Projects/gazelle-mobile/node_modules/gulp/bin/gulp.js:116:3)
    at Liftoff.<anonymous> (/Users/lehresman/Projects/gazelle-mobile/node_modules/liftoff/index.js:192:16)
    at module.exports (/Users/lehresman/Projects/gazelle-mobile/node_modules/flagged-respawn/index.js:17:3)
    at Liftoff.<anonymous> (/Users/lehresman/Projects/gazelle-mobile/node_modules/liftoff/index.js:185:9)

Nevermind. Upgrading to angular2@2.0.0-beta.7 fixed it.

Good news. If there’s anything else, raise an issue on my repo rather than here. I just don’t want to clog up Ionic forums with problems particular to our setup.

Thanks!

Hi, I’m getting the same output. How did you upgrade your angular?

You can upgrade your angular by editing the version in packages.json then running “npm install”.

Thank you. I needed to update ‘rxjs’ and ‘zone.js’ too.

Thanks, @lathonez! I’ve based all my testing code on your clicker repo code and it all works wonderfully - you have probably saved me tons of hours in getting testing + typescript + angular2 + ionic2 + coverage + … integrated.

I recently ran into a problem as soon as we had to add the line ‘import es6-shim’ to app.ts, as was recommended in this forum post (and as was needed otherwise I got errors, after starting to use the new ionic2 build process).

This causes PhantomJS to break with a 404 error complaining it cannot find ‘/base/es6-shim.js’.

The following fix worked (a fix to the clicker testing code, which is what I use, almost verbatum and which is in this repository.

Just change the file karma.config.js in two places:

  1. Add this line to the files: section:

    ‘node_modules/es6-shim/es6-shim.js’

  2. Add this line to the proxies: section:

    ‘/base/es6-shim.js’: ‘/base/node_modules/es6-shim/es6-shim.js’

1 Like

Cool I’m really glad you found it helpful.

I’ve done my best to explain how to test external modules on the blog post, see ‘Testing External Modules’, there are also a few good worked examples in the FAQ.

FWIW I think having to wrestle with this karma config each time you add a new module is the worst part of the set up. Recently I’ve found a good alternative, which is bundling the spec (and all external dependencies) together, in the same way as Ionic does in app.bundle.js.

I’ve got a proof of concept for this on a branch and am looking to merge it back and update the blog post this week.

I would like to see a version without TypeScript. Is there something you are willing to provide? I can help you out with this one, because there is no good resource about this.
Thanks for sharing!

If you think a version without Typescript would be useful I’d encourage you to fork and document. I’ll be happy to provide advice if I am able but am not interested in contributing.

Personally I’m happy to stick with Typescript and would rather further it’s userbase.

The site https://www.joshmorony.com/how-to-unit-test-an-ionic-2-application/ was extremely helpful for me. It references Lathonez’s work. I remember spending weeks on this back in Ionic alpha days. Now it takes just minutes!

1 Like

Glad you found Josh’s post helpful, it’s definitely more accessible than what I’ve written!

Hi everyone. Maybe some one can help me with test service, that include third party library (pouchDB)?

I’m use lathonez clicker app as base.

Typings for pouchDB installed in node_modules. App works correct, but when I try to test service with pouchDB I receive an error:

TypeError: pouchdb_1.default is not a constructor

And console.log show in terminal, that pouchDB is undefined. I think that test missing typings for pouchDB, but can’t figure out how to include it correctly.

Service example:

'use strict';

import PouchDB from 'pouchdb';
import quickSearch from 'pouchdb-quick-search';
import PouchDbFind from 'pouchdb-find';

PouchDB.plugin(quickSearch);
PouchDB.plugin(PouchDbFind);

import { Injectable } from '@angular/core';
import { CONSTANTS } from '../../constants';

@Injectable()
export class PouchDbService {
    private animalsDb: any = new PouchDB(CONSTANTS.dataBaseName); // this line throw error
    private searchFields: string[] = ['DE_Name', 'EN_Name'];

    public search(query: string): Promise<any> {
        return this.animalsDb.search({
            query: query,
            include_docs: true,
            mm: '50%',
            fields: this.searchFields
        });
    }
}
1 Like

Did you find a solution?

1 ) I switched on ionic2-boilerplate (Sorry, lathonez, your repo is great too, but I need a fast solution at that time).
2) Then I faced webpack issue with lie library (process is not defined)
3) I change script in package.json

"post-install": "gulp rm_broken_lie; webdriver-manager update"
  1. Add gulp and del to project with npm and gulp task to remove all broken lie library
var gulp = require('gulp'),
    del = require('del');

gulp.task('rm_broken_lie', done => {
    del('node_modules/pouchdb-quick-search/node_modules/pouchdb-promise/node_modules/lie')
        .then(() => del('node_modules/pouchdb-quick-search/node_modules/lie'))
        .then(() => del('node_modules/pouchdb-mapreduce-no-ddocs/node_modules/lie'))
        .then(() => del('node_modules/pouchdb-utils/node_modules/lie'))
        .then(() => del('node_modules/pouchdb-promise/node_modules/lie'))
        .then(() => del('node_modules/pouchdb-upsert/node_modules/lie'))
        .then(() => done());
});
  1. Fork lie, fix it and use in package.json
"lie": "https://github.com/EugeneSnihovsky/lie.git",
  1. In src/declarations.d.ts add
declare module 'pouchdb-quick-search' {
    const plugin: PouchDB.Plugin;
    export = plugin;
}
declare module 'pouchdb-find' {
    const plugin: PouchDB.Plugin;
    export = plugin;
}
  1. and in service
import * as PouchDB from 'pouchdb';
import * as quickSearch from 'pouchdb-quick-search';
import * as PouchDbFind from 'pouchdb-find';

PouchDB.plugin(quickSearch);
PouchDB.plugin(PouchDbFind);
  1. In test
import * as PouchDB from 'pouchdb';

// other logic and imports

beforeEach(() => {
        spyOn(PouchDB, 'plugin').and.callFake((a) => {});
    });


Hey you should probably have a look at:

and read this really helpful blog post: roblouie | Ionic 2 Unit Testing Setup: The Best Way