All work
Personal project

E-Commerce Web Automation

Cypress UI + API automation

CypressJavaScriptPage Object ModelGitHub ActionsMochawesomeRestful BookerAutomation Exercise
38
End-to-end tests
100%
Pass rate
9
Spec suites

Overview

A Cypress suite that covers a full e-commerce shopping journey on the Automation Exercise demo site - from register and login through products, cart, and checkout - alongside an API layer.

API testing is split across two targets: Restful Booker as a stable CRUD-with-auth target, and the Automation Exercise API for status-code and negative checks. UI flows use the Page Object Model.

Objective

Automate the register → login → browse → cart → checkout journey with real UI assertions, and cover a REST API end to end: auth, CRUD, and negative status codes.

Testing scope

  • Login & Register

    • Reject login with wrong credentials and with an empty email
    • Log in successfully with a registered account
    • Register a new user through to Account Created
    • Reject registration with an already-registered email
  • Products

    • List all products and open a product detail from the list
    • Search returns matching results
    • Search for a missing product returns an empty result
    • Filter by category (Women > Dress)
  • Cart & Checkout

    • Add one and multiple products; verify the displayed price
    • Remove a product, and remove one of several leaving the rest correct
    • Checkout end to end: cart → address → payment → order placed
    • Guests cannot check out - the Register/Login modal appears
  • Contact & Video Tutorials

    • Submit the Contact Us form with a file upload
    • Block submit when the required email is missing
    • The Video Tutorials link points to YouTube
  • API - Restful Booker (CRUD + auth)

    • POST /auth returns a token
    • GET list, POST create, GET by id
    • PUT update and DELETE require the token
    • GET the deleted booking returns 404
  • API - Automation Exercise

    • Negative verifyLogin: 404 unknown user, 400 missing email, 405 wrong method
    • GET products and GET brands
    • POST search products by keyword
    • Full account lifecycle: create → verify → delete

Test strategy

  • Page Object Model with a per-page element map and chainable actions.
  • API split: Restful Booker for stable CRUD, Automation Exercise for status codes.
  • Sequential CRUD passes the auth token and booking id between tests.
  • Dynamic test data - timestamped names and computed dates - avoids collisions.
  • File upload and required-field validation on the Contact form.
  • GitHub Actions runs the suite and publishes the Mochawesome report.

Architecture

  1. Spec fileUI + API describe / it
  2. Page Objectelement map + actions
  3. Automation Exercise / Restful Bookersystems under test
  4. GitHub ActionsCypress run on push
  5. Mochawesome → GitHub Pagespublished report

Implementation

The Page Object groups selectors in one map and returns this for chainable actions.
class LoginPage {
  elements = {
    emailInput:    () => cy.get('input[data-qa="login-email"]'),
    passwordInput: () => cy.get('input[data-qa="login-password"]'),
    loginButton:   () => cy.get('[data-qa="login-button"]'),
  };

  visit() {
    cy.visit('https://automationexercise.com');
    cy.get('a[href="/login"]').click();
    return this;
  }
  fillEmail(email)       { this.elements.emailInput().type(email); return this; }
  fillPassword(password) { this.elements.passwordInput().type(password); return this; }
  submit()               { this.elements.loginButton().click(); return this; }
}
The auth test captures a token that later PUT and DELETE calls reuse.
it('POST /auth returns a token', () => {
  cy.request({
    method: 'POST',
    url: `${baseUrl}/auth`,
    body: { username: 'admin', password: 'password123' },
  }).then((res) => {
    expect(res.status).to.eq(200)
    expect(res.body.token).to.be.a('string').and.not.be.empty
    token = res.body.token // reused by PUT & DELETE
  })
})
Booking data is generated per run so tests never collide on stale records.
const fmt = (d) => d.toISOString().split('T')[0]
const checkout = new Date()
checkout.setDate(checkout.getDate() + 3)

const booking = {
  firstname: `Fajar${Date.now()}`,
  lastname: 'QA',
  totalprice: 250,
  depositpaid: true,
  bookingdates: { checkin: fmt(new Date()), checkout: fmt(checkout) },
  additionalneeds: 'Breakfast',
}

Results

38

Tests

across 9 spec suites

38

Passed

0

Failed

100%

Pass rate

Links