Determining if a link exists w/ Cucumber/Capybara - cucumber

I want to verify that a link with a specific href exists on a page. I am currently doing I should see "/some-link-here" but that seems to fail. How can I make sure that link exists without having to do click + I should be on "/some-link-here" page?

You will need to add custom step
Then /^"([^\"]*)" should link to "([^\"]*)"(?: within "([^\"]*)")$/ do |link_text,
page_name, container|
with_scope(container) do
URI.parse(page.find_link(link_text)['href']).path.should == path_to(page_name)
end
end
You can use the step like Then "User Login" should link to "the user_login page", user_login is the name of your route

I used jatin's answer, but have a separate scoping step:
When /^(.*) within ([^:]+)$/ do |step, parent|
with_scope(parent) { When step }
end
Then /^"([^\"]*)" should link to "([^\"]*)"$/ do |link_text, page_name|
URI.parse(page.find_link(link_text)['href']).path.should == path_to(page_name)
end
Then I have this in my test:
step '"my foods" should link to "food_histories" within ".tabs"'
And this in my paths:
# note: lots not shown
def path_to(page_name)
case page_name
when /^food_histories$/
food_histories_path
end
end

This is what I have done myself, quite simple but it does mean you are hardcoding your url which to be honest is not ideal as it makes your test very brittle. Especially if you are using 3rd party URL's!
But if you are using a url that you manage and are happy to maintain this test then go for it.
Then /^the link is "(.*?)"$/ do |arg1|
page.should have_xpath("//a[#href='" + arg1 + "'][#target='_blank']")
end

I first landed here, when looking for a solution and thought I would give an updated answer. It depends what your capybara syntax is, but using the matcher has_link? you could write for href = /some-link-here and link_text "Click Me"
expect(page).to have_link("Click Me", href: '/some-link-here')

Related

Integrate GeeTestTask(python3_anticaptcha) with selenium in python3

I have a problem about python3_anticaptcha (api provided by anti-captcha.com), search on web, find support and try over a month but no luck.
API doc:
https://anticaptcha.atlassian.net/wiki/spaces/API/pages/416972814/GeeTestTaskProxyless+-+captcha+from+geetest.com+without+proxy
I am doing a auto login on a website, and copy the api on anti-captcha's doc:
def runGee(self, challenge):
print("start gee")
try:
# Enter the key to the AntiCaptcha service from your account. Anticaptcha service key.
ANTICAPTCHA_KEY = "mycode"
# обязательные параметры
websiteURL = "https:\/\/www.nike.com.hk"
gt = "2328764cdf162e8e60cc0b04383fef81"
print("sloving1")
print("challenge:" ,challenge)
# пример работы с GeeTestTask без прокси
result = GeeTestTaskProxyless.GeeTestTaskProxyless(anticaptcha_key=ANTICAPTCHA_KEY,
websiteURL=websiteURL,
gt=gt).captcha_handler(challenge=challenge)
print("sloving2")
print(result)
print("--end gee--")
except Exception as err:
print(err)
print("--end with error--")
However, the geetask start over 3 minute(or more), and got error everytime. usually error code like:
{'errorId': 34, 'errorCode': 'ERROR_TOKEN_EXPIRED', 'errorDescription': 'Captcha provider
reported that additional variable token has expired.', 'taskId': 1204556667}
or
{'errorId': 12, 'errorCode': 'ERROR_CAPTCHA_UNSOLVABLE', 'errorDescription': ' Captcha
could not be solved by 5 different workers.', 'taskId': 1204060350}
..etc
depends on what parameter i passed.
May i know am i passing the right value to geetask? or some wrong on the code?
Moreover, if geetest return the correct value, i need to do any else to pass capcha(or pass code to geetest server) or GeeTestTaskProxyless already done(not to do anything)?
it is extremely hard to me, does anyone had used this api successfully? Thanks
The problem is not in the anticaptcha but in the geetest provider.
The token challenger can only be used once, when your browser loads the geetest captcha it expires the token.
To fix this problem, you only need to block the request that consumes the token in your browser.
go to devtools and add the block for the geestest captcha API in the browser, like this:
You can automatically integrate this into the selenium with the following command:
driver.execute_cdp_cmd('Network.setBlockedURLs', {"urls": ["api.geetest.com/get.php"]})
driver.execute_cdp_cmd('Network.enable', {})
It seems for me that those errors are because of proxy (if you use any) or just bad IP.
Personally, I use another captcha service and I didn't have such problems with it.
I advice you to try it, it's actually much easier: https://2captcha.com/2captcha-api#solving_geetest
You should send a request like this one:
https://2captcha.com/in.php?key=1abc234de56fab7c89012d34e56fa7b8&method=geetest&gt=f1ab2cdefa3456789012345b6c78d90e&challenge=12345678abc90123d45678ef90123a456b&api_server=api-na.geetest.com&pageurl=https://www.example.com/page/
What you need to archieve is to get correct answer from it, like this one:
{
"challenge":"1a2b3456cd67890e12345fab678901c2de",
"validate":"09fe8d7c6ba54f32e1dcb0a9fedc8765",
"seccode":"12fe3d4c56789ba01f2e345d6789c012|jordan" }
Then you just need to implement that answer on a site. Just read the first link I gave you.
Cheers.

Calabash iOS - How to clear text in a webview

clear_text doesn't work for me when testing a webview. Does anyone know of a different method for webview/cordova apps? The locator I'm using is "webView css:'input#username'" but that seems to be fine as enter_text is working.
Any suggestions?
Thanks,
Lewis.
Thanks but set_text("webView css:'input#username'", "") didn't work. I ended up using the solution you mentioned here
Thanks.
set_text("webView css:'input#username'", "")
You might also try using the WebView JavaScript API
When I had a similar problem, I ended up using something like this :
Then /^I clear a field with "([^\"]*)" text$/ do |name|
name = set_value name
element = query("UITextFieldLabel text: '#{name}'")[0]
touch(element)
wait_for_keyboard
name.to_s.split('').each do |c|
keyboard_enter_char 'Delete'
end
end
Details are in here: Clear field with calabash-ios

How can I disable javascript for the page that's being opened?

I was up till 1 am last night trying to find an example of how to do this. My theory is that I'd write a function that would comment out all javascript.
The second option would be to add the url to the list of javascript settings.
Right now my extension is very simple:
function linkOnClick(info, tab) {
window.open(info.linkUrl)
}
chrome.contextMenus.create(
{title: "Load with no Javascript", contexts:["link"], onclick: linkOnClick});
This is my first extension and I'm kind of lost.
edit: let me know if I should also post the manifest.json.
edit: I can't mark this as solved for 2 days (why? who knows.), so I'll probably not remember to mark this as solved. So accept this as the official making: SOLVED.
chrome.contentSettings.javascript.set is the thing that disables javascript.
Here's the part that disables javascript.
(Google, here's what an actual example should look like):
chrome.contentSettings.javascript.set(
{'primaryPattern':AnyDomainName, /*this is a string with the domain*/
'setting': "block", /* block the domain. Can be switched to "allow" */
'scope':'regular'}, /*it's either regular or incognito*/
function(){
/*optional action you want to
take place AFTER something's been blocked'*/
});
Here's the script I used to import into my json script for my chrome extension.
var link=""
var pattern=""
function linkOnClick(info, tab) {
r = /:\/\/(.[^/]+)/;
link=info.linkUrl
pattern="http://"+link.match(r)[1]+"/*"
chrome.contentSettings.javascript.set(
{'primaryPattern':pattern,
'setting': "block",
'scope':'regular'},
function(){
window.open(link)
});
}
chrome.contextMenus.create({title: "Load with no Javascript", contexts:["link"], onclick: linkOnClick});
I couldn't tell how any of this worked by reading the developer.chrome.com page! They really need add complete working examples or allow a way for users to add examples. I can't even use it. The git hub link is what saved me.

watir, cucumber, select a variable with string without using a case/when

I have a cucumber step like this (it is not working, but it is a concept):
And (/^I navigate to this url '(.*?)'$/) do |web|
web = $ + 'web' + '_url'
#browser.goto web
end
In a different file, paths.rb, I have this hardcoded URL:
$google_url = http://www.google.com
I want to be able to select that URL, by doing something like this:
And I navigate to this url 'google'
Right now, I have not find a way of selecting the 'real content' of the variable $google_url. Any ideas?
Solution - Using eval (bad idea)
The quickest and most direct solution is to use eval to execute the string to get the variable. However, it is often suggested that eval is a bad idea.
And (/^I navigate to this url '(.*?)'$/) do |web|
url = eval('$' + web + '_url')
#browser.goto url
end
Solution - Create a module and use send
I think a better idea would be to create a module that includes all your path constants. This would be better because (1) you prevent polluting the space with many global variables and (2) using send is safer than eval.
In your paths.rb, you could replace your global variables with a module that can return the different urls:
module Paths
class << self
def google_url()
'http://www.google.com'
end
end
end
You would then use send in your steps to translate the string to a method:
And (/^I navigate to this url '(.*?)'$/) do |web|
url = Paths.send(web + '_url')
#browser.goto url
end

"immediate_failed" - Could not automatially log in the user

I have a problem when I developed my website with Google+ sign-in:
I did step by step that the doc told me but I always failed at step4:
https://developers.google.com/+/web/signin/
the result was always ""immediate_failed" - Could not automatially log in the user", I just don't kown why, can anyone help me, thanks very much! :-(
Note that in the sample code you pointed to, the "immediate_failed" check is commented out. This is intentional, since the first time a user encounters the Sign-in button on the page, it will fail.
The reason it fails is that when the page first loads, before the user even presses the button, a request is sent to Google to determine if the user has already logged in (via Google or another site, for example). If they are - there is no need for them to log in again, so the button never needs to be shown. But if they have not been logged in already, you will get the "immediate_failed" response, and will need to either show (or not clear) the button.
tl;dr - Don't worry aout getting immediate_failed when the page first loads. This is normal.
As a workaround I use gapi.auth.authorize method in the gapi.auth.signIn callback. Here is my code:
gapi.auth.signIn({
'callback': gPlusLoginCallback
});
function gPlusLoginCallback(authResult) {
if (authResult['status']['signed_in']) {
doSmth(authRes['access_token']);
} else if (authResult['error'] == "immediate_failed") {
gapi.auth.authorize({
client_id: gplusClientId,
scope: 'https://www.googleapis.com/auth/plus.login email',
immediate: true
}, function (authRes) {
if (authRes['status']['signed_in']) {
doSmth(authRes['access_token']);
}
});
}
}
function doSmth(accessToken){
//Do smth
}
Change this setting "immediate: true", to be false " immediate: false".
But if you like to make more complex implementation look at the first sample here https://developers.google.com/api-client-library/javascript/start/start-js. You have to calls to Google's "gapi.auth.authorize({...", the first one with "immediate: true", and the second one with "immediate: false".
The question is old but I faced this issue recently.
In my case, it was because I specified the URI parameter prompt to none. I guess Google doesn't like that if the user has never been logged to your platform before.
Whenever I changed that to consent or totally removed it, it worked great.
In my case, the error was because of explicitly specifying the authorization parameter prompt to 'none',similar to a previous answer.
It worked for me by specifying prompt=None or as per the official docs,you may skip this parameter.

Resources