I open a new tab in the browser with const w = window.open('www.example.com'); and I get the DOM with let d = w.document; Then I go to another webpage with an click-event: d.querySelector('a').click(); The new webpage opens, in the same window, and I want to grap the DOM of the just openend page by running d = w.document again. And this is the point where I get stuck.
I aspect the DOM of the currently openend window, but instead I get the DOM of the previous window back. When console.log(w) (in the .js itself not in the console), with the new webpage open, I get the window object of the current page and the window.document matches the DOM of the openend page. But as I said in reality I get the DOM of the previous page back when I run d = w.document on the new page.
The following code is the whole function I use. Sidenote: I didn't(/couldn't) use window.document.onload fom I reason I don't understand, but It seems I can't attach an function to the window onload event. Also to make things clear my code is inside of a ES6 Class so I didn't use the constas in the example.
The Problem:
When I run the getDOM method on the new openend webpage it returns the DOM of the previous page.
async foo() {
await this.getDOM()
.then(w => this.d = w.document);
const x = this.d.querySelector('button.x');
console.log(send); //null
}
getDOM () {
return new Promise(resolve => {
const interval = setInterval(() => {
if (this.w.document.readyState === 'complete') {
clearInterval(interval);
resolve(this.w);
}
}, 500);
});
}
I hope someone can help, thanks in advance!
Related
I need help on how to close a confirmation window which was triggered from an iframe. I am trying the code below, but this still can't close the confirm window.
cy.get('iframe[id="ParentMainContent_Frame"]').then(($iframe) => {
const $body = $iframe.contents().find('body')
const $win = $iframe[0].contentWindow
cy.stub($win,'confirm').as('windowConfirm')
cy.wrap($body)
.find('#ParentMainContent_MainContentMaster_ctl00_PlaceOrderButton').click().should(function () {
expect(this.windowConfirm).to.be.calledWith('Thank you for your Order!')
})
})
The button triggering this window is shown above:
Hoping someone could take a look and help.
Using cypress-iframe gives you more checks that the iframe loading has finished before you start testing it's contents.
The downside is this library's methods yield body but not the iframe window, though I think you can use body.ownerDocument.window to get it.
cy.enter('iframe[id="ParentMainContent_Frame"]').then(getBody => {
const body = getBody();
const win = body.ownerDocument.window;
cy.spy(win,'confirm').as('windowConfirm'); // spy not stub
body.find('#ParentMainContent_MainContentMaster_ctl00_PlaceOrderButton')
.click()
.should(function () {
expect(this.windowConfirm).to.be.calledWith('Thank you for your Order!')
})
})
})
I have been working on a Puppeteer system to help me handle my automation testing. However, my page would prompt a random pop-up to notify customers of on-going promotions - This prevents my test from proceeding. My initial thought was to run a endless loop in the background during the test to waitForSelector and click if it exists. However, I was thinking that this approach doesn't sound too smart, and I couldn't find anything suitable in the API.
Has anyone encountered the similar problem and has come out with a brilliant solution?
If the popup is always going to appear towards the beginning of the session, you can use page.waitForSelector():
await page.waitForSelector('#popup', {visible: true});
await page.click('#popup'); // Close Popup
Alternatively, if the element is dynamically added to the page and might not appear, you can use the MutationObserver interface to watch for the element to be added to the DOM tree and click it:
await page.evaluate(() => {
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
for (let i = 0; i < mutation.addedNodes.length; i++) {
if (mutation.addedNodes[i].id === 'popup' && window.getComputedStyle(mutation.addedNodes[i]).display !== 'none') {
mutation.addedNodes[i].click(); // Close Popup
}
}
});
});
observer.observe(document, {subtree: true});
});
When events are queued with setTimeout/setInterval, and the user is viewing a separate tab, Chrome and Firefox enforce a minimum 1000ms lag before the event is executed. This article details the behaviour.
This has been discussed on StackOverflow previously, but the questions and answers only applied to animations. Obviously, an animation can just be forced to update to the latest state when a user re-enters the tab.
But the solution does not work for sequenced audio. I have Web Audio API playing several audio files in sequence, and setTimeout is used to countdown to when the next audio file plays. If you put the tab in the background, you get an annoying 1 second gap between each pattern -- an extreme flaw in an API designed for advanced audio.
You can witness this behaviour in various HTML5 sequencers, e.g. with PatternSketch -- just by entering a pattern, playing, and going to another tab.
So I'm in need of a workaround: a way to queue events without the 1000ms clamp. Does anyone know of a way?
The only solution I can think of is to have window.postMessage run every single millisecond and check each time if the event is to execute. That is definitely detrimental to performance. Is this the only option?
Apparently there is no event system planned for Web Audio API, so that is out of question.
EDIT: Another answer is to use WebWorkers per https://stackoverflow.com/a/12522580/1481489 - this answer is a little specific, so here's something more generic:
interval.js
var intervalId = null;
onmessage = function(event) {
if ( event.data.start ) {
intervalId = setInterval(function(){
postMessage('interval.start');
},event.data.ms||0);
}
if ( event.data.stop && intervalId !== null ) {
clearInterval(intervalId);
}
};
and your main program:
var stuff = { // your custom class or object or whatever...
first: Date.now(),
last: Date.now(),
callback: function callback() {
var cur = Date.now();
document.title = ((cur-this.last)/1000).toString()+' | '+((cur-this.first)/1000).toString();
this.last = cur;
}
};
var doWork = new Worker('interval.js');
doWork.onmessage = function(event) {
if ( event.data === 'interval.start' ) {
stuff.callback(); // queue your custom methods in here or whatever
}
};
doWork.postMessage({start:true,ms:250}); // tell the worker to start up with 250ms intervals
// doWork.postMessage({stop:true}); // or tell it just to stop.
Totally ugly, but you could open up a child popup window. However, all this does is transfer some of the caveats to the child window, i.e. if child window is minimized the 1000ms problem appears, but if it is simply out of focus, there isn't an issue. Then again, if it is closed, then it stops, but all the user has to do is click the start button again.
So, I suppose this doesn't really solve your problem... but here's a rough draft:
var mainIntervalMs = 250;
var stuff = { // your custom class or object or whatever...
first: Date.now(),
last: Date.now(),
callback: function callback(){
var cur = Date.now();
document.title = ((cur-this.last)/1000).toString()+' | '+((cur-this.first)/1000).toString();
this.last = cur;
}
};
function openerCallbackHandler() {
stuff.callback(); // queue your custom methods in here or whatever
}
function openerTick(childIntervalMs) { // this isn't actually used in this window, but makes it easier to embed the code in the child window
setInterval(function() {
window.opener.openerCallbackHandler();
},childIntervalMs);
}
// build the popup that will handle the interval
function buildIntervalWindow() {
var controlWindow = window.open('about:blank','controlWindow','width=10,height=10');
var script = controlWindow.document.createElement('script');
script.type = 'text/javascript';
script.textContent = '('+openerTick+')('+mainIntervalMs+');';
controlWindow.document.body.appendChild(script);
}
// write the start button to circumvent popup blockers
document.write('<input type="button" onclick="buildIntervalWindow();return false;" value="Start" />');
I'd recommend working out a better way to organize, write, etc. but at the least it should point you in the right direction. It should also work in a lot of diff browsers (in theory, only tested in chrome). I'll leave you to the rest.
Oh, and don't forget to build in auto-closing of the child window if the parent drops.
I have a opened a rad window using below java-script code given below. Now I want to refresh my parent page on closing the rad window. To achieve this i have linked a jquery method, OnSendInviteClose with onclose event. Now this code refreshes my parent page but some time it gives me error described as "can't execute code from a freed script". How to fix this issue or reload my parent page on close (any other way).
Thanks
var e_showaddresslist = function (sender, args) {
var url = $page.url.create("Pages/CalendarInvites.aspx?parentScreen=sendInviteWnd");
var win = $window.createPopup(url,
{
size: "750, 500", behaviors: Telerik.Web.UI.WindowBehaviors.Close | Telerik.Web.UI.WindowBehaviors.Maximize | Telerik.Web.UI.WindowBehaviors.Move | Telerik.Web.UI.WindowBehaviors.Reload | Telerik.Web.UI.WindowBehaviors.Modal, name: "sendInviteWnd", onclose: onSendInviteClose
},
function () {
//$page.get_window().set_destroyOnClose(true);
});
}
function onSendInviteClose() {
window.location.reload(true);
}
Note: All the code is place in the calendar.js file which has references in both parent and radwindow page.
Have a read of this What causes the error "Can't execute code from a freed script"
The try / catch solution may help in your case.
You can hook the OnClientColose to the RadWindow and refresh the page using document.location.reload().
function RefreshParentPage()//function in parent page
{
document.location.reload();
}
Thanks,
Saritha
Make sure the code is executed in the correct context, i.e., in the main page and not in the CalendarInvites page.
Then, if this is ok, try adding a timeout like this:
function onSendInviteClose() {
setTimeout(function() {
window.location.reload(true);
}, 0); //you can also try increasing the timeout.
}
Usually, the cannot execute code from freed script means that the content page that is being disposed is still trying to run some code but it is orphaned (e.g., other pieces of code it depends on are disposed, or its context is gone - the window object). Most often this would be the page in the iframe (i.e., inside the RadWindow), but it may also be your main page.
Attached the 'onSendInviteClose' method on close event.
var win = $window.createPopup(url,
{
size: "750, 500", behaviors: Telerik.Web.UI.WindowBehaviors.Close |Telerik.Web.UI.WindowBehaviors.Move, onclose: onSendInviteClose
}
Now create that method in the page from which the popup is opened. This function will automatically fired when popup window is closed.
function onSendInviteClose() {
//get a reference to the current RadWindow
var wndow = GetRadWindow();
wndow .Close();
// and as this method is present in parent page
// we can refresh the page controls easily.
}
function GetRadWindow() {
var oWindow = null;
if (window.radWindow) oWindow = window.radWindow;
else if (window.frameElement.radWindow) oWindow = window.frameElement.radWindow;
return oWindow;
}
I have a web app that launches an URL in other windows/tabs. I would like to check if the window/tab exists. If not, I want to create it, else I would like to pick it in the first position.
I use:
wf=window.open(address, web_form_target, 'toolbar=1,scrollbars=1,location=1,statusbar=1,menubar=1,resizable=1,width=640,height=450');
if(wf!=null)
wf.focus();
But it goes well only the first time (in IE, not in Firefox). If I create a new tab in the window, when I call window.open() nothing happens. If I close the window it recreates it but keeps it ionized.
Is there a way I can follow to obtain a good result?
Thanks in advance.
Here's some code I've used for ages that still works as far as I know. Notice that oWindow has global scope, and that I pass it to the second parameter of open as a string, not as the object itself. Then, I test to see if it's closed before trying to open again...if it's already opened, then I just give it focus:
var oWindow;
function openWindow(p_strURL) {
if(!oWindow || oWindow.closed) {
oWindow = window.open(p_strURL, "oWindow", "status, scrollbars, resizable, width=800, height=500");
if(!oWindow.opener) {
oWindow.opener = window;
}
}
else {
oWindow.location.href = p_strURL;
oWindow.focus();
}
}
Hope it helps you find a solution,
Kevin
web_form_target is the window name.
if (wf.name !== web_form_target) {
// create it
}