Recommended Free Tools
Use cy.press() to move focus and .type() only on the editor that should receive text. In AG Grid, the cell you select and the input or contenteditable element opened for editing are often different focus targets. Click or navigate to the cell, start edit mode with the grid’s configured key, assert the editor has focus, type into that editor, then re-query the DOM to verify both the value and the focus state you need.
Why focus appears to “leave” the AG Grid cell
A grid cell is usually a container such as a div. It may have the grid’s cell-focus class while an input, textarea, or contenteditable editor inside (or temporarily rendered beside) it owns the browser’s actual focus. Those are two related but distinct states:
- Cell focus: AG Grid knows which cell is active for arrow-key, Enter, or Tab navigation.
- Editor focus: the text-control element receives keyboard and input events.
When editing begins, focus commonly moves from the cell wrapper to the editor. That is expected. The reliable test is not “the wrapper remains focused while text is entered”; it is “the intended editor receives the text, and focus returns to the intended grid target when the application commits editing.” The exact result depends on your AG Grid version, editor, and grid options.
What Cypress .type() actually does
.type(text) requires a DOM subject that Cypress can type into: an input, textarea, an element with contenteditable, the body, or another documented focusable element such as one with tabindex. If that subject is not focused, Cypress first clicks it to bring it into focus, then sends keyboard and input events. Therefore, typing against a cell wrapper or stale element can move focus away from the cell you meant to preserve.
#1 Best Overall
Cypress also documents that it is unsafe to chain further commands that rely on the subject after .type(). Treat the command as an action, then query the editor or cell again for assertions.
The dependable command split: navigation versus text entry
| Task | Preferred command | Reason |
|---|---|---|
| Move between cells with Tab or arrow keys | cy.press() |
Dispatches native keyboard events and is intended for navigation and focus management. |
| Open editing with a single key such as Enter or F2 | cy.press() |
Lets AG Grid handle its normal edit trigger. |
| Insert a string into an editor | .type() |
Generates the text and input events expected by the control. |
| Verify the result | Re-query with cy.get() or a scoped query |
Avoids relying on the subject yielded by .type(). |
Use the key that your application actually configures. AG Grid commonly supports Enter or F2 for editing and arrow keys for movement, but callbacks and options can change those defaults.
A robust test pattern
The following example uses application-owned test IDs. Replace them with the selectors rendered by your grid and editor.
// Select the cell and prove that the cell is the active target.
cy.get('[data-testid="target-cell"]')
.click()
.should('have.focus')
// Let AG Grid enter edit mode using its configured key.
cy.press(Cypress.Keyboard.Keys.ENTER)
// The editor, not the wrapper, should now receive text.
cy.get('[data-testid="cell-editor"]')
.should('be.visible')
.should('have.focus')
.type('new value')
// Re-query after typing; do not depend on the previous subject.
cy.get('[data-testid="cell-editor"]')
.should('have.value', 'new value')
If the editor is a contenteditable element, assert its text instead of a value property:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →cy.get('[data-testid="cell-editor"]')
.should('have.attr', 'contenteditable', 'true')
.should('have.focus')
.type('new value')
cy.get('[data-testid="cell-editor"]')
.should('contain.text', 'new value')
Do not target a child text node or an arbitrary descendant of a contenteditable control. Select the element carrying the contenteditable attribute.
Rank #2
Keeping focus after editing commits
Typing and committing are separate operations. Determine whether your application commits on Enter, Tab, blur, or a custom action, then assert the resulting focus explicitly.
Commit with Enter
cy.get('[data-testid="cell-editor"]')
.should('have.focus')
.type('new value')
cy.press(Cypress.Keyboard.Keys.ENTER)
cy.get('[data-testid="target-cell"]')
.should('have.focus')
Commit and move with Tab
cy.get('[data-testid="cell-editor"]')
.type('new value')
cy.press(Cypress.Keyboard.Keys.TAB)
cy.get('[data-testid="next-cell"]')
.should('have.focus')
Some grids keep focus on the edited cell; others advance to the next cell. Neither outcome is universal. Encode the behavior your product specifies rather than asserting a generic AG Grid outcome.
Navigate to a cell without accidentally typing into the wrong element
For a cell already rendered in the viewport, clicking it is straightforward. For keyboard navigation, start from a known grid target and use native key presses:
cy.get('[data-testid="grid"]')
.click()
cy.press(Cypress.Keyboard.Keys.ARROWDOWN)
cy.press(Cypress.Keyboard.Keys.ARROWRIGHT)
cy.get('[data-testid="target-cell"]')
.should('have.focus')
Virtualized rows can be mounted and unmounted as you scroll. Prefer stable row and column attributes, test IDs, or AG Grid’s own row and column identifiers rather than positional selectors that become stale after scrolling. If the target is not rendered, scroll or use the application’s supported navigation before querying it.
AG Grid settings that change the result
suppressCellFocus
If suppressCellFocus is enabled, AG Grid deliberately disables normal cell focus. A test that expects have.focus on a cell wrapper will fail even when editing works. Either test the editor or change the grid configuration if cell focus is required by the product.
Rank #3
Navigation callbacks
navigateToNextCell and tabToNextCell can override the default destination after arrow or Tab navigation. Assert the callback’s intended target, not the default next row or column.
Custom cell components
A renderer containing a button, link, or input owns internal focus behavior. AG Grid assigns responsibility for keyboard navigation among those internal elements to the custom component. If keyboard events are intercepted, inspect the component’s handling and any suppressKeyboardEvent configuration. You may need to focus the internal control directly, return the correct event-handling value, or provide an explicit handoff to the grid.
Editor lifecycle and asynchronous rendering
Some editors are inserted only after an animation, a framework render, or a data fetch. Query the editor after the edit trigger and use Cypress’s normal retrying assertions rather than a fixed sleep:
cy.press(Cypress.Keyboard.Keys.ENTER)
cy.get('[data-testid="cell-editor"]', { timeout: 10000 })
.should('be.visible')
.should('have.focus')
Common failures and precise fixes
| Symptom | Likely cause | Fix |
|---|---|---|
.type() changes focus unexpectedly |
The subject was not focused, so Cypress clicked it; or the subject was the cell wrapper rather than the editor. | Enter edit mode first, query the actual editor, assert focus, then type. |
| “Element is not typeable” | The selected node is not an input, textarea, contenteditable, or supported focusable element. | Inspect the rendered DOM and select the real control. |
| Cell assertion fails after Enter | Enter moved focus into an editor, or the grid suppresses cell focus. | Assert editor focus while editing; assert cell focus only after the configured commit action. |
| Value assertion intermittently fails | The editor was replaced after typing, or the framework has not committed its value. | Re-query the editor, wait for its value, and verify the committed cell data through the UI or application state. |
| Arrow or Tab changes the wrong cell | A custom navigation callback, pinned column, or component handler changes the default route. | Review navigateToNextCell, tabToNextCell, pinned-column behavior, and suppressKeyboardEvent. |
| Selector works once, then becomes detached | Virtualization or edit mode replaced the DOM node. | Use stable identifiers and re-query after each lifecycle-changing action. |
| Contenteditable text is not found | The test targeted a child node instead of the element carrying contenteditable. |
Select the contenteditable element itself and assert its text. |
Assertions that make focus bugs diagnosable
Keep focus and data assertions separate so a failure identifies the broken contract:
// During editing
cy.get('[data-testid="cell-editor"]')
.should('have.focus')
.type('42')
cy.get('[data-testid="cell-editor"]')
.should('have.value', '42')
// After the product’s commit action
cy.press(Cypress.Keyboard.Keys.ENTER)
cy.get('[data-testid="target-cell"]')
.should('have.focus')
.and('contain.text', '42')
When diagnosing a failure, log the active element in the browser:
Rank #4
cy.document().its('activeElement').then((el) => {
cy.log(`active element: ${el.tagName}.${el.className}`)
})
Use this temporarily or behind a debugging flag; a class name or generated framework attribute is not necessarily a stable test contract.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsVersion and configuration checks
The AG Grid keyboard documentation page consulted for this behavior identifies JavaScript Grid version 36.2.0, while Cypress’s current command documentation includes cy.press(). Match the examples to the Cypress and AG Grid versions installed in your project. Confirm the actual editor markup, edit trigger, commit event, and focus destination in your application; those details are configuration- and component-dependent.
Performance and reliability practices
- Use one navigation action per assertion when the focus path matters; a long unverified key sequence hides the first divergence.
- Prefer retryable visibility, focus, and value assertions over arbitrary waits.
- Keep selectors tied to semantic test IDs or stable AG Grid identifiers.
- Do not use forced typing to conceal a focus defect. A forced command can bypass the user-visible behavior you are trying to test.
- For large or virtualized grids, validate the visible target after scrolling and re-query it before editing.
- Separate a focused keyboard-flow test from a data-persistence test when a server round trip makes failures ambiguous.
Or skip the browser setup
If your goal is a dependable screenshot or PDF of a grid state rather than an interactive focus test, ScreenshotNeo can capture the page through one request. It accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
See the ScreenshotNeo API documentation for authentication and options. A basic capture is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
For a Cypress-generated page, replace the URL with the deployed route that renders your grid. ScreenshotNeo also supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper settings and page ranges, custom CSS or JavaScript, clicks before capture, selector or network-idle waits, request blocking, headers, cookies, user agents, Authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameters used by other screenshot APIs also work for easier migration.
Python
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan, and yearly billing provides two months free. Create a free ScreenshotNeo account to try it.
FAQ
Should I use cy.focused() in this test?
Yes, when you need a generic diagnostic or want to assert the browser’s active element. A direct selector assertion is usually clearer when the editor or cell has a stable test ID.
Can I type directly into an AG Grid cell?
Only if that cell element is itself a supported typeable control. Most grids require an edit trigger first and expose a separate editor, so inspect the DOM rather than assuming the wrapper accepts text.
Why does a test pass locally but fail in CI?
CI may expose timing, virtualization, animation, or a different browser event order. Replace fixed delays with retryable assertions, wait for the editor to be visible and focused, and verify the configured grid version and navigation handlers.
Free tools Windows power users keep installed
One-click scans. No signup required.
Frequently Asked Questions
Should I use cy.focused() in this test?
Yes, when you need a generic diagnostic or want to assert the browser’s active element. A direct selector assertion is usually clearer when the editor or cell has a stable test ID.
Can I type directly into an AG Grid cell?
Only if that cell element is itself a supported typeable control. Most grids require an edit trigger first and expose a separate editor, so inspect the DOM rather than assuming the wrapper accepts text.
Why does a test pass locally but fail in CI?
CI may expose timing, virtualization, animation, or a different browser event order. Replace fixed delays with retryable assertions, wait for the editor to be visible and focused, and verify the configured grid version and navigation handlers.
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.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →

