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
7 changes: 6 additions & 1 deletion cucumber.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
module.exports = {
default: `--require-module ts-node/register --require './steps/**/*.ts' --require './hooks/**/*.ts --format @cucumber/pretty-formatter`
default: [
'--require-module ts-node/register',
'--require hooks/**/*.ts',
'--require steps/**/*.ts',
'--publish-quiet'
].join(' ')
};
5 changes: 2 additions & 3 deletions features/login.feature
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ 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
Then I should see the login error message "Epic sadface: Sorry, this user has been locked out."
9 changes: 5 additions & 4 deletions features/product.feature
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ Feature: Product Feature
# 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
Then I sort products by "<sortOption>"
Then products should be sorted by price "<order>"
Examples:
# TODO: extend the datatable to paramterize this test
| sort |
| sortOption | order |
| Price (low to high) | asc |
| Price (high to low) | desc |
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 cart count should be "1"
Then I open the cart
Then I checkout the product
Then I enter checkout information "Rajesh" "Sathuri" "500081"
Then I finish the purchase
Then I should see the purchase confirmation text "Thank you for your order!"
9 changes: 8 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions pages/checkout.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Page } from "@playwright/test";

export class Checkout {
constructor(private page: Page) {}

async openCart() {
await this.page.locator('.shopping_cart_link').click();
}

async checkout() {
await this.page.locator('#checkout').click();
}

async enterUserInfo(first: string, last: string, zip: string) {
await this.page.locator('#first-name').fill(first);
await this.page.locator('#last-name').fill(last);
await this.page.locator('#postal-code').fill(zip);
await this.page.locator('#continue').click();
}

async finishPurchase() {
await this.page.locator('#finish').click();
}

async validateConfirmation(expected: string) {
const actual = await this.page.locator('.complete-header').innerText();
if (actual.trim() !== expected) {
throw new Error(`Expected "${expected}" but got "${actual}"`);
}
}
}
14 changes: 13 additions & 1 deletion pages/login.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,16 @@ export class Login {
await this.page.locator(this.passwordField).fill(this.password)
await this.page.locator(this.loginButton).click()
}
}
public async validateLoginError(expected: string) {
const errorMessage = await this.page
.locator('h3[data-test="error"]')
.innerText();

if (errorMessage.trim() !== expected) {
throw new Error(
`Expected error message to be "${expected}" but found "${errorMessage}"`
);
}
}
}

61 changes: 54 additions & 7 deletions pages/product.page.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,61 @@
import { Page } from "@playwright/test"
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 page: Page;

constructor(page: Page) {
this.page = page;
private readonly addToCart =
'button[id="add-to-cart-sauce-labs-backpack"]';
private readonly sortDropdown =
'select.product_sort_container';
private readonly prices =
'.inventory_item_price';
private readonly cartBadge =
'.shopping_cart_badge';

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

public async addBackPackToCart() {
await this.page.locator(this.addToCart).click();
}

public async sortProducts(option: string) {
const dropdown = this.page.locator(this.sortDropdown);
await dropdown.waitFor({ state: 'visible' });
await dropdown.selectOption({ label: option });
}

private async getAllPrices(): Promise<number[]> {
const priceTexts = await this.page
.locator(this.prices)
.allInnerTexts();

return priceTexts.map(p => Number(p.replace('$', '').trim()));
}

public async validatePriceSorting(order: string) {
const prices = await this.getAllPrices();
const sorted = [...prices].sort((a, b) =>
order === 'asc' ? a - b : b - a
);

if (JSON.stringify(prices) !== JSON.stringify(sorted)) {
throw new Error(
`Prices are not sorted in ${order} order. Actual: ${prices}`
);
}
}

// EXTRA COVERAGE

public async validateCartCount(expected: string) {
const count = await this.page.locator(this.cartBadge).innerText();

public async addBackPackToCart() {
await this.page.locator(this.addToCart).click()
if (count !== expected) {
throw new Error(
`Expected cart count ${expected} but found ${count}`
);
}
}
}
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 login error message {string}', async (expectedMessage) => {
await new Login(getPage()).validateLoginError(expectedMessage);
});
12 changes: 12 additions & 0 deletions steps/product.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,16 @@ 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 (option: string) => {
await new Product(getPage()).sortProducts(option);
});

Then('products should be sorted by price {string}', async (order: string) => {
await new Product(getPage()).validatePriceSorting(order);
});

Then('cart count should be {string}', async (count: string) => {
await new Product(getPage()).validateCartCount(count);
});
29 changes: 29 additions & 0 deletions steps/purchase.steps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Then } from '@cucumber/cucumber';
import { getPage } from '../playwrightUtilities';
import { Checkout } from '../pages/checkout.page';

Then('I open the cart', async () => {
await new Checkout(getPage()).openCart();
});

Then('I checkout the product', async () => {
await new Checkout(getPage()).checkout();
});

Then(
'I enter checkout information {string} {string} {string}',
async (first: string, last: string, zip: string) => {
await new Checkout(getPage()).enterUserInfo(first, last, zip);
}
);

Then('I finish the purchase', async () => {
await new Checkout(getPage()).finishPurchase();
});

Then(
'I should see the purchase confirmation text {string}',
async (expected: string) => {
await new Checkout(getPage()).validateConfirmation(expected);
}
);