Value undefined using then in cypress - javascript

Hey guys i keep getting undefined, do i need to somehow create a promise or there is another way around, my value only exist inside a then() , also i am calling same thing twice is there a nice way of writing this together.
it.only('should switch to transaction history second page', () => {
let firstRowDate;
let secondRowDate;
TransactionsPage.tableRows.eq(0).find("td.cdk-cell.date.cdk-column-Date.table-cell").then((value) =>{
firstRowDate = value.text()
})
console.log(firstRowDate) -> undefined
TransactionsPage.appIconNext.click();
TransactionsPage.tableRows.eq(0).find("td.cdk-cell.date.cdk-column-Date.table-cell").then((value) =>{
secondRowDate = value.text()
})
console.log(secondRowDate) -> undefined
cy.url().should('eq', `${Cypress.config().baseUrl}/${Route.TransactionListPage + '?page=2'}`);
})
});

You have to write the console.log inside a then to make sure cypress executes the command synchronously
TransactionsPage.tableRows
.eq(0)
.find('td.cdk-cell.date.cdk-column-Date.table-cell')
.then((value) => {
secondRowDate = value.text()
})
.then(() => {
console.log(secondRowDate)
})
You can use aliases to save values and use them like this:
TransactionsPage.tableRows
.eq(0)
.find('td.cdk-cell.date.cdk-column-Date.table-cell')
.then((value) => {
cy.wrap(value.text()).as('value')
})
cy.get('#value').then((value) => {
//Access value here
})
You can do something like this:
it.only('should switch to transaction history second page', () => {
TransactionsPage.tableRows
.eq(0)
.find('td.cdk-cell.date.cdk-column-Date.table-cell')
.then((value) => {
cy.wrap(value.text()).as('value1')
})
TransactionsPage.appIconNext.click()
TransactionsPage.tableRows
.eq(0)
.find('td.cdk-cell.date.cdk-column-Date.table-cell')
.then((value) => {
cy.wrap(value.text()).as('value2')
})
//compare values
cy.get('#value1').then((value1) => {
cy.get('#value2').then((value2) => {
expect(value1).to.eq(value2)
})
})
cy.url().should(
'eq',
`${Cypress.config().baseUrl}/${Route.TransactionListPage + '?page=2'}`
)
})

You can console log it in the same .then().
TransactionsPage.tableRows.eq(0).find("td.cdk-cell.date.cdk-column-Date.table-cell").then((value) =>{
secondRowDate = value.text()
console.log(secondRowDate)
})

Related

Cypress: How to get value of div (mixing up async and sync code)

I have a div with the following html
<div data-cy="pop" style="margin-right:5px;">12,300</div>
I am trying to get 12,3001 convert it to a int and save the value for use in another function. I am getting this error.
cy.then() failed because you are mixing up async and sync code.The value you synchronously returned was: 12300
Here is my code to get the value.
cy.elem('pop').invoke('text').then((num) => {
const res = parseInt(num.replaceAll(',',''))
return res
})
Does anyone know what I'm doing wrong?
It's not clear how you are attempting to pass the value of your parsed int into the another function.
One way to save the value of something is with an alias. To do that you will need to use the .as().
cy.elem('pop')
.invoke('text')
.then((num) => { return parseInt(num.replaceAll(',','')) })
.as('num')
// later down in your code
cy.get('#num')
.then(number => {
functionYouWantToPassYourNumber(number)
})
Bit of an edge-case, TLDR: return cy.wrap(res).
If I run this as a minimal test for your code, it passes
const num = "12,300";
cy.wrap(num).then((numAsString) => {
const numAsInt = parseInt(numAsString.replace(",", ""));
return numAsInt
})
.then(num => {
cy.log(num) // logs 12300 ✅
})
If I add an async line cy.wait(5000) (for example), it fails
const num = "12,300";
cy.wrap(num).then((numAsString) => {
const numAsInt = parseInt(numAsString.replace(",", ""));
cy.wait(5000)
return numAsInt
})
.then(num => {
cy.log(num) ❌
})
If I then cy.wrap() the result, it passes again
const num = "12,300";
cy.wrap(num).then((numAsString) => {
const numAsInt = parseInt(numAsString.replace(",", ""));
cy.wait(5000)
return cy.wrap(numAsInt)
})
.then(num => {
cy.log(num) // logs 12300 ✅
})
Theoretically your code should pass, but if you have another command inside the .then() that could be causing it.
Or possible the cy.elem('pop') is causing it.
For reference, this is Cypress' own test for the error
describe("errors", {defaultCommandTimeout: 100}, () => {
beforeEach(function () {
this.logs = [];
cy.on("log:added", (attrs, log) => {
this.lastLog = log;
this.logs?.push(log);
});
return null;
});
it("throws when mixing up async + sync return values", function (done) {
cy.on("fail", (err) => {
const { lastLog } = this;
assertLogLength(this.logs, 1)
expect(lastLog.get("error")).to.eq(err);
expect(err.message).to.include(
"`cy.then()` failed because you are mixing up async and sync code."
);
done();
});
cy.then(() => {
cy.wait(5000);
return "foo";
});
});
});

Chaining .then without dependency of previous results

I am using node version 6, and i have chained few of .then's. But , only second .then depends on previous results, but rest of the .thens are non dependent on previous results. How to chain .then when they are not dependent on previous results.
Here is my code:
return admin.auth().getUser(phone)
.then(userRecord => {
return rp(options)
})
.then((orderResponse) => {
return admin.database().ref('trans/'+ phone)
.push({ amount: orderResponse.amount })
})
.then(() => {
return admin.database().ref('ord/'+ phone)
.push({ payment_id })
})
.then(() => {
return saveThisAddress === true ?
admin.database().ref('add/'+phone)
.push({address: finalAddress}) : null
})
.then(() => {
return admin.database().ref('dStatus/'+phone+'/'+orderNumber)
.set({ plan: planName === "" ? "Single Day Plan" : planName, orderStatus: orderStatus,
}, () => {
res.status(200).send({ success:true })
})
})
.then(() => {
return admin.database().ref(`couponCodes/${couponCodeName}`)
.update({couponUsage: couponUsage + 1 })
})
.then(() => {
return admin.database().ref(`couponUsage/${phone}`)
.update({ [couponCodeName]: usersCouponUsage + 1 })
})
.catch((err) => {
res.status(422).send({error: err });
});
Few said that, i am misusing promises. What am i doing wrong ? How to handle multiple .then when each .then isnt dependent on previous results ? AS i am using node 6, async / await cant be used here.
Please guide
Maybe a good idea is to make use of the Promise.all function that according to Node green it is available in Node 6.
In this case, only the second promise depends on the first one, so one way of doing it would be:
var promise1 = ...
.then(function(param) { return /* your second promise */})
var promise3 = ...;
var promise4 = ...;
var promise5 = ...;
var promise6 = ...;
Promise.all(promise1, promise3, promise4, promise5, promise6)
.then(/* once all succeded */)
.catch(/* if an error occurred */)

React Native Wait All Image Prefetch Done

I'm trying to prefetch multiple image before navigating to another screen, but returnedStudents all undefined.
prepareStudentImages = async (students) => {
let returnedStudents = students.map(student => {
Image.prefetch(student.image)
.then((data) => {
...
})
.catch((data) => {
...
})
.finally(() => {
return student;
});
});
await console.log(returnedStudents); // ----> all items undefined
}
There are a couple of things to fix with this:
1) Your map() function does not return anything. This is why your console log is undefined.
2) Once your map functions work, you are logging an array of promises. To deal with multiple promises (an array), you can use Promise.all().
So I think to fix this, you can do:
prepareStudentImages = async (students) => {
const returnedStudents = students.map(student =>
Image.prefetch(student.image)
.then((data) => {
...
})
.catch((data) => {
...
})
.finally(() => {
return student
})
)
console.log(returnedStudents) // log the promise array
const result = await Promise.all(returnedStudents) // wait until all asyncs are complete
console.log(result) // log the results of each promise in an array
return result
}

Return value from asynchronous function and pass result to another function

I'm using a class to do do some database stuff. In this example I want to reset the data and return the data.
export default class Db {
constructor () {
this.connection = monk('localhost:27017/db')
}
async resetDB () {
const Content = this.connection.get('content')
await Content.remove({})
await createContent()
return Content.findOne({ title: 'article' })
}
}
In my test I'm calling the db.resetDB(), but I need to get the returned value, as I need to pass the ID as parameter.
But how do I do that? I think my problem is, that this is asynchronous.
let id
describe('Test', () => {
before(() => {
db.resetDB(res => {
id = res._id
Article.open(id) // How do I get the ID?? I do get undefined here
Article.title.waitForVisible()
})
})
it('should do something', () => {
// ...
})
})
When the async function is called, it returns a Promise. hence you can get the return value in .then() of the promise. You can do it something like this,
let id
describe('Test', () => {
before(() => {
db.resetDB().then(res => {
id = res._id
Article.open(id) // How do I get the ID?? I do get undefined here
Article.title.waitForVisible()
})
})
it('should do something', () => {
// ...
})
})
You can make the before function to wait until all asynch calls gets finished by using done() callback.
https://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support
What you can do is
let id
describe('Test', () => {
before((done) => {
db.resetDB().then(res => {
id = res._id
Article.open(id) // How do I get the ID?? I do get undefined here
Article.title.waitForVisible()
done()
})
})
it('should do something', () => {
// ...
})
})

Chai as promised not waiting for promise to be fulfilled

An output of my console. Note that the console logs are out of order (1,3,4,2 instead of 1,2,3,4)
Code here
it('can store file', () => {
console.log('1) file storage start')
return filestore.store.q(file).then(() => {
console.log('2) file storage done')
}).should.eventually.be.fullfilled
})
describe('block number', () => {
beforeEach(() => {
console.log('3) check blockNumber')
return web3.Q.all([
web3.eth.getBlockNumber.q().then((_blockNumber) => {
blockNumber = _blockNumber
}),
web3.eth.getMining.q().then((isMining) => {
})
])
})
it('can retreive files block number', () => {
console.log('4) retreive')
return filestore.getBlockNumber.q(fileHash).should.eventually.bignumber.equal(blockNumber)
})
})
This turned out to be a stupid typo. I typed fullfilled instead of fulfilled
I suspect you are getting a side-effect from Chai. Try testing without it first, for example:
const assert = require('assert');
it('can store file', () => {
console.log('1) file storage start')
return filestore.store.q(file).then(() => {
// Promise should have fulfilled. Nothing more to do.
// Using should and chai after this is probably causing the problem.
// But you should really add some sort of assertion here to
// be able to detect regressions.
console.log('2) file storage done')
});
});
describe('block number', () => {
let blockNumber;
beforeEach(() => {
console.log('3) check blockNumber')
return web3.Q.all([
web3.eth.getBlockNumber.q().then((_blockNumber) => {
blockNumber = _blockNumber
}),
web3.eth.getMining.q().then((isMining) => {
})
])
})
it('can retreive files block number', () => {
console.log('4) retreive')
return filestore.getBlockNumber.q(fileHash)
.then((result) => {
// I'm not sure if assert.equal will work with big numbers.
// You might need a different comparator here.
assert.equal(result, blockNumber, 'should equal the blocknumber));
});
});
});
Mocha knows how to handle a returned Promise so there's really no need for Chai. It's unnecessary sugar.

Categories