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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use the smallest stopping mechanism that matches your intent. Return from a normal JavaScript function or from a Cypress .then() callback to stop that callback successfully. Throw an Error when the condition should fail the test, call Mocha’s this.skip() when the test is not applicable, and use Cypress.stop() only when you want to stop the remaining tests in the current spec.

Cypress commands are queued, so a JavaScript return cannot retract commands that were already enqueued elsewhere. Put commands that might be skipped inside the conditional branch where the decision is made.

Choose what “terminate” should mean

There are four different scopes in Cypress. Decide the intended test outcome before choosing an API.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Goal Use Result
Leave the current function or callback successfully return The current JavaScript function ends. Cypress continues with commands already in its queue.
Mark the test as failed throw new Error('message') Cypress fails the test and does not continue its remaining test commands.
Mark the test as skipped or pending this.skip() Mocha skips the current test at runtime.
Stop later tests in this spec Cypress.stop() The runner stops the remaining tests in the current spec file.

Cypress does not have a “passed, but stopped early” status. A test ultimately passes, fails, or is pending/skipped, so select the behavior that communicates the real reason for stopping. See the official Conditional Testing guide.

Exit a normal JavaScript function

For ordinary synchronous JavaScript, return exits only the function that contains it. The caller receives the returned value and decides what to do next.

function validateConfig(config) {
  if (!config || !config.baseUrl) {
    return false
  }

  // Work that should happen only for a valid configuration.
  return true
}

if (!validateConfig({})) {
  console.log('Configuration is incomplete')
}

This does not stop a Cypress test runner by itself. It only controls JavaScript execution in that function.

Pass early from a Cypress callback

The reliable pattern is to make the condition inside .then() and enqueue later Cypress commands only when the condition allows them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
it('continues only when the prerequisite is present', () => {
  cy.get('a').then(($links) => {
    const conditionFailed = $links.length === 0

    if (conditionFailed) {
      return
    }

    cy.get('[data-testid="next-step"]').click()
  })
})

When conditionFailed is true, the callback returns before the click command is added. The test can still pass if no assertion or later command requires that step.

Do not queue the work at the top level

This does not provide an early exit:

cy.get('a')
cy.get('[data-testid="next-step"]').click()

cy.get('a').then(($links) => {
  if ($links.length === 0) {
    return
  }
})

The click was already queued before the condition was evaluated. Returning later cannot cancel it. Move the click into the .then() branch, or use a conditional flow that decides before adding subsequent commands.

Fail the test when the condition fails

If the condition represents a defect, throw an error from the callback. Cypress reports the test as failed and stops executing the test’s remaining commands.

it('requires an authenticated account', () => {
  cy.get('[data-testid="account-menu"]').then(($menu) => {
    if ($menu.length === 0) {
      throw new Error('Account menu was not rendered; authentication failed')
    }

    cy.get('[data-testid="billing"]').click()
  })
})

Use a specific message that identifies the missing state and, when useful, the expected selector or prerequisite. Do not throw merely to escape a branch that should be a valid pass or skip.

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.

Skip a test that is not applicable

Mocha’s runtime skip API is this.skip(). It requires a regular function () {} callback because Mocha binds its context to this; an arrow function does not bind that context.

describe('billing', function () {
  it('shows invoices for eligible accounts', function () {
    cy.get('[data-testid="account-type"]').then(($type) => {
      if ($type.text().trim() !== 'paid') {
        this.skip()
      }

      cy.get('[data-testid="invoices"]').should('be.visible')
    })
  })
})

Use this for a legitimate applicability decision, such as a feature unavailable to a particular account tier. If the account should be paid but is not, fail the test instead.

Why an arrow callback fails

it('cannot access Mocha context with an arrow', () => {
  // this.skip() is not bound to Mocha's test context here.
})

Change the test callback to function () {} when you need this.skip(). Cypress commands inside the test may still use arrow callbacks; only the callback that needs Mocha’s context must be a regular function.

Stop the remaining tests in a spec

Cypress.stop() is a runner-level control, not a function return. It stops execution of the remaining tests in the current spec file. In cypress run, later tests in that spec are skipped; in cypress open, execution stops while the app remains available for inspection. When recording to Cypress Cloud, screenshots, videos and Test Replay still upload. Cypress documents the API at Cypress.stop().

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
describe('deployment smoke tests', function () {
  it('stops this spec when the environment is unusable', function () {
    cy.request({
      url: '/health',
      failOnStatusCode: false
    }).then((response) => {
      if (response.status !== 200) {
        Cypress.stop()
        return
      }

      cy.visit('/')
    })
  })

  it('will not run after the stop in this spec', function () {
    cy.log('This is skipped when the previous test calls Cypress.stop()')
  })
})

Place return immediately after Cypress.stop() when the same callback, hook or block contains statements that must not execute. Cypress notes that code after Cypress.stop() in the current beforeEach or afterEach can still run. This mechanism affects the current spec, not every machine or spec in a parallel run. Cypress Cloud’s Auto Cancellation is a separate run-wide feature documented as available on the Business+ plan.

Make conditional checks reliable

Branching on a transient DOM snapshot is a common source of flaky tests. A class, text node or element may change immediately after you inspect it, producing different outcomes on different runs.

Prefer deterministic state

  • Arrange the account, feature flag or server response before visiting the page.
  • Use a stable data attribute such as data-testid rather than presentation classes.
  • Expose an API response or application state that unambiguously determines whether the branch applies.

Use retryable assertions for required states

Cypress assertions retry until they pass or time out, and many commands have implicit assertions. For a state that must exist, assert it directly rather than reading a one-time snapshot.

cy.get('[data-testid="ready"]')
  .should('be.visible')
  .and('have.attr', 'data-state', 'complete')

cy.get('[data-testid="next-step"]').click()

If absence is the actual business rule, make that rule deterministic—for example, seed an account without the feature—rather than checking whether a loading transition happens to have finished.

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

Common errors and fixes

“I returned, but Cypress still clicked”

Cause: the click was enqueued before the callback evaluated the condition.

Fix: move the click and all dependent commands inside the .then() branch that continues.

“The test passed even though the prerequisite was missing”

Cause: return is a successful early exit.

Fix: throw an error when absence is a defect, or use this.skip() when the test genuinely does not apply.

“this.skip is undefined”

Cause: the test was declared with an arrow callback.

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

Fix: declare the test or suite callback with function () {}.

“Cypress.stop did not stop the next statement”

Cause: stopping the runner does not automatically return from the current JavaScript block.

Fix: write Cypress.stop(); return and keep cleanup that must run in a deliberately structured hook.

“Conditional tests pass locally but fail in CI”

Cause: the branch depends on changing DOM timing.

Fix: control application state, wait on a deterministic network or UI signal, and use retryable assertions.

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

A practical decision sequence

  1. Identify the scope: function, callback, current test, or remaining spec.
  2. Choose the outcome: pass, fail, or skip.
  3. Ensure commands that may be omitted have not already been queued.
  4. Evaluate a deterministic signal, preferably one established before the UI changes.
  5. Return immediately after a stop call if code in the same block must not run.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your Cypress workflow mainly exists to capture a page image or PDF for a report, ScreenshotNeo can make that capture a single HTTP request. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.

With the API, pass the target URL and save the returned image:

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 documentation for all capture options, including full-page and element screenshots, device and viewport settings, custom JavaScript and CSS, waiting rules, request blocking, cookies and headers, PDF output, caching, signed links, asynchronous jobs and bulk capture.

The same request in Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Or Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

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

FAQ

Can I stop a Cypress test without failing it?

Yes. Return from the relevant callback, or call this.skip() when the test is not applicable. A successful early return is still a passing test, not a separate “stopped” status.

Does Cypress.stop stop every spec in a parallel run?

No. It stops remaining tests in the current spec. Stopping work across machines is a separate Cypress Cloud Auto Cancellation capability.

Should I use cy.then or cy.should for branching?

Use .then() when you need one deliberate decision and conditional command enqueueing. Use retryable assertions such as .should() when the state must eventually satisfy a condition.

Frequently Asked Questions

Can I stop a Cypress test without failing it?

Yes. Return from the relevant callback, or call this.skip() when the test is not applicable. A successful early return is still a passing test, not a separate “stopped” status.

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.

Does Cypress.stop stop every spec in a parallel run?

No. It stops remaining tests in the current spec. Stopping work across machines is a separate Cypress Cloud Auto Cancellation capability.

Should I use cy.then or cy.should for branching?

Use .then() for one deliberate decision and conditional command enqueueing; use retryable assertions such as .should() when the state must eventually satisfy a condition.

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.