ScreenshotNeo

BlogHow-to

How to Debug Cypress Test Failures with Code Frames

Use Cypress error views, code frames, Command Logs, source maps, and CI evidence to trace a failing test to its cause and fix.

By the ScreenshotNeo team4 October 20268 min read

A Cypress code frame shows where Cypress reported a failure in your test or application code. To find the cause, read the error message, follow the linked file and line, inspect the highlighted code and stack trace, then correlate that location with the Command Log and browser state. If the frame is missing or points into generated code, check source maps. For intermittent or CI-only failures, compare timing and environments and use captured run evidence.

A code frame is a location clue, not a complete diagnosis. The underlying cause may be an earlier application error, an unfinished request, test data, or an expectation that no longer matches the page.

1. Read the Cypress error view

  1. Read the error name and message. Identify whether Cypress reports an assertion mismatch, a command timeout, an actionability problem, or another command error. The message usually narrows the first thing to investigate.
  2. Note the linked source file, line, and column. Follow the location Cypress reports. It may open in your configured editor; stack frames in DevTools can also be clickable.
  3. Read the highlighted code frame. Look at the surrounding lines and the exact highlighted position. Check whether the failing statement is the original source or generated/transpiled code.
  4. Expand the stack trace. Follow the call path to see which test or application code led to the reported command. Cypress can also print the full error in the browser DevTools console.

Do not change the highlighted line automatically. For example, an assertion can be correctly reporting that a button never appeared because an earlier request failed or the page did not reach the expected state. Trace the sequence before editing the assertion.

2. Correlate the frame with the Command Log and browser

In Cypress open mode, select the failing command in the Command Log. Inspect the command, its subject, and the yielded result. Then look at the page and the commands immediately before the failure. Ask what state each command expected and whether the application had reached that state.

When the failure is reproducible locally, use cy.pause() to stop between Cypress commands. While paused, inspect the DOM, network activity, and browser storage in DevTools, then resume to see which step changes the state.

describe('checkout', () => {
  it('shows the order confirmation', () => {
    cy.visit('/checkout');

    cy.intercept('POST', '/api/orders').as('createOrder');
    cy.get('[data-cy=place-order]').click();
    cy.wait('@createOrder');

    // Pause here to inspect the page and browser state.
    cy.pause();

    cy.get('[data-cy=confirmation]').should('be.visible');
  });
});

Cypress commands are queued. A JavaScript debugger placed directly after a cy command may not pause where you expect, because the Cypress command has not executed in the ordinary synchronous sequence. Use Cypress’s pause workflow to step through queued commands.

3. Fix missing or misleading code frames with source maps

Cypress maps runtime stack traces from generated browser code back to authored files using source maps. Its default spec handling includes an inline source map. A custom preprocessor or TypeScript setup can change that behavior; without inline source maps, Cypress cannot display code frames for the mapped source.

Check the configuration that actually preprocesses your spec. For the documented webpack and esbuild preprocessors, the relevant settings are:

// webpack configuration used by the Cypress preprocessor
module.exports = {
  devtool: 'inline-source-map',
};
// esbuild preprocessor options
const options = {
  sourcemap: 'inline',
};

For TypeScript using a custom preprocessor, enable source maps in tsconfig.json:

{
  "compilerOptions": {
    "sourceMap": true
  }
}

Cypress specifically cautions that inlineSourceMap is not recommended for an accurate code frame. After adjusting the preprocessor or TypeScript configuration, rerun the failing spec and check that the frame points to the authored file and meaningful line. A better mapping helps locate the code; it does not explain why the application reached the failing state.

See the [Cypress debugging guide](https://docs.cypress.io/app/guides/debugging) and [preprocessor API](https://docs.cypress.io/api/node-events/preprocessors-api) for configuration details.

4. Make timing-dependent tests wait for the right condition

A common source of flaky failures is asserting on UI before the operation that drives it has finished. Avoid fixed delays as the default fix: they can make a test slower without making the state transition reliable. Instead, synchronize with the relevant request and assert on the resulting UI.

cy.intercept('GET', '/api/products').as('getProducts');
cy.visit('/products');
cy.wait('@getProducts');
cy.get('[data-cy=product-list]').should('be.visible');
cy.get('[data-cy=product-card]').should('have.length.greaterThan', 0);

Add assertions around required steps so the first failed prerequisite is visible. When a command times out, determine whether the selector is wrong, the application is stuck, a request failed, or the test is checking too early. Cypress’s guide discusses [debugging and race conditions](https://docs.cypress.io/app/guides/debugging).

5. Diagnose failures that occur only in CI

First compare the local and CI conditions: commit and build output, browser, operating system, environment variables, test data, and relevant service responses. A test can behave differently when timing or the environment changes, even when the source location is the same.

  1. Use the original failed run’s evidence. Inspect its screenshot and video if available. If the run was recorded in Cypress Cloud and Test Replay is available to your project, revisit the captured execution and error context. Availability and plan terms can change; check Cypress’s current [CI debugging documentation](https://docs.cypress.io/cloud/guides/debug-failing-tests).
  2. Reproduce visibly when the failure is headless-only. Run the affected spec locally with the same browser where possible. Cypress documents --headed and --no-exit as options for keeping the browser visible and Cypress open to inspect the final state and Command Log.
  3. Compare dependencies on the server. Check whether the UI depended on a request or setup step that was incomplete, failed, or returned different data in CI.
  4. Reduce the test. Split an oversized spec or long test, then remove steps until you have the smallest case that still fails. This helps distinguish a test-specific issue from browser, setup, or environment behavior.

A failed attempt may appear in the Command Log even if a retry later passes. Check the final test result and retry history before treating an earlier failed attempt as the final outcome; see Cypress’s guide to [writing and organizing tests](https://docs.cypress.io/app/core-concepts/writing-and-organizing-tests).

6. Capture a screenshot when the failure concerns visual state

A screenshot can preserve what the browser rendered at a point in the test. Use it when the question is whether a page was blank, a component was missing, or a visual state differed. Screenshots do not replace the error message, code frame, or command sequence: they show pixels, not the JavaScript call path or why a request failed.

For local or CI inspection, use the screenshots and videos produced by your Cypress workflow. If you need a standalone browser capture for a page, Cypress app, or rendered state, ScreenshotNeo is a screenshot API and MCP server. It is useful for capturing the page itself; it does not inspect Cypress’s error view, test stack, or CI run.

Or skip the browser setup

For a standalone page capture, ScreenshotNeo accepts a URL and returns an image or PDF. This example saves a WebP screenshot; see the ScreenshotNeo API documentation for options and formats.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before a shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, no card required.

Troubleshooting checklist

Symptom Likely cause What to check or change
No code frame appears Missing inline source maps or a custom preprocessor that omits them Check the preprocessor’s source map setting and TypeScript sourceMap; rerun the spec.
Frame points into bundled or generated code Generated code is not mapped to the authored source, or the map does not match the build Verify inline maps are produced by the active preprocessor and correspond to the current build.
Assertion says an element is absent Wrong selector, earlier app failure, or UI checked before its prerequisite completed Inspect earlier Command Log entries, network activity, selector state, and the failed run’s screenshot.
Test passes locally but fails in CI Timing, browser, build, data, or environment differs Compare conditions, wait for the relevant request, inspect CI artifacts, and reduce the reproduction.
debugger does not pause after a Cypress command Cypress commands are queued and execute later Use cy.pause() to inspect state between commands.
Application exception fails the test Cypress detected an uncaught exception from the application Investigate and fix the app error. Do not suppress exceptions globally as a first response; only handle a known, intentional exception narrowly.

Performance, reliability, and diagnostic cost

  • Prefer condition-based waits. Waiting on a relevant request and asserting the resulting UI is generally more reliable than adding arbitrary delays.
  • Use pause and verbose logging selectively. They help explain a reproduction but slow execution or produce substantial output. Cypress supports DEBUG=cypress:* for verbose diagnostics; its troubleshooting guide warns that debug output can be large and affect performance. Use narrower selectors when possible.
  • Preserve the failing evidence. Screenshots, video, and recorded run context can save time when a local rerun does not reproduce the original CI state. Confirm artifact retention and feature availability in your setup.
  • Keep tests focused. Smaller tests reduce the number of steps to inspect and make failures easier to reproduce, though a split should preserve the setup and state needed to expose the defect.
  • Do not retry away a real defect. Retries can reveal intermittency, but a passing retry does not explain the original failure. Keep the initial error and its evidence in view.

FAQ

Does a code frame always identify the root cause?

No. It identifies the reported source location. The cause may be earlier in the test or application flow, such as a failed request or state transition.

Why does a retry pass when the first attempt failed?

The run may be intermittent because timing, data, or environment state varied. Inspect the failed attempt and compare it with the passing retry instead of assuming the retry fixed the cause.

Should I ignore uncaught application exceptions in Cypress?

Not as a general workaround. Cypress treats uncaught app exceptions as failures; diagnose the exception first. Targeted handling is appropriate only when the exception is known and intentional.

Can a screenshot replace the Cypress error view?

No. A screenshot preserves rendered pixels, while the error view, stack trace, and Command Log provide source and execution context.

Primary Cypress references