Automating Mocks in Ionic Native 3.x

Automating Mocks in Ionic Native 3.x

Follow Josh Morony on

With the release of Ionic Native 3.x we are now able to create mocks for Ionic Native plugins. If you are not already familiar with the concept of a mock, the basic idea is to create a “fake” class that pretends to be the real class. This is a concept typically used for creating unit tests, but in the case of Ionic Native it is also quite useful for general development.

A lot of plugins that we may use through Ionic Native will only work on a real device, not through the browser. One of the great benefits of using Ionic is being able to quickly test and iterate through the browser, but when we start throwing native plugins into the mix it can get a little bit awkward. However, now we have the ability to mock native plugin functionality whilst we are working in the browser, and then switch to the real thing when we are testing on a device.

I just recently released a video on this topic, so if you would like a little more explanation around what a mock is and how to use one with Ionic Native I would recommend watching it first.

The main issue with the process I have discussed above and in the video, is that it is a bit of a manual process. Every time you want to test on a device you would have to remember to swap out the mock providers for the real thing. In this tutorial, we are going to discuss how you can automate the process of using mocks for Ionic Native plugins only when running in the browser.

Before We Get Started

Before you go through this tutorial, you should have at least a basic understanding of Ionic 2 concepts. You must also already have Ionic 2 set up on your machine.

If you’re not familiar with Ionic 2 already, I’d recommend reading my Ionic 2 Beginners Guide first to get up and running and understand the basic concepts. If you want a much more detailed guide for learning Ionic 2, then take a look at Building Mobile Apps with Ionic 2.

1. The Concept

The basic idea behind what we are going to do is to allow us to define two different arrays. One array will contain the providers we want to use when running through the browser, and one array will contain the providers we want to use when running on a real device.

In order to do this, we will need to detect whether we are running in a Cordova environment or not, but since we need this information in the main module for the application we can’t rely on using Ionic’s Platform service like we would usually. Instead, we are just going to use a little trick to detect if we are running through Cordova or not:

if(document.URL.includes('https://') || document.URL.includes('http://'))

If the URL contains http:// or https:// then we must be running through the browser, since Cordova does not use this protocol.

2. Create an AppProviders Class

In order to keep our main app.module.ts file, we are going to separate out the grunt work into a new file called app.providers.ts. This will define what the providers array should look like for both scenarios (through the browser, and on a device) and it will allow us to access it from the main module file.

Create a file at src/app/app.providers.ts and add the following:

import { ErrorHandler } from '@angular/core';
import { IonicErrorHandler } from 'ionic-angular';
import { Camera } from '@ionic-native/camera';

class CameraMock {
  getPicture(options) {
    return new Promise((resolve, reject) => {
      resolve("BASE_64_ENCODED_DATA_GOES_HERE");
    })
  }
}

export class AppProviders {

    public static getProviders() {

        let providers;

        if(document.URL.includes('https://') || document.URL.includes('http://')){

          // Use browser providers
          providers = [
            {provide: Camera, useClass: CameraMock},
            {provide: ErrorHandler, useClass: IonicErrorHandler}
          ];

        } else {

          // Use device providers
          providers = [
            Camera,
            {provide: ErrorHandler, useClass: IonicErrorHandler}
          ];  

        }

        return providers;

    }

}

We’ve moved all of our provider imports and our mock class into this file. We then define out AppProviders class which has a single function called getProviders() which will return the appropriate array of providers depending on whether the app is currently running through the browser or through Cordova.

You could continue to add as many mocks as you like to this class, and any providers you want to use in your application should now be added here.

3. Add AppProviders to NgModule

Now we just need to make use of that new AppProviders class in our app.module.ts file. We will import the class, and then access the getProviders function and use that for our providers array instead.

Modify src/app/app.module.ts to reflect the following:

import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { AppProviders } from './app.providers';
import { HomePage } from '../pages/home/home';

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: AppProviders.getProviders()
})
export class AppModule {}

All we have to do is swap our our usual providers array with a call to AppProviders.getProviders() and it will use the appropriate array of providers.

Summary

With this slightly revised structure, you can now test in the browser or on a real device without having to worry about modifying your providers array. Although you could do all of this directly in the app.module.ts file, by separating it out it keeps things much neater.

Check out my latest videos: