Skip to main content

Code Workspace

Overviewโ€‹

๐Ÿ‘‹ Welcome! In this section, we'll explore detailed examples to understand when and where specific Cypress functions should be used. By the end, you'll have a solid grasp of automating tests effectively! ๐Ÿš€

File Setupโ€‹

  • Test files should have the extension .cy.ts or .cy.js.
  • The syntax for TypeScript and JavaScript is the same.
  • All test files should be located in the cypress/e2e/ folder.

๐ŸŒŸ GitHub Repository: You can find the testing files in the GitHub repository.

GitHub


Automating Loginโ€‹

Let's start with a simple login example:

login.cy.js
describe('Login test', () => {
it('should successfully log in', () => {
cy.visit('/login');
cy.get("input[name='username']").type('mourya');
cy.get("input[name='password']").type('password123');
cy.get("button[type='submit']").click();
cy.contains('Login successful', {timeout:20000}).should('be.visible');
cy.url().should('include', '/list');
});
});
  1. Test Suite: Tests the "Login" feature.
  2. Test: 'should successfully log in':
    • Visits /login.
    • Enters "mourya" in the username and password fields.
    • Clicks the "Submit" button.
    • Verifies the success message and checks if redirected to /list.
  3. Assertions: Confirms visibility of "Login successful" and URL includes /list.
tip

The timeout option sets how long (in milliseconds) Cypress will wait for the element to appear before giving up.

login Example

Optimizing Login with Sessionsโ€‹

๐Ÿ’ก Logging in repeatedly can be time-consuming for large applications. Cypress offers the cy.session() function to cache session data.

Example:โ€‹

cy.session('mourya', () => {
cy.visit('/login');
cy.get("input[name='username']").type('mourya');
cy.get("input[name='password']").type(`password123`);
cy.get("button[type='submit']").click();
cy.contains('Login successful', { timeout: 20000 }).should('be.visible');
cy.url({ timeout: 20000 }).should('include', '/list');
});

  1. Purpose: This code sets up a session for the user "mourya" using cy.session.
  2. How it works:
    • cy.session creates and caches a session identified by the key 'mourya'.
    • Inside the session callback, it performs the login steps (visiting /login, entering credentials, and verifying success).
    • On subsequent calls with the same key ('mourya'), Cypress restores the cached session (cookies, local storage, etc.) instead of repeating the login steps.
  3. Key Benefits:
    • Reduces test runtime by skipping redundant login steps.
    • Ensures the test starts in a pre-authenticated state.
  4. Assertions:
    • Checks for the success message and the correct post-login URL.

Creating a Custom Commandโ€‹

Since login is a repetitive task, we can create a custom Cypress command: First rename cypress/support/commands.ts file to commands.js

  1. Navigate to: cypress/support/commands.js.
  2. Add the following code:
commands.js
const login = (email, password) => {
cy.session(email, () => {
cy.visit('/login');
cy.get("input[name='username']").type(email);
cy.get("input[name='password']").type(`${password}`);
cy.get("button[type='submit']").click();
cy.contains('Login successful', { timeout: 20000 }).should('be.visible');
cy.url({ timeout: 20000 }).should('include', '/list');
}, {
cacheAcrossSpecs: true
});
};

Cypress.Commands.add('login', login);
  1. Ensure import exists: In cypress/support/e2e.ts, verify the following:
import './commands';

๐ŸŽ‰ Now you can use the cy.login command in your tests!

Usage:โ€‹

visitPage.cy.js
describe('Visit Page', () => {
it('should visit page', () => {
cy.login('mourya', 'password123');
cy.visit('/list');
});
});
info
  • When the session exists: Cypress restores it using stored cookies and local/session storage.
  • When it doesn't exist: Cypress runs the login function and saves the session for future use.

Testing Registration and Loginโ€‹

Here's an example to test user registration and subsequent login:

signup.cy.js
describe('New User Registration', () => {
it('should register a new user and log in', () => {
const username = 'mourya';
const password = 'password123';

// register
cy.visit('/register');
cy.get("input[name='full_name']").type('Mourya');
cy.get("input[name='username']").type(username);
cy.get("input[name='password']").type(password);
cy.contains('button', 'Create account').click();
cy.contains('Registration successful!', { timeout: 20000 }).should('be.visible');
cy.url().should('include', '/login');
cy.log('Registration successful');

// login
cy.visit('/login');
cy.get("input[name='username']").type(username);
cy.get("input[name='password']").type(password);
cy.get("button[type='submit']").click();
cy.contains('Login successful', { timeout: 20000 }).should('be.visible');
cy.url().should('include', '/list');
cy.log('Login successful');
});
});
  1. Test Suite: Tests the "New User Registration" and subsequent login.

  2. Test: 'should register a new user and log in':

    • Registration:
      • Visits /register.
      • Enters a full name, username (mourya), and password (password123).
      • Clicks the "Create account" button.
      • Verifies the "Registration successful!" message and checks redirection to /login.
    • Login:
      • Visits /login.
      • Enters the newly registered username and password.
      • Clicks the "Submit" button.
      • Verifies the "Login successful" message and checks redirection to /list.
  3. Assertions:

    • Confirms successful registration with the correct message and URL (/login).
    • Confirms successful login with the correct message and URL (/list).

Viewing Notesโ€‹

Here's how you can test viewing a note:

viewNote.cy.js
describe('View Note', () => {
it('Title should be disabled', () => {
cy.login('mourya', 'uzumakiNaruto');
cy.visit('/list');

cy.get('button.border.border-input', { timeout: 30000 })
.filter(':has(svg.tabler-icon-eye)')
.last()
.click();

cy.get("input[placeholder='Title']")
.should('be.disabled');

cy.contains('button', 'Close')
.should('exist')
.click();
});
});
  1. Test Suite: Tests the "View Note" feature.
  2. Test: 'Title should be disabled':
    • Restores the user session (cy.login) and visits /list.
    • Finds buttons with the class border.border-input.
    • Filters these to select one containing an SVG (eye icon), selects the last button, and clicks it.
    • Verifies the title field (placeholder='Title') is disabled.
    • Ensures the "Close" button exists and clicks it to exit.
  3. Assertions: Confirms session restoration, correct button interaction, disabled title field, and "Close" button functionality.

Handling Dynamic Routingโ€‹

Here's how to test a landing page that dynamically redirects based on session state:

landingPage.cy.js
describe('Landing Page Renders', () => {
it('redirects to /list if session exists', () => {
cy.login('mourya', 'password123');
cy.visit('/');
cy.contains('button', 'Get Started')
.should('exist')
.click();
cy.url().should('include', '/list');
});

it('redirects to /register if session does not exist', () => {
cy.visit('/');
cy.contains('button', 'Get Started')
.should('exist')
.click();
cy.url().should('include', '/register');
});
});
  1. Test Suite: Tests the "Landing Page" behavior based on session state.
  2. Test1 Redirect to /list:
    • The user logs in with cy.login to establish a session.
    • Verifies on visiting /, clicking "Get Started" redirects to /list.
  3. Test2 Redirect to /register:
    • Without logging in, visits / .
    • Verfiies clicking "Get Started" button redirects to /register.
  4. Assertions:
    • Ensures the "Get Started" button is visible before interacting.
    • Validates the URL to confirm the correct redirection.

Stubbing the Notes API on /listโ€‹

This test validates the handling of the /list page when the notes API is stubbed.

networkStub.cy.js
describe('Stub Notes API on /list', () => {
it('should stub the notes/all API ', () => {
cy.intercept('GET', 'http://192.168.0.147:8000/note/all', {
statusCode: 200,
body: [
{
note_id: 1,
title: 'Sample Note',
body: 'This is a test note',
modified_at: '2025-02-07T06:30:16.803Z',
created_at: '2025-02-07T06:30:16.803Z',
user_id: 123,
additionalProp1: {}
},
{
note_id: 2,
title: 'Another Note',
body: 'This is another test note',
modified_at: '2025-02-07T07:00:00.000Z',
created_at: '2025-02-07T07:00:00.000Z',
user_id: 124,
additionalProp1: {}
}
]
}).as('getNotes');

cy.login('mourya', 'password123');

cy.visit('/list');

cy.wait('@getNotes', { timeout: 30000 }).then((interception) => {
expect(interception.response.statusCode).to.eq(200);
});

cy.contains('Sample Note', { timeout: 30000 }).should('be.visible');
cy.contains('Another Note', { timeout: 30000 }).should('be.visible');
});
});
  1. Test Suite: Verify the /list page with a stubbed notes/all API response.
  2. Test Details:
    • Stub the GET request to notes/all using cy.intercept with mock data.
    • Log in via cy.login and navigate to /list.
    • Wait for the stubbed API call (@getNotes) to complete.
  3. Assertions:
    • Validate the stubbed API response has statusCode: 200.
    • Ensure the notes, "Sample Note" and "Another Note," are visible on the page.

Creating a Noteโ€‹

Alright, let's get more complex and create a note!

createNote.cy.js
describe("Create Note", () => {
it("should create note when title and body is given", () => {
cy.login('mourya', 'password123');
cy.visit('/list');

let initialCount;
cy.get('div.rounded-xl.border.bg-card.text-card-foreground.shadow-md', {timeout:30000})
.its('length')
.then((count) => {
initialCount = count;
cy.log(`Initial number of elements: ${initialCount}`);
});
initialCount = initialCount+1

cy.contains('button', 'Create New Note', { timeout: 30000 })
.should('exist')
.click();

const title = "Fried Rice";
const info = "I loved the taste in the new shop";
cy.get('input[placeholder="Title"]', { timeout: 30000 }).type(title);
cy.get('div.ql-editor p').clear().type(info);
cy.contains('button', 'Create Note').click();

cy.get('div.rounded-xl.border.bg-card.text-card-foreground.shadow-md', { timeout: 30000 })
.its('length')
.then((newCount) => {
cy.log(`New number of elements: ${newCount}`);
expect(newCount).to.eq(initialCount);
});
});
});
  1. Test Suite: Tests the "Create Note" functionality.
  2. Test1 Create Note:
    • Logs in using cy.login and visits /list.
    • Counts the number of notes before creating a new one.
    • Clicks the "Create Note" button, fills in the required data, and submits the form.
    • Verifies the count of notes increases by one after creation.
  3. Test2 Missing Title Error:
    • Logs in using cy.login and visits /list.
    • Clicks the "Create Note" button.
    • Leaves the "Title" field empty and submits the form.
    • Verifies the "Title" field is marked invalid.
  4. Assertions:
    • Ensures the count of notes increases when a valid note is created.
    • Confirms the "Title" field is invalid when left empty.

Although we could just assert from the notification message, it's better to actually count and verify because it also checks if the website refreshes the /list automatically.


Simplifying Create Note Code:โ€‹

createNoteSimplify.cy.js
describe('Create Note', () => {
it('should create a new note', () => {
cy.login('mourya', 'password123');
cy.visit('/list');

cy.get('div.rounded-xl.border.bg-card.text-card-foreground.shadow-md', {timeout: 40000})
.then((notesBefore) => {
const countBefore = notesBefore.length;
const title = "Fried Rice";
const info = "I loved the taste in the new shop";
cy.log(`Initial number of notes: ${countBefore}`);

cy.contains('button', 'Create New Note', { timeout: 30000 })
.should('exist')
.click();

cy.get('input[placeholder="Title"]', { timeout: 30000 }).type(title);
cy.get('div.ql-editor p').clear().type(info);
cy.contains('button', 'Create Note').click();

cy.get('div.rounded-xl.border.bg-card.text-card-foreground.shadow-md')
.should((notesAfter) => {
expect(notesAfter.length).to.eq(countBefore + 1);
});
});
});
});

Explanation:โ€‹

  1. Test Suite: Tests the "Create Note" functionality.
  2. Test: 'should create a new note':
    • Logs in using cy.login with valid credentials.
    • Visits /list, the page where notes are listed.
    • Captures the current number of notes displayed using cy.get and the specified selector.
    • Here, .then((notesBefore) => { ... }) captures the list of notes currently displayed on the page and allows storing the length in a variable (countBefore) for further use in assertions.
    • Defines the title and content for the new note
    • Clicks the "Create New Note" button to open the form.
    • Fills in the "Title" and "Body" fields.
    • Submits the form by clicking the "Create Note" button.
    • Verifies the note count increased by 1, ensuring the note was created successfully.
  3. Assertions:
    • Confirms the "Create New Note" button exists.
    • Validates the final note count matches countBefore + 1.

Create Note Simplify


๐Ÿ“Œ Github Repositoryโ€‹

๐ŸŽ‰ That wraps it up! For more diverse examples, visit the GitHub repository. Happy testing! ๐Ÿงชโœจ