Cypress Setting Up a Reliable and Scalable Test Suite In Cypress Estimated reading: 4 minutes 208 views In this guide I’ll walk you through some essential Cypress features, such as setting the baseUrl, using the beforeEach hook, organizing tests with nested describe blocks, and creating custom commands. Let’s dive in!Using the baseUrl to Store Your Test URLOne of the first steps in setting up a Cypress project is configuring your test environment. Instead of hardcoding URLs throughout your tests, you can streamline your code by using the baseUrl configuration in Cypress. This not only makes your tests more maintainable but also easier to read and manage. Setting the baseUrl: To set up your baseUrl, navigate to your cypress.json file (located in the root of your Cypress project) and add the following configuration:cypress.config.jsconst { defineConfig } = require("cypress"); module.exports = defineConfig({ e2e: { defaultCommandTimeout: 10000, // 10 seconds pageLoadTimeout: 60000, // 60 seconds for page load baseUrl: 'https://jahmalrichard.github.io/kicks-flutter-web-app/', setupNodeEvents(on, config) { }, }, }); With this configuration, you can now visit your URL automatically during test.cy.visitcy.visit('/');Cypress automatically prepends the baseUrl to any relative URL you provide, making your tests more readable and easier to maintain. If you ever change your testing environment (e.g., from localhost to a staging server), you only need to update the baseUrl in one place.Using the beforeEach Hook in CypressThe beforeEach hook is a powerful feature in Cypress that allows you to run a specific piece of code before each test within a describe block. This is particularly useful for setting up a consistent test environment, ensuring that each test starts with the same conditions. Implementing beforeEach: In our sample script, we see the beforeEach hook used to set the viewport size and visit the homepage before each test. cy.viewport(1500, 780): Sets the browser window size to 1500x780 pixels, ensuring consistency across all tests. cy.visit('/'): Navigates to the homepage, using the relative path since baseUrl is set. cy.wait(5000):Pauses the test for 5 seconds to ensure that all elements on the page are loaded and ready for interaction.beforeEachdescribe('Home Screen', () => { beforeEach(() => { // This will run before each test, ensuring the website is always launched with custom viewport cy.viewport(1500, 780); cy.visit('/'); cy.wait(5000); // Ensures the page has fully loaded before running the test }); // Test cases will follow here... });This setup ensures that every test in the Home Screen block starts with the same conditions, leading to more reliable and predictable test outcomes.Using Nested describe BlocksAs your test suite grows, organizing your tests becomes crucial. Cypress allows you to structure your tests using nested describe blocks, which is particularly useful for grouping related tests and making your test suite easier to navigate.Implementing Nested describe Blocks:In the provided script, we see a nested describe structure used to organize tests related to the Home Screen and its Navigation Menu: Outer describe block (Home Screen): Groups all tests related to the home screen of your application. Nested describe block (Navigation Menu): Further organizes tests that specifically deal with the navigation menu.Nested describe()describe('Home Screen', () => { beforeEach(() => { cy.viewport(1500, 780); cy.visit('/'); cy.wait(5000); }); describe('Navigation Menu', () => { it('should navigate to the About Us page when the about link is clicked', () => { cy.get('flt-semantics[aria-label="About us"]') .should('be.visible') .focus() .click({ force: true }); cy.url().should('include', '/about-us'); const aboutUsPageHTitle = createMultilineSelector('About us'); cy.get(aboutUsPageHTitle).should('be.visible'); }); // Additional test cases for other navigation links... }); });This structure not only makes your tests easier to manage but also provides clear reporting when tests are run. You can easily identify which part of your application a failing test belongs to based on the describe block hierarchy.Using Custom Commands in CypressCypress allows you to extend its functionality by creating custom commands, which can simplify repetitive tasks and make your tests more expressive. Custom commands are particularly useful for abstracting complex interactions or frequently used selectors.Creating and Using a Custom Command:In the provided script, the createMultilineSelector command is imported and used to generate a selector for elements with multiline text. createMultilineSelector: This custom command likely returns a selector that matches elements based on their aria-label attribute, specifically targeting multiline text. By using this command, we avoid duplicating complex selectors throughout our tests. Usage in Tests:Instead of writing out the full selector each time, you simply call createMultilineSelector('About us'), making the test more readable and easier to maintain.Using createMultilineSelectorimport { createMultilineSelector } from '../../support/e2e.js'; describe('Home Screen', () => { beforeEach(() => { cy.viewport(1500, 780); cy.visit('/'); cy.wait(5000); }); describe('Navigation Menu', () => { it('should navigate to the About Us page when the about link is clicked', () => { cy.get('flt-semantics[aria-label="About us"]') .should('be.visible') .focus() .click({ force: true }); cy.url().should('include', '/about-us'); const aboutUsPageHTitle = createMultilineSelector('About us'); cy.get(aboutUsPageHTitle).should('be.visible'); }); // Additional test cases... }); });Creating Custom CommandsYou can define custom commands in the cypress/support/e2e.js file. Here’s how you might define the createMultilineSelector command:Custom function – createMultilineSelector()import './commands' export function createMultilineSelector(text) { let selector = 'flt-semantics[aria-label="'; for (let i = 0; i < text.length; i++) { selector += text[i]; if (i < text.length - 1) { selector += '\n'; // Add a newline after each character, except the last one } } selector += '"]'; return selector; }This function dynamically creates a selector that matches any element whose aria-label contains the specified text, making it versatile for various testing scenarios. ConclusionNow that we have our Cypress script set up in a scalable state, we’re ready to take the next step Running Test Scenarios in Cypress to ensure our application behaves as expected across different user interactions. This is where the true power of Cypress shines. By crafting various test scenarios, we can simulate real-world usage patterns, validating that all parts of our web application function correctly under different conditions.Tagged:Cypress Cypress - Previous Writing Your First Test in Cypress Next - Cypress Running Test Scenarios in Cypress