Protractor: How to locate elements on the second nested iframe - iframe

Using Protractor for nonAngular page I am facing a problem with modal element location from an iframe, which is nested in another iframe. I'm trying to locate the element and I always get Element not found error.
Page source:
<iframe ...
...
<iframe frameborder="0" ...
<html
<head
<body
<div id="viewport" style= ...
<div id="modal" class=" unit ...
Page object:
this.layout = element(by.css('div[data-field="device"]'));
this.firstIframe = this.layout.element(by.tagName('iframe'));
this.content = element(by.tagName('body.desktop'));
this.secondIframe = element.all(by.tagName('iframe')).last();
this.modalUnit = element(by.id('modal'));
Spec:
...
// waiting for first iframe to be visible
browser.wait(EC.visibilityOf(page.firstIframe),10000).then(function() {
// switch to first iframe
browser.driver.switchTo().frame(page.firstIframe.getWebElement());
// verify content is displayed
expect(page.content.isDisplayed()).toBeTruthy();
// switch to default content
browser.switchTo().defaultContent();
});
// waiting for second iframe to be visible
browser.wait(EC.visibilityOf(page.secondIframe),10000).then(function() {
// switch to second iframe
browser.driver.switchTo().frame(page.secondIframe.getWebElement());
// waiting for modal to be visible
browser.wait(EC.visibilityOf(page.modalUnit),10000).then(function() {
...
Content element is found in the first iframe without a problem. But modalUnit element from the second iframe is not found, whereas second iframe is found. Any idea why?

Heureka!!! Found simple solution to my problem (https://groups.google.com/forum/#!topic/selenium-users/OkcX2vaZoek):
...
// waiting for first iframe to be visible
browser.wait(EC.visibilityOf(page.firstIframe),10000).then(function() {
// switch to first iframe
browser.driver.switchTo().frame(page.firstIframe.getWebElement());
// verify content is displayed
expect(page.content.isDisplayed()).toBeTruthy();
});
// waiting for second iframe to be visible
browser.wait(EC.visibilityOf(page.secondIframe),10000).then(function() {
// switch to second iframe
browser.driver.switchTo().frame(page.secondIframe.getWebElement());
// waiting for modal to be visible
browser.wait(EC.visibilityOf(page.modalUnit),10000).then(function() {
...
I had to remove browser.switchTo().defaultContent(); before I switch to second iframe and all troubles were gone.

Related

How to move focus from "skip to main content" to an iframe and access iframe content in JAWS?

Scenario:
In my application, content in Iframe is loading from server side and entire markup comes from the backend. There is navigation menu buttons in the main html page and Skip to main content link. Role for the iframe body is given as "application"(also tried with document). When Skip to main content is removed, the JAWS read the iframe content as expected, but as soon as "Skip to main content" section is enabled, JAWS reads just the first line inside iframe. What aria role or property I should add, such that when focus is moved from "skip to main content" to iframe, JAWS should start reading the entire content inside iframe?
Sample code used to move focus inside iframe:
window.skipNav = function(event) {
switch(event.type)
{
case "keydown":
if (event && event.keyCode == 13) {
setTimeout(setFocusIframe, 100);
}
break;
case "click":
setTimeout(setFocusIframe, 100);
break;
default:
break;
}
}
function setFocusIframe() {
this.iframe[0].contentWindow.document.body.focus()
// var f = jQuery("iframe:first")
// if(f.length > 0) {
// //f[0].contentWindow.document.body.focus();
// f[0].contentWindow.focus();
// console.log("skipNav-------------------------------------------------------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
// }
}
Try to check if document.activeElement returns the element you are trying to focus on.
Sometimes jQuery .focus() fucntion dont do what you expect.

Loading content into a container div from a button within using jquery

This is just a test of something I'm trying to accomplish here that is probably incredibly simple but is racking my brain. I've reviewed some of the closest matches already available here, but I wasn't able to make any of them work.
I'm trying to load content into a div using a button, like so:
<div class="load-container">
<button class="load-first">Load First</button>
</div>
<script type="text/javascript">
$(".load-first").click(function() { $(".load-container").load("/test-1.html"); });
$(".load-second").click(function() { $(".load-container").load("/test-2.html"); });
$(".load-third").click(function() { $(".load-container").load("/test-3.html"); });
</script>
And this actually works on the first try, but then, when "/test-1.html" loads, the next button doesn't work. This is what is in /test-1.html file:
This is the first one.<br>
<button class="load-second">Load Second</button>
Clicking the second button should load the next bit of content but it does nothing. Is the problem that the button is inside of the destination container div? I need a container div with buttons inside that can load new content in this way.
Because at the time the page is loaded, the "load-second" button was not there yet, thus the click() event was not registered to the button that is yet to come via the load() content, you need to attach your event after your buttons are created in the DOM, try the following:
<div class="load-container">
<button class="load-first">Load First</button>
</div>
<script type="text/javascript">
$(".load-first").click(function() {
$(".load-container").load("/test-1.html", function(){
// now load-second button is available, register the click handler
$(".load-second").click(function() {
$(".load-container").load("/test-2.html", function(){
// now load-third button is available, register the click handler
$(".load-third").click(function() { $(".load-container").load("/test-3.html"); });
});
});
});
});
</script>

refresh iframe parent page using getElementById

Is is possible to refresh only once iframe parent page when iframe contain specified div id ?
I tried this on parent page but didn't work :
if document.frames('myiframe').(document.getElementById("iframedivID") !== null) { window.location.href = "mysite.com"; }
It is taking time to load the inner document. So we have to wait till inner document gets loaded and once it is loaded, the inner div can be accessed. Here is my example HTML and javascript code. Due to this, for the first time, you may get null in the alert. Hope this helps.
Test.html
<iframe id="iframedivID" src="Test1.html"></iframe>
Test1.html
<div id='myDiv'>My name is ravindra</div>
<script type="text/javascript">
if (window.parent.window.location.href.toString().indexOf("?refresh") == -1){
window.parent.window.location.href="Test.html?refresh";
}
</script>

return focus from iframe to parent

I have some keyboard shortcuts binded to the document object using the keydown event (I am using the jquery.hotkeys plugin to do this, but I doubt this matters).
I then have an iframe which I insert dynamically into the DOM and after some actions remove it. My problem is that after removing the iframe, I need to click back on the parent document in order to be able to use the keyboard shortcuts, otherwise the keydown events are not detected.
I have tried using .focus(), .click(), .mousedown() etc on the document element as well as on other elements on the parent page, but I could not get the focus back to the parent page.
How can I get the focus back to the page without requiring the user to click on the page?
Thanks!!
if you have an iframe that is contained in the document you can store the "main" document as a variable prior to creating the iframe.
Then when you remove the iframe just call top.doc.focus() or top.doc.getElement('id').focus().
I just spent a while struggling with a similar issue, and what I've concluded is that the script running in the child frame keeps stealing focus back to that frame. Then when the script terminates, the child frame has already been removed, so the browser doesn't know where to focus anymore.
How I solved this was to create a function in the parent (or top) frame, that first removes the child frame, and then restores focus to itself. Now, from the child frame, I simply call the parent's function, and that fixes it.
Example:
outer.html:
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /></head><body>
Outer content - press [Enter] to load the iframe
<div id="iframeHolder"></div>
<script src="//ajax.googleapis.com/ajax/libs/prototype/1.7.2.0/prototype.js"></script>
<script>
// Create a function for the child frame to call
function regainFocus(){
$('iframeHolder').update('');
window.focus();
}
// When the outer document loads, start handling keystrokes
Event.observe(window, 'load', function(){ Event.observe(window, 'keyup', function(e){
// Catch only the Enter key
if((e.which||window.event.keyCode) != Event.KEY_RETURN) return;
// Construct the iframe, set its src, add it to holder, and focus on it
var frame = $(document.createElement('iframe'));
frame.setAttribute('src', 'inner.html');
frame.observe('load', function(){ this.contentWindow.focus(); });
$('iframeHolder').appendChild(frame);
});});
</script>
</body></html>
inner.html:
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /></head><body>
Inner content - press [Esc] to close the iframe
<script src="//ajax.googleapis.com/ajax/libs/prototype/1.7.2.0/prototype.js"></script>
<script>
// When the inner document loads, start handling keystrokes
Event.observe(window, 'load', function(){ Event.observe(window, 'keyup', function(e){
// Catch only the Esc key
if((e.which||window.event.keyCode) != Event.KEY_ESC) return;
// Call the parent's function
parent.regainFocus();
});});
</script>
</body></html>

How to trigger onload event when downloading a file in an iframe?

Suppose we have the following HTML file:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test iframe download</title>
<script type="text/javascript">
var init = 0;
function download() {
document.getElementById("dload_frame").src = "http://example.com/dload.py";
}
function alert() {
if (init == 0) {
init = 1;
}
else {
document.getElementById("alert_span").innerHTML = "Got it!";
}
}
</script>
</head>
<body>
<span id="alert_span">Main content.</span><br/>
<input type="button" value="Download" id="btn" onclick="download()" />
<iframe id="dload_frame" src="http://404.com/404" onload="alert()"> </iframe>
</body>
</html>
Now, if the URL to which iframe's src is being rewritten to (in this case - "http://example.com/dload.py") returns HTML, no problem: the onload event fires, the span's contents are replaced, everybody's happy.
However, if the content type of the file returned by the URL is set to something that forces the browser to open the save file dialog, the iframe's onload event never fires.
Is there any workaround? Using iframes isn't necessary, the desired behavior is to launch a callback after the browser begins downloading the supplied file.
I have encountered the same problem as this:
Here is my work-around, please see if it works for you:
<script>
function download(){
var url = 'http://example.com/dload.py';
var htm = '<iframe src="' + url +'" onload="downloadComplete()"></iframe>';
document.getElementById('frameDiv').innerHTML = htm;
}
</script>
<div style="display:none" id="frameDiv">
</div>
<button onclick="download()">download file</button>
As far as I can remembered iframe's onload event fires only once.
Setting another value for src attribute will not cause the onload event to fire again.
I have the same problem, onLoad handler is only fire when the content change. If you download a file. If you delete HTTP header to print file content on iframe, the onload is correctly fire.
My solution after many different approaches to get this working across ff ie safari and chrome was not have a 2 step download.
the original JS request to create an iframe loads a src that would normally have loaded the pdf
However, the src now loads a page with yet another iframe inside of it, which now contains the url of the pdf.
in the html response I trigger the onload and also a catchall setTimeout funciton which calls my response on window.parent.window.handlerfunction which my onload on the top iframe would have been. The result is a PDF download and a trigger on the top level parent of the handler function that works across the browsers since it no longer relies on detecting an actual iframe load but rather relies on supported parent/child window relationships.
hope this helps someone who was also stuck
You can check iframe readyState property repeatedly after short time intervals until it gets completed.
function iframe_onload(iframe_id, js) {
var iframe = document.getElementById(iframe_id);
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
if (iframeDoc.readyState == 'complete') {
eval(js)
return;
}
window.setTimeout('iframe_onload("' + iframe_id + '",`' + js + '`);', 100);
}
You might need help of jquery for this, for instance you can do this:
$.get('http://example.com/dload.py',{},function(result){
$('alert_span').html(result);//or some content
});

Resources