Random fixtures? Yes, it is possible!
One of these days, in the Cypress-BR group on Telegram, the following question came up:
Is it possible to put
faker
on a.json
file?
The short answer is no.
But, it's possible to create a .json
file dynamically, using the cy.writeFile
functionality, and with the help of the faker
library, make all data in this file dynamic.
Let's look at an example, creating a fixture
for use in a test that mocks the backend and tests the frontend in isolation.
The application under test (AUT) is called Hacker Stories.
This application communicates with the Hackernews public API for listing stories.
However, as mentioned earlier, we will mock the API.
The test file is as follows.
// cypress/integration/hackerStories.spec.js
describe('Hacker Stories', () => {
beforeEach(() => {
cy.generateFixture()
cy.intercept(
'GET',
'**/search?query=React&page=0',
{ fixture: 'stories' }
).as('getStories')
cy.visit('/')
cy.wait('@getStories')
})
it('renders 20 stories, then 19 when dismissing one', () => {
cy.get('.item').should('have.length', 20)
cy.get('.button-small').first().click()
cy.get('.item').should('have.length', 19)
})
})
Note that in the beforeEach
hook, there is a custom command called generateFixture()
. We'll see what this command does in a moment.
Also, notice that we are intercepting a request, which we will respond with a fixture called stories
.
Afterward, we visit the AUT, wait for such mocked request to happen, and the test is executed, which verifies that there are 20 items in the list and that when removing the first one, 19 are left.
You might be curious about the implementation of the generateFixture()
command, right?
There it goes.
// cypress/support/commands.js
Cypress.Commands.add('generateFixture', () => {
const faker = require('@faker-js/faker')
cy.writeFile('cypress/fixtures/stories.json', {
'hits':Cypress._.times(20, () => {
return {
'title':`${faker.lorem.words(3)}`,
'url':`${faker.internet.url()}`,
'author':`${faker.name.firstName()} ${faker.name.lastName()}`,
'num_comments':`${faker.datatype.number()}`,
'points':`${faker.datatype.number()}`,
'objectID':`${faker.datatype.uuid()}`,
}
})
})
})
For the random data, we import faker
to the command, using JavaScript's require
function.
Then we use cy.writeFile
, to write a file called stories.json
in the cypress/fixtures/
directory. As a second argument, we pass an object, which will contain the value of that file.
Such an object will have a hits
property, which is exactly what the frontend expects, and that property expects an array of objects.
We use lodash's .times
functionality (which is bundled with Cypress), as it returns precisely an array.
Then the .times
function runs 20 times to create 20 random stories, each with its title
, url
, author
, num_comments
, points
, and objectID
, using different functionalities offered by the faker
library.
For an example of the created fixture, access this file.
Note: Since this fixture is dynamic, we must add it to the .gitignore
file, cause we don't want to version it.
And so, we have a test that consumes a dynamically created fixture with random data. 🥳
That is, for each run, the fixture will be overwritten with new data.
I invite you to clone the project on your computer, install the dependencies following the documentation and then run the tests (both in interactive and in headless mode).
Access the complete project on GitHub.
Take the opportunity to leave a ⭐.
Note 2: As an alternative to the proposed solution, check out this other one, where instead of using fixtures, we overwrite the request response's body.
Did you like the content? Leave a comment!
Curious and want to learn more about Cypress Testing Automation? Check out my courses on Udemy.
👋 Until next time and happy testing!
This post was originally published in Portuguese at the Talking About Testing blog.
Top comments (2)
This is Great. Generating huge set of data for testing is vital to a any test framework and this serves that just as needed.
I had 2 questions(happy to refer to docos and try mysellf too)
How can we generate a fixture as a set of objects without an array like below(dont need the "hits" property and as an array of objects)
{
"title": "illo error voluptates",
"url": "intelligent-bark.name",
"author": "Alva Hagenes",
"num_comments": "9822",
"points": "12529",
"objectID": "93ff1ecd-9bf7-42a6-a2ac-c1e43d3cd572"
},
{
"title": "officiis quaerat culpa",
"url": "dimpled-graft.com",
"author": "Bo Upton",
"num_comments": "67463",
"points": "3466",
"objectID": "b1ea1d95-f365-4bce-af66-fffbe88f6501"
},
{
"title": "sit et laudantium",
"url": "downright-wholesaler.name",
"author": "Sincere Marvin",
"num_comments": "97152",
"points": "319",
"objectID": "4ab017fe-dac7-4bda-8a2a-810c008b3f67"
}
}
For the example above if one wants to test request schema validations by generating data for each of the above properties what would be the best recommended approach ?
I want to test if the application api if it can catch invalid data and throw schema errors(as its suposed to). So the various combos of data I'll want to generate dynamically and send each time is as below :
a) "title": generate various combos --
number("title": 1) --> InValid
exceeds length("title": "TestTestTestTestTest") --> InValid as length exceeds 10 as per schema
missing key(doesnt create the json object witht he key "title" but has other properties --> Invalid as the mandatory key is missing.
all other fields for this set(1-3) like ulr, author, num_comments will have valid data.
b) The next set will target num_comments - an integer and generate invaluid data for it but will keep valid data for all other properties.
c) and so on for other proeprties in the json.
So the final fixture file might have 15-20 objects(5 json properties * 3 or 4 invalid data combos)
Hi @sam-nash, thanks for asking. For your first question, I'd suggest exploring native JavaScript ways of doing what you need. At the end of the day, Cypress uses JavaScript, and we should take advantage of it. About question two, I'd suggest looking for a Cypress plugin (npm package) for schema validation. I hope that brings you some light! ;)