Learn Cypress in 10 DaysDay 5: Navigation and Form Handling
Chapter 5Learn Cypress in 10 Days

Day 5: Navigation and Form Handling

What You Will Learn Today

  • Advanced options for cy.visit() (baseUrl, timeout, headers)
  • URL verification with cy.url() and cy.location()
  • Browser navigation with cy.go() and cy.reload()
  • Interacting with form elements (input, select, checkbox, radio, textarea)
  • File uploads with cy.selectFile()
  • Form submission and validation testing

Page Navigation Basics

Advanced Options for cy.visit()

cy.visit() does more than simply open a URL β€” it accepts a variety of configuration options.

// Basic usage
cy.visit('https://example.com')

// Relative path (when baseUrl is configured)
cy.visit('/login')

// With options
cy.visit('/dashboard', {
  timeout: 30000,          // Timeout in milliseconds
  failOnStatusCode: false, // Disable failure on non-2xx status codes
  headers: {
    'Accept-Language': 'en'
  },
  auth: {
    username: 'admin',
    password: 'secret'
  },
  qs: {
    page: 1,
    sort: 'name'
  }
})

Configuring baseUrl

Setting baseUrl in cypress.config.js eliminates the need to write full URLs in every test.

// cypress.config.js
const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
  }
})
// With baseUrl configured, relative paths are all you need
cy.visit('/')          // http://localhost:3000/
cy.visit('/about')     // http://localhost:3000/about
cy.visit('/users/1')   // http://localhost:3000/users/1
flowchart LR
    Config["cypress.config.js\nbaseUrl setting"] --> Visit["cy.visit('/path')"]
    Visit --> Full["http://localhost:3000/path"]

    style Config fill:#3b82f6,color:#fff
    style Visit fill:#8b5cf6,color:#fff
    style Full fill:#22c55e,color:#fff

URL Verification

Checking the URL with cy.url()

// Verify the current URL
cy.visit('/login')
cy.url().should('include', '/login')
cy.url().should('eq', 'http://localhost:3000/login')
cy.url().should('match', /\/login$/)

Getting Detailed URL Information with cy.location()

// URL: http://localhost:3000/search?q=cypress#results

cy.location().should((loc) => {
  expect(loc.protocol).to.eq('http:')
  expect(loc.hostname).to.eq('localhost')
  expect(loc.port).to.eq('3000')
  expect(loc.pathname).to.eq('/search')
  expect(loc.search).to.eq('?q=cypress')
  expect(loc.hash).to.eq('#results')
})

// Verify a specific property only
cy.location('pathname').should('eq', '/search')
cy.location('search').should('include', 'q=cypress')
Command Return Value Use Case
cy.url() Full URL string Simple URL verification
cy.location() Location object Detailed URL verification
cy.location('pathname') Path string Path-only verification
cy.location('search') Query string Query parameter verification
cy.location('hash') Hash string Hash fragment verification

Browser Navigation

Navigating History with cy.go()

// Visit pages then navigate back
cy.visit('/page-1')
cy.visit('/page-2')
cy.visit('/page-3')

// Go back
cy.go('back')
cy.url().should('include', '/page-2')

// Go back again
cy.go(-1)
cy.url().should('include', '/page-1')

// Go forward
cy.go('forward')
cy.url().should('include', '/page-2')

// Go forward 2 steps
cy.go(2)
cy.url().should('include', '/page-3') // Depends on browser history

Reloading the Page with cy.reload()

// Standard reload
cy.reload()

// Hard reload (bypass cache)
cy.reload(true)
flowchart LR
    Back["cy.go('back')\ncy.go(-1)"] --> Current["Current Page"]
    Current --> Forward["cy.go('forward')\ncy.go(1)"]
    Current --> Reload["cy.reload()"]
    Reload --> Current

    style Back fill:#f59e0b,color:#fff
    style Current fill:#3b82f6,color:#fff
    style Forward fill:#22c55e,color:#fff
    style Reload fill:#8b5cf6,color:#fff

Interacting with Form Elements

Text Input (input, textarea)

// Text input
cy.get('#username').type('testuser')
cy.get('#password').type('secret123')

// Textarea
cy.get('textarea#comment').type('This is a comment.\nLine breaks work too.')

// Special key input
cy.get('#search').type('Cypress{enter}')        // Enter key
cy.get('#email').type('{selectall}{backspace}')  // Select all and delete
cy.get('#field').type('{ctrl+a}')                // Ctrl+A

// Clear before typing
cy.get('#name').clear().type('New Name')

// Type with delay (100ms per character)
cy.get('#slow-input').type('typing slowly', { delay: 100 })

Special Keys Available in type()

Key Syntax Description
Enter {enter} Enter key
Tab {tab} Tab key
Escape {esc} Escape key
Backspace {backspace} Backspace key
Delete {del} Delete key
Up Arrow {uparrow} Up arrow key
Down Arrow {downarrow} Down arrow key
Left Arrow {leftarrow} Left arrow key
Right Arrow {rightarrow} Right arrow key
Select All {selectall} Select all text

Select Boxes

// Select by visible text
cy.get('#country').select('Japan')

// Select by value attribute
cy.get('#country').select('jp')

// Select by index
cy.get('#country').select(2)

// Multiple selection (select with multiple attribute)
cy.get('#skills').select(['JavaScript', 'TypeScript', 'Python'])

// Verify the selected value
cy.get('#country').should('have.value', 'jp')
// HTML example
// <select id="country">
//   <option value="">Please select</option>
//   <option value="jp">Japan</option>
//   <option value="us">United States</option>
//   <option value="uk">United Kingdom</option>
// </select>

cy.get('#country').select('Japan')
cy.get('#country').should('have.value', 'jp')

Checkboxes and Radio Buttons

// Check a checkbox
cy.get('#agree').check()
cy.get('#agree').should('be.checked')

// Uncheck a checkbox
cy.get('#agree').uncheck()
cy.get('#agree').should('not.be.checked')

// Check specific values (multiple checkboxes with the same name)
cy.get('input[name="hobbies"]').check(['reading', 'coding'])

// Select a radio button
cy.get('input[name="gender"]').check('male')
cy.get('input[name="gender"]').should('have.value', 'male')

// Force option (for hidden elements)
cy.get('#hidden-checkbox').check({ force: true })
flowchart TB
    subgraph CheckboxOps["Checkbox Operations"]
        Check["cy.check()"] --> Checked["Checked state"]
        Uncheck["cy.uncheck()"] --> Unchecked["Unchecked state"]
    end

    subgraph RadioOps["Radio Button Operations"]
        Radio["cy.check('value')"] --> Selected["Selected state"]
    end

    subgraph Verify["Verification"]
        V1["should('be.checked')"]
        V2["should('not.be.checked')"]
        V3["should('have.value', 'x')"]
    end

    style CheckboxOps fill:#3b82f6,color:#fff
    style RadioOps fill:#8b5cf6,color:#fff
    style Verify fill:#22c55e,color:#fff

File Uploads

Basics of cy.selectFile()

// Upload a file by path
cy.get('input[type="file"]').selectFile('cypress/fixtures/image.png')

// Upload multiple files
cy.get('input[type="file"]').selectFile([
  'cypress/fixtures/file1.pdf',
  'cypress/fixtures/file2.pdf'
])

// Drag-and-drop upload
cy.get('.dropzone').selectFile('cypress/fixtures/data.csv', {
  action: 'drag-drop'
})

// Upload from a Blob object
cy.get('input[type="file"]').selectFile({
  contents: Cypress.Buffer.from('file content'),
  fileName: 'test.txt',
  mimeType: 'text/plain',
  lastModified: Date.now()
})

Preparing Fixture Files

# Place test files in the fixtures directory
cypress/
  fixtures/
    image.png       # Test image
    data.csv        # Test CSV
    document.pdf    # Test PDF
    sample.json     # Test JSON

Form Submission and Validation Testing

Basic Form Submission Test

describe('Login Form', () => {
  beforeEach(() => {
    cy.visit('/login')
  })

  it('should log in successfully', () => {
    cy.get('#email').type('user@example.com')
    cy.get('#password').type('password123')
    cy.get('button[type="submit"]').click()

    cy.url().should('include', '/dashboard')
    cy.get('.welcome-message').should('contain', 'Welcome')
  })

  it('should show an error when email is empty', () => {
    cy.get('#password').type('password123')
    cy.get('button[type="submit"]').click()

    cy.get('#email-error')
      .should('be.visible')
      .and('contain', 'Please enter your email address')
  })

  it('should show an error for an invalid email', () => {
    cy.get('#email').type('invalid-email')
    cy.get('#password').type('password123')
    cy.get('button[type="submit"]').click()

    cy.get('#email-error')
      .should('be.visible')
      .and('contain', 'Please enter a valid email address')
  })
})

Comprehensive Registration Form Test

describe('Registration Form', () => {
  beforeEach(() => {
    cy.visit('/register')
  })

  it('should fill in all fields and submit successfully', () => {
    // Text inputs
    cy.get('#name').type('John Smith')
    cy.get('#email').type('john@example.com')
    cy.get('#password').type('SecurePass123!')
    cy.get('#password-confirm').type('SecurePass123!')

    // Select box
    cy.get('#state').select('California')

    // Radio button
    cy.get('input[name="gender"][value="male"]').check()

    // Checkboxes
    cy.get('input[name="interests"]').check(['technology', 'music'])

    // Textarea
    cy.get('#bio').type('Nice to meet you.')

    // File upload
    cy.get('#avatar').selectFile('cypress/fixtures/avatar.png')

    // Agree to terms
    cy.get('#terms').check()

    // Submit the form
    cy.get('form').submit()

    // Verify the success page
    cy.url().should('include', '/welcome')
    cy.get('.success-message').should('contain', 'Registration complete')
  })

  it('should show an error when passwords do not match', () => {
    cy.get('#password').type('SecurePass123!')
    cy.get('#password-confirm').type('DifferentPass456!')
    cy.get('form').submit()

    cy.get('#password-error')
      .should('be.visible')
      .and('contain', 'Passwords do not match')
  })
})

Validation Pattern Overview

flowchart TB
    subgraph Input["Input"]
        I1["Text Input"]
        I2["Selection"]
        I3["Checkbox"]
    end

    subgraph Validation["Validation"]
        V1["Required Check"]
        V2["Format Check"]
        V3["Match Check"]
        V4["Range Check"]
    end

    subgraph Result["Result"]
        R1["Success\nPage Redirect"]
        R2["Error\nMessage Display"]
    end

    Input --> Validation
    Validation --> |"Pass"| R1
    Validation --> |"Fail"| R2

    style Input fill:#3b82f6,color:#fff
    style Validation fill:#f59e0b,color:#fff
    style R1 fill:#22c55e,color:#fff
    style R2 fill:#ef4444,color:#fff

Summary

Category Command Purpose
Navigation cy.visit() Open a page
URL Verification cy.url() Verify the current URL
URL Verification cy.location() Verify detailed URL information
Navigation cy.go('back') Go to the previous page
Navigation cy.go('forward') Go to the next page
Navigation cy.reload() Reload the page
Text Input cy.type() Type text
Text Input cy.clear() Clear text
Select cy.select() Select an option
Check cy.check() Check a checkbox or radio button
Check cy.uncheck() Uncheck a checkbox
File cy.selectFile() Upload a file
Form .submit() Submit a form

Key Takeaways

  1. Configure baseUrl - Setting it in cypress.config.js keeps your test code clean and concise
  2. Use cy.location() - It lets you verify individual parts of the URL for more precise assertions
  3. clear() + type() pattern - Always clear existing input values before typing new ones
  4. Test validation thoroughly - Cover not just the happy path, but also edge cases (empty fields, invalid formats, boundary values)
  5. Use selectFile() - File uploads can be tested cleanly with this dedicated command

Exercises

Basics

  1. Use the qs option with cy.visit() to open a page with query parameters
  2. After navigating to a page, verify the URL using both cy.url() and cy.location('pathname')
  3. Use cy.clear() and cy.type() to update the value of a text input

Intermediate

  1. Write a test that interacts with a form containing a select box, checkboxes, and radio buttons
  2. Create a validation test that checks for password mismatch errors
  3. Write a navigation test using cy.go('back') and cy.go('forward')

Challenge

  1. Build an integration test that interacts with every field type in a registration form (text, select, radio, checkbox, file)
  2. Create a test suite that comprehensively covers the display and dismissal of validation error messages

References


Next Up

In Day 6, you will learn about controlling network requests. Using cy.intercept(), you will master techniques essential for testing modern web applications, including intercepting API requests, stubbing responses, and simulating errors.