Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,324 changes: 2,324 additions & 0 deletions cucumber_report.html

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions features/login.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Feature: Login Feature

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
When I will login as 'locked_out_user'
Then I should see error message as 'Sorry, this user has been locked out.'
27 changes: 20 additions & 7 deletions features/product.feature
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,23 @@ Feature: Product Feature
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 <sort>
Then I will login as 'standard_user'
# TODO: Sort the items by <sort>
# TODO: Validate all 6 items are sorted correctly by price
Examples:
# TODO: extend the datatable to paramterize this test
| sort |
Scenario Outline: Validate product sort by price
Then I will login as 'standard_user'
Then I sort the products by "<sort>"
Then the product prices should be sorted "<order>"

Examples:
| sort | order |
| Price (high to low) | desc |
| Price (low to high) | asc |

Scenario: Validate cart badge count after adding backpack
Then I will login as 'standard_user'
Then I will add the backpack to the cart
Then the cart badge count should be "1"

Scenario: Validate removing backpack from cart
Then I will login as 'standard_user'
Then I will add the backpack to the cart
Then I remove the backpack from the cart
Then the cart badge should not be visible
12 changes: 6 additions & 6 deletions features/purchase.feature
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ Feature: Purchase Feature
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!'
Then I click on the cart
Then I Select Checkout
Then I Fill in the "Jon", "Doe", and "53356"
Then I Select Continue
Then I Select Finish
Then I Validate the text 'Thank you for your order!'
104 changes: 104 additions & 0 deletions fixes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@

# ✅ Task Implementation

## ✔ 1. Fix Login Page Title Scenario

* **Task:** Modify the scenario *"Validate the login page title"* from [`login.feature`](features/login.feature#8), which was running but failing.

* **Root Cause:**
The expected page title was incorrect:

* ❌ Expected: `Labs Swag`
* ✅ Actual: `Swag Labs`

* **Fix Implemented:**
Updated the Cucumber scenario to validate the correct page title:

```
Swag Labs
```

---

## ✔ 2. Extend Login Error Message Scenario

* **Task:** Extend the scenario *"Validate login error message"* from [`login.feature`](features/login.feature#10), which was missing validation.

* **Enhancement Implemented:**
Added validation for the error message when logging in with a locked user.

* **Expected Behavior:**
When logging in with `locked_out_user`, the system should display:

```
Sorry, this user has been locked out.
```

* **Outcome:**
Scenario now validates both:

* Error visibility
* Correct error message text

---

## ✔ 3. Implement Successful Purchase Flow

* **Task:** Modify and extend *"Validate successful purchase text"* from [`purchase.feature`](features/purchase.feature#6).

* **Implementation Details:**

* Implemented complete end-to-end purchase flow:

* Login
* Add product to cart
* Open cart
* Checkout
* Enter user details
* Continue
* Finish purchase
* Created:

* `purchase.steps.ts`
* Updated `product.page.ts`

* **Validation Added:**

```
Thank you for your order!
```

---

## ✔ 4. Implement Product Sorting Validation

* **Task:** Modify and extend *"Validate product sort by price"* from [`product.feature`](features/product.feature#6).

* **Implementation Details:**

* Used **Scenario Outline** with **Examples table**
* Parameterized sorting options:

* `Price (low to high)`
* `Price (high to low)`

* **Validation Added:**

* Verified product prices are correctly sorted:

* Ascending order
* Descending order

---

## ✔ 5. Extend Test Coverage

### 🔹 Added Additional Scenarios:

* **Cart Badge Validation (Add Item)**

* Verified cart badge count after adding an item

* **Cart Badge Validation (Remove Item)**

* Verified cart badge is removed after deleting the item from cart
85 changes: 83 additions & 2 deletions pages/product.page.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
import { Page } from "@playwright/test"
import { Page, expect } from "@playwright/test"

export class Product {
private readonly page: Page
private readonly addToCart: string = 'button[id="add-to-cart-sauce-labs-backpack"]'
private readonly cartLink = '.shopping_cart_link';
private readonly checkoutButton = '#checkout';

private readonly firstNameField = '#first-name';
private readonly lastNameField = '#last-name';
private readonly postalCodeField = '#postal-code';
private readonly continueButton = '#continue';

private readonly finishButton = '#finish';
private readonly completeHeader = '[data-test="complete-header"]';

private readonly sortDropdown = '[data-test="product-sort-container"]';
private readonly productPrices = '.inventory_item_price';

private readonly cartBadge = '.shopping_cart_badge';

private readonly removeFromCart = '#remove-sauce-labs-backpack';

constructor(page: Page) {
this.page = page;
Expand All @@ -11,4 +28,68 @@ export class Product {
public async addBackPackToCart() {
await this.page.locator(this.addToCart).click()
}
}

public async openCart() {
await this.page.locator(this.cartLink).click();
}

public async clickCheckout(){
await this.page.locator(this.checkoutButton).click();
}

public async fillPersonalInfo(
firstName: string,
lastName: string,
zipCode: string) {

await this.page.locator(this.firstNameField).fill(firstName);
await this.page.locator(this.lastNameField).fill(lastName);
await this.page.locator(this.postalCodeField).fill(zipCode);

}
public async clickContinue(){
await this.page.locator(this.continueButton).click();
}

public async clickFinish() {
await this.page.locator(this.finishButton).click();
}

public async validatePurchaseConfirmationText(expectedText: string) {
await expect(this.page.locator(this.completeHeader)).toBeVisible();
await expect(this.page.locator(this.completeHeader)).toHaveText(expectedText);
}

public async sortProductsBy(sortOption: string) {
await this.page.locator(this.sortDropdown).selectOption({ label: sortOption });
}

public async validatePricesSorted(order: string) {
const priceTexts = await this.page.locator(this.productPrices).allTextContents();

const actualPrices = priceTexts.map((text) =>
Number(text.replace('$', '').trim())
);

expect(actualPrices).toHaveLength(6);

const expectedPrices = [...actualPrices].sort((a, b) =>
order.toLowerCase() === 'desc' ? b - a : a - b
);

expect(actualPrices).toEqual(expectedPrices);
}

public async validateCartBadgeCount(expectedCount: string) {
await expect(this.page.locator(this.cartBadge)).toBeVisible();
await expect(this.page.locator(this.cartBadge)).toHaveText(expectedCount);
}

public async removeBackPackFromCart() {
await this.page.locator(this.removeFromCart).click();
}

public async validateCartBadgeNotVisible() {
await expect(this.page.locator(this.cartBadge)).toHaveCount(0);
}
}
Loading