Wait for page redirection in Protractor / Webdriver - angularjs

I have a test that clicks a button and redirects to a user dashboard. When this happens Webdriver returns:
javascript error: document unloaded while waiting for result.
To fix this I insert browser.sleep(2000) at the point where redirection occurs and assuming my CPU usage is low, this solves the issue. However, 2000 ms is arbitrary and slow. Is there something like browser.waitForAngular() that will wait for the angular to load on the redirected page before the expect(..)?
it('should create a new user', () => {
$signUp.click();
$email.sendKeys((new Date().getTime()) + '#.com');
$password.sendKeys('12345');
$submit.click();
browser.sleep(2000); // Need alternative to sleep...
// This doesn't do it...
// browser.sleep(1);
// browser.waitForAngular();
$body.evaluate('user')
.then((user) => {
expect(user).toBe(true);
});
});

do you think something like this could work for you? This will wait up to 10 seconds for the url to include the text 'pageTwo', or whatever you put in.
var nextPageButton = $('#nextPage');
nextPageButton.click().then(function(){
return browser.driver.wait(function() {
return browser.driver.getCurrentUrl().then(function(url) {
return /pageTwo/.test(url);
});
}, 10000);
};
Just stick in the regex of the url you are expecting.
Alternatively, you could wait for an element from the next page to appear as well:
var nextPageButton = $('#nextPage');
nextPageButton.click();
var elementFromSecondPage = $('#coolElement');
browser.wait(protractor.until.elementIsVisible(elementFromSecondPage), 5000, 'Error: Element did not display within 5 seconds');
When using .click, protractor will naturally wait for angular to finish the action attached to the click, such as changing the page. But, while the page change, you may still be needing something specific to be loaded, so the test fails before that part is available. Using this, it should wait for the click part to finish, then wait for the element to appear.

To expand on user2020347's answer:
Thanks that solved my issue. I wonder why this isn't a built in function. I'll be using this in many places to wait for browser navigation.
To make it more concise, I made a little helper:
Object.assign(global, {
waitUntilURLContains: string => {
let fn = () => {
return browser.driver.wait(() => {
return browser.driver.getCurrentUrl().then((url) => {
return url.includes(string);
});
}, waitDelay);
}
return fn.bind(null, string);
}
});
In my test:
$button.click().then(waitUntilURLContains('dashboard'));

keeping it very simple. I was also running into the same problem but was able to solve it using the following code :
page.setUsername(objectrepository.userdetails.useremail);
page.setPassword(objectrepository.userdetails.userpassword);
page.login().click();
**browser.wait(EC.visibilityOf(page.greetingMessageElement()), 5000);**
page.greetingMessageElement().getText()
.then(function (value){
expect(browser.getCurrentUrl()).toContain("#/mytickets");
});

Related

React APP makes a ton of API Calls and crashes

I am making a simple app that makes an api request to my local server and gets some data and puts it on a chart from trading view. This should be pretty simple as everything is just for practice, but when I change some of the values on my server and make the call, the app keeps making the call like 35 times before the server crashes and then the app just says
"net::ERR_CONNECTION_REFUSED"
and doesn't display the data as it should.
This is the whole code, it has two parts. One parts makes the call to get example data of name and another call to get example data that will go to the chart (the second part is the issue.)
This is the code just for the second part:
getBars: async (
symbolInfo,
resolution,
periodParams,
onHistoryCallback,
onErrorCallback
) => {
try {
if (resolution === '1D') {
resolution = 1440;
}
const response2 = await axios.get('http://localhost:8000/chart');
console.log('got bars data');
const bars = response2.data.map((el) => ({
time: new Date(el.timeInterval.minute).getTime(), // date string in api response
low: el.low,
high: el.high,
open: Number(el.open),
close: Number(el.close),
volume: el.volume,
}));
if (bars.length) {
onHistoryCallback(bars, { noData: false });
} else {
onHistoryCallback(bars, { noData: true });
}
console.log('bars done');
} catch (err) {
console.log({ err });
}
};
So what happens is that the console.log "got bars data" and "bars done" repeats many times until my localhost:8000 server crashes and then the app gives the error I showed above, because of this it doesn't display the data. I have no Idea why this may be happening,
This is what the data looks like for the one that does not works:
{"timeInterval":{"minute":"2022-03-14T23:45:00Z"},"volume":0.05,"high":3.910209183178435e-9,"low":3.910209183178435e-9,"open":"3.910209183178435e-09","close":"3.910209183178435e-09"}
This is for the one that works:
{"timeInterval":{"minute":"2022-03-17T15:00:00Z"},"volume":0.05,"high":0.00001255389794727055,"low":0.00001255389794727055,"open":"1.255389794727055e-05","close":"1.255389794727055e-05"}
I would appreciate any help, thanks!
EDIT
I just noticed, with the data set that works, console.log('got bars data') and console.log('bars done') don't occur for some reason, but the data still shows up on the chart even though the console doesn't log.

Is there a way to get a useEffect cleanup to run when a user closes the webpage?

So for some reason, if I wanted to run a function to update a database when the user leaves a page, I can do that with a useEffect return/cleanup function. But is there a way to do that if they close the page/browser?
useEffect(() => {
return () => {
window.open("https://www.google.com", "_blank");
};
}, []);
I tried testing like so, but never seemed to work. So I am wondering if there is a way to do this.
To get notified when the window is just about to close, use the onbeforeunload event:
useEffect(() => {
const onBeforeUnload = (e) => {
// run your cleanup code here
}
window.addEventListener('beforeunload', onBeforeUnload);
return () => {
window.removeEventListener('beforeunload', onBeforeUnload);
}
}, []);
You are limited in terms of what you can do during this event. If you want, you can prompt the user whether they really want to close the page, which you do like this:
const onBeforeUnload = (e) => {
// Cancel the event
e.preventDefault(); // If you prevent default behavior in Mozilla Firefox prompt will always be shown
// Chrome requires returnValue to be set
e.returnValue = '';
}
This will display an alert-like message, which you cannot customize. Typically you should only do this if the user has done something where they would expect this kind of message. Ie, they've made changes, and those changes havn't been saved, and they'll be annoyed if they lose them. If you're just running cleanup code, you probably don't need to do this.
You cannot redirect them to another page or show a custom alert. Malicious pages would love this: "Ha ha, you tried to leave my page, well i'm routing you back to it instead".

Protractor reload a page when it's crashed

Let me explain the situation, I'm currently testing an AngularJS website with Protractor, I'm not developing it at all.
The problem is that, absolutely randomly the website is sometime not rendered. It's just blank with a different title :
If title is "VideoGame" -> then website is rendered
If title is "VideoGame-env-DEV" -> Then the website isn't rendered
No idea why and it's not my concern.
However, when testing with Protractor, it's obviously crashing.
So I wanted to bypass the problem with a temporary solution :
function specialRefreshFunction() {
cpt=0;
browser.get('https://blablabla');
browser.waitForAngular();
var title = browser.getTitle();
while (title != "VideoGame") {
cpt=cpt+1;
//sleep(1000);
//browser.sleep(1000);
browser.get('https://blablabla');
browser.waitForAngular();
//browser.navigate().refresh();
console.log("fail "+cpt);
}
console.log("Correct title " + title);}
My solution isn't working. I'm a total newbie with NodeJS & Protractor, so the code might be a nonsense.
W10 64bits
Latest Chromedriver
Protractor 5.4.2
NodeJS 10.15.0
Angular 6.1.10
Thank you !
You can go with browser.wait
let EC = protractor.ExpectedConditions;
browser.wait(
EC.presenceOf($('#some-element')),
10000,
'Element did not appear after route change'
).then(function() {}, function() {
browser.refresh();
});
In this particular example protractor will wait 10 sec for element #some-element to appear on the page. browser.wait returns a promise, so you can handle both cases - when element appear or element did not appear. Just put some specific selector instead of $('#some-element') that present on your page, by which you can consider page as loaded
Though, if you rely only on title value, you can use titleContains
var EC = protractor.ExpectedConditions;
// Waits for the title to contain 'foo'.
browser.wait(EC.titleContains('foo'), 5000);
Try to create a custom promise like that:
public vierifyPageTitle() {
return new Promise((resolve, reject) => {
const refreshUserData = setInterval(() => {
return browser.getTitle().then((title) => {
if (title === 'VideoGame') {
clearInterval(refreshUserData);
resolve(title);
}
}, (err) => {
browser.refresh();
reject(err);
});
}, 1000);
});
}
It's refreshing every 1000 ms if title is not equal to expected.

React Starter Kit error - page not found

I created a new route from the react-starter-kit project and it does an async fetch of some data, then renders it, but a second later the page reloads with a message saying "Page not found - sorry but the page you're trying to view does not exist".
In the console I see - "Warning: Text content did not match. Server: "Balances" Client: "Page Not Found"
async function action() {
let bittrex = new ccxt.bittrex ({
'apiKey': '',
'secret': ''
})
try {
// fetch account balance from the exchange
let bittrexBalance = await bittrex.fetchBalance ()
/**** commenting above and uncommenting this block stops it from happening....
let bittrexBalance = {};
bittrexBalance.info= [];
let currency = {};
currency.Currency = "BTC";
currency.Value=999;
// output the result
bittrexBalance.info.push(currency);*/
console.log ('balance', bittrexBalance)
let balances = [];
balances.push(bittrexBalance)
return {
title: "Balances",
component: (
<Layout>
<Balances balances={balances} />
</Layout>
),
};
} catch (e) {
console.log('SOME sort of error', e);
}
Does anyone have any idea what this could be?
Edit to add, I realise now that if I disable Javascript everything works perfectly...
It seems to be running through the universal router twice. The first time
That's the only clue I've found so far... I don't understand why it's reloading the page once it has already loaded...
The Page not found error is coming from it going through :
catch (e) the second time... I suspect something is happening inside the ccxt library but that the problem is actually that it is called a second time because the page is somehow reloaded...
It seems you have to call await bittrex.loadProducts() before fetching your Balance.
Edit : Seems also that bittrex.loadProducts() has been renamed by bittrex.loadMarkets()
More info in this issue on github
Your server code reached exception, which turns into rejection of route, because action method returns undefined, so server will fall down through —
next routes will not fit and finally it reaches the not found route.

Is there a timeout event in cucumber-js

I am using cucumber-js to run tests with selenium-webdriver.
I want to add a screenshot capture of the browser when any step times out.
I am using global timeout for all the steps as:
this.setDefaultTimeout(3 * 60 * 1000);
in my hooks file.
How do I register to the global timeout event (if such even exists)?
Selenium Webdriver js do provide function to get screenshot, you just need to use it in After, which is similar to #AfterClass tag in TestNG
The After scenario will execute after every scenario in Feature and check the result of the Scenario, it it is FAILED it will take the screenshot.
The reason for failure can be anything, like a bug, or DEFAULT_TIMEOUT
You need to add this in your world.js
this.After(function (scenario) {
if (scenario.isFailed()) {
// take a screenshot
// driver.takeScreenshot() is defined in webDriver.js
return driver.takeScreenshot()
.then(function (screenShot) {
scenario.attach(new Buffer(screenShot, 'base64'), 'image/png');
return driver.close()
.then(function () {
return driver.quit();
});
});
}
else {
return driver.close()
.then(function () {
return driver.quit();
});
}
});

Resources