Why does a pinned Cypress .click() command offer before and after snapshots?
answer
- Actions are about change, not end state
- One picture cannot show a difference
- The extra one is taken first
- The menu needs two states to exist
- Hover flickers; pinning stops the flicker
basics
~10 sCypress action commands take an extra snapshot immediately before they act on the element, so the entry carries two snapshots named before and after. Pinning the entry reveals a switcher for stepping between them.
solid answer
~50 sMost Cypress commands leave one snapshot, taken when the command finished. An action command such as `.click()`, `.type()`, `.check()` or `.select()` asks the log for a second one just before it dispatches its events, naming the pair `before` and `after` — because what matters about an action is the change it caused, not the end state alone. A query or an assertion leaves a single unnamed snapshot of the state it settled on. The switcher over the preview only renders when the pinned entry has **at least two** snapshots, so a pinned `cy.get()` shows none — the absence is itself a signal that the step changed nothing. While you merely hover an entry holding a pair, Cypress cycles the two states automatically every 800 milliseconds; pinning stops the cycling and hands you manual control, alongside a Highlights toggle and an unpin button.
go deeper
Recall that clicking a command pins it and that action commands give you two states to look at. Knowing which button switches between them is enough at this level.
Explain the mechanism: the action asks for an extra snapshot before it acts, the automatic end-of-command one is named after, and the switcher renders only when an entry holds two or more snapshots.
Demonstrate the diagnosis. Say what the hitbox on the before state and the row on the after state each rule out, and how that splits a failure into a test problem versus an application problem.
Be ready to argue how much of a team's debugging should depend on a local, interactive surface, and what a failure seen only by a pipeline must carry instead.
## A snapshot belongs to an entry, not to a moment in time Every row in the Cypress Command Log carries its own list of snapshots. By default a command leaves exactly one, taken when the command finishes — the state of the page once that step resolved. That is enough for a query: after `cy.get('[data-testid="ticket-row"]')` has yielded twelve rows, one picture of the page tells you everything the step produced. An **action command** is different, because the interesting thing about it is the *change* it caused. A single snapshot of the page after `.click()` shows you the escalated ticket but not the button that was there a moment earlier, and you cannot tell from it whether the click was even possible. ## Why an action command has two Before it dispatches its events, an action command explicitly asks the log for an extra snapshot and names it `before`, and tells the log to name the automatic end-of-command snapshot `after`. The entry therefore ends the step holding a **named pair**. The commands that do this are the ones that change the page: | Command | Snapshots on its entry | Named | |---|---|---| | `.click()`, `.dblclick()`, `.rightclick()` | 2 | `before`, `after` | | `.type()`, `.clear()` | 2 | `before`, `after` | | `.check()`, `.uncheck()`, `.select()` | 2 | `before`, `after` | | `.submit()`, `.trigger()`, `.selectFile()` | 2 | `before`, `after` | | `cy.get()`, `cy.contains()`, `.should()` | 1 | unnamed | | `cy.visit()`, `cy.request()` | 1 | unnamed | An unnamed snapshot is not a defect — there is nothing to distinguish it from, so the switcher labels it by its index instead of by a name. ## The switcher, and when it appears Pin an entry and a small toolbar appears over the application-under-test preview. It carries: - the **snapshot switcher**, one button per snapshot on the entry — `before` and `after` for an action, or `1` and `2` where the snapshots have no names; - a **Highlights** toggle, on by default, which draws or removes the highlight and the red hitbox over the element the command acted on; - an **unpin** button that releases the pin and puts the live page back. The switcher is conditional: **it only renders when the pinned entry has at least two snapshots.** Pin a `cy.get()` and you get the Highlights toggle and the unpin button but no before/after buttons, because there is only one state and nothing to compare it against. That is the quickest way to tell, without reading any documentation, whether a given command captured a pair. ## Hovering cycles; pinning steps The two gestures treat a pair differently, and the difference confuses people the first time: 1. **Hover** an entry with two snapshots and Cypress cycles between them automatically, about every 800 ms. The preview appears to flicker between two states — that is deliberate, and it is often enough on its own to see what an action changed. 2. **Click** to pin and the cycling stops immediately. The switcher appears and you step between `before` and `after` by hand, at whatever pace you want, with the element highlight redrawn on whichever state you land on. So the flicker is the feature announcing itself, and the pin is how you take control of it. ## Reading a before/after pair on a ticket queue Take a spec that escalates the oldest unassigned ticket and fails intermittently, on the assertion that the row's priority became urgent. Pin the `.click()` on the escalate button and step through the pair: - On **`before`**, look at where the red hitbox sits. If it is over the escalate button, the click had a real target. If it is over a toast, a loading overlay or a row that has since moved, the click went somewhere you did not intend and the assertion never had a chance. - On **`after`**, look at the same row. If the button is now in a pending state, the application did receive the interaction and the test is asserting too early. If the row is untouched, the click landed but the handler did nothing — a bug in the application, not in the test. Those two questions — *did the click reach the right element* and *did the application react* — are the first fork in almost every action-command failure, and the before/after pair answers both without re-running anything. ## Two things worth remembering - The pair is **captured, not reconstructed**: the `before` snapshot exists because the command asked for it at the time, so a command that did not ask has no second state to offer you later. - The names are just labels on a list. `cypress tap command` prints the same list as a numbered `SNAPSHOTS` table with a `NAME` column, showing `-` for the unnamed single snapshot on a query.
- You pin a Cypress cy.get() entry and no before/after switcher appears. Is something broken?No. The switcher is rendered only when the pinned entry holds two or more snapshots, and a query leaves a single unnamed one taken when it resolved. You still get the element highlight and the unpin button. The absence of the switcher is itself information: this command did not change the page, so there is no second state to compare.
- Why does the Cypress preview appear to flicker while you hover an action command?Because the entry has two snapshots and hovering cycles them roughly every 800 milliseconds so you can see the change without any clicks. It is a preview, not a rendering glitch. Click the row to pin it and the cycling stops, replaced by a switcher that lets you hold `before` or `after` for as long as you need.
saying these in an interview costs you the question
- Thinks every command captures a before and after pair
- Says Cypress diffs the two snapshots automatically
- Believes the before snapshot is reconstructed afterwards
- Treats the flickering preview as a rendering bug