·

Tiếng Việt: Frontend and UI testing

Frontend and UI testing

Trong tất cả các mảng domain-specific testing (kiểm thử theo lĩnh vực chuyên biệt), frontend và UI testing là nơi AI tạo ra khác biệt rõ rệt nhất mà bạn có thể cảm nhận ngay trong sprint đầu tiên áp dụng. Lý do rất thực tế: UI testing vừa tốn nhiều công sức tay chân nhất (chụp màn hình, so khớp pixel, dò từng breakpoint), vừa dễ bỏ sót nhất (accessibility, edge case trên Safari, layout vỡ ở màn hình 375px). Một QA lead có kinh nghiệm sẽ nói với bạn: viết test case cho một component "đơn giản" như Button hay Dropdown có thể tốn nửa ngày nếu làm đúng — phải cover đủ state, đủ breakpoint, đủ tiêu chí WCAG. AI không thay thế được sự tinh tế của con người khi đánh giá "cái này có đẹp không", nhưng nó rút ngắn phần lao động cơ bắp: sinh test case từ spec, phân loại hàng trăm visual diff, đối chiếu component với từng tiêu chí WCAG cụ thể — những việc lặp lại, có quy tắc rõ, và tốn thời gian.

Bài này đi sâu vào bốn năng lực cốt lõi: sinh test case UI từ design spec/wireframe, vận hành visual regression testing (kiểm thử hồi quy trực quan) có AI trợ giúp, chạy audit accessibility theo WCAG và nhận gợi ý khắc phục, và sinh scenario kiểm thử cross-browser/responsive. Đây là kiến thức bạn sẽ dùng hàng ngày nếu đang giữ vai trò Mid/Senior QA cho một sản phẩm có frontend phức tạp.

Làm thế nào để dùng AI sinh test case UI từ design spec và wireframe?

Ý tưởng nền tảng ở đây là "shift-left" thật sự: viết test case ngay khi có design spec, trước khi một dòng code frontend nào được viết ra. Điều này giúp bug được phát hiện ở giai đoạn rẻ nhất — khi còn là comment trên Figma — thay vì sau khi đã lên production. AI làm được việc này tốt vì nó có thể đọc spec (text, bảng thuộc tính, hoặc chính ảnh wireframe) và suy luận ra các trường hợp kiểm thử theo một cấu trúc nhất quán, thứ mà con người dễ làm không đều tay khi phải lặp lại cho hàng chục component.

Cần trích xuất gì từ design spec trước khi prompt

Sai lầm phổ biến nhất khi mới dùng AI cho việc này là dán nguyên một đường link Figma hoặc một đoạn mô tả sơ sài rồi bảo "sinh test case cho tôi". Kết quả là AI hallucinate (bịa ra) những test case chung chung, không bám sát thực tế component. Trước khi prompt, bạn cần tự trích xuất — hoặc yêu cầu AI trích xuất trước — các thông tin sau từ spec:

  • Các state của component: default, hover, focus-visible, active, disabled, loading, error, empty. Nhiều spec chỉ vẽ 2-3 state và ngầm định phần còn lại — đây chính là nơi bug hay lọt.
  • Breakpoint và kích thước: sm/md/lg, hoặc theo pixel cụ thể (320px, 768px, 1024px, 1440px). Ghi rõ component có tự co giãn (fluid) hay nhảy layout đột ngột tại breakpoint.
  • Design token: spacing, màu sắc (bao gồm mã hex/HSL và tỷ lệ contrast nếu spec có ghi), typography scale (font-size, line-height, font-weight).
  • Ràng buộc nội dung: giới hạn ký tự, quy tắc truncate (cắt "...") hay wrap, hành vi khi nội dung rỗng hoặc quá dài (ví dụ tên người dùng tiếng Đức dài hơn tiếng Anh 30-40%).
  • Rule hiển thị có điều kiện: ví dụ badge "New" chỉ hiện trong 7 ngày, nút CTA đổi label theo trạng thái đăng nhập.
  • Chú thích accessibility nếu có: aria-label, thứ tự focus, trong Figma Dev Mode nhiều team đã bắt đầu ghi annotation này trực tiếp trên frame.

Nếu spec thiếu một trong các mục trên, đừng để AI tự bịa — hãy liệt kê rõ "thông tin còn thiếu, cần hỏi lại designer" trong output. Đây là cách biến AI thành một trợ lý review spec, không chỉ là máy sinh test case.

Prompt: Generate test cases from a component spec

Dưới đây là một prompt mẫu đầy đủ bạn có thể copy và điều chỉnh, áp dụng cho một component Button:

Bạn là một Senior QA Engineer. Tôi cung cấp spec của component Button dưới đây.
Hãy sinh bộ test case đầy đủ, phân theo nhóm: Visual, Functional, Accessibility, Edge case.

SPEC:
- Component: Button
- Variants: primary, secondary, tertiary, destructive
- Sizes: sm (32px height), md (40px height), lg (48px height)
- States: default, hover, active, focus-visible, disabled, loading
- Slots: icon-left (optional), icon-right (optional), label (required, max 24 ký tự)
- Loading state: hiện spinner thay label, giữ nguyên width để tránh layout shift
- Disabled: opacity 40%, không nhận pointer event, không có focus-visible outline
- Focus-visible: outline 2px màu #2563EB, offset 2px
- Khi label bị truncate: hiển thị full text qua tooltip on hover

YÊU CẦU OUTPUT:
1. Trình bày dưới dạng bảng: | ID | Nhóm | Mô tả | Bước thực hiện | Kết quả mong đợi |
2. Với mỗi biến thể (variant x size x state), chỉ chọn tổ hợp có rủi ro cao nhất
   (không cần liệt kê hết combinatorial để tránh test case dư thừa).
3. Bắt buộc có ít nhất 3 test case Accessibility (keyboard navigation, screen reader
   label, focus order).
4. Bắt buộc có test case cho trường hợp label vượt quá 24 ký tự.
5. Liệt kê riêng phần "Thông tin spec còn thiếu, cần hỏi designer" nếu có.

Điểm quan trọng trong prompt này: bạn ép AI phải rút gọn tổ hợp (tránh combinatorial explosion — bùng nổ tổ hợp khi nhân variant x size x state ra hàng chục dòng vô nghĩa), và bắt nó tự khai báo thiếu sót thay vì im lặng bỏ qua.

Sinh test case từ wireframe dạng ảnh

Khi chưa có spec dạng text mà chỉ có ảnh wireframe (export từ Figma, hoặc ảnh chụp bảng vẽ tay), bạn tận dụng khả năng multimodal (đa phương thức — model đọc được cả ảnh) của các model như Claude hoặc GPT-4o. Quy trình thực tế:

  1. Export wireframe ra PNG/JPG với độ phân giải đủ rõ (tối thiểu 1440px chiều ngang cho desktop wireframe).
  2. Đính kèm ảnh vào prompt, mô tả ngắn gọn context (đây là màn hình gì, thuộc flow nào).
  3. Yêu cầu AI mô tả lại từng vùng trên màn hình bằng lời trước, để bạn xác nhận nó "nhìn" đúng — bước xác nhận này quan trọng, vì model có thể đọc sai vị trí một icon nhỏ hoặc nhầm lẫn hai nút trông giống nhau.

Ví dụ prompt kèm ảnh:

[Đính kèm ảnh wireframe màn hình "Checkout - Step 2: Payment"]

Đây là wireframe màn hình thanh toán bước 2. Hãy:
1. Mô tả từng khu vực trên màn hình theo thứ tự từ trên xuống, kèm chức năng suy luận được.
2. Với mỗi khu vực, sinh test case cho: hiển thị đúng, tương tác đúng, và các case lỗi
   (ví dụ: nhập sai số thẻ, hết hạn thẻ, mất kết nối khi submit).
3. Đánh dấu rõ những vùng mà chỉ nhìn wireframe không thể suy ra hành vi
   (ví dụ: không rõ có validate real-time hay chỉ validate khi submit) —
   liệt kê thành câu hỏi cần hỏi lại Product/Design.
4. Với vùng nhập liệu (input field), sinh riêng bộ test case boundary
   (độ dài tối thiểu/tối đa, ký tự đặc biệt, paste dữ liệu có khoảng trắng).

Cách làm này đặc biệt hữu ích ở giai đoạn discovery/refinement, khi QA tham gia review wireframe cùng BA và designer — AI giúp bạn hỏi đúng câu hỏi sớm hơn, thay vì đợi đến lúc code xong mới phát hiện flow chưa rõ.

Biến component documentation thành test suite

Nếu team đã có Storybook hoặc component doc dạng MDX với bảng props, đây là nguồn input sạch nhất để sinh test case, vì props table vốn đã có kiểu dữ liệu, giá trị mặc định, và mô tả. Cách làm:

  1. Copy bảng props từ Storybook doc hoặc file *.stories.tsx.
  2. Yêu cầu AI áp dụng kỹ thuật pairwise testing (kiểm thử theo cặp) để giảm số tổ hợp props cần test, vì nếu component có 6 props với 3-4 giá trị mỗi prop, test hết tổ hợp là bất khả thi.
  3. Yêu cầu AI xuất trực tiếp thành skeleton test file (Playwright Component Testing hoặc React Testing Library) để dev/QA automation chỉ cần điền assertion.

Ví dụ prompt:

Đây là props table của component <Select>:
- options: Array<{ label: string, value: string }> (required)
- multiple: boolean (default: false)
- disabled: boolean (default: false)
- searchable: boolean (default: false)
- maxSelectedItems: number (chỉ có ý nghĩa khi multiple=true, default: unlimited)
- error: string | null (default: null)

Hãy:
1. Dùng pairwise testing để chọn ra bộ tổ hợp props tối ưu (không cần full combinatorial),
   giải thích ngắn tại sao chọn từng tổ hợp.
2. Sinh test case cho tổ hợp "vô nghĩa" — ví dụ maxSelectedItems khi multiple=false —
   để xác nhận component xử lý đúng (ignore hay throw warning).
3. Xuất thành skeleton test file dùng @playwright/experimental-ct-react,
   để trống phần assertion cụ thể bằng comment TODO.

Mẹo: Đừng bao giờ prompt AI sinh test case từ một spec "trong đầu bạn" — luôn dán nguyên văn spec/props table/ảnh wireframe vào context. AI sinh test case tốt tỷ lệ thuận với độ cụ thể của input; input mơ hồ cho ra test case mơ hồ, và bạn sẽ mất nhiều thời gian sửa hơn là tự viết tay.

AI hỗ trợ visual regression testing hoạt động ra sao và làm sao diễn giải diff?

Visual regression testing giải quyết một loại bug mà unit test và API test không bao giờ bắt được: giao diện "chạy đúng logic" nhưng nhìn sai — margin lệch 4px, màu nền đổi nhầm token, icon bị vỡ layout khi text dài hơn dự kiến. Cái khó không nằm ở việc chụp ảnh so sánh — công nghệ đó đã chín từ lâu — mà nằm ở việc diễn giải diff: trong 300 điểm ảnh khác biệt được flag, bao nhiêu là bug thật, bao nhiêu là noise (do font rendering, anti-aliasing, hoặc do chính bạn cố ý sửa UI). AI xuất hiện đúng ở khâu triage này.

Quy trình visual regression

Quy trình chuẩn của visual regression testing gồm 5 bước, và hiểu rõ pipeline này là bắt buộc trước khi đưa AI vào:

  1. Capture baseline: chụp screenshot ở trạng thái được coi là "đúng" — thường chốt sau khi PR được approve và merge vào nhánh chính.
  2. Capture candidate: mỗi lần có PR mới hoặc build mới, chụp lại đúng những màn hình/component đó ở cùng viewport, cùng dữ liệu test.
  3. Diff engine so khớp: công cụ so hai ảnh bằng thuật toán pixel-diff thô hoặc thuật toán "nhận thức" (perceptual diffing) như SSIM (Structural Similarity Index) — SSIM ít nhạy cảm với khác biệt do anti-aliasing hơn so-khớp pixel từng điểm.
  4. Flag và review: mọi vùng vượt ngưỡng khác biệt được đánh dấu, hiển thị dạng overlay đỏ/xanh để người review nhìn ra vùng thay đổi.
  5. Approve hoặc reject: nếu thay đổi là chủ đích (feature mới), approve để nó trở thành baseline mới; nếu là lỗi, reject và tạo bug ticket.

Vấn đề thực tế: bước 4 và 5 là nơi tốn công nhất, vì một PR đổi 1 dòng CSS global (ví dụ đổi border-radius trong design token) có thể làm flag hàng trăm screenshot trên toàn site, dù bản chất chỉ là MỘT thay đổi.

Công cụ và điểm tích hợp

Bốn nhóm công cụ phổ biến nhất trong ngành hiện nay, mỗi nhóm có điểm mạnh riêng:

  • Percy (BrowserStack): tích hợp CI/CD dễ, UI review trực quan, hỗ trợ responsive snapshot nhiều viewport trong một lần chụp.
  • Chromatic: sinh ra riêng cho Storybook, rất mạnh khi team đã có component-driven development — mỗi story tự động thành một test visual.
  • Applitools Eyes: nổi bật với "Visual AI" — engine riêng có nhiều match level (Exact, Strict, Content, Layout) giúp giảm false positive khi nội dung động (ví dụ ngày giờ, tên người dùng) thay đổi nhưng layout không đổi.
  • Playwright (built-in): dùng expect(page).toHaveScreenshot(), không cần dịch vụ ngoài, phù hợp team muốn tự chủ hạ tầng, nhưng phải tự quản baseline trong git hoặc artifact storage.
  • BackstopJS, reg-suit: các lựa chọn self-hosted, mã nguồn mở, phù hợp khi không muốn phụ thuộc SaaS.

Điểm tích hợp quan trọng: pipeline này nên chạy ở PR check (block merge nếu có diff chưa approve), không nên chỉ chạy ở nightly build — vì càng phát hiện muộn, càng khó xác định PR nào gây ra thay đổi.

Tích hợp AI triage vào quy trình visual diff

Đây là nơi AI tạo giá trị rõ nhất. Khi một PR làm flag 80 screenshot, việc review tay từng cái để phân loại "noise" hay "bug thật" là cực kỳ tốn thời gian và dễ bỏ sót. Cách triển khai AI triage:

  1. Với mỗi diff được flag, lấy 3 ảnh: baseline, candidate, và ảnh diff-overlay (vùng highlight khác biệt).
  2. Đưa cả 3 ảnh vào một model có khả năng đọc ảnh, kèm theo mô tả PR (title, danh sách file thay đổi, nội dung commit message).
  3. Yêu cầu model phân loại diff vào một trong các nhóm: (a) noise do font-rendering/anti-aliasing, (b) thay đổi nội dung động không phải bug (ngày giờ, avatar random), (c) thay đổi có chủ đích khớp với PR, (d) khả năng là bug thật — cần người review kỹ.
  4. Chỉ đưa nhóm (d) — và một mẫu ngẫu nhiên của nhóm (c) để kiểm chứng — cho con người review tay.

Applitools Eyes đã tích hợp một phần năng lực này sẵn trong "Visual AI" của họ, nhưng nếu bạn dùng Percy/Playwright thuần, bạn có thể tự build lớp triage này bằng một script gọi API model bên ngoài pipeline diff.

Viết prompt setup visual test có AI hỗ trợ

Việc setup ban đầu — quyết định chụp gì, ở viewport nào, mask vùng nào — cũng có thể nhờ AI sinh code. Ví dụ prompt để sinh cấu hình Playwright:

Tôi cần viết Playwright visual regression test cho trang Product Listing.
Yêu cầu:
1. Chụp screenshot ở 3 viewport: 375x812 (mobile), 768x1024 (tablet), 1440x900 (desktop).
2. Mask các vùng nội dung động sau (không so khớp pixel trong vùng này):
   - Banner khuyến mãi (data-testid="promo-banner") vì nội dung xoay theo A/B test
   - Giá sản phẩm (data-testid="product-price") vì môi trường staging có dữ liệu giá random
   - Timestamp "Cập nhật lúc..." ở footer
3. Chờ tất cả ảnh sản phẩm load xong (network idle) trước khi chụp, timeout 5s.
4. Đặt threshold pixel-diff là 0.1% để tránh false positive do font anti-aliasing
   giữa các lần chạy CI khác runner.
5. Output: file playwright.config.ts cập nhật project "visual", và file
   product-listing.visual.spec.ts đầy đủ.

Việc khai báo rõ vùng cần mask ngay từ đầu giúp giảm đáng kể số lượng false positive về sau — đây cũng là bước dễ bị bỏ qua nhất khi team mới setup visual regression.

Diễn giải regression AI flag so với thay đổi có chủ đích

Kỹ năng quan trọng nhất của một Senior QA trong visual regression không phải là chạy tool, mà là ra quyết định approve/reject nhanh và đúng. AI giúp bạn ở bước tổng hợp: khi một PR làm thay đổi 40 screenshot cùng lúc, thay vì click qua từng ảnh, bạn có thể yêu cầu AI:

Đây là danh sách 40 diff được flag từ PR #482 "Update spacing token cho Card component".
[Đính kèm bảng: tên screenshot, % pixel thay đổi, vùng thay đổi theo tọa độ]

Hãy:
1. Nhóm các diff có cùng nguyên nhân gốc (root cause) lại với nhau.
2. Với mỗi nhóm, giải thích ngắn gọn nguyên nhân có khớp với mô tả PR không.
3. Đánh dấu riêng các diff KHÔNG khớp với mô tả PR (ví dụ: PR chỉ đổi spacing Card
   nhưng có diff xảy ra ở Header — đây là dấu hiệu regression ngoài ý muốn).
4. Đề xuất: nhóm nào nên approve theo lô, nhóm nào cần escalate cho dev kiểm tra riêng.

Cách làm này biến việc review 40 ảnh riêng lẻ thành việc review 3-4 "cụm nguyên nhân" — nhanh hơn nhiều và ít bỏ sót hơn vì bạn không bị mỏi mắt khi lướt qua ảnh thứ 35.

Mẹo: Luôn giữ lại lịch sử approve/reject kèm lý do (comment ngắn) trong tool visual regression. Khi feed lại lịch sử này cho AI ở lần triage sau, model học được "pattern" của riêng team bạn — ví dụ team bạn luôn coi thay đổi dưới 0.05% ở vùng shadow là noise — và triage sẽ ngày càng chính xác hơn theo thời gian.

Làm thế nào để chạy audit accessibility theo WCAG và nhận gợi ý khắc phục với AI?

Accessibility (khả năng truy cập — đảm bảo người dùng khuyết tật thị giác, vận động, thính giác vẫn dùng được sản phẩm) là mảng dễ bị QA bỏ quên nhất, một phần vì kiến thức về WCAG (Web Content Accessibility Guidelines — bộ tiêu chuẩn quốc tế về khả năng truy cập web) khá chuyên sâu, một phần vì việc test bằng screen reader thật (NVDA, JAWS, VoiceOver) tốn thời gian và ít QA được train kỹ. AI không thay thế hoàn toàn việc test bằng assistive technology thật, nhưng nó thu hẹp khoảng cách rất nhiều — cả về tốc độ audit và về việc "dịch" lỗi kỹ thuật thành hướng khắc phục cụ thể.

Cách tiếp cận accessibility testing 3 lớp

Cách tiếp cận đúng đắn không phải chọn một công cụ duy nhất, mà là kết hợp ba lớp, vì mỗi lớp bắt được một loại lỗi khác nhau:

  • Lớp 1 — Automated scanning: dùng axe-core, Lighthouse, hoặc WAVE để quét DOM tự động. Lớp này nhanh, rẻ, chạy được trong CI, nhưng theo nghiên cứu của Deque (đơn vị phát triển axe-core), automated scan chỉ phát hiện được khoảng 30-40% tổng số vấn đề accessibility thực tế — nó bắt tốt lỗi cấu trúc (thiếu alt text, contrast không đủ, thiếu label) nhưng không đánh giá được ngữ nghĩa hay trải nghiệm thực tế.
  • Lớp 2 — AI-assisted semantic review: đây là lớp AI tạo giá trị mới. Đưa DOM/HTML và ảnh chụp màn hình cho AI, yêu cầu nó suy luận về những vấn đề mà máy scan không bắt được: thứ tự focus có hợp lý về ngữ nghĩa không, thông báo lỗi có đủ ngữ cảnh khi đọc bằng screen reader không, tải nhận thức (cognitive load) của flow có quá phức tạp không.
  • Lớp 3 — Verification bằng assistive technology thật: vẫn cần con người thật ngồi test bằng NVDA/JAWS/VoiceOver, đặc biệt cho các flow quan trọng (checkout, đăng ký). AI có thể giúp bạn viết trước script/checklist thao tác để việc test lớp 3 có hệ thống, không phải "mò".

Ba lớp này bổ trợ nhau: lớp 1 rẻ và nhanh nên chạy mọi PR; lớp 2 chạy khi review component mới hoặc trước major release; lớp 3 chạy định kỳ cho các flow quan trọng nhất.

Prompt: WCAG audit of a component

Ví dụ audit một component Modal (hộp thoại) bằng cách đưa HTML thực tế cho AI:

Bạn là chuyên gia accessibility, audit theo chuẩn WCAG 2.2 mức AA.
Dưới đây là HTML render thực tế của component Modal xác nhận xóa:

<div class="modal-overlay">
  <div class="modal">
    <h3>Xác nhận xóa</h3>
    <p>Bạn có chắc muốn xóa mục này? Hành động không thể hoàn tác.</p>
    <button class="btn-cancel">Hủy</button>
    <button class="btn-confirm">Xóa</button>
  </div>
</div>

Hãy audit và với mỗi vấn đề tìm thấy, trả về theo format:
| Tiêu chí WCAG (số + tên) | Mức độ nghiêm trọng | Vấn đề | Vì sao vi phạm | Cách khắc phục |

Đặc biệt kiểm tra các tiêu chí sau (nhưng không giới hạn):
- 1.3.1 Info and Relationships (có dùng role="dialog", aria-modal chưa)
- 2.1.2 No Keyboard Trap (focus có bị trap đúng trong modal không, Esc có đóng được không)
- 2.4.3 Focus Order (khi mở modal, focus có chuyển vào modal không; khi đóng,
  focus có trả về đúng phần tử đã mở modal không)
- 2.4.7 Focus Visible
- 4.1.2 Name, Role, Value (modal có aria-labelledby trỏ đúng heading không)

Prompt này hiệu quả vì nó ép AI trích dẫn đúng số tiêu chí WCAG cụ thể — tránh việc AI trả lời chung chung "component thiếu accessibility" mà không actionable.

Dùng kết quả axe làm input cho AI

axe-core trả về output dạng JSON có cấu trúc rõ (rule id, impact, các node vi phạm, help URL). Đưa nguyên JSON này cho AI để nó làm ba việc: gộp nhóm lỗi trùng lặp, sắp xếp theo độ nghiêm trọng thực tế (không chỉ theo "impact" mặc định của axe mà theo tần suất xuất hiện trên site), và viết lại thành ticket dễ hiểu cho dev không chuyên accessibility.

Đây là kết quả axe-core scan trên trang /checkout (rút gọn):

{
  "violations": [
    {
      "id": "color-contrast",
      "impact": "serious",
      "help": "Elements must meet minimum color contrast ratio thresholds",
      "nodes": [
        { "html": "<span class='price-label'>Tổng cộng</span>", "target": [".price-label"] }
      ]
    },
    {
      "id": "label",
      "impact": "critical",
      "help": "Form elements must have labels",
      "nodes": [
        { "html": "<input type='text' name='promo-code'>", "target": ["input[name='promo-code']"] }
      ]
    }
  ]
}

Hãy:
1. Gộp các violation trùng nguyên nhân gốc (nếu 10 input đều thiếu label do
   cùng thiếu 1 component wrapper, coi là 1 ticket kỹ thuật, không phải 10).
2. Sắp lại độ ưu tiên theo: tiêu chí nào ảnh hưởng đến luồng thanh toán
   (revenue-critical) thì ưu tiên cao nhất, bất kể "impact" gốc của axe.
3. Viết mỗi ticket theo format: Title, Mô tả cho dev, WCAG criteria liên quan,
   Steps to reproduce, Suggested fix (kèm code snippet).

Sinh code khắc phục đạt chuẩn WCAG

Sau khi có ticket, bước tiếp theo là sinh code khắc phục. Đây là ví dụ với input field thiếu label ở trên:

Component input hiện tại:
<input type="text" name="promo-code" placeholder="Nhập mã giảm giá">

Hãy sửa để đạt WCAG 2.2 AA, yêu cầu:
- Có label thực sự liên kết qua for/id (không dùng placeholder làm label)
- Label không bị ẩn hoàn toàn nếu dùng visually-hidden (để screen reader vẫn đọc được)
- Có aria-describedby trỏ tới đoạn hướng dẫn định dạng mã (nếu có)
- Giữ nguyên class CSS hiện có để không phá layout, chỉ thêm/sửa attribute cần thiết
- Giải thích ngắn từng thay đổi và trích tiêu chí WCAG tương ứng

Lưu ý quan trọng: luôn yêu cầu AI giải thích lý do cho mỗi thay đổi và trích tiêu chí cụ thể — điều này giúp bạn (QA) verify lại được thay đổi có đúng thật không, thay vì tin mù vào code AI sinh ra.

Sinh test case accessibility

Ngoài audit code có sẵn, bạn cũng cần sinh test case accessibility ngay từ đầu, tương tự cách sinh test case UI ở phần 1 nhưng tập trung vào các trục sau: điều hướng chỉ bằng keyboard (Tab, Shift+Tab, Enter, Esc, phím mũi tên với component dạng list/menu), nội dung được screen reader công bố (announcement) khi trạng thái thay đổi động, hành vi khi zoom 200% hoặc scale text lớn, và hành vi khi user bật "reduced motion".

Sinh bộ test case accessibility cho component Dropdown menu (kiểu combobox),
gồm các nhóm:
1. Keyboard-only: mở bằng Enter/Space, di chuyển bằng mũi tên lên/xuống,
   chọn bằng Enter, đóng bằng Esc, Tab ra ngoài phải đóng dropdown.
2. Screen reader announcement: khi mở dropdown, có announce số lượng option
   không; khi chọn 1 option, có announce giá trị đã chọn không.
3. Zoom 200%: dropdown có bị cắt/overflow ra ngoài viewport không.
4. prefers-reduced-motion: animation mở/đóng có tắt khi user bật setting này không.
Trình bày dạng bảng: ID, Nhóm, Bước thực hiện, Kết quả mong đợi, Công cụ verify
(ví dụ: NVDA + Chrome, hoặc chỉ cần DevTools).

Xây baseline accessibility regression

Vấn đề thường gặp khi mới bật axe-core scan trong CI: site cũ đã có sẵn hàng trăm violation tồn đọng, nếu fail build ngay theo toàn bộ debt đó thì không ai merge được gì. Cách làm đúng là xây baseline: snapshot toàn bộ violation hiện tại, chỉ fail CI khi có violation MỚI phát sinh so với baseline, và có kế hoạch giảm dần debt cũ theo từng sprint.

Viết một Playwright test wrapper dùng @axe-core/playwright, với logic:
1. Chạy axe scan trên trang được test.
2. So kết quả với file baseline JSON đã lưu (accessibility-baseline.json),
   baseline này liệt kê các violation "đã biết, chưa fix" theo rule id + CSS selector.
3. Nếu có violation MỚI không nằm trong baseline -> fail test, in ra chi tiết.
4. Nếu violation trong baseline đã KHÔNG còn xuất hiện (đã được fix) ->
   in cảnh báo "có thể xóa khỏi baseline" để dọn dẹp dần, không fail test.
5. Output: file accessibility.spec.ts và script update-baseline.ts để dev
   chạy khi cố ý muốn cập nhật baseline.

Mẹo: Không đưa cả một trang lớn cho AI audit một lần — hãy audit theo từng component riêng biệt trước (isolated trong Storybook nếu có), vì HTML của cả trang thường vượt context window (kích thước tối đa AI đọc được trong một lần) và AI sẽ bỏ sót vấn đề ở phần bị cắt. Audit từng component xong rồi mới audit lại luồng tổng thể (page-level) cho các vấn đề liên quan đến focus order xuyên component.

Làm thế nào để dùng AI sinh kịch bản test cross-browser và responsive layout?

Cross-browser testing (kiểm thử đa trình duyệt) và responsive testing (kiểm thử đáp ứng đa kích thước màn hình) là hai mảng mà chi phí kiểm thử tay tăng theo cấp số nhân — mỗi trình duyệt thêm vào, mỗi breakpoint thêm vào, đều nhân số case cần chạy. AI giúp bạn ở hai việc: quyết định nên test tổ hợp nào (vì test hết tất cả là bất khả thi), và sinh sẵn code test cho các tổ hợp đã chọn.

Xây ma trận cross-browser test với AI

Ma trận cross-browser đúng đắn không phải "test hết mọi trình duyệt có thể" mà là ưu tiên theo dữ liệu thực tế người dùng của bạn. Cách làm:

Tôi có dữ liệu phân bổ browser/OS của user thực tế (lấy từ Google Analytics,
30 ngày gần nhất) cho sản phẩm thương mại điện tử:
- Chrome (Windows): 42%
- Safari (iOS): 28%
- Chrome (Android): 15%
- Safari (macOS): 8%
- Edge (Windows): 4%
- Firefox: 2%
- Còn lại: 1%

Ngân sách CI chỉ cho phép chạy tối đa 8 tổ hợp browser x viewport mỗi lần build.
Hãy đề xuất ma trận 8 tổ hợp, ưu tiên theo % user thực tế NHƯNG đảm bảo:
- Có ít nhất 1 tổ hợp mobile Safari (iOS) vì đây là nền tảng khó debug nhất
  khi lỗi xảy ra trên production.
- Có ít nhất 1 tổ hợp ở viewport nhỏ nhất phổ biến (kiểm tra iPhone SE 375px).
- Giải thích rõ tổ hợp nào bị loại và rủi ro nếu bug chỉ xảy ra ở tổ hợp đó.

Việc này đặc biệt hữu ích khi làm việc với BrowserStack, LambdaTest, hay Sauce Labs — các nền tảng cho phép chạy song song nhiều tổ hợp nhưng tính phí theo số session, nên chọn đúng tổ hợp giúp tiết kiệm ngân sách đáng kể.

Sinh kịch bản test responsive layout

Responsive testing không chỉ là "co giãn màn hình xem có vỡ không" — cần scenario có hệ thống hơn, bao gồm cả các trục dễ bị bỏ quên: đổi orientation (xoay ngang/dọc), container query (khi component tự responsive theo kích thước container cha, không theo viewport), và nội dung dài hơn dự kiến khi dịch sang ngôn ngữ khác.

Component: Card sản phẩm, hiển thị trong grid 1-2-4 cột theo breakpoint
(1 cột <768px, 2 cột 768-1279px, 4 cột >=1280px).

Sinh scenario test responsive, bao gồm:
1. Test tại đúng breakpoint và tại điểm biên +-1px (767px, 768px, 769px)
   để bắt lỗi off-by-one trong media query.
2. Test khi xoay orientation trên tablet (768px landscape vs 1024px portrait
   - đây có thể trùng breakpoint nhưng layout cần khác nhau).
3. Test khi tên sản phẩm dài bất thường (giả lập chuỗi tiếng Đức 60 ký tự)
   - kiểm tra card có giữ chiều cao đều nhau trong 1 row không.
4. Test container query nếu Card được nhúng trong sidebar hẹp (300px)
   dù viewport là desktop lớn.
Trình bày dạng bảng test case kèm viewport/điều kiện cụ thể.

Sinh test Playwright cho kịch bản cross-browser

Sau khi có ma trận và scenario, bước sinh code test là nơi AI tiết kiệm thời gian rõ nhất — vì cấu hình Playwright cho nhiều project (browser/viewport) khá lặp lại và dễ viết sai.

Viết playwright.config.ts với các project sau, dùng devices có sẵn của Playwright
khi phù hợp:
- desktop-chrome: Desktop Chrome, viewport 1440x900
- desktop-firefox: Desktop Firefox, viewport 1440x900
- mobile-safari: dùng device "iPhone 13"
- mobile-chrome: dùng device "Pixel 5"
- tablet-safari: dùng device "iPad (gen 7)"

Sau đó viết 1 file test product-card.spec.ts, dùng test.describe.configure
để chạy song song, kiểm tra:
- Card render đủ số lượng item mong đợi theo layout hiện tại
- Ảnh sản phẩm load thành công (không bị lỗi broken image) trên tất cả project
- Nút "Thêm vào giỏ" nằm trong viewport, không bị cắt (dùng
  expect(locator).toBeInViewport())

Xác định edge case CSS đặc thù trình duyệt với AI

Một số lỗi CSS chỉ xảy ra trên một trình duyệt cụ thể và rất khó nhận ra nếu chỉ nhìn code — cần kiến thức về browser engine (WebKit, Gecko, Blink) khác biệt thế nào. AI được train trên lượng lớn tài liệu MDN/Can I Use nên khá hữu ích để review trước khi bug thật sự xảy ra:

Review đoạn CSS sau, chỉ ra các rủi ro tương thích trình duyệt cụ thể
(đặc biệt Safari và các phiên bản trình duyệt cũ hơn 2 năm), với mỗi rủi ro
đề xuất fallback hoặc polyfill:

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}
.card {
  aspect-ratio: 4 / 3;
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
}

Với đoạn CSS này, AI thường sẽ chỉ ra các điểm cần lưu ý thực tế: gap trong grid được hỗ trợ rộng nhưng từng có hạn chế ở Safari cũ; backdrop-filter cần tiền tố -webkit- trên nhiều phiên bản Safari; position: sticky trong bảng (<table>) có hành vi khác nhau giữa các engine; aspect-ratio kết hợp với ảnh dùng object-fit cần kiểm tra kỹ vì có thể tính toán khác nhau khi ảnh chưa load xong. Bạn vẫn cần verify lại bằng caniuse.com hoặc test thật, vì kiến thức của model có thể không theo kịp bản cập nhật trình duyệt mới nhất — nhưng nó giúp bạn không phải tự nhớ hết những caveat này.

Tự động diff visual cross-browser

Bước cuối là kết hợp visual regression (đã nói ở phần 2) với ma trận cross-browser: chạy cùng một trang trên tất cả trình duyệt trong ma trận, chụp screenshot, rồi diff không chỉ so với baseline mà còn so sánh CHÉO giữa các trình duyệt với nhau để lộ ra sự khác biệt rendering.

Tôi có 5 screenshot của cùng trang Product Detail, chụp trên 5 project
(desktop-chrome, desktop-firefox, mobile-safari, mobile-chrome, tablet-safari).

Hãy so sánh chéo (không so với baseline, so giữa các browser với nhau) và:
1. Xác định vùng nào khác biệt CHỈ trên 1 trình duyệt cụ thể (dấu hiệu bug
   đặc thù browser đó) so với vùng khác biệt do chính kích thước viewport
   (không phải bug, là hành vi responsive đúng).
2. Với vùng nghi là bug đặc thù trình duyệt, gợi ý nguyên nhân kỹ thuật khả dĩ
   (font rendering, CSS property chưa hỗ trợ, khác biệt box model).
3. Ưu tiên theo mức ảnh hưởng: vùng nào nằm trong luồng thanh toán/CTA chính
   được coi là nghiêm trọng hơn vùng trang trí (decorative).

Việc so sánh chéo giữa các trình duyệt (thay vì chỉ so với baseline của riêng từng trình duyệt) là kỹ thuật ít người làm nhưng rất hiệu quả để lộ ra những lỗi rendering đặc thù mà bạn sẽ không bao giờ thấy nếu chỉ nhìn từng trình duyệt riêng lẻ theo thời gian.

Mẹo: Khi ma trận cross-browser của bạn lớn hơn 6-8 tổ hợp, đừng chạy full matrix ở mọi PR — dùng AI để phân loại PR theo mức rủi ro cross-browser (PR chỉ đổi text/copy thì rủi ro thấp, PR đổi CSS layout hoặc dùng API browser mới thì rủi ro cao) và chỉ chạy full matrix cho nhóm rủi ro cao, còn lại chạy tập rút gọn (1-2 tổ hợp đại diện) để tiết kiệm thời gian CI mà vẫn giữ được lưới an toàn.