Cypress Data Session
cypress-data-session is a Cypress plugin designed to streamline test data setup and reuse by implementing a powerful caching mechanism. It provides the `cy.dataSession` command, allowing developers to define how test data (like user objects, authentication tokens, or complex API responses) is created, validated, cached, and recreated if necessary. This plugin significantly speeds up test execution by avoiding repetitive, expensive data creation operations across multiple tests or even different spec files. Currently at v3.0.0, the package sees consistent maintenance and bug fixes, with major versions introducing breaking changes tied to Cypress core updates. Its key differentiator from Cypress's native `cy.session` command is its flexibility: `cy.dataSession` can cache *anything* (not just browser session state), provides direct access to cached data, supports custom validation logic, dependent caching, time limits, use count limits, and offers static utility methods, making it highly adaptable for complex test scenarios.
Common errors
-
TypeError: cy.dataSession is not a function
cause The `cypress-data-session` plugin has not been correctly imported into your Cypress support file, or the support file itself is not loaded.fixAdd `import 'cypress-data-session';` to your `cypress/support/e2e.ts` (or `cypress/support/index.ts` for older Cypress versions) file. Ensure your `cypress.config.ts` correctly points to your support file. -
Cypress command 'dataSession' failed because the session name was not a string.
cause The `name` option passed to `cy.dataSession` must be a non-empty string.fixProvide a valid string for the `name` property within the `cy.dataSession` options object, e.g., `{ name: 'myUniqueSession', ... }`. -
Error: Cypress plugin 'dataSession' was not able to register its tasks. This usually happens if setupNodeEvents was not called.
cause The `setupNodeEvents` function from `cypress-data-session/plugin` was not called in your `cypress.config.ts/js`, or it was called incorrectly.fixIn your `cypress.config.ts/js`, ensure you `import { setupNodeEvents } from 'cypress-data-session/plugin';` and then call `setupNodeEvents(on, config);` inside your `e2e.setupNodeEvents` function, returning the `config` object.
Warnings
- breaking Version 3.0.0 of `cypress-data-session` introduces a breaking change by no longer relying on `Cypress.env` for internal state management and instead using `Cypress.expose`. This change requires Cypress v15.10+.
- gotcha When `shareAcrossSpecs` option is enabled, the data session value is saved in the plugin process. This means that if `cypress-data-session` plugin's `setupNodeEvents` is not correctly registered in `cypress.config.js/ts`, sessions cannot be shared across different spec files.
- gotcha Directly clearing `Cypress.env` or reloading the browser can inadvertently clear `cy.dataSession` values if `shareAcrossSpecs` is not set to `true`, as the session data is typically stored in `Cypress.expose` (post v3) which resets on spec reloads or new specs.
Install
-
npm install cypress-data-session -
yarn add cypress-data-session -
pnpm add cypress-data-session
Imports
- cy.dataSession (command registration)
const cypressDataSession = require('cypress-data-session');import 'cypress-data-session';
- setupNodeEvents
const { setupNodeEvents } = require('cypress-data-session/src/plugin');import { setupNodeEvents } from 'cypress-data-session/plugin'; - clearAllDataSessions
const { clearAllDataSessions } = require('cypress-data-session/src/utils');import { clearAllDataSessions } from 'cypress-data-session';
Quickstart
import { defineConfig } from 'cypress';
import { setupNodeEvents } from 'cypress-data-session/plugin';
// cypress.config.ts
export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
setupNodeEvents(on, config); // Register plugin tasks
// IMPORTANT: return the config object
return config;
},
baseUrl: 'http://localhost:3000', // Example base URL
specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}',
},
});
// cypress/support/e2e.ts
import 'cypress-data-session'; // Registers cy.dataSession command
// cypress/e2e/user.cy.ts
describe('User Management with Data Session', () => {
const userSessionName = 'testUser';
let createdUserId: string; // Store ID for cleanup
beforeEach(() => {
cy.dataSession({
name: userSessionName,
setup: () => {
cy.log('Creating new user via API...');
// In a real app, this would be an API call to create a user
return cy.request('POST', '/api/users', {
username: 'testuser_' + Date.now(), // Unique username
password: 'password123',
}).then((response) => {
expect(response.status).to.eq(201);
createdUserId = response.body.id;
return { id: createdUserId, token: response.body.token }; // Data to cache
});
},
validate: (cachedData: { id: string, token: string }) => {
cy.log(`Validating user: ${cachedData.id}`);
// Check if the user still exists and the token is valid
return cy.request({
method: 'GET',
url: `/api/users/${cachedData.id}`,
headers: { Authorization: `Bearer ${cachedData.token}` },
failOnStatusCode: false,
}).then(response => response.status === 200);
},
recreate: (cachedData: { id: string, token: string }) => {
cy.log(`Recreating session for user: ${cachedData.id}`);
// Use the cached token to log in or set session state
cy.setCookie('authToken', cachedData.token);
cy.visit('/'); // Navigate to the app after setting session
},
onInvalidated: () => {
cy.log(`Data session '${userSessionName}' was invalidated. Performing cleanup if needed.`);
// Optional: specific cleanup actions if validation fails
},
shareAcrossSpecs: true, // Allow sharing this session across multiple spec files
// expire: 3600000, // Optional: expire session after 1 hour
recomputeOnRetry: true, // Optional: recompute session if a test retries
}).then((user) => {
cy.log(`Using cached/created user: ${JSON.stringify(user)}`);
cy.wrap(user).as('currentUser'); // Alias the user data for the test
createdUserId = user.id; // Ensure ID is updated for current test run
});
});
it('should display the dashboard for the logged-in user', () => {
cy.get('.welcome-message').should('be.visible').and('contain', 'Welcome, testuser');
cy.get('@currentUser').its('id').should('eq', createdUserId);
});
it('should allow the user to access their profile page', () => {
cy.visit('/profile');
cy.get('.profile-details').should('contain', `User ID: ${createdUserId}`);
});
after(() => {
// Cleanup the created user from the backend after all tests complete
// This ensures a clean state for subsequent test runs
if (createdUserId) {
cy.request('DELETE', `/api/users/${createdUserId}`, { failOnStatusCode: false });
}
});
});