Merge pull request #2599 from bootstraponline/ruby_sample

Update Ruby sample code
This commit is contained in:
bootstraponline
2014-05-20 06:08:19 -07:00
8 changed files with 210 additions and 260 deletions

1
.gitignore vendored
View File

@@ -42,3 +42,4 @@ build/
lib/devices/ios/uiauto/lib/status.js
lib/devices/ios/uiauto/appium/xpath.js
*DerivedData
sample-code/examples/ruby/pretty_app.png

View File

@@ -4,4 +4,6 @@ gem 'appium_lib'
gem 'rest-client'
gem 'rspec'
gem 'cucumber'
gem 'rspec-expectations'
gem 'rspec-expectations'
gem 'spec'
gem 'sauce_whisk'

Binary file not shown.

View File

@@ -8,7 +8,7 @@
# SAUCE_ACCESS_KEY = your-sauce-key
#
# Then just:
# $ rspec android_on_sauce.rb
# $ ruby android_on_sauce.rb
#
# Of note compared to the iOS example, here we're giving the package and
# activity, no OS and an empty browserName
@@ -16,97 +16,55 @@
# Of note compared to the non-sauce examples, you need to host your app
# somewhere Sauce Labs' cloud can fetch it for your test.
require "selenium-webdriver"
require 'selenium/webdriver/remote/http/persistent'
require "rspec"
require "rest_client"
require 'rubygems'
require 'spec'
require 'appium_lib'
require 'sauce_whisk'
SAUCE_USERNAME = ENV['SAUCE_USERNAME']
SAUCE_ACCESS_KEY = ENV['SAUCE_ACCESS_KEY']
describe "Notepad" do
before :each do
http_client = ::Selenium::WebDriver::Remote::Http::Persistent.new
http_client.timeout = 300 # Allow for slow network or boot time
@driver = Selenium::WebDriver.for(
:remote,
:desired_capabilities => desired_caps,
:url => server_url,
:http_client => http_client
)
http_client.timeout = 90
describe 'Notepad' do
def desired_caps
{
caps: {
'appium-version' => '1.0.0',
'platformName' => 'Android',
'platformVersion' => '4.3',
'deviceName' => 'Android Emulator',
'app' => 'http://appium.s3.amazonaws.com/NotesList.apk',
'name' => 'Ruby Appium Android example'
},
appium_lib: {
wait: 60
}
}
end
after(:each) do
# Get the success by checking for assertion exceptions,
# and log them against the job, which is exposed by the session_id
job_id = @driver.send(:bridge).session_id
update_job_success(job_id, example.exception.nil?)
@driver.quit
before do
Appium::Driver.new(desired_caps).start_driver
end
it "can create and save new notes" do
new_button = @driver.find_element(:name, "New note")
new_button.click
after do
driver_quit
end
text_field = @driver.find_element(:tag_name, "textfield")
text_field.send_keys "This is a new note, from Ruby"
it 'can create and save new notes' do
find('New note').click
find_element(:class, 'android.widget.EditText').type 'This is a new note, from Ruby'
save_button = @driver.find_element(:name, "Save")
save_button.click
find('Save').click
notes = @driver.find_elements(:tag_name, "text")
puts "The number of notes is: #{notes.length}"
notes[2].text.should eq "This is a new note, from Ruby"
note_count = ids('android:id/text1').length
note_count.must_equal 1
texts.last.text.must_equal 'This is a new note, from Ruby'
end
end
def desired_caps
{
"device" => "Android",
"browserName" => "",
"version" => "4.2",
"app" => "http://appium.s3.amazonaws.com/NotesList.apk",
"app-package" => "com.example.android.notepad",
"app-activity" => ".NotesList",
"name" => "Ruby Appium Android example"
}
end
def auth_details
un = SAUCE_USERNAME
pw = SAUCE_ACCESS_KEY
unless un && pw
STDERR.puts <<-EOF
Your SAUCE_USERNAME or SAUCE_ACCESS_KEY environment variables
are empty or missing.
You need to set these values to your Sauce Labs username and access
key, respectively.
If you don't have a Sauce Labs account, you can get one for free at
http://www.saucelabs.com/signup
EOF
exit
end
return "#{un}:#{pw}"
end
def server_url
return "http://#{auth_details}@ondemand.saucelabs.com:80/wd/hub"
end
def rest_jobs_url
"https://#{auth_details}@saucelabs.com/rest/v1/#{SAUCE_USERNAME}/jobs"
end
passed = Minitest.run_specs({ :trace => [__FILE__] }).first
# Because WebDriver doesn't have the concept of test failure, use the Sauce
# Labs REST API to record job success or failure
def update_job_success(job_id, success)
RestClient.put "#{rest_jobs_url}/#{job_id}", {"passed" => success}.to_json, :content_type => :json
end
user = ENV['SAUCE_USERNAME']
key = ENV['SAUCE_ACCESS_KEY']
if user && !user.empty? && key && !key.empty?
passed = passed.failures == 0 && passed.errors == 0
SauceWhisk::Jobs.change_status $driver.driver.session_id, passed
end

View File

@@ -23,30 +23,25 @@
Given /^I have entered (\d+) into field (\d+) of the calculator$/ do |value, field|
# Get a textfield by index
textfield = textfield(field.to_i)
textfield.send_keys value
textfield(field.to_i).type value
end
Given /^I have entered (\d+) into a field of the calculator showing (\w+)$/ do |value, field|
# Get a textfield by string
textfield = textfield field
textfield.send_keys value
textfield(field).type value
end
And /^I press button (\d+)$/ do |button_index|
# Find a button by index
button = button(button_index.to_i)
button.click
button(button_index.to_i).click
end
And /^I press a button labelled (\w+)$/ do |button_text|
# Find a button by text
button = button button_text
button.click
button(button_text).click
end
Then /^the result should be displayed as (\d+)$/ do |expected|
# You can get just the first of a class of elements
result = first_s_text
result.attribute("value").should eq expected
end
first_text.value.should eq expected
end

View File

@@ -36,7 +36,7 @@ SAUCE_USERNAME = ENV['SAUCE_USERNAME']
SAUCE_ACCESS_KEY = ENV['SAUCE_ACCESS_KEY']
# This is the test itself
describe "Computation" do
describe 'Computation' do
before(:each) do
Appium::Driver.new(caps: desired_caps).start_driver
Appium.promote_appium_methods RSpec::Core::ExampleGroup
@@ -50,13 +50,11 @@ describe "Computation" do
driver_quit
end
it "should add two numbers" do
it 'should add two numbers' do
values = [rand(10), rand(10)]
expected_sum = values.reduce(&:+)
# Standard selectors work to find elements
elements = find_elements :class_name, 'UIATextField'
elements.each_with_index do |element, index|
textfields.each_with_index do |element, index|
element.send_keys values[index]
end
@@ -64,13 +62,13 @@ describe "Computation" do
button(1).click
# You can find the first static text element
first_s_text.text.should eq expected_sum.to_s
first_text.text.should eq expected_sum.to_s
end
end
def desired_caps
{
'appium-version' => '1.0.0-beta.2',
'appium-version' => '1.0.0',
'platformName' => 'iOS',
'platformVersion' => '7.1',
'deviceName' => 'iPhone Simulator',
@@ -113,4 +111,4 @@ end
# Labs REST API to record job success or failure
def update_job_success(job_id, success)
RestClient.put "#{rest_jobs_url}/#{job_id}", {"passed" => success}.to_json, :content_type => :json
end
end

View File

@@ -28,78 +28,74 @@
# It will take a while, but once it's done you should get nothing but a line
# telling you "Tests Succeeded"; You'll see the iOS Simulator cranking away
# doing actions while we're running.
require 'rubygems'
require 'appium_lib'
APP_PATH = '../../apps/TestApp/build/release-iphonesimulator/TestApp.app'
def absolute_app_path
file = File.join(File.dirname(__FILE__), APP_PATH)
raise "App doesn't exist #{file}" unless File.exist? file
file
end
desired_caps = {
'platformName' => 'ios',
'platformName' => 'ios',
'versionNumber' => '7.1',
'app' => absolute_app_path
'app' => APP_PATH
}
# Start the driver, then add all the Appium library methods to object to make
# calling them look nicer. You should probably do this on your test class,
# not on Object.
# Start the driver
Appium::Driver.new(caps: desired_caps).start_driver
Appium.promote_appium_methods Object
module Calculator
module IOS
# Add all the Appium library methods to Test to make
# calling them look nicer.
Appium.promote_singleton_appium_methods Calculator
# Add two numbers
values = [rand(10), rand(10)]
expected_sum = values.reduce(&:+)
# Add two numbers
values = [rand(10), rand(10)]
expected_sum = values.reduce(&:+)
# Find every textfield
elements = e_textfields
# Find every textfield.
elements = textfields
elements.each_with_index do |element, index|
element.type values[index]
end
elements.each_with_index do |element, index|
element.type values[index]
end
# Get the first button
button = button(1)
button.click
# Click the first button
button(1).click
# Get the first static text field, then get its text
actual_sum = first_s_text.text
raise Exception unless actual_sum == (expected_sum.to_s)
# Get the first static text field, then get its text
actual_sum = first_text.text
raise unless actual_sum == (expected_sum.to_s)
# Alerts are visible
button('show alert').click
find_element :class_name, 'UIAAlert' # Elements can be found by :class_name
## Alerts are visible
button('show alert').click
alert = find_element :class_name, 'UIAAlert' # Elements can be found by :class_name
# wait for alert to show
wait { text 'this alert is so cool' }
## Elements can be found by their Class and value of an attribute
cancel_button = find_ele_by_attr 'UIATableCell', :label, "Cancel"
cancel_button.click
# Elements can be found by their Class and value of an attribute
find_ele_by_attr 'UIATableCell', :label, 'Cancel'
# Or by find
find('Cancel').click
# Waits until no exceptions are raised
wait(10) {
alerts = find_elements :class_name, 'UIAAlert'
raise Exception unless alerts.length == 0
}
# Waits until alert doesn't exist
wait_true { !exists { tag('UIAAlert') } }
# Alerts can be switched into
button('show alert').click # Get a button by its text
alert = driver.switch_to.alert # Get the text of the current alert, using
# the Selenium::WebDriver directly
alerting_text = alert.text
raise Exception unless alerting_text.include? 'Cool title'
alert_accept # Accept the current alert
## Alerts can be switched into
button('show alert').click # Get a button by its text
alert = driver.switch_to.alert # Get the text of the current alert, using
# the Selenium::WebDriver directly
alerting_text = alert.text
raise Exception unless alerting_text.include? "Cool title"
alert_accept # Accept the current alert
# Window Size is easy to get
sizes = window_size
raise Exception unless sizes.height == 568
raise Exception unless sizes.width == 320
## Window Size is easy to get
sizes = window_size
raise Exception unless sizes.height == 568
raise Exception unless sizes.width == 320
# Quit when you're done!
driver_quit
puts "Tests Succeeded!"
# Quit when you're done!
driver_quit
puts 'Tests Succeeded!'
end
end

View File

@@ -4,251 +4,251 @@
#
# It relies on the setup in simple_test.rb, which is also a good starting
# point to make sure you can run any tests at all.
#
# run with: rspec u_i_catalog.rb
#
# run only a tagged group: rspec --tag one u_i_catalog.rb
require 'rubygems'
require 'rspec'
require 'appium_lib'
require 'net/http'
include Selenium::WebDriver::DriverExtensions::HasInputDevices
include Selenium::WebDriver::DriverExtensions::HasTouchScreen
RSpec.configure do |c|
c.treat_symbols_as_metadata_keys_with_true_values = true
end
APP_PATH = '../../apps/UICatalog/build/Release-iphonesimulator/UICatalog.app'
APP_PATH = './UICatalog.app.zip'
def desired_caps
{
'platformName' => 'iOS',
'deviceName' => 'iPhone Simulator',
caps: {
'platformName' => 'iOS',
'deviceName' => 'iPhone Simulator',
'versionNumber' => '7.1',
'app' => absolute_app_path
'app' => APP_PATH
},
appium_lib:
{ :wait => 10 }
}
end
def absolute_app_path
File.join(File.dirname(__FILE__), APP_PATH)
end
def server_url
"http://127.0.0.1:4723/wd/hub"
end
describe "UI Catalog" do
describe 'UI Catalog' do
before(:all) do
Appium::Driver.new(caps: desired_caps).start_driver
Appium::Driver.new(desired_caps).start_driver
Appium.promote_appium_methods RSpec::Core::ExampleGroup
end
def back_click(opts={})
opts ||= {}
search_wait = opts.fetch(:wait, 10) # seconds
wait(search_wait) { button_exact('Back').click }
end
after(:all) do
driver_quit
end
describe "An Element" do
subject { find_elements(:class_name, "UIATableView")[0] }
it {should_not be nil}
describe 'An Element', :one do
subject { find_elements(:class_name, 'UIATableView')[0] }
context "when used as a selection context" do
it { should_not be nil }
it "Can be a selection context" do
rows = subject.find_elements(:class_name, "UIATableCell")
context 'when used as a selection context' do
it 'Can be a selection context' do
rows = subject.find_elements(:class_name, 'UIATableCell')
rows.size.should eq 12
end
it "does not return elements it does not contain" do
nav_bar = subject.find_elements(:class_name, "UIANavigationBar")
it 'does not return elements it does not contain' do
nav_bar = subject.find_elements(:class_name, 'UIANavigationBar')
nav_bar.length.should be 0
end
end
it "returns its text" do
rows = subject.find_elements(:class_name, "UIATableCell")
rows[0].attribute(:name).should eq "Buttons, Various uses of UIButton"
it 'returns its text' do
rows = subject.find_elements(:class_name, 'UIATableCell')
rows.first.name.should eq 'Buttons, Various uses of UIButton'
end
end
describe "position" do
it "is returned by the driver" do
third_row = find_elements(:class_name, "UIATableCell")[2]
describe 'position' do
it 'is returned by the driver' do
third_row = ele_index('UIATableCell', 3)
third_row.location.x.should be 0
third_row.location.y.should be 152
end
end
describe "Screenshots" do
it "can be made in base 64" do
describe 'Screenshots' do
it 'can be made in base 64' do
# screenshot for Appium saves to disk, to get base64 you need
# to use the underlying Selenium WebDriver
screenshot = driver.screenshot_as :base64
screenshot.should_not be_nil
end
it "can be saved to the filesystem" do
screenshot("./pretty_app.png")
it 'can be saved to the filesystem' do
screenshot('./pretty_app.png')
end
end
describe "attributes" do
describe 'attributes' do
before :all do
find_elements(:class_name, "UIATableCell")[9].click
@switch = find_element(:class_name, "UIASwitch")
id('ToolbarTitle').click
@switch = find_element(:class_name, 'UIASwitch')
end
# Go back to the menu when you're done
after :all do
back
back_click
end
it "can be tested for visibility" do
it 'can be tested for visibility' do
@switch.displayed?.should be_true
end
# TODO: Text checking still seems... Not good.
it "can have text checked" do
@switch.attribute("name").should eq "Image"
it 'can have text checked' do
@switch.name.should eq 'Image'
end
it "can have values checked" do
it 'can have values checked' do
# Check if this switch is off
@switch.attribute("value").should be 0
@switch.value.should be 0
end
it "reflect changes in their values" do
@switch.click
@switch.attribute("value").should be 1
it 'reflect changes in their values' do
@switch.click
@switch.value.should be 1
end
end
describe "text fields" do
describe 'text fields' do
before :all do
find_elements(:class_name, "UIATableCell")[2].click
id('TextFieldTitle').click
@text_field = first_textfield
end
after :all do
back
back_click
end
it "can accept key presses" do
@text_field.type("discombobulate")
it 'can accept key presses' do
@text_field.type('discombobulate')
end
it "can be checked for text" do
@text_field.attribute("value").should eq "discombobulate"
it 'can be checked for text' do
@text_field.value.should eq 'discombobulate'
end
it "can be cleared" do
it 'can be cleared' do
@text_field.clear
@text_field.attribute("value").should eq "<enter text>"
@text_field.value.should eq '<enter text>'
end
end
describe "alerts" do
describe 'alerts' do
before :all do
find_elements(:class_name, "UIATableCell")[10].click
id('AlertTitle').click
end
after :all do
back
back_click
end
it "can be clicked" do
s_text("Show OK-Cancel").click
b = button("OK")
b.click
it 'can be clicked' do
text('Show OK-Cancel').click
button('OK').click
end
it "can be accepted" do
s_text("Show OK-Cancel").click
it 'can be accepted' do
text('Show OK-Cancel').click
alert_accept
end
it "can be dismissed" do
s_text("Show OK-Cancel").click
it 'can be dismissed' do
text('Show OK-Cancel').click
alert_dismiss
end
it "can be Custom" do
s_text("Show Custom").click
button_1 = button("Button1")
button_2 = button("Button2")
button_2.click
it 'can be Custom' do
text('Show Custom').click
button('Button2').click
end
end
describe "scrolling" do
describe 'scrolling' do
# Does not work on iOS 7 yet
it "can be done with co-ordinates"
it 'can be done with co-ordinates'
end
describe "sliders" do
describe 'sliders' do
before :all do
find_elements(:class_name, "UIATableCell")[1].click
@slider = find_element(:class_name, "UIASlider")
find_elements(:class_name, 'UIATableCell')[1].click
@slider = find_element(:class_name, 'UIASlider')
end
after :all do
back
back_click
end
it "can have their values read" do
it 'can have their values read' do
# .value is a patched method to return the value attribute
@slider.value.should eq "50%"
@slider.value.should eq '50%'
end
it "can be changed" do
@slider.value.should eq "50%"
it 'can be changed' do
@slider.value.should eq '50%'
actions = Appium::TouchAction.new
actions.press element: @slider, x: 60, y: 3
actions.move_to element: @slider, x: 120, y: 3
actions.release
actions.perform
@slider.value.should eq "100%"
actions.perform
@slider.value.should eq '100%'
end
end
describe "sessions" do
it "can be obtained from the simulator or driver" do
describe 'sessions' do
it 'can be obtained from the simulator or driver' do
data = JSON.parse(Net::HTTP.get(URI "#{server_url}/sessions"))
data.should_not be_nil
# Convenience method to get the session ID
session_id.should eq (data["value"][0]["id"])
session_id.should eq (data['value'][0]['id'])
end
end
describe "sizes" do
it "can be obtained from elements" do
table_dimensions = find_element(:class_name, "UIATableView").size
row_dimensions = find_elements(:class_name, "UIATableCell")[0].size
describe 'sizes' do
it 'can be obtained from elements' do
table_dimensions = find_element(:class_name, 'UIATableView').size
row_dimensions = find_elements(:class_name, 'UIATableCell')[0].size
table_dimensions["width"].should eq row_dimensions["width"]
table_dimensions["height"].should_not eq row_dimensions["height"]
table_dimensions.width.should eq row_dimensions.width
table_dimensions.height.should_not eq row_dimensions.height
end
end
describe "page source" do
describe 'page source' do
before :all do
# get_source returns the source, source prints it directly
@main_source = get_source
find_elements(:class_name, "UIATableCell")[2].click
id('TextFieldTitle').click
@text_source = get_source
end
after :all do
back
back_click
end
it "can be obtained" do
@main_source.should include "UIATableView"
@main_source.should include "TextFields"
it 'can be obtained' do
@main_source.should include 'UIATableView'
@main_source.should include 'TextFields'
end
it "changes when the page does" do
@text_source.should_not eq @main_source
it 'changes when the page does' do
@text_source.should_not eq @main_source
end
end
end