Wait for the browser to do a refresh - javascript

I'm automating tests using protractor.
In the web app that I'm automating, there's a button that, when pressed, refreshes the page.
Is there a way to wait for a refresh to happen & complete using protractor ?

Could you use for tests GET variables?
So basically on first load you click the button and it appends "?is_reloaded=true".
Maybe this could help.
But I badly have no experience in protractor.

Are you testing the functionality of the refresh button? If not then just check for changes in the page that you have refreshed, if yes try injecting a flag in the page (window) by using browser.executeScript()
For example:
let getCurrentWindowHash = () => {
return browser.executeScript("return window.location.hash");
};
await browser.executeScript("window.location.hash = 'Not yet refreshed'");
// Confirm that the has has been set
console.log(`current window hash = ${getCurrentWindowHash()}`); // Should log '#Not yet refreshed'
// click the refresh button
// On refresh, window properties would get reset.
// If the window location hash is empty, then your page was refreshed.
console.log(`current window hash = ${getCurrentWindowHash()}`); // Should be empty

Related

How to determine whether the user closes browser tab or refreshes the page

I am building a two person game app using vue.js. The app uses vuex for state management and Firestore as the backend server.
If the user leaves the app by either closing the browser tab or navigating away, the games Firestore files need to be deleted. However, if the user refreshes the page, the Firestore files need to remain so that the reload process can repopulate the game.
So I need to determine if the user has refreshed the page as opposed to closing the browser or navigating away.
As shown below, in vue's created lifecycle I setup a "beforeunload" event Listener and also start my Firestore listeners
created() {
// This window event listener fires when the user
// navigates away from or closes the browser window
window.addEventListener("beforeunload", (event) => {
const isByRefresh = getUnloadInitiator();
if (!isByRefresh) {
this.stopFirestoreListeners("beforeunload");
}
// Cancel the event. This allows the user to cancel via popup. (for debug purposes)
event.preventDefault();
event.returnValue = "";
// the absence of a returnValue property on the event
// guarantees the browser unload happens
// delete event["returnValue"];
});
this.startFirestoreListeners("created");
},
The getUnloadInitiator function is shown below. This is where I need help. Right now all this function does is console.log various performance values.
function getUnloadInitiator() {
// check for feature support before continuing
if (performance.mark === undefined) {
console.log("performance.mark NOT supported");
return false;
}
console.log("===============================");
// Yes I know that performance.navigation is depreciated.
const nav = performance.navigation;
console.log("nav=", nav);
console.log("===============================");
// Use getEntriesByType() to just get the "navigation" events
var perfEntries = performance.getEntriesByType("navigation");
for (var i = 0; i < perfEntries.length; i++) {
var p = perfEntries[i];
console.log("= Navigation entry[" + i + "]=", p);
// other properties
console.log("type = " + p.type);
}
console.log("===============================");
performance.mark("beginLoop");
const entries = performance.getEntries({
name: "beginLoop",
entryType: "mark",
});
const firstEntry = entries[0];
console.log("firstEntry.type=", firstEntry.type);
console.log("===============================");
//TODO: Determine how unload was initiated
return true;
}
Below is the output from my console.logs. They are the same for refreshing the page, closing the browser tab, or navigating away. All show "reload" as the navigation type.
===============================
nav= PerformanceNavigation {type: 1, redirectCount: 0}
===============================
= Navigation entry[0]= PerformanceNavigationTiming {unloadEventStart: 25.399999976158142, unloadEventEnd: 25.69999998807907, domInteractive: 633, domContentLoadedEventStart: 633, domContentLoadedEventEnd: 633, …}
type = reload
===============================
firstEntry.type= reload
===============================
Any help on how to differentiate between refreshing the page, closing the browser tab, or navigating away would be appreciated. There must be away, because the native cancel browser popup I'm using for debug purposes differentiates between fresh and browser tab close.
Thanks
You can use a source of authority as persistence, be it firestore, local storage, or cookies. you are able to get the browser's tab ID with tab.id and compare it to an existing one should one exist.
browser.pageAction.show(tab.id);
Source: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Working_with_the_Tabs_API

Access a new window - cypress.io

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();

How do I navigate to bing.com and enter a search text using the chrome console?

Below is my code.
It is resulting in unexpected behaviour.
It navigates to bing.com but it does not fill in the text field. Also, I have noticed that the console get cleared after navigating to a new webpage.
window.location = "https://www.bing.com";
window.onload = function(){
var editSearch = document.getElementById("sb_form_q");
editSearch.value = "Quux";
}
You are binding the onload function to the existing window object.
When the browser loads the new page, it will make a new window object which won't have your property set on it.
JavaScript run in one page (even when you are running it through developer tools) can't persist variables onto a different page.
(Storage mechanisms like localStorage and cookies are available, but you would need code in the subsequent page to look for them).
JavaScript is only valid for the current page you are on. When you are executing code from DevTools console, you are executing code on that page itself. So, when you navigate to another page using window.location you loose the onload handler you have defined.
To add handlers to a different page, it must be connected to your page (the parent) in some way, like an iframe or a popup.
ifrm = document.getElementById('frame');
ifrm.src = 'http://example.com';
ifrm.contentWindow.onload = function () {
// do something here with
// ifrm.contentWindow.document.getElementById('form')
}
As #Quentin said.
But you can do another way like ..
var keyword = "Quux";
window.location = "https://www.bing.com/search?q="+keyword;

Javascript: How to make sure window.open returns same window, if already opened

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.

Cancel/Abort/Confirm an HTML 5 state change event (onpopstate)

With unload event of window, it is possible to show the user a confirmation dialog , let's say in a situation where there is an ongoing request you are waiting for to finish and navigating away from the page will terminate that request.
Is there a way to accomplish this with onpopstate of HTML5 history API? Or any other way with the same outcome?
I guess you could modify the behavior of pushState to ask for confirmation before pushing a new state :
// Store original pushState
var _pushState = window.history.pushState;
// Some bad global variable to determine if confirmation is needed
var askForConfirm = true;
// Modify pushState behavior
window.history.pushState = function() {
if(!askForConfirm || confirm('Are you sure you want to quit this page ?')) {
// Call original pushState
_pushState.apply(window.history,arguments);
}
};
I don't know if it helps in your situation, but Sammy.js, a popular hash-routing library has a before handler. I've used it in my application to record the previously accessed hash, and if it's the hash I want to stop them from leaving, return false will keep them on that page. You still need to rewrite the URL to display the previous page, but it seems to be working.
See my answer in this other thread for more info.

Categories

Resources