How can i compare arrays in Cypress? - cypress

I want to compare data present in an array with the data retrieved from a class using .each in cypress?
Using below code i have tried to iterate over the FileType array using below code.
const Filetype = ['Access', 'Excel', 'Text/CSV','PDF','JSON','dsdsd'];
const te = cy.wrap($bodyFind).find('.data-sourcename').should('have.length',6).each(($li) => { cy.log($li.text()); });
te.each(($text)=> {
cy.log("Te" + $text);
//prints ['Access','Excel','Text/CSV','PDF','JSON','XML'];
});
// Converted FileType Array to Cypress object using cy.wrap command.
const cywrap = cy.wrap(Filetype);
te.each((e1)=>cywrap.each((e2)=> {
if(e1 == e2) {
expect(e1).equals(e2);
}
}));
But the value of e1 and e2 is same.
expect should fail with 'dsdsd' is equals 'XML'
whereas it passes with 'dsdsd' is equals 'dsdsd'

You could use map here.
const filetypes = ['Access', 'Excel', 'Text/CSV','PDF','JSON','dsdsd'];
cy.get('.data-sourcename').should(($els) => {
// map jquery elements to array of their innerText
const elsText = $els.toArray().map(el => el.innerText)
expect(elsText).to.deep.eq(filetypes)
})

I hope by now you must have found out the solution for this. But still, there was no selected answers yet, thought I would add one.
const Filetype = ['Access', 'Excel', 'Text/CSV','PDF','JSON','dsdsd'];
cy
.get('whatever element')
.each(($span, i) => {
expect($span.text()).to.equal(Filetype[i]);
});
$span would go through each element and .text()will get the text value of that element.

Related

variable is not defined in cypress

I am using this code to make random selection. But in the end of this code I want to save the variable to use further in the test-cases. I did so, but I got the error
cy.get('div.cdk-virtual-scroll-content-wrapper nz-option-item') // we get the select/option by finding the select by class
.then(listing => {
const randomNumber = getRandomInt(0, listing.length-1); //generate a rendom number between 0 and length-1. In this case 0,1,2
cy.get('div.cdk-virtual-scroll-content-wrapper nz-option-item').eq(randomNumber).then(($select) => { //choose an option randomly
const text = $select.text() //get the option's text. For ex. "A"
cy.get('div.cdk-virtual-scroll-content-wrapper').contains(text).click() // select the option on UI
let region = text;
cy.wrap(region).as('region')
});
})
cy.log(region)
You can do this in case you want to use the value of the region within the same test (same it block).
cy.get('div.cdk-virtual-scroll-content-wrapper nz-option-item') // we get the select/option by finding the select by class
.then((listing) => {
const randomNumber = getRandomInt(0, listing.length - 1) //generate a rendom number between 0 and length-1. In this case 0,1,2
cy.get('div.cdk-virtual-scroll-content-wrapper nz-option-item')
.eq(randomNumber)
.then(($select) => {
//choose an option randomly
const text = $select.text() //get the option's text. For ex. "A"
cy.get('div.cdk-virtual-scroll-content-wrapper').contains(text).click() // select the option on UI
let region = text
cy.wrap(region).as('region')
})
})
cy.get('#region').then((region) => {
cy.get('selector').type(region)
})
In case if you use the value of text, in different test(different it block) or even different test suite you can do this:
cy.get('div.cdk-virtual-scroll-content-wrapper nz-option-item') // we get the select/option by finding the select by class
.then((listing) => {
const randomNumber = getRandomInt(0, listing.length - 1) //generate a rendom number between 0 and length-1. In this case 0,1,2
cy.get('div.cdk-virtual-scroll-content-wrapper nz-option-item')
.eq(randomNumber)
.then(($select) => {
//choose an option randomly
const text = $select.text() //get the option's text. For ex. "A"
cy.get('div.cdk-virtual-scroll-content-wrapper').contains(text).click() // select the option on UI
let region = text
Cypress.env('region', region)
})
})
cy.get('selector').type(Cypress.env('region'))
Add .then() to your log, and move the declaration of region to the top.
let region;
cy.get('div.cdk-virtual-scroll-content-wrapper nz-option-item')
.then(listing => {
const randomNumber = getRandomInt(0, listing.length-1); //generate a rendom number between 0 and length-1. In this case 0,1,2
cy.get('div.cdk-virtual-scroll-content-wrapper nz-option-item').eq(randomNumber).then(($select) => { //choose an option randomly
const text = $select.text() //get the option's text. For ex. "A"
cy.get('div.cdk-virtual-scroll-content-wrapper').contains(text).click() // select the option on UI
region = text;
cy.wrap(region).as('region')
});
})
cy.then(() => {
cy.log(region)
})

Cypress automation: multiple cy.get elements in one function

I have a function:
checkWebElemAndAssert(...elements) {
for (const element of elements) {
element.should('be.visible').click().should('be.checked');
}
}
and i use it within another function:
checkRegisterValues = () => {
let maleCheckBox = cy.get('input[value=Male]');
let femaleCheckBox = cy.get('input[value=FeMale]');
let cricketCheckBox = cy.get('#checkbox1');
let registerElemList = [maleCheckBox, femaleCheckBox, cricketCheckBox];
this.browserUtils.checkWebElemAndAssert(...registerElemList);
return this;
}
The problem is that when i use checkRegisterValues() it uses for each action the last element: cricketCheckBox. Any hints on what is wrong? i would expect that the action is made for each element and not the last one.
Have you tried passing in the array like this?
this.browserUtils.checkWebElemAndAssert(registerElemList);
You can also print out
checkWebElemAndAssert(...elements) {
console.log(elements);
for (const element of elements) {
element.should('be.visible').click().should('be.checked');
}
}
and see what you are passing in
ok so i read a bit more and made this:
checkWebElemAndAssert2(elements) {
cy.get(elements).each(($list) => {
cy.get($list).click({ multiple: true }).should('be.checked')
})
}
Basically in elements when i call checkWebElemAndAssert2 i will give the list identifier. Seems to work but not sure meets the standard.
checkRegisterValues = () => {
let myList = 'input[type=radio]';
this.browserUtils.checkWebElemAndAssert2(myList);
return this;
}

ckeditor 5 remove an element from the view

I try to delete an element/node from the view.
For now i try to do that:
editor.model.change(writer => {
writer.remove(element)
});
But I need a element or a range to do so.
So my question : How to get an (or an array of) element from a tag ?
(I found that : editor.editable().findOne( 'img' ).remove() here That's for ckeditor4 not 5 but it is exactly what i need)
You can iterate through all elements of the root and then remove the needed one:
let editorModel = editor.model;
let editorDocument = editorModel.document;
editorDocument.on('change:data', (event) => {
let root = editorDocument.getRoot();
let children = root.getChildren();
for(let child of children){
if(child.is('image')) {
editorModel.change(writer => {
writer.remove(child);
});
}
}
});

Updating react-table values after Dragging and Dropping a row in React Redux

I´ve accomplished the react drag and drop functionality into my project so i can reorder a row in a react table´s list. The problem is i have a column named 'Sequence', witch shows me the order of the elements, that i can´t update its values.
Example:
before (the rows are draggable):
Sequence | Name
1 Jack
2 Angel
after ( i need to update the values of Sequence wherea i change their position after dropping a specific draggable row, in this case i dragged Jack at the first position and dropped it at the second position) :
Sequence | Name
1 Angel
2 Jack
React/Redux it´s allowing me to change the index order of this array of elements, without getting the 'A state mutation was detected between dispatches' error message, but is not allowing me to update the Sequence values with a new order values.
This is what i have tried so far:
// within the parent class component
// item is an array of objects from child
UpdateSequence(startIndex, endIndex, item) {
// the state.Data is already an array of object
const result = this.state.Data;
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
// this is working without the mutation state error
this.setState({ Data: result })
let positionDiff = 0;
let direction = null;
let newIndex = 0;
positionDiff = endIndex - startIndex;
if (startIndex > endIndex) {
direction = "up";
}
else if (startIndex < endIndex) {
direction = "down";
}
if (positionDiff !== 0) {
for (var x = 0; x <= Math.abs(positionDiff); x++) {
if (x === 0) {
newIndex = startIndex + positionDiff - x;
this.setState(prevState => ({
Data: {
...prevState.Data,
[prevState.Data[newIndex].Sequence]: Data[newIndex].Sequence + positionDiff
},
}));
}
else {
if (direction === "down") {
newIndex = startIndex + positionDiff - x;
this.setState(prevState => ({
Data: {
...prevState.Data,
[prevState.Data[newIndex].Sequence]: Data[newIndex].Sequence - 1
},
}));
}
else if (direction === "up") {
Data= startIndex + positionDiff + x;
this.setState(prevState => ({
Data: {
...prevState.Data,
[prevState.Data[newIndex].Sequence]: Data[newIndex].Sequence + 1
},
}));
}
}
}
// so when i call save action i am stepping into the 'A state mutation was detected between dispatches' error message.
this.props.actions.saveSequence(this.state.Data)
.then(() => {
this.props.actions.loadData();
})
.catch(error => {
toastr['error'](error, 'error....');
})
}
Calling the action 'saveSequence' whenever i try to update the element of the array, 'Sequence', i am getting the 'A state mutation was detected between dispatches' error message.
Any help will be greatfull! Thank you!
note: The logic applied to reorder the Sequence is ok.
While I don't know redux particularly well, I am noticing that you are directly modifying state, which seems like a likely culprit.
const result = this.state.Data;
const [removed] = result.splice(startIndex, 1);
splice is a destructive method that modifies its input, and its input is a reference to something in this.state.
To demonstrate:
> state = {Data: [1,2,3]}
{ Data: [ 1, 2, 3 ] }
> result = state.Data.splice(0,1)
[ 1 ]
> state
{ Data: [ 2, 3 ] }
Notice that state has been modified. This might be what Redux is detecting, and a general React no-no.
To avoid modifying state, the easy way out is to clone the data you are looking to modify
const result = this.state.Data.slice()
Note that this does a shallow copy, so if Data has non-primitive values, you have to watch out for doing destructive edits on those values too. (Look up deep vs shallow copy if you want to find out more.) However, since you are only reordering things, I believe you're safe.
Well, i figured it out changing this part of code:
//code....
const result = item;
const [removed] = result.splice(startIndex, 1);
// i created a new empty copy of the const 'removed', called 'copy' and update the Sequence property of the array like this below. (this code with the sequence number is just a sample of what i came up to fix it )
let copy;
copy = {
...removed,
Sequence: 1000,
};
result.splice(endIndex, 0, copy);
After i didn´t setState for it, so i commented this line:
// this.setState({ Data: result })
//...code
and the end of it was putting the result to the save action as a parameter , and not the state.
this.props.actions.saveSequence(result)
Works and now i have i fully drag and drop functionality saving the new order sequence into the database with no more 'A state mutation was detected between dispatches' error message!

D3 stack() vs nested objects

I'm running into an issue when trying to implement a normalized stacked bar chart using D3v4.
The problem occurs due to my data format which contains nested object arrays populated dynamically on the server side.
var data = [{x:"data1", y:[{name:"red", value:10}, {name:"green", value:20}]},
{x:"data2", y:[{name:"red", value:30}, {name:"green", value:5}]}];
Calling d3.stack() on this will not work since d3 doesn't know how to traverse into the object array y. (https://jsfiddle.net/xv1qgqjg/)
Is there any way to tell d3.stack() where to find the relevant data similar to the .data(function(d){ return d.y; }) used elsewhere?
It doesn't seem to be possible. According to the documentation regarding stack(data[, arguments…]),
Any additional arguments are arbitrary; they are simply propagated to accessors along with the this object.
Thus, you'll have to change your data, creating an array which you can pass to d3.stack(), such as this:
[{red:10,green:20},
{red:30,green:5}]
Given the data array in your question, there are several ways for creating the above-mentioned array. Here is my solution (the new array is called newData):
newData = [];
data.forEach(d => {
var tempObj = {}
d.y.forEach(e => {
tempObj[e.name] = e.value;
})
newData.push(tempObj);
});
Here is a demo:
var data = [{x:"data1", y:[{name:"red", value:10}, {name:"green", value:20}]},
{x:"data2", y:[{name:"red", value:30}, {name:"green", value:5}]}];
newData = [];
data.forEach(d => {
var tempObj = {}
d.y.forEach(e => {
tempObj[e.name] = e.value;
})
newData.push(tempObj);
});
var stack = d3.stack()
.keys(["red", "green"])
.order(d3.stackOrderNone)
.offset(d3.stackOffsetExpand);
var series = stack(newData);
console.dir(series);
<script src="https://d3js.org/d3.v4.min.js"></script>

Resources