How to wait for page to re-open - selenium-webdriver

I have a page where extra features become available if you login. Login is via a popup panel. On successful login, the page is reloaded (so that options appropriate to user rights are dynamically added to the interface).
#Override
#Step("Logs in as: {0}")
public <T extends Actor> void performAs(T actor) {
actor.attemptsTo(
Open.browserOn(homePage),
Click.on(homePage.loginMenuItem),
Enter.theValue(authenticated(actor).username())
.into(homePage.userField),
Enter.theValue(authenticated(actor).password())
.into(homePage.pwdField),
Click.on(homePage.loginBtn),
);
}
The test uses a question to query state of the page. However, what I am seeing is that test seems to be operating on the page before it is reloaded. (times out waiting for target, returns old values elements on the page depending on how I do the question). I can see the revised page being displayed. Clearly, I need to wait till page is reopened in response to click before I ask the question which I thought selenium was supposed to do. But how do I do I wait? If I add:
Open.browserOn(homePage)
after click, then it works - mostly. Sometimes it still seems to respond to old page. But if I rerun, it usually works. Ie the above method is flaky. I could just wait 2 seconds, but theoretically it could still fail if authentication server was being slow. Ideas please.

On the line before
Click.on(homePage.loginBtn)
grab an element, like the login button and store it in a variable. Then click on the login button ... then wait for the login button to become stale. A stale element indicates that the page has refreshed. After that point, you are ready to access the page again.
I don't know what all helper functions you have available but it should look something like this
WebElement loginButton = driver.findElement(homePage.loginBtn);
Click.on(homePage.loginBtn)
new WebDriverWait(driver, 10).until(ExpectedConditions.stalenessOf(loginButton));
// do stuff

Related

Confirmation on browser back button

I'm trying to achieve the following with Gatsby
The user is on a form page, if they hit the browser back button, a pop up would appear, asking if they want to leave.
If the user selects ok, then it would go back.
If the user selects cancel, then it would stay on this page
I was able to "almost" make it happen by doing the following
useEffect(() => {
const confirmExit = e => {
const leaveThisPage = window.confirm("Would you like to leave this page?")
if (!leaveThisPage) {
window.history.forward()
}
}
window.addEventListener("popstate", confirmExit)
return () => {
window.removeEventListener("popstate", confirmExit)
}
}, [])
There is one issue, if the user selects cancel, then the browser would go to the previous page. Then window.history.forward() would fire and sends them back.
I noticed that popstate event cannot be cancelled, so e.preventDefault() won't work.
Note: I also tried to test with window.onbeforeunload, but it only triggers if I close to window, or if my previous is from outside my app. Is there a work around for my issue?
Gatsby is using #reach/router under the hood, which doesn't support intercepting and preventing navigation (emphasis mine):
No history blocking. I found that the only use-case I had was preventing the user from navigating away from a half-filled out form. Not only is it pretty easy to just save the form state to session storage and bring it back when they return, but history blocking doesn’t happen when you navigate away from the app (say to another domain). This kept me from actually using history blocking and always opting to save the form state to session storage. (Source)
I second the recommendation for saving the form state using localStorage.

Reactjs Refresh page

When I press the F5 button on my browser to refresh my page, I lose all the values that I once had in my state. How to keep the values updated in my State by pressing the F5 key
It is a bit tricky, but not impossible.
First, do this: Check if page gets reloaded or refreshed in Javascript
You need to recognize that your site has been reloaded and previous code might help you with that.
Next is, to pick place, where to store your state, before reload actually occurs. One option is to store it in local storage.
It is best, for you, if all data which you are trying to preserve, are on server already. If not, then you need some "middle point" between refreshes.
You could do something like this on the part where you recognize that store is reloading:
// Site is reloading
// Store information into users local storage... all current
// states with information of url under which data is stored
On the place, when site is loaded again, you can do:
// Check if there is something stored in local storage for this specific site
// When yes, fill in the states again with configured data
Now, this can make you a lot of trouble, but it would do the work. For example, what about situations when you do not want to store your data.
I suggest that you describe here your use-case, and there might be some nicer approach to this problem.
I have a menu with submenus. I initialize all of my main menus in False to load the page to say that the sub menus are not open. When I click on a menu to display the sub-menu, I true it to say that the sub-menu is open
componentWillMount (){
{this.props.routes.map((prop, key) => {
if(prop.subMenus != null){
this.setState({
[prop.code]:false
});
}
})}
}
As the other said you can save routes state in localStorage (it's like cookie, but better)
To save something with localstorage
localStorage.setItem('routes', JSON.stringify(this.props.routes))
And in the componentDidMount method you can do that
const routesString = localStorage.getItem('routes');
const routes = routesString ? JSON.parse(routesString) : undefined

React JS Routing issue on back button press

I have one odd requirement in one of my project, the requirement is -
1) On initial load of my web-app it should load initial page (first page).
2) If the user comes next time then he should be directly redirected to where he left previously - I'm getting the DROP STAGE from API.
3) When user comes next time then he is redirected to the previously dropped page, but on pressing back he could be redirected to the previous page of the page where he left
Now what I have done so far is -
I have used react-router-dom for routing, but the thing which happens to me is -
1) User comes first time and he is redirected to the very first page by checking the DROP stage from API
2) When user comes again, he has a DROP STAGE (from API) so I am redirecting him to the DROPPED Page.
3) When user press back button (mobile device), the user doesn't stays to the page instead he is redirected again to the DROPPED PAGE as I am checking the DROP STAGE on componentWillMount event and he is again redirected.
Workaround which I have tried are -
1) To set a localstorage variable on the dropped page and check that variable on the back button pressed page - BUT THE RESULT IS I GET THE LOCALSTORAGE VALUE AS EMPTY
2) To check the Action of page i.e. when the user press back button the action becomes POP, but the problem is when the user comes for the first time then too the action is POP - HOW CAN I GET THE ACTION AS PUSH ON INITIAL LOAD
How can I achieve my functionality. Please help
What you need is a module which will be called only once when the application is loaded but it should be loaded irrespective of which ever page the user accesses first.
What you can do is add an empty component in your main router file which should be the first to be called and is called in all the routes. And in the componentDidMount of the component, you should handle the redirection no where else. So the redirection will happen only once thus handling the back actions automatically.

React-Router v4 - Prevent Transition With Function

I was able to prevent navigation as per the v4 docs, but I'm trying to hook up a function so that I can use a modal instead of an alert.
Function:
abandonForm = (route) => {
this.props.showModal('confirm');
console.log('leaving..');
}
In my page:
<NavigationPrompt when={true} message={(location) => this.abandonForm('confirm')} />
this.props.showModal('confirm') activates the modal successfully, but behind the modal the page still transitions - how can I prevent transition until a button in the modal is clicked?
Browsers only allow navigation cancellation by means of the alert box that you've mentioned. This restriction is motivated by phishing/scamming sites that try to use javascript gimmicks to create user experiences that convincingly mimic something that a browser or the OS would do (whom the user trusts). Even the format of the text shown in the alert box is crafted so that it's obvious that it originates from the site.
Of course, as long as the current URL stays within your app, you have control over it using react-router's history. For example you can do the following on navigation:
allow the navigation without confirmation
immediately navigate back to the previous location, but now with a modal on top
navigate away for real this time when the user clicks on a button in the modal.
The disadvantage of this approach (leaving out the sheer complexity of it) is that the user will not get a confirmation dialog if they try to navigate to a different site entirely.
Use:
this.unBlock = this.props.history.block((location, navigateToSelectedRoute) => {
// save navigateToSelectedRoute eg this.navigateToSelectedRoute =
// navigateToSelectedRoute;
// use this.navigateToSelectedRoute() afterwards to navigate to link
// show custom modal using setState
});
and when unblocking is done then call this.unBlock() to remove the listener.
Documentation here for history api

Alert user if the current page is temporarily left with React + React-Router

If a user attempts to change the active page (window/tab/etc) from our page to another while myState is true, we want to notify/alert the user in React JS using react-router.
I tried implementing it with the help TransitionHook and React-router's Confirming Navigation article. Though these only point out / work when user wants to close the page or reload it. Whereas I need to know when user just temporarily leaves the page without necessarily closing it.
How can I achieve this?
If by "leaving the page", you mean that the page is open, but a different window has popped up, you could consider using the document.hasFocus property. Here is one way I handled a problem that was tangentially related:
componentDidMount: function (){
setInterval(()=>{
if (document.hasFocus()){
this.checkServerState();
}
},
},

Resources