Cypress get content of several DIVs, and compose one long string - javascript

I have some divs that render this way:
<div class="customer-data-column">
<h3>Title:</h3>
<div>Name Lastname</div>
<div>123 Address xxx yyy</div>
<div>Chicago XY 33056</div>
<div>Country name</div>
</div>
This content is generated by:
{customerData.replaceAll("/r", "").split("\n").map(item => <div key={item}>{item}</div>)}
This data is coming from redux.
In console log (from redux data) the address appears this way:
Name Lastname\n123 Address xxx yyy\nChicago XY 33056\nCountry name
I want to check in Cypress if this address is correct, the same that is in redux.
I need some way that merges the content of the divs into one string, and adds the \n between each div.
I thought I could start this way:
cy.get('.customer-data-column').should($title => {
const store = Cypress.store.getState();
const reduxPath = store.customerData;
expect("not sure what to put here... how to merge").to.equals(reduxPath)
Can anyone please help?
===
EDIT
I made it almost work this way:
I added a class to the inner divs, so they render this way:
<div class="customer-data-column">
<h3>Title:</h3>
<div class="address-row">Name Lastname</div>
<div class="address-row">123 Address xxx yyy</div>
<div class="address-row">Chicago XY 33056</div>
<div class="address-row">Country name</div>
</div>
And the test:
cy.get('.address-row').then($divList => {
const textArray = Cypress.$.makeArray($divList).map(el => el.innerText)
const actual = textArray.join(textArray, '\n') // use join to array of strings into single string
expect(actual).to.eql(billToAddress)
})
However it still fails with such message:
assert expected Name LastnameName Lastname,23 Address xxx yyy,Chicago
XY 33056,Country name23 Address xxx yyyName Lastname,23 Address xxx
yyy,Chicago XY 33056,Country name7th FloorName Lastname,23 Address xxx
yyy,Chicago XY 33056,Country nameBrooklyn NY 11210Name Lastname,23
Address xxx yyy,Chicago XY 33056,Country nameCountry name to deeply
equal Name Lastname\n23 Address xxx yyy\n7th Floor\nBrooklyn NY
11210\nCountry name
Edit 2:
The solution that I found and works is this one:
.then(users => {
const billToAddress = users.response.body.filter(el => el.orderNumber === '3-331877')[0]
.billTo
cy.get('.address-row').each((item, index) => {
cy.log(cy.wrap(item).should('contain.text', billToAddress.split('\n')[index]))
})
})
Of course if somebody has a better way for achieving this test, I am open to learn more and code better.

If you make an array of the store data, an .each() loop can compare them.
const store = Cypress.store.getState()
const reduxData = store.customerData // expect 'Name Lastname\n123 Address xxx yyy\nChicago XY 33056\nCountry name'
const reduxDataArray = reduxData.split('\n')
cy.contains('.customer-data-column', 'Title:')
.find('div') // only divs inside '.customer-data-column'
.each(($div, index) => {
expect($div.text()).to.eq(reduxDataArray[index])
})
From other comment, it looks like cy.get('.custom-data-column') isn't strong enough to isolate this HTML you need to work on.
Perhaps cy.contains('.customer-data-column', 'Title:') is better.
All text at once
In this particular case you can test all text at once by globally removing \n
const store = Cypress.store.getState()
const reduxData = store.customerData // expect 'Name Lastname\n123 Address xxx yyy\nChicago XY 33056\nCountry name'
const reduxAllTexts = reduxData.replace(/\n/g, '')
cy.contains('.customer-data-column', 'Title:')
.find('div')
.invoke('text')
.should('eq', reduxAllTexts)

If the Cypress function yields multiple elements, we can join the text of those elements to create your string.
cy.get('.custom-data-column').find('div').then(($divList) => {
const store = Cypress.store.getState();
const reduxPath = store.customerData;
const textArray = $divList.map((x) => x.text()); // get the text values as an array
const actual = textArray.join(textArray, '\n'); // use join to array of strings into single string
expect(actual).to.eql(reduxPath);
});

Related

Using Axios and Pokemon API to display more than one Pokemon of same type

so I'm trying to randomly generate a Pokemon and then five more Pokemon of the same type to display on a web page. So far, this is what I have:
const pokemonName = document.querySelector(".pokemon-name");
const pokemonImage = document.querySelector(".pokemon-image");
function getPokemon() {
const pokemonArr = []
const random = Math.floor(Math.random() * 256 + 1)
axios.get("https://pokeapi.co/api/v2/pokemon/1" + random)
.then(function (response) {
pokemonName.innerHTML = response.data.forms[0].name;
pokemonImage.src = response.data.sprites.front_default;
pokemonArr.push(pokemonName.innerHTML)
})
.catch(function (error) {
pokemonName.innerHTML = "An error has occurred.";
pokemonImage.src = "";
});
}
I've managed to display a Pokemon although it's still finnicky. My thought process was to append the name and image to an array or object but I'm having issues trying to apply that logic. This is my first time being introduced to the concept of APIs and using Axios. Would I be able to use a loop? How do I even go about comparing the types of Pokemon in the API?
Pokemon API: https://pokeapi.co/
https://replit.com/#heyitsmarcus/PokemonContainer#index.html
Above is a demo of the code explanation below.
If you want to fill with X amount of Pokemon on your page, you're on the right track to use classes. But, you need to utilize the querySelectorAll functionality to take advantage of your classes. This will allow you to run a for loop on the classes and pick a different pokemon for each matching selector. You really want to have a pokemon-container class, for example, that houses your pokemon-name and pokemon-image classes individually like so:
<div class="pokemon-container">
<div class="pokemon-name"></div>
<img class="pokemon-image" src="">
</div>
<div class="pokemon-container">
<div class="pokemon-name"></div>
<img class="pokemon-image" src="">
</div>
<div class="pokemon-container">
<div class="pokemon-name"></div>
<img class="pokemon-image" src="">
</div>
Repeat this for the number of pokemon you want to see. Then, you can run a for loop on the 3 pokemon-container classes to see 3 random pokemon while still using the same names you had before. The difference is, you just want to run a querySelector to grab the specific individual pokemon names and images for that container. This results in 3 random pokemon each time! =]
function getNewPokemon() {
//this loop grabs every pokemon container individually
const pokemonContainers = document.querySelectorAll('.pokemon-container');
for (const container of pokemonContainers) {
//Grab this specific container's pokemon name element
const pokemonName = container.querySelector('.pokemon-name');
//Grab this specific container's pokemon image element
const pokemonImage = container.querySelector('.pokemon-image');
//Get your random integer
const random = Math.floor(Math.random() * 256 + 1);
//also I removed the 1 from after the final slash because you're excluding pokemon by including that 1 in the URL
//and you can just use the natural JavaScript "fetch"
//there's really no need for a whole library for a request like this
axios.get(`https://pokeapi.co/api/v2/pokemon/${random}`)
.then(json => {
pokemonName.innerHTML = json.data.forms[0].name;
pokemonImage.src = json.data.sprites.front_default;
})
.catch(error => {
console.error('error in request', error);
pokemonName.innerHTML = "An error has occurred.";
pokemonImage.src = "";
})
}
}

Split string using elements of array JavaScript

Hello i'm working on dynamic search for my first web application
and i have a huge problem i've been working on this for several hours using diffrent solutions in the end i think this might be the closest to resolving my problems.
Search is not static so hard coding this is not an option.
const search = 'someone loves some thing';
const teams = ['some thing', 'someone', 'help'];
const twoTeams = [];
if (teams.some(el => search.includes(el))) {
teams.forEach(word => {
if (search.includes(word)) {
twoTeams.push(word);
}
})
}
console.log(twoTeams); // ['some thing','someone']
console.log(search) // 'someone loves some thing'
// looking for // console.log(twoTeams)// 'someone','some thing'
And here im stuck i have array of items that i need to split string with to access data from API i just need it in that order i cant reverse order because in the app theres too many elements in array and user can search anything so you dont know which one should will be index[0] and which one should be index[1] and thats crucial to my dynamic search.
First of all, I'd start with removing the outer if as we check every word anyway in the inner condition.
teams.forEach(word => {
// Get the position of word in the search text. Negative value means that there is no match.
let index = search.indexOf(word);
// If the search text contains the word
if (index >= 0) {
// Save both the matching word and its index
twoTeams.push( { 'word': word, 'index': index});
}
})
// Sort the results by the index and select the word only
twoTeams = results.sort((a,b)=> a.index - b.index).map(result => result.word);
You can simplify your code to built twoTeams object with filter like below.
const twoTeams = teams.filter(el => search.includes(el));
As you want preserve order then you can sort your results with indexOf like below.
twoTeams.sort((a, b) => search.indexOf(a) - search.indexOf(b));
Try it below.
const search = 'someone loves some thing';
const teams = ['some thing', 'someone', 'help'];
const twoTeams = teams.filter(el => search.includes(el));
twoTeams.sort((a, b) => search.indexOf(a) - search.indexOf(b));
console.log(twoTeams); // looking for ['someone', 'some thing']
console.log(search) // 'someone loves some thing'

How to split Json response and get specific part using angular

I am developing angular blockchain application using hyperledger composer tool.When i query the historian i got a response like in the below.
{
transactionType:"org.hyperledger.composer.system.AddParticipant"
}
I display the transaction type using follwing code snippet.
<div class="col-md-6">
{{participant.transactionType}}
</div>
The displayed part like this.
org.hyperledger.composer.system.AddParticipant
but I only want to display the 'AddParticipant' part in the response without 'org.hyperledger.composer.system.' part. How can I fix it?
For that just do little string manipulation. Make use of JS .split() method which splits string by argument character/string.
let arr = this.participant.transactionType.split(".");
then arr[arr.length-1] is your required string part which you can bind to view. Like use below {{txTyepe}} in template binding
this.txType = arr[arr.length-1];
you can use "substr" to pick a word from string but you need position of your word in your string first so :
const str = 'org.hyperledger.composer.system.AddParticipant'
let getPosition = str.indexOf('AddParticipant'); // get the position of AddParticipant
let getWord = str.substr(getPosition,13);
the length of AddParticipant is 13 also you can change the code above for better and cleaner and multi use code
const splitWord = (index)=>{
const str = 'org.hyperledger.composer.system.AddParticipant'
let strArray = str.split('.')
let getPosition = str.indexOf('AddParticipant'); // get the position of AddParticipant
let getWord = str.substr(getPosition,strArray[index].lenght); //you just need to change the number
return getWord;
}
console.log(splitWord(4));
You can also get the last "word" with regular expression :
<div class="col-md-6">
{{participant.transactionType.match(/\w+$/i)}}
</div>
When you see your historian data it'll look something like this
'$namespace': 'org.hyperledger.composer.system',
'$type': 'HistorianRecord',
'$identifier': '6e43b959c39bdd0c15fe45587a8dc866f1fa854d9fea8498536e84b45e281b31',
'$validator': ResourceValidator { options: {} },
transactionId: '6e43b959c39bdd0c15fe45587a8dc866f1fa854d9fea8498536e84b45e281b31',
transactionType: 'org.hyperledger.composer.system.IssueIdentity',
transactionInvoked:
Relationship {
'$modelManager': [Object],
'$classDeclaration': [Object],
'$namespace': 'org.hyperledger.composer.system',
'$type': 'IssueIdentity',
'$identifier': '6e43b959c39bdd0c15fe45587a8dc866f1fa854d9fea8498536e84b45e281b31',
'$class': 'Relationship' },
So, instead of taking transactionType you can use the transactionInvoked object. And then you can get whatever information you want from that object.
Finally your code should be like this
<div class="col-md-6">
{{participant.transactionInvoked.$type}}
</div>
In my case it will give me transaction type as just 'IssueIdentity'.

How to query firebase keys with a substring

I want to query Firebase that contains an input. for example in the database structure below, I would like to query all nodes that contains "4140"
so I use this code
var catref = Cataloguedatabase.ref("/Listing Search/");
return catref.once('value').then(function(snapshot){
snapshot.forEach(childSnapshot => {
let snapdb = childSnapshot.val();
let key = childSnapshot.key;
//use ES6 includes function
if(key.includes(schname)){
console.log(childSnapshot.val());
var searchresults = childSnapshot.val();
var container = document.getElementById('listing_gallery');
// container.innerHTML = '';
var productCard = `
<div class="col-sm-3">
<div class="card" onclick="gotoproduct(this);" id="${key}">
`
container.innerHTML += productCard;
}
})
})
This works but the problem is that it first query all the child and sort through the array.This is ok for node with few children but when it gets to thousands of children, it becomes impractical. is there a away i can only query key the contains the value in firebase and if not how else can i implement this?
As Doug says, there is no way to query for values that contain a certain string. But you can query for keys that start with a certain substring:
return catref.orderByKey().startAt("4140-").endAt("4140-\uf8ff").once('value').then(function(snapshot){
This will just match the child nodes whose key starts with 4140-.
What you're asking is not possible with Firebase Realtime Database. There are no substring queries.
If you're only interested in the first four characters for your query, what you can do is store that string as a child inside that node, then orderByChild() on that child to find only those items that begin with a certain four character sequence.
You can read more about ordering in the documentation.

using split and map in jsx

const arr = ['name', 'contact number']
const App = () => (
<div style={styles}>
Add {arr.split(',').map(o=>o)}
</div>
);
why this won't work? I want to print Add name & contact, but stuck at splitting it.
You're using 2 functions wrong:
split is supposed to be used to split a string into an array, around the provided character. You already have the resulting array.
.map(o=>o) is useless - it basically returns the same array provided.
You're probably looking to do this Add {arr.join(' & ')}.
You are looking to join the values
Add {arr.join(',')}
Below links should help you
MDN split
MDN join
There is nothing to split. I think you are trying to join them:
const arr = ['name', 'contact number']
const App = () => (
<div style={styles}>
Add {arr.join(',')}
</div>
);

Categories

Resources