From b1e951ac8941ab03190a9b6b9232335d2ea5648f Mon Sep 17 00:00:00 2001 From: vanitham4692-a11y Date: Tue, 24 Mar 2026 12:37:14 -0400 Subject: [PATCH] Added Test Scenarios for Login, Product, Purchase --- features/login.feature | 9 +++++--- features/product.feature | 15 +++++++------ features/purchase.feature | 17 +++++++------- pages/login.page.ts | 10 ++++++++- pages/product.page.ts | 17 ++++++++++++++ pages/purchase.page.ts | 47 +++++++++++++++++++++++++++++++++++++++ steps/login.steps.ts | 8 +++++++ steps/product.steps.ts | 9 ++++++++ steps/purchase.steps.ts | 32 ++++++++++++++++++++++++++ 9 files changed, 144 insertions(+), 20 deletions(-) create mode 100644 pages/purchase.page.ts create mode 100644 steps/purchase.steps.ts diff --git a/features/login.feature b/features/login.feature index fb9f1fa..daac559 100644 --- a/features/login.feature +++ b/features/login.feature @@ -4,9 +4,12 @@ Feature: Login Feature Given I open the "https://www.saucedemo.com/" page Scenario: Validate the login page title - # TODO: Fix this failing scenario - Then I should see the title "Labs Swag" + Then I should see the title "Swag Labs" Scenario: Validate login error message Then I will login as 'locked_out_user' - # TODO: Add a step to validate the error message received \ No newline at end of file + Then I should see the error message "Epic sadface: Sorry, this user has been locked out." + + Scenario: Validate invalid login + Then I will login as 'invalid_user' + Then I should see the error message "Epic sadface: Username and password do not match any user in this service" \ No newline at end of file diff --git a/features/product.feature b/features/product.feature index 8a7ceab..1a846b2 100644 --- a/features/product.feature +++ b/features/product.feature @@ -3,11 +3,12 @@ Feature: Product Feature Background: Given I open the "https://www.saucedemo.com/" page - # Create a datatable to validate the Price (high to low) and Price (low to high) sort options (top-right) using a Scenario Outline - Scenario Outline: Validate product sort by price - Then I will login as 'standard_user' - # TODO: Sort the items by - # TODO: Validate all 6 items are sorted correctly by price + Scenario Outline: Validate product sort by price + Then I will login as 'standard_user' + Then I sort products by "" + Then products should be sorted "" + Examples: - # TODO: extend the datatable to paramterize this test - | sort | \ No newline at end of file + | sort | order | + | Price (low to high) | asc | + | Price (high to low) | desc | \ No newline at end of file diff --git a/features/purchase.feature b/features/purchase.feature index 2863478..3bba2e9 100644 --- a/features/purchase.feature +++ b/features/purchase.feature @@ -3,12 +3,11 @@ Feature: Purchase Feature Background: Given I open the "https://www.saucedemo.com/" page - Scenario: Validate successful purchase text - Then I will login as 'standard_user' - Then I will add the backpack to the cart - # TODO: Select the cart (top-right) - # TODO: Select Checkout - # TODO: Fill in the First Name, Last Name, and Zip/Postal Code - # TODO: Select Continue - # TODO: Select Finish - # TODO: Validate the text 'Thank you for your order!' \ No newline at end of file + Scenario: Validate successful purchase text + Then I will login as 'standard_user' + Then I will add the backpack to the cart + Then I open the cart + Then I checkout the product + Then I enter checkout details "John" "Doe" "560001" + Then I finish the purchase + Then I should see confirmation message "Thank you for your order!" \ No newline at end of file diff --git a/pages/login.page.ts b/pages/login.page.ts index 5a01614..2b9f9fe 100644 --- a/pages/login.page.ts +++ b/pages/login.page.ts @@ -6,6 +6,7 @@ export class Login { private readonly passwordField: string = 'input[id="password"]' private readonly userNameField: string = 'input[id="user-name"]' private readonly loginButton: string = 'input[id="login-button"]' + private readonly errorMessage: string = 'h3[data-test="error"]' constructor(page: Page) { this.page = page; @@ -14,7 +15,7 @@ export class Login { public async validateTitle(expectedTitle: string) { const pageTitle = await this.page.title(); if (pageTitle !== expectedTitle) { - throw new Error(`Expected title to be ${expectedTitle} but found ${pageTitle}`); + throw new Error(Expected title to be ${expectedTitle} but found ${pageTitle}); } } @@ -23,4 +24,11 @@ export class Login { await this.page.locator(this.passwordField).fill(this.password) await this.page.locator(this.loginButton).click() } + + public async validateErrorMessage(expectedMessage: string) { + const actualMessage = await this.page.locator(this.errorMessage).innerText() + if (actualMessage !== expectedMessage) { + throw new Error(Expected error message: ${expectedMessage}, but got: ${actualMessage}) + } +} } \ No newline at end of file diff --git a/pages/product.page.ts b/pages/product.page.ts index 14bedb1..28917c9 100644 --- a/pages/product.page.ts +++ b/pages/product.page.ts @@ -3,6 +3,8 @@ import { Page } from "@playwright/test" export class Product { private readonly page: Page private readonly addToCart: string = 'button[id="add-to-cart-sauce-labs-backpack"]' + private readonly sortDropdown = '.product_sort_container' + private readonly prices = '.inventory_item_price' constructor(page: Page) { this.page = page; @@ -11,4 +13,19 @@ export class Product { public async addBackPackToCart() { await this.page.locator(this.addToCart).click() } + async sortBy(option: string) { + await this.page.selectOption(this.sortDropdown, { label: option }) + } + + async validateSorted(order: string) { + const priceTexts = await this.page.locator(this.prices).allTextContents() + + const prices = priceTexts.map(p => parseFloat(p.replace('$', ''))) + + const sorted = [...prices].sort((a, b) => order === 'asc' ? a - b : b - a) + + if (JSON.stringify(prices) !== JSON.stringify(sorted)) { + throw new Error(Products are not sorted correctly: ${order}) + } + } } \ No newline at end of file diff --git a/pages/purchase.page.ts b/pages/purchase.page.ts new file mode 100644 index 0000000..a410669 --- /dev/null +++ b/pages/purchase.page.ts @@ -0,0 +1,47 @@ +import { Page } from "@playwright/test" + +export class Purchase { + private readonly page: Page + + private readonly cartIcon = '.shopping_cart_link' + private readonly checkoutBtn = '#checkout' + private readonly firstName = '#first-name' + private readonly lastName = '#last-name' + private readonly zip = '#postal-code' + private readonly continueBtn = '#continue' + private readonly finishBtn = '#finish' + private readonly successMsg = '.complete-header' + + constructor(page: Page) { + this.page = page; + } + + async openCart() { + await this.page.locator(this.cartIcon).click() + } + + async checkout() { + await this.page.locator(this.checkoutBtn).click() + } + + async enterDetails(fn: string, ln: string, zip: string) { + await this.page.fill(this.firstName, fn) + await this.page.fill(this.lastName, ln) + await this.page.fill(this.zip, zip) + } + + async continue() { + await this.page.locator(this.continueBtn).click() + } + + async finish() { + await this.page.locator(this.finishBtn).click() + } + + async validateSuccessMessage(expected: string) { + const actual = await this.page.locator(this.successMsg).innerText() + if (actual !== expected) { + throw new Error(Expected: ${expected}, Got: ${actual}) + } + } +} \ No newline at end of file diff --git a/steps/login.steps.ts b/steps/login.steps.ts index c2aa0d8..b1f2643 100644 --- a/steps/login.steps.ts +++ b/steps/login.steps.ts @@ -8,4 +8,12 @@ Then('I should see the title {string}', async (expectedTitle) => { Then('I will login as {string}', async (userName) => { await new Login(getPage()).loginAsUser(userName); +}); + +Then('I should see the error message {string}', async (expectedMessage) => { + await new Login(getPage()).validateErrorMessage(expectedMessage); +}); + +Then('I click login without credentials', async () => { + await getPage().locator('#login-button').click(); }); \ No newline at end of file diff --git a/steps/product.steps.ts b/steps/product.steps.ts index bb52fb9..162347c 100644 --- a/steps/product.steps.ts +++ b/steps/product.steps.ts @@ -4,4 +4,13 @@ import { Product } from '../pages/product.page'; Then('I will add the backpack to the cart', async () => { await new Product(getPage()).addBackPackToCart(); +}); + + +Then('I sort products by {string}', async (sortOption) => { + await new Product(getPage()).sortBy(sortOption); +}); + +Then('products should be sorted {string}', async (order) => { + await new Product(getPage()).validateSorted(order); }); \ No newline at end of file diff --git a/steps/purchase.steps.ts b/steps/purchase.steps.ts new file mode 100644 index 0000000..2180099 --- /dev/null +++ b/steps/purchase.steps.ts @@ -0,0 +1,32 @@ +import { Then } from '@cucumber/cucumber'; +import { getPage } from '../playwrightUtilities'; +import { Purchase } from '../pages/purchase.page'; + +Then('I open the cart', async () => { + await new Purchase(getPage()).openCart(); +}); + +Then('I checkout the product', async () => { + await new Purchase(getPage()).checkout(); +}); + +Then( + 'I enter checkout details {string} {string} {string}', + async (firstName, lastName, zip) => { + await new Purchase(getPage()).enterDetails(firstName, lastName, zip); + } +); + +Then('I continue checkout', async () => { + await new Purchase(getPage()).continue(); +}); + +Then('I finish the purchase', async () => { + const purchase = new Purchase(getPage()); + await purchase.continue(); + await purchase.finish(); +}); + +Then('I should see confirmation message {string}', async (expected) => { + await new Purchase(getPage()).validateSuccessMessage(expected); +}); \ No newline at end of file