Skip to main content
Cypress App

last

Get the last DOM element within a set of DOM elements.

info

The querying behavior of this command matches exactly how .last() works in jQuery.

Syntax​

.last()
.last(options)

Usage​

Correct Usage

cy.get('nav a').last() // Yield last link in nav

Incorrect Usage

cy.last() // Errors, cannot be chained off 'cy'
cy.getCookies().last() // Errors, 'getCookies' does not yield DOM element

Arguments​

options (Object)

Pass in an options object to change the default behavior of .last().

OptionDefaultDescription
logtrueDisplays the command in the Command log
timeoutdefaultCommandTimeoutTime to wait for .last() to resolve before timing out

Yields ​

  • .last() yields the last DOM element within the set it was given.
  • .last() is a query, and it is safe to chain further commands.

Examples​

No Args​

Get the last list item in a list​

<ul>
<li class="one">Knick knack on my thumb</li>
<li class="two">Knick knack on my shoe</li>
<li class="three">Knick knack on my knee</li>
<li class="four">Knick knack on my door</li>
</ul>
// yields <li class="four">Knick knack on my door</li>
cy.get('li').last()

Assert on the newest item after adding one with .last()​

A new item often renders at the end of a list after a request resolves. Chain an assertion off .last(), and Cypress re-runs the query until the new item is the last one and the assertion passes.

index.html
<input class="new-todo" />
<ul class="todo-list">
<li>Buy milk</li>
</ul>
<!-- pressing Enter in .new-todo sends a request, then adds the text as a new <li> at the end of the list -->
spec.cy.js
cy.get('.new-todo').type('Write docs{enter}')
cy.get('.todo-list li').last().should('have.text', 'Write docs')

Act on the last row of a table with .last()​

.last() yields a DOM element, so you can keep chaining queries and actions off it.

index.html
<table>
<tbody>
<tr>
<td>Ada</td>
<td><button>Delete</button></td>
</tr>
<tr>
<td>Grace</td>
<td><button>Delete</button></td>
</tr>
</tbody>
</table>
<!-- clicking a Delete button removes its row -->
spec.cy.js
cy.get('tbody tr').last().find('td').first().should('have.text', 'Grace')
cy.get('tbody tr').last().find('button').click()
cy.get('tbody tr').should('have.length', 1)

Options​

Wait longer for the last element with the timeout option​

The timeout you pass to .last() sets how long Cypress retries the whole query chain, including the cy.get() before it. Here, the second notification appears after 6 seconds, which is past the default 4-second defaultCommandTimeout.

index.html
<div class="notification">Saved</div>
<!-- a second .notification with the text "Synced" is added after 6 seconds -->
spec.cy.js
cy.get('.notification').last({ timeout: 10000 }).should('have.text', 'Synced')

Notes​

How .last() compares to .eq(-1)​

.last() yields the same element as .eq(-1). Use .eq() to get an element at any other index, including negative indexes counted back from the end of the set.

Selecting the last element that matches a selector​

.last() takes no selector. cy.get('li').last('.active') yields the last <li> whether or not it has the class active. The Command Log still shows .active as the command's message, which can make it look as though the selector was applied:

Command Log showing get li followed by last with .active as its message, though the selector was not applied

TypeScript flags the call as an error. To get the last element that matches a selector, narrow the set with .filter() before calling .last().

cy.get('li').filter('.active').last()

How .last() compares to the :last-child selector​

.last() yields a single element, the last one in the whole set. The CSS :last-child selector matches the last child of each parent, so it can match several elements when the set spans more than one parent.

<ul class="fruits">
<li>Apple</li>
<li>Banana</li>
</ul>
<ul class="veggies">
<li>Carrot</li>
<li>Daikon</li>
</ul>
cy.get('li').last() // yields <li>Daikon</li>
cy.get('li:last-child') // yields <li>Banana</li> and <li>Daikon</li>

Click a row in the Command Log to pin its snapshot and highlight the elements it yielded. Pinning last highlights only Daikon:

Command Log with the last command pinned and only the Daikon list item highlighted in the app preview

Pinning get li:last-child highlights Banana and Daikon, the last item in each list:

Command Log with the get li:last-child command pinned and both the Banana and Daikon list items highlighted in the app preview

Aliasing the result of .last()​

An alias stores the query chain, not the element it found. Each time you use the alias, Cypress re-runs the chain against the current DOM, so an aliased .last() always yields the element that is last now. Learn more in aliasing DOM elements.

Using the to-do list from the newest item example:

cy.get('.todo-list li').last().as('newest')
cy.get('@newest').should('have.text', 'Buy milk')

cy.get('.new-todo').type('Write docs{enter}')
cy.get('@newest').should('have.text', 'Write docs')

Rules​

Requirements ​

  • .last() requires being chained off a command that yields DOM element(s) or a document.

Assertions ​

  • .last() will automatically retry until the element(s) exist in the DOM.
  • .last() will automatically retry until all chained assertions have passed.

Timeouts ​

  • .last() can time out waiting for the element(s) to exist in the DOM.
  • .last() can time out waiting for assertions you've added to pass.

Command Log​

Find the last button in the form

cy.get('form').find('button').last()

The commands above display in the Command Log as:

Command Log showing last chained after get form and find button

Click the last command in the Command Log to print the following to the console:

Console output for last, listing the two buttons it was applied to and the last button it yielded

History​

VersionChanges
12.6.0Overwrite .last() with Cypress.Commands.overwriteQuery() rather than Cypress.Commands.overwrite().
12.0.0.last() is now a query.

See also​