Find broken navigation links using Cypress

Victor Bruce
Mon Jan 22 2024

Seeing a 404 not found page when visiting a website as a user isn’t just frustrating and unpleasant but also an indication not to return to such a website. Aside from the bad user experience, broken links also negatively affect your SEO(Search Engine Optimization) ranking due to a high bounce rate.
Many factors account for broken links on a website, but the most common reasons are a deleted page, a page moved to another URL, an expired domain, or a wrong URL address entered.
Detecting Broken Links
In detecting broken links, our interest mainly lies in the HTTP 404 response status code, which indicates that a link leading to a specific page is missing on the server.
We can use Cypress to automate visiting each link on our website to check for broken links.
Test thought Process
- Visit the website you want to test for broken links.
- Get all the available links(URLs) for the Navigation component.
- Send HTTP requests to the URLs.
- Verify it’s throwing any error by logging the response.
Cypress Test To Find the Broken Link
// navigation.cy.ts
describe("Broken Navigation Links", () => {
beforeEach(() => {
cy.visit("http://localhost:3000/");
});
it("should find all broken links in the navigation component", () => {
cy.get("[data-test='navbar']")
.find("a:not([href*='mailto:'])")
.each(($link) => {
if($link.prop("href")) {
cy.request({
url: $link.prop("href"),
failOnStatusCode: false
})
}
cy.log($link.prop("href"));
});
});
});
Understanding the Code above:
Step 1:
beforeEach(() => {
cy.visit("http://localhost:3000/");
});
👉 Before each test case(it block), visit the URL http://localhost:3000/
Step 2:
cy.get("[data-test='navbar']")
👉 Get the navigation bar element using the data-test attribute on the nav element. <nav data-test="navbar"></nav>
Step 3:
cy.get("[data-test='navbar']").find("a:not([href*='mailto:'])")
👉 Chain the find()
query method to find descendant elements with a selector. We find all anchor elements excluding “mailto” anchor elements within our nav element.
Step 4:
cy.get("[data-test='navbar']")
.find("a:not([href*='mailto:'])")
.each(($link) => {}) // step 4
👉 Iterate through each a
element excluding the ones with href="mailto"
using the .each()
command.
Step 5:
// continuing from the .each() command
.each(($link) => {
})
👉 Validate if each <a>
has the href
attribute. If validation passes, make an HTTP request usingcy.request()
. By default cy.request
takes in a string as an argument cy.request('https://google.com')
for example.
But in our case, we changed the default behavior of cy.request
by passing in an options object. Aurl
option(for making HTTP requests) and a failOnStatusCode
option to fail on response codes other than 2xx and 3xx.
By default failOnStatusCode
option is true
. Since we are logging each request using cy.log()
, we will set failOnStatusCode: false
to avoid the test from stopping abruptly when we encounter response codes other than 2xx and 3xx.
References:
I was able to gather information on this topic with the help of the resources below: