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.
Related
I'm trying to create a simple app where a picture gets uploaded, and that picture is drawn on html canvas so that i can do some simple pixel manipulation.
Right now I have the GET method for root render an EJS template with a fileReader and a canvas.
With code attached at the bottom of the EJS file through script tags, I draw the uploaded image onto the canvas so I can read each pixel's rgb values.
I then tried to send those rgb values to the POST route in the app (through fetch), but it's not working as expected.
app.post("/", (req, res)=>{
console.log("inside post");
console.log(req.body);
res.render("test", {result: req.body});
console.log("after res.render");
});
All three of the console logs print correctly in the terminal, including the request body, but the test template is not being rendered. It just stays on the same "index" view the app launches with.
Can someone give me some insight as to why this is happening? I also included console logs inside the script tags in the ejs template, and these are only displayed in the browser, not in the terminal I launch the express app with. How can I render the view inside the post method?
First
If you use AJAX like Fetch API or XHR, browser will not render the test page.
Because it's asynchronous, and you could see Ajax in MDN web docs.
You need to use form post with following code.
<form action="/" method="post">
<button type="submit">go to another page</button>
</form>
But, if you use form post, your page which might be "index.ejs" will be replaced with "test.ejs".
In other words,
Browser uses the response from the forms POST request to load the new page.
But browser pass AJAX request's response to a callback and trigger callback in js.
Browser handle these two type request (Form Post and AJAX POST) with different ways.
In common, both are sending data to server.
So, in your case, res.render is triggered successfully.
Let me show you an example. Here is my server code.
const express = require('express')
const app = express()
app.set("view engine", "ejs")
app.get("/", (req, res, next) => {
res.render("test")
})
app.post("/test", (req, res, next) => {
res.render("other-test")
})
app.listen(3000)
<!-- test.ejs -->
<h1>this is test pages.</h1>
<!-- other-test.ejs -->
<h1>this is other test pages.</h1>
When I type url http://localhost:300, browser show me this.
And I open console in chrome and type following code.
fetch("/test", {
method: 'POST', // or 'PUT'
body: JSON.stringify({}), // data can be `string` or {object}!
}).then(res => {console.log("trigger response")})
Then go the network tab in chrome, you will see the request.
Here, this request trigger the express method.
But, what is the response?
Well, it's a html. That means res.render("other-test") is triggered correctly.
And you will find the console output show "trigger response" which callback is triggered in my fetch.
And, page still stay in "test.ejs".
Next, I add following code in my test.ejs
<form action="/test" method="post">
<button type="submit">Go to other page</button>
</form>
Page will be like this.
After you click, you will find out the browser show you "other-test" content.
That's a difference between form post and ajax post.
Second
You put script tag into ejs template.
Express will use ejs engine to render your ejs template become to html page.
After it become to html page, it means all script is running in browser not your nodejs terminal.
I'm trying to write a casperJS program that can navigate and download PDFs. If I can grab an actual URL corresponding to the PDF it's pretty straight-forward, but that isn't always the case. To test this, I've been working with this simple example locally:
<html>
<head>
</head>
<body>
<h1 class="page-title">Hello</h1>
<a id='1' href="test.pdf" target="_blank">one</a>
</body>
</html>
Basic casper:
casper.start('file:///opt/templates/templates/src/main/resources/casperjs/example.html').then(function() {
this.echo('started')
});
casper.then(function() {
this.waitForSelector('a', function() {
this.click('a');
});
});
casper.wait(1000, function() {
this.echo(JSON.stringify(this.popups[0]));
});
casper.run();
When I run this, the (only) popup that's present is a blank HTML page that never loads. It's also worth noting that if you test this without the 'target="_blank"' (i.e. the PDF opens in the same tab), the 'resource.received' event will be emitted (with null content type), but loading the resource will fail:
[warning] [phantom] Loading resource failed with status=fail: file:///opt/templates/templates/src/main/resources/casperjs/test.pdf
Is there any good way to handle links that will open/download PDFs in some generic way? You can hook into 'navigation.requested' perhaps and download there, but I don't think there's a wonderful way to figure out that the nav is for a PDF (the URL may not always have file extension).
I am using PhantomJS to do some rewriting of HTML. I'm adding a background-image property to an element. But when I write out the resulting DOM, the URL has been rewritten to a local URL. I've boiled this down to the following test case:
JS
var page = require('webpage').create();
page.open("test.html",function(){
setTimeout(function(){
page.evaluate(function(){
document.getElementById("test").style.backgroundImage="url(test.png)";
});
console.log(page.content);
phantom.exit();
},1000);
});
HTML
<html>
<body>
<div id="test"></div>
</body>
</html>
Output
$ phantomjs test.js
<html><head></head><body>
<div id="test" style="background-image: url(file:///C:/cygwin/tmp/test.png); ">
</div>
</body></html>
UPDATE
The problem remains if you specify ./test.png or //test.png. However, http://example.com/test.png is left unchanged, as might be expected.
If this HTML document is opened in Chrome, and the background-image property added to the div element in the style inspector, the URL is unmodified, whether the document is inspected in the Elements tab in devtools, or via document.body.innerHTML displayed in the console, or copying the HTML.
UPDATE 2
I just found out that if the document is located in Chrome, and the command elt.style.backgroundImage="url(test.png"); is issued in the console, then the URL is rewritten. So at the end of the day it appears that this is not a PhantomJS issue, although I still don't understand this behavior.
Obviously, I don't want this URL to be rewritten in this fashion, and I don't understand why PhantomJS feels the need to do this. Ideas?
Hi I am looking for tutorial based on Dojo 1.8.
What I am looking for is:- create and instantiate widget pragmatically after dojo page fully loaded and parsed, triggered after dojo/on button. I am not sure of which tutorial in Dojo website, for me to learn.
Please advise.
Thanks in advance.
Clement
There isn't one tutorial that fully answer all your question but the following will be helpful:
Dojo Events tutorial and dojo/on reference
dojo/ready reference
dojo/parser reference
To capture both the full loading of the page and parsing you need to use a combination of dojo/ready and dojo/parser. (I'm assuming that the parsing you refer to is the dojo widget parser, rather than the standard browser parsing of HTML).
To run code after parsing you'll need to add parseOnLoad: false to your dojoConfig and run the parser manually; otherwise, there is no way of capturing when it is complete.
<script type="text/javascript" async="true">
require([
"dojo/ready",
"dojo/parser",
"dojo/on,
"dojo/query"
], function(
ready, parser, on, $
){
ready(function(){
// Only run after the page is fully loaded
parser.parse().then(function(instances){
// Only run after parser has parsed the page
var myButton = $("#myButtonid"); // Find your button
if(myButton.length > 0){ // Check button is found
on(myButton[0], "click", function(evt){
// ... add your code here to create and
// instantiate widget
});
}
});
});
}
</script>
Don't forget that you need to turn off automatic parsing of widgets in you dojoConfig, hence, something like this (in the head):
<script type="text/javascript">
dojoConfig= {
"parseOnLoad": false,
"async": true
// ...other settings
};
</script>
Is there a script to make the browser refresh when a page is re-sized? More specifically, one that emulates the browser refresh button or F5? I've found two, but they don't quite do what I'm looking for;
<script type="text/javascript">
var currheight = document.documentElement.clientHeight;
window.onresize = function(){
if(currheight != document.documentElement.clientHeight) {
location.replace(location.href);
}
}
</script>
and
<body onResize="window.location=window.location;">
The problem with these two is they appear to completely reset the page where as using the browsers refresh function leaves some user made changes intact (like being at a specific hash for instance) which is what I need.
So is there a way to refresh the window on re-size with a script similar to if the browser refresh was clicked? I don't understand why there is even a difference but there is.
Thanks.
Yes, you probably want to take a look at some JavaScript events. There is an OnResize event.
Here's a link to get you started with events:
http://www.devarticles.com/c/a/JavaScript/OnReset-OnResize-and-Other-JavaScript-Events/
As far as reloading the page, you can do that too:
http://www.mediacollege.com/internet/javascript/page/reload.html
As far as keeping the user values, you could persist them in a session.
Here is the perfect solution :
I have included timeout of 1 sec i.e. browser will refresh after 1 sec of window resize
$(window).resize(function() {
setTimeout( function(){
window.location.href = window.location.href;
},1000);
});
Without timeout
$(window).resize(function() {
window.location.href = window.location.href;
});
NOTE : You may also use window.location.reload() instead of window.location.href = window.location.href
window.location.reload() reloads the current page with POST data, whilewindow.location.href=window.location.href does not include the POST data
-- hope it helps
Try this:
<![if !IE]> <body onresize="document.location=window.location;"> <![endif]>
<!--[if IE]> <body onresize="window.location.reload();"> <![endif]-->