skip to content

In Cypress, what does a Command Log snapshot actually store about the page?

level: juniorimportance: should knowfreq 60%

answer

  1. It is a copy, not a recording
  2. Cloned into a detached document
  3. Some tags never make the clone
  4. Styling is captured on its own track
  5. importNode, stripped script and style tags

basics

~20 s

A Cypress snapshot is a deep clone of the page's body taken when a command ran, with script and style tags stripped out, plus the html attributes, the CSS and the URL. It is not a video or an image.

solid answer

~50 s

Each time a command writes an entry into the Cypress Command Log, Cypress deep-clones the live `<body>` into a detached document with `importNode` — not `cloneNode` on the real page, because cloning a custom element in place can fire that element's own callbacks and change the application under test. From that clone it removes every `<script>`, `<style>` and `<link rel="stylesheet">`. It then records the attributes on the `<html>` element and the URL at that moment, and collects the page's CSS on a separate track: a stylesheet whose rules the browser lets it read is stored as rule text, deduplicated by content hash, while one it cannot read is stored as a bare `href`. Restoring swaps the live body for that clone and re-inserts the recorded styles. So a snapshot is a static structural copy of the DOM at one instant, and deliberately not a recording.

code

javascript · 10 lines
javascript
describe('support ticket queue', () => {
  it('escalates the oldest open ticket', () => {
    cy.visit('/queue')
    // each of these three commands stores its own snapshot:
    // a clone of <body>, the <html> attributes, the URL and the page CSS
    cy.get('[data-cy=ticket-row]').should('have.length', 12)
    cy.get('[data-cy=ticket-row]').first().find('[data-cy=escalate]').click()
    cy.get('[data-cy=queue-banner]').should('contain', 'Escalated')
  })
})

go deeper

for a junior

Be ready to say in one sentence that a Cypress snapshot is a cloned copy of the DOM, not a picture, and that it exists only while the app is open on your machine.

for a middle

Explain the mechanics: the deep clone into a detached document, which tags are removed from that clone, and the fact that CSS is captured on a separate track and re-inserted on restore.

for a senior

Show that you know where the copy stops being trustworthy in a real debugging session, and that you reach for assertions or saved media when the question is behavioural rather than structural.

for a principal

Own the convention: decide what your team treats a snapshot as proof of, and make sure the triage process for a failing suite does not silently assume one exists.

## What a snapshot is Cypress runs your spec **inside the browser, in the same page as the application under test**, so it can reach the live DOM directly rather than through a remote protocol. Every time a command writes an entry into the Command Log, Cypress also takes a **snapshot**: a structural copy of the page as it stood at that instant. That copy is what the runner puts back on screen when you revisit the entry, and knowing exactly what went into it explains almost every surprise you hit debugging a support-ticket queue that only misbehaves under load. ## The four things the capture does 1. **Deep-clones `<body>` into a detached document.** Cypress calls `importNode` against a throwaway document rather than `cloneNode` on the live one. That distinction is deliberate: cloning a custom element in place can fire that element's own lifecycle callbacks and mutate the very application you are trying to observe. 2. **Strips the executable and styling tags out of the clone.** Every `<script>`, `<style>` and `<link rel="stylesheet">` inside the cloned body is removed before the clone is stored. 3. **Records the frame around the body.** The attributes on the `<html>` element are copied — that is how a restored snapshot keeps a `class="theme-dark"` or a `lang` value — and the URL at that moment goes with it, so revisiting a command restores the address as well as the markup. 4. **Collects the page's CSS on a separate track.** Cypress walks the `<link rel="stylesheet">` and `<style>` elements in `head` and in `body` and turns them into an ordered list of styles that travels alongside the cloned body. ## Why the CSS travels separately Stripping styling tags out of the clone and re-adding the styles at restore time is what makes the mechanism affordable: - A stylesheet whose rules the browser lets Cypress read is **stored as rule text**, and that text is hashed so identical sheets captured across hundreds of commands are stored once rather than hundreds of times. - Relative `url()` references inside that text are **rewritten to absolute URLs**, so background images and web fonts still resolve when the rules are re-inserted somewhere else in the document. - Only stylesheets that apply to the screen are captured — a sheet with no `media` attribute, or one whose `media` matches `screen` or `all`. A `media="print"` sheet is skipped entirely. - A stylesheet Cypress cannot read is stored as **just its `href`**, and restoring writes a fresh `<link>` that the browser fetches again at that moment. ## What a snapshot is deliberately not - **Not a video.** Nothing between two commands is recorded. If the ticket queue flickered a spinner for 200 ms between `cy.get()` and `.click()`, no snapshot ever held it. - **Not an image.** It is live DOM, which is why you can open the browser's own element inspector on a restored snapshot and read classes, attributes and computed styles out of it. - **Not a running page.** Its scripts were removed, so a restored snapshot does not respond to clicks, does not re-render, and does not resume timers. - **Not durable.** Snapshots live in the browser's memory for the open-mode session that produced them. Nothing is written to disk, so they do not survive the session and cannot be attached to a bug report. ## Reading a snapshot honestly The practical rule is that a snapshot answers **structural** questions authoritatively and **behavioural** questions not at all: | Question you are asking | Does the snapshot settle it? | |---|---| | Was the `[data-cy=ticket-row]` element in the DOM? | Yes — it is the cloned markup | | What text and attributes did that row carry? | Yes | | Which classes were on `<html>` at the time? | Yes — the attributes are recorded | | What URL was the app on? | Yes — the URL is captured with it | | Did the SLA countdown keep ticking? | No — scripts were stripped | | Did the priority chart draw the right bars? | No — the drawing surface is not captured | | Did the embedded chat widget load? | No — frames are replaced | Reach for the snapshot to answer "what was in the DOM when this command ran". When the question is "what did the page *do*", the snapshot is the wrong instrument and a chain of assertions, a `cy.log()` trail or the run's own saved media is the right one.

  • Why does Cypress clone the body with importNode into a separate document instead of cloneNode?
    Cloning a custom element with `cloneNode` on the live document can trigger that element's own lifecycle callbacks, which would mutate the application under test while Cypress is only trying to observe it. Importing into a throwaway document keeps the clone side-effect free.
  • Does a Cypress snapshot preserve what a user had typed into a form field?
    Yes. The HTML specification's cloning steps for `input` propagate the current value and checkedness, and `textarea` and `option` carry their own equivalents, so typed text and ticked boxes survive the clone even though they are properties rather than attributes.

A snapshot is a pressed flower, not a time-lapse: the shape and the veins survive intact, but nothing about it is still growing.

saying these in an interview costs you the question

  • Calls a Cypress snapshot a screenshot or a video frame
  • Thinks the snapshot is written to disk
  • Assumes the snapshot is the whole document, not the body
  • Believes scripts are preserved so the copy stays interactive