I recently upgraded from:
Page Object 1.2.2
Watir-Webdriver 0.9.9
Selenium WebDriver 2.53.0
Firefox 45.8.0
To:
Page Object 2.2.0
Watir 6.3.0
Selenium-Webdriver 3.4.3
Firefox 52.2.0
After a little bit of pain, I've finally gotten my tests to start running! One small snag though. The methods #present?, #exists?, and #visible? don't return anything, they just timeout instead. Similarly, #wait_until, x_element.when_present?, and similar methods all hit the same problem!
Here is my page object:
class LoginPage < TeamConnectPage
MAX_LOGIN_ATTEMPTS = 3
button :ok, value: /^OK$/i
button :submit, value: 'Login'
button :new_session, value: 'New Session'
link :logout, id: 'LINK_default_logout'
span :error_message, class: 'texterror'
text_field :username, name: 'j_username'
text_field :password, name: 'j_password'
def login_as(username)
username = username.to_s
do_logout if logged_in?
attempts = 0
try_login(username)
while username_element.present?
fail "#{MAX_LOGIN_ATTEMPTS} logins attempted unsuccessfully for user #{username}" if (attempts+=1) == MAX_LOGIN_ATTEMPTS
try_login(username)
end
if new_session_element.present?
new_session
logout_element.when_present(10)
end
end
private
def try_login(username)
self.username = username
self.password = 'test'
submit
wait_for_login_submit
end
def wait_for_login_submit
wait_until(10) { !username_element.present? || (username_element.present? && username_element.value.empty?) }
wait_until(10) { error_message_element.present? || logout_element.present? || new_session_element.present? }
end
def do_logout
logout
end
def logged_in?
logout_element.present?
end
end
Here's the step definition where I'm calling the page object:
def login_role role
caps = Selenium::WebDriver::Remote::Capabilities.firefox(accept_insecure_certs: true)
#browser ||= Watir::Browser.new(:firefox, desired_capabilities: caps)
#browser.driver.manage.window.maximize
#browser.goto('http://ntdmatters-it4.nwie.net/TeamConnect/login')
#logged_in_user = User[RoleMapping[role]]
on_page(LoginPage).login_as(#logged_in_user.userid)
end
Here's my load order:
require 'pry'
require 'active_support'
require 'active_support/core_ext'
require 'chronic'
require 'page-object'
require 'rspec'
require 'watir'
require 'selenium-webdriver'
And here's the error I'm getting:
timed out after 30 seconds, waiting for #<Watir::Anchor: located: false; {
:id=>"LINK_default_logout", :tag_name=>"a"}> to be located (Watir::Exception::UnknownObjectException)
(eval):1:in `process_watir_call'
./features/support/env.src/pages/login_page.rb:48:in `do_logout'
./features/support/env.src/pages/login_page.rb:15:in `login_as'
./features/step_definitions/login_steps.rb:24:in `login_role'
./features/step_definitions/login_steps.rb:2:in `/^I login to Project
with role (.*)$/'
What happens is that the script will hit that the #logged_in? method and just sit there. Then it will time out and give me the above error message.
I can't help and wonder if this is some sort of configuration problem and that things just need to be loaded correctly or if there's some sort of deeper trap I have fallen into.
EDIT:
When I changed the Selenium logger level to 'Info', I got the following repeated for 30 seconds:
2017-07-12 12:11:21 INFO Selenium >>> http://127.0.0.1:4444/session/8d74a28f-
d8fc-4db6-a851-4f238edf7d70/element | {"using":"css selector","value":"#LINK_def
ault_logout"}
2017-07-12 12:11:21 INFO Selenium <- {"value":{"error":"no such element","messag
e":"Unable to locate element: #LINK_default_logout","stacktrace":"stack backtrac
e:\n 0: 0x4bd56f - <no info>\n 1: 0x4bdcc9 - <no info>\n
2: 0x43dc4d - <no info>\n 3: 0x44db84 - <no info>\n 4
: 0x44a1ca - <no info>\n 5: 0x4207bc - <no info>\n 6:
0x405e47 - <no info>\n 7: 0x6db3d9 - <no info>\n 8:
0x417847 - <no info>\n 9: 0x6d56d3 - <no info>\n 10: 0x
776c59cd - BaseThreadInitThunk"}}
EDIT2: This occurs whether or not the element is actually present or not.
Related
I'm maintaining a standalone test automation suite written in Rspec & Capybara and SitePrism (No Rails).
Recently I started integrating it with Testrail for reporting - I used rspec-testrail gem for that but I had to modify it a bit, because I also wanted to send Slack notifications with test progress and report.
Anyway, the integration works smoothly, except the fact that example processing is relying on example having an exception and lack of exception causes setting the test status as Passed on Testrail.
As it appears, after :each nor after :example in Rspec.configure doesn't guarantee that the example has finished running.
I also tried around :example and around :each as described here, but to no avail.
I inspected contents of example.metadata and it looks that example.metadata[:execution_result] has only started_at variable, but a finished example would have also finished_at and status variables, according to the docs
My suspicion (after reading the relish docs) is that :aggregated_failures is the cause of different metadata structure and multiple expects running in threads that are later merged into one backtrace.
Do you know how can I wait for the example to finish or how to hook into the state where it's finished?
Or maybe I should create a custom formatter where I would hook after example notifications printed to the console (I would like to keep the stacktrace there).
My code is as follows:
Test (both assertions are failing):
require 'spec_helper'
feature 'Sign in' do
let(:login_page) { LoginPage.new }
let(:user) { { email: ENV['ADMIN_EMAIL'], password: ENV['ADMIN_PASSWORD'] } }
scenario 'is successful and user is redirected to dashboard for user with correct credentials', testrail_id: 5694 do
login_page.load
login_page.form.email.set(user[:email])
login_page.form.password.set(user[:password])
login_page.form.submit_btn.click
expect(login_page.sidebar).to have_jobs(text: "some_nonexistenttext")
login_page.logout
expect(current_url).to have_content "google.com"
end
end
Console output from the above test:
Failures:
1) Sign in is successful and user is redirected to dashboard for user with correct credentials
Got 2 failures:
1.1) Failure/Error: expect(login_page.sidebar).to have_jobs(text: "blala")
expected #has_jobs?({:text=>"some_nonexistenttext"}) to return true, got false
# ./spec/auth/login_spec.rb:13:in `block (3 levels) in <top (required)>'
1.2) Failure/Error: expect(current_url).to have_content "google.com"
expected to find text "google.com" in "https://example.com/"
# ./spec/auth/login_spec.rb:15:in `block (3 levels) in <top (required)>'
Finished in 53.91 seconds (files took 1.45 seconds to load)
4 examples, 1 failure
Failed examples:
rspec ./spec/auth/login_spec.rb:8 # Sign in is successful and user is redirected to dashboard for user with correct credentials
Spec helper:
require 'rubygems'
require 'capybara/rspec'
require 'selenium-webdriver'
require 'site_prism'
require 'slack-notifier'
require_relative '../config'
require_relative '../lib/testrail'
...
RSpec.configure do |config|
config.define_derived_metadata do |meta|
meta[:aggregate_failures] = true
end
config.example_status_persistence_file_path = 'examples.txt'
config.before :all do
testrail_initialize_test_run!
end
config.after :example, testrail_id: proc { |value| !value.nil? } do |example|
RSpec::Testrail.process(example)
end
end
processing method (slightly modified from original)
def process(example)
if example.exception
status = 5
message = example.exception.message
slack_notifier.publish(message_text "Failed")
elsif example.skipped? || example.pending?
puts 'Example skipped or pending'
status = 10
message = 'Pending or not implemented'
else
status = 1
message = ''
end
client.send_post("add_result_for_case/#{testrun['id']}/#{example.metadata[:testrail_id]}",
status_id: status,
comment: message)
end
So basically all I had to was to use a reporter listener and process notifications inside it :)
config.reporter.register_listener RSpec::Testrail::Listener.new, :start, :example_failed, :example_passed, :example_pending, :stop
I have some experience of Selenium in Python and Cucumber/Watir/RSpec in Ruby, and can write scripts that execute successfully, but they aren't using classes, so I am trying to learn more about classes and splitting the scripts up in to pageobejcts.
I found this example to learn from: http://watir.com/guides/page-objects/ so copied the script and made some minor edits as you'll see below.
I'm using SublimeText 3.x with Ruby 2.4.x on Win10, so you know what tools I'm using.
I put the whole script in to a single .rb file (the only differences are that I replaced the URL and the elements to enter the username and password) and tried to execute it and get the following error:
C:/selenium/ruby/lotw/lotwlogin.rb:3:in `<main>': uninitialized constant Site (NameError).
I added the top line (required 'watir') line and it made no difference to the error encountered.
So I have in lotwlogin.rb essentilly the structure and syntax of the original script with custom elements. However, the core structure is reporting an error and I don't know what to do about it.
Here is my script:
require 'watir'
site = Site.new(Watir::Browser.new :chrome) # was :firefox but that no longer works since FF63
login_page = site.login_page.open
user_page = login_page.login_as "testuser", "testpassword" # dummy user and password for now
user_page.should be_logged_in
class BrowserContainer
def initialize(browser)
#browser = browser
end
end
class Site < BrowserContainer
def login_page
#login_page = LoginPage.new(#browser)
end
def user_page
#user_page = UserPage.new(#browser)
end
def close
#browser.close
end
end
class LoginPage < BrowserContainer
URL = "https://lotw.arrl.org/lotw/login"
def open
#browser.goto URL
##browser.window.maximize
self # no idea what this is for
end
def login_as(user, pass)
user_field.set user
password_field.set pass
login_button.click
next_page = UserPage.new(#browser)
Watir::Wait.until { next_page.loaded? }
next_page
end
private
def user_field
#browser.text_field(:name => "login")
end
def password_field
#browser.text_field(:name => "password")
end
def login_button
#browser.button(:value => "Log On")
end
end # LoginPage
class UserPage < BrowserContainer
def logged_in?
logged_in_element.exists?
end
def loaded?
#browser.h3 == "Welcome to Your Logbook of the World User Account Home Page"
end
private
def logged_in_element
#browser.div(:text => "Log off")
end
end # UserPage
Any assistance how to not get the Site error would be appreciated.
Thanks
Mike
You define class Site only a few lines below. But at that point, it's not yet known.
Move this logic to after all class definitions:
site = Site.new(Watir::Browser.new :chrome) # was :firefox but that no longer works since FF63
login_page = site.login_page.open
user_page = login_page.login_as "testuser", "testpassword" # dummy user and password for now
user_page.should be_logged_in
I am fairly new to automation testing and I am writing BDD automation test scenarios in Ruby using selenium-webdriver, when running my tests, they fail at the first step. (tumblr just as an example)
What does this error message mean and how do I fix it? Any help would be much appreciated!
In my feature file:
Feature: tumblr
#s1
Scenario: Logging in to Tumblr
Given I am on the Tumblr login page
When I enter my login details
Then I should be sent to the dashboard
In my login_page.rb:
def visit
#browser.goto "#{EnvConfig.base_url}/login"
await_on_page
end
In my login_step_defs.rb:
Given /^I am on the Odicci login page$/ do
#app.tumblr_login.visit
end
When /^I enter my login details$/ do
#app.tumblr_login.login
end
Then /^I should be sent to the dashboard$/ do
#app.tumblr_dashboard.go_to_dashboard
end
Initially when I was running 'cucumber features.feature' but the step definitions could not be located so the scenarios were finishing off as 'undefined' so running 'cucumber features.feature -r step_definitions works to run the tests but they fail because of this error message:
Scenario: Logging in to Tumblr # features.feature:4
Given I am on the Tumblr login page # step_definitions/login_step_defs.rb:2
undefined method `tumblr_login' for nil:NilClass (NoMethodError)
./step_definitions/login_step_defs.rb:3:in `/^I am on the Tumblr login page$/'
features.feature:5:in `Given I am on the Tumblr login page'
#maxpleaner
if ENV['HEADLESS']
require 'headless'
require 'selenium-webdriver'
headless = Headless.new display: '100'
headless.start
end
# Set up browser
# browser = Watir::Browser.new (ENV['BROWSER'] || 'chrome').to_sym
driver = Selenium::WebDriver.for :chrome
browser_type = ENV['BROWSER'] || 'chrome'
$setup_done = false
Before do |scenario|
#browser = browser
#app = App.new #browser
unless $setup_done
$setup_done = true
# This stuff will only run before the first scenario executed. Use it to set up data etc.
end
end
After do |scenario|
end
at_exit do
browser.quit
end
hi getting error which is not understand able i am new to ruby so please help .
i checked all thing which is possible for me.
require 'rubygems'
require 'selenium-webdriver'
require 'test/unit'
class SeleniumTest < Test::Unit::TestCase
driver = Selenium::WebDriver.for :firefox
driver.get "http://localhost:9000/assets/build/index.html#/login"
element = driver.find_element :name => "email"
element.send_keys "kaushik#abc.com"
element = driver.find_element :name => "password"
element.send_keys "password"
element.submit
page.find(:xpath, "//a[#href='#/courses/new']").click
#click_link ("//a[#href='#/courses/new']")
puts "Page title is #{driver.title}"
#page.should have_selector(:link_or_button, ' Create New Course...')
wait = Selenium::WebDriver::Wait.new(:timeout => 2000)
driver.quit
end
getting This error:-
TestClass.rb:7:in `<class:SeleniumTest>': undefined local variable or method `logger' for SeleniumTest:Class (NameError)
from TestClass.rb:6:in `<main>'
It seems that you didn't included the complete source code.
Besides that, all you code is bare in class SeleniumTest. You should put your code into the appropriate method or methods.
This type of errors are generated when objects or methods are not created or not scoped well.
In your case, the error message is telling you that the object logger in line 7 of you script does not exist.
As I can see from your source code, line 7 falls into the class definition. I guess you have something like
logger.log 'logging text'
in that line but you delete it from your post, and in lines 4 and 5 you have something like:
require 'logger'
logger = Logger.new('file.log')
If that is the case, you could put logger = Logger.new('file.log') inside the class definition, or define an instance object of type Logger inside the SeleniumClass class, or a global method or something other for logging messages.
Examples:
class SeleniumTest < Test::Unit::TestCase
logger = Logger.new('file.log')
logger.log "logging text"
...
end
or
class SeleniumTest < Test::Unit::TestCase
def initialize
#logger = Logger.new('file.log')
end
def log(message)
#logger.log mesage
end
...
def some_method_with_your_code
...
log "logging text"
...
end
end
st = SeleniumTest.new
st.some_method_with_your_code
... or something similar...
I hope this can help you solve your problem.
If not, you should put the complete source code and tell us what are you trying to do!
I have 66 watir scripts that I have been creating over the past week to automate testing on the clients website.
However I have recently found out about a test framework called MiniTest which I am trying to implement now.
The reason I have set the URL as a variable is because there are 5 different sites that these tests need to run on so when they want me to run my pack on a different website I just need to update that 1 variable and not in each individual test.
require 'minitest/autorun'
require "watir-webdriver"
class MPTEST < MiniTest::Unit::TestCase
def setup()
url = "http://thewebsite.com/"
$browser = Watir::Browser.new :chrome
$browser.goto url
end
def test_myTestCase
$browser.link(:text, "Submit your CV").click
sleep(2)
$browser.button(:value,"Submit").click
assert($browser.label.text.includes?("This field is required"))
def teardown
$browser.close
end
end
When running that I receive the following output:
NameError: undefined local variable or method 'browser' for #<MPTEST:0x4cc72f8>c:/directory stuff...
Any ideas?
EDIT I have browser working however now there is an issue with my assert:
New code:
require 'minitest/autorun'
require "watir-webdriver"
class MPTEST < MiniTest::Unit::TestCase
def setup()
url ="http://thewebsite.com"
$browser = Watir::Browser.new :chrome
$browser.goto url
end
def test_myTestCase
$browser.link(:text, "Submit your CV").click
sleep(2)
$browser.button(:value,"Submit").click
assert($browser.label.text.includes?("This field is required"))
end
def teardown
$browser.close
end
end
And the error is:
NoMEthodError: undefined method 'includes?' for "":String
it seems to me you can you use #browser instead of $browser (but the problem might be not in this code)
The exception
NoMEthodError: undefined method 'includes?' for "":String
Is due to strings, in this case the value returned by $browser.label.text do not have an includes? method.
The method you actually want is include? (no plural):
assert($browser.label.text.include?("This field is required"))