In Cypress, verify a hyperlink in two stages: use cy.contains() or a stable selector to find the anchor, then assert its href. If the feature includes navigation that your application owns, click the link and assert the resulting URL with cy.url(). For an external destination, usually assert the href without leaving your test origin.
Choose what the test must prove
A link test can check different contracts. Decide which one applies before writing the command:
- Content and target: the expected visible label is present and points to the expected path.
- Navigation behavior: clicking the link changes the browser location to the expected route.
- Exact wording: the entire label, including punctuation or spacing, must match.
- Partial or flexible wording: a substring or regular expression is sufficient.
These are separate assertions. A correct href does not prove that a click handler, router, redirect, or authorization guard produces the right destination.
Verify a visible link and its href
Use the wording a user sees when that wording is the meaningful selector. Cypress’s cy.contains() command prefers an anchor over a deeper element in common cases, so it can locate the link directly:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →#1 Best Overall
- CRISP CLARITY: This 23.8″ Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
- WORK SEAMLESSLY: This sleek monitor is virtually bezel-free on three sides, so the screen looks even bigger for the viewer. This minimalistic design also allows for seamless multi-monitor setups that enhance your workflow and boost productivity
- A BETTER READING EXPERIENCE: For busy office workers, EasyRead mode provides a more paper-like experience for when viewing lengthy documents
cy.contains('nav', 'Sign Out')
.should('have.attr', 'href', '/signout')
The first argument scopes the search to the navigation container. Scoping matters when the same text appears in a heading, menu, dialog, or footer. If the text is unique on the page, this shorter form is valid:
cy.contains('a', 'Documentation')
.should('have.attr', 'href', '/docs')
Passing the expected value to have.attr checks both that the attribute exists and that its value is exactly the supplied string. Cypress automatically retries the assertion until it passes or the command times out, which normally removes the need for a fixed wait.
Assert an existing anchor by selector
When the link has a stable semantic selector, select the anchor directly. This is preferable to text when labels are translated, duplicated, or likely to change:
cy.get('#header a')
.should('have.attr', 'href', '/users')
A data attribute is often more stable than a CSS class used only for styling:
cy.get('[data-cy="account-link"]')
.should('have.attr', 'href', '/account')
Make the selector identify one intended link. If several anchors match, Cypress can produce an assertion failure or leave you testing the wrong element. Narrow the scope with a parent container, an accessible role convention used by your application, or a more specific selector.
Verify navigation after a click
When following the link is part of the feature, click it and assert the browser URL:
Rank #2
- CRISP CLARITY: This 22 inch class (21.5″ viewable) Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- 100HZ FAST REFRESH RATE: 100Hz brings your favorite movies and video games to life. Stream, binge, and play effortlessly
- SMOOTH ACTION WITH ADAPTIVE-SYNC: Adaptive-Sync technology ensures fluid action sequences and rapid response time. Every frame will be rendered smoothly with crystal clarity and without stutter
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
cy.contains('a', 'Edit User').click()
cy.url().should('include', '/users/1/edit')
cy.url() retries chained assertions while the application renders, redirects, or completes a client-side route change. Prefer a configured Cypress baseUrl so the test does not embed a host name that changes between local, staging, and CI environments. Assert only the portion that is contractual: include is useful when query parameters or a host vary; an exact URL assertion is appropriate when every component is fixed.
Check both the link contract and the result
For an important in-app route, combine the checks without adding a hard-coded sleep:
Windows 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 reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutecy.contains('nav', 'Projects')
.should('have.attr', 'href', '/projects')
.click()
cy.url().should('include', '/projects')
The first assertion catches a broken or mistargeted anchor before the click. The second verifies the user-visible outcome. Keep side effects out of a callback passed to should; Cypress may invoke that callback repeatedly, and Cypress commands should not be called from inside it.
Match text correctly
Visible text with contains
cy.contains() is designed for user-facing text. It accepts strings, numbers, and regular expressions. Cypress collapses runs of whitespace for matching, except inside a <pre> element. This makes it resilient to line breaks and ordinary formatting differences.
cy.contains('a', 'Read more').should('have.attr', 'href', '/articles/42')
cy.contains('a', /reads+more/i).should('be.visible')
If the same wording appears in several regions, scope the command first:
cy.get('[data-cy="results"]')
.contains('a', 'Details')
.should('have.attr', 'href', '/items/42')
Exact element text
Use have.text when the complete text content of a known element is the requirement. Use include.text when only a substring matters:
Recommended Free Tools
Rank #3
- Clear visuals. Fluid motion: A 144Hz refresh rate and 1ms MPRT deliver smooth, tear‑free motion across work, gaming, and streaming for clearer, more fluid viewing.
- Eye comfort: TÜV Rheinland 3‑star* certification reduces harmful blue light while preserving stunning color quality without compromise. *TÜV Rheinland 3-star eye comfort certification.
- Wide viewing angle: Get consistent views across a wide 178° /178° viewing angle.
- In-Plane Switching (IPS): See excellent color accuracy and consistency across wide viewing angles with In-plane Switching (IPS) technology.
- Ultra-thin bezels: Maximize your viewing experience with thin bezels.
cy.get('[data-cy="terms-link"]')
.should('have.text', 'Terms of Service')
cy.get('[data-cy="status-link"]')
.should('include.text', 'Status')
Non-breaking spaces are a common source of surprising exact-text failures. For an exact assertion, represent the character as u00a0:
cy.get('[data-cy="price-link"]')
.should('have.text', 'Viewu00a0pricing')
cy.contains() handles non-breaking spaces while matching, but exact equality still distinguishes the character from a normal space.
External links and test boundaries
For a third-party destination that your team does not control, verify the target attribute instead of performing a real navigation:
cy.contains('a', 'Privacy provider')
.should('have.attr', 'href', 'https://privacy.example.test/policy')
This keeps the test deterministic, avoids loading an unrelated site, and checks the contract your application owns. Do not turn an external-link check into a network availability test unless that is a separate, explicit requirement.
Free tools Windows power users keep installed
One-click scans. No signup required.
If the feature genuinely requires interacting with another origin, declare that origin with cy.origin() and place commands for the expected domain inside its callback. Keep the cross-origin test focused on the behavior you need; unrelated third-party pages can change without notice.
Reusable Cypress examples
Testing a menu item
describe('account navigation', () => {
it('links Sign Out to the sign-out route', () => {
cy.visit('/account')
cy.contains('nav', 'Sign Out')
.should('be.visible')
.and('have.attr', 'href', '/signout')
})
})
Testing a client-side route
it('opens the edit screen', () => {
cy.visit('/users/1')
cy.contains('a', 'Edit User').click()
cy.url().should('include', '/users/1/edit')
cy.get('h1').should('have.text', 'Edit User')
})
Testing a link rendered after data loads
it('shows the invoice link after loading', () => {
cy.visit('/billing')
cy.get('[data-cy="invoice-list"]')
.contains('a', 'Invoice 1042')
.should('have.attr', 'href', '/invoices/1042')
})
Because Cypress retries queries and assertions, this pattern waits for the element and attribute as the application renders them. A fixed cy.wait(2000) is slower and can still fail on a slower run.
Rank #4
- CURVED FOR ENHANCED ENGAGEMENT: An immersive viewing experience with a curved monitor that wraps more closely around your field of vision; It creates a wider view, enhancing depth perception and minimizing peripheral distraction
- SMOOTH PERFORMANCE FOR SEAMLESS CONTENT: Stay in the action when playing games, watching videos, or working on creative projects; The 100Hz refresh rate reduces lag and motion blur so you don't miss a thing in fast-paced moments¹
- MORE GAMING POWER: Gain the edge with optimizable game settings; Color and image contrast can be adjusted to see scenes more vividly and spot enemies hiding in the dark; Game Mode adjusts any game to fill the screen so you can view every detail²
- KEEP IT EASY ON THE EYES: Care for your eyes and stay comfortable, even during long sessions; Advanced eye comfort technology certified by TÜV reduces eye strain by minimizing blue light and reducing irritating screen flicker²
- INCREASED VERSATILITY: Connect to more; Plug devices straight into your monitor for increased flexibility, making your computing environment even more convenient
Common failures and fixes
“Expected to find content, but never did”
- Confirm the test visited the route that renders the link.
- Scope the search to the correct container; duplicate or hidden text may be matching elsewhere.
- Check capitalization, punctuation, and whether the label is split across elements.
- If the content is loaded asynchronously, wait on the application’s observable state or use a selector that Cypress can retry rather than a fixed delay.
The href assertion fails even though the link looks right
- Inspect whether the application emits a relative path, an absolute URL, or a URL with a trailing slash.
- Check query strings, hash fragments, and URL encoding.
- Assert the exact form your application promises; do not silently normalize a real regression.
The test finds the wrong link
Repeated labels such as “Details” or “Learn more” need a parent scope, a unique selector, or a position-independent data attribute. Avoid relying on :nth-child when the list order can change.
The click does not reach the expected URL
- Verify the anchor’s
hrefbefore clicking. - Check whether a router intercepts the click and whether the test is asserting the route after the application has finished rendering.
- Use
cy.url().should('include', ...)for variable query strings and exact equality only for a fully fixed URL. - If the destination is another origin, use
cy.origin()only when cross-origin interaction is part of the requirement; otherwise asserthrefalone.
An exact text check fails on spacing
Use include.text or cy.contains() when formatting is not contractual. If exact text is contractual, account for non-breaking spaces with u00a0 and preserve the element’s actual punctuation.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Reliability and maintenance guidance
- Test the user-visible label and destination together when the link itself is the feature.
- Separate link correctness from navigation behavior so a failure identifies the broken contract.
- Prefer semantic, stable selectors over styling classes and DOM positions.
- Let Cypress retry assertions; reserve explicit waits for a documented external synchronization need.
- Keep external-site availability outside ordinary hyperlink tests.
- Use
baseUrlfor environment-specific hosts and assert only stable URL components.
Or skip the browser setup
If your goal is to capture a page for a visual record, documentation, or an AI workflow rather than run Cypress assertions, ScreenshotNeo returns a screenshot or PDF from one request. It accepts cookie and consent banners, removes more than 60 known consent platforms plus newsletter popups and chat widgets before capture, and lets you turn each cleanup step off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
Use the ScreenshotNeo documentation for the complete option list. A direct cURL request is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
The same request in 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)
And in 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}`);
Every plan includes the features: full-page and element capture, dark mode, device presets and custom viewports, retina scale, PDF controls, custom CSS and JavaScript, click and wait actions, request blocking, headers, cookies, user-agent, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, an OpenAPI specification, and compatible parameter names used by other screenshot APIs.
The Free plan includes 1,000 screenshots each month with no card. Paid plans start at $5 for 3,000 shots; yearly billing provides two months free. Create a free ScreenshotNeo account to try it without a card.
FAQ
Should I assert href or the final URL?
Assert href for a link contract, and assert the final URL when the click-and-navigation experience is what you are testing. Important in-app links can use both.
Best Value
- 【INTEGRATED SPEAKERS】Whether you're at work or in the midst of an intense gaming session, our built-in speakers provide rich and seamless audio, all while keeping your desk clutter-free.
- 【EASY ON THE EYES】 Protect your eyes and enhance your comfort with Blue-Light Shift technology. This feature reduces harmful blue light emissions from your screen, helping to alleviate eye strain during long hours of use and promoting healthier viewing habits.
- 【WIDEN YOUR PERSPECTIVE】Our sleek minimal bezel design ensures undivided attention. The nearly bezel-free display seamlessly connects in a dual monitor arrangement, delivering an unobstructed view that lets you focus on more at once, completely distraction-free.
Can cy.contains match a regular expression?
Yes. It accepts regular expressions as well as strings and numbers, which is useful for labels whose capitalization or whitespace varies.
Why avoid clicking an external link?
The external site is outside your control. Checking its href verifies your application’s output without introducing a page-load or third-party availability dependency.
What is the best selector for translated link text?
Use a stable selector such as a dedicated data attribute, then assert the localized text separately if wording is part of the requirement.
Frequently Asked Questions
Does Cypress wait for a dynamically rendered href?
Yes. Queries and chained should assertions retry until they pass or the command timeout is reached, so a fixed sleep is usually unnecessary.
How can I test a link with a query string?
Assert the complete href when the query is deterministic; otherwise use a URL assertion that checks the stable path and separately verify the parameters your application owns.
Can I verify a download link without downloading the file?
Yes. Assert the anchor’s href and any download-related attributes. Follow the link only if the download behavior itself is the feature under test.
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.

