Protractor Test cases - javascript

I am new to protractor e2e testing. and i have written my first test code.. I would like to know your feedback and ways i can improve it.
describe("Map feedback Automation",function(){
it("Check if the Url works ",function()
{
browser.get(browser.params.url);
expect(browser.getCurrentUrl()).toContain("report");
});it("test browser should reach report road option",function()
{
element.all(by.css('div[ng-click="setLocation(\'report_road\')"]')).click();
expect(browser.getCurrentUrl()).toContain("report_road");
});
it("test browser should reach report road missing",function()
{
element.all(by.css('div[ ng-click="mapFeedBack.editObject= mapFeedBack.createMapObjectModel();setLocation(mapFeedBack.noMap?\'road_new\':\'choose_location_road_new/road_new\')"]')).click();
expect(browser.getCurrentUrl()).toContain("choose_location_road_new/road_new");
browser.sleep(browser.params.sleeptime);
});
it("test browser should zoom on map ",function() //manual
{
element.all(by.css('div[ng-click="zoomIn()"]')).click();
browser.sleep(browser.params.sleeptime);
element.all(by.css('div[ng-click="zoomIn()"]')).click();
browser.sleep(browser.params.sleeptime);
element.all(by.css('div[ng-click="zoomIn()"]')).click();
browser.sleep(browser.params.sleeptime);
element.all(by.css('div[ng-click="zoomIn()"]')).click();
browser.sleep(browser.params.sleeptime);
});
it("Should click on ok option",function()
{
element(by.buttonText('OK')).click();
expect(browser.getCurrentUrl()).toContain("road_new");
});
it("test browser should reach report road option",function()
{
browser.sleep(browser.params.sleeptime);
expect(browser.getCurrentUrl()).toContain("road_new");
});
it("should enter a road name",function()
{
browser.sleep(browser.params.sleeptime);
var testroadname = browser.params.testroadname;
element(by.model("mapFeedBack.editObject.roadName")).sendKeys(testroadname);
browser.sleep(browser.params.sleeptime);
});
it("should check the type of road is highway",function() //spec3
{
element(by.model("mapFeedBack.editObject[attrs.select].selected")).$("[value='string:app.road.roadType.highway']").click();
});
it("should submmit the map feedback",function()
{
element(by.css('button[ng-click="onSubmit({reportType: reportType})"]')).click();
browser.sleep(browser.params.sleeptime);
});});
A colleague of mine told me to remove the delay
browser.sleep(browser.params.sleeptime);
and add some event when the zoom in button is clicked. can you suggest me the ways i can achieve it?

As they say, every code has it's own smell. One the worst smells produced by Protractor-specific code is the use of browser.sleep() to tackle timing issues. browser.sleep() calls usually are making the tests much slower than it is needed and occasionally don't add enough of a delay to make a test pass making the author of the code increase the sleep delay which again makes a test even more slower. And, by the way, there is a related third-party ESLint rule that would help to prevent you from having browser.sleep() in the e2e codebase.
A more robust alternative to having a hardcode delay, is to use browser.wait() and a set of built-in Expected Conditions. The main advantage here is that browser.wait() would wait as long as it is necessary continuously checking the state of the expected condition.
For example, in your case, you might make the world a better place to do test automation by using elementToBeClickable condition:
var EC = protractor.ExpectedConditions;
var elm = element(by.id("myid"));
browser.wait(EC.elementToBeClickable(elm), 10000);
elm.click();
Here, Protractor would wait up to (up to is really what makes the difference) 10 seconds (yes, you still need a timeout value) and would raise a Timeout Exception if the element would not become clickable.

You can also wait for the button to be visible using the following wait command:
var btn = element(by.css("mycss"));
browser.driver.wait(protractor.until.elementIsVisible(btn), 5000);
btn.click();
Visibility means that the element is not only displayed but also has a height and width that is greater than 0.

Related

What is the correct way to perform TestCafe assertions

I am basically stuck between a rock and sort of a hard place. I’m writing some automation scripts using TestCafe and I need some help on best practices. Basically I would like to know the best way to create an assertion that waits a brief period of time until an element appears before executing.
My Current implementation:
const setTimeout = 5000;
await t
.expect(this.papernote.exists, { timeout: setTimeout })
.ok('The trail is not visible');
When the test executes, it seems like the timeout does not get respected. Meaning TestCafe will wait the default time (3 seconds I believe) then the assertion will fail
If you need to define a timeout for a particular assertion, pass the options object to the ok method:
await t
.expect(this.papernote.exists)
.ok('The trail is not visible', { timeout: setTimeout });
See the documentation article for details: https://devexpress.github.io/testcafe/documentation/test-api/assertions/assertion-api.html#ok
I hope you want to increase the selector timeout. Try using this flag
--selector-timeout 500000
and you can also try
--assertion-timeout 10000
or you can try waiting for the element,
await element.with({ visibilityCheck: true }).with({timeout: 10000});
https://devexpress.github.io/testcafe/documentation/using-testcafe/command-line-interface.html

Cypress conditional quit runner/test

So I built out a command that I'm using in multiple tests that looks at the page and if a prompt is there then the page is redirected to another page to handle the prompt (in this case approving a schedule). Then it additionally looks at that new page and if the page has some text instead then it redirects to the home page (where the issue lies) OR it clicks the button to approve and redirects to the home page and continues normally through the test.
Cypress.Commands.add('approval_redirect', () => {
cy.get('body').then(($body) => {
if ($body.text().includes(
'You must approve your weekly schedule before starting!'
)) {
cy.get('.container a')
.first()
.click()
cy.get('main').then(($main) => {
if ($main.text().includes('schedule')) {
cy.get('button')
.click()
cy.pause()
} else {
cy.get('ul > button')
.click()
}
})
}
})
})
Right now if it's going to the new page to verify the schedule and does NOT have a button to click it's returning home and then pausing. I put in the pause because it would then continue the test with massive failures.
So for example in one test I have:
it('starts here', function (){
cy.login()
.wait(1000)
cy.approval_redirect()
cy.get('#Route')
.click()
.wait(1000)
})
So in this if it redirects home after not clicking the button I'd like for it to completely stop the test. There's nothing to actually do.
Is there a way to completely stop the runner? How do I put that in my test to check against the command for failure?
I thought I could just wrap a function around the command with something like:
function findFailure(failure,success){cy.get...}
Then instead of cy.pause() I put
failure();
return;
And under the ul > button I put
success();
return;
Then in my test I did:
it('starts here', function (){
cy.login()
.wait(1000)
cy.approval_redirect()
const failure = function(){
this.skip()
}
const success = function(){
cy.get('#Route')
.click()
.wait(1000)
}
})
There are no errors and the test runs but it doesn't actually go through the command now. So how do I conditionally stop the cypress test?
This one is interesting. I commend your resourcefulness, especially since Cypress has strong feelings when it comes to conditional testing due to its asynchronous nature.
I had a similar problem recently. For me, nothing on a page was clickable at a certain point if there was network activity, and a toast would appear saying "Loading...", and nothing could be done until network activity was done and the toast disappeared. Basically, I needed the page to wait as long as it needed for the toast to disappear before continuing (thus conditional testing).
What I did was something like this:
In commands.js:
Cypress.Commands.add('waitForToast', () => {
cy.get('toast-loading', {timeout: 20000}).should('not.exist');
});
Then in the actual test.spec.js, using the command:
cy.waitForToast();
What's happening here is Cypress is pausing the test and looking for the toast, and waiting with a timeout of 20000 milliseconds. If the toast gets stuck, the test will exit/fail. If the toast disappears, the test will continue.
Using asserts so far has been the most effective way to do conditional testing. If you're waiting for a button to appear, use an assert with a longer timeout to wait for it. Then, if it doesn't show up, the test will exit and fail.
In your case, you can assert if you didn't go home.
Alternatively
If you want the test to just end without asserting and failing, you can try something like this:
cy.get('home-page-item`)
.its('length')
.then(numberOfItems => {
if (numberOfItems > 0) {
DO-NOTHING-ASSERT
} else {
CONTINUE-TEST
}
});
Otherwise I don't think Cypress has anything like cy.abortTest(), so you'll have to work around their anti-conditional testing methodology with asserts or if else.
After a bit I noticed an issue with my conditional as it was looking for if a prompt was there then go to the schedule; then if certain text wasn't there then go home (where the pause/desire to abort lived) OR click on the button, go home and finish. I noticed that I didn't put in another else on the first condition.
My solution was to just create a function that contained all the steps for a complete test barring no redirects/redirect that had a button click. Then I put in the failures a console log about what happened to end the test. Something like:
cy.log('Schedule not approved, redirected, no published schedule. Test ended.')
This gives a clean end/break to the test. Albeit wrapping a success/failure would be wonderful.

protractor hanging on element click

I've got an angular 5.x project. I'm trying to execute some e2e tests with Protractor. I've got a few simple tests running that simply check the browser title and check for the presence of basic elements.
I'm now trying to do more complex tests where I interact with the page. Unfortunately clicking an element causes a nasty hang that never comes back (not even after 30-60 seconds). Any ideas what could be causing this, or how I could even troubleshoot?
Tests that work:
it('should have correct title', () => {
expect(browser.getTitle()).toEqual("My App");
});
it('should have a login button', () => {
let loginButton = element(by.id('btnLogin'));
var untilLoginIsVisible = ExpectedConditions.presenceOf(loginButton);
browser.wait(untilLoginIsVisible, 20000);
expect(loginButton.isDisplayed()).toEqual(true);
});
Test that hangs - note similarity with successful test above
it('show login transition', () => {
let loginButton = element(by.id('btnLogin'));
var untilLoginIsVisible = ExpectedConditions.presenceOf(loginButton);
browser.wait(untilLoginIsVisible, 20000);
//EITHER ONE OF THESE FAILS, AND JUST HANGS FOREVER
loginButton.click().then(() => { console.log("Clicked, yo!"); });
browser.actions().mouseMove(loginButton).mouseDown(loginButton).mouseUp().perform();
});
Other info:
I've tried other buttons on the page - same result
While I get no errors, after ~60 seconds I do get an F in the output, indicating a failed test, but it never moves to the next test
After ~2 minutes it starts spitting out ERROR:process_metrics.cc(105)] NOT IMPLEMENTED which I don't think is the source of the problem (similar unrelated complaints here)
I finally found the cause for this. I'm using multiCapabilities to test various browsers & sizes. Unfortunately my first capability was using mobile emulation:
chromeOptions: {
'mobileEmulation': {
'deviceName': 'iPhone 4'
},
This was the trigger to making clicks completely hang. Below is some more info on what works and what doesn't.
Works on non-mobile emulation, hangs on mobile emulation
loginButton.click().then(() => { console.log("Clicked, yo!"); });
Works with mobile emulation
browser.touchActions().tap(loginButton).perform().then(() => { console.log("Tapped, yo!"); });
It's unfortunate that whatever is causing this made protractor hang completely and not give any errors. Moving to the next capability would have made this more obvious. A follow-up question I'll need to deal with is if all mobile emulation tests need to use tap() in place of click()...

Why must I use browser.sleep while writing protractor tests

My first run at E2E tests. I'm trying to digest someone else's protractor tests.
Problem: There are a lot of browser.driver.sleep and this seems fragile.
Goal: not to use browser.driver.sleep
Question: What is a better approach to browser.driver.sleep? Something less fragile like a promise or something I dont know about lol?
var config = require('../../protractor.conf.js').config;
describe('this Homepage Body Tests', function(){
browser.driver.get(config.homepageUrl);
it("should open find a clinic page", function(){
// page loads :: want to fix this random wait interval
browser.driver.sleep(2000);
browser.ignoreSynchronization = true;
var string = 'clinic';
var main = '.search-large-text';
var link = element(by.cssContainingText('.submenu li a', string));
link.click().then(function() {
// page reloads :: want to fix this random wait interval
browser.driver.sleep(3000);
var title = element(by.cssContainingText(main, string));
expect(title.getText()).toBe(string);
});
});
});
Since there is an ignoreSynchronization turned on, you cannot use waitForAngular(), which would be a solution in case of an angular-site testing.
A better solution here would be to set a page load timeout:
browser.manage().timeouts().pageLoadTimeout(10000); // 10 seconds
See also these relevant threads on explicit waits and timeouts:
Use protractor to test login on non-AngularJS page (Leo's answer is very detailed)
Protractor : How to wait for page complete after click a button?
Timeouts

Mocha tests on focus-related behaviors (Backbone/CoffeeScript app)

I have a Backbone app written in CoffeeScript. I'm trying to use Mocha (with Chai and Sinon) to write tests for DOM-related behaviors, but it seems that hidden fixtures (I'm using js-fixtures now but I've also tried this unsuccessfully with a hidden '#fixtures' div) don't register certain DOM-related behaviors which makes testing certain types of DOM-related behaviors (seemingly) impossible.
For example, my main app view has several subviews which are never rendered at the same time: when the app view renders subview A, it remembers the focused element of the currently active subview B (#_visibleView), saves that information on subview B, closes the subview B, and then renders subview A.
_rememberFocusedElement: ->
focusedElement = $ document.activeElement
if focusedElement
focusedElementId = focusedElement.attr 'id'
if focusedElementId
#_visibleView?.focusedElementId = focusedElementId
This works when I test it manually, but when I try to write unit tests for this behavior they fail because I can't set focus (e.g., via $(selector).focus()) to an element in a hidden div/iframe. (I have the same issue with functionality which listens for window resize events.)
I thought that if I changed $ document.activeElement to #$ ':focus" I might get different results, but that doesn't fix the issue.
Here is what the relevant parts of my Mocha (BDD) tests look like. This spec will print TEXTAREA to the console and then undefined, indicating that there is a textarea with id='transcription' but I can't set focus to it.
beforeEach (done) ->
fixtures.path = 'fixtures'
callback = =>
#$fixture = fixtures.window().$ "<div id='js-fixtures-fixture'></div>"
#appView = new AppView el: #$fixture
done()
describe 'GUI stuff', ->
it 'remembers the currently focused element of a subview', (done) ->
#appView.mainMenuView.once 'request:formAdd', =>
#appView._visibleView.$('#transcription').focus()
console.log #appView._visibleView.$('#transcription').prop 'tagName'
console.log #appView._visibleView.$(':focus').prop 'tagName'
done()
#appView.mainMenuView.trigger 'request:formAdd'
Is there any way that I can write unit tests for these types of behaviors?
Ok, first off let me clarify something: the term "unit test" means man different things to many people. Often times it becomes synonymous with "any test written using a unit test framework (like Mocha)". When I use the term "unit test" that's not what I mean: what I mean is a test that tests only a single unit of work (which, in a JS environment, will usually be a single function, but might be a whole class).
Ok, with that out of the way, if you really are trying to unit test your code, you're sort of taking the wrong approach. A unit test really shouldn't rely on anything outside the context of the function being tested, and so relying on the (external) DOM is where your problem lies.
Let's assume your focus-handling code is in a function called handleFocus (I don't know the actual method name). Consider the following test, which I'll write using JavaScript since my CoffeScript is rusty:
describe('#handleFocus', function() {
it('remembers the currently focused element of a subview', function() {
var setFocusStub = sinon.stub($.fn, 'focus');
appView._visibleView.handleFocus();
expect(setFocusStub.calledOnce).to.be(true);
});
});
The above is a bit of an over-simplification, but hopefully it illustrates the point. What you're really trying to check isn't whether the DOM (fake or real) does X; what you're trying check is whether your function does X. By focusing on that in your test, and relying on a stub that checks whether "X" happened or not, you completely eliminate the need for the DOM to be involved.
Now of course you might wonder: "well great, that helps me in test-land, but how do I know it will work in a real environment?" My answer to that would be that your (probably Selenium-based) acceptance tests should cover that sort of thing. Acceptance tests should check whether your overall code works in the real world, while unit tests should ensure that individual pieces of that code work in a fake environment.
The former is great for ensuring your customers don't see bugs, while the latter is great for figuring out exactly where those bugs come from, and for making it possible for you to refactor safely.

Categories

Resources