I am trying to open a new window with a URL for oAuth, however I cannot add any event listener.
const wind = window.open(msg.data.url);
console.log(wind);
wind.onload = function () {
wind.onpopstate = function (e) {
console.log('pop', e);
};
};
It just does nothing. However it turned out that window.open() has given me a not full window object. And that is all what I have got. How do I add event listener for that?
According to the MDN web docs regarding the window.open() function:
The returned Window reference can be used to access properties and
methods of the new window as long as it complies with Same-origin
policy security requirements.
That means if you call window.open("/questions") in a terminal on this webpage, you get a full window object, but if you call window.open("https://google.com"), it returns only a simplified object on which you will not be able to add event listeners. This is to prevent cross-origin attacks. You may, however, transfer data to the new window object via Window.postMessage(), if the new window is listening for that type of event. See here for more information on that.
Related
Suppose, i have two chrome instance opened, instance1 and instance2, and my application is running in instance1, and when user do any click event on instance1, Can i open new url in instance 2 using javascript?
If the second instance is not opened from your application, then it have no authority to access that instance.
I would suggest using window.open from your application, then you can pass an additional parameter as per your requirements. This way you will have control over the other instance you have created.
Reference: https://www.w3schools.com/jsref/met_win_open.asp
Updated
Regarding your comment:
You can add multiple event listeners for you instance window to detect changes on them like (load, close, resize etc).
componentDidMount() {
let strWindowFeatures = 'location=yes'
let URL = 'http://localhost:3001'
let win3Instace = window.open(URL, '_blank', strWindowFeatures)
win3Instace.addEventListener('load', (event) => {
console.log('Instance 3 is loaded, add callback funtion here')
})
}
The question is as simple as that. In Cypress, how can I access a new window that opens up when running the test.
Steps to recreate :
Run the test. After some action, new window pops up (the url is dynamic in nature).
Fill in the fields in the new window, and click a few buttons.
After required actions are completed in the new Window, close the new window and move back to the main window.
Continue execution with the main window.
Point of interest: the focus should be
main window -> new window -> main window
I have read few things that relate to use of iframe and confirmation box, but here its none of those. Relates to accessing a whole new window. Something like Window Handlers in Selenium. Unfortunately could not find anything related to it.
Accessing new windows via Cypress is intentionally not supported.
However, there are many ways this functionality can be tested in Cypress now. You can split up your tests into separate pieces and still have confidence that your application is covered.
Write a test to check that when performing the action in your app, the window.open event is called by using cy.spy() to listen for a window.open event.
cy.visit('http://localhost:3000', {
onBeforeLoad(win) {
cy.stub(win, 'open')
}
})
// Do the action in your app like cy.get('.open-window-btn').click()
cy.window().its('open').should('be.called')
In a new test, use cy.visit() to go to the url that would have opened in the new window, fill in the fields and click the buttons like you would in a Cypress test.
cy.visit('http://localhost:3000/new-window')
// Do the actions you want to test in the new window
Fully working test example can be found here.
I am not cypress expert, just started using it few days ago, but I figured out this kind solution for stateful application with dynamic link:
// Get window object
cy.window().then((win) => {
// Replace window.open(url, target)-function with our own arrow function
cy.stub(win, 'open', url =>
{
// change window location to be same as the popup url
win.location.href = Cypress.config().baseUrl + url;
}).as("popup") // alias it with popup, so we can wait refer it with #popup
})
// Click button which triggers javascript's window.open() call
cy.get("#buttonWhichOpensPopupWithDynamicUrl").click()
// Make sure that it triggered window.open function call
cy.get("#popup").should("be.called")
// Now we can continue integration testing for the new "popup tab" inside the same tab
Is there any better way to do this?
// We can remove the offending attribute - target='_blank'
// that would normally open content in a new tab.
cy.get('#users').invoke('removeAttr', 'target').click()
// after clicking the <a> we are now navigated to the
// new page and we can assert that the url is correct
cy.url().should('include', 'users.html')
Cypress - tab handling anchor links
I was able to achieve the same requirement via the following:
let newUrl = '';
cy.window().then((win) => {
cy.stub(win, 'open').as('windowOpen').callsFake(url => {
newUrl = url;
});
})
cy.get('.open-window-btn').click()
cy.get('#windowOpen').should('be.called');
cy.visit(newUrl)
Here's a solution i'm using on my project based on "Cypress using child window"
Cypress Window Helpers (aka. Cypress Tab Helpers)
They're really popup-windows or child-windows, but i call them tabs for api brevity
cy.openTab(url, opts)
cy.tabVisit(url, window_name)
cy.switchToTab(tab_name)
cy.closeTab(index_or_name) - pass nothing to close active tab
cy.closeAllTabs() - except main root window
I was recently faced with this issue as well - url for the new tab is dynamic, so I don't know what it is. After much searching, some trial and error, and input from co-workers, resolved by doing the following:
// AFTER cy.visit()
cy.window().then((win) => {
cy.spy(win, 'open').as('windowOpen'); // 'spy' vs 'stub' lets the new tab still open if you are visually watching it
});
// perform action here [for me it was a button being clicked that eventually ended in a window.open]
// verify the window opened
// verify the first parameter is a string (this is the dynamic url) and the second is _blank (opens a new window)
cy.get('#windowOpen').should('be.calledWith', Cypress.sinon.match.string, '_blank');
this is how you can handle tabs in same window..
use this code snippet
cy.xpath("//a[#href='http://www.selenium.dev']").invoke('removeAttr','target').click();
I am working on a web based application, in which I have to open popup window. I am using window.open() method to open the popup, like this:
window.open(url, "popupWin");
where url contains the URL I would like my popup window to navigate to. Now, the problem is, if I execute window.open() from multiple tabs (with same or different URLs), at least on Chrome, it might / might not give you the same window which was opened earlier. This behaviour is inconsistent, I mean, either it should get me fresh window every time, or it should get me previously opened window every time.
I need to persist the same popup window for entire domain. How can I do that?
Well looks like there is a direction to go or at least to give it a try.
It fully remains on localStorage which gives you ability to share the knowledge across your tabs within a single domain.
The code I give below does not work yet (it is only a direction), so don't expect too much from running it as it is.
What it does: it saves the popups by the url in a localStorage and when you try to open a new one with the same url it won't do that. If you don't want to distinguish them by URL it is even simpler: store boolean in a localStorage instead of an object.
What it does not do but should:
it should listen to the popup onunload (close) event and reset the localStorage information accordingly. Best for you here is just to set your localStorage boolean value to false
it should listen to the current tab onunload (reload, close) event and also reset something according to Your logic. As I understand the best for you would be just check whether this tab is the last one from your domain (you can also do this using localStorage, e.g. on every new tab adding its identifier, e.g. creation timestamp and destroying it on tab close) and if it is set your localStorage boolean value to false.
This, I think, would be enough to solve the problem. And finally a small piece of code:
// get the localstorage url map
function getOpenPopups() {
var obj = localStorage.getItem('mypopups');
return obj ? JSON.parse(obj) : {};
}
// set the localstorage url map
function setOpenPopups(object) {
localStorage.setItem('mypopups', JSON.stringify(object))
}
// open the popup
function popup(url, title) {
var popups = getOpenPopups();
// check whether popup with this url is already open
// if not then set it and open the popup
if (!popups[url]) {
popups[url] = true;
setOpenPopups(popups);
return window.open('abc', 'cde');
}
else {
return false;
}
}
jsFiddle
From w3c documentation we can see that window.open() returns a reference to the newly created window, or null if the call failed. That means we can keep it in memory and check for closed flag of that window.
var newWindow = window.open('/some/path', 'TestWindow');
// ...
if (!newWindow.closed) {
}
Keep in mind that if window with following name exists, page will be loaded in the same window without opening new one.
Other variants of name parameter like _blank, _self, _top, _parent you can find in official docs too.
I have a Firefox extension that modifies the content of the page that the user is looking at. As part of that process the extension needs to trigger a custom event that the extension itself adds to the page source. I am having difficulties passing parameters to that custom event. What am I doing wrong?
Script block inserted into the head of the page:
document.addEventListener("show-my-overlay", EX_ShowOverlay, false, false, true);
function EX_ShowOverlay(e) {
alert('Parameter: ' + e.index);
// ...
}
Code in the extension:
var event = content.document.createEvent("Events");
event.initEvent("show-my-overlay", true, true);
event['index'] = 123;
content.document.dispatchEvent(event);
The event gets triggered successfully, but e.index is undefined.
I managed to get it working by creating an element on the page and then having the event handler find the element and read its attributes, but it didn't feel elegant. I want to do it without the element.
EDIT:
I also tried triggering the event with CustomEvent, but it throws an exception in the handler:
var event = new CustomEvent('show-my-overlay', { detail: { index: 123 } });
content.document.dispatchEvent(event);
function EX_ShowOverlay(e) {
alert('Parameter: ' + e.detail.index);
// ...
}
Permission denied to access property 'detail'
OP has solved their problem using postMessage. For those of us who actually do have to solve it using CustomEvent (being able to specify message types is useful), here's the answer:
Firefox won't allow the page script to access anything in the detail object sent by the content script via CustomEvent unless you clone the event detail into the document first using the Firefox-specific cloneInto() function.
The following does work over here to send an object from the extension to the page:
var clonedDetail = cloneInto({ index: 123 }, document.defaultView);
var event = new CustomEvent('show-my-overlay', { detail: clonedDetail });
document.dispatchEvent(event);
The Mozilla docs have more detail on cloneInto.
You cannot access "expandos" (additional properties defined on a native prototype object) across security boundaries. The security boundary in this case being between the fully privileged chrome (add-on) code and the non-privileged website code.
So you need to pass data using something "standard". The CustomEvent stuff would do, however your code is wrong. You have to call the constructor or initCustomEvent() correctly:
var event = new CustomEvent('show-my-overlay', { detail: { index: 123 } });
content.document.dispatchEvent(event);
Another alternative is the postMessage API.
I am new to javascript. I would like to know how a new window can be opened from a javascript method, and then call it's javascript methods.
The url of the window, is in another domain (can cause a security problem !?), and I don't have control over it.
For example, a code that should behave as the followings:
handler<-openAWindow("www.someurl.com");//open a window and get a handler for it
handler->someMethod1(param1, param2);//call some javascript method
handler->someMethod2(param3, param4);//call some other javascript method<br>
Thanks,
Eran.
You cannot control or access a cross domain window unfortunately. This is done for security precautions. Do you have control over the other URL?
However, if the window is on the same domain you do have access to the window and its DOM.
var win = window.open("/page", "title");
win.someFunction();
var el = win.document.getElementById("id123");
//etc.