I had the same question, and couldn't quite square the accepted answer with what I saw happening (in Cypress 9.2.1).
It turns out that when a .js
file is given as a fixture, cypress eval()
s the content of the file (actually, it uses eval-with-parentheses), and uses whatever object this results in.
So it is possible to have a file user-details.js
, which looks like
[{name: "Bob", age: 30 + 5}]
or even execute some "real" code:
["Bob", "Rob", "Job"].map((name, index) => ({user: name, age: 20 + index}))
or
(() => {
const users = ....
return users
})()
It should be noted that it's not as flexible as you might want (e.g. you cannot import code, do asynchronous things, etc), but it's more than nothing.
The question is, should you....
Quite honestly, I think this is a great way to allow making your fixtures slightly more human readable, being able to add comments, and easy conversions. And you're not bothered by JSON's comma-stictness E.g
[
// have a single user, because blah blah
{name: "Bob", date_of_birth: new Date(1979, 5, 3).valueOf() / 1000},
]
(Date(1979, 5, 3)
is much better human-readable than some unix timestamp (even though it means 5th of June, not 5th of May....))
I fully think that the .js
fixture is a good way to do this (and would be even happier if it would just import the fixture as a module and use the default export as item or something, but eval
is acceptable....), as long as the thing you're producing is constant! If you want something dynamic (or, probably, something constant that takes a bit more complexity to make), you're much better of with @seth-lutske 's suggestion (meaning that in your case, the accepted answer is what you need, however I wanted to document how .js
fixtures work in case someone else came by).
Having said all this, it's questionable why cypress uses an eval()
here, even though the suggested way is to use window.Function()
; in addition, I wonder if you want to run the risk that down the line, some other developer (which includes future-you) decides to build a system that downloads your fixtures from some external website, which means that you created a nice security hole....
It's very informative to read the github issue on Javascript fixtures (I wish I had before I dove into all this myself); if you're looking for a good workaround, see this and this comment.
As a concrete answer to the question asked, the problem is that
eval(`data = {
email: function () {
const currentTimestamp = new Date().getTime();
return \`test\${currentTimestamp}@test.com\`
},
firstName: 'Max',
lastName: 'Mustermann',
street: 'Some Street',
} `)
will return exactly that object, which should be accessible on this.userDetails
. Therefore this.userDetails.data
points to the data-field in this object, which is undefined
.
The following would work:
user-details.js:
{
data: {
email: function () {
const currentTimestamp = new Date().getTime();
return `test${currentTimestamp}@test.com`
},
firstName: 'Max',
lastName: 'Mustermann',
street: 'Some Street',
}
}
(or, in case you want email
to be a string rather than a function:
{
data: {
email: (function () {
const currentTimestamp = new Date().getTime();
return `test${currentTimestamp}@test.com`
})(),
firstName: 'Max',
lastName: 'Mustermann',
street: 'Some Street',
}
}
)