Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 56 — Mobile Web vs Native vs PWA Testing

Đã đọc 0/12 mục · còn khoảng 11 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Mở đầu — vì sao bài này quan trọng

Khi một khách hàng gõ tên thương hiệu của bạn vào điện thoại, họ có thể chạm vào ba "cửa" hoàn toàn khác nhau mà không hề hay biết: mở app đã cài trong máy, gõ URL vào trình duyệt Chrome/Safari, hoặc bấm vào một biểu tượng trông y hệt app nhưng thực chất là một trang web đã được "cài" lên màn hình chính. Ba hình thức này — Native app, Mobile web, và PWA (Progressive Web App) — nhìn từ ngoài thì giống nhau đến 80%, nhưng bên trong lại vận hành theo những cơ chế khác biệt sâu sắc. Và chính 20% khác biệt đó là nơi bug ẩn nấp.

Là một QA mobile, nếu bạn không phân biệt được mình đang test hình thức nào, bạn sẽ dễ mắc hai sai lầm chết người. Thứ nhất: áp một bộ test case Native lên một trang Mobile web (rồi ngơ ngác vì "app này sao không có màn hình cài đặt permission?"). Thứ hai: bỏ sót cả một tầng rủi ro riêng của PWA — thứ mà nhiều team Việt Nam vẫn tưởng "web thì test như web thôi" cho đến khi nó vỡ ngoài production.

Bài này giúp bạn dựng một bản đồ tư duy rõ ràng: mỗi hình thức là gì, chạy ở đâu, rủi ro đặc trưng nằm chỗ nào, và một bộ test case của bạn nên tách nhánh ra sao. Đây là kiến thức nền, nhưng là loại nền mà thiếu nó thì mọi kỹ thuật automation sau này đều dễ đặt sai chỗ.

Khái niệm cốt lõi

Ba hình thức — bản chất thật sự

Native app là ứng dụng được viết bằng ngôn ngữ/công cụ riêng của nền tảng (Swift/Kotlin, hoặc framework như React Native, Flutter), được cài đặt vào máy qua App Store / Google Play. Nó có mặt trong danh sách app, có biểu tượng, chạy trong "sandbox" riêng, truy cập trực tiếp phần cứng (camera, GPS, cảm biến vân tay), nhận push notification qua APNs/FCM, và tồn tại cả khi không có mạng.

Mobile web là trang web bình thường, người dùng mở bằng trình duyệt (Chrome, Safari, Cốc Cốc) qua một URL. Không cài đặt, không chiếm dung lượng máy, luôn là phiên bản mới nhất (deploy là dùng ngay). Nhưng nó bị "nhốt" trong trình duyệt: quyền truy cập phần cứng hạn chế, không có push notification kiểu native trên iOS Safari cho đến rất gần đây, và tắt mạng là gần như trắng màn hình.

PWA (Progressive Web App) là con lai. Về kỹ thuật nó vẫn là web (HTML/CSS/JS chạy trong engine trình duyệt), nhưng nhờ ba thành phần cốt lõi — Service Worker (một đoạn JS chạy nền, đứng giữa app và mạng để cache và xử lý offline), Web App Manifest (file JSON khai báo tên, icon, màu, chế độ hiển thị), và HTTPS bắt buộc — nó có thể được "Add to Home Screen" (cài lên màn hình chính), chạy toàn màn hình không thanh địa chỉ, hoạt động offline, và trên nhiều nền tảng còn nhận được push notification. Người dùng nhìn vào tưởng là Native app, nhưng nó không đi qua App Store.

Ma trận khác biệt mà QA cần nhớ

Cách tôi khuyên học viên ghi nhớ là dựng một bảng đối chiếu theo các trục rủi ro, thay vì học vẹt định nghĩa:

  • Cài đặt & cập nhật: Native đi qua store, có version cứng, người dùng có thể xài bản cũ (bạn phải test nhiều version). Mobile web luôn mới. PWA cập nhật qua Service Worker — và đây là cái bẫy lớn nhất: nội dung cũ có thể bị cache "dính" lại dù bạn đã deploy bản mới.
  • Offline: Native luôn có, Mobile web hầu như không, PWA có nhưng phụ thuộc hoàn toàn vào chiến lược cache của Service Worker.
  • Truy cập phần cứng: Native đầy đủ; Mobile web và PWA bị giới hạn theo API mà trình duyệt cho phép (và khác nhau giữa iOS Safari với Android Chrome).
  • Push notification: Native ổn định; PWA có nhưng iOS chỉ hỗ trợ từ iOS 16.4 trở lên và bắt buộc đã "Add to Home Screen"; Mobile web thuần thì gần như không.
  • Storage & vòng đời: Native có sandbox bền; web/PWA dùng LocalStorage, IndexedDB, Cache Storage — có thể bị hệ điều hành xoá khi máy thiếu dung lượng (đặc biệt iOS xoá dữ liệu web nếu không mở trong 7 ngày).
Hiểu ma trận này, bạn sẽ biết ngay: một bug "mất giỏ hàng khi offline" là chuyện bình thường với Mobile web, là bug nghiêm trọng với Native, và là bug về cấu hình Service Worker với PWA.

Tình huống thực tế

Tình huống 1 — Tiki và cái bẫy "3 mặt trận cùng một tính năng"

Giả định một sàn TMĐT lớn như Tiki tung khuyến mãi flash sale. Tính năng "đếm ngược 5 phút + tự động refresh giá" được PO mô tả trong một user story duy nhất. Team QA giao cho một bạn test và bạn ấy chỉ mở Native app để kiểm, thấy ổn, đóng ticket.

Ba ngày sau, bộ phận CSKH báo: rất nhiều khách vào bằng Mobile web (từ link chia sẻ Facebook, Zalo) thấy đồng hồ đếm ngược nhưng giá không tự cập nhật khi hết giờ — vì Mobile web không có cơ chế background refresh như app, phải reload trang. Tệ hơn, nhóm khách dùng PWA đã cài lên màn hình chính lại thấy giá cũ của đợt sale tuần trước, do Service Worker cache trang HTML quá "hung hăng".

Một story, ba hành vi khác nhau. Bài học: với tính năng cross-platform, QA phải hỏi ngay từ đầu "tính năng này chạy trên những hình thức nào?" và tách test case theo từng hình thức, đặc biệt là hành vi refresh/real-time. Đừng bao giờ giả định "test một cái là đủ cho cả ba".

Tình huống 2 — Ngân hàng số và bug Service Worker "ma ám"

Một ngân hàng số (kiểu Cake, Timo) triển khai PWA cho phân khúc khách hàng không muốn tải app nặng. Team deploy bản vá lỗi bảo mật cho form chuyển tiền lúc 2 giờ sáng. Sáng ra, một số khách hàng cài PWA vẫn thấy giao diện cũ — Service Worker cũ vẫn phục vụ file JS cache, và bản vá không có hiệu lực với họ.

QA đã bỏ sót vì họ test bản mới trên trình duyệt "sạch" (chưa từng cài PWA), nên Service Worker cũ không tồn tại và mọi thứ trông hoàn hảo. Vấn đề chỉ lộ ra trên máy đã cài phiên bản trước đó.

Bài học: với PWA, bạn phải test theo hai kịch bản: cài mới hoàn toàn và nâng cấp từ bản cũ đã cache. Test case bắt buộc phải có bước "kiểm tra Service Worker cập nhật đúng sau deploy" — thường là kiểm skipWaiting() được gọi, hoặc người dùng được nhắc reload. Đây là loại bug mà 90% team web mới chuyển sang PWA đều dính ít nhất một lần.

Tình huống 3 — Startup giao đồ ăn và permission camera "biến mất"

Một startup giao đồ ăn ở TP.HCM có tính năng "chụp ảnh món đã nhận để xác nhận". Trên Native app, luồng permission camera rõ ràng: bấm chụp → hệ thống hỏi quyền → cấp → mở camera. QA test đủ các case allow/deny/deny-forever.

Nhưng khi khách vào bằng Mobile web trên iOS Safari, camera mở được qua thẻ <input capture> nhưng không có luồng permission dai dẳng như native, và trên một số phiên bản Safari cũ tính năng chọn ảnh từ thư viện bị lỗi im lặng. QA vốn quen với luồng native đã không nghĩ tới việc camera trên web hoạt động qua cơ chế hoàn toàn khác (Web API, phụ thuộc trình duyệt), nên bỏ trống toàn bộ nhánh test này.

Bài học: các tính năng dùng phần cứng là nơi ba hình thức phân kỳ mạnh nhất. Đừng bê nguyên checklist permission của Native sang web — web có mô hình quyền riêng, mỏng hơn và phụ thuộc trình duyệt/OS. Luôn xác định "trên hình thức này, phần cứng được truy cập qua API nào?" trước khi viết test case.

Hướng dẫn từng bước

Đây là quy trình tôi khuyên áp dụng mỗi khi nhận một sản phẩm hoặc tính năng cần test cross-form:

Bước 1 — Xác định hình thức đang test. Đừng đoán. Hỏi dev hoặc tự kiểm: Có file manifest.json và Service Worker không? (mở DevTools → tab Application). Có nút "Thêm vào màn hình chính" xuất hiện không? App có trong store không? Ghi rõ vào test plan: đây là Native, Mobile web, hay PWA — hay cả ba.

Bước 2 — Dựng ma trận phạm vi. Lập bảng: hàng là tính năng, cột là ba hình thức. Đánh dấu ô nào cần test. Nhiều tính năng chỉ tồn tại ở một số hình thức (ví dụ push notification thường không có ở Mobile web thuần), tránh test thừa.

Bước 3 — Test phần "chung" trước, phần "riêng" sau. Logic nghiệp vụ (tính tiền, validate form) thường giống nhau — test một lượt. Sau đó tập trung vào phần đặc trưng: offline (PWA), cache/update (PWA), giới hạn phần cứng (web), đa version (Native).

Bước 4 — Với PWA, bắt buộc chạy checklist riêng: kiểm tra Add to Home Screen hoạt động, mở app từ icon có chạy standalone (không thanh địa chỉ) không, tắt mạng xem offline fallback đúng không, deploy bản mới rồi kiểm Service Worker cập nhật, và kiểm dữ liệu cache không "ăn" mất nội dung mới.

Bước 5 — Kiểm tra chuyển tiếp giữa các hình thức. Người dùng đăng nhập trên Mobile web rồi cài PWA — có phải đăng nhập lại không? Deep link từ web mở được app native không (nếu có cả hai)? Đây là vùng xám hay bị bỏ quên.

Bước 6 — Ghi rõ hình thức trong bug report. Mỗi bug phải kèm "reproduced on: Native/Mobile web/PWA + trình duyệt + OS version". Một bug đúng trên PWA nhưng không tồn tại trên Native là thông tin sống còn cho dev.

Lỗi thường gặp & mẹo

Lỗi 1 — Nhầm PWA là "web bình thường". Đây là lỗi phổ biến nhất. Team test PWA hệt như một trang web, bỏ qua toàn bộ tầng Service Worker/cache/offline. Mẹo: luôn mở DevTools → Application → Service Workers để nhìn thấy "trái tim" của PWA đang chạy gì.

Lỗi 2 — Test PWA trên trình duyệt sạch nên bỏ sót bug cache. Như tình huống ngân hàng. Mẹo: giữ một thiết bị/profile đã cài phiên bản cũ để test kịch bản nâng cấp; đừng lúc nào cũng "Clear storage".

Lỗi 3 — Áp checklist permission Native lên web. Web có mô hình quyền riêng. Mẹo: với mỗi tính năng phần cứng, tra xem Web API tương ứng có được iOS Safari và Android Chrome hỗ trợ không — hai trình duyệt này khác nhau đáng kể.

Lỗi 4 — Quên iOS là "vùng đặc biệt" của PWA. iOS hỗ trợ PWA hạn chế hơn Android: push chỉ từ iOS 16.4+, storage bị xoá sau 7 ngày không dùng, một số API bị chặn. Mẹo: luôn có ít nhất một thiết bị iOS thật trong ma trận test PWA, đừng chỉ dựa vào Android.

Lỗi 5 — Không test trạng thái offline có chủ đích. Nhiều bug PWA chỉ lộ khi mất mạng giữa chừng. Mẹo: dùng chế độ "Offline" trong DevTools hoặc bật máy bay giữa một thao tác đang chạy, xem app xử lý ra sao — hiện fallback đẹp hay treo trắng.

Mẹo tổng quát: khi nghi ngờ một hành vi thuộc về hình thức nào, hãy hỏi "cái này chạy ở đâu — trong máy, trong trình duyệt, hay trong Service Worker?". Trả lời được câu đó là bạn đã khoanh vùng được nửa cái bug.

Bài tập thực hành

  • Lập ma trận sản phẩm. Chọn một sản phẩm bạn hay dùng có cả app lẫn web (ví dụ Shopee, Grab, Tiki). Xác định họ có PWA không (mở web trên Chrome, xem có gợi ý "Cài đặt" không, kiểm DevTools → Application). Lập bảng 3 cột (Native / Mobile web / PWA) và liệt kê 5 tính năng, đánh dấu mỗi tính năng có mặt ở hình thức nào.
  • Săn bug cache PWA. Tìm một PWA bất kỳ, cài lên màn hình chính, dùng vài lần. Vào DevTools → Application → Cache Storage xem nó cache những gì. Bật chế độ Offline và thử dùng — ghi lại tính năng nào còn chạy, tính năng nào chết.
  • So sánh luồng permission. Với cùng một tính năng (ví dụ chụp ảnh hoặc lấy vị trí), thử trên app native và trên web mobile của cùng sản phẩm. Ghi lại điểm khác nhau trong cách hệ thống hỏi quyền và xử lý khi từ chối.
  • Viết test case tách nhánh. Chọn một user story đơn giản (ví dụ "đăng nhập") và viết bộ test case có phần chung + phần riêng cho từng hình thức, trong đó ít nhất PWA phải có case về offline và cập nhật Service Worker.

Tóm tắt

Ba hình thức — Native app (cài đặt, mạnh nhất, đa version), Mobile web (mở qua trình duyệt, luôn mới, giới hạn phần cứng, yếu offline), và PWA (con lai cài được, offline nhờ Service Worker, nhưng dễ dính bug cache/cập nhật) — nhìn giống nhau nhưng vận hành trên ba cơ chế khác biệt. Là QA, việc đầu tiên khi nhận sản phẩm là xác định đúng hình thức, sau đó dựng ma trận phạm vi để test phần chung một lần và phần riêng theo từng nhánh rủi ro đặc trưng: đa version với Native, giới hạn phần cứng với Mobile web, và Service Worker/cache/offline với PWA. Đặc biệt cảnh giác với PWA — luôn test cả kịch bản cài mới lẫn nâng cấp từ bản cũ, luôn có thiết bị iOS thật, và luôn ghi rõ hình thức trong mọi bug report. Nắm chắc sự phân biệt này, bạn sẽ không bao giờ áp nhầm checklist hay bỏ sót cả một tầng rủi ro nữa.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi