Click the column header, then assert that the displayed cell values are in the expected order. A reliable Cypress test also checks the grid’s sort-state indicator and accounts for whether the component’s DOM order matches its visual row order.
Write a basic sorting test
Start with deterministic data, scope commands to the table or grid, click the header as a user would, and inspect the rendered values. The following pattern is adapted from Cypress’s Sorting the Table recipe and uses Ag-Grid-specific selectors; use the equivalent selectors for your component.
cy.get('#myGrid').within(() => {
cy.contains('.ag-header-cell-label', 'Price').click()
cy.contains('.ag-header-cell-label', 'Price')
.find('[ref=eSortAsc]')
.should('be.visible')
cy.get('[col-id=price].ag-cell')
.then((cells) => [...cells].map((cell) => Number(cell.textContent)))
.then((prices) => {
const expected = [...prices].sort((a, b) => a - b)
expect(prices).to.deep.equal(expected)
})
})
The test performs two distinct checks: the header reports ascending sort, and the values are actually ascending. A changed arrow alone does not prove the records are ordered correctly. These Ag-Grid selectors are examples, not Cypress conventions.
For a standard HTML table
Target the table’s body rows and the cell in the column under test. For example, for a table with a second-column numeric value:
#1 Best Overall
cy.get('table#orders').within(() => {
cy.contains('thead th', 'Price').click()
cy.get('tbody tr')
.then(($rows) => [...$rows].map((row) => Number(row.cells[1].textContent)))
.then((prices) => {
expect(prices).to.deep.equal([...prices].sort((a, b) => a - b))
})
})
Change the table selector, header text, and cell index to match your markup. If rows can be inserted, removed, or paginated, first establish which rows should be present; otherwise the assertion may validate only the currently rendered subset.
Normalize values before comparing
Text read from cells is a string. Convert numeric text to numbers before testing numeric order. JavaScript’s default array sort compares string representations, so values such as 100 and 20 can end up in lexicographic rather than numeric order. MDN documents the numeric comparator pattern (a, b) => a - b in its Array.prototype.sort() reference.
Rank #2
Also note that sort() mutates the array it sorts. Copy the observed values first, as in [...prices].sort(...), so creating the expected order does not change the values you are asserting.
- Numbers: parse or convert cell text before comparing; decide how to handle currency symbols, grouping separators, empty cells, and invalid values.
- Text: compare according to the application’s intended case and locale behavior. If the product uses locale-sensitive ordering, the test should encode that contract rather than assume a generic order.
- Dates: normalize displayed dates to comparable timestamps or a consistently parsed representation; do not rely on lexicographic display order unless the format guarantees it.
Make sure your assertion follows displayed row order
A grid can look sorted while keeping its row elements in their original DOM sequence. In Cypress’s Ag-Grid example, rows were visually repositioned with translateY, and a row-index attribute represented displayed position. A raw sequence of cell elements therefore did not necessarily represent the visible order. The recipe’s correction associates values with row indices, orders the pairs by that index, and checks the resulting values.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallRank #3
cy.get('#myGrid').within(() => {
cy.contains('.ag-header-cell-label', 'Price').click()
cy.get('[col-id=price].ag-cell')
.then(($cells) => [...$cells].map((cell) => ({
rowIndex: Number(cell.closest('[row-index]').getAttribute('row-index')),
price: Number(cell.textContent),
})))
.then((rows) => {
const displayedPrices = rows
.sort((a, b) => a.rowIndex - b.rowIndex)
.map((row) => row.price)
expect(displayedPrices).to.deep.equal(
[...displayedPrices].sort((a, b) => a - b)
)
})
})
This is illustrative only: confirm that your grid exposes a meaningful displayed-order signal, and adapt the selector and attribute accordingly. Virtualized grids may render only visible rows, so a DOM query may not include every record. In that case, assert the visible page or use the component’s supported mechanism to inspect the data set you intend to verify. Avoid testing a private implementation detail unless it is the only reliable way to establish displayed order.
Wait for a meaningful state, not a fixed delay
The Cypress recipe includes .wait(1000) to slow the example down for demonstration, but a fixed wait is usually unnecessary in a test. Use retryable Cypress queries and assertions for the completed sort state, such as the expected indicator or ordered values. Cypress’s API overview explains how queries read application state and retry.
Rank #4
For asynchronous data grids, make the test’s starting state deterministic and wait on a meaningful application condition before clicking—for example, the expected rows becoming visible. Then assert the post-click state. Do not use an arbitrary pause as a substitute for knowing which state must be ready.
Check the sort direction contract
Keep the direction assertion separate from the data-order assertion. A visible ascending or descending indicator tells you what direction the control claims to use; comparing cell values tells you whether the rendered records follow it. If the table is accessible, include its accessibility state in the test contract. MDN’s aria-sort reference describes using aria-sort on sortable table headers to communicate the current direction. Components may expose a different accessibility contract, so assert the markup and state your component actually provides.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Keep the test independently runnable
Set up the table’s initial rows as part of the test or its own isolated setup. Do not rely on a preceding test to leave the table unsorted or to seed particular records. Cypress’s test-writing guide recommends tests that pass independently and notes that end-to-end test isolation is enabled by default.
Troubleshoot common failures
- Values look sorted but the assertion fails: check whether DOM sequence differs from displayed order. Inspect the grid’s rendered markup and use its displayed-position signal, or assert a user-visible representation.
- Numbers sort unexpectedly: confirm cell text is normalized to numbers and that the expected array uses a numeric comparator, not bare
sort(). - The direction indicator passes but values do not: keep both assertions; the indicator alone can pass even if row sorting is broken or stale.
- The click does not find a header: confirm the exact accessible or visible header text and selector in the rendered component. Avoid carrying Ag-Grid selectors into ordinary tables or other grids.
- The result changes across runs: make the input rows and initial sort state deterministic, and avoid depending on test execution order.
- Only some records are checked: determine whether pagination or virtualization means only a subset is rendered, then align the assertion with the intended scope.
- The test needs a long wait: replace fixed time with a retryable assertion on a real completion signal, such as the updated sort state or expected row order.
Or skip the browser setup
For a screenshot of a page after you have verified it—or any other URL—ScreenshotNeo offers a one-request screenshot API. Its browser-side behavior is separate from Cypress assertions: it captures a page rather than testing whether your table sorted correctly. Configure the target URL and desired output using the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://stripe.com
-o shot.webp
ScreenshotNeo accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for the free plan.
Frequently Asked Questions
Does Cypress sort the table automatically?
No. Cypress drives the page and checks its state; the application’s table or grid implements sorting.
Free tools Windows power users keep installed
One-click scans. No signup required.
Can I use the same selectors for every data grid?
No. Selectors such as Ag-Grid’s header label, cell class, or row index are specific to its rendered markup. Inspect and test the contract of the grid in your application.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




