NỘI DUNG BÀI HỌC
✅LẶP LẠI CÓ CẤU TRÚC VỚI VÒNG LẶP for
✅LÀM VIỆC VỚI DANH SÁCH DÙNG MẢNG (ARRAY)
✅LÀM VIỆC VỚI DỮ LIỆU CÓ CẤU TRÚC (OBJECT)
🔁 Phần 1: Lặp lại hành động với vòng lặp while
Vòng lặp while phù hợp khi bạn chưa biết trước chính xác số lần lặp. Bạn chỉ biết rằng một khối lệnh cần tiếp tục chạy cho đến khi một điều kiện nào đó không còn đúng nữa.
Trong automation, đây là kiểu vòng lặp rất hợp cho các tình huống chờ một trạng thái thay đổi, ví dụ chờ nút xuất hiện, chờ loading biến mất hoặc chờ dữ liệu được cập nhật.
🔹 1. Cấu trúc của vòng lặp while
Một vòng lặp while luôn có 3 phần bạn phải nhớ:
- Khởi tạo: tạo biến điều kiện trước khi vòng lặp bắt đầu.
- Điều kiện: nếu điều kiện còn
truethì vòng lặp tiếp tục chạy. - Cập nhật: thay đổi biến điều kiện để vòng lặp có thể dừng lại đúng lúc.
💻 Cú pháp chuẩn:
let dieuKien = 1; // 1. Khởi tạo biến điều kiện
while (dieuKien <= 5) { // 2. Kiểm tra điều kiện trước mỗi lần lặp
console.log(`Giá trị hiện tại: ${dieuKien}`); // Khối lệnh cần chạy lặp lại
dieuKien++; // 3. Cập nhật điều kiện để vòng lặp tiến tới điểm dừng
}
🔹 2. Ví dụ cơ bản với while
Ví dụ đơn giản nhất là in các số từ 1 đến 5. Mục đích ở đây là giúp bạn nhìn rõ vai trò của biến đếm và bước cập nhật sau mỗi lần lặp.
💻 Ví dụ in số từ 1 đến 5:
let count = 1; // Bắt đầu từ số 1
while (count <= 5) { // Chỉ lặp khi count còn nhỏ hơn hoặc bằng 5
console.log(`Đếm số: ${count}`); // In ra giá trị hiện tại
count++; // Tăng count lên 1 để tiến tới lần lặp tiếp theo
}
console.log("Đã đếm xong!"); // Chạy sau khi vòng lặp kết thúc
⚠️ Lưu ý: Nếu bạn quên bước cập nhật biến điều kiện, vòng lặp có thể chạy mãi không dừng và làm treo chương trình.
💻 Ví dụ vòng lặp vô hạn cần tránh:
let i = 0; // Biến đếm được tạo ra ban đầu
while (i < 5) { // Điều kiện này luôn đúng nếu i không thay đổi
console.log("Lặp lại mãi mãi...");
// Quên không có i++ ở đây => vòng lặp sẽ không dừng
}
🔹 3. Ứng dụng while trong automation
Khi viết test, bạn không phải lúc nào cũng biết chính xác một phần tử sẽ xuất hiện sau bao nhiêu lần kiểm tra. Lúc đó, while rất hữu ích vì bạn chỉ cần nói: “cứ kiểm tra tiếp cho đến khi điều kiện đạt yêu cầu”.
Tuy nhiên, trong automation bạn không nên để while chạy tự do. Hãy luôn có thêm giới hạn số lần kiểm tra hoặc timeout để tránh kịch bản bị treo vô hạn.
💻 Ví dụ chờ nút “Thanh toán” xuất hiện:
let nutThanhToanIsVisible = false; // Giả lập trạng thái ban đầu
let soLanKiemTra = 0; // Biến đếm số lần đã kiểm tra
const soLanKiemTraToiDa = 10; // Giới hạn để tránh vòng lặp vô hạn
while (!nutThanhToanIsVisible && soLanKiemTra < soLanKiemTraToiDa) {
console.log(`Lần kiểm tra ${soLanKiemTra + 1}: Nút chưa xuất hiện`);
// Trong code Playwright thật, bạn có thể kiểm tra trạng thái phần tử ở đây
// await page.waitForTimeout(1000);
// nutThanhToanIsVisible = await page.locator("#checkout-button").isVisible();
if (soLanKiemTra === 4) {
nutThanhToanIsVisible = true; // Giả lập rằng nút xuất hiện ở lần kiểm tra thứ 5
}
soLanKiemTra++; // Luôn cập nhật để vòng lặp có cơ hội kết thúc
}
if (nutThanhToanIsVisible) {
console.log("Nút Thanh toán đã xuất hiện, có thể click");
} else {
console.log("Đã vượt quá số lần kiểm tra cho phép");
}
🔂 Phần 2: Lặp có cấu trúc với vòng lặp for, break và continue
Nếu while phù hợp khi chưa biết trước số lần lặp, thì for là công cụ lý tưởng khi bạn biết khá rõ mình muốn lặp bao nhiêu lần. Đây là vòng lặp xuất hiện rất nhiều trong code JavaScript cơ bản và trong các bài toán retry.
🔹 1. Cú pháp của vòng lặp for
Vòng lặp for thực chất vẫn có đủ 3 phần giống while, chỉ khác là JavaScript gom chúng lại trên một dòng.
- Khởi tạo: thường là tạo biến đếm như
let i = 0. - Điều kiện: quyết định có tiếp tục lặp hay không.
- Cập nhật: thường là
i++hoặci--.
💻 Cú pháp chuẩn:
for (let i = 0; i < 5; i++) { // Khởi tạo; điều kiện; cập nhật
console.log(`Lần lặp thứ: ${i}`); // Chạy mỗi khi điều kiện còn đúng
}
🔹 2. Ví dụ cơ bản với for
Ví dụ dưới đây in các số từ 0 đến 4. Điểm mạnh của for là bạn nhìn một dòng đã biết vòng lặp bắt đầu ở đâu, dừng ở đâu và tăng như thế nào.
💻 Ví dụ in số từ 0 đến 4:
for (let i = 0; i < 5; i++) { // Bắt đầu từ 0, lặp đến khi nhỏ hơn 5
console.log(`Lần lặp thứ: ${i}`); // In ra giá trị hiện tại của i
}
console.log("Đã kết thúc vòng lặp");
🔹 3. Ứng dụng for trong automation
Khi bạn muốn thử lại một thao tác đúng 3 lần, hoặc chạy qua một nhóm test case theo số thứ tự, for sẽ là lựa chọn tự nhiên nhất. Bạn kiểm soát được số vòng lặp và dễ chèn thêm logic kiểm tra ở từng lượt.
💻 Ví dụ retry đăng nhập tối đa 3 lần:
const soLanThuLaiToiDa = 3; // Chỉ cho phép thử lại tối đa 3 lần
let dangNhapThanhCong = false; // Giả lập trạng thái đăng nhập
for (let lanThu = 1; lanThu <= soLanThuLaiToiDa; lanThu++) {
console.log(`Đang thử đăng nhập lần thứ ${lanThu}`);
if (lanThu === 3) {
dangNhapThanhCong = true; // Giả lập rằng lần thử thứ 3 thành công
console.log("Đăng nhập thành công");
break; // Thành công rồi thì thoát ngay khỏi vòng lặp
}
console.log("Thất bại, chuẩn bị thử lại...");
}
console.log(`Kết quả cuối cùng: ${dangNhapThanhCong}`);
🔹 4. Hiểu rõ break và continue
Hai từ khóa này rất quan trọng khi làm việc với vòng lặp:
break: dừng hẳn vòng lặp ngay lập tức.continue: bỏ qua phần còn lại của lần lặp hiện tại và nhảy sang lần tiếp theo.
💻 Ví dụ dùng break để dừng sớm:
for (let testNumber = 1; testNumber <= 5; testNumber++) {
console.log(`Đang kiểm tra test case #${testNumber}`);
if (testNumber === 3) {
console.log("Đã tìm thấy lỗi nghiêm trọng, dừng toàn bộ vòng lặp");
break; // Dừng luôn, không chạy test case 4 và 5 nữa
}
}
💻 Ví dụ dùng continue để bỏ qua một lượt:
for (let testNumber = 1; testNumber <= 5; testNumber++) {
if (testNumber === 2) {
console.log(`Bỏ qua test case #${testNumber} vì đang bị disable`);
continue; // Bỏ qua phần code phía dưới của lần lặp này
}
console.log(`Đang chạy test case #${testNumber}`);
}
💡 Mẹo nhớ nhanh: Nếu biết trước số lần lặp, hãy nghĩ tới
fortrước. Nếu không biết trước số lần lặp và đang chờ một điều kiện, hãy nghĩ tớiwhile.
🧺 Phần 3: Làm việc với danh sách bằng mảng (array)
Mảng dùng để lưu một danh sách giá trị trong cùng một biến. Đây là cấu trúc rất quan trọng vì khi làm automation, bạn thường phải xử lý danh sách browser, danh sách test data, danh sách kết quả hoặc danh sách phần tử lấy từ UI.
🔹 1. Khởi tạo và truy cập phần tử trong mảng
Mảng được tạo bằng cặp dấu ngoặc vuông []. Mỗi phần tử trong mảng có một index, và index luôn bắt đầu từ 0.
💻 Cú pháp tạo mảng cơ bản:
const browsers = ["chrome", "firefox", "webkit"]; // Mảng chuỗi
const retryAttempts = [1, 2, 3]; // Mảng số
const errorMessages = []; // Mảng rỗng
💻 Cú pháp truy cập phần tử và độ dài mảng:
const browsers = ["chrome", "firefox", "webkit"];
console.log(browsers[0]); // "chrome" => phần tử đầu tiên có index 0
console.log(browsers[1]); // "firefox"
console.log(browsers.length); // 3 => độ dài của mảng
const lastBrowser = browsers[browsers.length - 1]; // Lấy phần tử cuối cùng
console.log(lastBrowser); // "webkit"
💻 Thay đổi phần tử trong mảng:
const browsers = ["chrome", "firefox", "webkit"];
browsers[1] = "edge"; // Thay phần tử tại index 1
console.log(browsers); // ["chrome", "edge", "webkit"]
⚠️ Lưu ý: Mảng khai báo bằng
constvẫn có thể thay đổi phần tử bên trong. Điềuconstngăn cản là gán lại cả biến, không phải chặn sửa nội dung bên trong mảng.
🔹 2. Thêm và xóa phần tử bằng push() và pop()
Đây là hai phương thức bạn sẽ dùng rất thường xuyên khi cần thêm dữ liệu mới vào cuối mảng hoặc bỏ phần tử cuối cùng ra khỏi mảng.
💻 Thêm phần tử bằng push():
const users = ["an", "binh"]; // Mảng ban đầu có 2 phần tử
users.push("chi"); // Thêm "chi" vào cuối mảng
console.log(users); // ["an", "binh", "chi"]
💻 Xóa phần tử cuối bằng pop():
const users = ["an", "binh", "chi"];
const userDaXoa = users.pop(); // Xóa phần tử cuối và trả nó về
console.log(userDaXoa); // "chi"
console.log(users); // ["an", "binh"]
🔄 Phần 4: Lặp qua mảng và xử lý dữ liệu danh sách
Sau khi có mảng, việc tiếp theo là lặp qua từng phần tử để xử lý. JavaScript có nhiều cách lặp khác nhau, và mỗi cách phù hợp với một kiểu tình huống riêng.
🔹 1. Dùng for khi cần kiểm soát tối đa
Vòng lặp for cổ điển phù hợp khi bạn cần:
- dùng
indextrực tiếp, - lặp ngược,
- nhảy bước,
- hoặc cần
breakvàcontinue.
💻 Ví dụ lặp ngược mảng bằng for:
const items = ["a", "b", "c"];
for (let i = items.length - 1; i >= 0; i--) { // Bắt đầu từ phần tử cuối
console.log(items[i]); // In lần lượt: c, b, a
}
🔹 2. Dùng forEach() khi muốn chạy qua tất cả phần tử
forEach() là phương thức có sẵn của mảng. Cú pháp của nó gọn và dễ đọc, nhưng nhược điểm quan trọng là không dừng sớm được bằng break hoặc continue.
💻 Ví dụ dùng forEach():
const menuItems = ["Home", "Products", "Contact"];
menuItems.forEach((item, index) => {
console.log(`Index ${index}: ${item}`); // Xử lý từng phần tử theo thứ tự
});
⚠️ Lưu ý:
forEach()gọn, nhưng không phải lựa chọn tốt khi bạn cần dừng sớm, cầncontinue, hoặc cần xử lý bất đồng bộ kiểuasync/await.
🔹 3. Dùng for...of như lựa chọn mặc định
for...of là cách lặp hiện đại, dễ đọc và cân bằng khá tốt giữa sự gọn gàng với khả năng kiểm soát. Trong đa số trường hợp làm automation, đây là lựa chọn rất đáng ưu tiên.
💻 Ví dụ dùng for...of để tìm và dừng sớm:
const userRoles = ["admin", "editor", "guest"];
for (const role of userRoles) {
console.log(`Đang kiểm tra vai trò: ${role}`);
if (role === "editor") {
console.log("Đã tìm thấy vai trò editor, dừng lại");
break; // for...of vẫn hỗ trợ break giống for cổ điển
}
}
💻 Cách lấy index trong for...of:
const browsers = ["chrome", "firefox", "webkit"];
for (const [index, browserName] of browsers.entries()) {
console.log(`Index: ${index}, Trình duyệt: ${browserName}`); // Lấy cả index và value
}
🔹 4. Khi nào dùng for, forEach() và for...of?
for: dùng khi cần kiểm soát tối đa, cần index, lặp ngược, hoặc cầnbreakvàcontinue.forEach(): dùng khi chỉ muốn chạy qua tất cả phần tử với cú pháp gọn và không cần dừng sớm.for...of: lựa chọn mặc định trong đa số tình huống vì dễ đọc và vẫn hỗ trợbreak,continue.
🔹 5. Các hàm mảng hay dùng: map(), filter(), includes(), find()
Đây là nhóm phương thức rất quan trọng vì chúng giúp bạn biến đổi dữ liệu, lọc danh sách, kiểm tra sự tồn tại hoặc tìm một phần tử cụ thể. Khi xử lý dữ liệu lấy từ UI hoặc API, bạn sẽ gặp nhóm này rất nhiều.
💻 Dùng map() để biến đổi dữ liệu:
const giaTienText = [" $15.50 ", "20 USD", " $ 9.99 "];
const giaTienNumber = giaTienText.map((gia) => {
const giaDaLamSach = gia.trim().replace("USD", "").replace("$", ""); // Làm sạch chuỗi giá
return parseFloat(giaDaLamSach); // Trả về số thực sau khi đã làm sạch
});
console.log(giaTienNumber); // [15.5, 20, 9.99]
💻 Dùng filter() để lọc dữ liệu:
const testStatuses = ["Passed", "Passed", "Failed", "Skipped", "Failed"];
const failedTests = testStatuses.filter((status) => {
return status === "Failed"; // Chỉ giữ lại các phần tử thỏa điều kiện
});
console.log(failedTests); // ["Failed", "Failed"]
💻 Dùng includes() để kiểm tra tồn tại:
const userPermissions = ["view", "edit", "comment"];
const canDelete = userPermissions.includes("delete"); // Kiểm tra xem quyền delete có tồn tại hay không
console.log(canDelete); // false
💻 Dùng find() để lấy phần tử đầu tiên thỏa điều kiện:
const browsers = ["chrome", "firefox", "edge"];
const foundBrowser = browsers.find((browser) => {
return browser === "firefox"; // Tìm phần tử đầu tiên khớp điều kiện
});
console.log(foundBrowser); // "firefox"
💡 Mẹo nhớ nhanh:
map()để biến đổi,filter()để lọc,includes()để hỏi “có hay không”, cònfind()để lấy ra phần tử đầu tiên phù hợp.
📇 Phần 5: Làm việc với dữ liệu có cấu trúc bằng object
Nếu mảng phù hợp để lưu danh sách, thì object phù hợp để lưu một thực thể có nhiều thuộc tính rõ nghĩa. Đây là cấu trúc cực kỳ quan trọng khi bạn làm việc với test data, config, API response hoặc các nhóm locator.
🔹 1. Object là gì và tạo object như thế nào?
Object lưu dữ liệu dưới dạng các cặp key: value. Khác với mảng, object không tập trung vào thứ tự phần tử mà tập trung vào ý nghĩa của từng thuộc tính.
💻 Cú pháp tạo object:
const user = {
name: "Sơn Tinh", // key là name, value là chuỗi
age: 3000, // key là age, value là số
address: "Núi Tản Viên",
isMarried: true,
skills: ["đẩy lùi lũ lụt", "xây núi", "săn bắn"] // value cũng có thể là một mảng
};
🔹 2. Truy cập thuộc tính bằng dấu chấm và ngoặc vuông
Có hai cách phổ biến để lấy giá trị từ object:
- Dot notation: cú pháp ngắn gọn, dễ đọc, dùng nhiều nhất.
- Bracket notation: dùng khi key có ký tự đặc biệt hoặc key nằm trong một biến khác.
💻 Truy cập thuộc tính bằng dot notation và bracket notation:
const user = {
name: "Sơn Tinh",
address: "Núi Tản Viên",
skills: ["đẩy lùi lũ lụt", "xây núi"]
};
console.log(user.name); // Lấy thuộc tính bằng dấu chấm
console.log(user.skills[0]); // Truy cập phần tử đầu tiên trong mảng skills
console.log(user["address"]); // Lấy thuộc tính bằng ngoặc vuông
💻 Khi key có ký tự đặc biệt:
const car = {
"serial-number": "ABC-123" // Key có dấu gạch ngang
};
console.log(car["serial-number"]); // Phải dùng ngoặc vuông
// console.log(car.serial-number); // Sai vì JavaScript hiểu thành phép trừ
🔹 3. Thêm, sửa và xóa thuộc tính của object
Object trong JavaScript là kiểu dữ liệu có thể thay đổi được. Bạn có thể sửa giá trị, thêm thuộc tính mới hoặc xóa thuộc tính không còn cần dùng.
💻 Thêm, sửa và xóa thuộc tính:
const user = {
name: "Sơn Tinh",
age: 3000,
isMarried: true
};
user.isMarried = false; // Sửa giá trị cũ
user.role = "admin"; // Thêm thuộc tính mới
delete user.age; // Xóa thuộc tính age khỏi object
console.log(user);
🔹 4. Các phương thức quan trọng của Object
JavaScript cung cấp sẵn một nhóm công cụ rất hữu ích để làm việc với object. Đây là những hàm bạn nên quen mặt từ sớm.
💻 Dùng Object.keys() để lấy danh sách key:
const testData = {
username: "standard_user",
password: "secret_sauce",
expectedUrl: "/inventory.html"
};
Object.keys(testData).forEach((key) => {
console.log(`${key}: ${testData[key]}`); // Dùng key để truy cập value tương ứng
});
💻 Dùng Object.values() để lấy danh sách value:
const loginPage = {
usernameInput: "#username",
passwordInput: "#password",
submitButton: "button[type='submit']"
};
const locators = Object.values(loginPage); // Lấy toàn bộ selector thành một mảng
console.log(locators);
💻 Dùng Object.entries() để lấy cả key và value:
const testConfig = {
browser: "chrome",
timeout: 5000,
headless: true
};
for (const [key, value] of Object.entries(testConfig)) {
console.log(`${key.toUpperCase()}: ${value}`); // Lặp qua từng cặp key-value
}
💻 Dùng Object.assign() để gộp object:
const defaultConfig = {
browser: "chrome",
timeout: 30000,
headless: true
};
const smokeTestConfig = {
timeout: 10000, // Ghi đè timeout mặc định
tags: "smoke"
};
const finalConfig = Object.assign({}, defaultConfig, smokeTestConfig); // Gộp hai object thành object mới
console.log(finalConfig);
⚠️ Lưu ý: Nếu nhiều object có cùng một key,
Object.assign()sẽ lấy giá trị của object đứng sau để ghi đè lên object đứng trước.
💻 Dùng hasOwnProperty() để kiểm tra key có tồn tại hay không:
const apiResponse = {
userId: 123,
status: "success"
};
if (apiResponse.hasOwnProperty("errorMessage")) {
console.log("FAIL: API trả về có trường lỗi");
} else {
console.log("PASS: API không trả về trường lỗi");
}
🔹 5. Ghi nhớ nhanh cho Tester
- Dùng
whilekhi chưa biết trước số lần lặp, nhưng luôn phải có giới hạn để tránh treo chương trình. - Dùng
forkhi biết khá rõ số lần lặp và cần kiểm soát mạnh. breaklà dừng hẳn vòng lặp, còncontinuelà bỏ qua lượt hiện tại.- Index của mảng luôn bắt đầu từ
0. for...ofnên là lựa chọn mặc định khi lặp qua mảng nếu bạn muốn code sạch và vẫn có thểbreak.forEach()gọn nhưng không phải lúc nào cũng phù hợp, nhất là khi cần dừng sớm.map(),filter(),includes(),find()là bộ hàm mảng rất đáng thuộc lòng.- Dùng object khi dữ liệu có ý nghĩa theo từng thuộc tính, thay vì nhét tất cả vào mảng.
- Dot notation dễ đọc hơn, nhưng bracket notation là bắt buộc khi key có ký tự đặc biệt.
✅ Kết luận: Bài 4 là bước chuyển rất quan trọng từ việc viết các câu lệnh đơn lẻ sang xử lý danh sách và dữ liệu có cấu trúc. Nếu nắm chắc while, for, mảng và object, bạn sẽ viết test gọn hơn, đọc dữ liệu tốt hơn và đi tiếp sang các bài thực hành phức tạp một cách dễ dàng hơn.
