How to validate an element is gone using webdriverIO, Mocha and Chai - mocha.js

I'm working on some automated tests, using webdriverIO, Mocha and Chai. I keep running into the same problem when I want to verify if an element is deleted.
I'm working with a shoppingbasket where i delete an item and then verify that it is gone. It takes a while for the item to be gone though, so if I immediately go to the expect, the item is still there.
I have solved this by doing this:
browser.waitForExist(deletedProduct, 5000, true)
expect (boodschappenLijstPage.isProductPresent(SKU), 'the removed item was still there' ).to.equal(false)
The webdriverIO waitfor command waits for the product to dissapear, and after that the chai expect checks if it is gone.
The problem I have with this is that the expect will never fail. If the product is not properly deleted the waitfortimeout will throw an error before I get to the expect part, meaning that the expect part is only reached if the product is gone
I have read through the docs for chai, but I can't seem to find a way of doing this.
Can anyone show be a way of waiting for the product to be gone, without missing the expect (I don't want to use browser.pause for obvious reasons)

Refer this
webElement.waitForDisplayed({ reverse: true });

You can use try catch and basically wait for error. When element disappears from DOM selenium will throw NoSuchElementError and we can use it.
isNotPresent(element) {
try {
return !element.isVisible()
} catch (error) {
return true
}
}
// or wait for element to disappear from dom
waitForNotVisible(element) {
browser.waitUntil(() => {
try {
return !element.isVisible()
} catch (error) {
return true
}
})
}

If you're trying to validate that an element is gone, then using expect is the correct solution, but you should use the Webdriver-expect assertions instead of the chai expect assertions. While chai assertions check the state immediately, the WebdriverIO-expect assertions have the waitFor functionality built inside of it. Here is an example:
let deletedProduct = $(/* your xpath/CSS selector/*);
expect(deletedProduct).not.toBeDisplayed();
The difference between the assertion and using waitForDisplayed with the reverse flag is that some reporters, such as Allure, will report your test as broken when instead the test should be reported as failed. For example, when we ran tests and had the waitForDisplayed, all of our failing tests were marked in yellow. When we use expect, the tests are marked in red.
Here is the documentation for the WebdriverIO Expect matchers. They didn't document the .not method very clearly, but in my example you can see I added the .not before the toBeDisplayed call.
Again, this expect will wait for the timeout specified in the wdio.conf.js, just like the waitFors will.

Related

Katalon counting the conditional statements that goes into else block, into failure

I recently started using the Katalon Studio, for automation. While writing the scripts I checked if an object is present or not on the DOM by using:
if(findTestObject('{Object ID}')){
//do some work
} else{
//do another work
}
if the object is found it's all good, but if it isn't, it continues executing in the else block, but in failure log it shows it as a failure. I've tried implementing some of the solutions to fix it that were on the Katalon discussion page, but none of them worked.
Is there any way to stop counting the else block code into failure?
Recommended way is using Verify Element Present. Try changing your script to:
if(WebUI.verifyElementPresent(findTestObject('{Object ID}'), 5)){
//do some work
} else{
//do another work
}
(in this example, '5' is the timeout you expect to find the element in, lower it if needed).
I believe this happens because findTestObject only returns reference to object in Object Repository but does not guarantee the element is really loaded in DOM.

Cypress: How to capture text from a selector on one page to use as text on another page

New cypress user here, I am aware that cypress does not handle variables like how testcafe and others do due to the asyn nature of it. Using the example given and what I could find I have this as an example:
cy.get('selector').invoke('text').as('text_needed')
cy.get('#text_needed')
const txtneeded = this.text_needed
cy.log(txtneeded)
This looks at a given selector, takes what it finds and uses it as text and set it as a variable usable at any time in the test and outputs it to the log. The plan is to use that text in a search filter in another page to find the item it references.
The problem is that it fails with Cannot read properties of undefined (reading 'text_needed')
Is this because the content of the selector is not assigned to text properly, the outer html is <a data-v-78d50a00="" data-v-3d3629a7="" href="#">PO90944</a> The PO90944 is what I want to capture.
Your help would be appreciated!
You cannot save an alias and access it via this.* in the same execution context (callback) because it's a synchronous operation and your alias is not yet resolved at this time.
This is a correct way to go:
cy.get('selector').invoke('text').as('text_needed')
cy.get('#text_needed').then(txtneeded => {
cy.log(txtneeded)
})
First, make sure to define it as traditional function, not as an arrow function as this context doesn't work as you'd expect there, more info here.
Next, typically in a single test you should use .then() callback to perform additional actions on elements, and use aliases when you need to share context between hooks or different tests, so please consider the following:
// using aliases together with this within the single test won't work
cy.get(<selector>).invoke('text').as('text_needed')
cy.get('#text_needed').should('contain', 'PO90944') // works fine
cy.log(this.text_needed) // undefined
// this will work as expected
cy.get(<selector>).invoke('text').then(($el) => {
cy.wrap($el).should('contain', 'PO90944'); // works fine
cy.log($el) // works fine
});
Setting alias in beforeEach hook for example, would let you access this.text_needed in your tests without problems.
Everything nicely explained here.
Edit based on comments:
it('Some test', function() {
cy.visit('www.example.com');
cy.get('h1').invoke('text').as('someVar');
});
it('Some other test', function() {
cy.visit('www.example.com');
cy.log('I expect "Example Domain" here: ' + this.someVar);
});
And here's the output from cypress runner:

Cypress - How to Wait for an attribute value to be false in Cypress

I have a website which has everything in an iFrame. My scripts are failing because cypress is not able to wait for loading bar as cypress does not support iframes as of now. I want to write a custom command which wait until attributes 'ng-reflect-loading' value is changed to false.
I have tried with below code but its not working and halts cypress runner. Reference Thread 136
cy.get('iframe').iframeLoaded().its('document').getInDocument('.main >ng-component > :nth-child(1)').then(function($loading) {
while( $loading.attr('ng-reflect-loading')!='false')
{
cy.log('waiting')
}
})
Can anyone please help on this.
I don't have any insight of how iFrames work. But is 'ng-reflect-loading' eventually hidden?
In that case this check should work:
cy.get('.ng-reflect-loading')
.should('not.exist')
If it remains existing but the value should change you could either check on the first value not existing:
cy.get('.ng-reflect-loading')
.should('not.contain.attr', 'attr_name', 'first value')
Or if the value changes, you could check for the second value to be available:
cy.get('.ng-reflect-loading')
.should('contain.attr', 'attr_name', 'second value')

Grails filter stops working after

I have a filter set up as follow to control users login status.
class SecurityFilters {
def filters = {
login(controller:'login|logout|proxy|API|error', action:'*', invert: true) {
before = {
if (!session.isLoggedIn){
switch(controllerName){
case "enroll":
switch(actionName){
...
default:
log.warn "Permission Denied. Default action for enroll."
render(view: '/permissionDenied', model: [message: "You must be logged in to access the enroll system. If you are a consumer, please contact your agent for more information."])
break
}
break
...
}
else {
switch(controllerName){
case "agent":
if (!session.user.isAgent) {
render view: "/permissionDenied", model: [message: 'This portion of the site is only available to agents.']
return false
}
break
....
}// switch
}// else
}// before
...
}// login
}// filters
The problem I am having is that when I run this in development it works fine but when I run it on our QA system it works fine for a while and then suddenly it stops working correctly.
I added logging and I can see that the session information is available in the filter and the session variable (session.user.isAgent) is set correctly (true) but the code inside the if(!session.user.isAgent) gets executed regardless.
I can's seem to find the cause for odd behaviour.
My question is has anyone seen this behaviour before and how did they solve it or have any ideas of where to look for probable cause for the sudden change in the way the filter is working.
Thanks in advance.
UPDATE (02/19/2014):
After adding more logging in an effort to hunt down the cause the filter did not execute the code in the if(!session.user.isAgent) as it was doing before. Now it runs normally and then executes only the render line for when the user is not logged in. The logging still show that the user is logged in and that (s)he is an agent but then it runs the render but not the lines of code above it. It is as if there was a "goto" the render line after it completes checking if the agent is logged in.
Again any information or solution would be appreciated
I've had a few issues with filters and Groovy truth. The problem I was seeing was that no errors were logged, even with aggressive exception catching (i.e. catching Throwable) and the only output in the browser was a blank page. This seems to happen only in Filters- everywhere else the errors get logged.
In my case, the issue was down to Groovy truth. I was trying to set a Boolean attribute on the session, but every time I did this it failed. In the end I had to convert the value to a String, and then set it, and it worked.
I know this isn't a direct answer, but I've been bitten a few times by the above and for example, lazy GString evaluation.
If you're still debugging, I'd log some output showing the underlying Class type of what you think you're dealing with. It may be that when your boolean conditions are evaluated above an exception is being thrown and swallowed. I'd log the actual values of each of your conditional statements to see what they are. Also remove each line one by one, to see if the failure goes away. And/or replace your conditionals with absolute values i.e. true/false to see if the code gets executed. If it does, it points to an error in the current conditional evaluation.

Custom matcher not asserting in Astrolabe/Protractor + Jasmine test

I'm writing some page-object driven tests using Protractor and Astrolabe.
Jasmine is being used to implement describe/it style specs.
Adding custom matchers won't work using this.addMatchers (TypeError: Object #<Object> has no method 'toContainLowered'), so I used this guide to implement them.
It seems to be working, until I look closely at the output of my test run:
$> grunt test:func
Running "test:func" (test) task
Running "shell:protractor" (shell) task
Using the selenium server at http://localhost:4444/wd/hub
..
Finished in 6.727 seconds
2 tests, 1 assertion, 0 failures
Here is my code:
var loginPage = require('./../pages/loginPage');
describe('Login page', function () {
var ptor = loginPage.driver;
beforeEach(function () {
jasmine.Matchers.prototype.toContainLowered = function (expected) {
return this.actual.toLowerCase().indexOf(expected) > -1;
};
loginPage.go();
ptor.waitForAngular();
});
it('should display login page', function () {
expect(loginPage.currentUrl).toEqual(ptor.baseUrl);
});
it('should display an error when the username or password is incorrect', function() {
loginPage.login('bad', 'credentials');
ptor.waitForAngular();
expect(loginPage.lblError.getText()).toContainLowered('invalid username and/or password');
// expect(loginPage.lblError.getText()).toContain('Invalid Username and/or Password');
});
});
If I uncomment the last line and remove the toContainLowered matcher, I get the proper output:
2 tests, 2 assertions, 0 failures
I'm having a really difficult time debugging this promise-based code, and any efforts to put a console.log(this.actual.toLowerCase().indexOf(expected) > -1); will print false, which is confusing.
I even tried replacing the entire function definition with just return false;. Which still does not do anything. Finally, I tried passing no argument to the matcher, which should have thrown an Invalid Argument Error or something.
How do I define my own matchers in Jasmine when using Protractor/Astrolabe tests?
I've had similar problems with matchers, in particular with the .not matchers, which all seem to not work. I hypothesise that protractor is extending the Jasmine matchers to deal with the promises, and that that extension hasn't been applied to the .not, or to the custom matchers.
In my case, I wanted a .not.toMatch, and so I just wrote a convoluted regex that gave me what I wanted, with the not embedded in the regex.
I note that your matcher is called "toContainLowered", so perhaps you're looking for lowercase, and therefore you could instead do this with a regex by using .toMatch?
The issue I raised on this on the protractor github is here: https://github.com/angular/protractor/issues/266
I also see, in this code file: https://github.com/angular/protractor/blob/master/jasminewd/spec/adapterSpec.js, that the last commit is marked as "patched matcher should understand not". That might either fix the custom matchers for you, or provide an indication of what needs to be done to fix that custom matcher.
EDIT: now looking further into that issue thread, I see you've already been there. Which makes my answer somewhat superfluous. :-)

Resources