Từ số 0 đến bài test Selenium + Cucumber đầu tiên
Mục tiêu của bài này không phải là chép vài dòng code để thấy Chrome bật lên. Mục tiêu là hiểu mỗi lớp đang chịu trách nhiệm gì, đọc được log khi test hỏng, và biết sửa đúng chỗ.
[FPT] Đây là dự án thử thách hoàn thành setup cho bài test Selenium + Cucumber chỉ từ 1 câu prompt duy nhất, chạy luồng đăng nhập cơ bản của SauceDemo. Câu prompt hoàn hảo cb xem ở cuối bài nhé.
Tham khảo 3 Repo, 3 vesrion prompt:
Setup Tech Stack:
- Java 17+ / Maven 3.9+
- Selenium 4.27.0 / Cucumber 7.20.1
- JUnit Jupiter 5.11.4 / JUnit Platform 1.11.4
- Maven Surefire 3.5.2
🧭 Mô hình tổng thể
Maven
|
+-- src/test/resources/config.properties
| base.url, username, password
|
+-- src/test/resources/features/login.feature
| Given / When / Then
|
+-- RunCucumberTest (JUnit Platform)
|
v
Cucumber tìm step trong package com.example.saucedemo
|
+-- Hooks: tạo và đóng WebDriver
| |
| +-- DriverFactory: ChromeDriver / FirefoxDriver
| |
| +-- Selenium Manager tìm driver phù hợp
|
+-- LoginSteps: nối câu Gherkin với Java
|
+-- LoginPage: locator + thao tác UI + explicit wait
|
+-- Chrome -> https://www.saucedemo.com/
Luồng dễ nhớ: Feature mô tả hành vi -> Steps điều phối -> Page Object thao tác -> Driver điều khiển trình duyệt.
🧰 1) Chuẩn bị từ đầu
JDK 17+
Mở PowerShell và kiểm tra:
java -version
Project đặt:
<maven.compiler.release>17</maven.compiler.release>
Vì vậy JDK 17 là mốc tối thiểu của project. JDK mới hơn có thể chạy nếu dependency và môi trường tương thích.
Maven 3.9+
Kiểm tra:
mvn --version
Maven đọc pom.xml, tải dependency vào local repository, biên dịch test và gọi Surefire để chạy JUnit/Cucumber.
Chrome
Cài Chrome trên máy. DriverFactory tạo ChromeDriver, còn Selenium Manager của Selenium 4.27.0 tự xử lý việc tìm hoặc quản lý driver phù hợp. Vì vậy project không cần tải ChromeDriver thủ công và không cần đặt webdriver.chrome.driver.
Vì sao?
Nếu thiếu JDK hoặc Maven, test chưa thể chạy. Nếu thiếu Chrome, nhánh mặc định chrome trong DriverFactory không thể tạo trình duyệt. Ba điều kiện này phải được kiểm tra trước khi đọc lỗi Cucumber.
🗂️ 2) Maven layout của project
CucumberJava/
|-- pom.xml
|-- README.md
|-- src/
| `-- test/
| |-- java/com/example/saucedemo/
| | |-- config/Config.java
| | |-- driver/DriverFactory.java
| | |-- hooks/Hooks.java
| | |-- pages/LoginPage.java
| | |-- runner/RunCucumberTest.java
| | `-- steps/LoginSteps.java
| `-- resources/
| |-- config.properties
| `-- features/login.feature
`-- target/ (Maven sinh ra, khong sua tay)
src/test/java: Java code phục vụ test.src/test/resources: feature và cấu hình được đưa lên test classpath.target: class đã biên dịch, report và file tạm; có thể bị xóa rồi sinh lại.pom.xml: danh sách dependency, Java release và plugin chạy test.
Vì sao?
Tách resources khỏi Java giúp feature và cấu hình dễ đọc, dễ thay đổi. Cucumber có thể tìm features trên classpath, còn Config có thể đọc config.properties bằng ClassLoader.
🧩 3) Đọc pom.xml: dependency nào làm việc gì?
Các phiên bản đang dùng trong pom.xml:
| Thành phần | Dependency / cấu hình | Vai trò |
|---|---|---|
| Java | maven.compiler.release=17 |
Biên dịch theo Java 17 |
| Selenium | org.seleniumhq.selenium:selenium-java:4.27.0 |
WebDriver, locator, wait, Chrome/Firefox driver |
| Cucumber Java | io.cucumber:cucumber-java:7.20.1 |
Annotation @Given, @When, @Then |
| Cucumber JUnit | io.cucumber:cucumber-junit-platform-engine:7.20.1 |
Chạy Cucumber qua JUnit Platform |
| JUnit Suite | org.junit.platform:junit-platform-suite:1.11.4 |
@Suite, @IncludeEngines, chọn resource |
| JUnit API | org.junit.jupiter:junit-jupiter-api:5.11.4 |
Assertion assertTrue trong step |
| Surefire | maven-surefire-plugin:3.5.2 |
Maven tìm và chạy test; sinh report |
Cấu hình report hiện tại trong Surefire:
cucumber.plugin=pretty,html:target/cucumber-reports/cucumber.html,json:target/cucumber-reports/cucumber.json
cucumber.publish.quiet=true
Vì sao?
Cucumber không tự chạy chỉ vì có file .feature. Cucumber cần engine, JUnit Platform cần suite, còn Maven cần Surefire để gọi toàn bộ chuỗi đó bằng mvn test.
🔐 4) Cấu hình URL và tài khoản
[config.properties]
├─ base.url
├─ username
└─ password
│ ClassLoader
▼
[Config.get(key)] → [LoginPage / LoginSteps]
File hiện tại là src/test/resources/config.properties:
base.url=https://www.saucedemo.com/
username=standard_user
password=secret_sauce
Config.java tải file từ test classpath:
try (InputStream input = Config.class.getClassLoader()
.getResourceAsStream("config.properties")) {
if (input == null) {
throw new IllegalStateException(
"config.properties was not found on the test classpath");
}
properties.load(input);
}
Mọi nơi dùng cấu hình qua:
Config.get("base.url");
Config.get("username");
Config.get("password");
Nếu key không tồn tại hoặc rỗng, Config.get ném IllegalArgumentException.
Với project thật, mật khẩu không nên commit công khai. Bài này giữ credentials mẫu của SauceDemo để reproducing đúng bài test.
Vì sao?
URL và credential là dữ liệu thay đổi, không phải trách nhiệm của Page Object. Đưa chúng vào properties giúp LoginPage chỉ lo thao tác giao diện, còn LoginSteps lấy dữ liệu từ cấu hình.
🧱 5) POM: Page Object Model là gì?
LoginPage đại diện cho màn hình đăng nhập. Nó giữ:
WebDriverđể gửi lệnh tới browser.- Locator
usernameInput,passwordInput,loginButton,productsTitle. WebDriverWaitdùng lại cho các thao tác cần chờ.- Các method mang ý nghĩa nghiệp vụ:
open,logIn,isProductsPageDisplayed.
LoginSteps
|
| goi logIn(username, password)
v
LoginPage
|
| dung locator va wait
v
WebDriver -> Chrome -> SauceDemo
Vì sao?
Nếu locator nằm rải rác trong step, thay đổi HTML sẽ buộc sửa nhiều nơi. POM gom locator và thao tác UI vào một lớp, nên step đọc gần với ngôn ngữ người dùng hơn.
🚗 6) DriverFactory và Selenium Manager
DriverFactory.createDriver() đọc hai system property:
browser = chrome (mac dinh)
headless = false (mac dinh)
Các lựa chọn hiện có:
chrome: tạoChromeDrivervà đặt kích thước cửa sổ1920x1080.firefox: tạoFirefoxDriver.headless=true: chạy không mở cửa sổ thật.- browser khác: ném
IllegalArgumentException.
Ví dụ phần tạo Chrome:
private static ChromeOptions chromeOptions(boolean headless) {
ChromeOptions options = new ChromeOptions();
if (headless) {
options.addArguments("--headless=new");
}
options.addArguments("--window-size=1920,1080");
return options;
}
Vì sao?
Factory tạo driver ở một chỗ duy nhất. Selenium Manager được Selenium 4.27.0 gọi phía dưới để tìm driver; test không cần biết đường dẫn executable.
🪝 7) Hooks: tạo driver, chụp ảnh, đóng driver
Hooks chạy quanh mỗi scenario:
@Before
public void setUp() {
DRIVER.set(DriverFactory.createDriver());
}
@After
public void tearDown(Scenario scenario) {
WebDriver driver = DRIVER.get();
if (scenario.isFailed() && driver instanceof TakesScreenshot screenshotDriver) {
scenario.attach(screenshotDriver.getScreenshotAs(OutputType.BYTES),
"image/png", "failure");
}
if (driver != null) {
driver.quit();
DRIVER.remove();
}
}
ThreadLocal<WebDriver> tách driver theo thread. Hooks.driver() trả driver cho step; nếu gọi quá sớm, nó báo WebDriver has not been initialized.
Vì sao?
Mỗi scenario cần trạng thái browser sạch. quit() giải phóng browser sau test; screenshot khi fail giúp nhìn thấy màn hình thực tế tại thời điểm lỗi.
🥒 8) Feature Cucumber: viết hành vi trước
File src/test/resources/features/login.feature:
Feature: SauceDemo login
As a SauceDemo user
I want to log in with valid credentials
So that I can access the products page
Scenario: Login succeeds with valid credentials
Given I am on the SauceDemo login page
When I log in with valid credentials
Then I should see the products page
Given, When, Then mô tả hành vi, không mô tả chi tiết CSS hay WebDriver. Đây là lý do feature có thể được đọc bởi người không viết Java.
Vì sao?
Feature là hợp đồng hành vi. Chi tiết “tìm phần tử bằng id nào” thuộc Page Object, không nên làm feature khó đọc.
🔗 9) Steps: nối Gherkin với Java
LoginSteps ánh xạ từng câu trong feature:
@Given("I am on the SauceDemo login page")
public void openLoginPage() {
loginPage = new LoginPage(Hooks.driver());
loginPage.open();
}
@When("I log in with valid credentials")
public void logInWithValidCredentials() {
loginPage.logIn(Config.get("username"), Config.get("password"));
}
@Then("I should see the products page")
public void verifyProductsPage() {
assertTrue(loginPage.isProductsPageDisplayed(),
"The products page should be displayed after login");
}
Vì sao?
Step chỉ điều phối: lấy driver, lấy dữ liệu cấu hình, gọi Page Object và assert kết quả. Nó không nên chứa nhiều locator hoặc logic chờ riêng lẻ.
▶️ 10) JUnit runner: điểm bắt đầu của Maven
RunCucumberTest là JUnit Platform suite:
@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME,
value = "com.example.saucedemo")
public class RunCucumberTest {
}
@Suite: đây là một suite JUnit.@IncludeEngines("cucumber"): dùng Cucumber engine.@SelectClasspathResource("features"): tìm feature trongsrc/test/resources/features.GLUE_PROPERTY_NAME: tìm step, hook và các class Cucumber trongcom.example.saucedemo.
Vì sao?
Không có runner đúng, Maven có thể biên dịch Java nhưng không tìm thấy scenario để chạy. Runner là điểm nối giữa JUnit Platform và Cucumber.
🏃 11) Chạy project và đọc output
[clean test-compile] → [mvn test]
│
┌────────────┴────────────┐
▼ ▼
[Chrome / Firefox] [HTML + JSON report]
Biên dịch cả main/test code:
mvn clean test-compile
Chạy test bình thường, mở Chrome:
mvn test
Chạy headless:
mvn test -Dheadless=true
Chọn Firefox, vì DriverFactory có hỗ trợ:
mvn test -Dbrowser=firefox
Các report được ghi vào:
target/cucumber-reports/cucumber.html
target/cucumber-reports/cucumber.json
Output thành công thường có ba bước màu xanh:
Given I am on the SauceDemo login page
When I log in with valid credentials
Then I should see the products page
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
Lưu ý: Maven có thể chạy xong nhưng log vẫn chứa WARNING. Hãy phân biệt WARNING với ERROR, Failures và BUILD FAILURE.
🐞 12) Lỗi thực tế: NoSuchElementException tại #user-name
Lỗi người dùng gặp có dạng bản chất như sau:
org.openqa.selenium.NoSuchElementException:
Unable to locate element: {"method":"css selector","selector":"#user-name"}
Trong log còn thể hiện implicit wait bằng 0. Điều đó có nghĩa là lệnh tìm phần tử chỉ kiểm tra một lần tại thời điểm đó. Nếu trang chưa tải xong hoặc form chưa xuất hiện, Selenium ném lỗi ngay.
driver.findElement(By.id("user-name"))
|
+-- kiem tra ngay lap tuc
+-- implicit wait = 0
+-- chua co element -> NoSuchElementException
Cách đọc lỗi
- Đọc loại exception:
NoSuchElementExceptionnói rằng Selenium không tìm thấy element tại thời điểm tìm. - Đọc locator:
#user-nametương đươngBy.id("user-name"); locator của SauceDemo là hợp lệ. - Đọc wait: implicit wait
0cho thấy không có thời gian chờ ngầm. - Đọc step đang fail: lỗi xảy ra trong thao tác login, trước assertion products page.
- Kiểm tra URL và screenshot: có thể trang chưa mở đúng URL, mạng chậm, hoặc browser đang ở trang khác.
Vì sao không nên chỉ tăng implicit wait?
Implicit wait là cấu hình toàn cục cho mọi findElement. Nó có thể làm test chậm và khó đoán khi trộn với explicit wait. Với trạng thái cụ thể như “username đã hiển thị”, explicit wait diễn đạt đúng ý định hơn.
🛠️ 13) Sửa đúng chỗ bằng WebDriverWait
[findElement ngay]
│ element chưa sẵn sàng
▼
[NoSuchElementException]
│ sửa bằng
▼
[WebDriverWait + điều kiện đúng]
Trước: tìm ngay lập tức
Đây là kiểu code gây lỗi khi implicit wait bằng 0:
public void logIn(String username, String password) {
driver.findElement(usernameInput).sendKeys(username);
driver.findElement(passwordInput).sendKeys(password);
driver.findElement(loginButton).click();
}
Nếu thao tác open() cũng chỉ gọi driver.get(...) mà không chờ form, rủi ro còn rõ hơn:
public void open() {
driver.get(Config.get("base.url"));
}
Vì sao?
driver.get chờ một phần quá trình tải trang, nhưng không nên giả định rằng mọi element động đã sẵn sàng đúng vào thời điểm lệnh tiếp theo chạy. Mạng, máy và browser có tốc độ khác nhau.
Sau: chờ đúng trạng thái cần thao tác
LoginPage hiện tại đã dùng hướng này:
public LoginPage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
}
public void open() {
driver.get(Config.get("base.url"));
wait.until(ExpectedConditions.visibilityOfElementLocated(usernameInput));
}
public void logIn(String username, String password) {
wait.until(ExpectedConditions.visibilityOfElementLocated(usernameInput))
.sendKeys(username);
wait.until(ExpectedConditions.visibilityOfElementLocated(passwordInput))
.sendKeys(password);
wait.until(ExpectedConditions.elementToBeClickable(loginButton)).click();
}
Cách đọc từng dòng:
Duration.ofSeconds(10): tối đa chờ 10 giây cho mỗi điều kiện.visibilityOfElementLocated(usernameInput): element phải tồn tại và nhìn thấy được.elementToBeClickable(loginButton): nút phải sẵn sàng để click.- Nếu hết 10 giây, lỗi sẽ là timeout có ngữ cảnh hơn, thay vì thất bại tức thời.
Explicit wait không chữa được URL sai, selector sai hoặc server không phản hồi. Nó chỉ xử lý đúng bài toán đồng bộ hóa khi element xuất hiện muộn.
Cải thiện tiếp theo cho assertion
isProductsPageDisplayed() hiện kiểm tra URL rồi gọi ngay:
return driver.getCurrentUrl().contains("/inventory.html")
&& driver.findElement(productsTitle).getText().equals("Products");
Đây là điểm có thể làm explicit-wait robust hơn ở bước tiếp theo, chẳng hạn chờ productsTitle visible trước khi đọc text. Bài này không sửa code đó; chỉ ghi nhận để tránh nhầm rằng mọi điểm trong flow đã có wait.
⚠️ 14) Cảnh báo CDP với Chrome 153
Log thực tế còn có:
WARNING: Unable to find CDP implementation matching 153
WARNING: Unable to find version of CDP to use for 153.0.8010.53
Giải thích:
- Chrome đang là nhánh major
153. - Selenium 4.27.0 có các module CDP cụ thể cho một số phiên bản Chromium, nhưng không có implementation khớp
153trong bộ dependency hiện tại. - Đây là WARNING, không phải nguyên nhân trực tiếp của
NoSuchElementException. - Test login có thể vẫn chạy thành công nếu chỉ dùng WebDriver API thông thường. Log chạy thành công gần nhất của project có
Failures: 0, nhưng vẫn in cảnh báo này.
CDP đặc biệt quan trọng khi test dùng DevTools API như network interception, performance log hoặc browser emulation. Với flow hiện tại chỉ dùng ChromeDriver, locator, click và wait, cần theo dõi warning nhưng không nên chữa nhầm nó thành lỗi locator.
Vì sao?
Hai vấn đề khác nhau:
NoSuchElementException + implicit wait 0
-> vấn đề đồng bộ element
Unable to find CDP implementation matching 153
-> lệch phiên bản Chrome/CDP integration
Ưu tiên sửa explicit wait cho lỗi element. Nếu sau này cần CDP API, cân nhắc cập nhật Selenium tương thích với Chrome hoặc thêm module CDP đúng theo hướng dẫn của chính Selenium; không tự đoán artifact version.
📋 15) Checklist xử lý lỗi
[ ] java -version >= 17
[ ] mvn --version >= 3.9
[ ] Chrome đã cài và mở được
[ ] base.url có dấu / đúng và truy cập được
[ ] config.properties nằm trong src/test/resources
[ ] username/password không rỗng
[ ] feature nằm trong src/test/resources/features
[ ] runner chọn đúng resource "features"
[ ] glue trỏ tới com.example.saucedemo
[ ] locator #user-name đúng với trang đang mở
[ ] URL thực tế là https://www.saucedemo.com/
[ ] dùng explicit wait cho element xuất hiện/click được
[ ] screenshot failure được xem trong report
[ ] phân biệt WARNING với BUILD FAILURE
[ ] kiểm tra target/cucumber-reports/cucumber.html
Nếu vẫn lỗi #user-name, kiểm tra theo thứ tự:
- In hoặc quan sát URL hiện tại; có thể browser bị redirect hoặc không tải được mạng.
- Mở
base.urlbằng tay trên Chrome. - Xem screenshot do
Hooksattach khi scenario fail. - Xác nhận
LoginPagedùngBy.id("user-name"), không gõ nhầmusername. - Giữ explicit wait và kiểm tra timeout có đủ 10 giây trong môi trường chậm.
- Nếu lỗi là
TimeoutException, đó là dấu hiệu element không xuất hiện trong thời gian chờ; quay lại kiểm tra URL, mạng và DOM.
🧠 16) Tổng kết:
| Thành phần | Trách nhiệm chính |
|---|---|
pom.xml |
Dependency, Java release, Surefire, report |
Config |
Đọc properties và báo thiếu key |
DriverFactory |
Tạo Chrome/Firefox và options |
Hooks |
Setup, teardown, screenshot |
LoginPage |
Locator, thao tác UI, explicit wait |
LoginSteps |
Nối Gherkin với Page Object, assertion |
login.feature |
Mô tả hành vi người dùng |
RunCucumberTest |
Chọn Cucumber engine, feature, glue |
Tổng kết 1 câu: Feature nói cần gì, Step điều phối, Page Object biết làm thế nào, Hook quản lý vòng đời, DriverFactory biết tạo browser, Maven biết cách chạy tất cả.
Khi test fail, đừng sửa theo dòng log cuối cùng một cách máy móc. Hãy hỏi: đây là locator sai, trang sai, browser chưa sẵn sàng, hay chỉ là warning tương thích? Với lỗi hiện tại, câu trả lời là đồng bộ hóa element: dùng WebDriverWait và ExpectedConditions trong LoginPage.
🎯 Kết luận
Một project Selenium + Cucumber dễ bảo trì khi mỗi lớp có trách nhiệm rõ: feature mô tả hành vi, step điều phối, Page Object thao tác UI, hook quản lý vòng đời và Maven chạy test. Khi lỗi xảy ra, cần phân biệt lỗi locator, lỗi đồng bộ, lỗi môi trường và cảnh báo tương thích trước khi sửa.
🧳 Tóm tắt bỏ túi (Take away)
| Điểm chính | Hành động |
|---|---|
| Môi trường | Kiểm tra JDK, Maven, browser và cấu hình trước khi debug. |
| Page Object | Giữ locator và explicit wait trong LoginPage, không rải logic UI vào step. |
| Debug | Đọc exception, URL, screenshot và report cùng nhau. |
| Tham khảo | Có thể xem project CucumberJava, nhưng phải tự xác minh dependency và yêu cầu CI. |
Phụ lục “The Perfect 1-PROMPT” (3 version):
Đây là câu prompt mình đã dùng bản trong bản miễn phí của github copilot default. Mở VScode lên 1 folder trống trơn và gõ vào ô chat:
The Perfect 1-PROMPT (version 0):
Version 0: /pkduong/CucumberJava
giúp tôi setup project này: java selenium and cucumber, testing sample webapp: https://www.saucedemo.com/ ; project design with standard POM. Sau khi setup xong, create a first feature file to login with username/password: standard_user / secret_sauce that save in config data file
25.9.2026: Đây là một câu prompt rất ngẫu hứng của tôi test thử Agent mode Auto, lúc đó nó đã chọn GPT-5.6 Luna
Completed 23 steps in 10m 57s
Đây là thời gian Luna nó chạy để set up cho tôi. Detail nó trả về trong cửa sổ chat bên dưới.
Kết quả: thấy ngon lành lắm nó có báo self-test đồ, nhưng khi tôi chạy thì văng lỗi: NoSuchElementException. Và Luna cũng xác định nguyên nhân là test tìm element ngay sau driver.get() trong khi implicit wait = 0. Sau đó nó fix tại LoginPage.java dùng WebDriverWait như đã nói tại số 12. Lỗi thực tế ở trên
Tôi sẽ kiểm tra cấu trúc project và build file hiện có trước, sau đó giữ nguyên framework đang dùng nếu đã có. Mục tiêu là xác định điểm đặt cho POM, config dữ liệu đăng nhập, và test runner rồi mới tạo feature đầu tiên và chạy một kiểm tra hẹp.
Search Files Completed with input: { “workspacePath”: “d:\workspace\CucumberJava”, “query”: “<artifactId>|cucumber|selenium|class “, “includePattern”: “**/*”, “sessionId”: “setup-cucumber-java” }
Inspect Java project structure
Searched for files matching CucumberJava · **/*, 2 matches
Searched for regex cucumber|selenium|webdriver|@Given|@When|@Then|pom.xml|build.gradle|settings.gradle, 2 results
Searched for files matching CucumberJava · **/pom.xml, no matches
Searched for files matching CucumberJava · **/build.gradle*, no matches
Searched for files matching CucumberJava · **/*.java, no matches
Searched for files matching CucumberJava · **/*.feature, no matches
Project hiện chỉ có README.md và .gitignore, chưa có build tool hay source code. Vì vậy tôi sẽ dựng một Maven project tối thiểu theo layout chuẩn, với src/test/java cho runner/page objects/steps và src/test/resources cho feature/config; sau đó kiểm tra bằng Maven compile hoặc test nếu môi trường có Maven/JDK.
Create Selenium Cucumber framework
Generating patch (307 lines) in , , , , , , , , ,
Ran terminal command: mvn -q test-compile
Ran terminal command: mvn -q test -Dheadless=true
Checked terminal output
Sent Y to terminal
Ran terminal command: mvn -q test -Dheadless=true
Checked pom.xml, 1 problem found
Read CucumberJava
Read src/test/java/com/example/saucedemo
Generating patch (13 lines) in pom.xml
Ran terminal command: mvn test-compile Completed with input: mvn test-compile Tool execution failed with exit code 1
Checked pom.xml, 1 problem found
Generating patch (16 lines) in pom.xml
Ran terminal command: mvn test-compile
Ran terminal command: mvn test -Dheadless=true
Read src/test/resources
Read src/test/java/com/example/saucedemo/config
Read src/test/java/com/example/saucedemo/driver
Read src/test/java/com/example/saucedemo/hooks
Read src/test/java/com/example/saucedemo/pages
Read src/test/java/com/example/saucedemo/runner
Read src/test/java/com/example/saucedemo/steps
Generating patch (6 lines) in .gitignore
Đã setup project Java Selenium + Cucumber theo chuẩn Maven và Page Object Model.
Các thành phần chính:
pom.xml: Selenium, Cucumber, JUnit, Maven Surefireconfig.properties: lưu URL, username và passwordLoginPage.java: Page ObjectLoginSteps.java: Cucumber stepslogin.feature: test đăng nhậpRunCucumberTest.java: test runnerHooks.java: quản lý WebDriver
Đã kiểm tra thành công:
mvn test-compile
mvn test -Dheadless=true
Kết quả: 1 test passed, không lỗi. Selenium có một cảnh báo CDP không ảnh hưởng đến test.
The Perfect 1-PROMPT (version 1):
Còn đây là phiên bản prompt hoàn hảo cho các bạn copy & paste, 1 phát là ăn ngay. Check repo đã chạy với 1-prompt này:
Version 1: /pkduong/CucumberJava-1prompt
Hãy setup hoàn chỉnh project Java Selenium + Cucumber để test đăng nhập tại https://www.saucedemo.com/, theo Maven và Page Object Model chuẩn.
Yêu cầu:
- Dùng Java 17+, Selenium, Cucumber và JUnit 5 với các phiên bản tương thích.
- Tạo cấu trúc Maven chuẩn, Cucumber runner, hooks quản lý WebDriver, Page Object, step definitions và feature đăng nhập thành công.
- Lưu base URL, standard_user và secret_sauce trong file config; không hardcode trong step hoặc Page Object.
- Dùng Selenium Manager để tự tìm browser driver.
- Dùng explicit wait (WebDriverWait/ExpectedConditions) để chờ form hiển thị sau khi mở trang, chờ các trường nhập liệu và nút login sẵn sàng, rồi chờ trang sản phẩm sau khi đăng nhập. Không dựa vào implicit wait hoặc Thread.sleep().
- Viết assertion xác nhận đăng nhập thành công trên trang sản phẩm.
- Chạy mvn test -Dheadless=true. Nếu test lỗi, hãy đọc log, xác định nguyên nhân, sửa code và chạy lại cho đến khi test pass; không báo thành công nếu chưa chạy được.
Tôi đã thử lần thứ 2 cũng từ 1 folder trống không, ngày 13.10.2026, tôi cũng dùng copilot free as default. Agent auto mode nó chọn GPT-6-Luna.
- Lần này nó nhanh hơn hẳn, chỉ có 3m 57s là xong, tốn 1.3 credits.
Completed 7 steps in 3m 57s (took 1.3 credits, used GPT-6-Luna)
Đã setup xong project Maven cho kiểm thử đăng nhập SauceDemo theo Page Object Model.
- Cấu hình Maven, Java 17+, Selenium, Cucumber và JUnit 5: pom.xml
- Base URL và tài khoản demo được lưu ngoài code test: config.properties
- Cucumber runner: RunCucumberTest.java
- Khởi tạo và đóng WebDriver qua hooks; dùng ChromeDriver để Selenium Manager tự tìm driver: DriverManager.java, Hooks.java
- Page Objects với explicit waits: LoginPage.java, ProductsPage.java
- Steps và feature đăng nhập thành công: LoginSteps.java, login.feature
- Đã chạy mvn test -Dheadless=true: BUILD SUCCESS, 1 test chạy, 0 lỗi, 0 thất bại. Log có cảnh báo CDP không tìm thấy implementation khớp phiên bản Chromium, nhưng không ảnh hưởng đến test; scenario đăng nhập và assertion trang Products đều pass.
PS D:\workspace\CucumberJava-1prompt> mvn test
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 12.090 s
[INFO] Finished at: 2026-10-13T21:33:24+07:00
[INFO] ------------------------------------------------------------------------
PS D:\workspace\CucumberJava-1prompt>
The Perfect 1-PROMPT (version 2):
Version này có thêm 3 yếu tố “sang chảnh”: Tích hợp Allure report, Data-driven testing (login với nhiều user) và tích hợp CI/CD GitHub Actions
version 2: /pkduong/CucumberJava-1prompt-v2
Hãy setup hoàn chỉnh project Java Selenium + Cucumber để test đăng nhập tại https://www.saucedemo.com, theo Maven và Page Object Model chuẩn.
Yêu cầu:
- Dùng Java 17+, Selenium, Cucumber và JUnit 5 với các phiên bản tương thích.
- Tạo cấu trúc Maven chuẩn, Cucumber runner, hooks quản lý WebDriver, Page Object, step definitions và feature đăng nhập thành công.
- Dùng Selenium Manager để tự tìm browser driver.
- Dùng **explicit wait** (`WebDriverWait`/`ExpectedConditions`) để chờ form hiển thị sau khi mở trang, chờ các trường nhập liệu và nút login sẵn sàng, rồi chờ trang sản phẩm sau khi đăng nhập. Không dựa vào `implicit wait` hoặc `Thread.sleep()`.
- Tích hợp Allure Report tương thích với Cucumber và JUnit Platform. Ghi kết quả test vào Allure results, cấu hình cách tạo report và ghi rõ các lệnh để chạy test và xem report.
- Chuyển kiểm thử đăng nhập sang data-driven testing bằng Cucumber `Scenario Outline` và `Examples` hoặc một cách tương đương phù hợp. Chạy lần lượt với các username `standard_user`, `locked_out_user`, `problem_user`, `performance_glitch_user`, `error_user`, `visual_user`; mật khẩu dùng chung cho tất cả là `secret_sauce`.
- Lưu base URL, danh sách username và mật khẩu dùng chung trong file cấu hình; không hardcode URL hay thông tin đăng nhập trong step definitions hoặc Page Objects.
- Assertion phải phản ánh đúng kết quả của từng user: `locked_out_user` phải bị từ chối và hiển thị thông báo lỗi phù hợp; các user còn lại phải đăng nhập thành công và thấy trang Products.
- Tích hợp GitHub Actions để chạy `mvn test -Dheadless=true` khi có pull request và khi push lên nhánh chính. Dùng Java 17, lưu lại Allure results/report thành artifact để có thể tải từ workflow run, và cấu hình workflow theo hướng bảo trì được.
- Chạy test tại local bằng `mvn test -Dheadless=true`, kiểm tra kết quả và report. Nếu có lỗi, hãy đọc log, xác định nguyên nhân, sửa rồi chạy lại đến khi pass; không báo thành công nếu chưa chạy được. Cuối cùng liệt kê các file đã tạo hoặc chỉnh sửa và cách xem Allure report.
Và đây là response evidence của em Luna, mode Auto nó chọn GPT-6-Luna, phiên bản default free.
Completed 14 steps in 6m 39s, 1.8 credits.
Đã setup xong project SauceDemo. Lần chạy đầu phát hiện thiếu JUnit Jupiter API; em đã bổ sung dependency và chạy lại.
Kết quả kiểm thử: mvn --batch-mode test -Dheadless=true — 6 passed, 0 failures, 0 errors. Allure results được ghi vào target/allure-results, và báo cáo HTML đã tạo thành công. Kiểm tra thêm xác nhận đủ 6 kết quả Allure đều passed.
File đã tạo
pom.xml— Maven, Java 17, Selenium, Cucumber, JUnit 5, Allure.RunCucumberTest.java— Cucumber runner trên JUnit Platform.TestConfig.java— đọc và kiểm tra cấu hình test.DriverManager.javavàWebDriverHooks.java— quản lý vòng đời WebDriver; Selenium Manager tự tìm driver.LoginPage.javavàProductsPage.java— Page Objects với explicit waits.LoginSteps.java— đăng nhập và kiểm tra kết quả.login.feature— Scenario Outline chạy sáu tài khoản theo vị trí trong cấu hình.test-data.properties— base URL, danh sách username, mật khẩu chung và tài khoản bị khóa.allure.properties— vị trí lưu Allure results.selenium-tests.yml— GitHub Actions chạy khi có pull request và push lênmain, dùng Java 17 và tải Allure artifacts.README.mdvà.gitignore.
Chạy test và xem báo cáo Alure
mvn test -Dheadless=true
mvn allure:serve
Trong GitHub Actions, tải artifact allure-report-<run number> từ workflow run để lấy results và HTML report.
PS D:\workspace\CucumberJava-1prompt-v2> mvn test
[INFO] Results:
[INFO]
[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 56.159 s
[INFO] Finished at: 2026-10-13T22:19:31+07:00
[INFO] ------------------------------------------------------------------------
PS D:\workspace\CucumberJava-1prompt-v2> mvn allure:serve
[INFO] Generate Allure report (serve) with version 2.30.0
[INFO] Generate Allure report to D:\workspace\CucumberJava-1prompt-v2\target\site/allure-maven-plugin
[INFO] Found results directory D:\workspace\CucumberJava-1prompt-v2\target\allure-results
[INFO] Can't find information about categories
[INFO] Generate report to D:\workspace\CucumberJava-1prompt-v2\target\site\allure-maven-plugin
Generating report to temp directory...
Report successfully generated to C:\Users\PKDUONG\AppData\Local\Temp\14055471429166865311\allure-report
Starting web server...
2026-10-13 22:40:06.760:INFO::main: Logging initialized @5615ms to org.eclipse.jetty.util.log.StdErrLog
Server started at <http://192.168.1.138:52163/>. Press <Ctrl+C> to exit