What Are Fixtures?
Fixtures are external files that contain test data in JSON format. They provide a centralized way to manage test data, making your tests more maintainable and reusable.
Benefits of Using Fixtures
Centralized Data Store all test data in one location for easy updates
Reusability Share the same data across multiple tests
Separation of Concerns Keep test data separate from test logic
Easy Maintenance Update data once, affect all tests using it
Fixture File Structure
Fixtures are stored in the cypress/fixtures/ directory:
cypress/fixtures/
├── users.json # User credentials
├── loginPageData.json # UI messages and text
└── bookings.json # API test data
Creating Fixtures
Simple Object Fixture
For single objects like user credentials:
{
"standard" : "standard_user" ,
"locked" : "locked_out_user" ,
"problem" : "problem_user" ,
"performance" : "performance_glitch_user" ,
"error" : "error_user" ,
"visual" : "visual_user" ,
"password" : "secret_sauce"
}
Usage:
cy . fixture ( 'users' ). then (( user : any ) => {
loginPage . typeUsername ( user . standard ) // "standard_user"
loginPage . typePassword ( user . password ) // "secret_sauce"
})
Array Fixture
For collections of data:
[
{
"firstname" : "James" ,
"lastname" : "Brown" ,
"totalprice" : 111 ,
"depositpaid" : true ,
"bookingdates" : {
"checkin" : "2018-01-01" ,
"checkout" : "2019-01-01"
},
"additionalneeds" : "Breakfast"
},
{
"firstname" : "Jim" ,
"lastname" : "Jones" ,
"totalprice" : 681 ,
"depositpaid" : true ,
"bookingdates" : {
"checkin" : "2022-03-26" ,
"checkout" : "2025-03-19"
},
"additionalneeds" : "Breakfast"
}
]
Usage:
cy . fixture ( 'bookings' ). then (( bookings : any ) => {
bookings . forEach (( booking , index ) => {
cy . request ( `/booking/ ${ index + 1 } ` ). then (( res ) => {
expect ( res . body . firstname ). to . equal ( booking . firstname )
expect ( res . body . lastname ). to . equal ( booking . lastname )
})
})
})
Nested Object Fixture
For complex, structured data:
{
"errorMsg" : "Epic sadface: Sorry, this user has been locked out." ,
"successMsg" : "Login successful" ,
"validation" : {
"usernameRequired" : "Username is required" ,
"passwordRequired" : "Password is required"
}
}
Usage:
cy . fixture ( 'loginPageData' ). then (( data : any ) => {
loginPage . verifyErrorMessage ( data . errorMsg )
// Or access nested properties
loginPage . verifyValidationMessage ( data . validation . usernameRequired )
})
Loading Fixtures in Tests
Method 1: Using cy.fixture() with Aliases
This is the most common approach in the framework:
describe ( 'User Authentication' , () => {
beforeEach (() => {
// Load fixture and create alias
cy . fixture ( 'users' ). as ( 'userData' )
cy . fixture ( 'loginPageData' ). as ( 'loginData' )
cy . visit ( '/' )
});
it ( 'Should log in successfully' , () => {
// Access aliased fixture
cy . get ( '@userData' ). then (( user : any ) => {
loginPage . typeUsername ( user . standard )
loginPage . typePassword ( user . password )
loginPage . clickOnLoginButton ()
})
});
});
Using aliases (as()) makes fixtures available throughout the test. The @ prefix accesses the aliased value.
Method 2: Direct Loading
Load fixtures directly within tests:
it ( 'Should validate user data' , () => {
cy . fixture ( 'users' ). then (( user : any ) => {
// Fixture is only available within this callback
expect ( user . standard ). to . exist
expect ( user . password ). to . equal ( 'secret_sauce' )
})
})
Method 3: Loading Multiple Fixtures
beforeEach (() => {
cy . fixture ( 'users' ). as ( 'userData' )
cy . fixture ( 'loginPageData' ). as ( 'loginData' )
cy . fixture ( 'products' ). as ( 'productData' )
})
it ( 'Should use multiple fixtures' , () => {
cy . get ( '@userData' ). then (( user : any ) => {
cy . get ( '@loginData' ). then (( login : any ) => {
cy . get ( '@productData' ). then (( products : any ) => {
// Use all fixtures
})
})
})
})
Real-World Examples from the Framework
Example 1: Login Tests with Multiple Users
let loginPage : LoginPage
let homePage : HomePage
describe ( 'User Authentication' , () => {
beforeEach (() => {
cy . fixture ( 'users' ). as ( 'userData' )
loginPage = new LoginPage ()
homePage = new HomePage ()
cy . visit ( '/' )
});
it ( 'Should log in with standard user' , () => {
cy . get ( '@userData' ). then (( user : any ) => {
loginPage . userLogin ( user . standard , user . password )
homePage . verifyHomePageIsVisible ()
})
});
it ( 'Should log in with problem user' , () => {
cy . get ( '@userData' ). then (( user : any ) => {
loginPage . userLogin ( user . problem , user . password )
homePage . verifyHomePageIsVisible ()
})
});
it ( 'Should not log in with locked user' , () => {
cy . get ( '@userData' ). then (( user : any ) => {
cy . get ( '@loginData' ). then (( login : any ) => {
loginPage . typeUsername ( user . locked )
loginPage . typePassword ( user . password )
loginPage . clickOnLoginButton ()
loginPage . verifyErrorMessage ( login . errorMsg )
})
})
});
});
Example 2: API Tests with Expected Data
describe ( 'API Requests - GET' , () => {
it ( 'Should return specific booking data' , () => {
cy . fixture ( 'bookings' ). then (( bookingData : any ) => {
for ( let i = 1 ; i < 4 ; i ++ ) {
cy . request ({
method: 'GET' ,
url: `/booking/ ${ i } ` ,
}). then (( res ) => {
const { firstname , lastname , totalprice , depositpaid } = res . body
expect ( firstname ). to . equal ( bookingData [ i - 1 ]. firstname )
expect ( lastname ). to . equal ( bookingData [ i - 1 ]. lastname )
expect ( totalprice ). to . equal ( bookingData [ i - 1 ]. totalprice )
expect ( depositpaid ). to . equal ( bookingData [ i - 1 ]. depositpaid )
})
}
})
})
});
Fixture Organization Strategies
Strategy 1: By Feature
Organize fixtures by application feature:
cypress/fixtures/
├── auth/
│ ├── users.json
│ └── credentials.json
├── products/
│ ├── inventory.json
│ └── pricing.json
└── checkout/
└── payment-methods.json
Usage:
cy . fixture ( 'auth/users' ). as ( 'userData' )
cy . fixture ( 'products/inventory' ). as ( 'products' )
Strategy 2: By Test Type
Separate UI and API test data:
cypress/fixtures/
├── ui/
│ ├── users.json
│ └── messages.json
└── api/
├── bookings.json
└── responses.json
Strategy 3: By Environment
Different data for different environments:
cypress/fixtures/
├── dev/
│ └── users.json
├── staging/
│ └── users.json
└── prod/
└── users.json
Advanced Fixture Patterns
Pattern 1: Dynamic Data with Functions
Generate dynamic data at runtime:
it ( 'Should create booking with current date' , () => {
cy . fixture ( 'bookings' ). then (( booking : any ) => {
const today = new Date (). toISOString (). split ( 'T' )[ 0 ]
const checkoutDate = new Date ( Date . now () + 7 * 24 * 60 * 60 * 1000 )
. toISOString (). split ( 'T' )[ 0 ]
cy . request ({
method: 'POST' ,
url: '/booking' ,
body: {
... booking [ 0 ],
bookingdates: {
checkin: today ,
checkout: checkoutDate
}
}
})
})
})
Pattern 2: Fixture Merging
Combine multiple fixtures:
it ( 'Should use merged data' , () => {
cy . fixture ( 'users' ). then (( users : any ) => {
cy . fixture ( 'addresses' ). then (( addresses : any ) => {
const userData = {
... users . standard ,
address: addresses . home
}
// Use merged data
})
})
})
Pattern 3: Parameterized Tests with Fixtures
it ( 'Should login with multiple users' , () => {
cy . fixture ( 'users' ). then (( user : any ) => {
const userTypes = [ 'standard' , 'problem' , 'performance' , 'visual' ]
userTypes . forEach ( userType => {
cy . visit ( '/' )
loginPage . userLogin ( user [ userType ], user . password )
homePage . verifyHomePageIsVisible ()
navbar . userLogout ()
})
})
})
TypeScript Type Safety with Fixtures
Create interfaces for type-safe fixtures:
interface UserCredentials {
standard : string
locked : string
problem : string
performance : string
error : string
visual : string
password : string
}
interface Booking {
firstname : string
lastname : string
totalprice : number
depositpaid : boolean
bookingdates : {
checkin : string
checkout : string
}
additionalneeds ?: string
}
Usage with types:
it ( 'Should use typed fixtures' , () => {
cy . fixture < UserCredentials >( 'users' ). then (( user ) => {
// TypeScript knows the structure
loginPage . typeUsername ( user . standard )
loginPage . typePassword ( user . password )
})
})
Fixture Best Practices
Don’t over-complicate fixture structure: // ✅ Good - simple and clear
{
"standard" : "standard_user" ,
"password" : "secret_sauce"
}
// ❌ Bad - overly nested
{
"users" : {
"valid" : {
"primary" : {
"main" : "standard_user"
}
}
}
}
Use descriptive property names
Make it clear what each property represents: // ✅ Good
{
"errorMsg" : "Epic sadface: Sorry, this user has been locked out."
}
// ❌ Bad
{
"msg1" : "Epic sadface: Sorry, this user has been locked out."
}
Don’t store real credentials or sensitive information: // ✅ Good - test credentials
{
"username" : "test_user" ,
"password" : "test_pass_123"
}
// ❌ Bad - real credentials
{
"username" : "[email protected] " ,
"password" : "MyRealPassword123!"
}
Commit fixtures to version control since they’re test code: # ✅ Include in git
git add cypress/fixtures/ * .json
# ❌ Don't exclude unless they contain secrets
# .gitignore
# cypress/fixtures/*.json ← Usually wrong
Common Issues and Solutions
Error: cy.fixture() failed because the fixture does not existSolution: Verify the file path and name:// Check file exists at: cypress/fixtures/users.json
cy . fixture ( 'users' ) // No .json extension needed
// For subdirectories
cy . fixture ( 'auth/users' )
Cannot read properties of undefined
Error: Accessing fixture data outside the .then() callbackSolution: Access data within the callback:// ❌ Bad
cy . fixture ( 'users' ). as ( 'userData' )
const user = cy . get ( '@userData' ) // Won't work
// ✅ Good
cy . get ( '@userData' ). then (( user : any ) => {
// Access user here
})
Fixture data not updating
Issue: Changes to fixture files not reflected in testsSolution: Cypress caches fixtures. Reload the test or restart Cypress:# Close and reopen Cypress Test Runner
# Or in headless mode, just re-run
npm run cy:run:ui
Fixtures vs Environment Variables
Use Fixtures For
Test data
Expected results
User information
API payloads
Use Environment Variables For
Base URLs
API keys
Configuration settings
Sensitive credentials
// ✅ Fixture for test data
cy . fixture ( 'users' ). then (( user ) => {
loginPage . typeUsername ( user . standard )
})
// ✅ Environment variable for sensitive data
const apiKey = Cypress . env ( 'API_KEY' )
cy . request ({
url: '/api/data' ,
headers: { 'Authorization' : `Bearer ${ apiKey } ` }
})
Next Steps
Writing UI Tests Apply fixtures in your UI tests
Writing API Tests Use fixtures for API test data
Test Organization Organize fixtures with your tests
Maintainability Keep fixtures maintainable