page.pause() & page.on('console') (Debug nhanh và bắt log trình duyệt)
automationplaywright
page.pause() là 'breakpoint mềm' dừng test và mở Inspector ngay tại dòng đó; page.on('console') / page.on('pageerror') lắng nghe mọi log và lỗi JS mà trang phát ra — bộ đôi giúp bắt lỗi frontend mà assertion UI không thấy được.
Khái niệm & Bản chất
page.pause()tạm dừng thực thi và mở Playwright Inspector tại đúng điểm đó — debug giữa chừng mà không cần PWDEBUG chạy lại từ đầu.page.on('console')bắt mọiconsole.log/warn/errorcủa trang trong browser — khác hẳn console của Node process đang chạy test.page.on('pageerror')bắt uncaught exception trên trang — lỗi JS làm tính năng chết âm thầm mà UI test vẫn có thể xanh.- Đây là cặp debug 'nhanh và bẩn': chèn vài dòng là thấy ngay trang đang nói gì, đang lỗi gì — không cần setup phức tạp.
Cách hoạt động & API chính
await page.pause()— dừng tại dòng, điều khiển tiếp bằng Inspector (Resume / Step Over / Pick Locator).page.on('console', msg => ...):msg.type()trả'log' | 'error' | 'warning' | 'info'...,msg.text()lấy nội dung,msg.location()biết log bắn từ file/dòng nào.page.on('pageerror', err => ...):errlà Error thật của trang, cómessagevàstackđầy đủ.- Họ event liên quan:
page.on('requestfailed')bắt request hỏng,page.on('response')soi mọi response — kết hợp là thấy cả lỗi JS lẫn lỗi API. - Listener phải gắn trước hành động gây ra log (đặc biệt trước
goto) — log bắn trong lúc load trang sẽ bị lỡ nếu gắn sau.
Ví dụ & Cú pháp thực tế
- Forward console trang ra terminal, chỉ lọc lỗi:
``
ts test('soi lỗi trang', async ({ page }) => { // Gắn TRƯỚC goto để không lỡ log lúc load page.on('console', msg => { if (msg.type() === 'error') { console.log('[PAGE CONSOLE]', msg.text()); } }); page.on('pageerror', err => console.log('[UNCAUGHT]', err.message)); await page.goto('/cart'); await page.pause(); // dừng soi DOM/locator tại đây await page.getByRole('button', { name: 'Thanh toán' }).click(); });`` - Pattern kinh điển: assert 'trang không có JS error':
``
ts test('trang chủ không có lỗi JS', async ({ page }) => { const errors: string[] = []; page.on('pageerror', err => errors.push(err.message)); await page.goto('/'); await page.getByRole('link', { name: 'Khoá học' }).click(); // App bắn uncaught error → test fail, kèm message expect(errors,Trang có JS error: ${errors.join(' | ')}).toEqual([]); });`` - Bắt cả lỗi API trong cùng một test:
``
ts test('checkout không lỗi API', async ({ page }) => { const badResponses: string[] = []; page.on('response', res => { if (res.status() >= 500) badResponses.push(${res.status()} ${res.url()}); }); await page.goto('/checkout'); // ... thao tác expect(badResponses).toEqual([]); });``
Best practices & Khi nào dùng
- Test fail do hành vi app lạ (không phải locator): forward console ra terminal trước — phần lớn sẽ thấy ngay API lỗi hoặc JS exception giấu kín.
- Dùng pattern 'collect
pageerrorrồiexpect(errors).toEqual([])' làm smoke check cho trang quan trọng — bắt lỗi mà UI assertion bỏ sót. - Đặt
page.pause()ngay trước action nghi ngờ — đỡ phải PWDEBUG rồi step từ đầu test. - Listener lặp lại ở nhiều test → gom vào fixture/helper dùng chung (vd
autoFixturesgắn pageerror collector cho mọi test).
Gotchas, So sánh & Lưu ý
page.pause()trên CI/headless là no-op — không treo pipeline, nhưng vẫn nên xoá sau khi debug xong để code sạch.pageerrorchỉ bắt uncaught error — lỗi đã bị apptry/catch(vd API fail đã xử lý) không hiện; phối hợp thêmconsole errorhoặcresponselistener.- Forward toàn bộ console không lọc → output cực rối; nên chỉ lấy
type === 'error'hoặc gom vào mảng rồi assert cuối test. - Khác mở DevTools bằng tay: listener bắt được log ngay cả khi headless và assert tự động trên log — đây là lợi thế automation so với debug tay.
- Đừng biến 'assert không có console error' thành rule cứng cho mọi trang — nhiều app có warning/error vô hại từ third-party, cần whitelist hợp lý.
