Episode ini membahas interaksi lanjutan: handling iframes, popups, dan multiple windows, drag and drop, uploads, keyboard events, testing single-page apps dengan konten dinamis, serta network stubbing dengan cy.intercept.

Test mulai diuji saat aplikasi punya hal-hal rumit: iframe dari pihak ketiga, popup, window baru, drag and drop, upload file, dan konten yang berubah dinamis. Episode 8 memandu kalian menghadapi skenario itu satu per satu dengan teknik yang benar.
Ini adalah episode paling berbau "pekerjaan nyata" sejauh ini. Setelah menguasainya, jarang ada interaksi web yang tidak bisa kalian otomasi.
Konten di dalam iframe terpisah dari DOM utama. Untuk iframe dari domain yang sama, akses langsung lewat cy.iframe() dari plugin cypress-iframe, atau seleksi manual dengan cy.get("iframe"). Untuk iframe lintas domain, gunakan cy.origin() yang tersedia sejak Cypress 12:
cy.origin("https://auth.example.com", () => {
cy.get("[data-cy=login-oauth]").click();
});cy.origin("https://auth.example.com", () => { ... }) memungkinkan Cypress menjalankan perintah di dalam konteks domain lain — mengatasi batasan "satu domain per test" yang lama. Perhatikan bahwa argumen dan variabel yang dipakai dari luar harus dikirim eksplisit lewat parameter fungsi.
Popup dan window baru adalah tantangan klasik. Kunci utamanya: jangan bergantung pada tab browser baru. Sebagai gantinya, tangkap window.open dan periksa URL-nya:
cy.window().then((win) => {
cy.stub(win, "open").as("openWindow");
});
cy.get("[data-cy=link-dokumentasi]").click();
cy.get("@openWindow").should("be.calledWith", "/docs");cy.stub(win, "open").as("openWindow") menggantikan fungsi window.open dengan stub yang bisa di-assert. Alih-alih pindah ke tab baru yang sulit dikontrol, test memverifikasi bahwa aplikasi memang memanggil open dengan URL yang benar.
Drag and drop di browser menembakkan event sequence. Cara paling andal memakai .trigger() untuk meniru urutan event:
cy.get("[data-cy=item]").trigger("dragstart");
cy.get("[data-cy=dropzone]").trigger("drop");cy.trigger("dragstart") dan cy.trigger("drop") membangkitkan event DOM secara langsung. Untuk library drag-and-drop tertentu yang butuh koordinat, kombinasikan dengan .trigger("dragstart", { clientX: 0, clientY: 0 }) lalu .trigger("drop", { clientX: 200, clientY: 200 }).
cy.selectFile memungkinkan upload file nyata tanpa plugin tambahan:
cy.get("[data-cy=input-avatar]").selectFile("cypress/fixtures/avatar.png");
cy.contains("Avatar terunggah").should("be.visible");cy.selectFile("cypress/fixtures/avatar.png") menempelkan file ke input upload dan memicu event perubahan. Siapkan file contoh di folder fixtures agar test tidak bergantung pada file pengembang.
Untuk aksi papan ketik seperti shortcut:
cy.get("[data-cy=editor]").type("{ctrl}s");
cy.contains("Tersimpan").should("be.visible");cy.type("{ctrl}s") menekan kombinasi tombol. Sintaks seperti {enter}, {esc}, {backspace}, dan {shift}tab tersedia untuk kebutuhan lain.
SPA (single-page app) merender konten secara dinamis tanpa reload halaman penuh. Ini menguntungkan: state halaman relatif stabil. Yang perlu diperhatikan adalah elemen yang muncul bergantian — spinner, skeleton, dan konten yang diganti.
cy.intercept("GET", "/api/produk").as("produk");
cy.get("[data-cy=tab-terbaru]").click();
cy.wait("@produk");
cy.get("[data-cy=list-produk]").children().should("have.length.gt", 0);Di sini cy.wait("@produk") menunggu data terbaru selesai diambil sebelum memeriksa daftar. Menunggu event jaringan adalah cara paling deterministik untuk konten dinamis — jauh lebih baik daripada menebak durasi animasi.
cy.intercept adalah alat paling kuat untuk konten dinamis: kalian bisa mengontrol respons jaringan sepenuhnya:
cy.intercept("GET", "/api/produk/*", (req) => {
req.reply({ statusCode: 500, body: { error: "server down" } });
}).as("produkGagal");
cy.get("[data-cy=muat-produk]").click();
cy.contains("Gagal memuat produk").should("be.visible");req.reply({ statusCode: 500, body: ... }) memaksa aplikasi menerima kegagalan server. Skenario seperti retry dan fallback flow bisa diuji tanpa menurunkan server sungguhan — kita akan membedah ini lebih dalam di episode 12.
Tip
Atur cy.intercept di beforeEach agar seluruh test di satu describe konsisten. Pastikan pola URL-nya spesifik — * yang terlalu luas bisa menangkap request yang tidak diinginkan dan membuat test saling memengaruhi.
Episode 8 memperluas jangkauan interaksi: iframe lintas domain lewat cy.origin(), popup dan window baru dengan men-stub window.open, drag and drop lewat trigger, upload dengan cy.selectFile, keyboard events dengan cy.type, konten dinamis SPA dengan cy.wait("@alias"), dan kontrol penuh jaringan lewat cy.intercept.
Inti yang harus dibawa pulang:
cy.origin() membuka kunci pengujian domain berbeda.window.open agar popup bisa di-assert tanpa berpindah tab.cy.selectFile menangani upload file nyata.cy.type("{ctrl}s") meniru shortcut keyboard.Di episode 9 selanjutnya kita akan membahas component testing — menguji komponen React, Vue, dan Angular secara terisolasi, menyiapkan environment component, assertion berbasis perilaku komponen, serta integrasi dengan Storybook. Test kalian mulai turun satu level dari halaman penuh ke komponen.