Q25 of 48 · Cypress
Explain the difference between cy.wrap and cy.then.
Short answer
Short answer: `cy.wrap(value)` puts a JavaScript value into the Cypress chain so you can run Cypress commands on it. `cy.then(fn)` pulls the *current subject* out of the chain so you can run plain JS on it. They're inverses: wrap goes JS → Cypress, then goes Cypress → JS.
Detail
Cypress chains operate on a "subject" — cy.get('.foo') yields a jQuery-wrapped element as the subject, and the next command (.click(), .should(...)) operates on that subject. The two boundaries between Cypress's queue and plain JavaScript are wrap and then.
cy.wrap(value) takes any value (an element, a promise, a primitive, an object) and yields it as the chain subject. Useful when:
- You have a value from outside the chain and want to assert on it:
cy.wrap({ id: 1 }).should('have.property', 'id', 1). - You're inside a
.thenand want to return to the chain:cy.then(($el) => { ... return cy.wrap($el); }). - You're working with a promise from a non-Cypress source:
cy.wrap(somePromise).then(...).
cy.then(fn) is the opposite — it gives you the current subject as a JS value inside a callback:
cy.get('h1').then(($el) => {
const text = $el.text();
expect(text).to.include('Welcome'); // standalone Chai
cy.wrap(text).should('eq', 'Welcome'); // back into the chain
});
The crucial difference: code inside .then doesn't auto-retry. Querying the DOM inside .then snapshots the value once; if the DOM updates, your snapshot is stale. So prefer chained .should for retry-sensitive checks, and reserve .then for situations where you genuinely need the value as plain JS.
// EXAMPLE
// cy.wrap — bring JS into the chain
const expectedUser = { id: 'u1', email: 'alice@x.com' };
cy.wrap(expectedUser).should('have.property', 'email', 'alice@x.com');
// cy.then — pull subject out as JS
cy.get('[data-test=cart-row]').then(($rows) => {
expect($rows).to.have.length(3);
// Plain JS — no retry
const ids = [...$rows].map((el) => el.dataset.id);
expect(ids).to.deep.equal(['p1', 'p2', 'p3']);
});
// Combined — read text, transform, assert via chain
cy.get('[data-test=total]')
.invoke('text') // string
.then((s) => parseFloat(s.replace('£', '')))
.should('be.greaterThan', 0);