How can I switch between two frames with Capybara - ruby

I am trying do something inside 2 frames but error raises everytime when I try to switch between frames.
For example:
# encoding: utf-8
require "capybara/dsl"
Capybara.run_server = false
Capybara.current_driver = :selenium
Capybara.app_host = 'https://hb.posted.co.rs/posted'
class Account
include Capybara::DSL
def check_balance
visit('/')
page.driver.browser.switch_to.frame 'main'
fill_in 'korisnik', :with => 'foo'
fill_in 'lozinka', :with => 'bar'
click_button 'Potvrda unosa'
page.driver.browser.switch_to.frame 'header'
click_on 'Stanje'
end
end
account = Account.new
account.check_balance
Error is:
[remote server]
file:///tmp/webdriver-profile20120810-9163-xy6dtm/extensions/fxdriver#googlecode.com/components/driver_component.js:6638:in
`unknown': Unable to locate frame: main
(Selenium::WebDriver::Error::NoSuchFrameError)
What is the problem? Maybe I am doing something wrong here?
If I change order of switching frames so try first to switch to 'header' then switch to 'main' frame then same error raises except that it says that this time there is no 'main' frame:
# encoding: utf-8
require "capybara/dsl"
Capybara.run_server = false
Capybara.current_driver = :selenium
Capybara.app_host = 'https://hb.posted.co.rs/posted'
class Account
include Capybara::DSL
def check_balance
visit('/')
page.driver.browser.switch_to.frame 'header'
click_on 'Stanje'
page.driver.browser.switch_to.frame 'main'
fill_in 'korisnik', :with => 'foo'
fill_in 'lozinka', :with => 'bar'
click_button 'Potvrda unosa'
end
end
account = Account.new
account.check_balance
Error:
[remote server]
file:///tmp/webdriver-profile20120810-9247-w3o5hj/extensions/fxdriver#googlecode.com/components/driver_component.js:6638:in
`unknown': Unable to locate frame: main
(Selenium::WebDriver::Error::NoSuchFrameError)

Problem
The problem is that when you do page.driver.browser.switch_to.frame, it switches the page's context to the frame. All actions against the page are now actually against the frame. So when you are switching frames the second time, you are actually saying find the 'header' frame inside the 'main' frame (rather than, what I assume you want, the 'header' frame inside the main page).
Solution - Capybara within_frame (recommended):
When working inside a frame, you should use Capybara's within_frame method. You would want to do:
def check_balance
visit('/')
within_frame('main'){
fill_in 'korisnik', :with => 'foo'
fill_in 'lozinka', :with => 'bar'
click_button 'Potvrda unosa'
}
within_frame('header'){
click_on 'Stanje'
}
end
Solution - Selenium switch_to:
If you want to do the frame management yourself (ie not use Capybara's built-in method), you can switch the page's context back to the browser and then to the second frame. This would look like the following. Though I would suggest using the built-in Capybara method.
def check_balance
visit('/')
page.driver.browser.switch_to.frame 'header'
click_on 'Stanje'
#Switch page context back to the main browser
page.driver.browser.switch_to.default_content
page.driver.browser.switch_to.frame 'main'
fill_in 'korisnik', :with => 'foo'
fill_in 'lozinka', :with => 'bar'
click_button 'Potvrda unosa'
end

I've found solution. within_frame works as expected:
# encoding: utf-8
require "capybara/dsl"
Capybara.run_server = false
Capybara.current_driver = :selenium
Capybara.app_host = 'https://hb.posted.co.rs/posted'
class Account
include Capybara::DSL
def check_balance
visit('/')
within_frame 'main' do
fill_in 'korisnik', :with => 'foo'
fill_in 'lozinka', :with => 'bar'
click_button 'Potvrda unosa'
end
within_frame 'header' do
click_on 'Stanje'
end
end
end
account = Account.new
account.check_balance
I've found source code for within_frame in file https://github.com/jnicklas/capybara/blob/master/lib/capybara/selenium/driver.rb. starting from line 81.
EDIT:
While I wrote this answer, #JustinKo answered question, so both answers are correct but +1 and accepted answer for him.

Related

Getting Frozen Error-Can't modify frozen string

Getting frozen error while running below mentioned cod. Also find the helpers files. Below is the main file:
require 'spec_helper.rb'
require 'rspec_capybara_assignment_helper.rb'
describe 'Open the automationpractices site' , :type => :request do
it 'Test: Page Content', :page do
visit "http://automationpractice.com/index.php"
expect(page).to have_xpath(".//img[contains(#src,'automationpractice.com/img/logo')]")
expect(page).to have_xpath(".//input[#id='search_query_top']")
expect(page).to have_link("Contact us")
expect(page).to have_link("Sign in")
within('div#block_top_menu') do
expect(page).to have_link("Women")
expect(page).to have_link("Dresses")
expect(page).to have_link("T-shirts")
end
within('div#center_column') do
expect(page).to have_link("Popular")
expect(page).to have_link("Best Sellers")
end
expect(page).to have_content("Automation Practice Website")
end
end
Spec_Helper file:-spec_helper.rb
require 'rspec'
require 'capybara/rspec'
require 'capybara/dsl'
require "selenium-webdriver"
require "capybara"
require 'capybara/rspec/matchers'
RSpec.configure do |config|
config.include Capybara::DSL , :type => :request # to include capybara DSL methods
config.include Capybara::RSpecMatchers,:type => :request # to include Rspec matchers available.
end
Capybara.configure do |config|
config.run_server = false
config.default_driver = :selenium # which driver to use (selenium / chrome /internet explorer)
config.default_selector = :css #(by default css selector) # if user want to use xpath, he has to write find(:xpath, <xpath>).click
config.app_host = "http://automationpractice.com/index.php" # host app
config.default_max_wait_time = 5 # wait for 4 seconds.
config.app_host = #url
config.ignore_hidden_elements = true # will ignore hidden elements on page.
config.match =:prefer_exact # check for exact match.
end
Rspec Capybara Assignmnet Helper File:
rspec_capybara_assignment_helper.rb
def click_on(value)
find(value).click
end
def link_click(value)
click_link(value)
end
def button_click(value)
click_button(value)
end
def login_application
link_click('Sign in')
fill_in('email', :with => 'test.test#testing.com')
fill_in('passwd', :with => 'testtest')
button_click('SubmitLogin')
end
def sign_out
link_click('Sign out')
end
def search_product(value)
fill_in('search_query_top', :with => value)
button_click('Search')
sleep(2)
end
def add_product(value)
page.find(:css,'.product-image-container').hover
sleep(2)
first("a", :text => "More").click
sleep(4)
fill_in('quantity_wanted', :with => '2', visible: false)
select('M', :from => 'group_1')
find('button.exclusive').click
sleep(2)
first("span", :text => "Continue shopping", wait: 3).click
sleep(2)
end
def check_locator(value)
expect(page).to have_selector(value)
end
Error as below:
Open the automationpractices site
Test: Page Content (FAILED - 1)
Failures:
Open the automationpractices site Test: Page Content
Failure/Error: visit "http://automationpractice.com/index.php"
FrozenError:
can't modify frozen String
./spec/tests/rspec_capybara_assignment.rb:6:in `block (2 levels) in <top (required)>'
Finished in 0.7789 seconds (files took 3.61 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/tests/rspec_capybara_assignment.rb:5 # Open the automationpractices site Test: Page Content
This appears to be related to selenium-webdriver, not capybara itself.
There's an issue about this at https://github.com/SeleniumHQ/selenium/issues/7365
To fix, specify in your gemfile that you want 3.142.4 as a minimum: gem 'selenium-webdriver', '~> 3.142.4'
And then run bundle update selenium-webdriver
That should get this specific issue resolved.

Rspec and Capybara uninitialized constant

I am using Rspec 3.2 and Capybara 2.4 in a non RoR project. I am trying to test with feature mode provided by Capybara gem.
$ cat .rspec
--color
--require spec_helper
$ cat spec/features/test_spec.rb
feature 'login' do
username ="rspec#{Time.now.to_i}"
valid_email = "#{username}#gmail.com"
scenario 'with valid email' do
sign_up_with valid_email, 'pwd', 'pwd', username
expect(page).to have_content('LOGOUT')
end
end
$ cat spec/support/session_helper.rb
module SessionHelper
def sign_up_with(email, password, confirm_password, username)
visit '/signup'
fill_in 'email', with: email
fill_in 'password', with: password
fill_in 'passconf', with: confirm_password
fill_in 'username', with: username
click_button 'submit'
end
end
$ cat spec/spec_helper.rb
require 'capybara/rspec'
Capybara.default_driver = :selenium
RSpec.configure do |config|
...
config.include SessionHelper, type: :feature
...
end
This is a non RoR project, when I run the test I have this error:
$ rspec
spec/spec_helper.rb:26:in `block in <top (required)>': uninitialized constant SessionHelper (NameError)
In online documentation there are many examples, I have structured my files like the examples but it not works.
The way I handle this in all of my projects is like this:
Require all the support files:
In spec_helper.rb
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
And then your spec/support/session_helper.rb should look like this:
module SessionHelper
def sign_up_with(email, password, confirm_password, username)
visit '/signup'
fill_in 'email', with: email
fill_in 'password', with: password
fill_in 'passconf', with: confirm_password
fill_in 'username', with: username
click_button 'submit'
end
end
RSpec.configure do |config|
# Remove the equivalent line from spec_helper.rb
config.include(SessionHelper)
end

Issue with Shoes setup

When i am running shoes.rb file, which contains code to install gem, it throws error.
Undefined method setup for Shoes:Class
Code:
Shoes.setup do
gem 'activerecord' # install AR if not found
require 'active_record'
require 'fileutils'
ActiveRecord::Base.establish_connection(
:adapter => 'postgresql',
:dbfile => 'shoes_app'
)
# create the db if not found
unless File.exist?("shoes_app.sqlite3")
ActiveRecord::Schema.define do
create_table :notes do |t|
t.column :message, :string
end
end
end
end
class ShoesApp < Shoes
require 'note'
url '/', :index
def index
para 'Say something...'
flow do
#note = edit_line
button 'OK' do
Note.new(:message => #note.text).save
#note.text = ''
#result.replace get_notes
end
end
#result = para get_notes
end
def get_notes
messages = []
notes = Note.find(:all, :select => 'message')
notes.each do |foo|
messages << foo.message
end
out = messages.join("n")
end
end
Shoes.app :title => 'Notes', :width => 260, :height => 350
The problem was using Shoes4, where the setup method was unimplemented.
Shoes4 now implements Shoes.setup for backwards compatibility reasons but you don't really need it, so it doesn't do anything except for printing a warning that you should rather do gem install gem_name instead of using Shoes.setup.

Why am I getting FactoryGirl wrong number of arguments error?

Having strange behavior from FactoryGirl in non-rails app. getting wrong number of arguments error...don't know why.
gideon#thefonso ~/Sites/testing (master)$ rspec spec
/Users/gideon/.rvm/gems/ruby-1.9.3-p194/gems/factory_girl-4.1.0/lib/factory_girl/syntax/default.rb:6:in `define': wrong number of arguments (1 for 0) (ArgumentError)
from /Users/gideon/Sites/testing/spec/factories.rb:1:in `<top (required)>'
Here are the files involved...
login_user_spec.rb
require_relative '../spec_helper'
require_relative '../lib/login_user'
describe "Existing User Log in Scenario", :type => :request do
before :all do
#user = FactoryGirl(:user)
end
xit "should allow user to select login from top nav" do
visit "/"
within("#main-header")do
click_link 'Log In'
end
page.should have_content('Log in to your account')
end
it "and fill in login form" do
visit "/login"
within("#login-form")do
fill_in 'user-email', :with => #user.email
fill_in 'user-password', :with => #user.password
end
#FIXME - the design crew will make this go away
within("#login-form") do
click_link '#login-link' #this gives false failing test...geek query...why?
end
page.should have_content('Manage courses')
end
end
Factories.rb
FactoryGirl.define :user do |u|
u.email "joe#website.com"
u.password "joe009"
end
user.rb
class User
attr_accessor :email, :password
end
spec_helper.rb
require 'rubygems'
require 'bundler/setup'
require 'capybara'
require 'rspec'
require 'capybara/rspec'
require 'json'
require 'capybara/dsl'
# Capybara configuration
Capybara.default_driver = :selenium
Capybara.app_host = "http://www.website.com"
require 'factory_girl'
# give me ma stuff
FactoryGirl.find_definitions
require "rspec/expectations"
include Capybara::DSL
include RSpec::Matchers
ANSWER: :user is a reserved word..changed it to :stuff...works fine now.
Try to use new syntax from readme
FactoryGirl.define do
factory :user do
email "joe#website.com"
password "joe009"
end
end
If this is a non-rails app you will have to create a Userclass first. I'm not sure if you have to have instance vars with name, password and email but you definitely will have to have that class defined somewhere.
See the Getting Started file on Github for more on that.
Try this
FactoryGirl.define do
factory :user do |u|
u.email "joe#website.com"
u.password "joe009"
end
end

Capybara testing of sinatra app fails

I am trying to test a sinatra app using minitest and capybara but get several errors on all tests using capybara features like fill_in or visit.
test_index gives:
undefined local variable or method `app' for #
test_create_user gives:
Invalid expression: .////form[#id = 'register']
test_same_email gives:
Unable to find css "#register"
test_login gives:
cannot fill in, no text field, text area or password field with id,
name, or label 'email' found
Any suggestions on what may be wrong?
test.rb
require "test/unit"
require "minitest/autorun"
require "capybara"
require "capybara/dsl"
require "rack/test"
require_relative "../lib/kimsin.rb"
ENV["RACK_ENV"] = "test"
class KimsinTests < Test::Unit::TestCase
include Rack::Test::Methods
include Capybara::DSL
Capybara.app = Sinatra::Application
def test_index
visit "/"
assert stuff..
end
def test_create_user
visit "/user/new"
within "//form#register" do
fill_in :username, :with => "first#company.com"
fill_in :password, :with => "abC123?*"
fill_in :confirm_password, :with => "abC123?*"
click_link "Register"
end
assert stuff..
end
end
I'm using cygwin 1.7.15-1 on windows 7, rvm -v 1.14.1 (stable) and ruby -v 1.9.2p320.
----UPDATE----
Finally I got the tests work by incorporating Steve's suggestions:
within "form#register" do
fill_in "email", :with => "first#company.com"
click_button "Register"
and asserting the response by using capybara_minitest_spec:
page.must_have_content "Password"
page.must_have_button "Register"
I just answered a more recent question you posted about Sintra with Webrat.
Acceptance testing of sinatra app using webrat fails
I think the problem here is the same. Try replacing:
Capybara.app = Sinatra::Application
with:
Capybara.app = Kimsin
Personally I would choose Capybara over Webrat.

Resources