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
4 changes: 2 additions & 2 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
Then I should see the error message "Epic sadface: Sorry, this user has been locked out."
14 changes: 7 additions & 7 deletions features/product.feature
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ 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 <sort>
Then I will login as 'standard_user'
# TODO: Sort the items by <sort>
# TODO: Validate all 6 items are sorted correctly by price
Scenario Outline: Validate product sort by price <sort>
Then I will login as 'standard_user'
Then sort the items by "<sort>"
Then all items are sorted correctly by "<sort>"
Examples:
# TODO: extend the datatable to paramterize this test
| sort |
| sort |
| Price (low to high) |
| Price (high to low) |
18 changes: 9 additions & 9 deletions features/purchase.feature
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ 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!'
Scenario: Validate successful purchase text
Then I will login as 'standard_user'
Then I will add the backpack to the cart
Then select the cart
Then select Checkout
Then fill in "John" "Doe" and "12345"
Then select Continue
Then select Finish
Then should see the confirmation text "Thank you for your order!"
46 changes: 46 additions & 0 deletions pages/checkout.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Page } from "@playwright/test"

export class Checkout {
private readonly page: Page
private readonly cartIcon: string = 'a.shopping_cart_link'
private readonly checkoutButton: string = 'button[id="checkout"]'
private readonly firstNameField: string = 'input[id="first-name"]'
private readonly lastNameField: string = 'input[id="last-name"]'
private readonly postalCodeField: string = 'input[id="postal-code"]'
private readonly continueButton: string = 'input[id="continue"]'
private readonly finishButton: string = 'button[id="finish"]'
private readonly confirmationHeader: string = 'h2.complete-header'

constructor(page: Page) {
this.page = page;
}

public async goToCart() {
await this.page.locator(this.cartIcon).click();
}

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

public async fillInDetails(firstName: string, lastName: string, postalCode: string) {
await this.page.locator(this.firstNameField).fill(firstName);
await this.page.locator(this.lastNameField).fill(lastName);
await this.page.locator(this.postalCodeField).fill(postalCode);
}

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

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

public async validateConfirmationText(expectedText: string) {
const confirmationText = await this.page.locator(this.confirmationHeader).innerText();
if (confirmationText !== expectedText) {
throw new Error(`Expected confirmation text to be "${expectedText}" but found "${confirmationText}"`);
}
}
}
7 changes: 7 additions & 0 deletions pages/login.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,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 errorMessage = await this.page.locator('[data-test="error"]').innerText();
if (errorMessage !== expectedMessage) {
throw new Error(`Expected error message to be "${expectedMessage}" but found "${errorMessage}"`);
}
}
}
18 changes: 18 additions & 0 deletions pages/product.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: string = 'select[data-test="product-sort-container"]'
private readonly itemPrices: string = '.inventory_item_price'

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

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

public async validateSortedByPrice(sortOption: string) {
const priceElements = await this.page.locator(this.itemPrices).allInnerTexts();
const prices = priceElements.map(p => parseFloat(p.replace('$', '')));

const isAscending = sortOption === 'Price (low to high)';
const sorted = [...prices].sort((a, b) => isAscending ? a - b : b - a);

if (JSON.stringify(prices) !== JSON.stringify(sorted)) {
throw new Error(`Expected prices to be sorted by "${sortOption}" but found: ${prices.join(', ')}`);
}
}
}
27 changes: 27 additions & 0 deletions steps/checkout.steps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Then } from '@cucumber/cucumber';
import { getPage } from '../playwrightUtilities';
import { Checkout } from '../pages/checkout.page';

Then('select the cart', async () => {
await new Checkout(getPage()).goToCart();
});

Then('select Checkout', async () => {
await new Checkout(getPage()).selectCheckout();
});

Then('fill in {string} {string} and {string}', async (firstName: string, lastName: string, postalCode: string) => {
await new Checkout(getPage()).fillInDetails(firstName, lastName, postalCode);
});

Then('select Continue', async () => {
await new Checkout(getPage()).selectContinue();
});

Then('select Finish', async () => {
await new Checkout(getPage()).selectFinish();
});

Then('should see the confirmation text {string}', async (expectedText: string) => {
await new Checkout(getPage()).validateConfirmationText(expectedText);
});
4 changes: 4 additions & 0 deletions steps/login.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ 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);
});
8 changes: 8 additions & 0 deletions steps/product.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,12 @@ import { Product } from '../pages/product.page';

Then('I will add the backpack to the cart', async () => {
await new Product(getPage()).addBackPackToCart();
});

Then('sort the items by {string}', async (sortOption: string) => {
await new Product(getPage()).sortBy(sortOption);
});

Then('all items are sorted correctly by {string}', async (sortOption: string) => {
await new Product(getPage()).validateSortedByPrice(sortOption);
});
Loading