Skip to content

Commit 8e1e843

Browse files
committed
Add "Checkout Process" and "Purchase Confirmation" tests. Added a new page object to support address validation. Updated test-plan.md.
1 parent 35844f9 commit 8e1e843

File tree

5 files changed

+117
-10
lines changed

5 files changed

+117
-10
lines changed

docs/test-plan.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Test Plan for AutomationPractice by Miguel Garces
22
*Project Owner: Miguel Garces*
3-
*Latest Revision: 8/13/2025*
3+
*Latest Revision: 8/19/2025*
44

55
## Project Overview
66
This project performs end-to-end testing to the demo website [Automation Exercise](https://automationexercise.com/). It extensively covers major user flows such as login/registration, product filtering, checkout, and API functionality.
@@ -33,9 +33,9 @@ This project performs end-to-end testing to the demo website [Automation Exercis
3333
| Product Search & Filters | UI || Filter by category and other options available |
3434
| Product Preview | UI || Verifies product information is matches with listing |
3535
| Add to Cart | UI + Validation || Validates product is in the cart |
36-
| Checkout Process | UI | 🔄 | N/A |
37-
| Purchase Confirmation | UI + Validation | 🔄 | Ensure successful purchase and verify product is found in "Orders" |
38-
| Contact Form | UI + Form Validation | | N/A |
36+
| Checkout Process | UI | | N/A |
37+
| Purchase Confirmation | UI + Validation | | Ensure successful purchase and verify product is found in "Orders" |
38+
| Contact Form | UI + Form Validation | 🔄 | N/A |
3939
| User Login (POST) | API || N/A |
4040
| Get Products (GET) | API || N/A |
4141

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "qa-automation-automationexercise",
3-
"version": "2.3",
3+
"version": "2.4",
44
"description": "QA automation project showcasing UI, API, and visual tests for AutomationExercise. Integrated with Docker, Allure, and CI/CD pipelines.",
55
"main": "index.js",
66
"directories": {

page-objects/AddressValidation.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Page, Locator } from "@playwright/test";
2+
3+
export class AddressValidation {
4+
private page: Page;
5+
6+
// Locators
7+
private fullNameLocator: Locator;
8+
private addressLines: Locator;
9+
private cityStateZipLocator: Locator;
10+
private countryLocator: Locator;
11+
private phoneLocator: Locator;
12+
13+
// Properties to hold normalized values
14+
fullname = '';
15+
firstName = '';
16+
lastName = '';
17+
address1 = '';
18+
address2 = '';
19+
city = '';
20+
state = '';
21+
zipcode = '';
22+
country = '';
23+
mobileNumber = '';
24+
25+
constructor(page: Page) {
26+
this.page = page;
27+
28+
this.fullNameLocator = page.locator("#address_delivery li.address_firstname.address_lastname");
29+
this.addressLines = page.locator("#address_delivery li.address_address1.address_address2");
30+
this.cityStateZipLocator = page.locator("#address_delivery li.address_city.address_state_name.address_postcode");
31+
this.countryLocator = page.locator("#address_delivery li.address_country_name");
32+
this.phoneLocator = page.locator("#address_delivery li.address_phone");
33+
}
34+
35+
/**
36+
* Load and normalize address data from the page.
37+
*/
38+
async load() {
39+
await this.page.waitForSelector("#address_delivery");
40+
41+
const fullNameRaw = (await this.fullNameLocator.textContent()) ?? '';
42+
this.fullname = fullNameRaw.replace(/^(Mr\.|Mrs\.|Miss\.|Ms\.)\s*/i, '').trim();
43+
[this.firstName, this.lastName] = this.fullname.split(' ');
44+
45+
const address1Raw = (await this.addressLines.nth(1).textContent()) ?? '';
46+
const address2Raw = (await this.addressLines.nth(2).textContent()) ?? '';
47+
this.address1 = address1Raw.trim();
48+
this.address2 = address2Raw.trim();
49+
50+
const cityStateZipRaw = (await this.cityStateZipLocator.textContent()) ?? '';
51+
const parts = cityStateZipRaw.trim().split(/\s+/);
52+
this.zipcode = parts.pop() ?? '';
53+
this.state = parts.pop() ?? '';
54+
this.city = parts.join(' ') ?? '';
55+
56+
this.country = ((await this.countryLocator.textContent()) ?? '').trim();
57+
this.mobileNumber = ((await this.phoneLocator.textContent()) ?? '').trim();
58+
}
59+
}

playwright.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ export default defineConfig({
1616
testDir: './tests',
1717
fullyParallel: true,
1818
retries: 1,
19-
workers: 10,
20-
timeout: 30 * 1000, // Maximum time one test can run for (30 seconds)
19+
workers: 3,
20+
timeout: 60 * 1000, // Maximum time one test can run for (30 seconds)
2121
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
2222
reporter: 'allure-playwright',
2323
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */

tests/cart-checkout.spec.ts

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import { test, expect } from '@playwright/test'
22
import { UserLogin } from '../page-objects/Login'
3-
import { ProductTypes } from '../utils/types/productTypes'
3+
import { RegistrationTypes, ProductTypes } from '../utils/types/'
44
import products from '../utils/fixtures/productData.json'
5+
import registrationData from '../utils/fixtures/registrationData.json'
6+
import { AddressValidation } from '../page-objects/AddressValidation'
57

6-
const productData: ProductTypes[] = products.products
8+
9+
export const productData: ProductTypes[] = products.products
10+
export const userData: RegistrationTypes = structuredClone(registrationData)
711

812
test.beforeEach(async ({ page }) => {
913
const userLogin = new UserLogin(page)
1014
await userLogin.autoLogin() // Uses predefined credentials from loginData.json. Manual login with provided credentials is available.
1115
await page.goto('/products')
1216
})
1317

14-
test.only('@CART - Add product to cart and validate it', async ({ page }) => {
18+
test('@CART - Add product to cart and validate it', async ({ page }) => {
1519

1620
const cartTable = page.locator('#cart_info_table tbody');
1721
let productID : number = productData[0].id;
@@ -24,4 +28,48 @@ test.only('@CART - Add product to cart and validate it', async ({ page }) => {
2428
// Goes to "View Cart" and confirms product is in cart
2529
await page.click('.modal-content a[href="/view_cart"]')
2630
await expect(cartTable.locator(`tr#product-${productID}`)).toBeVisible() // getByText() can cause issues if one or more items are named "Blue Top"
31+
})
32+
test('@CART - Checkout process', async ({ page }) => {
33+
34+
// Proceed to checkout
35+
await page.click('a[href="/view_cart"]');
36+
await page.getByText("Proceed To Checkout").click();
37+
38+
// Confirm address details
39+
// Raw Data
40+
const addressValidator = new AddressValidation(page);
41+
await addressValidator.load();
42+
43+
expect(addressValidator.fullname).toBe(userData.name);
44+
expect(addressValidator.address1).toBe(userData.address.address);
45+
expect(addressValidator.address2).toBe(userData.address.address2);
46+
expect(addressValidator.city).toBe(userData.address.city);
47+
expect(addressValidator.state).toBe(userData.address.state);
48+
expect(addressValidator.zipcode).toBe(userData.address.zipcode);
49+
expect(addressValidator.country).toBe(userData.address.country);
50+
expect(addressValidator.mobileNumber).toBe(userData.address.mobile_number);
51+
52+
// Validate order
53+
const cartTable = page.locator('#cart_info tbody');
54+
let productID : number = productData[0].id;
55+
await expect(cartTable.locator(`tr#product-${productID}`)).toBeVisible() // getByText() can cause issues if one or more items are named "Blue Top"
56+
57+
// Place order
58+
await page.getByText("Place Order").click();
59+
60+
// Insert card details
61+
await page.fill('[data-qa="name-on-card"]', userData.name);
62+
await page.fill('[data-qa="card-number"]', '4111111111111111');
63+
await page.fill('[data-qa="expiry-month"]', '12');
64+
await page.fill('[data-qa="expiry-year"]', '2025');
65+
await page.fill('[data-qa="cvc"]', '123');
66+
67+
// Submit order
68+
await page.click('[data-qa="pay-button"]');
69+
70+
// Wait for URL to load and validates
71+
await page.waitForURL('https://automationexercise.com/payment_done/500');
72+
73+
// Validates order placement
74+
expect(page.locator('[data-qa="order-placed"]')).toBeVisible();
2775
})

0 commit comments

Comments
 (0)