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
10 changes: 8 additions & 2 deletions features/login.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ 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
# TODO: Add a step to validate the error message received
Then I should see error message "Epic sadface: Sorry, this user has been locked out."

#Extra coverage
Scenario: Validate successful login
Then I will login as 'standard_user'
Then I should be navigated to the products page
6 changes: 5 additions & 1 deletion features/product.feature
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ Feature: Product Feature
Scenario Outline: Validate product sort by price <sort>
Then I will login as 'standard_user'
# TODO: Sort the items by <sort>
Then I sort the items by "<sort>"
# TODO: Validate all 6 items are sorted correctly by price
Then I should see all products sorted by price "<sort>"
Examples:
# TODO: extend the datatable to paramterize this test
| sort |
| sort |
|hilo|
|lohi|
14 changes: 13 additions & 1 deletion features/purchase.feature
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,20 @@ Feature: Purchase Feature
Then I will login as 'standard_user'
Then I will add the backpack to the cart
# TODO: Select the cart (top-right)
Then I will select cart on the top-right
# TODO: Select Checkout
Then I will select Checkout
# TODO: Fill in the First Name, Last Name, and Zip/Postal Code
Then I will Fill in the First Name, Last Name and Zip/Postal Code
# TODO: Select Continue
Then select continue
# TODO: Select Finish
# TODO: Validate the text 'Thank you for your order!'
Then select finish
# TODO: Validate the text 'Thank you for your order!'
Then validate the text 'Thank you for your order'

#Extra coverage
Scenario: Validate cart badge count after adding a product
Then I will login as 'standard_user'
Then I will add the backpack to the cart
Then I should see the cart badge count as "1"
28 changes: 27 additions & 1 deletion package-lock.json

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

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@
"cucumber-html-reporter": "^7.1.1",
"ts-node": "^10.9.1",
"typescript": "^5.3.2"
},
"dependencies": {
"@faker-js/faker": "^10.3.0"
}
}
16 changes: 15 additions & 1 deletion pages/login.page.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Page } from "@playwright/test"
import { Page,expect } from "@playwright/test"

export class Login {
private readonly page: Page
private readonly password: string = 'secret_sauce'
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;
Expand All @@ -23,4 +24,17 @@ export class Login {
await this.page.locator(this.passwordField).fill(this.password)
await this.page.locator(this.loginButton).click()
}

public async validateErrorMessage(expectedErrorMsg:string) {
this.page.pause();
const errorMessage = this.page.locator(this.errorMessage);
await expect(errorMessage).toBeVisible();
await expect(errorMessage).toContainText(expectedErrorMsg);
}

public async validateSuccessfulLogin(){
await this.page.waitForURL('**/inventory.html');
}


}
68 changes: 67 additions & 1 deletion pages/product.page.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
import { Page } from "@playwright/test"
import { Page, expect } from "@playwright/test"
import { getRandomFirstName, getRandomLastName, getRandomZipCode } from "../playwrightUtilities"

export class Product {
private readonly page: Page
private readonly addToCart: string = 'button[id="add-to-cart-sauce-labs-backpack"]'
private readonly sortDropdown: string = '[data-test="product-sort-container"]'
private readonly itemPrices: string = '[data-test="inventory-item-price"]'
private readonly cart: string = 'a[data-test="shopping-cart-link"]'
private readonly checkout: string = 'button[data-test="checkout"]'
private readonly firstName: string = 'input[data-test="firstName"]'
private readonly lastName: string = 'input[data-test="lastName"]'
private readonly zipCode: string = 'input[data-test="postalCode"]'
private readonly continue: string = 'input[data-test="continue"]'
private readonly finish: string = 'button[data-test="finish"]'
private readonly thankyouMessage: string = 'h2[data-test="complete-header"]'
private readonly cartBadge: string = '[data-test="shopping-cart-badge"]'



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

public async selectCart() {
await this.page.locator(this.cart).click();
}

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

public async fillInTheDetails() {
await this.page.waitForSelector(this.firstName);
await this.page.locator(this.firstName).fill(getRandomFirstName());
await this.page.locator(this.lastName).fill(getRandomLastName());
await this.page.locator(this.zipCode).fill(getRandomZipCode());

}
public async sortItemsByPrice(sort: string) {
await this.page.locator(this.sortDropdown).selectOption(sort);
}
public async selectContinue() {
await this.page.locator(this.continue).click();

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

}
public async validateFinalMessage(ThankyouMsg: string) {
const finalMsg = await this.page.locator(this.thankyouMessage);
await expect(finalMsg).toBeVisible();
await expect(finalMsg).toContainText(ThankyouMsg);

}
public async validateProductsAreSortedByPrice(sort: string) {
const priceTexts = await this.page.locator(this.itemPrices).allTextContents();
const actualPrices = priceTexts.map(price => Number(price.replace('$', '').trim()));
await expect(actualPrices.length).toBe(6);
const expectedPrices = [...actualPrices].sort((a, b) =>
sort === 'hilo' ? b - a : a - b
);

await expect(actualPrices).toEqual(expectedPrices);

}

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


}
18 changes: 17 additions & 1 deletion playwrightUtilities.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Browser, chromium, Page } from 'playwright';
import { faker } from '@faker-js/faker';

let browser: Browser | null = null;
let page: Page | null = null;
Expand Down Expand Up @@ -30,4 +31,19 @@ export const closeBrowser = async () => {
browser = null;
page = null;
}
};
};

export const getRandomFirstName = ():string =>{
return faker.person.firstName();
}

export const getRandomLastName = ():string =>{
return faker.person.lastName();
}

export const getRandomZipCode = ():string =>{
return faker.location.zipCode("#####");
}



8 changes: 8 additions & 0 deletions steps/login.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 error message {string}', async (ErrorMessage) => {
await new Login(getPage()).validateErrorMessage(ErrorMessage);
});

Then('I should be navigated to the products page', async () => {
await new Login(getPage()).validateSuccessfulLogin();
});
13 changes: 12 additions & 1 deletion steps/product.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,15 @@ import { Product } from '../pages/product.page';

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

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

Then('I should see all products sorted by price {string}', async (sort) => {
await new Product(getPage()).validateProductsAreSortedByPrice(sort);
});



36 changes: 36 additions & 0 deletions steps/purchase.steps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Then } from '@cucumber/cucumber';
import { getPage } from '../playwrightUtilities';
import { Product } from '../pages/product.page';


Then('I will select cart on the top-right', async () => {
await new Product(getPage()).selectCart();
});

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


Then('I will Fill in the First Name, Last Name and Zip\\/Postal Code', async () => {
await new Product(getPage()).fillInTheDetails();
});

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


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


Then('validate the text {string}', async (expectedMsg) => {
await new Product(getPage()).validateFinalMessage(expectedMsg);
});

Then('I should see the cart badge count as {string}', async (count)=> {
await new Product(getPage()).validateCartBadgeCount(count);

});
Loading