Cypress, how to check property exists - testing

I'm new to cypress and am trying a couple of different methods to get a checkbox property...
checkBox().should('have.prop', 'checked')
checkBox().its('checked').should('exist')
The first line works fine but I was expecting the second to also pass but I get a "expected Undefined to exist" response.
Thanks

Assuming checkBox() function returns cy.get('.checkbox'), I think
checkBox().its('checked').should('exist')
fails because checkBox() does not return an object containing just the attributes. It returns the whole element (I think as an array). so you can't use its('checked') directly on checkbox().
Anyways, to do what you are expecting to do, you can use several methods,
using invoke('attr', 'checked')
checkBox().invoke('attr', 'checked')
.should('exist')
using getAttribute js function and expect chai assertion
checkBox().then($el => {
expect($el[0].getAttribute('checked')).to.exist;
})
using attributes in js and (its, wrap) in cypress.
Note: As mentioned earlier, you can't directly use its on the cy.get(). You need to extract the attributes from the object and use cy.wrap()
checkBox().then($el => {
cy.wrap($el[0].attributes)
.its('checked')
.should('exist')
})
you can use any of those methods, but the one I recommend is your first method.
cheers. Hope it helps.

Related

Cypress Get Attribute value and store in Variable

I want to get the Attribute value and store in a variable how we can achieve this in cypress
In my case I want to get the complete class value and store it in variable.
This code just give me the attribute class value but how I can store the fetch value in variable
cy.get('div[class*="ui-growl-item-container ui-state-highlight ui-corner-all ui-shadow ui-growl-message"]').invoke('attr', 'class')
I was trying to compare the style of one element with another to make sure they were equal. Here's the code that seems to work for me.
cy.get('.searchable-group-selector-card-image')
.eq(4)
.invoke('attr', 'style')
.then(($style1) => {
const style1 = $style1
})
A good way to solve this kind of scenario is to use the alias mechanism. One could leverage this functionality to enqueue multiple elements and then check all of them together by chaining the results. I've recently come to a case in an SPA where the assertion had to happen between elements that were spread across different angular routes (call them different pages).
In your use case, this would like:
cy.get('.searchable-group-selector-card-image')
.eq(4)
.invoke('attr', 'style')
.as('style_1')
cy.get('.another-element')
.invoke('attr', 'style')
.as('style_2')
// later on for example you could do
cy.get('#style_1').then(style_1 => {
cy.get('#style_2').then(style_2 => {
// Both values are available and any kind of assertion can be performed
expect(style_1).to.include(style_2)
});
});
This is described in Variables and Aliases section of the Cypress Documentation.
Here is how I got the value of for attribute in a label tag which had text "Eat" inside.
cy.contains('Eat').then(($label) => {
const id = $label.attr('for');
}
Most important thing is to get the selector right, so it exactly finds the value you are looking for. In this case you already found it. By using then() gives you the ability to store it in a variable.
cy.get('div[class*="ui-growl-item-container ui-state-highlight ui-corner-all ui-shadow ui-growl-message"]').invoke('attr', 'class')
.then($growl-message => {
const message = $growl-message.text()
//do the checks with the variable message. For example:
cy.contains(message)
})
Note that the scope of the variable is within the curly brackets. Thus using the variable has to be within those curly brackets.

dragAndDrop using webdriverio

I have tried every single thing to perform dragAndDrop using webdriverio but nothing works. I have also posted a question in the webdriverio gitter but no response. below posted code is one of the ways I tried and its supposed to work but it just doesn't!
` await this.driver.moveToObject(source);
await sleep(2000);
await this.driver.buttonDown(0);
await sleep(2000);
await this.driver.moveToObject(destination);
await sleep(2000);
await this.driver.buttonUp(0);`
I'm not sure what properties are on the source and destination objects you are using but here is an example of how I was able to get it to work using the same commands you are trying.
In my example I have a table with columns that can be re-ordered by dragging and dropping them wherever I want them to be. First I get the two column headers I want to switch
let docIdHeader = browser.element('div[colid="documentid1"]');
let pageCountHeader = browser.element('div[colid="_PAGE_COUNT1"]');
If I log these objects out to the console I can see the properties stored in them.
> docIdHeader
{ sessionId: 'e35ae3e81f1bcf95bbc09f120bfb36ae',
value:
{ ELEMENT: '0.3568346822568915-1',
'element-6066-11e4-a52e-4f735466cecf': '0.3568346822568915-1' },
selector: 'div[colid="documentid1"]',
_status: 0 }
> pageCountHeader
{ sessionId: 'e35ae3e81f1bcf95bbc09f120bfb36ae',
value:
{ ELEMENT: '0.3568346822568915-2',
'element-6066-11e4-a52e-4f735466cecf': '0.3568346822568915-2' },
selector: 'div[colid="_PAGE_COUNT1"]',
_status: 0 }
Now using the same technique you are using and the selector property off of these objects I can get it to work in two ways.
browser.dragAndDrop(docIdHeader.selector, pageCountHeader.selector);
Or
browser.moveToObject(docIdHeader.selector)
browser.buttonDown(0)
browser.moveToObject(pageCountHeader.selector)
browser.buttonUp(0)
I ran this in the REPL interface so I know it works as I could see each step being executed after I sent the commands. If you are not familiar with how to use the REPL I highly recommend learning. You can play around with commands in the console until you figure something out and then add those commands to your tests.
Also, as I stated in my comments above. dragAndDrop() and moveToObject() are going to be deprecated soon and you will likely see a lot of warnings about it when you use these. The correct way to implement a drag and drop action going forward is to use browser.actions(). Unfortunately, I don't have an example of how to do it that way as I haven't played with it yet. If no one provides an example by tonight I will try to get one together for you.
Even I faced this issue wherein the cursor doesn't move to the destination object after buttonDown and using moveToObject twice worked for me.
await this.driver.moveToObject(source);
await this.driver.buttonDown(0);
await this.driver.moveToObject(destination);
await this.driver.moveToObject(destination);
await this.driver.buttonUp(0);

Protractor/Webdriver Accessing DOM elements properties

I'm writting e2e tests for a Angular/Polymer app (thus using web-components). Is it possible to have access to DOM properties as in :
$0.selectedItem?
I tried using :
elem = browser.executeScript('return document.querySelector("my-scrollList")');
and then calling
elem .then(function (el){
console.log(el.selectedItem);
});
But it doesn't work.
However, if I call the property directly from the executeScript command like so it works but it is very tedious :
elem = browser.executeScript('return document.querySelector("my-scrollList").selectedItem');
Is there a way to access DOM properties through WebElements or Protractor API ?
Thanks in advance.
With a CSS selector by selecting the selected attribute among the <option>:
$("my-scrollList").$("option[selected]")
or :
$("my-scrollList option[selected]")
Probably you want to calls to $ by chained to find element within a parent. Take a look at Protractor API .
Your code, probably, should look like this one:
elem.then(function (el){
console.log(el.$('selectedItem'));
});

Iterating elements using NightWatchJS

How do i click a button returned by elements command in night watch
client.elements('xpath', ".//a[#class='abcd')]", function (allButtons){
console.log('Element value is '+element)
allButtons.value.forEach(function (element) {
this.elementIdClick(element, function(res){});
}
}
While running i am getting an error as
Element value is [object Object]
TypeError: Object #<Object> has no method 'elementIdClick'
So how do i get each element from the element list returned by client.elements
I realized the parameters for elementIdClick is wrong, i updated the code as
client.elements('xpath', ".//a[#class='abcd')]", function (allButtons){
allButtons.value.forEach(function (element) {
console.log('Element value is '+element)
this.elementIdClick(this.elementIdAttribute(allButtons.value[element].ELEMENT, 'id'), function(res){});
Now the error is
Element value is [object Object]
TypeError: Cannot read property 'ELEMENT' of undefined
So again back to original question. How do i get individual elements from a list of webelements using nightwatchJS
The following worked for me:
function iter(elems) {
elems.value.forEach(function(element) {
client.elementIdClick(element.ELEMENT)
})
};
client.elements('css selector', 'button.my-button.to-iterate', iter);
Each element is a JSON object of the form { ELEMENT: string } (so, has no method itself.)
this in forEach does not point to the element, nor client: you need to invoke client.elementIdClick() or will get a TypeError.
Hope it helps.
I used the following strategy to iterate over DOM elements using Nightwatch:
// Executing a function in the application context.
client.execute(function () {
// Get elements by CSS selector.
var elements = document.querySelectorAll('.elements');
// Iterate over them.
[].forEach.call(elements, function (element) {
// Manipulate each element.
element.click();
});
});
That snippet is inside a test of course.
If you use jQuery or something similar you can use that too.
I think the error is getting generated by your console.log() statement.
From the elements() command, allButtons.value will be an array of several objects. To access key pairs in that array, you need need to specify where in the array and then reference the object: allButtons.value[index].ELEMENT
Because you gave your .forEach() loop only one arg, it's interpreting that as the index for the array, and in my code sample below I replaced your local variable element with index for clarity. There is also no need to use the .elementIdAttribute() function; the number returned by allButtons.value[0].ELEMENT will work as the id.
client.elements('xpath', ".//a[#class='abcd')]", function (allButtons){
allButtons.value.forEach(function (index) {
console.log('Element value is '+index.ELEMENT)
client.elementIdClick(index.ELEMENT);}})
Hope that helps.

KoLite asyncCommand accessing element data

So I'm displaying a observable array in my view, and I want to be able to remove an element from that list using asyncCommand. However, I'm not sure how I should be getting that element. Is there a way of accessing or passing the selected element into the asyncCommand method?
Thanks for the input
addGroupCmd = ko.asyncCommand({
execute: function (data, complete) {
//access your observable here with the data object
//EX. var demo = data.id();
},
canExecute: function (isExecuting) {
return !isExecuting && isEditing();
}
}),
Ok, so I figured it out with it little bit of google's help. All you have to do is pass in the data parameter and ko.lite will figure out what object your talking about. pretty nice, not really sure how it works, but it does.