diff --git a/features/login.feature b/features/login.feature index fb9f1fa5..4e205110 100644 --- a/features/login.feature +++ b/features/login.feature @@ -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 \ No newline at end of file + Then I should see the error message "Epic sadface: Sorry, this user has been locked out." \ No newline at end of file diff --git a/features/product.feature b/features/product.feature index 8a7ceab9..6d076756 100644 --- a/features/product.feature +++ b/features/product.feature @@ -6,8 +6,11 @@ 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 Then I will login as 'standard_user' - # TODO: Sort the items by - # TODO: Validate all 6 items are sorted correctly by price + Then I click on filter and choose "" and "" + Then I validate item order Examples: - # TODO: extend the datatable to paramterize this test - | sort | \ No newline at end of file + | sort_option | expected_order | + | Price | descending | + | Price | ascending | + | Name | descending | + | Name | ascending | \ No newline at end of file diff --git a/features/purchase.feature b/features/purchase.feature index 28634789..82587f8d 100644 --- a/features/purchase.feature +++ b/features/purchase.feature @@ -7,8 +7,12 @@ 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 click on shopping cart # TODO: Select Checkout + Then I will click 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 + Then I will fill out and submit checkout form with 'Jackson' and 'Lei' and '1234' + # TODO: Validate the text 'Thank you for your order!' + Then I will see the message 'Thank you for your order!' \ No newline at end of file diff --git a/pages/checkout.page.ts b/pages/checkout.page.ts new file mode 100644 index 00000000..ea4ca9e9 --- /dev/null +++ b/pages/checkout.page.ts @@ -0,0 +1,27 @@ +import { Page, expect } from "@playwright/test" + +export class Checkout { + private readonly page: Page + private readonly firstNameInput: string = '//input[@data-test="firstName"]' + private readonly lastNameInput: string = '//input[@data-test="lastName"]' + private readonly zipCodeInput: string = '//input[@data-test="postalCode"]' + private readonly continueButton: string = '//*[@data-test="continue"]' + private readonly finishButton: string = '//*[@data-test="finish"]' + private readonly completeText: string = '//*[@data-test="complete-header"]' + + constructor(page: Page) { + this.page = page; + } + public async submitCheckoutForm(firstname: string, lastname: string, zipcode: string) { + await this.page.locator(this.firstNameInput).fill(firstname) + await this.page.locator(this.lastNameInput).fill(lastname) + await this.page.locator(this.zipCodeInput).fill(zipcode) + await this.page.locator(this.continueButton).click() + await this.page.locator(this.finishButton).click() + } + + public async validateCompletedMessage(message: string) { + expect(message).toEqual(await this.page.locator(this.completeText).textContent()) + } + +} \ No newline at end of file diff --git a/pages/login.page.ts b/pages/login.page.ts index 5a01614b..cdc4e92c 100644 --- a/pages/login.page.ts +++ b/pages/login.page.ts @@ -1,4 +1,4 @@ -import { Page } from "@playwright/test" +import { expect, Page } from "@playwright/test" export class Login { private readonly page: Page @@ -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; @@ -23,4 +24,9 @@ export class Login { await this.page.locator(this.passwordField).fill(this.password) await this.page.locator(this.loginButton).click() } + + public async validateErrorMessage(expectedErrorMessage: string) { + const actualErrorMessage = await this.page.locator(this.errorMessage).textContent(); + expect(actualErrorMessage).toEqual(expectedErrorMessage); + } } \ No newline at end of file diff --git a/pages/product.page.ts b/pages/product.page.ts index 14bedb1b..f450e637 100644 --- a/pages/product.page.ts +++ b/pages/product.page.ts @@ -1,8 +1,13 @@ -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 shoppingCartLink: string = '//*[@data-test="shopping-cart-link"]' + private readonly checkoutButton: string = '//*[@data-test="checkout"]' + private readonly dropDownButton: string = '//*[@data-test="product-sort-container"]' + private readonly itemName: string = '//*[@data-test="inventory-item-name"]' + private readonly itemPrice: string = '//*[@data-test="inventory-item-price"]' constructor(page: Page) { this.page = page; @@ -11,4 +16,46 @@ export class Product { public async addBackPackToCart() { await this.page.locator(this.addToCart).click() } + + public async clickShoppingCart() { + await this.page.locator(this.shoppingCartLink).click() + } + + public async clickCheckout() { + await this.page.locator(this.checkoutButton).click() + } + + public async selectFilterOption(sortOption: string, expectedOrder: string) { + if (sortOption == "Price" && expectedOrder == "descending") { + await this.page.locator(this.dropDownButton).selectOption("hilo") + } else if (sortOption == "Price" && expectedOrder == "ascending") { + await this.page.locator(this.dropDownButton).selectOption("lohi") + } else if (sortOption == "Name" && expectedOrder == "descending") { + await this.page.locator(this.dropDownButton).selectOption("za") + } else if (sortOption == "Name" && expectedOrder == "ascending") { + await this.page.locator(this.dropDownButton).selectOption("az") + } + } + + public async validateItemOrder() { + const sortOption = await this.page.locator(this.dropDownButton).inputValue() + const actualNameOrder = await this.page.locator(this.itemName).allTextContents() + const itemPriceList = await this.page.locator(this.itemPrice).allTextContents() + if (sortOption == "az") { + const expectedNameOrder = [...actualNameOrder].sort((a,b) => a.localeCompare(b)) + expect(actualNameOrder).toEqual(expectedNameOrder) + } else if (sortOption == "za") { + const expectedNameOrder = [...actualNameOrder].sort((a,b) => b.localeCompare(a)) + expect(actualNameOrder).toEqual(expectedNameOrder) + } else if (sortOption == "lohi") { + const itemPriceListTransFormed = itemPriceList.map(price => parseFloat(price.replace(/[$,]/g, ""))) + const expectedPriceOrder = [...itemPriceListTransFormed].sort((a,b) => a - b) + expect(itemPriceListTransFormed).toEqual(expectedPriceOrder) + } else if (sortOption == "hilo") { + const itemPriceListTransFormed = itemPriceList.map(price => parseFloat(price.replace(/[$,]/g, ""))) + const expectedPriceOrder = [...itemPriceListTransFormed].sort((a,b) => b - a) + expect(itemPriceListTransFormed).toEqual(expectedPriceOrder) + } + } + } \ No newline at end of file diff --git a/steps/login.steps.ts b/steps/login.steps.ts index c2aa0d80..ca4c1b06 100644 --- a/steps/login.steps.ts +++ b/steps/login.steps.ts @@ -7,5 +7,10 @@ Then('I should see the title {string}', async (expectedTitle) => { }); Then('I will login as {string}', async (userName) => { - await new Login(getPage()).loginAsUser(userName); + const loginPage = new Login(getPage()); + await loginPage.loginAsUser(userName); +}); + +Then('I should see the error message {string}', async (expectedMessage) => { + await new Login(getPage()).validateErrorMessage(expectedMessage); }); \ No newline at end of file diff --git a/steps/product.steps.ts b/steps/product.steps.ts index bb52fb98..e624a526 100644 --- a/steps/product.steps.ts +++ b/steps/product.steps.ts @@ -4,4 +4,20 @@ import { Product } from '../pages/product.page'; Then('I will add the backpack to the cart', async () => { await new Product(getPage()).addBackPackToCart(); -}); \ No newline at end of file +}); + +Then('I will click on shopping cart', async () => { + await new Product(getPage()).clickShoppingCart(); +}) + +Then('I will click checkout', async () => { + await new Product(getPage()).clickCheckout(); +}) + +Then('I click on filter and choose {string} and {string}', async (sortOption, expectedOrder) => { + await new Product(getPage()).selectFilterOption(sortOption, expectedOrder) +}) + +Then('I validate item order', async () => { + await new Product(getPage()).validateItemOrder() +}) \ No newline at end of file diff --git a/steps/purchase.steps.ts b/steps/purchase.steps.ts new file mode 100644 index 00000000..38d999ec --- /dev/null +++ b/steps/purchase.steps.ts @@ -0,0 +1,11 @@ +import { Then } from '@cucumber/cucumber'; +import { getPage } from '../playwrightUtilities'; +import { Checkout } from '../pages/checkout.page'; + +Then('I will fill out and submit checkout form with {string} and {string} and {string}', async (firstname, lastname, zipcode) => { + await new Checkout(getPage()).submitCheckoutForm(firstname, lastname, zipcode); +}) + +Then('I will see the message {string}', async (message) => { + await new Checkout(getPage()).validateCompletedMessage(message) +}) \ No newline at end of file