Skip to main content
Cypress App

fixture

Load a fixed set of data located in a file.

Tests are easiest to trust when every run starts from the same data. cy.fixture() loads known test data, such as JSON records, images, and CSV files, from your fixturesFolder. That keeps the data out of your spec code, lets many tests share it, and means a test fails because your app changed, not because the data did.

Reach for cy.fixture() when you need to:

  • Stub network responses with cy.intercept(), so your tests don't depend on a live backend or on data that changes between runs
  • Fill in forms or check the page against the same known records every time
  • Upload a sample file through a file input with .selectFile()

To read a file that changes while your tests run, or a file your app produces, use cy.readFile() instead. See How cy.fixture() differs from cy.readFile().

Syntax​

cy.fixture(filePath)
cy.fixture(filePath, encoding)
cy.fixture(filePath, options)
cy.fixture(filePath, encoding, options)

Usage​

Correct Usage

cy.fixture('users').as('usersJson') // load data from users.json
cy.fixture('logo.png').then((logo) => {
// load data from logo.png
})

Arguments​

filePath (String)

A path to a file within the fixturesFolder , which defaults to cypress/fixtures.

You can nest fixtures within folders and reference them by defining the path from the fixturesFolder:

cy.fixture('users/admin.json') // Get data from {fixturesFolder}/users/admin.json

encoding (String)

The encoding to be used when reading the file. The following encodings are supported:

  • 'ascii'
  • 'base64'
  • 'binary'
  • 'hex'
  • 'latin1'
  • 'utf8'
  • 'utf-8'
  • 'ucs2'
  • 'ucs-2'
  • 'utf16le'
  • 'utf-16le'
  • null

Passing an encoding yields the raw file contents without parsing them, whatever the file extension. For example, cy.fixture('users.json', 'utf8') yields the JSON as a string rather than an object. Passing null yields the contents as a Cypress.Buffer instance.

options (Object)

Pass in an options object to change the default behavior of cy.fixture().

OptionDefaultDescription
timeoutresponseTimeoutTime to wait for cy.fixture() to resolve before timing out

Yields ​

  • cy.fixture() yields the contents of the file. Formatting is determined by its file extension, unless you pass an encoding.
  • cy.fixture() yields a copy of the cached contents, so changing the yielded object does not affect later cy.fixture() calls for the same file.
  • The yielded subject is not updated if the contents change on disk. See How Cypress caches fixture data for when Cypress reads the file again.

Examples​

JSON​

Load a users.json fixture​

cy.fixture('users.json').as('usersData')

Omit the fixture file's extension​

When no extension is passed to cy.fixture(), Cypress first looks for a file with exactly that name. If there isn't one, Cypress searches for files with the specified name and a supported extension within the fixturesFolder (which defaults to cypress/fixtures) and resolves the first one.

cy.fixture('admin').as('adminJSON')

The example above would resolve in the following order:

  1. cypress/fixtures/admin.json
  2. cypress/fixtures/admin.js
  3. cypress/fixtures/admin.html
  4. cypress/fixtures/admin.txt
  5. cypress/fixtures/admin.csv
  6. cypress/fixtures/admin.png
  7. cypress/fixtures/admin.jpg
  8. cypress/fixtures/admin.jpeg
  9. cypress/fixtures/admin.gif
  10. cypress/fixtures/admin.tif
  11. cypress/fixtures/admin.tiff
  12. cypress/fixtures/admin.zip

Import a JSON fixture into your spec​

If you are loading a JSON fixture, you can use the import statement and let the bundler load it:

cypress/e2e/spec.cy.js
import user from '../fixtures/user.json'
it('loads the same object', () => {
cy.fixture('user').then((userFixture) => {
expect(user, 'the same data').to.deep.equal(userFixture)
})
})

Generate a test for each record in a fixture​

To create one test per fixture record, import the fixture. cy.fixture() supplies data inside a test, but a loop inside its callback can't add new it() blocks.

cypress/e2e/users.cy.js
import users from '../fixtures/users.json'

describe('User profiles', () => {
users.forEach((user) => {
it(`shows the profile for ${user.name}`, () => {
cy.visit(`/users/${user.id}`)
cy.contains('h1', user.name)
})
})
})

Type fixture data in TypeScript​

cy.fixture() accepts a type argument that describes the yielded contents. Cypress doesn't check the file against the type, so keep the two in sync.

type User = {
id: number
name: string
email: string
}

cy.fixture<User[]>('users').then((users) => {
// users is typed as User[]
cy.get('[data-cy="user-email"]').first().should('have.text', users[0].email)
})

Read a JSON fixture as raw text​

Pass an encoding to yield the file's contents as a string instead of the parsed object. This helps when you want the exact text of the file, such as to compare it with a raw request body.

cy.fixture('users.json', 'utf8').then((raw) => {
expect(raw).to.be.a('string')
expect(raw).to.include('"email"')
})

Images​

Image fixtures yield base64 strings by default​

cy.fixture('images/logo.png').then((logo) => {
// logo will be encoded as base64
// and should look something like this:
// aIJKnwxydrB10NVWqhlmmC+ZiWs7otHotSAAAOw==...
})

Read an image fixture as a Cypress.Buffer​

cy.fixture('images/logo.png', null).then((logo) => {
// logo will be read as a buffer
// and should look something like this:
// Buffer([0, 0, ...])
expect(Cypress.Buffer.isBuffer(logo)).to.be.true
})

File uploads​

Upload a fixture with .selectFile()​

Load the fixture with a null encoding so it yields a Cypress.Buffer, alias it, and pass the alias to .selectFile(). Cypress keeps the fixture's file name, so the upload arrives as avatar.png.

cy.fixture('images/avatar.png', null).as('avatar')
cy.get('input[type="file"]').selectFile('@avatar')

Audio​

Play an MP3 fixture in the browser​

cy.fixture('audio/sound.mp3', 'base64').then((mp3) => {
const uri = 'data:audio/mp3;base64,' + mp3
const audio = new Audio(uri)

audio.play()
})

Accessing fixture data​

Stub a network response with fixture data​

cy.fixture('users').then((json) => {
cy.intercept('GET', '/users/**', json)
})

Load a fixture in beforeEach() and read it with cy.get()​

Aliases are cleared between tests, so load the fixture in a beforeEach() hook and read the alias back with cy.get(). This works with arrow functions, unlike the this context.

describe('User list', () => {
beforeEach(() => {
cy.fixture('users').as('users')
})

it('shows a row for every user', () => {
cy.visit('/users')
cy.get('@users').then((users) => {
cy.get('[data-cy="user-row"]').should('have.length', users.length)
})
})
})

Bootstrap your app's data with fixtures​

Change fixture data before stubbing a response​

You can modify fixture data directly before visiting a URL or mounting a component that makes a network request to that URL.

cy.fixture('user').then((user) => {
user.firstName = 'Jane'
cy.intercept('GET', '/users/1', user).as('getUser')
})

cy.visit('/users')
cy.wait('@getUser').then(({ response }) => {
expect(response.body.firstName).to.eq('Jane')
})

Notes​

How cy.fixture() differs from cy.readFile()​

Both commands read a file from disk, but they answer different questions. cy.fixture() answers "what data should this test start with?" while cy.readFile() answers "what's in this file right now?" Use cy.fixture() for known data that stays the same during the run, and cy.readFile() for files that change or that your app creates. For when to reach for a static import or cy.task() instead, see Choosing how to load test data in Cypress.

cy.fixture()cy.readFile()
Path is relative tofixturesFolderThe project root
File extensionOptionalRequired
Reads from diskOnce per path and encoding, then yields the cached copyOn every call
Retries until assertions passNoYes, reading the file again on each retry
Images by defaultA base64 stringA utf8 string
Default timeoutresponseTimeoutdefaultCommandTimeout
Command LogNot loggedLogged
Missing fileAlways failsCan be asserted with .should('not.exist')

Serve a fixture directly from cy.intercept()​

Fixtures can also be referenced directly without using the cy.fixture() command by using the special property fixture on the cy.intercept() StaticResponse object.

cy.intercept('GET', '/users/**', { fixture: 'users' })

The Command Log's Routes panel lists the route as stubbed, and each request it answers appears in the test body without a live server behind it:

Command Log with the Routes panel showing GET /users/** stubbed, and a fetch to /users/1 answered by it

cy.intercept() serves image and .zip fixtures as raw bytes. Other binary files, such as .mp4 or .pdf, are read as utf8 text by default, which corrupts them. To serve one of those byte for byte, add null as the encoding after a comma:

cy.intercept('GET', '/media/intro.mp4', { fixture: 'media/intro.mp4,null' })

You can pass any other supported encoding the same way.

How Cypress validates JSON and JavaScript fixtures​

Cypress automatically validates your fixtures. If your .json or .js files contain syntax errors, the test fails with an error that names the fixture and describes the problem.

A .js fixture is evaluated as a single JavaScript expression, such as an object literal ({ name: 'Jane' }), rather than loaded as a module.

How Cypress chooses a fixture's encoding​

When you don't pass an encoding, Cypress reads the file based on its extension:

ExtensionYields
.jsonThe parsed JSON
.jsThe evaluated JavaScript expression
.png, .jpg, .jpeg, .gif, .tif, .tiff, .zipA base64 string
.html, .txt, .csv, and every other extensionA utf8 string

To read a file differently, pass an encoding as the second argument of cy.fixture(). You can specify null as the encoding to read the file as a Cypress.Buffer instance instead.

These defaults describe what cy.fixture() yields. When you serve a fixture from cy.intercept(), image and .zip fixtures are sent as raw bytes instead of base64.

Sharing fixture data through the this context​

If you store and access the fixture data using this test context object, make sure to use function () { ... } callbacks. Otherwise the test engine will NOT have this pointing at the test context.

describe('User page', () => {
beforeEach(function () {
// "this" points at the test context object
cy.fixture('user').then((user) => {
// "this" is still the test context object
this.user = user
})
})

// the test callback is in "function () { ... }" form
it('has user', function () {
// this.user exists
expect(this.user.firstName).to.equal('Jane')
})
})

Loading large files with cy.fixture()​

Why large fixtures can crash or stall Cypress​

cy.fixture() reads the entire file into memory and transfers its contents from the Cypress Node.js server process to the browser test runner over an internal WebSocket connection. There is no explicit file size limit in Cypress itself, but large files — especially binary files like .zip archives — can cause Cypress to crash or become unresponsive due to:

  • Memory pressure: The complete file must fit in available RAM. Cypress keeps the contents in the fixture cache and yields a separate copy, so each loaded fixture takes up memory more than once. By default, binary files such as images and .zip archives are also converted to a base64 string in the browser, which is about a third larger than the file itself.
  • Single-message transfer: File contents are sent as a single message over the internal socket, so the whole payload is buffered at once.

As a practical guideline, avoid using cy.fixture() with files larger than a few megabytes. Smaller test fixtures (representative subsets of production data) are preferable wherever possible.

Upload a large file with .selectFile() and a path​

If your goal is to simulate a file upload through an <input type="file"> element, use .selectFile() with a path string rather than loading the fixture first and then setting the input manually:

// ✅ Preferred for file upload simulation
cy.get('input[type="file"]').selectFile('cypress/fixtures/large.zip')

Check a large file in Node.js with cy.task()​

For scenarios where you must work with large files but do not need to transfer their full contents to the browser (for example, verifying file metadata or invoking a server-side operation), use cy.task() to keep the operation in the Node.js context:

const { defineConfig } = require('cypress')
const { statSync } = require('fs')

module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('task', {
getFileSize(filePath) {
const { size } = statSync(filePath)
return size
},
})
},
},
})
// in your test
cy.task('getFileSize', 'cypress/fixtures/large.zip').then((size) => {
expect(size).to.be.greaterThan(0)
})

How Cypress caches fixture data​

The first time you load a fixture, Cypress caches its contents, keyed on the path exactly as you wrote it and the encoding. Later cy.fixture() calls with the same path and encoding yield the cached contents, even if the file has changed on disk. Because the key is the path as written, cy.fixture('users') and cy.fixture('users.json') are cached separately, so use one form consistently to read the file only once.

When you write to a file inside the fixturesFolder with cy.writeFile(), Cypress clears that file from the cache, so the next cy.fixture() call reads the new contents:

cy.writeFile('cypress/fixtures/todo.json', { title: 'New data' })
cy.fixture('todo').its('title').should('eq', 'New data')

Cypress doesn't detect changes made any other way, such as from cy.task() or another process. To read a file that changes during your tests, use cy.readFile() instead.

Fixtures in cy.intercept() are read when the route is added​

The fixture property of a cy.intercept() StaticResponse reads the file when Cypress registers the route. Overwriting the file afterwards doesn't change what that route replies with, so the following will not work:

// 🚨 DOES NOT WORK
cy.intercept('GET', '/todos/1', { fixture: 'todo' }).as('todo')
// application requests the /todos/1 resource
// the intercept replies with the object from todo.json file

cy.wait('@todo').then(() => {
cy.writeFile('cypress/fixtures/todo.json', { title: 'New data' })
})
// application requests the /todos/1 resource again
// the intercept replies with the object read from todo.json
// when the route was added and NOT { "title": "New data" }

In this situation, respond to the network request with the object and add a new intercept when the data changes:

// ✅ RESPOND WITH OBJECT
cy.fixture('todo.json').then((todo) => {
cy.intercept('GET', '/todos/1', { body: todo }).as('todo')
// application requests the /todos/1 resource
// the intercept replies with the initial object

cy.wait('@todo').then(() => {
// modify the response object
todo.title = 'New data'
// and override the intercept
cy.intercept('GET', '/todos/1', { body: todo })
})
})

Rules​

Requirements ​

  • cy.fixture() requires being chained off of cy.
  • cy.fixture() requires fixturesFolder to be set. It fails if fixturesFolder is false.

Assertions ​

  • cy.fixture() will only run assertions you have chained once, and will not retry.

Timeouts ​

  • cy.fixture() can time out waiting for the Cypress server to send the fixture. It waits for the timeout option, which defaults to responseTimeout.
  • cy.fixture() yields cached contents without waiting on the server, so a cached fixture never times out.

Command Log​

  • cy.fixture() does not log in the Command Log

History​

VersionChanges
15.18.0An aliased fixture keeps its file name for .selectFile() when a later test loads the same fixture.
15.0.0cy.writeFile() clears the cache for a fixture it writes. An explicit encoding always yields raw file contents.

See also​