wait for http request to complete in protractor - protractor

I am trying to wait for spinner to disappear and then for my steps to execute but nothing is working for me.
browser.wait(function () {
return this.spinner.isDisplayed().then(function (result) {
return !result;});}, 20000);
and i even tried with
browser.wait(function () {
return !browser.isElementPresent(this.spinner);}, 20000);
even with below method
browser.sleep(1000);
this.spinner.isPresent().then(function (result) {
if (result === true) {
var EC = protractor.ExpectedConditions;
browser.wait(EC.invisibilityOf(this.spinner), 10000);}});
then only thing that works is
browse.sleep(10000);
i don't want to use sleep in my code. can anyone help me with how to wait for complete http request to complete and then process with testing

you should consider using Expected Conditions since they return true/false based on current conditions
http://www.protractortest.org/#/api?view=ProtractorExpectedConditions.prototype.invisibilityOf
so your test case would become:
browser.wait(EC.invisibilityOf(this.spinner),20000).then(function(){
...continue test, spinner gone
});
UPDATE
in order to use done, you would generally pass this cb into your it() function. This means your test could look like
describe("example describe",function(){
it("should be an example only", function(done){
request.get("www.google.com",function(res){
//done with async request, now call done
done();
})
})
});
Since your entire code isn't posted up here, you should have something similar to:
it("should wait for spinner to go bye-bye",function(done){
browser.wait(EC.invisibilityOf(this.spinner),20000).then(function(){
done()
});
});

Related

Jest + Axios: Test Whether Promise Was Fulfilled

Using Vue test utils with Jest, I am attempting to spy on an axios.get call which runs in my component's created() lifecycle hook. I would like to test that the promise has been fulfilled (i.e. was not rejected) based on a method that runs in the then() block, but not the catch() block.
The way I have the test setup right now, the spyOn always resolves because I am using .mockResolveValue(). I tried declaring mockResolveValue() in the it('') portion of the test, but it says the axios get is called 0 times when I do that.
DeptPrefs.vue
<script>
import axios from 'axios'
export default {
name: "DeptPrefs",
data () {
return {
...
}
},
async created () {
await this.getPrefs()
},
computed: {},
methods: {
async getPrefs () {
await axios.get('/coolsite/api/admin/getstuff?dept=216001')
.then(r => {
this.setDeptPrefs(r.data)
}).catch((e) => {})
}
...
</script>
And this is how the deptprefs.spec.js currently looks.
describe('when prefs created() hook loads', () => {
const localVue = createLocalVue()
localVue.use(Vuex)
...
const getPrefs = jest.spyOn(DeptPrefs.methods, 'getPrefs') // spy on getPrefs() method
jest.spyOn(axios, 'get').mockResolvedValue([]) // spy on axios .get() method
const wrapper = mount(DeptPrefs, {
...
})
it('makes an api call to get the dept prefs', async () => {
await expect(getPrefs).toHaveBeenCalled() // works fine
await expect(axios.get).toHaveBeenCalledTimes(1) // works fine
const setDeptPrefs = jest.spyOn(appModule.mutations, 'setDeptPrefs')
expect(setDeptPrefs).toHaveBeenCalledTimes(1) // this is the expectation in question. It's always 1.
})
})
So let's say I change the URL of the API call to be a non-existent route. The test will still say that the setDeptPrefs() method has been called 1 time. It shouldn't be called at all because the axios should've hit the catch block, where that method does not run.
I want to amend my test to reflect this; when the then() block is hit, setDeptPrefs should NOT be called. When it does, it should be.
Also please feel free to chime in on if this is something I should even be unit testing. I am trying to get a feel for what's test-worthy and what isn't.

Protractor tests are inconsistent even with browser.wait and helper functions

I am looking for some advice. I have been using protractor for a few weeks and just cannot get my tests to be consistent unless I use browser.sleep. I have tried helper functions as well as browser.wait(expectedCondition). I have reduced browser.sleep immensely, but protractor still just goes way to fast. I can never successfully run multiple tests unless I have a few browser.sleeps just so protractor can relax for a second. Here is an example:
The Test I need to select a user, delete that user and wait for a success message. Then I click the same user and click the activate button.
Outcome: Unless I have browser.sleep, my success messages do not even appear after deletion/activation. The tests fail because protractor is moving way too fast. Even with the expected conditions. My main problem is that protractor moves to fast for the angular web page. I have tried ifCLickable or isDisplayed but they do not fix the issue entirely. Here is the code:
async deleteUser() {
await sendClick(this.getNewUser());
await sendClick(this.getDelete());
await waitTillPresent(this.getDeleteConfirm());
await sendClick(this.getDeleteConfirm());
await waitTillPresent(this.getSuccessMsg())
expect(await page.getSuccessMsg().isDisplayed()).toBeTruthy();
}
async activateUser() {
await sendClick(this.getNewUser());
await waitTillPresent(this.getEditBtn())
await sendClick(this.getActive());
await waitTillPresent(this.getSuccessMsg())
expect(await page.getSuccessMsg().isDisplayed()).toBeTruthy();
}
Functions:
export async function sendClick(element: ElementFinder): Promise<boolean> {
try {
if(!await element.isDisplayed()) {
return false;
}
await browser.executeScript('arguments[0].click();', await element.getWebElement());
return true;
}
catch (err) {
return false;
}
}`
export async function waitTillPresent (element: ElementFinder, timeout: number = 10000) {
return browser.wait(() => {
return element.isPresent();
}, timeout);
}
My Question: Am I handling this correctly? Is there a better to ensure my tests are consistent? Before these tests, I visit a non-angular webpage. So I have to include the line browser.waitForAngularEnabled(false)
Does this mess with the async nature of angular? Thank you.
I worked the last few months on our e2e test suite to make it stable. I did not believe it's possible but I made it using correct wait functions and sometimes browser.sleep() as a last resort.
You have a correct approach for waiting for elements. But there are 2 problems regarding your implementation:
1) The function waitTillPresent() does exactly what its name stands for. But if you only wait until the element is present on the page it does not mean it's clickable or displayed. An element can be hidden and at the same time still be present. Please rename waitTillPresent() to waitTillDisplayed() and change it as follows:
export async function waitTillDisplayed(element: ElementFinder, timeout: number = 20000): Promise<boolean> {
let result = await browser.wait(() => element.isPresent(), timeout);
if(!result) {
return false;
}
return await browser.wait(element.isDisplayed(), timeout);
}
2) You should exceed the default timeout. Set it a bit higher like 20 to 25 seconds. Just play with it.
Unfortunately, I don't know how browser.waitForAngularEnabled(false) changes test behavior. We do not use it :)
Note:
These functions are all exactly the same:
function foo() { return 'hello world'; }
var foo = () => { return 'hello world'; };
var foo = () => 'hello world';
Play with arrow functions, it's syntactic sugar.
Cheers and gl!

Protractor not waiting for modal

I have a modal that shows up in a protractor test. When I run the test case solo, it works perfectly, but when I run it as part of the larger file (currently 10 cases, some lengthy) it slows things down and, as a result, the modal is slower to open and close. The chain effect is that, when I try to click on a button on the page, it crashes since the modal (which was supposed to be closed by now) is still there and blocking the button.
How can I properly sense when the modal is open/closed so that I can work around this?
Thanks!
(Also, this is an AngularJS application)
These are my helper functions for manual waiting:
static async forElementAbsent(element) {
return await new Promise<any>((resolve) => {
browser.driver.wait(ExpectedConditions.stalenessOf(element), 10000,
`Timed out waiting for element to be absent`).then(() => {
resolve();
});
});
}
static async forElementPresent(element) {
return await new Promise<any>((resolve) => {
browser.driver.wait(ExpectedConditions.presenceOf(element), 10000,
`Timed out waiting for element to be present`).then(() => {
resolve();
});
});
}
In our tests, we are waiting for modals to be displayed manually. We have helper functions such as
export async function forCondition(condition: () => boolean | PromiseLike<boolean>, timeout = 20000): Promise<boolean> {
try {
return await browser.wait(condition, timeout);
} catch (err) {
return false;
}
}
Given function waits for a condition to fullfill. So in your particular case you would have to find out the css selector of the modal which is displayed.
Let's say the selector is by.css('.modal.visible'), then we would have to write something like the following if we wanted to wait for the modal to be displayed:
t.it('modal should be displayed', async function() {
// wait for modal to be displayed
var result = await forCondition(function() {
return element(by.css('.modal.visible')).isDisplayed();
});
expect(result).toBeTruthy();
});

Protractor Timing Issues

I currently have the following code in one of my test specs for Protractor:
.then(function() {
return button.click();
})
.then(function() {
return element(otherButton).isDisplayed();
})
.then(function(otherButtonIsPresent) {
if(otherButtonIsPresent) {
return browser.wait(EC.elementToBeClickable(element(otherButton)), getWaitTime())
.then(function() {
element(otherButton).click();
return element(continueButton).isPresent();
})
}
})
When I use Chrome to debug using the --debug-brk and --inspect flags, I am able to pass these checks and resume as normal. When I run the same test without the flags, the test fails and stalls during looking for otherButton before trying to click on it.
I'm wondering if this is because during debugging, I set breakpoints and wait for the buttons to show up on the screen before attempting to click on them.
I need to make sure that this element is visible on the page before trying to click it and was wondering if there were another way if accomplishing this?
Thanks
I'm using Answer as I can't comment yet.
You're basically mention it yourself: after you clicked a button you just want to wait until a next button is clickable.
Therefore your .then()-functions should start from the button it depends on. To me it seems, the three lined-up .then()-functions depend on the same condition, so after you .click() the first button, the second .then() gets immediately executed, not waiting the previous .click() to finish.
Therefore putting the .then() directly behind the relevant .click() and inside the preceding .then()-function, this should work:
.then(function() {
element(button).click().then(function(){
element(otherButton).click().then(function(){
return element(continueButton).isPresent();
});
});
});
Or if you go with ExpectedConitions, you shouldn't need .then()-functions. Because Protractor should manage the ControlFlow, allowing you to write it without chained .then()-functions:
.then(function() {
browser.wait(EC.elementToBeClickable(element(button)), getWaitTime());
element(button).click();
browser.wait(EC.elementToBeClickable(element(otherButton)), getWaitTime());
element(otherButton).click();
browser.wait(EC.elementToBeClickable(element(continueButton)), getWaitTime());
return element(continueButton).isPresent();
});
This nice post elaborates a bit on asynchronous writing, but thanks to Protractor synchronous execution.
As alternative an example combining my both inputs, kind of double-securing the test:
.then(function() {
browser.wait(EC.elementToBeClickable(element(button)), getWaitTime());
element(button).click().then(function(){
browser.wait(EC.elementToBeClickable(element(otherButton)), getWaitTime());
element(otherButton).click().then(function(){
browser.wait(EC.elementToBeClickable(element(continueButton)), getWaitTime());
return element(continueButton).isPresent();
});
});
});

Protractor - How to obtain the new URL

I am new to Protractor (and Javascript by the way), and I am writing some tests to practice. My goal so far is to check that when I click on the home button of a website, the redirection leads me correctly to the expected address.
I have written this:
var HomeTopBanner = function() {
this.homeUrl = browser.params.homePageObject.homeUrl;
this.topBanner = element(by.css('.navbar-inner'));
this.homeButton = this.topBanner.element(by.css('.icon-home'));
}
describe('Home button', function(){
var homeTopBanner = new HomeTopBanner();
var newUrl = '';
it('clicks on the Home button', function(){
homeTopBanner.homeButton.click();
browser.getCurrentUrl().then(function storeNewUrl(url) {
newUrl = url;
});
})
it('checks that the home button leads to the homepage', function(){
expect(newUrl).toEqual(homeTopBanner.homeUrl);
})
});
This works, but my question is:
Why do I need to separate the "GetCurrentUrl" and the "expect(newUrl)" parts? I would prefer to have both of them in the same spec, but if I do that, during the comparison of the expect, newUrl=''
I assume this is related to browser.getCurrentUrl() being a promise, but is there a better way to do it?
Yes, getCurrentUrl returns a promise with the url in the form of a string as explained in the protractor api docs. You have to wait until the url is returned in order to use it. Now in order to combine both the specs you can write your expect statement inside the function that getCurrentUrl returns as shown below and there is no need of using a newUrl variable too if you want -
it('clicks on the Home button', function(){
homeTopBanner.homeButton.click();
browser.getCurrentUrl().then(function(url) {
expect(url).toEqual(homeTopBanner.homeUrl);
});
})
There could also be another issue when after the click action the previous url is being captured due to the fact that protractor is async and fast. In that case you can write your getCurrentUrl() function inside the promise that click() function returns. Here's an example of it -
it('clicks on the Home button', function(){
homeTopBanner.homeButton.click().then(function(){
browser.getCurrentUrl().then(function(url) {
expect(url).toEqual(homeTopBanner.homeUrl);
});
});
})
Hope this helps.