How can I access to each element inside of a grid element with Cypress? - testing

I have a Grid component which includes 24 divs and inside of each div I need to take the value.
This value actually arrives in <p>, so which is the best way to do this?
Below is the app image. I would appreciate an example.

You could probably do something like storing the data in an object or array outside of the Cypress chain. Without a code example, here's my best guess.
cy.get('grid').within(() => { // cy.within() searches only within yielded element
const data = {}; // create data object
cy.get('div').each(($div, index) => { // cy.each() allows us to iterate through yielded elements
data[index] = $div.text() // or possibly some other JQuery command to get the value
// additionally, could go without the index at all and make `data` an array.
}).then(() => {
// whatever needs to be done with `data`, wrapped in `then` to make sure data is populated correctly.
});
});

You can add use each for this to loop through the elements and then do further operations:
cy.get('.chakra-stack')
.find('p')
.each(($ele) => {
cy.log($ele.text().trim()) //Logs all the texts one by one
})

Just add the p selector to your cy.get() command
cy.get('div.chakra-stack p') // access <p> within <div>
.each($el => {
cy.wrap($el).invoke('text')
.then(text => {
...
})
})
To get the value before the text
cy.get('div.chakra-stack p') // access <p> within <div>
.each($el => {
cy.wrap($el)
.prev() // element with value
.invoke('text')
.then(value => {
...
})
})

Accessing values by text label like this
const values = {}
cy.get('div.chakra-stack p')
.each($el => {
const frase = $el.text()
cy.wrap($el).prev().invoke('text')
.then(value => values[frase] = +value)
})
.then(() => {
// values = {'shield': 1, 'session': 2, ...}
})

Related

Always first filtered selected on Quasar Select

I am using Quasar Framework and using the Q-Select with filter.
I would like to the first filtered option always be already marked, because then if I hit enter, the first will selected.
After some research I found out how to achieve this in a generic way.
The second parameter on the function update received at filterFn is the instance of QSelect itself.
Hence, we can use
ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true);
To keep the focus on the first filtered element, regardless of multiselect or not.
The final code is something like
filterFn(val, update) {
update(
() => {
const needle = val.toLocaleLowerCase();
this.selectOptions = this.qSelectOptions.filter(v => v.toLocaleLowerCase().indexOf(needle) > -1);
},
ref => {
ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true);
});
}
There is one option to achieve this is set model value in the filter method if filtered options length is >0.
filterFn (val, update, abort) {
update(() => {
const needle = val.toLowerCase()
this.options = stringOptions.filter(v => v.toLowerCase().indexOf(needle) > -1)
if(this.options.length>0 && this.model!=''){
this.model = this.options[0];
}
})
}
Codepen - https://codepen.io/Pratik__007/pen/QWjYoNo

How can i create multiple editors whit class name

I try to create multiple ckeditors classic.
The problem is that i dont know how many i will have. So i init them by className.
This init the editors and work, but dont send anything trough ajax. So when i try to update the textarea only i can send the last editor because window.editor is overwrite.
I try then to store in an array but i cant pass th for neditor value because its a then so it executes when the for loop is done, so neditor is always 2.
How can i made it work? Idont understand very well promises
Thanks!
import ClassicEditor from './ckeditor5-build-classic';
var allEditors = document.querySelectorAll('.usarCkeditor');//i have 2 editors in that case
for (var neditores = 0; neditores < allEditors.length; neditores++) {
ClassicEditor.create(allEditors[neditores])
.then(editor => {
window.editor = editor;//window.editor is alway the last editor
})
.catch(err => {
console.error(err.stack);
});
}
This is other version :
for (var neditores = 0; neditores < allEditors.length; neditores++) {
window["editor" + neditores] = 'paco';
ClassicEditor.create(document.querySelector('#' + allEditors[neditores].attributes.id.value))
.then(editor => {
console.log(editor);
window["editor" + neditores] = editor;
console.log(neditores);//always 2 so it overwrites the array
})
.catch(err => {
console.error(err.stack);
});
}
//window.editor -> [0] = 'paco';[1] = 'paco';[2]= ckeditor
Please notice that querySelectorAll returns an HTMLNodeList not an Array.
If you want to initialize editor over multiple elements with classes you can do it for example in this way. All references to editors instances will be stored in window.editors object.
window.editors = {};
document.querySelectorAll( '.editor' ).forEach( ( node, index ) => {
ClassicEditor
.create( node, {} )
.then( newEditor => {
window.editors[ index ] = newEditor
} );
} );
This is a working sample: https://codepen.io/msamsel/pen/pXONjB?editors=1010

Store result from api call React native

How can I store the recipe name from this api call into a state variable or some other variable to be used further down in the render
{
this.props.recipeList.recipeList.filter((recipe) => recipe.recipeName === search).map(recipe => {
return <Recipe
name={recipe.recipeName}
numberOfServings={recipe.numberOfServings}
key={'recipe-' + recipe.recipeId}
/>
})
}
As this is performed within render, avoid modifying the component state.
I would recommend declaring a variable at the top of your render method and then assigning it in your map call. This, of course, assumes that filter will only ever return a single result.
Something like:
render() {
let name;
....
{
this.props.recipeList.recipeList.filter((recipe) => recipe.recipeName === search).map(recipe => {
name = recipe.recipeName; // this bit
return <Recipe
name={recipe.recipeName}
numberOfServings={recipe.numberOfServings}
key={'recipe-' + recipe.recipeId}
/>
})
}
....

Apply filter to API response - vue.js

I have this method to get data from an API, which sends me information of many furniture pieces:
loadPieces() {
this.isLoading = true;
axios.get(this.galleryRoute)
.then(r => {
this.gallery = r.data;
this.isLoading = false;
})
.catch(error => {
this.$nextTick(() => this.loadPieces());
});
console.log(this.galleryRoute);
},
This is a part of the response I get, which represents only one piece:
[[{"id":266,"name":" Tray 7x45x32, white stained ash","thumbnail":{"width":840,"height":840,"urls":{"raw":"http:\/\/localhost:8888\/storage\/9c\/9d\/9c9dadc6-15a2-11e8-a80a-5eaddf2d1b4a.jpeg","small":"http:\/\/localhost:8888\/storage\/9c\/9d\/9c9dadc6-15a2-11e8-a80a-5eaddf2d1b4a#140.jpeg","medium":"http:\/\/localhost:8888\/storage\/9c\/9d\/9c9dadc6-15a2-11e8-a80a-5eaddf2d1b4a#420.jpeg"}}},
Now I want to create a filter so that I can get a specific piece from the JSON object, using it's id. I've tried searching but so far I have no idea how to do this.
Thanks in advance!
Add a computed property which applies the filter to this.gallery:
computed: {
filteredGallery() {
if (!this.gallery) return []; // handle gallery being unset in whatever way
return this.gallery.filter(picture =>
// some reason to show picture
);
}
}
I'm assuming gallery is an array, but you could apply a similar technique to it if it was an object, using e.g. Object.keys(this.gallery).
Then in your template, use filteredGallery instead of gallery.

Iterating with v-for on dynamic item

I'm trying to iterate through a db object I fetch during created(), I get the values in a console.log but the v-for template part remains empty. My sub-question is : is this good practice ? I'm quite new to Vue and my searches on this issue make me think it's a lifecycle issue.
Thanks for the help.
TEMPLATE PART :
.content(v-for="(content, key, index) in contents")
h3 {{key}}
.line
| {{getValue(content)}} // this is blank
METHODS PART:
getValue(value) {
PagesService.fetchDataWrap({
id: value
}).then((response) => {
const test = response.data.values[0].value
console.log(test) //this is working and gives the right value
return test
})
},
getPage() {
PagesService.fetchPage({
id: this.$route.params.page
}).then((response) => {
this.name = response.data.result.name
this.langs = response.data.result.langs
this.project = response.data.result.parent
this.contents = response.data.result.values
})
this.getProject()
}
console.log(this.contents) result :
{__ob__: Observer}
footer: "5a29943b719236225dce6191"
header: "5a29a9f080568b2484b31ee1"
which is the values I want to send when v-for iterates on contents so the getValue can process it to fetch corresponding values
I wouldn't recommend attempting to output the value of an asynchronous method. It's highly unlikely that it will work correctly.
Instead, populate your contents array / object fully during the created hook. For example, this can replace the contents hash value with whatever comes back from fetchDataWrap...
getPage () {
PagesService.fetchPage({
id: this.$route.params.page
}).then(response => {
this.name = response.data.result.name
this.langs = response.data.result.langs
this.project = response.data.result.parent
let contents = response.data.result.values
Promise.all(Object.keys(contents).map(key => {
// map each key to a "fetchDataWrap" promise
return PageService.fetchDataWrap({
id: contents[key]
}).then(res => {
// replace the hash with the resolved value
contents[key] = res.data.values[0].value
})
}).then(() => {
// all done, assign the data property
this.contents = contents
})
})
}
Then you can trust that the content has been loaded for rendering
.content(v-for="(content, key, index) in contents")
h3 {{key}}
.line
| {{content}}