Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

cy.session() does not stop Cypress beforeEach or a Cucumber Before() hook from running. Instead, put the login flow inside a reusable helper that calls cy.session(), then invoke that helper from the hook for tests that need authentication. Cypress can restore a valid cached browser session, while the hook still runs any navigation or scenario-specific setup required for each test.

Why the hook still repeats

Hooks and sessions solve different problems. Cypress runs beforeEach before every applicable test; the Cucumber preprocessor’s imported Before() runs for each matching scenario. cy.session() can avoid repeating the expensive authentication callback when the same valid session is restored, but it does not change either hook’s lifecycle. See the Cypress hook documentation, session documentation, and Cucumber preprocessor hook guide.

The useful distinction is: a hook may run for every test or scenario, but the login flow inside a session wrapper need not. Keep work that must happen every time—such as visiting a page, creating scenario data, or making assertions—in the hook or test body.

Put login inside a reusable cy.session helper

Define one custom command or helper and make the full repeatable authentication sequence its session setup callback. The following JavaScript example is illustrative: replace selectors, URLs, credentials, and the validation request with the equivalents for your application.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Cypress.Commands.add('login', (username) => {
  cy.session(username, () => {
    cy.visit('/login')
    cy.get('[data-test=username]').type(username)
    cy.get('[data-test=password]').type(Cypress.env('password'))
    cy.get('form').submit()
    cy.url().should('include', '/dashboard')
  }, {
    validate() {
      // Check that the restored authentication is still valid.
      cy.request('/api/me').its('status').should('eq', 200)
    },
  })
})

Then call the command where authentication is needed, and keep per-test navigation outside the login setup:

beforeEach(() => {
  cy.login('test-user')
  cy.visit('/dashboard')
})

On a cache miss, Cypress runs the setup callback and stores the session. On a later call with the same valid ID, Cypress can restore that session instead of running the login sequence again. If validation fails after restoration, Cypress reruns setup. Cypress recommends wrapping cy.session() in a login custom command or reusable wrapper; details and options are in the cy.session reference.

Choose an ID for the authentication context

The session ID should be stable and distinguish contexts that must not share authentication state. A username is suitable only if it fully identifies the context for your tests. If roles, tenant, locale, or another setting changes the resulting session, include the relevant non-secret context in the ID. Do not put passwords or tokens in IDs: Cypress notes that IDs appear in the reporter.

For cross-spec reuse, Cypress cautions that calls must use the same ID, setup, validation, and cacheAcrossSpecs configuration wherever that session is called. Treat these as one shared contract rather than subtly changing the helper between specs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Validate what matters to the application

The example validates with an authenticated API request, but the right check depends on how your app proves a session is valid. A check should fail when the restored browser state is expired or unusable, so Cypress can rebuild it. Avoid a check that always passes regardless of authentication: it can let a stale session reach the test and fail later in a less obvious place.

Use Cucumber hooks at the scope you actually need

With @badeball/cypress-cucumber-preprocessor, import its hooks from the package. Use tag filtering when only some scenarios require login:

import { Before } from '@badeball/cypress-cucumber-preprocessor'

Before({ tags: '@authenticated' }, () => {
  cy.login('test-user')
})

This Before() hook remains scenario-scoped: it runs before every scenario matching @authenticated. The login callback can be skipped on a valid session restoration, but the hook itself is not skipped. Put scenario navigation or setup that must recur in the hook or step definitions.

When BeforeAll is appropriate

Use BeforeAll() for work genuinely intended once before scenarios in a feature. It is analogous to Cypress before(), not a replacement for per-scenario session restoration. Moving login to BeforeAll() simply to avoid repeated setup can leave later scenarios relying on shared state that is not available or appropriate under the suite’s isolation rules.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For the package’s current hook and quick-start patterns, see its quick start and hook guide. Those repository documentation links point to the moving master branch; verify the API against the version installed in your project.

Make sure the hook file is paired with the feature

A correctly written hook will not run for a feature if its definition file is not paired with that feature by the preprocessor’s stepDefinitions configuration. Conversely, a broad glob can pair files widely and make hooks apply to more features than intended. Check the pairing configuration as well as the hook code. The preprocessor explains this behavior in its step-definition pairing guide.

  1. Find the preprocessor configuration and inspect its stepDefinitions patterns.
  2. Confirm the file containing the imported Before() is paired with the feature in question.
  3. Confirm the glob is not unintentionally pairing the hook with unrelated features.
  4. Check whether the hook’s tag expression matches the scenario’s tags.

Know what cy.session restores—and what it does not

Cypress documents cy.session() as caching and restoring cookies, localStorage, and sessionStorage. It does not preserve IndexedDB. If the application’s authentication or scenario state depends on IndexedDB, set up or clear that data explicitly rather than assuming it is part of the session snapshot. Refer to cy.session and test isolation.

Page behavior depends on the testIsolation setting, and Cypress clears cookies and web storage before session setup regardless of that setting. Disabling isolation is not a general way to prevent repeated hooks: it changes which browser state carries across tests and can make tests order-dependent. Use it only when the suite is deliberately designed for shared state.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the right setup scope

Need Where it belongs What still repeats
Every Cypress test needs authentication A beforeEach that calls the session-backed login helper The hook and any per-test work; the login setup can be restored from a valid session
Only selected scenarios need authentication A tag-filtered Cucumber Before() that calls the helper The hook for each matching scenario; the login setup can be restored
One-time feature-level preparation Cucumber BeforeAll(), only for work intended once Scenario hooks and scenario-specific work remain separate
Independent state is important Keep normal test isolation and restore the needed session Each test still receives the isolation behavior configured by Cypress
Shared browser state is intentional Consider isolation settings only as part of a deliberately designed suite Tests may become order-dependent if they rely on state left by earlier tests

The best placement depends on scope, login cost, isolation needs, and whether the hook definition file is paired with the relevant feature. There is no hook setting that makes a per-scenario Before() run only once while preserving its scenario scope.

Check versions and configuration before changing the pattern

The preprocessor documentation currently demonstrates imported hooks such as Before and BeforeAll, but the linked pages are on master and do not establish which version your project has installed. Check your Cypress and @badeball/cypress-cucumber-preprocessor versions, the project’s hook imports, stepDefinitions pairing, and testIsolation configuration before adopting code verbatim. The quick start shows the newer plugin configuration; projects on other versions may differ.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance and reliability expectations

Cypress’s performance guide gives an illustrative estimate of 2–5 seconds per test for a typical full login flow and 3–8 minutes across 100 tests in its example. Those are examples from Cypress, not a benchmark of your application or a guaranteed speedup. Measure your own suite before and after introducing session reuse; time spent on navigation, data setup, and assertions will still remain when those tasks run for every test. See Cypress’s test performance guide.

Reliability depends on making the session ID, setup, and validation agree about what counts as the same usable login. Keep the login flow deterministic, validate actual authenticated access, and leave scenario-specific state management in the scenario’s lifecycle.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshooting repeated logins

The full login form still appears for every test

  • Confirm the login flow is inside the cy.session() setup callback, not before or after the call.
  • Confirm each call uses the same ID for the same authentication context.
  • Check whether the validation callback fails after restoration; a failure intentionally causes setup to run again.

The hook runs even when the session is cached

This is expected. Hooks run according to Cypress and Cucumber lifecycle rules; session caching optimizes the authentication setup, not hook scheduling. Keep the hook if its per-test work is required.

The Cucumber hook never runs

  • Verify the hook file is paired to the feature through stepDefinitions.
  • Check the tag expression and ensure the scenario has the expected tag.
  • Confirm the import and configuration match the installed preprocessor version.

A test passes alone but fails after another scenario

Inspect assumptions about shared cookies, web storage, IndexedDB, and testIsolation. Do not depend on the previous scenario’s page or browser state unless the suite is intentionally configured for it. Restore required state explicitly in each scenario.

Session reuse works in one spec but not across specs

For cross-spec reuse, align the ID, setup, validation, and cacheAcrossSpecs configuration wherever the session is used. A mismatch means the calls do not share the same configured session contract.

Or skip the browser setup

If your goal is to capture a website screenshot rather than exercise your application through Cypress, ScreenshotNeo provides a screenshot API and MCP server for developers. One GET request can return an image or PDF; its cleanup removes known consent banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, and failed loads are never billed, and an MCP server lets AI agents use screenshot tools.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Its free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Learn about ScreenshotNeo or sign up for 1,000 free screenshots a month, with no card required.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.