How to handle protractor test to run in a sequential order - protractor

This is my Block which contain an element.element(by.model("$ctrl.benchmark.name"));
This is not present on Dom. It give me error that element is not on page but still execute all lines of code written after it. I want this to handle in sequential way if above passes then go to next only. How can I handle these types of problem in Protractor.
it("Test BenchMark",function(){
browser.getTitle().then(function (name) {
console.log(name);
browser.sleep(2000);
element(by.linkText("Manage Benchmarks")).click();
browser.sleep(4000)
//element(by.xpath("//main[#class='ng-scope']//a[text()='Create Benchmark']")).click();
console.log("megha");
element(by.model("$ctrl.benchmark.name")).sendKeys("bench");
element(by.buttonText("Save")).click();
console.log(megha);
element(by.xpath("//button[#class='dropdown-toggle']")).click();
console.log("dropdown clicked")
});

The behavior which you are expecting will not be handled by Protractor, it will be by testing framework(ex: Jasmine). But
"Jasmine doesn't support failing early, in a single spec. The idea is to give
you all of the failures in case that helps figure out what is really wrong
in your spec"

You can use browser.wait() combined with Expected Conditions.
browser.wait() blocks control flow execution until a promise is resolved, and Expected Conditions all evaluate to a promise.
So in your case, you could use either presenceOf() and/or visibilityOf().
var EC = protractor.ExpectedConditions;
var el = element(by.model("$ctrl.benchmark.name"));
var present = EC.presenceOf(el); // wait for it to be added to DOM
var visible = EC.visibilityOf(el); // wait for it to be visible on page
browser.wait(EC.and(present, visible), 10000); // wait maximum of 10 seconds
// rest of code

Related

Avoiding repetitive calls when creating reactfire hooks

When initializing a component using reactfire, each time I add a reactfire hook (e.g. useFirestoreDocData), it triggers a re-render and therefore repeats all previous initialization. For example:
const MyComponent = props => {
console.log(1);
const firestore = useFirestore();
console.log(2);
const ref = firestore.doc('count/counter');
console.log(3);
const { value } = useFirestoreDocDataOnce(ref);
console.log(4);
...
return <span>{value}</span>;
};
will output:
1
1
2
3
1
2
3
4
This seems wasteful, is there a way to avoid this?
This is particularly problematic when I need the result of one reactfire hook to create another (e.g. retrieve data from one document to determine which other document to read) and it duplicates the server calls.
See React's documentation of Suspense.
Particulary that part: Approach 3: Render-as-You-Fetch (using Suspense)
Reactfire uses this mechanics. It is not supposed to fetch more than one time for each call even if the line is executed more than once. The mechanics behind "understand" that the fetch is already done and will start the next one.
In your case, react try to render your component, see it needs to fetch, stop rendering and show suspense's fallback while fetching. When fetch is done it retry to render your component and as the fetch is completed it will render completely.
You can confirm in your network tab that each calls is done only once.
I hope I'm clear, please don't hesitate to ask for more details if i'm not.

Protractor: Why cucumber steps shows as executed before the actual execution happened

I am new to protractor-cucumber. I am trying to execute below step definition from protractor conf.js.
this.Given(/^I go to sparqHomePage$/, function (callback) {
homepage.goToHomePage()
homepage.login(data[0].UserName,data[0].Password).then(callback);
});
this.Then(/^I create a process$/, function () {
homepage.clickDesign();
homepage.clickFlowDesigner();
console.log(params.flow.procName + ' '+ params.flow.procDesc);
designPage.createNewProc(params.flow.procName, params.flow.procDesc);
});
this.Then(/^I should see process is saved in db$/, function (callback) {
var sql = "select * from process where name = ?";
sql = mysql.format(sql, params.flow.procName);
console.log(sql);
dbConn.query(sql, function(err, rows, fields){
if(!err) {
procDbObj = rows;
console.log(rows);
expect(procDbObj[0].name).to.eventually.equal( params.flow.procName);
expect(procDbObj[0].description).to.eventually.equal(params.flow.procDesc).and.notify(callback);
}
});
});
As soon as I start the execution, the console log shows, feature file execution was completed, but the actual execution is not yet completed.
In my 3rd step I am doing some db validation based on the step 1 and step 2 actions. As cucumber trying to execute all the steps before the completion of real execution with browser, my 3rd test is always failing.
How can I make cucumber to wait for step execution is completed before moving to the next step.
You are calling
homepage.goToHomePage() and homepage.login(data[0].UserName,data[0].Password).then(callback);. Are both methods correct promises that are correctly handled? It now looks like it is calling both methods but giving a direct callback before resolving the promise.
As Ross stated, you can also chain the promises, but first be sure the promises are correctly handled
Edit:
As Ross stated, you can also chain the promises, but first be sure the promises are correctly handled.
You can also return the promise in stead of the callback, just use it as this
this.Given(/^I go to sparqHomePage$/, function () {
homepage.goToHomePage();
return homepage.login(data[0].UserName,data[0].Password);
});
homepage.goToHomePage()
homepage.login(data[0].UserName,data[0].Password).then(callback);
I'm not sure exactly what is happening in the first line but I assume thats going to be doing a click, you will need to make that return a promise and re-write it like
homepage.goToHomePage().then(()=>{
homepage.login(data[0].UserName,data[0].Password).then(callback);
})
And then follow this pattern for the rest of your code as I can see this same issue throughout

How to stop automatically closing browser when writing protractor test cases

I am new to writing test cases using protractor for non angular application. I wrote a sample test case.Here the browser closes automatically after running test case.How can I prevent this. Here is my code
var submitBtnElm = $('input[data-behavior=saveContribution]');
it('Should Search', function() {
browser.driver.get('http://localhost/enrollments/osda1.html');
browser.driver.findElement(by.id('contributePercentValue')).sendKeys(50);
submitBtnElm.click().then(function() {
});
});
I was also struggling with a similar issue where i had a test case flow where we were interacting with multiple application and when using Protractor the browser was closing after executing one conf.js file. Now when I looked into the previous response it was like adding delay which depends on how quick your next action i performed or it was hit or miss case. Even if we think from debugging perspective most of the user would be performing overnight runs and they would want to have browser active for couple of hours before they analyze the issue. So I started looking into the protractor base code and came across a generic solution which can circumvent this issue, independent of any browser. Currently the solution is specific to requirement that browser should not close after one conf.js file is executed, then could be improved if someone could add a config parameter asking the user whether they want to close the browser after their run.
The browser could be reused for future conf.js file run by using tag --seleniumSessionId in command line.
Solution:
Go to ..\AppData\Roaming\npm\node_modules\protractor\built where your
protractor is installed.
Open driverProvider.js file and go to function quitDriver
Replace return driver.quit() by return 0
As far as my current usage there seems to be no side effect of the code change, will update if I came across any other issue due to this change. Snapshot of code snippet below.
Thanks
Gleeson
Snapshot of code snippet:
Add browser.pause() at the end of your it function. Within the function itself.
I found Gleeson's solution is working, and that really helped me. The solution was...
Go to %APPDATA%Roaming\npm\node_modules\protractor\built\driverProviders\
Find driverProviders.js
Open it in notepad or any other text editor
Find and Replace return driver.Quit() to return 0
Save the file
Restart your tests after that.
I am using
node v8.12.0
npm v6.4.1
protractor v5.4.1
This solution will work, only if you installed npm or protractor globally; if you have installed your npm or protractor locally (in your folder) then, you have to go to your local protractor folder and do the same.
I suggest you to use browser.driver.sleep(500); before your click operation.
See this.
browser.driver.sleep(500);
element(by.css('your button')).click();
browser.driver.sleep(500);
Add a callback function in It block and the browser window doesn't close until you call it.
So perform the action that you need and place the callback at your convenience
var submitBtnElm = $('input[data-behavior=saveContribution]');
it('Should Search', function(callback) {
browser.driver.get('http://localhost/enrollments/osda1.html');
browser.driver.findElement(by.id('contributePercentValue')).sendKeys(50);
submitBtnElm.click().then(function() {
// Have all the logic you need
// Then invoke callback
callback();
});
});
The best way to make browser NOT to close for some time, Use browser.wait(). Inside the wait function write logic for checking either visibilityOf() or invisibilityOf() of an element, which is not visible or it will take time to become invisible on UI. In this case wait() keep on checking the logic until either condition met or timeout reached. You can increase the timeout if you want browser visible more time.
var EC=protractor.ExpectedConditions;
var submitBtnElm = $('input[data-behavior=saveContribution]');
it('Should Search', function() {
browser.driver.get('http://localhost/enrollments/osda1.html');
browser.driver.findElement(by.id('contributePercentValue')).sendKeys(50);
submitBtnElm.click().then(function() {
browser.wait(function(){
EC.invisibilityOf(submitBtnElm).call().then(function(isPresent){
if(isPresent){
return true;
}
});
},20000,'error message');
});
});
I'm sure there is a change triggered on your page by the button click. It might be something as subtle as a class change on an element or as obvious as a <p></p> element with the text "Saved" displayed. What I would do is, after the test, explicitly wait for this change.
[...]
return protractor.browser.wait(function() {
return element(by.cssContainingText('p', 'Saved')).isPresent();
}, 10000);
You could add such a wait mechanism to the afterEach() method of your spec file, so that your tests are separated even without the Protractor Angular implicit waits.
var submitBtnElm = $('input[data-behavior=saveContribution]');
it('Should Search', function() {
browser.driver.get('http://localhost/enrollments/osda1.html');
browser.driver.findElement(by.id('contributePercentValue')).sendKeys(50);
submitBtnElm.click().then(function() {
});
browser.pause(); // it should leave browser alive after test
});
browser.pause() should leave browser alive until you let it go.
#Edit Another approach is to set browser.ignoreSynchronization = true before browser.get(...). Protractor wouldn't wait for Angular loaded and you could use usual element(...) syntax.
Protractor will close browsers, that it created, so an approach that I am using is to start the browser via the webdriver-reuse-session npm package.
DISCLAIMER: I am the author of this package
It is a new package, so let me know if it solves your problem. I am using it with great success.

How to know any UI rendering is completed in automation code

I am wanting to know a button is rendered on main window UI or not. This button rendering is depending on server response result (written in Objective C). If server response comes perfectly it becomes render perfectly (VISIBLE) otherwise it is not present there (INVISIBLE). And whenever it becomes visible I always tap on it for further next process.
I wrote code
UIATarget.localTarget().pushTimeout(200);
//My code
UIATarget.localTarget().popTimeout();
By the above code I have to wait till 200 sec but my concern is I want to wait but whenever object is on screen I don't want keep me busy in WAITING MODE.
How will I write code in automation?
Thanks
Ok, this might give you idea how to follow-up:
For your view implement an accessibilityValue method which returns a JSON formatted value:
- (NSString *)accessibilityValue
{
return [NSString stringWithFormat:
#"{'MyButtonisVisible':%#}",
self.MyButton.isHidden ? #"false" : #"true"];
}
Then somehow you can access it from your test javascript:
var thisproperty = eval("(" + element.value() + ")");
if (thisproperty.MyButtonisVisible) {
UIATarget.localTarget().tap({"x":100, "y":100});
}
Hope that helps.
If you make the name different when you enable the button you can do this:
var awesomeButton = target.frontMostApp().mainWindow().buttons()[0];
UIATarget.localTarget().pushTimeout(200);
awesomeButton.withName("My Awesome Button");
if (awesomeButton.isVisible()) {
UIALogger.logError("Error no awesome button!");
}
UIATarget.localTarget().popTimeout();
withName will repeatedly test the name and control will return to your script once the name matches or when the time out is reached.
Per Apple's Doc
withName:
Tests if the name attribute of the element has the given string value. If the match fails, the test is retried until the current timeout expires.
Timeout Periods:
If the action completes during the timeout period, that line of code returns, and your script can proceed. If the action doesn’t complete during the timeout period, an exception is thrown.
https://developer.apple.com/library/etc/redirect/xcode/ios/e808aa/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/UsingtheAutomationInstrument/UsingtheAutomationInstrument.html#//apple_ref/doc/uid/TP40004652-CH20

What is better approach to wait for elements on a page Waitforcomplete() or system.threading.thread.sleep()

I am Using WaitforComplete() in watiN but it doesnt seems to work well. As it executes the next statement even if you have given longer time to wait. I am using thread.sleep() to stop my application until it gets the desired page or element. But the thing is pages are so much dynamic that sometimes it takes much longer time as specified.
Any better solution. Any thing that will catch the page return dynamically and dont go to execute next statments in application.
Sample of Code
'Show Details page
Assert.AreEqual("Confirmation", _internetExplorer.Title)
If (_internetExplorer.Button(Find.ById(New Regex("btnFinish"))).Exists) Then
_internetExplorer.Button(Find.ById(New Regex("btnFinish"))).Click()
Else
Assert.Fail("Could not Find Finish Booking Button on Confirmation Page")
End If
System.Threading.Thread.Sleep(100000)
'Show Booking Summary page
Assert.AreEqual("Display Booking", _internetExplorer.Title)
I want something that detect the return of page dynamically. instead of giving some constant value.
WaitForComplete only works well if there is a postback after some action. Otherwise you have to find something else to wait for. Following an example on how to wait for the specified title:
_internetExplorer.Element("title", "Confirmation").WaitUntilExists();
I would always prefer to use one of the WaitXXX methods instead of Thread.Sleep cause the WaitXXX methods do only wait until the contraint is met. Where as Sleep waits for the time you specified. If its to long, time is waisted. If its to short, problems arise.
HTH,
Jeroen
The WaitForComplete method esentially moves on once the browser has set it's readystate to comllete and the busy state to false.
What I typically do is to try and access what you need to, then perform a thread.sleep for say half a second, then try again. I also have a global timeout that quits after say 10 seconds.
int timeout = 20;
bool controlFound = false;
for (int i = 0; i < timeout; i++)
{
if (_internetExplorer.Button(Find.ById(New Regex("btnFinish"))).Exists)
{
_internetExplorer.Button(Find.ById(New Regex("btnFinish"))).Click();
controlFound = true;
break;
}
else
{
System.Threading.Thread.Sleep(500);
}
}
if (!controlFound)
{
Assert.Fail("Control not found");
}
If it is executing the next statement, it should be finding the corresponding element. I suggest posting a sample of the code you are trying.