SDK Testing Framework

The Zendrive SDK testing framework allows developers to perform 'at-desk' integration testing for a variety of use cases and end-user scenarios. These include simulations for trip lifecycle, automatic trip detection, driving behavior events, and collisions.

Developers can test the application's UI components by receiving callbacks for a simulated trip without physically going for a drive. The testing workflow can then be rolled into a continuous integration (CI) pipeline.

This page outlines step-by-step instructions to integrate the Zendrive Android/iOS Testing SDK into your application.

Integrate the Zendrive Testing Library

For Android

1. Add the following code snippet to your gradle file


//Existing Zendrive react native dependency
implementation project(':react-native-zendrive')

// Add the below testing dependency
implementation 'com.zendrive.sdk.android:ZendriveSDK-testing:6.3.1'

2. Expose bridge modules to JavaScript

Create SDKTestModule.kt and paste the following code.

package com.example

import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.module.annotations.ReactModule
import com.zendrive.sdk.testing.mockdrive.MockDrive
import com.zendrive.sdk.testing.mockdrive.PresetTripType

@ReactModule(name = SDKTestModule.MODULE_NAME, needsEagerInit = true)
class SDKTestModule(private val reactContext: ReactApplicationContext) :
  ReactContextBaseJavaModule(reactContext) {

  override fun getName(): String {
    return MODULE_NAME
  }

  @ReactMethod
  fun simulatePreset(presetName: String, promise: Promise) {
    val builder =
      MockDrive.Builder.presetMockDrive(reactApplicationContext, PresetTripType.valueOf(presetName))
    val presetMockDrive = builder.build()
    val opResult = presetMockDrive.simulate(reactApplicationContext, 10)
    val map = Arguments.createMap()
    map.putBoolean("isSuccess", opResult.isSuccess)
    map.putString("errorMessage", opResult.errorMessage)
    promise.resolve(map)
  }

  @ReactMethod
  fun availablePresets(promise: Promise) {
    promise.resolve(PresetTripType.values().map { it.toString() }.foldRight(
      Arguments.createArray(),
      { preset, map -> map.pushString(preset); map }
    ))
  }

  companion object {
    const val MODULE_NAME = "ZendriveTest"
  }
}

Create SDKTestPackage.kt and paste the following code

package com.example

import android.view.View
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager

class SDKTestPackage : ReactPackage {
  override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
    return arrayListOf(
      SDKTestModule(reactContext)
    )
  }

  override fun createViewManagers(
    reactContext: ReactApplicationContext
  ): List<ViewManager<View, ReactShadowNode<*>>> {
    return arrayListOf()
  }
}

Add this test package in MainApplication.kt file.

override fun getPackages(): List<ReactPackage> {
      return listOf(
        //..other package
        ....
        // Zendrive package
        RNZendrivePackage()
        // test package
        SDKTestPackage()
      )
    }

For iOS

1. Install via cocoapods

pod 'ZendriveSDK/Testing', :git => 'https://bitbucket.org/zendrive-root/zendrive_cocoapod.git', :tag => '6.3.0'

2. Enable Testing Framework

Add the ZendriveMockModeEnabled key to the Info.plist file of the application with a value set to YES (Boolean value).

3. Expose bridge modules to js

Create RNZendriveTest.m file and paste the following snippet:

#import "React/RCTBridgeModule.h"
@interface RCT_EXTERN_MODULE(RCTZendriveTest, NSObject)
RCT_EXTERN_METHOD(
                  simulatePreset: (NSString *)preset
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter: (RCTPromiseRejectBlock)reject
                  )
RCT_EXTERN_METHOD(
                  availablePresets: (RCTPromiseResolveBlock)resolve
                  rejecter: (RCTPromiseRejectBlock)reject
                  )
@end

Create RNZendriveTest.swift file and paste the following snippet:


import Foundation
import ZendriveSDKTesting
@objc(RCTZendriveTest)
class RNZendriveTest: NSObject {
    let namePresetMapping: [String: ZendriveSDKTesting.ZendrivePresetTripType] = [
        "Highway60MinTrip": ZendriveSDKTesting.ZendrivePresetTripType.Highway60MinTrip,
        "InvalidTrip": ZendriveSDKTesting.ZendrivePresetTripType.InvalidTrip,
        "NonDriving60MinTrip": ZendriveSDKTesting.ZendrivePresetTripType.NonDriving60MinTrip,
        "Urban10MinTrip": ZendriveSDKTesting.ZendrivePresetTripType.Urban10MinTrip,
        "Urban30MinWithCollisionTrip": ZendriveSDKTesting.ZendrivePresetTripType.Urban30MinWithCollisionTrip
    ]
    @objc
    func constantsToExport() -> [AnyHashable: Any]! {
        return [:]
    }

    @objc
    static func requiresMainQueueSetup() -> Bool {
        return false
    }

    @objc
    func availablePresets(_
        resolve: @escaping RCTPromiseResolveBlock,
                          rejecter reject: RCTPromiseRejectBlock) {
        let availablePresets = Array(namePresetMapping.keys)
        resolve(availablePresets)
    }

    @objc
    func simulatePreset(
        _ preset: String,
        resolver resolve: @escaping RCTPromiseResolveBlock,
        rejecter reject: RCTPromiseRejectBlock
        ) {
        let builder = ZendriveMockDriveBuilder.presetMockDrive(namePresetMapping[preset]!)
        var simulationError: NSError?
        builder.build().simulateDrive(20000, error: &simulationError)
        if simulationError != nil {
            resolve([
                "isSuccess": false,
                "errorMessage": simulationError?.description ?? ""
                ])
        } else {
            resolve([
                "isSuccess": true
                ])
        }
    }
}

Usage

Once the testing framework is enabled, developers can simulate the trip lifecycle. Developers can choose from a preset trip or create a custom trip. Once a simulation is triggered, the application will receive the configured callbacks automatically. Developers can also simulate the trip when the test app is in background.

Listing Available Presets

The availablePresets bridge method in the ZendriveTest module provides all the presets available via the native test library. Use it as shown below:

import { NativeModules } from 'react-native';
const ZendriveTest = NativeModules.ZendriveTest;

ZendriveTest.availablePresets().then(presets => {
  //presets is an array of strings
  console.log(presets);
});

Running the Simulation

The simulatePreset bridge method on the ZendriveTest module provides simulation of a specific preset available via the native test library. Use it as shown below:

// simulationPreset is one of the values returned by availablePresets method.
ZendriveTest.simulatePreset(simulationPreset).then(item => {
  if (item.isSuccess) {
    //simulation succeeded
  } else {
    console.log(item.errorMessage);
  }
});

Tips & Best Practices

  1. The testing framework must not be shipped with the production application.

  2. We recommend that developers create a new target in case of iOS and a new build type in case of android, which uses the SDK testing library.

  3. While the testing framework removes the necessity to go for a physical drive, we still recommend that you go for a drive to test the application.

  4. The following features of Zendrive SDK cannot be tested using this library. We plan to include these in future releases of the testing framework:

    1. on-drive-resume, on-settings-changed events.

    2. Manual trip lifecycle

    3. insurance and feedback modules

Last updated

Was this helpful?