NỘI DUNG BÀI HỌC

✅ Kỹ thuật Lấy Dữ liệu: Hiểu rõ và sử dụng hiệu quả .textContent(), .innerText(), .getAttribute(), .inputValue(), .allTextContents(), và xử lý Strict Mode.

✅ Khẳng định Giá trị Tức thời: Nắm vững các expect thông thường (toBe, toEqual, toContain, toHaveLength, objectContaining, arrayContaining) để kiểm tra dữ liệu.



Phần 1:📝 Lấy Dữ liệu từ Phần tử

Khi bạn đã tìm thấy một phần tử bằng locator, Playwright cung cấp nhiều cách để "đọc" thông tin bên trong nó. Việc chọn đúng phương thức rất quan trọng để lấy được chính xác dữ liệu bạn cần.

1. .textContent() 📄

Lấy gì? Lấy nội dung text thô của một phần tử và tất cả con cháu của nó, nối thành một chuỗi duy nhất.

Đặc điểm:

Bao gồm cả text ẩn: Sẽ lấy cả text của các phần tử bị ẩn bởi CSS (display: none).

Không có định dạng: Chỉ ghép các đoạn text lại, không thêm khoảng trắng hay xuống dòng giữa các thẻ.

Tuân thủ Strict Mode: Sẽ báo lỗi nếu locator khớp nhiều hơn một phần tử (trừ khi bạn dùng .first()/.nth()).

Khi nào dùng? Khi bạn cần dữ liệu text gốc, không cần định dạng, để xử lý logic (ví dụ: trích xuất ID, số liệu). Không nên dùng để khẳng định trực tiếp.

Ví dụ:

HTML

<div id="data">Mã: <span>ABC-123</span> <span style="display:none;">Internal</span></div>

const dataDiv = page.locator('#data');

const rawText = await dataDiv.textContent();

// rawText = "Mã: ABC-123 Internal"

console.log(rawText);

 

2. .innerText() 👀

Lấy gì? Cố gắng lấy nội dung text như người dùng nhìn thấy trên trang đã được render.

Đặc điểm:

Tôn trọng CSS: Bỏ qua text của các phần tử bị ẩn (display: none, visibility: hidden).

Giữ lại Định dạng (một phần): Cố gắng giữ lại các dấu xuống dòng và khoảng trắng hợp lý giữa các khối văn bản.

Chậm hơn textContent(): Vì cần tính toán layout.

Tuân thủ Strict Mode: Sẽ báo lỗi nếu locator khớp nhiều hơn một phần tử.

Khi nào dùng? Khi bạn muốn lấy text gần giống nhất với những gì hiển thị cho người dùng (ví dụ: để ghi log). Tuy nhiên, để khẳng định, expect().toHaveText() thường tốt hơn.

Ví dụ: (Dùng lại HTML trên)

const dataDiv = page.locator('#data');

const visibleText = await dataDiv.innerText();

// visibleText = "Mã: ABC-123" (bỏ qua "Internal")

console.log(visibleText);

 

3 .innerHTML()

Lấy gì? Lấy toàn bộ chuỗi mã HTML nằm bên trong phần tử được chọn.

Đặc điểm: Trả về mã HTML thô, bao gồm cả các thẻ con. Tuân thủ Strict Mode.

Khi nào dùng? Hiếm khi cần thiết. Hữu ích khi cần kiểm tra cấu trúc HTML động hoặc nội dung từ trình soạn thảo WYSIWYG.

Ví dụ:

HTML

<div id="content"><p>Hello <strong>World</strong></p></div>

const contentDiv = page.locator('#content');

const innerHtmlContent = await contentDiv.innerHTML();

// innerHtmlContent = '<p>Hello <strong>World</strong></p>'

console.log(innerHtmlContent);

 

4. 📎 .getAttribute(attributeName)

Lấy gì? Lấy giá trị của một thuộc tính HTML cụ thể (ví dụ: href, src, data-id, value ban đầu, class, id).

Đặc điểm: Trả về giá trị dưới dạng chuỗi (string) hoặc null nếu thuộc tính không tồn tại. Tuân thủ Strict Mode.

Khi nào dùng? Cực kỳ hữu ích để lấy các liên kết, nguồn ảnh, ID dữ liệu, hoặc giá trị ban đầu của input.

Ví dụ:

HTML

<a id="myLink" href="/profile" data-user-id="123">Hồ sơ</a>

const myLink = page.locator('#myLink');

const linkUrl = await myLink.getAttribute('href');     // "/profile"

const userId = await myLink.getAttribute('data-user-id'); // "123"

const classAttr = await myLink.getAttribute('class');   // null (vì không có class)

console.log(`URL: ${linkUrl}, User ID: ${userId}, Class: ${classAttr}`);


5. 🏷️ .inputValue()

Lấy gì? Lấy giá trị hiện tại của các phần tử form như <input>, <textarea>, <select>.

Đặc điểm: Phản ánh giá trị sau khi người dùng đã tương tác, khác với getAttribute('value') chỉ lấy giá trị ban đầu trong HTML. Tuân thủ Strict Mode.

Khi nào dùng? Để kiểm tra xem người dùng đã nhập đúng dữ liệu vào form chưa, hoặc lựa chọn hiện tại của dropdown là gì.

Ví dụ:

HTML

<input type="text" id="username" value="initial">

const usernameInput = page.locator('#username');

console.log(await usernameInput.inputValue()); // "initial"

await usernameInput.fill('new_value');

console.log(await usernameInput.inputValue()); // "new_value"

 

6. 📜 .allTextContents() / .allInnerTexts()

Lấy gì? Dùng khi locator của bạn khớp với nhiều phần tử. Chúng trả về một mảng (array) các chuỗi text.

allTextContents(): Lấy textContent của từng phần tử.

allInnerTexts(): Lấy innerText của từng phần tử.

Đặc điểm: Không bị Strict Mode violation vì chúng được thiết kế để làm việc với nhiều phần tử.

Khi nào dùng? Khi bạn cần lấy nội dung của tất cả các mục trong một danh sách, các kết quả tìm kiếm, v.v.

Ví dụ:

HTML

<ul><li>Táo</li><li>Cam</li></ul>

const listItems = page.locator('ul > li');

const allTexts = await listItems.allInnerTexts();

// allTexts = ['Táo', 'Cam']

console.log(allTexts);

 

💡 Lời khuyên Quan trọng

Để khẳng định (assert) text/thuộc tính: Hãy ưu tiên dùng Web-First Assertions (expect(locator).toHaveText(), expect(locator).toHaveAttribute(), expect(locator).toHaveValue()). Chúng có auto-waiting tích hợp sẵn, giúp test ổn định hơn.

Để lấy dữ liệu xử lý: Dùng các phương thức .textContent(), .innerText(), .getAttribute(), .inputValue()... khi bạn thực sự cần giá trị đó cho các bước logic tiếp theo. Hãy nhớ xử lý Strict Mode bằng cách dùng .first(), .nth(), hoặc làm locator cụ thể hơn.

Phần 2: Khẳng định Giá trị Tức thời với expect Thông thường

Đây là những lệnh expect bạn sẽ dùng để so sánh các giá trị đã biết, giống như trong các thư viện test JavaScript khác như Jest.

Nhóm expect này hoạt động ngay lập tứckhông liên quan đến việc chờ đợi các yếu tố trên giao diện web.

 1. .toBe(value) ✨ - So sánh Bằng Tuyệt đối (===)

Kiểm tra: So sánh nghiêm ngặt (strict equality), giống hệt toán tử === trong JavaScript. Nó kiểm tra cả giá trị và kiểu dữ liệu.

Dùng cho: Các kiểu dữ liệu nguyên thủy (primitive types) như string, number, boolean, null, undefined, symbol. Không dùng để so sánh object hay array.

Phép so sánh: "Cái này có chính xác là cái kia không?" (Cùng một vật thể).

Ví dụ:

test('sử dụng .toBe()', () => {

  const name: string = 'Playwright';

  const version: number = 1.4;

  const isActive: boolean = true;

  const nothing: null = null;

  expect(name).toBe('Playwright'); // ✅ PASS

  expect(version).toBe(1.4);       // ✅ PASS

  expect(isActive).toBe(true);      // ✅ PASS

  expect(nothing).toBe(null);      // ✅ PASS




  // ❌ FAIL: '1.4' (string) không giống hệt 1.4 (number)

  // expect(version).toBe('1.4');

});


2 .toEqual(value) 🧑‍🤝‍🧑 - So sánh "Sâu" Nội dung

Kiểm tra: So sánh giá trị nội dung của các object hoặc array. Nó sẽ đi sâu vào bên trong và kiểm tra từng thuộc tính hoặc phần tử.

Dùng cho: object, array.

Phép so sánh: "Hai cái hộp này có chứa đúng những thứ giống hệt nhau bên trong không?" (Không quan tâm chúng có phải là cùng một cái hộp hay không).

Ví dụ:

test('sử dụng .toEqual()', () => {

  const user1 = { id: 1, name: 'A', roles: ['admin'] };

  const user2 = { id: 1, name: 'A', roles: ['admin'] };

  const user3 = { id: 2, name: 'B', roles: ['user'] };

  const arr1 = [1, 2, { a: 3 }];

  const arr2 = [1, 2, { a: 3 }];

  // ✅ PASS: Nội dung giống hệt

  expect(user1).toEqual(user2);

  expect(arr1).toEqual(arr2);


  // ❌ FAIL: .toBe() sẽ thất bại vì chúng là 2 object/array khác nhau trong bộ nhớ

  // expect(user1).toBe(user2);

  // expect(arr1).toBe(arr2);

  // ❌ FAIL: Nội dung khác nhau

  // expect(user1).toEqual(user3);

});

 

3. .toContain(item) / .toContainEqual(item) 🔍 - Kiểm tra "Có Chứa"

Kiểm tra: Một mảng (array) hoặc chuỗi (string) có chứa một phần tử/chuỗi con cụ thể hay không.

Dùng cho: array, string.

.toContain(item): Dùng === để so sánh các phần tử nguyên thủy trong mảng.

.toContainEqual(item): Dùng so sánh "sâu" (toEqual) khi bạn muốn kiểm tra sự tồn tại của một object trong mảng.

Phép so sánh: "Trong cái túi này có chứa 'quả táo' không?"

Ví dụ:

test('sử dụng .toContain() và .toContainEqual()', () => {

  const permissions: string[] = ['read', 'write', 'delete'];

  const users: { id: number; name: string }[] = [{ id: 1, name: 'A' }, { id: 2, name: 'B' }];

  // ✅ PASS

  expect(permissions).toContain('write');

  expect('Hello Playwright').toContain('Play');

  // ✅ PASS: Kiểm tra object trong mảng

  expect(users).toContainEqual({ id: 2, name: 'B' });

  // ❌ FAIL: 'execute' không có trong mảng

  // expect(permissions).toContain('execute');


  // ❌ FAIL: .toContain không so sánh sâu object

  // expect(users).toContain({ id: 2, name: 'B' });

});


### 4. .toBeTruthy() / .toBeFalsy() 👍👎 - Kiểm tra "Tính Đúng/Sai"

Kiểm tra: Một giá trị có được coi là "truthy" (đúng) hay "falsy" (sai) trong ngữ cảnh boolean của JavaScript.

Truthy values: Bất cứ thứ gì không phải là falsy (ví dụ: true, số khác 0, chuỗi không rỗng, object, array).

Falsy values: false, 0, "" (chuỗi rỗng), null, undefined, NaN.

Phép so sánh: "Cái này có được coi là 'có' hay 'không'?"

Ví dụ:

test('sử dụng .toBeTruthy() và .toBeFalsy()', () => {

  expect('hello').toBeTruthy(); // Chuỗi không rỗng là truthy

  expect(1).toBeTruthy();       // Số khác 0 là truthy

  expect({}).toBeTruthy();      // Object là truthy

  expect([]).toBeTruthy();      // Array là truthy


  expect('').toBeFalsy();       // Chuỗi rỗng là falsy

  expect(0).toBeFalsy();        // Số 0 là falsy

  expect(null).toBeFalsy();     // null là falsy

  expect(undefined).toBeFalsy();// undefined là falsy

  expect(NaN).toBeFalsy();      // NaN là falsy

});

 

5. .toBeGreaterThan() / .toBeLessThan() (và các biến thể) 📈📉 - So sánh Số học

Kiểm tra: So sánh các giá trị số.

Các biến thể:

.toBeGreaterThan(number) (>): Lớn hơn.

.toBeGreaterThanOrEqual(number) (>=): Lớn hơn hoặc bằng.

.toBeLessThan(number) (<): Nhỏ hơn.

.toBeLessThanOrEqual(number) (<=): Nhỏ hơn hoặc bằng.

Phép so sánh: Các phép so sánh toán học cơ bản.

Ví dụ:

test('sử dụng các so sánh số học', () => {

  const itemCount = 5;

  const totalPrice = 100.50;




  expect(itemCount).toBeGreaterThan(0);

  expect(itemCount).toBeLessThanOrEqual(5);

  expect(totalPrice).toBeGreaterThanOrEqual(100);

});

## Kết luận

Nhóm expect thông thường này là công cụ cơ bản để bạn xác minh tính đúng đắn của dữ liệu và logic bên trong kịch bản test của mình, sau khi bạn đã lấy được dữ liệu từ trang web hoặc thực hiện các phép tính. Hãy nhớ rằng chúng hoạt động tức thời và không có auto-waiting. Khi bạn cần chờ đợi và kiểm tra trạng thái của các phần tử trên trang, bạn sẽ cần đến nhóm "Web-First Assertions" mà chúng ta đã học.



Phần 3: Kiểm tra Object & Array với expect Thông thường


1. expect(object).toEqual(expectedObject) 🧑‍🤝‍🧑 - So sánh "Sâu" Nội dung Object

Kiểm tra: So sánh giá trị nội dung của hai đối tượng (object). Nó sẽ đi vào từng cặp key: value của cả hai object và so sánh chúng với nhau một cách đệ quy (so sánh cả các object/array lồng nhau bên trong).

Triết lý: "Hai cái hộp này có chứa đúng những thứ giống hệt nhau bên trong không?" (Không quan tâm chúng có phải là cùng một cái hộp hay không).

Khi nào dùng: Đây là matcher chính của bạn khi muốn khẳng định rằng một object trả về từ API hoặc được tạo ra trong code có đúng cấu trúc và dữ liệu mong đợi.

Ví dụ: Hãy kiểm tra một đối tượng movie.

test('should deeply compare movie objects using .toEqual()', () => {

  interface Movie {

    id: number;

    title: string;

    director: string;

    genres: string[];

  }
  const movieFromApi: Movie = {

    id: 101,

    title: "Inception",

    director: "Christopher Nolan",

    genres: ["Sci-Fi", "Thriller"]

  };

  const expectedMovieData: Movie = {

    id: 101,

    title: "Inception",

    director: "Christopher Nolan",

    genres: ["Sci-Fi", "Thriller"]

  };

  const anotherMovie: Movie = {

    id: 102,

    title: "Interstellar",

    director: "Christopher Nolan",

    genres: ["Sci-Fi", "Adventure"]

  };

  // ✅ PASS: Nội dung giống hệt, kể cả mảng genres lồng nhau.

  expect(movieFromApi).toEqual(expectedMovieData);

  // ❌ FAIL: .toBe() sẽ thất bại vì chúng là 2 object khác nhau trong bộ nhớ.

  // expect(movieFromApi).toBe(expectedMovieData);
  // ❌ FAIL: Nội dung khác nhau (id, title, genres).

  // expect(movieFromApi).toEqual(anotherMovie);

});

 

 

2. expect(object).toHaveProperty(keyPath, value?) 🔑 - Kiểm tra Thuộc tính

Kiểm tra: Sự tồn tại của một thuộc tính (key) trong object, và tùy chọn, kiểm tra cả giá trị của thuộc tính đó.

Triết lý: "Trong cái hộp này, có món đồ tên là 'X' không? Và giá trị của nó có phải là 'Y' không?"

Khi nào dùng: Khi bạn chỉ muốn kiểm tra một vài thuộc tính quan trọng của một object lớn, hoặc khi bạn muốn kiểm tra các thuộc tính lồng nhau mà không cần viết lại cả cấu trúc object.

keyPath (string): Tên thuộc tính. Bạn có thể dùng dấu chấm (.) để truy cập các thuộc tính lồng nhau (ví dụ: 'director.name').

value (any, tùy chọn): Giá trị mong đợi của thuộc tính. Nếu bỏ qua, nó chỉ kiểm tra sự tồn tại.

Ví dụ:

test('should check for properties using .toHaveProperty()', () => {

  const movie = {

    title: "The Dark Knight",

    details: {

      year: 2008,

      rating: 9.0

    },

    cast: ["Christian Bale", "Heath Ledger"]

  };
  // 1. Kiểm tra sự tồn tại của thuộc tính 'title'

  expect(movie).toHaveProperty('title');
  // 2. Kiểm tra sự tồn tại VÀ giá trị của 'title'

  expect(movie).toHaveProperty('title', 'The Dark Knight');

  // 3. Kiểm tra thuộc tính lồng nhau 'year'

  expect(movie).toHaveProperty('details.year');

  // 4. Kiểm tra giá trị của thuộc tính lồng nhau 'rating'

  expect(movie).toHaveProperty('details.rating', 9.0);

  // ❌ FAIL: Thuộc tính 'genre' không tồn tại

  // expect(movie).toHaveProperty('genre');

  // ❌ FAIL: Giá trị của 'year' không phải là 2010

  // expect(movie).toHaveProperty('details.year', 2010);

});


 3. expect(array).toHaveLength(number) #️⃣ - Kiểm tra Độ dài Mảng

Kiểm tra: Số lượng phần tử có trong một mảng (array).

Triết lý: "Trong cái túi này có chính xác bao nhiêu món đồ?"

Khi nào dùng: Cách đơn giản và rõ ràng nhất để khẳng định số lượng kết quả trả về, số lượng mục trong danh sách, v.v.

Ví dụ:

test('should check array length using .toHaveLength()', () => {

  const genres = ["Sci-Fi", "Thriller", "Action"];

  const emptyList: string[] = [];

  // ✅ PASS

  expect(genres).toHaveLength(3);
  // ✅ PASS

  expect(emptyList).toHaveLength(0);
  // ❌ FAIL: Mảng genres không có 4 phần tử

  // expect(genres).toHaveLength(4);

});

## Kết luận

Ba matcher này là những công cụ cơ bản nhưng cực kỳ quan trọng khi bạn cần làm việc với dữ liệu có cấu trúc trong các bài test của mình:

Dùng .toEqual() để so sánh toàn bộ nội dung của object hoặc array.

Dùng .toHaveProperty() để kiểm tra sự tồn tại hoặc giá trị của một thuộc tính cụ thể trong object.

Dùng .toHaveLength() để kiểm tra số lượng phần tử trong array.

Hãy nhớ rằng, chúng chỉ so sánh các giá trị đã có sẵn và không có cơ chế chờ đợi.

Phần 4:🔬  Kiểm tra "Sự có mặt" và So sánh "Một phần"

 1. expect(arrayOrString).toContain(item) 🔍 - Kiểm tra "Có Chứa" (Đơn giản)

Kiểm tra: Một mảng có chứa một phần tử cụ thể hay không, hoặc một chuỗi có chứa một chuỗi con hay không.

Triết lý: "Trong cái túi/chuỗi này có món đồ/chữ 'X' không?"

Cách so sánh:

Đối với mảng chứa giá trị nguyên thủy (string, number), nó dùng so sánh bằng (===).

Đối với chuỗi, nó kiểm tra chuỗi con.

Khi nào dùng: Khi bạn chỉ cần xác nhận sự hiện diện của một phần tử đơn giản trong mảng hoặc một chuỗi con.

Ví dụ:

test('sử dụng .toContain()', () => {

  const colors: string[] = ['đỏ', 'xanh lá', 'xanh dương'];

  const message: string = 'Playwright is awesome';
  // ✅ PASS: Mảng colors chứa 'xanh lá'

  expect(colors).toContain('xanh lá');

  // ✅ PASS: Chuỗi message chứa 'awesome'

  expect(message).toContain('awesome');

  // ❌ FAIL: Mảng không chứa 'vàng'

  // expect(colors).toContain('vàng');

  // Lưu ý: .toContain() không so sánh sâu object trong mảng

  const users = [{ id: 1 }, { id: 2 }];

  // ❌ FAIL: Mặc dù có object {id: 1}, .toContain không kiểm tra sâu

  // expect(users).toContain({ id: 1 });

  // => Dùng .toContainEqual() cho trường hợp này

  expect(users).toContainEqual({ id: 1 }); // ✅ PASS

});

 

2. Nâng cao: expect.objectContaining(object) 🧩 - So sánh "Một phần" Object

Kiểm tra: Một đối tượng có chứa ít nhất các cặp key: value được chỉ định trong expectedObject hay không. Nó bỏ qua các thuộc tính khác không được liệt kê.

Triết lý: "Cái hộp này có chứa ít nhất những món đồ quan trọng này không? Các món đồ khác tôi không quan tâm."

Khi nào dùng: Cực kỳ hữu ích khi kiểm tra một object lớn (ví dụ: response từ API) mà bạn chỉ quan tâm đến một vài thuộc tính cốt lõi và không muốn test bị lỗi nếu API thêm các thuộc tính mới trong tương lai.

Ví dụ:

test('sử dụng .objectContaining()', () => {

  const apiResponse = {

    userId: 'u-123',

    username: 'gemini',

    email: 'gemini@example.com',

    timestamp: '2025-10-25T...', // Giá trị này có thể thay đổi

    token: 'xyz...'             // Giá trị này cũng thay đổi

  };


  const essentialData = {

    userId: 'u-123',

    username: 'gemini'

  };

  // ✅ PASS: apiResponse chứa tất cả các key/value trong essentialData.

  // Nó bỏ qua timestamp và token.

  expect(apiResponse).toEqual(expect.objectContaining(essentialData));
  // Bạn cũng có thể dùng nó lồng nhau

  const complexResponse = { data: { user: apiResponse }, status: 'ok' };

  expect(complexResponse).toEqual(

    expect.objectContaining({

      status: 'ok',

      data: expect.objectContaining({ // Kiểm tra lồng nhau

        user: expect.objectContaining({ username: 'gemini' })

      })

    })

  );

  // ❌ FAIL: Thiếu thuộc tính userId hoặc giá trị sai

  // expect(apiResponse).toEqual(expect.objectContaining({ userId: 'u-456' }));

});

 

3. Nâng cao: expect.arrayContaining(array) 🧺 - So sánh "Một phần" Array (Không cần thứ tự)

Kiểm tra: Một mảng có chứa ít nhất tất cả các phần tử được chỉ định trong expectedArray hay không. Thứ tự các phần tử không quan trọng, và mảng thực tế có thể chứa nhiều phần tử hơn.

Triết lý: "Trong cái giỏ này có chứa ít nhất một quả táo và một quả cam không? Các loại quả khác hay thứ tự của chúng tôi không quan tâm."

Khi nào dùng: Khi bạn muốn xác nhận sự hiện diện của một tập hợp các giá trị quan trọng trong một mảng mà không cần quan tâm đến thứ tự hoặc các phần tử khác. Rất hữu ích khi kiểm tra các quyền hạn, các tag sản phẩm...

Ví dụ:

test('sử dụng .arrayContaining()', () => {

  const userPermissions = ['read', 'write', 'comment', 'delete'];

  const requiredPermissions = ['read', 'write']; // Chỉ cần có 2 quyền này

  const missingPermissions = ['read', 'admin'];   // Thiếu 'admin'

  // ✅ PASS: userPermissions chứa cả 'read' và 'write'.

  // Thứ tự và các quyền khác ('comment', 'delete') không quan trọng.

  expect(userPermissions).toEqual(expect.arrayContaining(requiredPermissions));

  // ✅ PASS: Thứ tự trong requiredPermissions không ảnh hưởng

  expect(userPermissions).toEqual(expect.arrayContaining(['write', 'read']));




  // ❌ FAIL: userPermissions không chứa 'admin'.

  // expect(userPermissions).toEqual(expect.arrayContaining(missingPermissions));

  // Lưu ý: Nó cũng hoạt động với object (so sánh sâu)

  const products = [{ id: 1, name: 'A' }, { id: 2, name: 'B' }, { id: 3, name: 'C' }];

  expect(products).toEqual(expect.arrayContaining([

    { id: 2, name: 'B' },

    { id: 1, name: 'A' } // Thứ tự không quan trọng

  ]));

});

## Kết luận

.toContain() / .toContainEqual(): Dùng để kiểm tra sự tồn tại của một phần tử đơn lẻ trong mảng/chuỗi.

.objectContaining(): Dùng để kiểm tra một object có chứa một tập hợp các thuộc tính hay không (bỏ qua các thuộc tính khác).

.arrayContaining(): Dùng để kiểm tra một mảng có chứa một tập hợp các phần tử hay không (bỏ qua các phần tử khác và thứ tự).

Hai công cụ nâng cao .objectContaining và .arrayContaining giúp các khẳng định của bạn trở nên linh hoạt và bền vững hơn rất nhiều, đặc biệt khi làm việc với các cấu trúc dữ liệu phức tạp hoặc dễ thay đổi.

Teacher

Teacher

Nguyên Hoàng

Automation Engineer

With 7+ years of hands-on experience across multiple languages and frameworks. I'm here to share knowledge, helping you turn complex processes into simple and effective solutions.

Cộng đồng Automation Testing Việt Nam:

🌱 Telegram Automation Testing:   Cộng đồng Automation Testing
🌱 
Facebook Group Automation: Cộng đồng Automation Testing Việt Nam
🌱 
Facebook Fanpage: Cộng đồng Automation Testing Việt Nam - Selenium
🌱 Telegram
Manual Testing:   Cộng đồng Manual Testing
🌱 
Facebook Group Manual: Cộng đồng Manual Testing Việt Nam

Chia sẻ khóa học lên trang

Bạn có thể đăng khóa học của chính bạn lên trang Anh Tester để kiếm tiền

Danh sách bài học