Understanding Cypress Basics: Core Features and Syntax Explained

Profile picture of Bhavik Bamania
Bhavik Bamania
·4 min read
Cypress Basics: Core Features & Syntax for Beginners
Cypress Basics: Core Features & Syntax for Beginners

Cypress is one of the most popular end-to-end (E2E) testing frameworks, known for its simplicity, power, and developer-friendly features. In this article, we’ll explore Cypress's core features and syntax, helping you build a strong foundation for writing reliable E2E tests. This guide is written for beginners, with simple explanations and practical examples to make Cypress accessible to everyone.

Introduction

This article is part of our Cypress Tutorial Series designed to help beginners master Cypress, starting from the basics. If you're new to Cypress, we recommend starting with the previous article, A Beginner's Guide to Cypress: End-to-End Testing Made Easy. It introduces Cypress, explains its benefits, and walks you through the setup process.

By the end of this series, you’ll have the skills to confidently write, execute, and debug Cypress tests for modern web applications.


Why Cypress?

Modern web applications involve a lot of dynamic and user-driven interactions. Testing these interactions manually is tedious and error-prone. Cypress allows you to:

  • Automate user interactions, such as form submissions, dropdown selections, and navigation.
  • Validate UI elements and ensure they function as expected.
  • Test edge cases and user flows to ensure the reliability of your application.

Now let’s set up the project and get started.

 

Setting Up the Demo Project

 

Step 1: Create a Vite React Project

To follow along with this guide, you need a sample application to test. Create a new React project using Vite:

npm create vite@latest cypress-demo --template react
cd cypress-demo
npm install

Step 2: Install Cypress

Install Cypress as a development dependency:

npm install cypress --save-dev

and install cypress types:

npm install --save-dev @cypress/types

Add Cypress to the tsconfig.json:

{
  "compilerOptions": {
    "types": ["cypress"]
  }
}

 

Step 3: Open Cypress

Initialize Cypress and open its interactive runner:

npx cypress open

This command will create a cypress folder in your project with default configurations.

Step 4: Create Sample Components

For this tutorial, we’ll test a simple login form. Create a LoginForm component:

src/components/LoginForm.tsx:

import React, { useState } from 'react';

const LoginForm: React.FC = () => {
  const [username, setUsername] = useState<string>('');
  const [password, setPassword] = useState<string>('');

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    alert(`Welcome, ${username}!`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        id="username"
        type="text"
        placeholder="Username"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <input
        id="password"
        type="password"
        placeholder="Password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button type="submit">Login</button>
    </form>
  );
};

export default LoginForm;

Now that the project is ready, let’s dive into writing test cases.

Writing Cypress Test Cases

Cypress uses a BDD-style syntax with describe and it blocks:

  • describe: Groups related test cases.
  • it: Defines individual test cases.

Let’s write a basic test suite for our LoginForm.

Creating Test Suites and Tests

A test suite is a collection of related tests, and each test validates specific functionality. Here’s an example:

describe('LoginForm Tests', () => {
  it('should render the login form', () => {
    cy.visit('http://localhost:5173'); // Visit the app
    cy.get('form').should('be.visible'); // Assert the form is visible
  });

  it('should allow users to enter username and password', () => {
    cy.get('#username').type('testuser'); // Type into username
    cy.get('#password').type('password123'); // Type into password
    cy.get('#username').should('have.value', 'testuser'); // Assert value
    cy.get('#password').should('have.value', 'password123');
  });
});

Breaking down the above code into pieces to understand each command and its usuage.

Visiting Pages

The cy.visit() command is used to load a specific URL:

cy.visit('http://localhost:5173');
cy.url().should('eq', 'http://localhost:5173/');

This command ensures the target page loads successfully and is ready for testing.

Selecting Elements

Cypress provides powerful selectors to locate elements on the page.

Using .get()

The .get() command locates elements by id, class, or other attributes:

cy.get('#submit-button').click();

 

Using .find()

The .find() command narrows the search scope to a specific parent element:

cy.get('.form').find('input').type('Hello!');

Selecting by Text

Use cy.contains() to locate elements by their text content:

cy.contains('Submit').click();

This command is especially useful for buttons, links, and other text-based elements.

Checking for Partial Text

You can assert partial text matches for dynamic content:

cy.contains('Welcome').should('exist');

This ensures that elements with partial text, such as greetings or messages, are present.

Assertions

Assertions validate that elements behave as expected.

Implicit Assertions

Built into Cypress commands like .should():

cy.get('#login').should('be.visible');

Explicit Assertions

Use libraries like chai for more complex checks:

cy.get('#title').then((element) => {
  expect(element.text()).to.equal('Welcome Back!');
});

Dropdown Selections

Test dropdowns by selecting a value and asserting the result:

cy.get('select').select('Option 1');
cy.get('select').should('have.value', 'Option 1');

Cypress Test Isolation

Each Cypress test runs in isolation. Cypress resets the browser state (cookies, local storage, etc.) between tests.

describe('Test Isolation Example', () => {
  it('should set a cookie', () => {
    cy.setCookie('session', '12345');
    cy.getCookie('session').should('exist');
  });

  it('should not retain the cookie', () => {
    cy.getCookie('session').should('not.exist');
  });
});

Practical Example: Testing the Login Form

Combining everything, here’s a complete example:

describe('LoginForm Tests', () => {
  beforeEach(() => {
    cy.visit('http://localhost:5173'); // Replace with your app's URL
  });

  it('should render the login form', () => {
    cy.get('form').should('be.visible'); // Assert the form is visible
  });

  it('should allow users to type in the fields', () => {
    cy.get('#username').type('testuser'); // Type into username
    cy.get('#password').type('password123'); // Type into password
    cy.get('#username').should('have.value', 'testuser'); // Assert value
    cy.get('#password').should('have.value', 'password123');
  });

  it('should display an alert on submit', () => {
    cy.get('#username').type('testuser');
    cy.get('#password').type('password123');
    cy.get('button[type="submit"]').click();

    // Listen for the alert
    cy.on('window:alert', (text) => {
      expect(text).to.contains('Welcome, testuser!');
    });
  });
});

Conclusion

In this article, we explored Cypress’s core features and syntax, including how to create test suites, select elements, and make assertions. By following along with the React-based demo project, you’ve gained hands-on experience with Cypress.

In the next article, we’ll cover advanced features like stubs, spies, and handling network requests. Stay tuned, and happy testing!

Author of Bhavik Bamania

Written by

Bhavik Bamania