Đang tải...

Lửng Lọc Lõi

Đeo kính để soi Bug cho rõ, nhíu mày để nhắc Dev sửa cho kỹ. Với tôi, 'chạy được' thôi là chưa đủ! 🧐💻


0

Selenium Cho Tester: Hướng Dẫn Automation Testing Cơ Bản Từ A-Z

Lửng Lọc Lõi
Lửng Lọc Lõi

5 tháng trước · 19 phút đọc

Selenium là gì và tại sao tester cần biết?

Mình nhớ lần đầu được giao task regression testing cho một app thương mại điện tử - hơn 80 test case, chạy tay mất gần 2 ngày. Deadline 24 tiếng. Đó là lúc mình thực sự hiểu tại sao automation testing tồn tại.

Selenium là framework kiểm thử tự động (automation testing) mã nguồn mở, cho phép bạn điều khiển trình duyệt web bằng code - giống như bạn đang ngồi click chuột, nhập liệu, nhưng máy làm thay bạn. Viết một lần, chạy bao nhiêu lần cũng được.

343365 Selenium tự động hóa thao tác trình duyệt, giải phóng tester khỏi lặp đi lặp lại

Tại sao tester cần biết? Ba lý do thực tế:

  • Regression testing tốn thời gian nhất trong chu kỳ phát triển. Selenium giảm thời gian đó từ ngày xuống giờ.
  • Job description tester ngày càng yêu cầu automation. Biết Selenium = lợi thế cạnh tranh rõ ràng.
  • Manual testing không scale được. App lớn, release nhanh, team nhỏ - automation là bắt buộc.

Selenium hỗ trợ nhiều ngôn ngữ: Java, Python, C#, JavaScript, Ruby. Trong bài này mình dùng Java vì cộng đồng lớn, nhiều tài liệu, dễ tìm giải pháp khi gặp lỗi.


Các thành phần của Selenium

Selenium không phải một tool đơn lẻ. Đây là bộ công cụ gồm 3 thành phần chính, mỗi thứ phục vụ mục đích khác nhau.

343366 Ba thành phần Selenium phục vụ các nhu cầu testing khác nhau

Selenium WebDriver - thứ bạn sẽ dùng 90% thời gian. WebDriver giao tiếp trực tiếp với trình duyệt (Chrome, Firefox, Edge) thông qua driver tương ứng. Bạn viết code Java, WebDriver dịch lệnh đó thành hành động thực trên trình duyệt. Không cần server trung gian, không cần cài plugin - kết nối thẳng.

Selenium IDE - plugin trình duyệt, cho phép record thao tác tay rồi export thành code. Hữu ích khi mới bắt đầu hoặc cần tạo test case nhanh. Giới hạn: không xử lý được logic phức tạp như điều kiện if/else, vòng lặp, hay dynamic data. Dùng để học, không dùng cho production.

Selenium Grid - cho phép chạy test song song trên nhiều máy/trình duyệt cùng lúc. Bạn có 50 test case cần test trên Chrome, Firefox, Safari - Grid chạy cùng lúc thay vì tuần tự. Đây là thứ team lớn cần, fresher chưa cần vội.

Tóm lại: Bắt đầu với Selenium WebDriver + Java. IDE để thử nghiệm, Grid để scale sau.


Cài đặt môi trường Selenium WebDriver với Java

Bước này nhiều bạn bị stuck đầu tiên. Mình sẽ đi từng bước, không bỏ qua gì.

Cần cài gì?

  • JDK 11+ (Java Development Kit) - nền tảng để chạy Java
  • IntelliJ IDEA Community (miễn phí) hoặc Eclipse - IDE để viết code
  • Maven - quản lý thư viện, tự động tải Selenium về
  • ChromeDriver - cầu nối giữa Selenium và Chrome

Bước 1: Tạo Maven project và thêm dependency

Mở IntelliJ, tạo project mới kiểu Maven. Trong file pom.xml, thêm:

<dependencies>
  <!-- Selenium WebDriver -->
  <dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>4.18.1</version>
  </dependency>

  <!-- WebDriverManager: tự tải ChromeDriver đúng version -->
  <dependency>
    <groupId>io.github.bonigarcia</groupId>
    <artifactId>webdrivermanager</artifactId>
    <version>5.7.0</version>
  </dependency>
</dependencies>

343367 WebDriverManager giải quyết vấn đề version ChromeDriver không khớp - bạn không cần tải thủ công

WebDriverManager là thư viện cực quan trọng cho người mới. Thay vì tự tải ChromeDriver đúng version với Chrome đang dùng (dễ nhầm lắm), WebDriverManager tự lo phần đó. Một dòng code là xong.

Bước 2: Kiểm tra môi trường

Sau khi Maven tải dependencies xong, test nhanh bằng đoạn code này:

import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

public class SanityCheck {
    public static void main(String[] args) {
        // Tự tải ChromeDriver đúng version
        WebDriverManager.chromedriver().setup();

        // Mở trình duyệt Chrome
        WebDriver driver = new ChromeDriver();

        // Mở trang Google
        driver.get("https://www.google.com");

        // In title của trang ra console
        System.out.println("Title: " + driver.getTitle());

        // Đóng trình duyệt
        driver.quit();
    }
}

Chạy được, Chrome mở lên, in Title: Google - môi trường ok. Không chạy được? Kiểm tra JDK version (java -version trong terminal phải ra 11+).

Thấy bước này nhiều thứ cài? Bình thường. Mình cũng mất nửa buổi lần đầu. Quan trọng là làm từng bước, không skip.


Viết test script đầu tiên: Kiểm thử form đăng nhập

Kịch bản thực tế nhất cho fresher: test trang đăng nhập. Hầu hết app đều có, logic rõ ràng, dễ áp dụng sang project thật.

Mình dùng trang demo The Internet - trang luyện automation testing - trang web được tạo ra để luyện automation testing, không lo bị block hay thay đổi layout bất ngờ.

Locator - cách Selenium tìm element

Trước khi code, cần hiểu locator: cách Selenium tìm đúng element trên trang. Như bạn cần địa chỉ để tìm nhà vậy.

4 locator phổ biến nhất:

Locator Ví dụ Khi nào dùng
By.id By.id("username") Có id - ưu tiên dùng nhất
By.name By.name("password") Input có attribute name
By.cssSelector By.cssSelector(".login-btn") Linh hoạt, học được từ HTML/CSS
By.xpath By.xpath("//button[@type='submit']") Khi id/name không có

343368 DevTools (F12) giúp bạn inspect element và tìm id, name, class để viết locator

Test script hoàn chỉnh

import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

public class LoginTest {
    public static void main(String[] args) {
        WebDriverManager.chromedriver().setup();
        WebDriver driver = new ChromeDriver();

        try {
            // Bước 1: Mở trang đăng nhập
            driver.get("https://the-internet.herokuapp.com/login");

            // Bước 2: Tìm ô username và nhập dữ liệu
            WebElement usernameField = driver.findElement(By.id("username"));
            usernameField.sendKeys("tomsmith");

            // Bước 3: Tìm ô password và nhập dữ liệu
            WebElement passwordField = driver.findElement(By.id("password"));
            passwordField.sendKeys("SuperSecretPassword!");

            // Bước 4: Click nút đăng nhập
            driver.findElement(By.cssSelector("button[type='submit']")).click();

            // Bước 5: Verify kết quả - đọc thông báo hiển thị
            WebElement successMsg = driver.findElement(
                By.cssSelector(".flash.success")
            );
            System.out.println("Kết quả: " + successMsg.getText());

            // Kiểm tra đã vào trang đúng chưa
            if (driver.getCurrentUrl().contains("/secure")) {
                System.out.println("PASS: Đăng nhập thành công");
            } else {
                System.out.println("FAIL: Chuyển trang sai");
            }

        } finally {
            // Luôn đóng trình duyệt dù pass hay fail
            driver.quit();
        }
    }
}

Lưu ý try-finally: bắt buộc phải có. Nếu test fail giữa chừng mà không có finally, Chrome sẽ mở lơ lửng, tiêu tốn RAM, đến lần sau chạy lại có thể lỗi. Mình từng bỏ qua rồi hỏng cả buổi test.

Chạy và đọc kết quả

Chạy class này, bạn sẽ thấy Chrome tự mở, tự điền form, tự click, rồi đóng. Console in ra PASS: Đăng nhập thành công. Làm được bước này là bạn đã viết automation test đầu tiên rồi.


Kết hợp Selenium với JUnit 5 và TestNG

Viết test trong main() như trên chỉ để học. Thực tế đi làm, bạn cần framework để tổ chức test case, báo cáo kết quả, và chạy nhiều test cùng lúc. Đó là lúc JUnit hoặc TestNG vào cuộc.

JUnit 5 hay TestNG?

Tiêu chí JUnit 5 TestNG
Học nhanh Dễ hơn Có nhiều annotation hơn
Phổ biến Rất phổ biến Java Phổ biến trong QA
Parallel testing Cần config thêm Hỗ trợ built-in
Report Cần plugin Built-in HTML report
Dùng khi Mới học, project nhỏ Project QA chuyên dụng

Mình sẽ hướng dẫn JUnit 5 vì đơn giản hơn, phù hợp người mới. TestNG học sau khi đã quen.

Cấu trúc test với JUnit 5

Thêm dependency vào pom.xml:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.2</version>
    <scope>test</scope>
</dependency>

Viết lại LoginTest theo chuẩn JUnit:

import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

class LoginJUnitTest {
    private WebDriver driver;

    // Chạy TRƯỚC mỗi test case - setup
    @BeforeEach
    void setUp() {
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver();
        driver.get("https://the-internet.herokuapp.com/login");
    }

    // Test case 1: Đăng nhập đúng thông tin
    @Test
    @DisplayName("Đăng nhập thành công với thông tin hợp lệ")
    void testLoginSuccess() {
        driver.findElement(By.id("username")).sendKeys("tomsmith");
        driver.findElement(By.id("password")).sendKeys("SuperSecretPassword!");
        driver.findElement(By.cssSelector("button[type='submit']")).click();

        // Assertions.assertTrue kiểm tra điều kiện đúng/sai
        Assertions.assertTrue(
            driver.getCurrentUrl().contains("/secure"),
            "URL phải chứa /secure sau khi đăng nhập thành công"
        );
    }

    // Test case 2: Đăng nhập sai password
    @Test
    @DisplayName("Hiện thông báo lỗi khi sai password")
    void testLoginFail() {
        driver.findElement(By.id("username")).sendKeys("tomsmith");
        driver.findElement(By.id("password")).sendKeys("sai_mat_khau");
        driver.findElement(By.cssSelector("button[type='submit']")).click();

        // Kiểm tra thông báo lỗi hiển thị
        String errorMsg = driver.findElement(By.cssSelector(".flash.error")).getText();
        Assertions.assertTrue(
            errorMsg.contains("Your password is invalid"),
            "Phải có thông báo lỗi khi sai password"
        );
    }

    // Chạy SAU mỗi test case - cleanup
    @AfterEach
    void tearDown() {
        if (driver != null) {
            driver.quit();
        }
    }
}

343369 @BeforeEach và @AfterEach đảm bảo mỗi test case chạy độc lập, không ảnh hưởng nhau

3 annotation JUnit quan trọng nhất:

  • @BeforeEach - chạy trước mỗi @Test, setup môi trường sạch
  • @Test + @DisplayName - đánh dấu test case, đặt tên đọc được
  • @AfterEach - chạy sau mỗi @Test, dọn dẹp (đóng browser)

Sau khi chạy, IntelliJ hiện panel xanh (pass) hoặc đỏ (fail) với tên test case rõ ràng. Đây là format bạn sẽ dùng mỗi ngày khi làm automation tester.


Page Object Model - tổ chức code test như người chuyên nghiệp

Bạn viết được 5-10 test case rồi? Đến lúc học cách tổ chức code đúng chuẩn. Không phải để phức tạp hóa, mà vì lý do rất thực tế: khi UI thay đổi, bạn chỉ sửa 1 chỗ thay vì sửa 10 file.

Page Object Model (POM) là design pattern phổ biến nhất trong Selenium. Ý tưởng: mỗi trang web = một class riêng, chứa tất cả locator và method của trang đó. Test case chỉ gọi method, không cần biết locator.

343370 POM tách biệt locator và logic test - thay đổi UI chỉ cần sửa Page Class, không đụng đến test

Cấu trúc project theo POM

src/
├── main/java/
│   └── pages/
│       └── LoginPage.java    ← chứa locator + method
└── test/java/
    └── tests/
        └── LoginTest.java    ← chỉ gọi method, không có locator

LoginPage.java - Page Class

package pages;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class LoginPage {
    private WebDriver driver;

    // Locator tập trung 1 chỗ - UI thay đổi, sửa ở đây thôi
    private final By usernameField = By.id("username");
    private final By passwordField = By.id("password");
    private final By loginButton = By.cssSelector("button[type='submit']");
    private final By successMessage = By.cssSelector(".flash.success");
    private final By errorMessage = By.cssSelector(".flash.error");

    public LoginPage(WebDriver driver) {
        this.driver = driver;
    }

    // Method: thực hiện đăng nhập
    public void login(String username, String password) {
        driver.findElement(usernameField).sendKeys(username);
        driver.findElement(passwordField).sendKeys(password);
        driver.findElement(loginButton).click();
    }

    // Method: lấy text thông báo thành công
    public String getSuccessMessage() {
        return driver.findElement(successMessage).getText();
    }

    // Method: lấy text thông báo lỗi
    public String getErrorMessage() {
        return driver.findElement(errorMessage).getText();
    }
}

LoginTest.java - Test Class dùng POM

package tests;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.*;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import pages.LoginPage;

class LoginTest {
    private WebDriver driver;
    private LoginPage loginPage;

    @BeforeEach
    void setUp() {
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver();
        driver.get("https://the-internet.herokuapp.com/login");
        loginPage = new LoginPage(driver); // Khởi tạo Page Object
    }

    @Test
    @DisplayName("Đăng nhập thành công")
    void testLoginSuccess() {
        // Test code cực kỳ đọc được - không thấy 1 locator nào
        loginPage.login("tomsmith", "SuperSecretPassword!");

        Assertions.assertTrue(
            driver.getCurrentUrl().contains("/secure")
        );
    }

    @Test
    @DisplayName("Sai password - hiện lỗi")
    void testWrongPassword() {
        loginPage.login("tomsmith", "sai_pass");

        Assertions.assertTrue(
            loginPage.getErrorMessage().contains("Your password is invalid")
        );
    }

    @AfterEach
    void tearDown() {
        driver.quit();
    }
}

Thấy test class không có locator nào không? Nếu ngày mai dev đổi id của ô username, bạn chỉ vào LoginPage.java sửa 1 dòng. Không đụng đến test. Đây là lý do POM tồn tại.

Tải template project POM đã setup sẵn để dùng ngay: Checklist POM Selenium tương tác


Xử lý wait và dynamic content

Lỗi phổ biến nhất của fresher khi viết Selenium: NoSuchElementException - Selenium tìm element không thấy vì trang chưa load xong. Lỗi này không phải code sai, mà do timing.

Trang web hiện đại load không tuyến tính. DOM render xong, nhưng data từ API chưa về. Hay button chỉ xuất hiện sau animation 500ms. Selenium chạy nhanh hơn browser render.

Đừng dùng Thread.sleep()

// ❌ Cách sai - cứng nhắc, chậm, không đáng tin
Thread.sleep(3000); // Ngủ 3 giây, dù trang load xong sau 0.5s
driver.findElement(By.id("result")).getText();

Thread.sleep() vừa lãng phí thời gian (luôn chờ đủ 3s), vừa không đáng tin (nếu máy chậm thì 3s vẫn chưa load xong). Không dùng trong production code.

Dùng Explicit Wait

import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;

// ✅ Cách đúng - chờ đúng khi cần, không chờ thừa
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

// Chờ tối đa 10s đến khi element xuất hiện và click được
WebElement button = wait.until(
    ExpectedConditions.elementToBeClickable(By.id("submit-btn"))
);
button.click();

// Chờ tối đa 10s đến khi text xuất hiện
wait.until(
    ExpectedConditions.textToBePresentInElementLocated(
        By.cssSelector(".result"), "Thành công"
    )
);

343372 Explicit Wait chờ đúng điều kiện, tối đa 10s - tránh chờ cứng nhắc bằng Thread.sleep

3 ExpectedConditions hay dùng nhất:

  • elementToBeClickable - chờ element hiện và click được (nút, link)
  • visibilityOfElementLocated - chờ element hiện và visible
  • textToBePresentInElementLocated - chờ text cụ thể xuất hiện

Quy tắc đơn giản: bất kỳ chỗ nào sau action (click, submit form) mà cần lấy element - dùng Explicit Wait. Không đoán mò timing.


Kiểm thử toàn diện: Kết hợp Selenium và Postman

Selenium kiểm thử giao diện (UI testing). Nhưng app thực tế có 2 lớp: UI và API backend. Chỉ test UI thôi chưa đủ.

Postman là tool kiểm thử API - gửi request HTTP (GET, POST, PUT, DELETE) và kiểm tra response trả về. Không cần giao diện, giao tiếp thẳng với backend.

343373 Kết hợp Selenium (UI) và Postman (API) tạo bộ kiểm thử toàn diện cả 2 lớp

Khi nào dùng Selenium, khi nào dùng Postman?

Tình huống Dùng gì Lý do
Test form đăng nhập trên web Selenium Có giao diện cần tương tác
Test API đăng nhập trả đúng token Postman Kiểm thử tầng backend
Verify button disable sau submit Selenium Logic UI
Verify dữ liệu lưu đúng vào DB Postman Gọi API GET để kiểm tra
Regression test toàn bộ UI Selenium Chạy lại 50 test case tự động
Load test với 100 request Postman Collection Runner Selenium không phù hợp

Ví dụ test kết hợp thực tế

Kịch bản: User đặt hàng thành công trên web.

Bước 1 - Selenium test UI flow:

// Test user đặt hàng qua giao diện
productPage.addToCart("Áo thun");
cartPage.checkout();
paymentPage.fillShipping(name, address, phone);
paymentPage.confirmOrder();
// Verify trang cảm ơn hiện đúng
Assertions.assertTrue(driver.getTitle().contains("Cảm ơn"));

Bước 2 - Postman verify data backend:

GET /api/orders?userId=123

Expected response:
{
  "status": 200,
  "data": {
    "orderId": "ORD-456",
    "status": "confirmed",
    "items": [{"name": "Áo thun", "qty": 1}]
  }
}

Test script trong Postman:

// Viết trong tab Tests của Postman
pm.test("Order được tạo với status confirmed", function() {
    const response = pm.response.json();
    pm.expect(response.data.status).to.equal("confirmed");
    pm.expect(response.data.items).to.have.length.above(0);
});

Selenium xác nhận UI đúng, Postman xác nhận data backend đúng. Cả hai cùng pass mới thực sự gọi là feature hoạt động tốt.

Tải checklist kiểm thử kết hợp Selenium + Postman: Checklist kiểm thử Selenium + Postman


Lỗi thường gặp và cách xử lý

Dưới đây là những lỗi mình gặp nhất và thấy fresher hay bị stuck nhất. Lưu lại, đỡ mất thời gian Google.

Lỗi 1: NoSuchElementException

org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element

Nguyên nhân thường gặp:

  • Element chưa load kịp khi Selenium tìm
  • Locator sai (id bị thay đổi, có space thừa)
  • Element nằm trong iframe

Fix:

// Kiểm tra lại locator bằng DevTools (F12 → Console)
// document.querySelector('#your-id') - nếu trả về null là locator sai

// Nếu locator đúng nhưng vẫn lỗi → dùng Explicit Wait
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("your-id")));

// Nếu element trong iframe:
driver.switchTo().frame("frame-name");
driver.findElement(By.id("element-in-iframe"));
driver.switchTo().defaultContent(); // Quay về main page

Lỗi 2: StaleElementReferenceException

org.openqa.selenium.StaleElementReferenceException

Nguyên nhân: Bạn lưu element vào biến, sau đó trang refresh/DOM thay đổi, element cũ không còn valid.

Fix: Tìm lại element thay vì dùng biến cũ:

// ❌ Sai: Lưu biến, sau đó DOM thay đổi
WebElement btn = driver.findElement(By.id("btn"));
driver.navigate().refresh();
btn.click(); // Lỗi ở đây

// ✅ Đúng: Tìm lại sau khi DOM thay đổi
driver.navigate().refresh();
driver.findElement(By.id("btn")).click();

Lỗi 3: ElementClickInterceptedException

Nguyên nhân: Một element khác đè lên element muốn click (popup, overlay, banner cookie).

Fix:

// Option 1: Đóng popup trước
if (driver.findElements(By.id("cookie-banner")).size() > 0) {
    driver.findElement(By.id("accept-cookie")).click();
}

// Option 2: Scroll đến element rồi click
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].scrollIntoView(true);", element);
element.click();

343374 Ba lỗi Selenium phổ biến nhất và cách nhận biết từ error message

Một tip thực tế: khi gặp lỗi lần đầu, copy nguyên error message ra Google. Selenium có cộng đồng lớn, hầu hết lỗi đã có giải pháp trên Stack Overflow. Điều quan trọng là đọc hiểu lỗi trước khi tìm cách fix.


Bước tiếp theo sau khi học xong bài này

Bạn vừa đi qua toàn bộ nền tảng automation testing với Selenium: hiểu cấu trúc, cài môi trường, viết test script, tổ chức code POM, xử lý timing, kết hợp Postman. Đây là đủ để bắt đầu contribute vào project thật.

Làm ngay sau bài này:

  1. Cài JDK + IntelliJ + Maven trong buổi chiều hôm nay - không để qua hôm sau
  2. Viết test case đăng nhập cho trang The Internet Herokuapp - dùng đúng code trong bài, chạy xem kết quả
  3. Thêm 2-3 test case negative (sai username, để trống, ký tự đặc biệt)
  4. Refactor theo POM - tách LoginPage.java và LoginTest.java
  5. Thêm Explicit Wait vào mọi chỗ sau action

Học tiếp sau khi thành thạo bài này:

  • TestNG - annotation phong phú hơn, report đẹp hơn, parallel testing dễ hơn. Nhiều công ty QA dùng TestNG hơn JUnit.
  • Selenium Grid - chạy test song song trên nhiều trình duyệt cùng lúc, rút ngắn thời gian regression
  • CI/CD với GitHub Actions - tự động chạy test mỗi lần commit code, kết quả báo về email/Slack
  • Cucumber + BDD - viết test case bằng ngôn ngữ tự nhiên (Given/When/Then), non-technical stakeholder đọc được

343375 Lộ trình học automation: từ Selenium cơ bản đến CI/CD tự động hóa hoàn toàn

Một điều mình muốn nói thẳng: Selenium có learning curve, nhưng không phải rocket science. Khó nhất là bước đầu - setup môi trường, hiểu locator, debug lỗi đầu tiên. Qua được 3 bước đó, phần còn lại là thực hành thêm nhiều test case.

Nếu bạn chưa quen với HTML/CSS (cần để hiểu locator và cấu trúc DOM), khóa HTML CSS từ Zero đến Hero miễn phí sẽ giúp bạn đọc DOM dễ hơn - không cần học cả khóa, chỉ cần phần selector và box model là đủ.

Bắt đầu với 1 test case. Rồi 5. Rồi 20. Tester giỏi không phải người biết nhiều tool, mà là người test kỹ và test đúng chỗ cần test.

Comment bên dưới nếu bạn bị stuck ở bước nào - mình trả lời từng bạn.