Appium Testing With React Native and CI

What are some tips and tricks for setting up CI with a React Native project, including how integration testing, probably with Appium.

Tips

  1. Accessibility labels are your friends and critically needed for image/icon buttons.
  2. You might have to use xpath if there’s no accessibility label. The appium inspector is particularly useful for this.
  3. The ruby console is also great for testing out the command to get appium objects. You can use binding.pry in your tests.

Setup

  1. Install appium per the instructions at appium.io.
  2. Add appium files to your react-native project, per the below example.

/test/appium/spec_helper.rb

require 'rspec'
require 'appium_lib'

SPEC_ROOT = File.expand_path(File.dirname(__FILE__))
Dir[File.expand_path('support/**/*.rb', SPEC_ROOT)].each { |f| require f }

app_path = '../../ios/build/Build/Products/Debug-iphonesimulator/SpylightApp.app'

RSpec.configure do |config|
  config.include ::Screenshot
  config.include ::Helpers

  config.before(:suite) do
    driver_caps = {
      platformName:  'iOS',
      versionNumber: '9.3',
      deviceName:    'iPhone 6s',
      newCommandTimeout: 9999,
      app: app_path
    }

    Appium::Driver.new(caps: driver_caps).start_driver
    Appium.promote_appium_methods RSpec::Core::ExampleGroup
  end

  config.after(:suite) do
    $driver.driver_quit
  end
end

/test/appium/Gemfile

source 'https://www.rubygems.org'

gem 'appium_lib', '~> 6.0.0'
gem 'rspec'

/tests/appium/features/login_spec.rb

require './spec_helper'

describe 'Login' do
  it 'User logs in' do
    find('Log in').click
    find_by_accessibility_label('Email').click

    textfields[0].type 'somebody@email.com'
    textfields[1].type 'wrongpass'
    find_by_accessibility_label('FORWARD').click

    alert = driver.switch_to.alert
    expect(alert.text).to include('Invalid username or password. Please try again.')
    alert_accept

    textfields[1].type 'password'
    find_by_accessibility_label('FORWARD').click

    # some_reference_on_next_screen is a helper in /test/appium/support to find some screen object
    expect(some_reference_on_next_screen).not_to be_nil 
  end
end

/test/appium/support/screenshot.rb

Example of the kind of file you can put in the /test/appium/support directory, from github.


require 'fileutils'

module Screenshot
  module_function

  ## Usage:
  # capture_screenshot => #{screenshot_dir}/img_1.png
  # capture_screenshot(prefix: 'foo') => #{screenshot_dir}/foo_img_2.png
  def capture_screenshot(prefix: nil)
    img_name = "img_#{screenshot_count}.png"
    img_name = "#{prefix}_#{img_name}" unless prefix.nil?
    img_path = File.join(screenshot_dir, img_name)

    begin
      $driver.driver.save_screenshot(img_path)
      @@screenshot_count += 1
    rescue => e
      $stderr.puts "saving screenshot failed #{e.message}"
    end
    img_path
  end

  def screenshot_count
    @@screenshot_count ||= 1
  end

  def screenshot_dir
    @@screenshot_dir ||= File.join(Bundler.root, 'screenshots', Time.now.strftime('%Y%m%d-%H%M%S')).tap do |dirname|
      FileUtils.mkdir_p dirname
    end
  end