Skip to main content
Cypress App
End-to-End Only

url

Get the full URL of the page under test as a string.

info

cy.url() yields the same value as cy.location('href').

Syntax​

cy.url()
cy.url(options)

Usage​

Correct Usage

cy.url() // Yields the current URL as a string

Incorrect Usage

const url = cy.url() // Yields a chainable, not the URL string
cy.get('a').url() // Ignores the link, yields the page's URL

Cypress commands are enqueued and run later, so cy.url() never returns the URL directly. To work with the string, read it in a .then() callback or save it as an alias:

cy.url().then((url) => {
// url is the current URL as a string
})

cy.url().as('startUrl')

Arguments​

options (Object)

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

cy.url( options )

OptionDefaultDescription
decodefalseDecode the URL with decodeURI() before yielding it
logtrueDisplays the command in the Command log
timeoutdefaultCommandTimeoutTime to wait for cy.url() to resolve before timing out

Yields ​

  • cy.url() yields the current URL as a string.
  • cy.url() is a query, and it is safe to chain further commands.

cy.url() yields the whole URL, labeled href in this diagram:

Diagram of the URL https://example.com:8080/app/users?tab=1#section split into its parts: protocol is https:, hostname is example.com, port is 8080, host is example.com:8080, origin is https://example.com:8080, pathname is /app/users, search is ?tab=1, hash is #section, and href is the whole URL.

Examples​

No Args​

Assert the URL is http://localhost:8000/users/1/edit​

// clicking the anchor causes the browser to follow the link
cy.get('#user-edit a').click()
cy.url().should('include', '/users/1/edit')
cy.url().should('eq', 'http://localhost:8000/users/1/edit')

decode option​

The browser percent-encodes non-ASCII characters in the URL. To assert on the readable text, pass decode: true.

// For the curious, '사랑' means 'love' in Korean.
cy.url({ decode: true }).should('contain', '사랑')

decode runs the URL through decodeURI(), which leaves escapes for reserved characters such as /, ?, &, and # encoded. Given the remote URL http://localhost:8000/search?q=caf%C3%A9%26bar, the decoded URL keeps %26:

cy.url({ decode: true }).should(
'eq',
'http://localhost:8000/search?q=café%26bar'
)
In the URLWith decode: trueWhy
%EC%82%AC%EB%9E%91사랑Non-ASCII characters are decoded
%C3%A9éNon-ASCII characters are decoded
%26%26& is reserved, so it stays encoded
%2F%2F/ is reserved, so it stays encoded

Redirects and navigation​

Wait for a redirect after signing in​

cy.url() retries until its assertions pass, so the test waits for your application to finish redirecting without a cy.wait().

cy.get('#email').type('[email protected]')
cy.get('#password').type('secret')
cy.contains('button', 'Sign in').click()
cy.url().should('include', '/dashboard')

In the Command Log, the url assertion passes on the dashboard URL, and the redirect's page load and new URL appear as their own rows:

Command Log showing click, then url with a passing assertion that http://localhost:8000/dashboard includes /dashboard, followed by page load and new url rows for the dashboard

Match a URL that contains a generated ID​

When a URL includes a value your test doesn't know in advance, such as the ID of a record the test created, match it with a regular expression.

cy.contains('button', 'Create user').click()
cy.url().should('match', /\/users\/\d+\/edit$/)

Assert that the URL doesn't change​

Save the URL before an action, then compare against it afterward. Here, the required field blocks the form from submitting, so the page stays where it is.

index.html
<form action="/saved">
<input name="name" required />
<button>Save</button>
</form>
spec.cy.js
cy.url().then((startUrl) => {
cy.contains('button', 'Save').click()
cy.url().should('eq', startUrl)
})

Cross-origin redirects​

Assert that sign-in redirects to an identity provider​

Because cy.url() reads the URL across origins, you can confirm where a sign-in flow landed before you interact with that page inside cy.origin().

cy.visit('http://localhost:8000/')
cy.contains('a', 'Sign in with SSO').click()

cy.url().should('include', 'http://auth.example.com/login')

cy.origin('http://auth.example.com', () => {
cy.get('input[name="username"]').type('jane')
})

Notes​

cy.url() versus cy.location('href')​

cy.url() reads the current URL and yields its href, the same string cy.location('href') yields. Given the remote URL http://localhost:8000/index.html, all 3 of these assertions are the same:

cy.location('href').should('include', '/index.html')

cy.location().its('href').should('include', '/index.html')

cy.url().should('include', '/index.html')

href is the name the window.location spec gives the full URL. There is no url property on the location object, so cy.url() gives the full current URL the name most developers reach for first.

Assert on part of the URL with cy.location()​

cy.url() yields the whole URL, including the protocol, host, and port, so an assertion on it names the host. When you only care about the path or the query string, assert on that part with cy.location() instead of hardcoding or slicing the full URL. The assertion then passes on any host, such as a local server, CI, or a preview deployment. The pathname and search labels in the URL diagram under Yields show which part each one reads.

// given remote URL: http://localhost:8000/users/1/edit?tab=profile
cy.location('pathname').should('eq', '/users/1/edit')
cy.location('search').should('eq', '?tab=profile')

To keep the host out of cy.visit() as well, define a baseUrl in your Cypress configuration. For more details on why, see our Best Practices guide on setting a global baseUrl.

Trailing # and ? in the URL​

The browser keeps a bare # or ? at the end of the URL, so cy.url() yields it even though the hash or query string is empty. A link to # adds a trailing #:

index.html
<nav>
<a href="#/users/1">Open profile</a>
<a href="#">Close profile</a>
</nav>
spec.cy.js
cy.contains('a', 'Close profile').click()
cy.url().should('eq', 'http://localhost:8000/index.html#')
cy.hash().should('eq', '')
cy.location('pathname').should('eq', '/index.html')

A URL ending in ? works the same way:

// given remote URL: http://localhost:8000/index.html?
cy.url().should('eq', 'http://localhost:8000/index.html?')
cy.location('search').should('eq', '')

To leave the trailing character out of the assertion, compare the pathname with cy.location().

Cross-origin pages and cy.url()​

cy.url() reads the URL from the browser rather than from the page's window, so it yields the URL after your application navigates to another origin, without wrapping the command in cy.origin().

Rules​

Requirements ​

  • cy.url() requires being chained off of cy.

Assertions ​

  • cy.url() automatically retries until all chained assertions have passed

Timeouts ​

  • cy.url() can time out waiting for assertions you've added to pass.

Command Log​

Assert that the URL includes #users/new

cy.url().should('include', '#users/new')

The commands above display in the Command Log as:

Command Log showing the url command and a passing assertion that the URL includes #users/new

When clicking on url within the Command Log, the console outputs the following:

DevTools console showing Command: url and Yielded: the full URL ending in #users/new

History​

VersionChanges
15.0.0Reads the URL through the browser's automation client instead of the page's window in Chromium-based browsers and Firefox
8.4.0decode option added
< 0.3.3cy.url() command added

See also​