Episode ini membahas skenario browser tingkat lanjut: handling frames, popups, dan multiple tabs, drag and drop serta aksi keyboard dan mouse, otomasi upload dan download file, serta network interception dan request mocking untuk mengendalikan respons.

Test end-to-end yang hanya mengeklik tombol dan mengisi form akan cepat menemui batas. Aplikasi nyata memakai iframe, membuka popup, melibatkan drag and drop, upload file, dan berkomunikasi dengan server yang kadang tidak bisa diandalkan. Episode 8 ini membahas aksi-aksi tingkat lanjut yang membuka skenario tersebut.
Kemampuan ini membedakan test suite yang sekadar jalan dari suite yang benar-benar menguji aplikasi secara menyeluruh. Kalian akan belajar mengendalikan elemen di dalam frame, menangani jendela baru, mensimulasikan input kompleks, mengotomasi file, dan mengendalikan respons jaringan seolah-olah kalian adalah proxy di antara aplikasi dan servernya.
Elemen di dalam iframe tidak bisa diakses langsung dari page. Playwright menyediakan page.frameLocator() yang menghasilkan locator yang beroperasi di dalam frame:
const frame = page.frameLocator('#iframe-pembayaran');
await frame.getByLabel('Nomor Kartu').fill('4111111111111111');
await frame.getByRole('button', { name: 'Bayar' }).click();page.frameLocator('#iframe-pembayaran') mengembalikan locator yang scoping ke frame tertentu. Untuk menangani frame yang tidak diketahui sebelumnya, gunakan page.frames() untuk mendaftar semua frame yang ada dan memilih sesuai kebutuhan.
Popup adalah halaman baru yang terbuka dari halaman induk. Jangan menunggu langsung dengan page.waitForEvent setelah aksi — pasang listener lebih dulu untuk menghindari race condition:
const popupPromise = page.waitForEvent('popup');
await page.getByRole('link', { name: 'Buka Kebijakan' }).click();
const popup = await popupPromise;
await popup.getByRole('heading').waitFor();page.waitForEvent('popup') mengembalikan promise yang selesai saat popup terbuka. Setelah popup didapat, aksi bisa diarahkan ke instance page baru tersebut sepenuhnya terpisah dari halaman induk.
Context memungkinkan membuka beberapa tab dan berpindah di antara mereka. page.bringToFront() membuat tab tertentu menjadi aktif:
const page2 = await context.newPage();
await page2.goto('https://example.com');
await page2.bringToFront();Memakai context.newPage() menciptakan tab baru dalam context yang sama — tab-tab ini berbagi session storage dan cookies. Cocok untuk menguji alur yang melibatkan beberapa tab sekaligus.
Ada dua cara drag and drop: melalui method khusus atau via aksi mouse manual:
await page.getByRole('listitem', { name: 'Item 1' }).dragTo(
page.getByRole('listitem', { name: 'Target' })
);dragTo() menangani urutan mouse down, move, dan up secara otomatis. Jika aplikasi membutuhkan kontrol yang lebih presisi, pakai page.mouse secara manual.
Untuk skenario khusus, aksi keyboard dan mouse bisa dikendalikan penuh:
await page.getByRole('textbox').press('Control+a');
await page.keyboard.type('teks baru');
await page.mouse.move(100, 200);
await page.mouse.down();
await page.mouse.move(300, 400);
await page.mouse.up();page.keyboard.type('teks baru') mengetik dengan kecepatan default, sementara page.mouse memberi kendali koordinat piksel untuk drag manual yang rumit.
Upload bisa dilakukan dengan setInputFiles pada input file, atau dengan payload buffer untuk skenario yang membutuhkan fleksibilitas:
await page.getByLabel('Upload Dokumen').setInputFiles('laporan.pdf');
await expect(page.getByText('laporan.pdf')).toBeVisible();setInputFiles('laporan.pdf') menerima path lokal. Playwright juga mendukung objek buffer untuk membuat file langsung dari memori, berguna saat data uji dibuat dinamis.
Untuk menangkap download, pasang event listener sebelum memicu unduhan:
const downloadPromise = page.waitForEvent('download');
await page.getByRole('button', { name: 'Unduh Laporan' }).click();
const download = await downloadPromise;
await download.saveAs('./artifacts/laporan.pdf');download.saveAs('./artifacts/laporan.pdf') menyimpan file yang diunduh ke lokasi yang ditentukan. Kalian bisa memeriksa download.suggestedFilename() untuk validasi nama file.
Dengan page.route, kalian bisa mengarahkan request ke mock, memblokir request tertentu, atau memodifikasinya:
await page.route('**/api/produk/**', (route) => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([{ id: 1, nama: 'Produk Mock' }]),
});
});page.route('**/api/produk/**', handler) mencegat semua request yang cocok pola URL. Di dalam handler, route.fulfill(...) mengembalikan respons buatan tanpa benar-benar menghubungi server.
Untuk mempercepat test, blokir request aset yang tidak relevan seperti font atau analytics:
await page.route('**/analytics.js', (route) => route.abort());
await page.route('**/*.woff2', (route) => route.abort());route.abort() membatalkan request sehingga browser tidak mengunduh resource itu. Ini mengurangi noise jaringan dan mempercepat eksekusi test pada aplikasi yang berat dengan tracking script.
npx playwright test tests/aksi-lanjutan.spec.tsPerintah npx playwright test tests/aksi-lanjutan.spec.ts menjalankan test yang memakai teknik di atas. Saat kombinasi frame, popup, dan network mocking dipakai bersama, trace viewer menjadi teman terbaik untuk memverifikasi urutan aksi.
Episode 8 memperluas jangkauan test kalian ke skenario yang selama ini terasa sulit: elemen dalam iframe dan popup, beberapa tab sekaligus, drag and drop serta aksi keyboard dan mouse yang presisi, upload dan download file, serta network interception dan request mocking untuk mengendalikan respons server.
Inti yang harus dibawa pulang:
frameLocator menargetkan elemen di dalam iframe tanpa keluar dari API locator.dragTo, page.keyboard, dan page.mouse melayani berbagai tingkat presisi.setInputFiles dan waitForEvent('download') mengotomasi pertukaran file.page.route memungkinkan mock, modifikasi, dan pemblokiran request.Di episode 9 selanjutnya kita akan membahas data-driven dan parameterized testing — parameterized test dengan test.each, sumber data eksternal seperti CSV dan JSON, menjalankan skenario yang sama dengan banyak dataset, serta best practice untuk coverage yang dapat diulang.