I was trying to use capybara to help me upload vocabulary to memrise.com, but I encounter some problems in its login page.
Here is what I've written.
def sign_in
self.visit 'https://www.memrise.com/login/'
find(".inpt-large[name='username']").set 'my-username' # Step 1
find(".inpt-large[name='password']").set 'my-password' # Step 2
find('input.btn-success.btn-large').click # Step 3
end
It can finish the step1 and setp2 but fail at step3 sometimes.
And below is the error message.
gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/response.rb:70:in `assert_ok': Element is not clickable at point (592.5, 23). Other element would receive the click: <span class="nav-item-btn-text"></span> (Selenium::WebDriver::Error::UnknownError)
Since the only items on the page I can find matching <span class="nav-item-btn-text"></span> are in the fixed header, I'm guessing you're running your tests with too small of a window size, so the actual Login button you want to hit is off the page when the test is run. This means when the test goes to click the button, it needs to scroll the item into view and it does that by scrolling it to the top of the page. That leaves the button behind the fixed header and unable to be clicked. To fix that you can either
increase your window size so the form doesn't need to be scrolled
set the elementScrollBehavior capability to 1 in your driver registration which will cause elements to be scrolled until they're visible at the bottom of the page rather than top.
scroll the page yourself before clicking the button
Additionally is there are reason you're using find(...).set vs just using fill_in for this form?
def sign_in
visit 'https://www.memrise.com/login/'
within('form#login') do
fill_in('username', with: 'my-username')
fill_in('password', with: 'my-password')
click_button('Login')
end
assert_text('You are now logged in') # whatever messagge is shown once login complete
end
Related
I cannot get Capybara to click on the SCA/3DS ‘Complete authentication’ button when running RSpec tests. Similar tests which do not trigger SCA pass just fine, and if I run VNC to view what Firefox is doing, the button is visible and I can click it myself in the browser.
My problem seems very similar to what’s discussed in the comments here, but the solutions do not work: I have tried changing the browser used, and flattening the iframe traversal.
Test code:
scenario "SCA required" do
create_payment_method(account, payment_method: "stripe", last_four: "1234")
visit "/billing"
click_on "Enter Card Payment"
within "#main-content" do
within_frame(find("iframe")) do # Stripe payment form is in an iframe.
find("input#Field-numberInput").set("4000002760003184") # SCA-required test card.
find("input#Field-expiryInput").set("1234")
find("input#Field-cvcInput").set("123")
find("input#Field-postalCodeInput").set("12345")
end
end
find("button#submit").click
# Stripe nests the popup in several layers of iframes.
stripe_frame = find("body > div > iframe") # Popup is prepended to the body element.
switch_to_frame(stripe_frame)
challenge_frame = find("iframe#challengeFrame")
switch_to_frame(challenge_frame)
fullscreen_frame = find("iframe.FullscreenFrame")
switch_to_frame(fullscreen_frame)
click_on "Complete authentication"
switch_to_frame(:top)
expect(page).to have_content "ends in 3184"
end
Is there some way to debug what Selenium is doing under the hood here? I don’t see any movement on the page when running click_on "Complete authentication", but if I click on the button myself in the Firefox instance being controlled by Selenium it does work.
Running click_on "Complete authentication" returns the element clicked, which appears to be the expected element when I drop into Pry and call native.dom_attribute("id").
I can see an error of some kind in the browser container’s logs:
1654078084345 Marionette WARN TimedPromise timed out after 500 ms: stacktrace:
TimedPromise/<#chrome://remote/content/marionette/sync.js:239:19
TimedPromise#chrome://remote/content/marionette/sync.js:224:10
interaction.flushEventLoop#chrome://remote/content/marionette/interaction.js:431:10
webdriverClickElement#chrome://remote/content/marionette/interaction.js:179:31
It’s a bit odd because it mentions #chrome but this is a headless Firefox instance.
Assuming no error is returned by the click_on call then I'm guessing the button is being clicked before it's ready to be clicked. You can test that by sleeping for a few seconds before calling 'click_on'/navigating through the frames. If that fixes it then you'd need to look at what changes on the button to indicate that the page has finished whatever work it's doing and the button is ready to be clicked.
I have solved this by clicking on the button directly with JavaScript:
execute_script(%Q{ document.querySelector("button#test-source-authorize-3ds").click() })
However, this does not in any way explain why click_on is not working, and if anything makes it more strange that it is not. If anyone has a better solution or a way to dig into why Capybara/Selenium are failing then that would be welcome.
I have encountered an issue that really makes me confused. I'm able to find elements on a page but after I interact with elements from bottom of page, I cannot click element that are on top of page without scrolling to top of page. This only happens on Edge browser (Chrome, Firefox work well).
My code is as below:
page.fill_in_form # This part is middle/bottom of page
page.click_button 'SAVE' # This button is middle/bottom of page
page.select_sub_menu 'Category' #This sub menu is top navigation of page
And this is error message.
Unable to find css "#subnav"
My select_sub_menu funciton:
def select_sub_menu(sub_menu)
within('#subnav') { click_link(sub_menu) }
end
It looks like Capybara does not recognise the elements are on top of page after scrolling into middle of page although they are available.
My driver is configured as below:
Selenium::WebDriver::Edge.driver_path = "#{file_path}/MicrosoftWebDriver.exe"
Is there any solution for this?
I am trying to automate tests in Ruby using the latest Watir-Webdriver 0.9.1, Selenium-Webdriver 2.53.0 and Chrome extension 2.21. However the website that I am testing has static headers at the top or sometimes static footers at the bottom. Hence since Watir auto-scrolls an element into view before clicking, the elements get hidden under the static header or the static footer. I do not want to set desired_capabitlites (ElementScrollBehavior) to 1 or 0 as the websites I am testing can have both - static header or static footer or both.
Hence the question are:
1) Why does Watir throw an exception Element not clickable even when the element is visible and present? See ruby code ( I have picked a random company website for an example) and the results below.
2) How can I resolve this without resorting to ElementScrollBehaviour?
Ruby code:
require 'watir-webdriver'
browser = Watir::Browser.new :chrome
begin
# Step 1
browser.goto "shop.coles.com.au/online/mobile/national"
# Step 2 - click on 'Full Website' link at the bottom
link = browser.link(text: "Full website")
#check if link exists, present and visible?
puts link.exists?
puts link.present?
puts link.visible?
#click on link
link.click
rescue => e
puts e.inspect
ensure
sleep 5
end
puts browser.url
browser.close
Result:
$ ruby link_not_clickable.rb
true
true
true
Selenium::WebDriver::Error::UnknownError: unknown error: Element is not clickable at point (460, 1295). Other element would receive the click: div class="shoppingFooter"...div
(Session info: chrome=50.0.2661.75)
(Driver info: chromedriver=2.21.371459 (36d3d07f660ff2bc1bf28a75d1cdabed0983e7c4),platform=Mac OS X 10.10.5 x86_64)>
http://shop.coles.com.au/online/mobile/national
thanks!
You can do a click at any element without getting it visible. Check this out:
link.fire_event('click')
BUT It is very very very not good decision as far as it will click the element even if it is not actually visible or in case when it is just impossible to click it (because of broken sticky footer for example).
That's why much better to wait the fooler, scroll the page and then click like:
browser.div(id: "footerMessageArea").wait_until_present
browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
link.click
The sticky footer is blocking webdriver from performing the click, hence the message that says 'other element would receive the click'.
There are several different ways you can get around this.
Scroll down to the bottom of the page before the click
Hide/Delete the sticky footer before any/all link clicks
Focus on an element below the element you want to click before you perform the click
I Guess your element is visible in the screen.
Before clicking on the element first you have to scroll the webpage so that element is visible then perform the click. Hope it should work.
I had similar issue,
I just used following javascript code with watir:
link = browser.link(text: "Full website")
#browser.execute_script("arguments[0].focus(); arguments[0].click();", link)
Sometimes I have to use .click! which i believe is the fire_event equivalent. Basically something is layered weird, and you just have to go around the front end mess.
I'm using watir-webdriver with the page-object gem to drive cucumber tests for a single web page app built in angular js.
The site uses a multiple stage registration process, filling a series of details each time then clicking a 'next' button. (which is enabled when all details are completed for that page)
The issue occurs when I'm attempting to reuse the following step definition:
And(/^I click next$/) do
#registration = RegistrationPage.new(#browser)
#registration.click_next
end
Which calls the page-object:
class RegistrationPage
include PageObject
button(:next, :value => "Next")
def click_next
#browser.wait_while { next_element.disabled? }
next_element.click
end
end
For the first section, the Next button is found correctly, however on the second call to the step definition, the button cannot be found, despite the button being verifiably enabled and otherwise identical.
I see that you've answered your question but in case it helps to explain it to anyone else:
The issue is likely that to watir it isn't the same next button on each page and all of the next buttons are in scope all of the time. Therefore to click the correct one you would have to use the index property of the button you want i.e. index: 1 for the second page and index 2 for the the button on the third page.
Watir code which is working but add condition link is not identifying again here :(
require 'spec'
require 'watir'
browser = Watir::Browser.new
pages = { "RCM Workspace Homepage" => "http://rcm-bpmt.apmoller.net/workspace/faces/jsf/workspace/workspace.xhtml" }
Given(/^that I am on the (.*?)$/) do |page|
# Opening new browser and going to the page which is specified
browser.goto(pages[page])
#Maximizing the opened browser window
browser.maximize
end
When(/^I search for (.*?)$/) do |text|
# Ensuring that we have opened expected page only by verifying the page content
browser.html.include?(text).should == true
end
Then(/^I click on Show Filters link$/) do
#Opening the Conditions window by clicking on the show filters link
browser.link(:id, "portletComponentWorkList_viewNormalModeWorkList_viewPanel_showFiltersLink").click
#Clicking on Add condition link which is placed in a frame and it opnes when I click on Show filters link
browser.element(:id, 'portletComponentWorkList_viewNormalModeWorkList_viewPanel_conditionButton').click
end
HTML details:
<A id=portletComponentWorkList_viewNormalModeWorkList_viewPanel_conditionButton onclick="oc.ajax.jsf.doCallback('portletComponentWorkList','portletComponentWorkList:viewNormalModeWorkList:viewPanel:conditionButton');return false;" href="http://rcm-bpmt.apmoller.net/workspace/faces/jsf/workspace/workspace.xhtml#">
Add condition
</A>
In the following line, Watir will look for the element anywhere except for in the frames.
browser.element(:id, 'portletComponentWorkList_viewNormalModeWorkList_viewPanel_conditionButton').click
Unlike other elements, you must tell Watir when an element is in a frame. This is done similar to how you would scope the search of an element to a specific element.
For example, if there is only 1 frame or your element is in the first frame, you can do (noting the addition of the .frame):
browser.frame.element(:id, 'portletComponentWorkList_viewNormalModeWorkList_viewPanel_conditionButton').click
If there are multiple frames, you will need to add parameters to be more specific about which frame to use. For example, if the frame has an id:
browser.frame(:id => 'myframe').element(:id, 'portletComponentWorkList_viewNormalModeWorkList_viewPanel_conditionButton').click