Woah I got Git working in VSC; now to push

This commit is contained in:
Kira 2023-09-15 15:11:58 -07:00
parent d659852b9d
commit 743c57f13b
13 changed files with 388 additions and 9 deletions

36
data/deliveryDetails.js Normal file
View File

@ -0,0 +1,36 @@
const delivery1 = {
firstName: "First",
lastName: "LastOne",
address: "123 Address Avenue",
postcode: "1020301",
city: "Major City One",
country: "United States of America"
}
const delivery2 = {
firstName: "Second",
lastName: "LastTwo",
address: "123 Address Avenue",
postcode: "1020302",
city: "Major City Two",
country: "United States of America"
}
const delivery3 = {
firstName: "Third",
lastName: "LastThree",
address: "123 Address Avenue3",
postcode: "1020303",
city: "Major City Three",
country: "United States of America"
}
export const deliveryDetails = [
delivery1,
delivery2,
delivery3
]

6
data/paymentDetails.js Normal file
View File

@ -0,0 +1,6 @@
export const paymentDetails = {
owner: "First LastOne",
number: "1234123412341234",
date: "12/47",
cvc: "456",
}

11
package-lock.json generated
View File

@ -8,6 +8,9 @@
"name": "automated-web-testing-with-javascript-and-playwright", "name": "automated-web-testing-with-javascript-and-playwright",
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": {
"uuid": "^9.0.0"
},
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.37.1" "@playwright/test": "^1.37.1"
} }
@ -62,6 +65,14 @@
"engines": { "engines": {
"node": ">=16" "node": ">=16"
} }
},
"node_modules/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
"bin": {
"uuid": "dist/bin/uuid"
}
} }
} }
} }

View File

@ -4,12 +4,15 @@
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test":"playwright test --headed" "test": "playwright test --headed"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.37.1" "@playwright/test": "^1.37.1"
},
"dependencies": {
"uuid": "^9.0.0"
} }
} }

View File

@ -0,0 +1,43 @@
import { expect } from "@playwright/test"
export class CheckoutPage {
constructor(page) {
this.page = page
this.basketCards = page.locator('[data-qa="basket-card"]')
this.basketItemPrices = page.locator('[data-qa="basket-item-price"]')
this.basketItemRemoveButtons = page.locator('[data-qa="basket-card-remove-item"]')
this.continueToCheckoutButton = page.locator('[data-qa="continue-to-checkout"]')
}
removeCheapestProduct = async () => {
await this.basketCards.first().waitFor()
await this.basketItemPrices.first().waitFor()
const itemsBefore = await this.basketCards.count()
const allPriceTexts = await this.basketItemPrices.allInnerTexts()
const convertToNumbers = allPriceTexts.map((text) => {
const formatText = text.replace("$","")
return parseInt(formatText, 10)
})
const smallestPrice = Math.min(convertToNumbers)
const smallestPriceIndex = convertToNumbers.indexOf(smallestPrice)
const specificRemoveButton = this.basketItemRemoveButtons.nth(smallestPriceIndex)
await specificRemoveButton.waitFor()
await specificRemoveButton.click()
await expect(this.basketCards).toHaveCount(itemsBefore - 1)
}
continueToCheckout = async () => {
await this.continueToCheckoutButton.waitFor()
await this.continueToCheckoutButton.click()
await this.page.waitForURL(/\/login/, {timeout: 3000})
}
}

View File

@ -0,0 +1,83 @@
import { expect } from "@playwright/test"
export class DeliveryPage {
constructor(page) {
this.page = page
this.firstNameField = page.locator('[data-qa="delivery-first-name"]')
this.lastNameField = page.locator('[data-qa="delivery-last-name"]')
this.addressField = page.locator('[data-qa="delivery-address-street"]')
this.postcodeField = page.locator('[data-qa="delivery-postcode"]')
this.cityField = page.locator('[data-qa="delivery-city"]')
this.countryDropdown = page.locator('[data-qa="country-dropdown"]')
this.paymentButton = page.getByRole('button', { name: 'Continue to payment' })
this.saveButton = page.locator('[data-qa="save-address-button"]')
this.savedAddressContainer = page.locator('[data-qa="saved-address-container"]')
this.savedFirstName = page.locator('[data-qa="saved-address-firstName"]')
this.savedLastName = page.locator('[data-qa="saved-address-lastName"]')
this.savedAddress = page.locator('[data-qa="saved-address-street"]')
this.savedPostcode = page.locator('[data-qa="saved-address-postcode"]')
this.savedCity = page.locator('[data-qa="saved-address-city"]')
this.savedCountry = page.locator('[data-qa="saved-address-country"]')
}
fillDeliveryDetails = async (deliveryDetails) =>{
await this.firstNameField.waitFor()
await this.firstNameField.fill(deliveryDetails.firstName)
await this.lastNameField.waitFor()
await this.lastNameField.fill(deliveryDetails.lastName)
await this.addressField.waitFor()
await this.addressField.fill(deliveryDetails.address)
await this.postcodeField.waitFor()
await this.postcodeField.fill(deliveryDetails.postcode)
await this.cityField.waitFor()
await this.cityField.fill(deliveryDetails.city)
await this.countryDropdown.waitFor()
await this.countryDropdown.selectOption(deliveryDetails.country)
}
saveAddress = async () => {
const addrCountBefore = await this.savedAddressContainer.count()
await this.saveButton.waitFor()
await this.saveButton.click()
await expect(this.savedAddressContainer).toHaveCount(addrCountBefore + 1)
await this.savedFirstName.first().waitFor()
expect(await this.savedFirstName.first().innerText()).toBe(await this.firstNameField.inputValue())
expect(await this.savedLastName.first().innerText()).toBe(await this.lastNameField.inputValue())
expect(await this.savedAddress.first().innerText()).toBe(await this.addressField.inputValue())
expect(await this.savedPostcode.first().innerText()).toBe(await this.postcodeField.inputValue())
expect(await this.savedCity.first().innerText()).toBe(await this.cityField.inputValue())
expect(await this.savedCountry.first().innerText()).toBe(await this.countryDropdown.inputValue())
}
clearDetails = async () => {
await this.firstNameField.waitFor()
await this.firstNameField.fill("")
await this.lastNameField.waitFor()
await this.lastNameField.fill("")
await this.addressField.waitFor()
await this.addressField.fill("")
await this.postcodeField.waitFor()
await this.postcodeField.fill("")
await this.cityField.waitFor()
await this.cityField.fill("")
}
continueToPayment = async () => {
await this.paymentButton.waitFor()
await this.paymentButton.click()
await this.page.waitForURL(/\/payment/, {timeout: 3000})
}
}

15
page-objects/LoginPage.js Normal file
View File

@ -0,0 +1,15 @@
import { expect } from "@playwright/test"
export class LoginPage {
constructor(page) {
this.page = page
this.signupButton = page.locator('[data-qa="go-to-signup-button"]')
}
moveToSignup = async () => {
await this.signupButton.waitFor()
await this.signupButton.click()
await this.page.waitForURL(/\/signup/, {timeout: 3000})
}
}

View File

@ -0,0 +1,22 @@
export class Navigation {
constructor(page){
this.page = page
this.basketCounter = page.locator('[data-qa="header-basket-count"]')
this.checkoutLink = page.getByRole('link', { name: 'Checkout' })
}
getBasketCount = async () => {
await this.basketCounter.waitFor()
const text = await this.basketCounter.innerText()
return parseInt(text, 10)
}
goToCheckout = async () => {
this.checkoutLink.waitFor()
await this.checkoutLink.click()
await this.page.waitForURL("/basket")
}
}

View File

@ -0,0 +1,77 @@
import { expect } from "@playwright/test"
export class PaymentPage {
constructor(page) {
this.page = page
// Discount
this.discountField = page.getByPlaceholder('Discount code')
this.discountCode = page
.frameLocator('[data-qa="active-discount-container"]')
.locator('[data-qa="discount-code"]')
this.applyDiscount = page.getByRole('button', { name: 'Submit discount' })
this.priceTotal = page.locator('[data-qa="total-value"]')
this.discountTotal = page.locator('[data-qa="total-with-discount-value"]')
this.discountText = page.locator('[data-qa="discount-active-message"]')
// Card
this.cardOwner = page.locator('[data-qa="credit-card-owner"]')
this.cardNumber = page.locator('[data-qa="credit-card-number"]')
this.cardDate = page.locator('[data-qa="valid-until"]')
this.cardCVC = page.locator('[data-qa="credit-card-cvc"]')
// Pay
this.payButton = page.getByRole('button', { name: 'Pay' })
}
activateDiscount = async () => {
await this.discountCode.waitFor()
const code = await this.discountCode.innerText()
await this.discountField.waitFor()
//await this.discountText.waitFor()
expect (await this.discountTotal.isVisible()).toBe(false)
expect (await this.discountText.isVisible()).toBe(false)
// 1. Using .full with await expect() due to laggy input
// await this.discountField.fill(code)
// expect (this.discountField).toHaveValue(code)
// 2. Using page.keyboard.type to manually enter in code / simulate real world
await this.discountField.focus()
await this.page.keyboard.type(code, {delay: 500})
expect (await this.discountField.inputValue()).toBe(code)
await this.priceTotal.waitFor()
const totalValueText = await this.priceTotal.innerText()
const totalNumber = totalValueText.replace("$","")
const totalValue = parseInt(totalNumber, 10)
await this.applyDiscount.waitFor()
await this.applyDiscount.click()
await this.discountTotal.waitFor()
const discountValueText = await this.discountTotal.innerText()
const discountNumber = discountValueText.replace("$","")
const discountValue = parseInt(discountNumber, 10)
expect(discountValue).toBeLessThan(totalValue)
}
fillPaymentDetails = async (paymentDetails) => {
await this.cardOwner.waitFor()
await this.cardOwner.fill(paymentDetails.owner)
await this.cardNumber.waitFor()
await this.cardNumber.fill(paymentDetails.number)
await this.cardDate.waitFor()
await this.cardDate.fill(paymentDetails.date)
await this.cardCVC.waitFor()
await this.cardCVC.fill(paymentDetails.cvc)
}
}

View File

@ -1,27 +1,46 @@
import { expect } from "@playwright/test" import { expect } from "@playwright/test"
import { Navigation } from "./Navigation.js"
export class ProductsPage { export class ProductsPage {
constructor(page) { constructor(page) {
this.page = page this.page = page
this.addButtons = page.locator('[data-qa="product-button"]') this.addButtons = page.locator('[data-qa="product-button"]')
this.sortDropdown = page.locator('[data-qa="sort-dropdown"]')
this.productTitle = page.locator('[data-qa="product-title"]')
} }
visit = async () => { visit = async () => {
await this.page.goto("/") await this.page.goto("/")
//console.log("Buttons --- " + await this.page.locator('[data-qa="product-button"]').count())
} }
addProductToBasket = async (productIndex) => {
//data-qa="product-button"
console.log("--- addProductToBasket("+ productIndex +")")
addProductToBasket = async (productIndex) => {
const specificAddButton = this.addButtons.nth(productIndex) const specificAddButton = this.addButtons.nth(productIndex)
await specificAddButton.waitFor() await specificAddButton.waitFor()
await expect(specificAddButton).toHaveText("Add To Basket")
await specificAddButton.click()
await expect(specificAddButton).toHaveText("Remove from Basket")
await expect(specificAddButton).toHaveText("Add to Basket")
const navigation = new Navigation(this.page)
const basketCountBefore = await navigation.getBasketCount()
await specificAddButton.click()
await expect(specificAddButton).toHaveText("Remove from Basket")
const basketCountAfter = await navigation.getBasketCount()
expect(basketCountAfter).toBeGreaterThan(basketCountBefore)
}
sortByCheapest = async () => {
await this.sortDropdown.waitFor()
await this.productTitle.first().waitFor()
const productTitleBefore = await this.productTitle.allInnerTexts()
await this.sortDropdown.selectOption("price-asc")
const productTitleAfter = await this.productTitle.allInnerTexts()
expect(productTitleAfter).not.toEqual(productTitleBefore)
} }
} }

View File

@ -0,0 +1,20 @@
export class RegisterPage {
constructor(page) {
this.page = page
this.emailInput = page.getByPlaceholder('e-mail')
this.passwordInput = page.getByPlaceholder('password')
this.registerButton = page.getByRole('button', { name: 'Register' })
}
signupNewUser = async (email, password) => {
await this.emailInput.waitFor()
await this.emailInput.fill(email)
await this.passwordInput.waitFor()
await this.passwordInput.fill(password)
await this.registerButton.waitFor()
await this.registerButton.click()
}
}

Binary file not shown.

View File

@ -1,19 +1,63 @@
import {test} from "@playwright/test" import {test} from "@playwright/test"
import { v4 as uuidv4 } from "uuid";
import {ProductsPage} from "../page-objects/ProductsPage.js" import {ProductsPage} from "../page-objects/ProductsPage.js"
import { Navigation } from "../page-objects/Navigation.js"
import { CheckoutPage } from "../page-objects/CheckoutPage.js"
import { LoginPage } from "../page-objects/LoginPage.js"
import { RegisterPage } from "../page-objects/RegisterPage.js"
import { DeliveryPage } from "../page-objects/DeliveryPage.js"
import { deliveryDetails } from "../data/deliveryDetails.js";
import { PaymentPage } from "../page-objects/PaymentPage.js"
import { paymentDetails } from "../data/paymentDetails.js";
test.only("New user full end-to-end test journey", async ({page}) => { test.only("New user full end-to-end test journey", async ({page}) => {
// init // init
const productsPage = new ProductsPage(page) const productsPage = new ProductsPage(page)
const navigation = new Navigation(page)
const checkoutPage = new CheckoutPage(page)
const loginPage = new LoginPage(page)
const registerPage = new RegisterPage(page)
const deliveryPage = new DeliveryPage(page)
const paymentPage = new PaymentPage(page)
// 1. Visit // 1. Visit
await productsPage.visit() await productsPage.visit()
await productsPage.sortByCheapest()
// 2. Add to Basket // 2. Add to Basket
await productsPage.addProductToBasket(0) await productsPage.addProductToBasket(0)
await productsPage.addProductToBasket(1) await productsPage.addProductToBasket(1)
await productsPage.addProductToBasket(2) await productsPage.addProductToBasket(2)
// 3. Navigate to Checkout
await navigation.goToCheckout()
await checkoutPage.removeCheapestProduct()
await checkoutPage.continueToCheckout()
// 4. Navigate to Signup
await loginPage.moveToSignup()
const email = uuidv4() + "@gmail.com"
const password = "secret"
// 5. Register New User
await registerPage.signupNewUser(email, password)
await deliveryPage.fillDeliveryDetails(deliveryDetails[0])
await deliveryPage.saveAddress()
// await deliveryPage.clearDetails()
// await deliveryPage.fillDetails(deliveryDetails[1])
// await deliveryPage.saveAddress()
// await deliveryPage.clearDetails()
// await deliveryPage.fillDetails(deliveryDetails[2])
// await deliveryPage.saveAddress()
await deliveryPage.continueToPayment()
await paymentPage.activateDiscount()
await paymentPage.fillPaymentDetails(paymentDetails)
// Hold // Hold
await page.pause(); //await page.pause();
}) })