How can I switch to an IFrame with Codeception using ID? Actually I can use the name of the IFrame but not the ID -> Codeception SwitchToIFrame
IFrame Example:
<iframe id="iframeToolbar" src="link" frameborder="0" style="position: fixed; left: 0px; top: 0px; z-index: 998; width: 940px;" scrolling="no" width="100px" height="100%"></iframe>
Codeception Example:
<?php
# switch to iframe
$I->switchToIFrame("another_frame");
# switch to parent page
$I->switchToIFrame();
Is it maybe a Codeception <-> Facebook Webdriver Connection Problem?
EDIT: I reinstalled Codeception, followed the Quick Step Guide. Result - the Problem is still the same: Codeception and the Facebook Webdriver doesn't want to work together. My Codeception Code
acceptance.suite.yml:
actor: AcceptanceTester
modules:
enabled:
- \Helper\Acceptance
- WebDriver:
url: https://xxxxxxxxxxxxxx.com
browser: chrome
window_size: maximize
clear_cookies: true
codeception.yml:
paths:
tests: tests
output: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
actor_suffix: Tester
extensions:
enabled:
- Codeception\Extension\RunFailed
settings:
colors: true
OS: Windows 10
PHP: 7.1.7
PHPUnit: 6.4.4
Selenium Server: 3.8.1
Codeception: 2.3.7
Chrome: 63.0.3239.108
I had this issue, testing a page with a Google reCaptcha in it ... the reCaptcha is in its own iframe, and since that iframe is generated by 3rd-party code, we have no control over its name attribute (at least when it's first generated).
What I ended up doing was running a javascript snippet which can find the iframe based on other things, and then giving it an id, so that Codeception Webdriver could switch to it:
public function _clickOnCaptcha(AcceptanceTester $I)
{
// give the recaptcha iframe a name so codeception webdriver can switch to it
$recaptcha_frame_name = 'recaptcha-frame';
$I->executeJS("$('.g-recaptcha iframe').attr('name', '$recaptcha_frame_name')");
$I->switchToIFrame($recaptcha_frame_name);
$I->see('not a robot');
$I->seeElement('.rc-anchor');
$I->click(['id' => 'recaptcha-anchor']);
$I->switchToIFrame(); // switch back to main window
}
I did have control over the containing elements, so in this case, it's contained within an element with class g-recaptcha ... so we use jquery to find the iframe inside that element: $('.g-recaptcha iframe'), and then give it a name attribute: .attr('name', '$recaptcha_frame_name').
Then we can use Codeception to switch to it and click the captcha checkbox:
$I->switchToIFrame($recaptcha_frame_name);
$I->click(['id' => 'recaptcha-anchor']);
Then, when we're done, switch back out to the main frame so we can submit our form:
$I->switchToIFrame(); // switch back to main window
NB, I'm using the reCaptcha test keys, as specified here, in the testing environment so that it will never actually ask to solve a captcha.
https://developers.google.com/recaptcha/docs/faq
With the following test keys, you will always get No CAPTCHA and all verification requests will pass.
Site key: 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
Secret key: 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe
The reCAPTCHA widget will show a warning message to claim that it's only for testing purposes. Please do not use these keys for your production traffic.
First of all, in your case the problem might be that you're not calling the acceptance tester. You should start your script with this:
<?php
$I = /*am a */ new AcceptanceTester($scenario);
Now to get into an IFrame in Codeception using the WebDriver:
You just have to name the IFrame in a string, using EITHER the ID or the name. Here is an example:
There is a page with the IFrame:
<iframe name = "IFrameByName" id = "IFrameByID" width = "500" height = "300" src = "https://messagetothefish.com"></iframe>
This IFrame contains the string, "No one knows who discovered water" but the parent frame does not. I tested this Cept with PhantomJS and Selenium.
<?php
$I = /*am a */ new AcceptanceTester($scenario);
$I->wantTo('See how Iframes work');
$I->amOnUrl("https://wordpress-bdd.com/codeception-iframe/");
$I->dontSee("No one knows who discovered water");
//Switch by name
$I->switchToIFrame("IFrameByName");
$I->see("No one knows who discovered water");
//switch back to parent
$I->switchToIFrame();
$I->dontSee("No one knows who discovered water");
//Switch by ID
$I->switchToIFrame("IFrameByID");
$I->see("No one knows who discovered water");
$I->dontSee('Lorum Ipsum');
//switch back to parent
$I->switchToIFrame();
$I->dontSee("No one knows who discovered water");
Related
Original question:
using
browser.switchToFrame(iframeEl);
I can switch to a particular iframe window, and that's alright - clicking elements and etc works.
But, for whatever reason, using Selector when the iframe is the current context, does not work. I suspect that it's because switchToFrame is a method on the browser instance, and I'm using Selector function imported in such manner:
import { Selector } from 'testcafe';
My question is - if I want to select a particular element within the iframe using testcafe (to read its HTML attributes for example) - how should I approach it? Am I missing something?
More details from GitHub thread:
More details: I'm creating an iframe with remote src, and to that iframe, I later inject some HTML, CSS, and JavaScript. I'm 100% sure that the iframe will have the DOM element that'd match my requested selector - but still, I get an error: Cannot obtain information about the node because the specified selector does not match any node in the DOM tree.
My code looks roughly like this:
const iframeEl = await Selector('a-iframe_inner[name="something"]');
if (await iframeEl.count === 0) {
await this.fBrowser.switchToMainWindow();
} else {
await this.fBrowser.switchToIframe(iframeEl);
}
const something = await Selector('.something');
And on a line with await Selector the code breaks. In my other tests, where I'm also accessing the iframe and click some element using await browser.click(someOtherThing); it works flawlessly.
I can also read the console state of the iframe without hassle.
I suspect that the content of the iframe element might not be ready yet, but I'm wondering how can I wait until it's ready? I've tried setting a timeout option to the Selector call, but it didn't change anything. Can you share any tips on how to delay getting a selector after switching to iframe context?
Solution:
Turned out that it was indeed a bug on my part. Sorry. For future gens: Iframe switching and using selectors should work all fine, at least in TestCafe v0.20.1. Just make sure that your selectors match and you are really in iframe context, not just think that you are there
There is no need to do anything special to make Selectors work in iframes. It should work as expected. If they do not wish to create a bug report in the official repository using this form, I would appreciate it if you provide an example that demonstrates the issue.
As for your question, I was not able to reproduce this problem in a simple example.
Test page:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Click me</h1>
<iframe id="frame" src="http://example.com" style="width: 500px; height: 500px;"></iframe>
</body>
</html>
Test code:
import { Selector } from 'testcafe';
fixture `Selector in iframe`
.page `../pages/index.html`;
const selector = Selector('h1');
test('test', async t => {
await t.click(selector);
console.log(await selector.innerText);
await t.switchToIframe('#frame');
await t.click(selector);
console.log(await selector.innerText);
});
All clicks work as expected and I was able to get innerText of the Selector successfully.
In addition, I would recommend you check what element really exists on a page, that Selector refers to the existing element and that the element has width and height greater than zero.
I'm trying to make a test for a login webpage where there is the possibility of using Thirdparties social login. When you click on facebook icon, for example, a new popup appears asking for user/password. I'm using waitForPopup and withPopup as specified by the documentation to handle that, but is not working. Is never finding the element (via xpath) inside the xpath, so I can never log in using facebook in our test.
This is an example code that check if the facebook button is there, click on it and wait for the popup:
casper.then(function() {
test.comment("When we click facebook button");
casper.waitForSelector(x(facebookButton), function() {
test.assertExists(x(facebookButton), "Facebook icon is showing");
casper.click(x(facebookButton));
}, function timeout() { // step to execute if check has failed
casper.test.fail("Timeout loading login page");
});
});
casper.then(function() {
casper.waitForPopup(/facebook\.com\/login/, function() {
test.comment("And we fill facebook login info");
casper.withPopup(/facebook\.com\/login/, function() {
this.viewport(1600, 900);
casper.sendKeys(x(facebookEmail), facebookLogin[0]);
casper.sendKeys(x(facebookPassword), facebookLogin[1]);
casper.click(x(facebookLogin));
});
}, function timeout() { // step to execute if check has failed
casper.test.fail("Timeout loading faceebook login");
});
});
The output of the test is:
# When we click facebook button
PASS Facebook icon is showing
# And we fill facebook login info
FAIL Cannot get informations from xpath selector: //input[#id='email']: element not found.
# type: uncaughtError
# file: casper/import-login-testing.js:1058
# error: Cannot get informations from xpath selector: //input[#id='email']: element not found.
# CasperError: Cannot get informations from xpath selector: //input[#id='email']: element not found.
# at getElementInfo (/Users/ginogalotti/testing-presentation/node_modules/casperjs/modules/casper.js:1058)
# at /Users/ginogalotti/testing-presentation/node_modules/casperjs/modules/casper.js:1589
# at casper/import-login-testing.js:84
# at runStep (/Users/ginogalotti/testing-presentation/node_modules/casperjs/modules/casper.js:1553)
# at checkStep (/Users/ginogalotti/testing-presentation/node_modules/casperjs/modules/casper.js:399)
# stack: not provided
For me, that means that is finding the popup, the waitForPopup is triggering and is just not using the popup to look for the facebookEmail element. I'm still learning about casperjs, so probably this is not even the best way to approach the problem; but I would really thank some guidance.
Thanks in advance,
Example website that I'm testing: https://import.io/login
I am using a hybrid app and writing tests using Appium + Selenium Webdriver in Ruby.
I start my test with some textbox editing + click a button to open the UIWebview (so far everything works). The problem is when the UIWebview is opened - I cannot access it (it is immediately closed when I'm trying to click a html element (I am using Appium inspector to find elements and to record my Ruby test). I understand that I have to switch to the UIWebview (as I found here), but I cannot make it to work.
Code example:
require 'rubygems'
require 'selenium-webdriver'
capabilities = {
'browserName' => 'iOS',
'platform' => 'Mac',
'version' => '7.1',
'device' => 'iPhone Retina (4-inch)',
'app' => '/Users/{my user here}/Library/Developer/Xcode/DerivedData/{path here}/Build/Products/Debug-iphonesimulator/SDK.app'
}
server_url = "http://127.0.0.1:4723/wd/hub"
#wd = Selenium::WebDriver.for(:remote, :desired_capabilities => capabilities, :url => server_url)
# ...
# Do all kind of native actions here
# ...
#wd.find_element(:name, "showWebviewButton").click
#wd.manage.timeouts.implicit_wait = 30 # seconds
# ???
# How do I switch to my UIWebview here???
# (cannot access html elements here with #wd.find_element(:name, "htmlElement"))
# ???
#wd.quit
EDIT:
Using Appium inspector I found that my UIWebview is "window(1) ", so I tried:
#wd.switch_to.window(1)
This gives me the error:
A request to switch to a different window could not be satisfied because the window could not be found
(The error is thrown before the UIWebview is loaded)
It seems , you are switching to WebView before it loads. Please pause the script for some time and then switch to the WebView after it appears.
I have tried the following in java and worked fine for me, you may need to find the ruby version of the same.
driver.switchTo().window("WEBVIEW");
try this
#wd.switch_to.window("WEBVIEW") // i am not sure about the syntax
You need to access the element as shown below
findElement(By.xpath("//input[#name='firstName']"))
The only solution that finally worked for me (using Appium 1.2) is (taken from here, written in node.js)
// javascript
// assuming we have an initialized `driver` object for an app
driver
.contexts().then(function (contexts) { // get list of available views. Returns array: ["NATIVE_APP","WEBVIEW_1"]
return driver.context(contexts[1]); // choose the webview context
})
// do some web testing
.elementsByCss('.green_button').click()
.context('NATIVE_APP') // leave webview context
// do more native stuff here if we want
.quit() // stop webdrivage
In the above link you could find the solution written in other languages.
i use casperjs for automatical click on twitter share button. Twitter use iframe for create this buttons:
<iframe src="some src">
</iframe>
When i click it open popup window, but when i trying to login into twitter, i got error, form not found
casper.withFrame(0) { //it twitter iframe
this.fill("#twitter-widget-0 form#update-form", {
"session[username_or_email]": "myemail#email.com",
"session[password]": "password"
}, true);
});
Why? It possible with casperjs?
I'm not familiar with Twitter widgets, but are you sure #twitter-widget-0 is not the id of the iframe you just switched in to? It seems that way, because I found code like this: https://dev.twitter.com/discussions/11450
If you switched into the iframe, you cannot access elements from the parent page anymore, and you are trying to access the iframe element, which resides in the parent.
You should just select form#update-form, because it's not a child element of #twitter-widget-0: it is just an element that is contained in the iframe.
If so, the solution is simply omitting #twitter-widget-0 from your selector inside the iframe.
casper.withFrame(0) { //it twitter iframe
this.fill("form#update-form", {
"session[username_or_email]": "myemail#email.com",
"session[password]": "password"
}, true);
});
I'm using the Selenium2 module for acceptance tests
My acceptance.suite.yml contains
class_name: WebGuy
modules:
enabled: [Selenium2]
config:
Selenium2:
url: 'http://localhost/'
browser: firefox
capabilities:
unexpectedAlertBehaviour: 'accept'
In my test file I've tried both of the following and they both fail
$I->seeElement('.menu .subMenu');
$I->dontSeeElement('.menu .subMenu');
I would expect the dontSee assertion to pass as the sub menu is hidden by default
The error I get is
Guy unexpectedly managed to see element ".menu .subMenu": Failed asserting that an object is empty.
The beginning of my HTML looks like this
<div class="menu">
<div class="subMenu" style="display: none;">
<ul>
<li>Contact</li>
</ul>
</div>
</div>
Try using XPaths:
$I->seeElement("//div[#class='menu']");
I believe this is a bug in Codeception: https://github.com/Codeception/Codeception/issues/617
Edit: Switching to the WebDriver module instead of Selenium seems to have fixed the problem for me.
Is disabled your HTML-code div.menu by display:none;? Perhaps that's the reason.
I think, I have had a similiar problem with the webdriver and the code
$checkHygienePlans = $I->grabMultiple('.js-my-test-block a');
The result $checkHygienePlans was an array with empty string and $I->assertContains('TestSomeThing', $checkHygienePlans); would fail the test.
The reason was, that the wraping block of the element with class js-my-test-block was hidden with CSS display: none;
After I used codeception to untoggle that block, everything worked fine.