Pre-filtering in a Kendo grid - kendo-ui

I am trying to pre-filter a kendo grid, and I have a problem.
For pre-sorting and pre-grouping I am using first 2 lines, that work great:
grid.DataSource(ds =>
{
var ajaxDsBuilder = ds.Ajax();
// ...
ajaxDsBuilder.Sort(sort => sort.Add(col.Name).Ascending());
ajaxDsBuilder.Group(grp => grp.Add(col.Name, typeof(string)));
// problem at the next line with filter
ajaxDsBuilder.Filter(f=> f.Add(c=>col.Name.ToString()).IsEqualTo("something"));
which is giving me a server error after running.
For pre-filtering I found this :
.Filter(filter => filter.Add(/* your filter rule */))
If I remove the ToString() I get the error: Property with specified name: col.Name cannot be found on type: System.Data.DataRowView
If I try:
ajaxDsBuilder.Filter(f=> f.Add(c=> c.col.Name).IsEqualTo("something"));
I get the error:
An expression tree may not contain a dynamic operation
I have also tried to use dynamic lambda but the same problems appear ...
What am I missing?
P.S. I am new to all this, so any help will be highly appreciated.

I answered the same question on Telerik forum and I got my answer:
.Filter(filter => filter.AddRange(new [] {
new Kendo.Mvc.FilterDescriptor(col.Name, Kendo.Mvc.FilterOperator.IsEqualTo, "TEST") })
In case someone needs this :)

Related

Cypress - verify if each table row in one column contains the same item and ignoring header

I have a filtered table, a grid table created by DIVs, so no real table elements, that I want to confirm that my filter has worked in but the ways I have tried keep trying to also check the header which is then telling me that my results are wrong
cy.get('div[data-field="name"]')
.then($col => {
const count = $col.length
.wrap($col)
.should('have.text', 'Bob'.repeat(count))
})
I have 3 bobs in my example, but it is also viewing the header so I am getting an error telling me that it is trying to find 3 instances of Bob but also finds Name, so finds 4.
If I try
cy.get('div[data-field="name"]')
.each($col => {
expect($col.text()).to.eq('Bob')
})
It fails as it tells me the first entry is 'Name' as it is finding the header and I am not sure how to avoid it counting/reading the header.
I'm sure its something simple that I am missing and not thinking of but any help is appreciated!
NOTE: I got both these ways of checking from this other stack answer Cypress - verify if each table row in one column contains the same item
There are probably many ways to solve this, here are a couple.
For the first sample, take one off the count (since there is only one header)
cy.get('div[data-field="name"]')
.then($col => {
const count = $col.length
.wrap($col)
.should('have.text', 'Bob'.repeat(count-1))
})
For the second sample, don't look at the first element
cy.get('div[data-field="name"]')
.each(($col, index) => {
if (index > 0) {
expect($col.text()).to.eq('Bob')
}
})

How can I get my cypress custom command to ingest this data (i think i structured the data wrong)?

Alright, as the title says- i'm trying to write a custom command for a cypress test suite. The situation as as follows: I have several tests that need to select an indeterminate number of fields and select an option from the each fields list of drop downs.
The logic for this is crayons-in-mouth simple and works fine:
cy.get(selector)
.select(selection)
.scrollIntoView()
and this works great. But because I use it a lot it's a lot of highly repetitive code so I'm trying to create a custom command where I can just inject an array of arrays (various sets of selectors and selections depending on the situation) into it and it'll do the rest.
This is the custom command as I have it written now.
commands.js
Cypress.Commands.add("assignImportFields", (array) => {
cy.wrap(array).each((selector, selection) => {
cy.get(selector)
.select(selection)
.scrollIntoView()
cy.log('using ' + selector + ' to select ' + selection)
})
})
I have the data in a seperate file that looks like this:
data.js
const importFields = {
actorListImports : [
[selectors.lastName, 'Last_Name'],
[selectors.firstName, 'First_Name'],
[selectors.phoneNum, 'Phone_Number']
]
}
exports.importFields = importFields;
and finally, in my test file:
tests.js
const {actorListImports} = data.importFields;
cy.assignImportFields(actorListImports)
The response I get from this is that the 'select' failed because it requires a dom element. My selectors are fine, so I think it's trying to use an entire array (both selector and selection at once) as the selector instead of the first part of the array.
I know i'm not structuring the data correctly, but i've tried a few different variations of it and my primitive monkey brain just can't put together.
Can someone help me identify what's wrong with how i've structure this?
You need to de-structure the array elements in the .each() parameter list, like this cy.wrap(data).each(([selector, selection])
This is a minimal example:
const selectors = {
'lastName': 'lastName'
}
const data = [
[selectors.lastName, 'Last_Name'],
// [selectors.firstName, 'First_Name'],
// [selectors.phoneNum, 'Phone_Number']
]
cy.wrap(data).each(([selector, selection]) => {
console.log(selector, selection)
expect(selector).to.eq('lastName') // passing
expect(selection).to.eq('Last_Name') // passing
})

How to get a value from a datatable using cypress?

I want to get the 'Created On Date' from the datatable to find out which timezone it falls into?
I was searching for a particular campaign using filter. But I am not sure how to extract a text from the datatable.
cy.get('input[placeholder="Filter..."]:nth(2)').type("campaign1");
cy.get("tbody")
.contains("campaign1")
.closest("tr")
.should("contain.text", this.Advertiser)
.should("contain.text", this.Brand)
.then(text => {
const rowText = text;
});
}
But I got this response from Cypress
CypressError: Timed out retrying: expected '<tr.MuiTableRow-root>' to contain text undefined, but the text was 'Advertiser UKBrand UKcampaign14 Nov 2019'
How do I extract just the date from the datable?
You are on the correct way, but you're not searching deep enough. This should help:
cy.get('input[placeholder="Filter..."]:nth(2)').type("campaign1");
cy.get("tbody")
.contains("campaign1")
.closest("tr")
.should("contain.text", this.Advertiser)
.should("contain.text", this.Brand)
.find("td")
.eq(5)
.then(text => {
const rowText = text;
});
You did find the correct row, but not the correct cell. By adding the find("td") it does search for the cells. And the .eq(5) actually selects the 5th occurence of the td, which is the cell for the Created On column
What I can understand from your question is you just want to grab the date values and make an assertion on that.
Assumption Made: With filter applied you always get results and you want to write tests only for the cell with date.
This might help you:
function getTextOfCell(rowIndex){
cy
.get('tbody.MultiTableBody-root')
.get('tr.MultiTableRow-root')
.eq(rowIndex)
.find('td').eq(3).invoke('text').then((txt)=>{
cy.log(txt)
})
}
describe('Test Test', ()=>{
it('Test Test', ()=>{
cy.visit('yourURl')
cy.get('tbody.MultiTableBody-root tr.MultiTableRow-root').its('length').then((rowLength)=>{
for(let i=0; i<rowLength; i++){
getTextOfCell(i)
}
});
})
})
Note:
I am assuming that sometimes you will have more than one row as
result. So iterating over all the available rows.
And the date cell will have always have the index 3 for any
row.
In function getTextOfCell we are grabbing the text of the cell
and saving it in txt. Here I am logging out only. You can
make your assertion here.
The problem is that this.Advertiser is undefined when the should function is called. You didn't provide the piece of code where this member is initialed, but I guess that it's initialed inside a then or it's a property. Anyway, like most Cypress methods, when should is called, it doesn't actually performs the validation, but only queues a command that will be executed later to perform the validation. This means that when should is called, this.Advertiser is still undefined and this gets passed as an argument to theshould function, even though when the should command is executed later on, this.Advertiser has a valid value.
The solution should be, instead of using this.Advertiser, put the entire code block that appears in your question, inside the then block where the value in which this.Advertiser is initialized, and use the parameter passed to this then block instead. It should look something like this:
cy.somethingThatProvidesAdvertiser().then(advertiser => {
cy.get('input[placeholder="Filter..."]:nth(2)').type("campaign1");
cy.get("tbody")
.contains("campaign1")
.closest("tr")
.should("contain.text", advertiser)
.should("contain.text", this.Brand)
.find("td")
.eq(5)
.then(text => {
const rowText = text;
});
});
I guess that you should do the same for this.Brand, which means that you should have the 2 then clauses nested.
I hope I managed to explain it clear enough...
Thanks All for the responses. The below code helped me to fetch the desired value from the datatable.
const txt = [];
cy.get("tbody")
.contains("campaign1")
.parent()
.next("td")
.invoke("text")
.then(x => {
txt.push(x);
});
cy.log((this.txt = txt));
I'd suggest that you assign a cypress-dedicated id on a row/a column to easily extract data and tests are more maintainable.
<tr data-cy='campaign-${id}' ...>
<td data-cy='created-on'>
....
<td>
</tr>
For any given campaign, you can get its text with ease and code is readable.
cy.get('[data-cy=campain-3]').find('[data-cy=created-on]').invoke('text')

How to update item conditionally with branch in RethinkDB

I am trying to do simple upsert to the array field based on branch condition. However branch does not accept a reql expression as argument and I get error Expected type SELECTION but found DATUM.
This is probably some obvious thing I've missed, however I can't find any working example anywhere.
Sample source:
var userId = 'userId';
var itemId = 'itemId';
r.db('db').table('items').get(itemId).do(function(item) {
return item('elements').default([]).contains(function (element) {
return element('userId').eq(userId);
}).branch(
r.expr("Element already exist"),
//Error: Expected type SELECTION but found DATUM
item.update({
elements: item('elements').default([]).append({
userId: 'userId'
})
})
)
})
The problem here is that item is a datum, not a selection. This happens because you used r.do. The variable doesn't retain information about where the object originally came from.
A solution that might seem to work would be to write a new r.db('db').table('items').get(itemId) expression. The problem with that option is the behavior isn't atomic -- two different queries might append the same element to the 'elements' array. Instead you should write your query in the form r.db('db').table('items').get(itemId).update(function(item) { return <something>;) so that the update gets applied atomically.

Finding documents containing at least one embedded object missing a given field

Is there an efficient way to find all documents of a Mongo collection that have at least one embedded object missing a given field?
I'm trying:
Response.where('answers.question_id' => nil)
However, this only returns Responses for which every answer is missing a question_id, rather than responses that contain at least one answer missing a question_id.
I could loop through the Responses testing each, but this is horrendously slow for the size of the database I'm working with, so I'm keen to find a way to construct a query to narrow the response list.
EDIT:
Response.where(:'answers.question_id'.exists => false)
Still does not solve my problem - it still only finds responses for which all embedded answers are missing question_id, not responses for which any embedded answers are missing question_id.
Have you tried either of the following?
Response.where(:answers => { "$elemMatch" => { :"answer_id".exists => false }})
Response.where(:answers.elem_match => { :answer_id.exists => false})

Resources