Test App Upgrades/Mid-Session App Installations

App instrumentation means adding extra hooks to your app while it runs on TestingBot's devices. It lets your automated tests interact with things that normally require human interaction, such as authentication, taking a specific photo or making a call.

With app instrumentation, you can perform the following tasks in an automated Appium test script:

Injecting images into camera

Android Emulators Only

Image injection allows you to specify a base64 encoded image to the virtual camera of the Android emulator.

The test script will fetch the content of the image, convert it to base64 and send it to the TestingBot grid. The image will be used by the remote device to inject into the camera.

Make sure to include the images Appium plugin, as it is required for this to function correctly.

import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.net.URL;
import java.util.Base64;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;

public class ImageInjectionExample {
    public static String imageToBase64(String url) throws Exception {
        byte[] data = java.net.URI.create(url).toURL().openStream().readAllBytes();
        return Base64.getEncoder().encodeToString(data);
    }

    public static void main(String[] args) throws Exception {
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("platformName", "Android");
        caps.setCapability("browserName", "chrome");
        caps.setCapability("browserVersion", "15");
        caps.setCapability("appium:deviceName", "Pixel 9");
        caps.setCapability("tb:appiumPlugins", new String[]{"images"});
        caps.setCapability("tb:appiumVersion", "2.11.3");
        caps.setCapability("appium:injectedImageProperties", new HashMap<>());

        AppiumDriver driver = new AppiumDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps);

        String base64Image = imageToBase64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png");
        driver.executeScript("mobile: injectEmulatorCameraImage", new HashMap<String, Object>() {{
            put("payload", base64Image);
        }});

        Thread.sleep(30000);

        base64Image = imageToBase64("https://testingbot.com/assets/about.png");
        driver.executeScript("mobile: injectEmulatorCameraImage", new HashMap<String, Object>() {{
            put("payload", base64Image);
        }});

        Thread.sleep(30000);
        driver.quit();
    }
}
const { remote } = require('webdriverio');
const fs = require('fs');
const fetch = require('node-fetch');

async function imageToBase64(url) {
  const res = await fetch(url);
  const buffer = await res.buffer();
  return buffer.toString('base64');
}

(async () => {
  const caps = {
    platformName: 'Android',
    'appium:deviceName': 'Pixel 9',
    browserName: 'chrome',
    browserVersion: '15',
    'tb:appiumPlugins': ['images'],
    'tb:appiumVersion': '2.11.3',
    'appium:injectedImageProperties': {}
  };

  const driver = await remote({
    protocol: 'https',
    hostname: 'hub.testingbot.com',
    port: 443,
    path: '/wd/hub',
    user: 'key',
    key: 'secret',
    capabilities: caps
  });

  let base64Image = await imageToBase64('https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png');
  await driver.executeScript('mobile: injectEmulatorCameraImage', [{ payload: base64Image }]);

  console.log("Injected first image");
  await driver.pause(30000);

  base64Image = await imageToBase64('https://testingbot.com/assets/about.png');
  await driver.executeScript('mobile: injectEmulatorCameraImage', [{ payload: base64Image }]);

  console.log("Injected second image");
  await driver.pause(30000);

  await driver.deleteSession();
})();
from appium import webdriver
import base64
import requests
import time

def image_to_base64(url):
    response = requests.get(url)
    return base64.b64encode(response.content).decode('utf-8')

caps = {
    "platformName": "Android",
    "browserName": "chrome",
    "browserVersion": "15",
    "appium:deviceName": "Pixel 9",
    "tb:appiumPlugins": ["images"],
    "tb:appiumVersion": "2.11.3",
    "appium:injectedImageProperties": {}
}

driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps)

base64_image = image_to_base64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png")
driver.execute_script("mobile: injectEmulatorCameraImage", { "payload": base64_image })

time.sleep(30)
print("Changing image")

base64_image = image_to_base64("https://testingbot.com/assets/about.png")
driver.execute_script("mobile: injectEmulatorCameraImage", { "payload": base64_image })

time.sleep(30)
driver.quit()
#!/usr/bin/env ruby
require 'rubygems'
require 'appium_lib'
require 'base64'
require 'open-uri'

def image_to_base64(image_url)
  image_data = URI.parse(image_url).open.read
  Base64.strict_encode64(image_data)
end

caps = {
  "browserName" => "chrome",
  "browserVersion" => "15",
  "appium:deviceName" => "Pixel 9",
  "platformName" => "Android",
  "tb:appiumPlugins" => ["images"],
  "tb:appiumVersion" => "2.11.3",
  "appium:injectedImageProperties" => {}
}

appium_driver = Appium::Driver.new({
  caps: caps,
  appium_lib: {
    server_url: "https://key:secret@hub.testingbot.com/wd/hub"
  }
}, true)

driver = appium_driver.start_driver

base64_image = image_to_base64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png")
driver.execute_script('mobile: injectEmulatorCameraImage', { payload: base64_image })

sleep 30
puts "Changing image"

base64_image = image_to_base64("https://testingbot.com/assets/about.png")
driver.execute_script('mobile: injectEmulatorCameraImage', { payload: base64_image })

sleep 30
driver.quit
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Remote;
using System;
using System.Net.Http;
using System.Threading.Tasks;

class ImageInjectionExample
{
    static async Task<string> ImageToBase64(string url)
    {
        using (HttpClient client = new HttpClient())
        {
            var data = await client.GetByteArrayAsync(url);
            return Convert.ToBase64String(data);
        }
    }

    static async Task Main(string[] args)
    {
        var options = new AppiumOptions();
        options.PlatformName = "Android";
        options.AddAdditionalCapability("browserName", "chrome");
        options.AddAdditionalCapability("browserVersion", "15");
        options.AddAdditionalCapability("appium:deviceName", "Pixel 9");
        options.AddAdditionalCapability("tb:appiumPlugins", new string[] { "images" });
        options.AddAdditionalCapability("tb:appiumVersion", "2.11.3");
        options.AddAdditionalCapability("appium:injectedImageProperties", new { });

        var driver = new RemoteWebDriver(
            new Uri("https://key:secret@hub.testingbot.com/wd/hub"),
            options
        );

        var base64Image = await ImageToBase64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png");
        driver.ExecuteScript("mobile: injectEmulatorCameraImage", new Dictionary<string, object> { { "payload", base64Image } });

        Console.WriteLine("Injected first image");
        System.Threading.Thread.Sleep(30000);

        base64Image = await ImageToBase64("https://testingbot.com/assets/about.png");
        driver.ExecuteScript("mobile: injectEmulatorCameraImage", new Dictionary<string, object> { { "payload", base64Image } });

        Console.WriteLine("Injected second image");
        System.Threading.Thread.Sleep(30000);

        driver.Quit();
    }
}

Biometric authentication (Finger Print, Touch Id)

Android fingerprint authentication

Emulate fingerprints on Android Emulator, with the mobile:fingerprint command. Only works on API 23+ with Appium version 2 or higher.

import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.net.URL;
import java.util.HashMap;

public class FingerprintExample {
    public static void main(String[] args) throws Exception {
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("platformName", "Android");
        caps.setCapability("appium:deviceName", "Pixel 9");
        caps.setCapability("browserName", "chrome");
        caps.setCapability("browserVersion", "15");
        caps.setCapability("tb:appiumVersion", "2.11.3");

        AppiumDriver driver = new AppiumDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps);

        HashMap<String, Object> args1 = new HashMap<>();
        args1.put("fingerprintId", 1);
        driver.executeScript("mobile: fingerprint", args1);

        Thread.sleep(5000);
        driver.quit();
    }
}
const { remote } = require('webdriverio');

(async () => {
  const caps = {
    platformName: 'Android',
    'appium:deviceName': 'Pixel 9',
    browserName: 'chrome',
    browserVersion: '15',
    'tb:appiumVersion': '2.11.3'
  };

  const driver = await remote({
    protocol: 'https',
    hostname: 'hub.testingbot.com',
    port: 443,
    path: '/wd/hub',
    user: 'key',
    key: 'secret',
    capabilities: caps
  });

  await driver.executeScript('mobile: fingerprint', [{ fingerprintId: 1 }]);
  await driver.pause(5000);

  await driver.deleteSession();
})();
from appium import webdriver
import time

caps = {
    "platformName": "Android",
    "appium:deviceName": "Pixel 9",
    "browserName": "chrome",
    "browserVersion": "15",
    "tb:appiumVersion": "2.11.3"
}

driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps)

# Simulate fingerprint auth with ID 1
driver.execute_script("mobile: fingerprint", { "fingerprintId": 1 })

time.sleep(5)
driver.quit()
require 'appium_lib'

caps = {
  "platformName" => "Android",
  "appium:deviceName" => "Pixel 9",
  "browserName" => "chrome",
  "browserVersion" => "15",
  "tb:appiumVersion" => "2.11.3"
}

driver = Appium::Driver.new({
  caps: caps,
  appium_lib: {
    server_url: "https://key:secret@hub.testingbot.com/wd/hub"
  }
}, true).start_driver

driver.execute_script("mobile: fingerprint", { fingerprintId: 1 })
sleep 5

driver.quit
using OpenQA.Selenium.Remote;
using System;
using System.Collections.Generic;
using OpenQA.Selenium.Appium;

class FingerprintExample {
    static void Main(string[] args) {
        var options = new AppiumOptions();
        options.PlatformName = "Android";
        options.AddAdditionalCapability("appium:deviceName", "Pixel 9");
        options.AddAdditionalCapability("browserName", "chrome");
        options.AddAdditionalCapability("browserVersion", "15");
        options.AddAdditionalCapability("tb:appiumVersion", "2.11.3");

        var driver = new RemoteWebDriver(
            new Uri("https://key:secret@hub.testingbot.com/wd/hub"), options);

        driver.ExecuteScript("mobile: fingerprint", new Dictionary<string, object> {
            { "fingerprintId", 1 }
        });

        System.Threading.Thread.Sleep(5000);
        driver.Quit();
    }
}

iOS TouchID/FaceID authentication

You can simulate a biometric match/non-match event with TouchID and FaceID, with the mobile: sendBiometricMatch command.

import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.net.URL;
import java.util.HashMap;

public class TouchIDExample {
    public static void main(String[] args) throws Exception {
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("platformName", "iOS");
        caps.setCapability("appium:deviceName", "iPhone 15");
        caps.setCapability("platformVersion", "18.0");
        caps.setCapability("browserName", "safari");
        caps.setCapability("tb:appiumVersion", "2.11.3");

        AppiumDriver driver = new AppiumDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps);

        HashMap<String, Object> args1 = new HashMap<>();
        args1.put("type", "touchId");
        args1.put("match", true);
        driver.executeScript("mobile: sendBiometricMatch", args1);

        Thread.sleep(5000);

        HashMap<String, Object> args2 = new HashMap<>();
        args2.put("type", "touchId");
        args2.put("match", false);
        driver.executeScript("mobile: sendBiometricMatch", args2);

        Thread.sleep(5000);
        driver.quit();
    }
}
const { remote } = require('webdriverio');

(async () => {
  const caps = {
    platformName: 'iOS',
    'appium:deviceName': 'iPhone 15',
    platformVersion: '18.0',
    browserName: 'safari',
    'tb:appiumVersion': '2.11.3'
  };

  const driver = await remote({
    protocol: 'https',
    hostname: 'hub.testingbot.com',
    port: 443,
    path: '/wd/hub',
    user: 'key',
    key: 'secret',
    capabilities: caps
  });

  // Successful Touch ID
  await driver.executeScript('mobile: sendBiometricMatch', [{ type: 'touchId', match: true }]);
  await driver.pause(5000);

  // Failed Touch ID
  await driver.executeScript('mobile: sendBiometricMatch', [{ type: 'touchId', match: false }]);
  await driver.pause(5000);

  await driver.deleteSession();
})();
from appium import webdriver
import time

caps = {
    "platformName": "iOS",
    "appium:deviceName": "iPhone 15",
    "platformVersion": "18.0",
    "browserName": "safari",
    "tb:appiumVersion": "2.11.3"
}

driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps)

# Successful Touch ID
driver.execute_script("mobile: sendBiometricMatch", { "type": "touchId", "match": True })
time.sleep(5)

# Failed Touch ID
driver.execute_script("mobile: sendBiometricMatch", { "type": "touchId", "match": False })
time.sleep(5)

driver.quit()
require 'appium_lib'

caps = {
  "platformName" => "iOS",
  "appium:deviceName" => "iPhone 15",
  "platformVersion" => "18.0",
  "browserName" => "safari",
  "tb:appiumVersion" => "2.11.3"
}

driver = Appium::Driver.new({
  caps: caps,
  appium_lib: {
    server_url: "https://key:secret@hub.testingbot.com/wd/hub"
  }
}, true).start_driver

# Success
driver.execute_script("mobile: sendBiometricMatch", { type: "touchId", match: true })
sleep 5

# Failure
driver.execute_script("mobile: sendBiometricMatch", { type: "touchId", match: false })
sleep 5

driver.quit
using OpenQA.Selenium.Remote;
using System;
using System.Collections.Generic;
using OpenQA.Selenium.Appium;

class TouchIDExample {
    static void Main(string[] args) {
        var options = new AppiumOptions();
        options.PlatformName = "iOS";
        options.AddAdditionalCapability("appium:deviceName", "iPhone 15");
        options.AddAdditionalCapability("platformVersion", "18.0");
        options.AddAdditionalCapability("browserName", "safari");
        options.AddAdditionalCapability("tb:appiumVersion", "2.11.3");

        var driver = new RemoteWebDriver(
            new Uri("https://key:secret@hub.testingbot.com/wd/hub"), options);

        driver.ExecuteScript("mobile: sendBiometricMatch", new Dictionary<string, object> {
            { "type", "touchId" },
            { "match", true }
        });

        System.Threading.Thread.Sleep(5000);

        driver.ExecuteScript("mobile: sendBiometricMatch", new Dictionary<string, object> {
            { "type", "touchId" },
            { "match", false }
        });

        System.Threading.Thread.Sleep(5000);
        driver.Quit();
    }
}

Receiving calls and text messages (SMS)

You can simulate an incoming call or text message with Appium. Please see the examples below.

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.connection.GsmCallActions;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.net.URL;

public class AndroidGsmExample {
    public static void main(String[] args) throws Exception {
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("platformName", "Android");
        caps.setCapability("appium:deviceName", "Pixel 9");
        caps.setCapability("browserName", "chrome");
        caps.setCapability("browserVersion", "15");
        caps.setCapability("tb:appiumVersion", "2.11.3");

        AndroidDriver driver = new AndroidDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps);

        // Send SMS
        driver.sendSMS("5555555555", "Your message here!");

        // Make and handle a phone call
        driver.makeGsmCall("5555555555", GsmCallActions.CALL);
        Thread.sleep(2000);
        driver.makeGsmCall("5555555555", GsmCallActions.ACCEPT);
        Thread.sleep(2000);
        driver.makeGsmCall("5555555555", GsmCallActions.CANCEL);

        driver.quit();
    }
}
const { remote } = require('webdriverio');

(async () => {
  const caps = {
    platformName: 'Android',
    'appium:deviceName': 'Pixel 9',
    browserName: 'chrome',
    browserVersion: '15',
    'tb:appiumVersion': '2.11.3'
  };

  const driver = await remote({
    protocol: 'https',
    hostname: 'hub.testingbot.com',
    port: 443,
    path: '/wd/hub',
    user: 'key',
    key: 'secret',
    capabilities: caps
  });

  // Send SMS
  await driver.sendSms('5555555555', 'Your message here!');

  // Phone call
  await driver.makeGsmCall('5555555555', 'call');
  await driver.pause(2000);
  await driver.makeGsmCall('5555555555', 'accept');
  await driver.pause(2000);
  await driver.makeGsmCall('5555555555', 'cancel');

  await driver.deleteSession();
})();
from appium import webdriver
import time

caps = {
    "platformName": "Android",
    "appium:deviceName": "Pixel 9",
    "browserName": "chrome",
    "browserVersion": "15",
    "tb:appiumVersion": "2.11.3"
}

driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps)

# Send SMS
driver.send_sms(phone_number: "5555555555", message: "Your message here!")

# Phone call
driver.gsm_call(phone_number: "5555555555", action: :call)
sleep 2
driver.gsm_call(phone_number: "5555555555", action: :accept)
sleep 2
driver.gsm_call(phone_number: "5555555555", action: :cancel)

driver.quit()
require 'appium_lib'

caps = {
  "platformName" => "Android",
  "appium:deviceName" => "Pixel 9",
  "browserName" => "chrome",
  "browserVersion" => "15",
  "tb:appiumVersion" => "2.11.3"
}

driver = Appium::Driver.new({
  caps: caps,
  appium_lib: {
    server_url: "https://key:secret@hub.testingbot.com/wd/hub"
  }
}, true).start_driver

# Send SMS
driver.send_sms("5555555555", "Your message here!")

# Phone call
driver.make_gsm_call("5555555555", "call")
sleep 2
driver.make_gsm_call("5555555555", "accept")
sleep 2
driver.make_gsm_call("5555555555", "cancel")

driver.quit
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Android;
using System;

class AndroidGsmExample {
    static void Main(string[] args) {
        var options = new AppiumOptions();
        options.PlatformName = "Android";
        options.AddAdditionalCapability("appium:deviceName", "Pixel 9");
        options.AddAdditionalCapability("browserName", "chrome");
        options.AddAdditionalCapability("browserVersion", "15");
        options.AddAdditionalCapability("tb:appiumVersion", "2.11.3");

        var driver = new AndroidDriver(new Uri("https://key:secret@hub.testingbot.com/wd/hub"), options);

        // Send SMS
        driver.SendSMS("5555555555", "Your message here!");

        // Phone call
        driver.MakeGsmCall("5555555555", "call");
        System.Threading.Thread.Sleep(2000);
        driver.MakeGsmCall("5555555555", "accept");
        System.Threading.Thread.Sleep(2000);
        driver.MakeGsmCall("5555555555", "cancel");

        driver.Quit();
    }
}
Was this page helpful?

Looking for More Help?

Have questions or need more information?
You can reach us via the following channels: