Cypress index position to came before a specific string - position

I need to check a string on a Thead to come before a specific string.
User need to be before Primium like in the e.g
Here is the code I am using
it('test', () => {
cy.visit('url')
cy.wait('#geturl')
.its('response.statusCode')
.should('be.oneOf', [200, 201])
cy.url().should('include', 'url')
cy.get('h1').should('contain', 'url List')
cy.get('thead').find(`th:contains('User')`).invoke('index').as('userIndex')
cy.get('thead')
.find(`th:contains('Premium')`)
.invoke('index')
.as('premiumUndex')
cy.get('#userIndex').then((userIndex) => {
cy.get('#premiumUndex').then((premiumUndex) => {
expect(userIndex).to.be.lessThan(premiumUndex)
})
})
})
It is working, but I need to check the User column is before Premium column and after Agent column Is there a better way to do it?

Check three column headers using .slice() to get just the columns you want.
Then map elements to the text. Use .trim() if there is whitespace around it.
cy.get('thead th')
.invoke('slice', 4, 7)
.then($th => [...$th].map(th => th.innerText.trim()))
.should('deep.eq', ['Agent', 'User', 'Premium'])

The easiest way I can see is to take all the header texts as one long string and check that "AgentUserPremium" is in it.
In case there are whitespace characters like " " or "\n", add a filter to remove these.
cy.get('thead th')
.invoke('text')
.then(text => text.replace(/\s/g, ''))
.should('contain', 'AgentUserPremium')

If you are checking for headers as part of a test, the a stronger test would be to set the headers as a static variable within your test and then use .each() to check each header in the table.
const headers = [
"",
"Number",
"Code",
"Client",
"Agent",
"User",
"Premium",
"Status",
"Time",
"",
];
cy.get("th")
.should("have.length", headers.length)
.each((header, index) => {
expect(header).to.have.text(headers[index]);
});
Here is a working example based on the screenshot.

Related

SUBSTITUTE based on a table of replacement strings

I have a list of business names and addresses in A, and shortened versions of just the business names with an added store # shown in B,
I would like to be able to paste a set of data into column D and have the file automatically find and substitute based on the info in the table, and output to column E.
The total number of potential substitutions is >200, so a nested SUBSTITUTE function would very quickly get too messy.
The sheet must handle multiples of the same entries in column D. i.e. The same business can appear multiple times in the raw data, and I want each entry to be subbed.
A4 and A5 represent the same location for my purposes, so the output needs to be the same between them.
A9 include a comma after "Sobeys", so the data formatting is not reliable enough to find the first comma and erase everything after.
This is currently being handled in Google Sheets, but if a more accessible solution exists in Excel I'd be willing to work there just for the substitutions. I've seen similar questions answered using QUERY or ARRAYFORMULA, but I'm out of my depth to try and adjust those answers to suit my needs here. Thank you!
To replace a big amount of data, try this (you have to enable the service Google Sheets API )
function replacements() {
const ar = [
{ text: "Example 1", newText: 'text1' },
{ text: "Example 2", newText: 'text2' },
{ text: "Example 3", newText: 'text3' },
];
const requests = ar.map(({ text, newText }) => ({ findReplace: { allSheets: true, find: text, replacement: newText, matchEntireCell: true, matchCase: true } }));
Sheets.Spreadsheets.batchUpdate({ requests }, SpreadsheetApp.getActive().getId());
}
You can construct the ar matrix based on your sheet in a separate spreadsheet (otherwise your table will also update). For instance
function replacements() {
var ar = []
var data = SpreadsheetApp.openById('id of the spreadsheet that contains the table').getSheets()[0].getDataRange().getValues()
data.forEach(function(r) {
var prov = {}
prov['text']=r[0]
prov['newText']=r[1]
ar.push(prov)
})
const requests = ar.map(({ text, newText }) => ({ findReplace: { allSheets: true, find: text, replacement: newText, matchEntireCell: true, matchCase: true } }));
Sheets.Spreadsheets.batchUpdate({ requests }, SpreadsheetApp.getActive().getId());
}

How to get all results that contain a certain string (explained more in post)

So, let's say I put "h" in a post form and I have 5 things in my data base:
1st Entry - Name: Hello
2nd Entry - Name: Height
3rd, 4th, 5th entries do not have a word that has "h" in them
How would I make it return all of the ones that include the string provided (like Hello and Height)
Here is my current setup:
app.post('/search/full', async (req, res) =>{
const URLs = await shortURL.find({
"short": {
"$regex": req.body.fullURLSearch,
"$options": "i"
}
})
res.render('searchFull', {
fullURLsearch: URLs
})
})
If you want case insensitive query, you can do this (if you want case sensitive query, just remove "$options": "i"):
db.collection.find({
"field": {
"$regex": "YourQueryString",
"$options": "i"
}
})
Here is the working snippet: https://mongoplayground.net/p/F6oSaf8P7lb
You don't really give much to go on, but based on your question I can assume something like this might work:
db.collection.find({field:/H/}})
naturally replace the H with a variable as required

How to update a key of object with value in json column with knexjs?

I'm trying to update a column in users table the column type is json.
column name is test.
and the column consists of an object default value for example is
{a: "text", b: 0}
how to update let's say the object key b without changing the whole column
the code i'm using is
knexDb('users').where({
email: email
})
.update({
test: { b: 1 }
})
second solution
knexDb('users').where({
email: email
})
.update({
test: knexDb.raw(`jsonb_set(??, '{b}', ?)`, ['test', 1])
})
first solution changes the whole column cell and test will be only { b: 1 }
second solution doesn't work it give an error
function jsonb_set(json, unknown, unknown) does not exist
The expected result
is to manage to update only a certain key value in an object without changing the whole object.
PS
I also want to update an array that consists of objects like the above one for example.
[{a: "text", b: 0}, {c: "another-text", d: 0}]
if i use the code above in kenxjs it'll update the whole array to only {b: 1}
PS after searching a lot found that in order to make it work i need to set column type to jsonb, in order the above jsonb_set() to work
but now i'm facing another issue
how to update multiple keys using jsonb_set
knexDb('users').where({
email: email
})
.update({
test: knexDb.raw(`jsonb_set(??, '{b}', ?)`, ['test', 1]),
test: knexDb.raw(`jsonb_set(??, '{a}', ?)`, ['test', "another-text"]),
})
the first query key b is now not updating, in fact all updates don't work except the last query key a, so can some explain why ?
Your issue is that you're overwriting test. What you're passing into update is a JS object (docs). You cannot have multiple keys with identical values (docs). You'll have to do something like this where you make 1 long string with all your raw SQL as the value to test.
knexDb('users').where({
email: email
})
.update({
test: knexDb.raw(`
jsonb_set(??, '{a}', ?)
jsonb_set(??, '{b}', ?)
`,
['test', "another-text", 'test', 1])
})
Probably a better option exists - one that would be much more readable if you have to do this for several columns is something like what I have included below. In this example, the column containing the jsonb is called json.
const updateUser = async (email, a, b) => {
const user = await knexDb('users')
.where({ email })
.first();
user.json.a = a;
user.json.b = b;
const updatedUser = await knexDb('users')
.where({ email })
.update(user)
.returning('*');
return updatedUser;
}
Update/insert a single field in a JSON column:
knex('table')
.update( {
your_json_col: knex.jsonSet('your_json_col','$.field', 'new value')
})
.where(...)
Update/insert multiple fields
Option 1 (nested)
knex('table')
.update( {
your_json_col: knex.jsonSet(knex.jsonSet('your_json_col','$.field1', 'val1')
'$.field2', 'val2')
})
.where(...)
Option 2 (chained)
knex('table')
.update( {
your_json_col: knex.jsonSet('your_json_col','$.field1', 'val1')
})
.update( {
your_json_col: knex.jsonSet('your_json_col','$.field2', 'val2')
})
.where(...)

React-Bootstrap-Table-Next Only One Row of Data in Table

I am trying to create a table for my website and for some reason it is only showing the first row of data.
This is how I am formatting the columns of the data:
const { items } = this.props.item;
// console.log({ items });
// react - bootstrap - table - next
const columns = [{
dataField: 'team',
text: 'Team',
sort: true,
formatter: (cellContent, row, rowIndex) => (
Object.values(row.team)[rowIndex]
)
}, {
dataField: 'current_Rank',
text: 'Current Rank',
sort: true,
formatter: (cellContent, row, rowIndex) => (
Object.values(row.current_Rank)[rowIndex]
)
}, {
dataField: 'new_Rank',
text: '321 Rank',
sort: true,
formatter: (cellContent, row, rowIndex) => (
Object.values(row.new_Rank)[rowIndex]
)
}];
This is how I am returning the table so that it renders the table:
return (
<BootstrapTable
keyField="team"
data={items}
columns={columns}
striped
hover />
)
}
}
The data:
Picture from the console
Live site: https://nhl-321-pointsystem.herokuapp.com/
I looked up your network response for /api/items API call, and found out that the data contains only one item. This being one of the reason you're seeing a single row when the table is rendered.
Please note the, another reason for the issue is, react-bootstrap-table-next key
data accepts a single Array object. And not array of single object.
You should re-arrange your data so that key 'team' will be present for all items in the array. And rest of the column header values (e.g. current_Rank) are available for each like.
Something like a reformat function I created in the sandbox available here.
Plus point - After you apply the reformat function, you won't need formatter for each column unlike your previous solution.
Alternate but recommended solution would be to send the formatted response from the API endpoint only, instead of re-parsing and creating new object to fit the needs of UI.
Sandbox link - https://codesandbox.io/embed/32vl4x4oj6

How to match the two strings with and without including spaces

For example: In DB I've the string value like "cell phones". If I get the string value like "cellphones" from frontend. How can I compare it with DB string and get the related string values in response.
You can compare so:
let val1 = 'cell phones';
let val2 = 'cellphones';
console.log(val1.replace(/\s/g, '') === val2.replace(/\s/g, '')) // true
//OR
console.log(val1.split(' ').join('') === val2.split(' ').join('')) // true
If you need some aggregation trick then you can try this
db.collection.aggregate([
{ "$project": {
"name": {
"$reduce": {
"input": { "$split": ["$name", " "] },
"initialValue": "",
"in": { "$concat": ["$$value", "$$this"] }
}
}
}},
{ "$match": { "name": "cellphones" }}
])
You can test it
Here
You can first start by stripping out the spaces on both the strings before comparing them, for example:
let a = "cell phone";
let b = "cellphone";
let c = "cell phones"
const stripSpaces = s => s.replace(/\s/g, '');
// compare
console.log(stripSpaces(a) == stripSpaces(b)); // true
console.log(stripSpaces(a) == stripSpaces(c)); // false
Just remove those spaces from the response you are getting after query find then pass the response to require input field. Then match that string with front-end or input string. If both matches load the required content.
Suppose the collection name is Category. Then the sample query will be like this
Category.find().exec((err, categories) => {
var details=[]
var matchCategory=[]
categories.map((category,key)=>{
var obj ={}
obj.name = category.name.toLowerCase().replace(/\s/g, "")
details.push(obj);
})
if(details.length > 0){
var detailsLength=details.length
details.map((category,key)=>{
if(category.name=="cellphones"){ // match your input string
matchCategory.push(category)
}
detailsLength--
})
if(detailsLength==0){
resolve(matchCategory);
}
}
})
This may help you to reach out.
Answers below this question are good, like using where and Regex, but might be at their best if you got a small number of docs that you may want to query from.
If you got many docs, I'd suggest you:
1. Use an extra field like cellphone without any space, if the values of the original field are expected to be short.
2. Try using search engines, like ElasticSearch, or MongoDB's own text search, to find what you need, not only cell phone to cellphone, but mobile phone even smartphone. Actually, when you google something, the suggestions while you're typing are also coming from similar but more complex algorithms.
Given a document like this:
{
"text" : "cell phones"
}
You could use the $where operator like this:
db.collection.find({
$where: function() {
return this.text.replace(' ', '') == "cellphones"
}
});
I wouldn't necessarily recommend this for big collections (performance might not be great). However, even with big collections you could supposedly achieve some pretty ok performance by adding an extra filter on the "text" field to filter out all documents that don't start with the correct first character(s):
db.collection.find({
"text": { $regex: "^" + "cellphones".charAt(0) }, // this will use an index on the "text" field if available
$where: function() {
return this.text.replace(' ', '') == "cellphones"
}
});
Or perhaps even this version with yet another filter in the $where bit that checks the string lengths for a reduced number of string comparisons:
db.collection.find({
"text": { $regex: "^" + "cellphones".charAt(0) }, // this will use an index on the "text" field if available
$where: function() {
return this.text.length >= "cellphones".length // performance shortcut
&& this.text.replace(' ', '') == "cellphones"
}
});
You can first start by stripping out the spaces on both the strings before comparing them. I'm assuming you don't know which one has spaces before hand, so you will run all the values through the stripSpaces function, for example:
let a = "cell phone";
let b = "cellphone";
let c = "cell phones"
const stripSpaces = (s) => s.split(' ').join('');
// compare
console.log(stripSpaces(a) == stripSpaces(b)); // true
console.log(stripSpaces(a) == stripSpaces(c)); // false
try replacing empty string from query string first, and then compare to the field as
db.test.find(function() {
return this.data(function(elm) {
"cell phones".replace(/ /g,"") == elm.name
});
});
May be it solves Your problem
Take Device_Names column contains
"cell phone"
"mobile phone"
"cellphone"
"laptop"
1.) Normal way:
select Device_Name from devices where Device_Name='cellphone' ;
result:
"cellphone"
which is third one
2.)By Remove spaces:
SELECT Device_Name FROM devices WHERE REPLACE(Device_Name, ' ', '')='cellphone'
result:
"cell phone"
"cellphone"
which includes first and third one
You can use of a regex when looking for your value, like :
cellphones|cell phones
Collection.find({
someName: {
$regex: new RegExp('cellphones|cell phones', ''),
},
});

Resources