To check whether Cypress can perform a normal click on a radio button, query the radio and call .click(). Cypress waits for its actionability checks; if the element remains hidden, disabled, covered, detached, or otherwise not actionable, the command fails. To test whether the option is selected, follow the action with a fresh query and .should('be.checked'). If your goal is simply to select the option—not specifically to test a pointer click—use .check() instead.
Choose the command that matches what you mean by “clickable”
“Clickable,” “enabled,” and “checked” describe different things. Cypress does not have a single assertion that proves all three. Decide what your test is meant to establish before choosing the command:
| Test intent | Use | What it establishes |
|---|---|---|
| Can Cypress perform an ordinary click? | .click() |
The target passed Cypress’s actionability checks and Cypress attempted the click. |
| Is the radio enabled? | .should('be.enabled') |
The native control is not disabled. |
| Can the test select this radio option? | .check() |
Cypress performs the radio-selection action. |
| Did the intended option become selected? | .should('be.checked') |
The radio’s checked state is true at assertion time. |
For a test explicitly about ordinary clickability, use .click() and then verify the expected state separately:
cy.get('input[type="radio"][value="email"]')
.click()
cy.get('input[type="radio"][value="email"]')
.should('be.checked')
For a test whose outcome is only “the email option is selected,” prefer the more direct selection command:
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
cy.get('input[type="radio"][value="email"]')
.check()
cy.get('input[type="radio"][value="email"]')
.should('be.checked')
Cypress’s cy.click() documentation describes a click as an action that waits for actionability checks and executes once when they pass. Its assertions documentation includes radio selection with .check() followed by be.checked.
What Cypress checks before an ordinary click
Cypress action commands wait for the target to be actionable. The interaction guide describes checks including whether the element is visible, disabled, detached, readonly, animating, or covered. Cypress can scroll an element into view before attempting an action, and it retries the query chain while waiting for actionability conditions.
That makes a successful .click() useful evidence that Cypress could perform the interaction under its rules. It is not a substitute for checking the application’s outcome: the click can be dispatched without producing the state change your test expects. Pair it with an assertion that expresses the result, such as be.checked or a change in dependent UI.
Visibility and actionability are not interchangeable. For example, the Cypress interaction guide notes that an element with opacity: 0 can still be actionable, whereas a visibility assertion also waits for opacity. Likewise, Cypress checks whether the target is covered before acting. See Interacting with elements in Cypress for the behavior and details.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Rank #2
Write a test for a real radio interaction
Use a selector that identifies the intended option, ideally a stable application selector such as a data-cy attribute. The exact selector depends on your page’s markup; this example uses a radio’s name and value:
const expressRadio = 'input[type="radio"][name="delivery"][value="express"]'
describe('delivery options', () => {
it('lets the user select express delivery', () => {
cy.visit('/checkout')
cy.get(expressRadio).should('be.enabled')
cy.get(expressRadio).click()
cy.get(expressRadio).should('be.checked')
})
})
The enabled assertion is useful when the test needs to document that prerequisite explicitly. It is not required merely to make .click() work: a normal click already waits for actionability and fails if the target remains disabled or otherwise not actionable. Keep an explicit enabled assertion when it is part of the behavior you want to specify or diagnose.
If the test is about selecting an option rather than pointer-click behavior, make the intent clearer with .check():
cy.get(expressRadio).check()
cy.get(expressRadio).should('be.checked')
For radio groups, checking one option ordinarily means that the corresponding option is selected and another option in the group is not. If that mutual-exclusion behavior matters to the feature, assert the other option’s state too:
Rank #3
cy.get('input[name="delivery"][value="standard"]').should('not.be.checked')
cy.get(expressRadio).check()
cy.get(expressRadio).should('be.checked')
cy.get('input[name="delivery"][value="standard"]').should('not.be.checked')
Handle labels and custom radio controls
Many interfaces visually hide the native radio and present a styled label, button, or other element as the user-facing control. Decide which behavior matters:
- If the test specifically checks whether the native input is ordinarily clickable, act on the input with
.click(). - If a user selects the option by clicking its label or styled control, interact with that user-facing element, then query the native radio and assert
be.checked. - If the page uses a custom widget without a native radio, test the actual accessible control and its documented state rather than assuming it is an
input[type="radio"].
For example, if the label is the actual target in your markup, a test can act on it and verify the native state afterward:
cy.get('label[for="delivery-express"]').click()
cy.get('#delivery-express').should('be.checked')
Use selectors that match your application rather than copying this markup literally. An assertion on the native input’s checked state confirms the selection result, even when the user-facing click target is its label.
Understand retries, rerenders, and timeouts
Cypress retries queries leading up to an action while waiting for the target to become actionable. The click itself is not retried once it is attempted. Assertions after an action can retry until they pass or time out. If selecting a radio rerenders the component or replaces the input node, start a fresh query for the assertion, as in the examples above, rather than continuing to use a potentially stale subject. Cypress explains this distinction in its Retry-ability in Cypress and cy.click() documentation.
Rank #4
Cypress documents a four-second default command retry timeout and supports a timeout override for an individual query. If an option genuinely takes longer to render, set a targeted timeout on that query instead of adding a fixed sleep:
cy.get('input[name="delivery"][value="express"]', { timeout: 10000 })
.click()
Use a longer timeout only when the application’s expected rendering time warrants it. A timeout increase cannot fix a selector that never matches, a permanently covered element, or a disabled control.
Diagnose common failures
| Symptom | Likely explanation | What to check |
|---|---|---|
| Click fails because the radio is disabled | The native control has its disabled property set. |
Assert .should('be.disabled') or .should('be.enabled') at the point relevant to the test; check the application condition that should enable it. |
| Click fails because the radio is covered | An overlay, animation, or another element is intercepting the interaction. | Inspect the rendered page and determine whether the overlay should disappear, whether the test needs to wait for a real state, or whether the selector targets the intended user control. |
| Click fails because the element is hidden | The input may be visually hidden, or the wrong element may have been selected. | If the real interaction is through a label or styled control, click that user-facing target and assert the native radio’s checked state. |
| Click passes but the expected option is not checked | The click did not trigger the intended selection behavior, or the selected element/state differs from the test’s expectation. | Use a fresh query and .should('be.checked'); confirm the selector’s name/value and that the user-facing target is correct. |
| Test fails after the component updates | The application may have replaced the original radio node during a rerender. | Query the radio again after the action instead of relying on a subject captured before the update. |
| Test times out while waiting for the element | The selector may not match, rendering may be slower than expected, or the control may never become actionable. | Check the selector and actual application state first. Use a focused timeout override only if the expected render really takes longer. |
Native disabled state versus ARIA
For a native form control, Cypress’s enabled/disabled checks concern the native disabled state. An aria-disabled="true" attribute alone does not make a native radio disabled for Cypress actionability; Cypress documents that it can still click such an element. If your application uses ARIA to communicate a disabled-like state, test both the relevant ARIA attribute and the application’s behavior. Do not assume an ARIA value changes the browser’s native control behavior. The distinction is covered in Cypress’s click API documentation and interaction guide.
Why not use a forced click?
.click({ force: true }) bypasses normal actionability checks. It can be appropriate when the test intentionally needs to dispatch an event despite those checks, but it does not demonstrate that a user can ordinarily click the control. If the purpose of the test is clickability, keep the ordinary click and address the underlying hidden, covered, disabled, or stale-element condition instead. Cypress documents the option in cy.click().
Or skip the browser setup
ScreenshotNeo can capture a page for visual inspection, but it does not run Cypress tests or determine whether a radio is actionable. Use Cypress for the interaction assertion above; use a screenshot when you also need a visual record of the page state. The example below requests a WebP screenshot of the Cypress Kitchen Sink page; replace the URL with the page you want to inspect. See the ScreenshotNeo documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://example.cypress.io/commands/actions
-o shot.webp
ScreenshotNeo accepts consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents using Claude, Cursor, or another MCP client. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Learn more at ScreenshotNeo.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
Frequently Asked Questions
Does a successful Cypress click prove a real person can click the radio?
It establishes that Cypress’s interaction rules allowed the click at test time. It does not replace checking the application’s expected response or testing the specific input method and user-facing control relevant to your product.
Can I assert that a radio is checked without clicking it?
Yes. Query the radio and use .should('be.checked') to inspect its current selected state.
Should I use .click() or .check() in a radio test?
Use .click() when ordinary click actionability is the point of the test. Use .check() when the test’s purpose is selecting the radio.
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.

