Can't find elements inside iframe on Safari using Protractor - javascript

We have an html page with an iframe. As you can see in the code below, iframe is generated by javascript (this is simplified version, since we cannot show the production code). Our goal is to write end-to-end tests using Protractor. We would like to assure the presence of div element inside iframe (the test is also given below). The problem is that the test is passing on Chrome on mac OS Mojave, but falling on Safari 12.0.2.
If iframe is not generated by JS, the test is passed on Safari.
<html>
<head>
<script>
function domOnLoad() {
const rootElement = document.getElementById('root');
const iframeElement = document.createElement('iframe');
iframeElement.frameBorder = 0;
iframeElement.seamless = true;
iframeElement.scrolling = 'no';
rootElement.appendChild(iframeElement);
const divElement = document.createElement('div');
divElement.id = 'iframeRoot';
const textElement = document.createTextNode('Test Iframe');
divElement.appendChild(textElement);
iframeElement.contentDocument.body.appendChild(divElement);
console.log(rootElement);
}
</script>
</head>
<body onload="domOnLoad()">
<div id="root">
</div>
</body>
</html>
describe('Test should have', function() {
browser.waitForAngularEnabled(false);
it('div inside iframe with an id iframeRoot', () => {
browser.get('http://localhost:5000/examples/iframe.html/');
browser.switchTo().frame(0);
var divInsideIframe = $('#iframeRoot');
expect(divInsideIframe.isPresent()).toBeTruthy();
});
});

you have to switch to iframe first
browser.switchTo().frame('iframe');
then try to find element which is in iframe
I hope this will help you

Related

Unable to create a div inside iframe

I have an iframe and I want to add a div to it using JavaScript. But it's not showing up. What am I doing wrong?
<html>
<body>
<iframe
id="zzz"
srcdoc="<html><h1>hello</h1><button>click </button> <button>btn 2</button></html>"
width="500"
height="500">
</iframe>
<script>
let myiframe = document.getElementById("zzz").contentWindow.document;
let mydiv = myiframe.createElement("div");
mydiv.style.background = "red";
mydiv.style.width = "300px";
myiframe.body.appendChild(mydiv);
</script>
</body>
</html>
I'm running this on my local server using VSCode live server extension and I also ran it on w3schools tryit editor too:
See, no red div here!
Edit 1:
Okay, I checked the DOM too. Still nothing here...
Chrome likes a load event - also we can use document.getElementById("zzz").contentDocument;
https://jsfiddle.net/mplungjan/ju8t6xoq/
Stacksnippets will not allow accessing the iFrame
window.addEventListener("load", function() {
let myiframeDocument = document.getElementById("zzz").contentDocument;
let mydiv = myiframeDocument.createElement("div");
mydiv.style.background = "red";
mydiv.style.width = "300px";
mydiv.style.height = "300px";
mydiv.textContent = 'bla'
myiframeDocument.body.appendChild(mydiv);
});

Returned JavaScript value wont render inside a div element

This a basic question (Posting this again, as it was not re-opened after I updated the question). But I couldn't find any duplicates on SO.
This is a script I intend to use in my project on different pages. The purpose is to override the default ID shown in a span element to the order number from the URL parameter session_order. This doesn't affect anything and only enhances the UX for my project.
scripts.js (loaded in the header):
function get_url_parameter(url, parameter) {
var url = new URL(url);
return url.searchParams.get(parameter);
}
And in my HTML template, I call the function this way,
<div onload="this.innerHTML = get_url_parameter(window.location.href, 'session_order');">24</div>
Also tried this,
<div><script type="text/javascript">document.write(get_url_parameter(window.location.href, 'session_order'));</script></div>
When the page is rendered, nothing changes. No errors or warnings in the console either for the first case.
For the second case, console logged an error Uncaught ReferenceError: get_url_parameter is not defined, although script.js loads before the div element (without any errors).
Normally, I'd do this on the server-side with Flask, but I am trying out JavaScript (I am new to JavaScript) as it's merely a UX enhancement.
What am I missing?
Try this:
// This is commented because it can't be tested inside the stackoverflow editor
//const url = window.location.href;
const url = 'https://example.com?session_order=13';
function get_url_parameter(url, parameter) {
const u = new URL(url);
return u.searchParams.get(parameter);
}
window.onload = function() {
const el = document.getElementById('sessionOrder');
const val = get_url_parameter(url, 'session_order');
if (val) {
el.innerHTML = val;
}
}
<span id="sessionOrder">24</span>
Define the function you need for getting the URL param and then on the window load event, get the URL parameter and update the element.
Here you go. Try to stay away from inline scripts using document.write.
function get_url_parameter(url, parameter) {
var url = new URL(url);
return url.searchParams.get(parameter);
}
window.addEventListener('load', function() {
const url = 'https://yourpagesdomain.name/?session_order=hello'; //window.location.href;
const sessionOrder = get_url_parameter(url, 'session_order');
document.getElementById('sessionOrder').innerText = sessionOrder;
});
<div id="sessionOrder"></div>
The order of your markup and script matters...
<div></div>
<script>
function get_url_parameter(url, parameter) {
var url = new URL(url);
return url.searchParams.get(parameter);
}
</script>
<script>
document.querySelector('div').innerHTML = get_url_parameter('https://example.com?session_order=2', 'session_order');
</script>

How to access an iframe from chrome extension?

How can I get my extension to work on all frames like adblock does?
I tried adding "all_frames" : true to my manifest file but it didn't work.
I tried to use this code to get the text with specific ids:
var theId = "starts with something";
var myArray = [];
$('[id^="theId"]').each(function(i, obj) {
myArray.push($(this).text());
});
$.unique(myArray);
console.log(myArray);
but it says my array is empty. When I inspect element on the page, I see a "top" layer, and a "target content" layer. The code only works when I execute it in the console on the "target content" layer. Can I use this code in a content script, or do I need to use background.js somehow?
Continued from SO44122853
I see you figured out that the content was loaded in an iframe. So I have a working demo here PLUNKER, the snippet is here just in case the plunker goes down.
Details are commented in PLUNKER
Demo
Not functional due to the need to run 2 separate pages
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">
<style></style>
</head>
<body>
<!--iframe is same as the one on the site, with the exception
of the src-->
<iframe id="ptifrmtgtframe" name="TargetContent" title="Main Content" frameborder="0" scrolling="auto" width='90%' src="tables.html"></iframe>
<!--The data is displayed as a one string-->
<output id='display'></output>
<script>
// Reference the iframe
var iFID = document.getElementById("ptifrmtgtframe");
// Register the load event on iframe
iFID.onload = function(e) {
// Callback is extractText function
return extractText('#ptifrmtgtframe', '#display', '.PSLONGEDITBOX');
}
/* Pass iframe and display as a single selector
|| Pass targets as a multiple selector
*/
function extractText(iframe, display, targets) {
var iArray = [];
var iFrame = document.querySelector(iframe);
var iView = document.querySelector(display);
var iNode = "";
/* .contentWindow is property that refers to content
|| that is in an iframe. This is the heart of the
|| demo.
*/
var iContent = iFrame.contentDocument || iFrame.contentWindow.document;
var iTarget = iContent.querySelectorAll(targets);
/* .map() will call a function on each element
|| and return a new array as well.
*/
Array.from(iTarget).map(function(node, idx) {
iNode = node.textContent;
iView.textContent += iNode;
iArray.push(iNode);
return iArray;
});
console.log(iArray);
}
</script>
</body>
I think your script may be executing before the DOM loads, try putting your function inside:
document.addEventListener('DOMContentLoaded', function() {
});
EDIT
That event seems to do nothing in content scripts, I think that is because they are already loading after DOM is loaded, and never fires.
However this seems to fire but not sure why:
$(function(){
//something
});
This needs jQuery injected aswell

How to set HTML content into an iframe

I have a HTML string
<html>
<body>Hello world</body>
</html>
and I want to set it to an iframe with JavaScript. I am trying to set the HTML like this:
contentWindow.document.body.innerHTML
or
contentDocument.body.innerHTML
or
document.body.innerHTML
but IE gives "Access is denied." or "Object does not support this property or method." or "Invalid final element to the action." errors.
Here is my full code:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery_1.7.0.min.js"/>
<script type="text/javascript">
$(document).ready(function(){
var htmlString = "<html><body>Hello world</body></html>";
var myIFrame = document.getElementById('iframe1');
// open needed line commentary
//myIFrame.contentWindow.document.body.innerHTML = htmlString;
//myIFrame.contentDocument.body.innerHTML = htmlString;
//myIFrame.document.body.innerHTML = htmlString;
//myIFrame.contentWindow.document.documentElement.innerHTML = htmlString;
});
</script>
</head>
<body>
<p>This is iframe:
<br>
<iframe id="iframe1">
<p>Your browser does not support iframes.</p>
</iframe>
</body>
</html>
You could use:
document.getElementById('iframe1').contentWindow.document.write("<html><body>Hello world</body></html>");
Here's a jsFiddle, which works in all major browsers.
Note that instead of contentDocument.write you should use contentWindow.document.write: this makes it work in IE7 as well.
var htmlString="<body>Hello world</body>";
var myIFrame = document.getElementById('iframe1');
myIFrame.src="javascript:'"+htmlString+"'";
With html5 you'll be able to use the srcdoc attribute.
The innerHTML is a bit tricky especially in IE, where elements like thead are read-only and cause a lot of trouble.
Based on the documentation on msdn you might try documentMode which provides a innerHTML property.
myIFrame = myIFrame.contentWindow ||
myIFrame.contentDocument.document ||
myIFrame.contentDocument;
myIFrame.document.open();
myIFrame.document.write('Your HTML Code');
myIFrame.document.close();
this might only work in IE.
http://msdn.microsoft.com/en-us/library/ie/ms535862(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/ie/ms533897(v=vs.85).aspx
How about document.documentElement.innerHTML. But do know that everything in the page will be replaced even the script that does that.
For an iframe it would be like this myIFrame.contentWindow.document.documentElement.innerHTML
I have a problem with 'origin' with the answers here. This is how it's work for me:
const frame1 = document.createElement('iframe');
frame1.name = 'frame1';
//not have to set this style,just for demo
frame1.style.position = 'absolute';
frame1.style.height = '800px';
frame1.style.top = '100px';
frame1.style.left = '100px';
frame1.style.background = 'white';
document.body.appendChild(frame1);
const frameDoc =
frame1.contentWindow || frame1.contentDocument.document ||
frame1.contentDocument;
frameDoc.document.write('<html><head><title></title><body>Hello world</body></html>');
frameDoc.document.close();
In 2023, the correct answer to this problem is to use the srcdoc attribute of the <iframe> element. I can be done straight in your HTML file or with javascript:
document.getElementById('iframe').srcdoc = "<html><body>Hello world!</body></html>";
try it:
$('iframe').load(function() {
$(this).contents().find('body').append("Hello world");
});
update:
$(function(){
$('iframe').load(function() {
$(this).contents().find('body').append("Hello world");
});
})

Changing innerHTML of script tags in IE for loading google plusone button explicitly

To add Google's plusone button on your website the following script tag is to be inserted (for explicit load).
<script type="text/javascript" src="https://apis.google.com/js/plusone.js">
{"parsetags": "explicit"}
</script>
It looks pretty straight forward in HTML. However I wan't to insert the script using a JS file. So I use the following code:
var e = document.createElement('script');
e.src = "https://apis.google.com/js/plusone.js";
e.id = "googplusonescript";
e.innerHTML = '{"parsetags": "explicit"}';
document.getElementsByTagName("head")[0].appendChild(e);
It works pretty awesome in all the browsers except IE because IE doesn't allow us to write the innerHTML of script tags. Anywork arounds anyone ? (I have jquery inserted in the page. So can use jquery too.)
Came across the same issue.
Under IE you should use
script.text = '{"parsetags": "explicit"}';
instead of script.innerHTML
try creating a textNode and appending it to your script tags:
var myText = document.createTextNode('{"parsetags": "explicit"}');
myScriptTag.appendChild(myText);
Try the following:
window['___gcfg'] = { parsetags: 'explicit' };
var ispoloaded;
function showpo() {
var pohd = document.getElementsByTagName('head')[0];
var poscr = document.createElement('script');
poscr.type ='text/javascript';
poscr.async = true;
poscr.text ='{"parsetags": "explicit"}'; //works on IE too
poscr.src = "http://apis.google.com/js/plusone.js";
pohd.appendChild(poscr);
ispoloaded = setInterval(function () {
//check if plusone.js is loaded
if(typeof gapi == 'object') {
//break the checking interval if loaded
clearInterval(ispoloaded);
//render the button, if passed id does not exists it renders all plus one buttons on page
gapi.plusone.go("idthatexists");
}
}, 100); //checks every 0.1 second
}

Categories

Resources