Reputation: 1251
For the following result like structure
<div class="results">
<div class="result">
<div class="name">x</div>
<div class="price">99</div>
</div>
<div class="result">
<div class="name">y</div>
<div class="price">88</div>
</div>
</div>
I want to store in an list of array like this
var resultList = [{"name":"x","amount":"99"}, {"name":"y","amount":"88"}]
And in cypress, I have the following code in cypress but it prints null and I am not sure how to resolve it?
let listOfResults = [];
let singleResult = {};
cy.get('[class="results"]').each((resultItem) => {
singleResult = {};
//Retrive name
cy.wrap(resultItem)
.find('div[class$="name"]')
.invoke("text")
.then((val) => {
cy.log("singleResult value for Title:" + val);
singleResult["title"] = val;
cy.log("singleResult::" + JSON.stringify(singleResult));//prints correctly
});
//Retrive price
cy.wrap(resultItem)
.find('div[class$="amount"]')
.invoke("text")
.then((val) => {
cy.log("singleResult value for Title:" + val);
singleResult["amount"] = val;
cy.log("singleResult::" + JSON.stringify(singleResult)); //prints correctly
});
});
listOfResults.push(JSON.stringify(singleResult)); //singleResult became blank
cy.log("list:" + JSON.stringify(listOfResults));
Upvotes: 1
Views: 1521
Reputation: 1
Pull all data from dropdown list and then convert to array. Then click on desire label.
cy.get('ul[id="module-multiselect-options"] > li')
.each(($ele) => {
list.push($ele.text().trim())
})
.then(() => {
cy.log(list[2])
cy.get('ul[id="module-multiselect-options"] > li').contains(list[2]).click()
})
Upvotes: 0
Reputation: 465
Just to clarify how to write JSON values to a file, as I couldn't convey properly in comments.
cy.writeFile('cypress/fixtures/example.json', `{ "name": "${val}" }`, {flag: 'a+'})
...
cy.writeFile('cypress/fixtures/example.json', `{ "amount": "${price}" }`, {flag: 'a+'})
Without the quotes, the json in the file is invalid and can't be read.
There is another problem, the final comma in the array causes a problem. Will post more if I can figure out how to avoid that issue.
Upvotes: 1
Reputation: 18618
You can also use a write file for this. Basically, you create an empty JSON under your fixtures file and then create the structure of the JSON you want. {flag: 'a+'}
will append the data at the end of the file rather than replacing the contents.
cy.writeFile('cypress/fixtures/example.json', '') //Remove everything from the previous iteration
cy.writeFile('cypress/fixtures/example.json', '[') //Start Array
cy.get('[class="results"]').each((resultItem) => {
//Retrive name
cy.wrap(resultItem)
.find('div[class$="name"]')
.invoke('text')
.then((val) => {
cy.log('singleResult value for Title:' + val)
cy.writeFile('cypress/fixtures/example.json', '{"name":', {flag: 'a+'})
cy.writeFile('cypress/fixtures/example.json', `${val}`, {flag: 'a+'})
cy.writeFile('cypress/fixtures/example.json', ',', {flag: 'a+'})
})
//Retrive price
cy.wrap(resultItem)
.find('div[class$="amount"]')
.invoke('text')
.then((price) => {
cy.log('singleResult value for Title:' + price)
cy.writeFile('cypress/fixtures/example.json', '"amount":', {flag: 'a+'})
cy.writeFile('cypress/fixtures/example.json', `${price}`, {flag: 'a+'})
cy.writeFile('cypress/fixtures/example.json', '},', {flag: 'a+'})
})
})
cy.writeFile('cypress/fixtures/example.json', '\b', {flag: 'a+'}) //Remove last comma
cy.writeFile('cypress/fixtures/example.json', ']', {flag: 'a+'}) //End Array
Upvotes: 0
Reputation: 5461
You must wrap code following your extractor in .then()
because Cypress commands are asynchronous.
let listOfResults = [];
let singleResult = {};
cy.get('[class="results"]')
.each((resultItem) => {
...
})
.then(() => {
listOfResults.push(JSON.stringify(singleResult));
cy.log("list:" + JSON.stringify(listOfResults));
})
When you call cy.log()
it always takes it's value before the test runs, unless it is inside a .then()
. So cy.log("list:" + JSON.stringify(listOfResults))
sees the empty listOfResults
.
Iterate class="result"
cy.get('[class="results"]')
should be cy.get('[class="result"]')
because class="results"
is the overall div
, but you want to iterate class="result"
divs (assuming your cut-down HTML is accurate)
Push inside the .each()
listOfResults.push(JSON.stringify(singleResult))
should be inside the .each()
because you are pushing the singleResult of each iteration. But you also need a .then()
to do that, to ensure you push after singleResult is populated (same problem as above, async commands).
Don't stringify
You don't need to stringify for the logs, just add a comma. That way you keep the object structure for easier/better down-test usage.
const listOfResults = [];
// let singleResult = {}; // don't need this here
cy.get('[class="results"]').each((resultItem) => {
const singleResult = {}; // declare it fresh each iteration
//Retrive name
cy.wrap(resultItem)
.find('div[class$="name"]') // also 'div.name'
.invoke("text")
.then((val) => {
cy.log("singleResult value for Title:" + val);
singleResult["title"] = val;
cy.log("singleResult::", singleResult);
});
//Retrive price
cy.wrap(resultItem)
.find('div[class$="amount"]') // also 'div.amount'
.invoke("text")
.then((val) => {
cy.log("singleResult value for Title:" + val);
singleResult["amount"] = val;
cy.log("singleResult::", singleResult);
});
// Now push to list
cy.then(() => {
listOfResults.push(singleResult)
})
})
.then(() => {
cy.log("list:", listOfResults);
})
Or use an alias
const listOfResults = [];
cy.get('[class="result"]').each((resultItem) => {
...
})
.then(() => {
cy.wrap(listOfResults').as('listOfResults') // save for later in the test
})
// later on
cy.get('@listOfResults')
.then(listOfResults => {
cy.log("list:", listOfResults) // logs the value of parameter
// not the outer listOfResults
})
Upvotes: 2