NỘI DUNG BÀI HỌC
✅ Hiểu được mối liên kết giữa các tầng trong POM (BasePage → Page Object → Test Layer).
✅ Nắm vững cấu trúc dự án hoàn chỉnh và ý nghĩa từng thư mục trong automation framework.
✅ Phân biệt và áp dụng được các mô-đun mở rộng trong POM: Component, Utils, Data, Config.
✅ Biết cách xây dựng dòng chảy nghiệp vụ (Business Flow) giữa các Page Object.
✅ Định hình được tư duy thiết kế framework chuyên nghiệp có khả năng mở rộng và tái sử dụng.
I. ÔN TẬP NGẮN: TRIẾT LÝ CỐT LÕI CỦA POM
1. POM là gì?
Page Object Model là mô hình giúp tách biệt:
- 
WHAT – Nghiệp vụ cần kiểm thử.
 - 
HOW – Cách thực hiện thao tác trên UI.
 
2. Mục tiêu chính
- 
Tập trung logic kỹ thuật vào BasePage.
 - 
Mô tả nghiệp vụ rõ ràng trong Page Object.
 - 
Giúp test case ngắn gọn, dễ đọc, dễ mở rộng.
 
II. TỔNG QUAN VỀ CẤU TRÚC POM NÂNG CAO
Một framework chuyên nghiệp thường mở rộng từ kiến trúc POM cơ bản sang mô hình đa tầng sau:
project_root/
│
├── core/                                ← FOUNDATION LAYER (Kỹ thuật nền)
│   ├── base_page.py                     → Base class cho tất cả Page Object
│   └── base_component.py                → Base class cho Component (UI lặp lại)
│
├── pages/                               ← PAGE OBJECT LAYER (Nghiệp vụ)
│   ├── login_page.py                    → LoginPage: chứa locators + hàm login()
│   ├── inventory_page.py                → InventoryPage: add_to_cart(), verify_item()
│   ├── cart_page.py                     → CartPage: remove_item(), proceed_to_checkout()
│   └── checkout_page.py                 → CheckoutPage: fill_info(), complete_order()
│
├── components/                          ← COMPONENT LAYER (UI tái sử dụng)
│   ├── header_component.py              → Header: logout(), go_to_cart()
│   ├── sidebar_component.py             → Sidebar: open_menu(), navigate_to()
│   └── modal_component.py               → Modal: confirm(), cancel()
│
├── resources/                           ← DATA & CONFIG LAYER (Nguồn dữ liệu)
│   ├── config.json                      → URL, môi trường, credentials
│   ├── credentials.json                 → Dữ liệu login test
│   └── products.json                    → Dữ liệu sản phẩm cho test
│
├── utils/                               ← HELPER LAYER (Hỗ trợ phi UI)
│   ├── db_helper.py                     → Kết nối và truy vấn Database
│   ├── api_client.py                    → Gọi API hỗ trợ test data
│   ├── file_reader.py                   → Đọc file JSON/CSV/Excel
│   └── logger.py                        → Ghi log chi tiết hành động test
│
├── tests/                               ← TEST SCENARIO LAYER (WHAT)
│   ├── test_login_pom.py                → Test đăng nhập
│   ├── test_add_to_cart.py              → Test thêm sản phẩm vào giỏ
│   ├── test_checkout_flow.py            → Test checkout toàn bộ luồng
│   └── test_error_handling.py           → Test lỗi hiển thị UI
│
├── conftest.py                          ← THE GLUE (CONNECTOR)
│                                         → Tạo và bơm fixture (Page Object, Config, DB)
│
├── reports/                             ← OUTPUT LAYER (Kết quả kiểm thử)
│   ├── allure-results/                  → Báo cáo Allure
│   └── pytest-html/                     → Báo cáo HTML chi tiết
│
└── screenshots/                         ← EVIDENCE LAYER (Ảnh minh chứng)
    ├── error_login_fail.png
    └── cart_page_validation.png
1. Định nghĩa
BasePage là lớp nền tảng duy nhất mà tất cả các Page Object kế thừa.
Trong thực tế, lớp này thường được mở rộng thêm:
- 
Wait động (Explicit Wait) để xử lý element chưa sẵn sàng.
 - 
Logging để ghi lại hành động test.
 - 
Screenshot on Fail để debug lỗi UI.
 - 
Hàm tiện ích (helper) như scroll, press, get_text, …
 
2. Ví dụ – core/base_page.py
IV. COMPONENT OBJECT – TÁCH NHỮNG PHẦN TỬ UI DÙNG CHUNG
1. Khái niệm
Component Object là phần mở rộng của POM, được sử dụng khi có các phần tử UI xuất hiện trên nhiều trang
(ví dụ: Header, Menu, Sidebar, Popup, Footer, …).
Mỗi component là một class độc lập, giúp tái sử dụng hành vi và locator dùng chung.
2. Lợi ích
- 
Giảm trùng lặp code.
 - 
Dễ bảo trì khi thay đổi layout.
 - 
Tăng khả năng tổ chức và mở rộng framework.
 
3. Ví dụ – components/header_component.py
V. ÁP DỤNG COMPONENT TRONG PAGE OBJECT
Ví dụ – pages/inventory_page.py
from core.base_page import BasePage
from components.header_component import HeaderComponent
class InventoryPage(BasePage):
    """Đại diện cho trang danh sách sản phẩm."""
    ITEM_BACKPACK_ADD_BUTTON = "[data-test='add-to-cart-sauce-labs-backpack']"
    SHOPPING_CART_BADGE = ".shopping_cart_badge"
    def __init__(self, page):
        super().__init__(page)
        self.header = HeaderComponent(page)   # Gắn Component Header vào trang
    def add_backpack_to_cart(self):
        """Thêm sản phẩm 'Sauce Labs Backpack' vào giỏ."""
        self._click(self.ITEM_BACKPACK_ADD_BUTTON, "Add Backpack Button")
    def verify_item_added(self):
        """Kiểm tra biểu tượng giỏ hàng hiển thị số lượng đúng."""
        self._assert_visible(self.SHOPPING_CART_BADGE, "Cart Badge")
    def logout_via_header(self):
        """Đăng xuất qua Header Component."""
        self.header.logout()
👉
InventoryPagecó thể sử dụng trực tiếpself.header.logout()hoặcself.header.go_to_cart()
mà không cần lặp lại logic header trong mỗi trang khác.
VI. DATA-DRIVEN TESTING VỚI POM
1. Khái niệm
Data-Driven Testing (Kiểm thử dựa trên dữ liệu) là kỹ thuật tách riêng dữ liệu đầu vào khỏi logic test.
Trong POM, việc này thường được thực hiện bằng cách đọc dữ liệu từ file JSON, CSV, hoặc Excel.
2. Ví dụ cấu trúc file – data/credentials.json
3. Cách sử dụng trong test
Ý nghĩa:
→ Giúp tách phần dữ liệu test (input) ra khỏi logic kiểm thử.
→ Dễ dàng mở rộng khi có thêm các bộ dữ liệu khác mà không phải viết lại test case.
VII. PAGE OBJECT MỞ RỘNG – CHUỖI HÀNH ĐỘNG NGHIỆP VỤ
Trong framework thực tế, test flow thường liên quan đến nhiều trang liên tiếp.
Nhờ POM, ta có thể kết nối các Page Object để tạo thành chuỗi hành động nghiệp vụ.
Ví dụ – Quy trình “Login → Add to Cart → Checkout”
Ưu điểm của chuỗi này:
- 
Mỗi trang có trách nhiệm riêng.
 - 
Không cần lặp lại logic login hay add to cart ở nhiều test khác.
 - 
Test mô tả hành trình người dùng thực tế bằng ngôn ngữ nghiệp vụ.
 
Sơ đồ 1 chiều
tests/ (WHAT)
   ↓  (gọi nghiệp vụ)
pages/ (Page Objects – HOW nghiệp vụ theo trang)
   ↓  (tái sử dụng)
components/ (UI dùng chung theo thành phần)
   ↓  (kế thừa/ủy quyền)
core/ (Base classes: BasePage, BaseComponent – HOW kỹ thuật)
   ↓  (thao tác thật)
Playwright API (page, locator, expect)
resources/ (config, testdata) → được đọc bởi tests/ hoặc pages/ (khi cần)
utils/ (db, api, file, logger) → được gọi bởi tests/ hoặc pages/ (khi cần)
conftest.py (fixtures) → khởi tạo “đối tượng + dữ liệu” và bơm vào tests/
reports/, screenshots/ → nhận log, ảnh, kết quả assert khi chạy
VIII. TỔNG KẾT KIẾN THỨC POM NÂNG CAO
| Khái niệm | Định nghĩa | Ứng dụng trong automation | 
|---|---|---|
| BasePage nâng cao | Lớp cha chuẩn hóa hành động với Wait, Logging, Screenshot | Giúp test ổn định, dễ debug | 
| Component Object | Mô hình tách phần tử UI dùng chung (header, sidebar, popup) | Tăng tái sử dụng, giảm lặp code | 
| Data-Driven Testing | Cách tách dữ liệu test ra khỏi logic test | Dễ mở rộng, dễ quản lý test data | 
| Business Flow | Chuỗi hành động kết hợp nhiều Page Object | Mô phỏng luồng người dùng thực tế | 
| Clean Test Case | Test chỉ thể hiện luồng nghiệp vụ, không chứa kỹ thuật | Dễ đọc, dễ bảo trì, rõ ràng với non-dev | 
IX. BÀI TẬP THỰC HÀNH
Trang web: https://hrm.anhtester.com/erp/login
Yêu cầu:
📦 PlaywrightProject/
│
├── Core/                                  # Thư mục chứa lớp nền (BasePage) dùng chung
│   ├── base_page.py                       # Định nghĩa các hàm cơ bản: open_url, click, fill, screenshot
│   └── __init__.py                        # Giúp Python nhận diện đây là package
│
├── components/                            # Thư mục chứa các thành phần UI tái sử dụng (Header, Footer)
│   ├── header_component.py                # Xử lý menu header: click từng mục, chụp ảnh, logout
│   └── __init__.py
│
├── pages/                                 # Thư mục chứa các Page Object đại diện cho từng trang
│   ├── login_page.py                      # Trang đăng nhập: đọc dữ liệu từ JSON, login, chụp ảnh, logout
│   └── __init__.py
│
├── data/                                  # Lưu trữ dữ liệu test (JSON, CSV, Excel)
│   ├── credentials.json                   # Chứa thông tin đăng nhập test
│   └── __init__.py
│
├── results/                               # Lưu kết quả chạy test (report HTML)
│   ├── report.html                        # Báo cáo tự động sinh sau khi chạy pytest
│   └── __init__.py
│
├── screenshots/                           # Thư mục lưu toàn bộ ảnh chụp màn hình khi test
│   └── (ảnh tự sinh khi chạy test)
│
├── tests/                                 # Chứa file test case thực tế (Pytest)
│   ├── test_login_flow.py                 # Kịch bản: mở → đăng nhập → chụp ảnh → logout
    └── __init__.py
Đánh giá hoàn thành:
| Tiêu chí | Mức độ đạt yêu cầu | 
|---|---|
| Có Component Header riêng | ✅ | 
| Dữ liệu test tách riêng file JSON | ✅ | 
| Flow liên kết nhiều Page Object | ✅ | 
| Không chứa locator trong test | ✅ | 
| Test chạy ổn định, dễ đọc | ✅ | 
