Smoke Test Playwright di GitHub Actions: Serve, Tunggu, Gagal
Tambahkan smoke test Playwright ke GitHub Actions: jalankan app Next.js hasil build, tunggu sampai merespons, pasang Chromium headless, cetak log gagal.
Oleh Matthews WongDitinjau pada
Poin utama
Smoke test membuka app hasil build di browser sungguhan dan memeriksa bahwa beberapa hal yang wajib jalan memang jalan. Ia menangkap yang tidak bisa ditangkap unit test dan contract test: build yang berhasil dikompilasi tetapi merender halaman rusak. Di CI Anda build, menyalakan server di latar belakang, menunggu ia merespons, menjalankan tes, dan mencetak log server jika ada yang gagal.
Setelah pelajaran ini, Anda bisa
- Menjelaskan apa yang dijaga smoke test browser yang tidak bisa dijaga unit test dan contract test.
- Menulis workflow yang build, serve, menunggu kesiapan, menguji, dan menampilkan log server saat gagal.
- Menjaga versi Playwright dan build browsernya tetap selaras.
Ikuti diagramnya langkah demi langkah
Tekan Putar, atau melangkah dengan panah. Setiap langkah juga ditulis di bawah diagram.
Dari build sampai smoke test yang gagal
Sebuah workflow membangun app, menyalakannya di latar belakang dengan outputnya ke file log, memeriksa berulang sampai ia menjawab, menjalankan tes browser, dan mencetak log saat tes gagal.
Tombol: ← → langkah · Home / End · K putar atau jeda
Satu job menjalankan lima hal berurutan: build, server di latar belakang, loop tunggu, tes browser headless, dan file log yang hanya dibaca jika ada yang gagal.
Build berjalan lebih dulu, lalu server menyala di latar belakang dengan outputnya ke file log, sehingga langkah berikutnya bisa jalan selagi server tetap hidup.
PORT=3000 npm start > server.log 2>&1 &Menyala belum berarti siap. Sebuah loop meminta halaman setiap dua detik dan lanjut hanya ketika mendapat respons sukses.
if curl -sf -o /dev/null http://localhost:3000/en/play/; then exit 0; fiTebak langkah berikutnya Request pertama tiba sebelum server mendengarkan. Apa yang sebaiknya dilakukan loop? (Langsung menggagalkan job · Tidur sebentar, lalu coba lagi · Tetap menjalankan tes)Dengan server yang sudah menjawab, sebuah skrip membuka halaman di Chromium headless, menelusuri jalur utama, dan mencatat setiap pengecekan yang tidak terpenuhi.
BASE_URL=http://localhost:3000 npm run game:smokeTebak langkah berikutnya Sebuah pengecekan gagal, misalnya canvas tidak pernah muncul. Apa yang dilakukan skrip? (Tetap lulus · Mencetak FAIL dan keluar dengan kode 1 · Menghentikan server)Skrip mengatur exit code bukan nol. Langkah workflow gagal, dan langkah berikutnya yang hanya berjalan saat sukses dilewati.
process.exitCode = 1;Langkah terakhir yang ditandai berjalan saat gagal mencetak file log. Browser menyebut apa yang rusak di layar, dan log menyebut mengapa server rusak.
if: failure()
Apa yang dijaga smoke test yang tidak bisa dijaga unit test?
Smoke test menjawab satu pertanyaan: apakah yang akan kita rilis ini pada dasarnya berfungsi? Ia membuka app hasil build yang asli di browser sungguhan dan menjalankan jalur terpendek di dalamnya. Unit test dan contract test membaca data dan memanggil fungsi, jadi tetap lulus meski bundle melempar error saat dimuat, sebuah route mengembalikan halaman error, atau skrip gagal di browser. Hanya menjalankan hasil build yang menyadarinya.
Baca selengkapnya (2)Tutup
Skrip smoke di repo ini, yang ditulis untuk halaman game 3D, menunjukkan bentuknya. Ia memeriksa bahwa notice persetujuan tampil, tidak ada file aset berat yang diminta sebelum pengunjung menerima, menerima akan memasang canvas yang benar-benar menghasilkan frame, deep link membuka kartu yang tepat, dan halaman tidak mencatat error di console. Itu semua hasil yang terlihat pengguna, yang menurut dokumentasi Playwright memang sebaiknya diverifikasi tes.
Jaga agar tetap kecil. Smoke test adalah kawat jebakan, bukan suite regresi: beberapa pengecekan pada jalur terpenting, sehingga kegagalan berarti ada yang jelas rusak dan proses cukup singkat untuk dijalankan di setiap pull request.
Bagaimana menyalakan app hasil build di workflow dan menunggunya?
Langkah CI adalah perintah shell, dan server tidak pernah berhenti, jadi Anda menyalakannya di latar belakang dengan tanda ampersand di akhir dan mengarahkan outputnya ke file. Lalu Anda menunggu. Proses yang menyala belum tentu siap, jadi langkah berikutnya tidak boleh mengira port sudah terbuka. Workflow ini memeriksa halaman asli dengan curl setiap dua detik, hingga enam puluh kali, dan menganggap sukses pertama sebagai tanda siap.
Baca selengkapnya (2)Tutup
Memeriksa halaman asli lebih baik daripada tidur dengan waktu tetap: ia lanjut begitu server siap dan tidak menebak. Jika loop habis, langkah itu mencetak pesan, menampilkan log server, dan keluar dengan kode 1, sehingga server yang tidak pernah menyala gagal dengan pesan errornya sendiri terlihat, bukan timeout samar di langkah tes sesudahnya.
Mengapa perintah yang gagal menghentikan job? GitHub mendokumentasikan bahwa secara default shell bash untuk sebuah langkah berjalan dengan perilaku fail-fast, sehingga exit code bukan nol menggagalkan langkah, dan langkah yang gagal membuat langkah sesudahnya dilewati kecuali dinyatakan lain.
Bagaimana memasang Chromium headless dan menjaga versi tetap selaras?
Playwright mengunduh build browsernya sendiri. Dokumentasi menunjukkan npx playwright install --with-deps chromium untuk memasang satu browser beserta pustaka sistem operasi yang dibutuhkannya di Linux, dan menyarankan hanya memasang browser yang dipakai, terutama di CI. Secara default Playwright meluncurkan browser dalam mode headless, jadi runner ubuntu biasa tidak butuh layar.
Baca selengkapnya (3)Tutup
Dokumentasi juga menyatakan bahwa setiap versi Playwright membutuhkan versi binary browser tertentu. Itulah aturan pinning: build browser adalah fungsi dari versi paket Playwright, jadi pasang browser setelah dependensi, dari lockfile yang sama, di job yang sama. package.json repo ini mengizinkan rentang, sedangkan lockfile mencatat rilis persis yang benar-benar didapat workflow, dan versi yang berubah berarti build browser yang berbeda untuk diunduh.
Bagaimana dengan cache browser? Halaman CI di dokumentasi tidak menyarankannya, dengan alasan memulihkan cache memakan waktu yang sebanding dengan mengunduh, dan dependensi sistem Linux memang tidak bisa di-cache. Jika tetap di-cache, kunci cache dengan versi Playwright. Workflow ini meng-cache paket npm lewat setup-node dan mengunduh Chromium baru di setiap run.
Satu catatan praktis untuk halaman 3D: tanpa GPU di runner, skrip meluncurkan Chromium dengan flag yang memilih renderer perangkat lunak, sehingga WebGL berfungsi. Itu khusus untuk game ini, dan halaman biasa tidak butuh flag tambahan.
Bagaimana membuat run yang gagal menjelaskan dirinya sendiri?
Server berjalan di latar belakang, jadi outputnya masuk ke file dan tes yang gagal hanya menampilkan sisi browser. Langkah dengan if: failure() memperbaikinya. GitHub mendokumentasikan bahwa failure() bernilai true ketika ada langkah sebelumnya dalam job yang gagal, dan bahwa sebuah langkah hanya berjalan setelah sukses kecuali Anda menambahkan fungsi status check ke kondisinya. Langkah terakhir workflow ini memakainya untuk mencetak log.
Baca selengkapnya (2)Tutup
Skrip tes ikut membantu. Alih-alih melempar error pada masalah pertama, ia mencatat setiap kegagalan dengan pesan yang jelas, mengatur exit code ke 1, dan melanjutkan, sehingga satu run melaporkan semua pengecekan yang rusak. Untuk kegagalan yang tidak bisa direproduksi dari teks, dokumentasi Playwright merekomendasikan trace viewer di CI dibanding video dan screenshot, yang bisa Anda tambahkan di atas log.
Terakhir, beri pagar pada job. Workflow membatalkan run lama pada branch yang sama saat push baru tiba, hanya memberi akses baca ke isi repositori, dan berjalan hanya saat path yang relevan berubah. Smoke test yang tidak membuat orang menunggu adalah smoke test yang dipertahankan.
Konfigurasi nyata di balik pelajaran ini
Kutipan dari repositori yang membangun dan men-deploy situs ini, apa adanya.
- name: Serve
run: |
PORT=3000 npm start > server.log 2>&1 &
for i in $(seq 1 60); do
if curl -sf -o /dev/null http://localhost:3000/en/play/; then exit 0; fi
sleep 2
done
echo "server did not come up"
cat server.log
exit 1Nyalakan, tunggu, menyerah dengan jelas. Ampersand di akhir menaruh server di latar belakang dan 2>&1 mengirim kedua stream ke server.log. Loop selesai pada request sukses pertama, dan jika enam puluh percobaan lewat, ia mencetak log lalu keluar dengan kode 1 sehingga job gagal di sini, bukan nanti.
- name: Server log on failure
if: failure()
run: cat server.log || trueJaring pengaman. failure() menimpa kondisi bawaan yang hanya berjalan saat sukses, jadi langkah ini berjalan setelah langkah mana pun sebelumnya gagal. || true di akhir mencegah langkah ini sendiri gagal jika file log belum ada.
- name: Install Chromium for Playwright
run: npx playwright install --with-deps chromiumSatu browser beserta pustaka sistem operasinya, dipasang setelah npm ci agar build browser cocok dengan versi Playwright yang terpasang. Hanya Chromium yang dipasang karena tes hanya meluncurkan Chromium.
function fail(message) {
console.error(`smoke-test: FAIL — ${message}`);
process.exitCode = 1;
}Pengecekan yang gagal tanpa menghentikan proses. Ia mencetak pesan berlabel dan mengatur exit code, sehingga setiap pengecekan yang rusak muncul dalam satu putaran dan proses tetap berakhir dengan status gagal yang dipahami langkah workflow.
const browser = await chromium.launch({
headless: true,
args: [
"--use-gl=angle",
"--use-angle=swiftshader",
"--enable-unsafe-swiftshader",
],
});Chromium headless dengan renderer GL perangkat lunak, karena runner CI tidak punya GPU dan halaman ini menggambar WebGL. Argumen itu hanya untuk game 3D ini; halaman biasa cukup memanggil launch dengan headless saja.
"playwright": "^1.60.0",Dependensi ini mengizinkan rentang. package-lock.json di sampingnya mencatat rilis persis yang terpasang, dan build browser yang diunduh mengikuti versi itu. Perketat rentangnya jika Anda butuh build browser yang sama di setiap mesin.
Kesalahan yang benar-benar membuang waktu
Tes mulai sebelum server siap
Menyalakan server dan menjalankan tes di baris berurutan membuat balapan dengan terbukanya port, dan run pertama lulus atau gagal secara kebetulan. Periksa URL asli sampai menjawab, dan gagalkan langkah tunggu beserta log jika tidak pernah menjawab.
Build browser hilang setelah versi naik
Setiap versi Playwright membutuhkan binary browser tertentu. Jika rentang dependensi memindahkan Playwright ke rilis yang build browsernya belum ada di mesin, peluncuran gagal sampai Anda menjalankan perintah install lagi. Di CI langkah install berjalan setiap kali, itulah sebabnya di sana berhasil.
Kegagalan tanpa log server
Output server masuk ke file, jadi tanpa langkah yang mencetaknya run merah hanya bilang bahwa pengecekan browser gagal. Tambahkan langkah dengan if: failure() yang mencetak log.
Smoke test yang tumbuh menjadi suite yang rewel
Setiap jalur tambahan menambah cara gagal yang tidak berhubungan dengan perubahan. Batasi smoke test pada jalur terpendek yang membuktikan app hidup, dan uji kedalamannya di tempat lain. Stub respons pihak ketiga agar situs luar tidak membuat run menjadi merah.
| Aspek | Unit atau contract test | Smoke test browser |
|---|---|---|
| Dijalankan terhadap | Modul sumber dan data | App hasil build yang disajikan |
| Menangkap | Logika salah, aturan data yang rusak | Halaman yang error, skrip yang melempar error, aset yang hilang |
| Membutuhkan | Hanya Node | Build, server yang berjalan, dan browser |
Lakukan di komputer Anda sendiri
Tambahkan smoke test ke proyek Next.js dan jalankan seperti CI akan menjalankannya, di mesin Anda sendiri lebih dulu.
Pasang Playwright sebagai dependensi dan unduh hanya Chromium beserta pustaka sistemnya.
npm install --save-dev playwright npx playwright install --with-deps chromiumTulis scripts/smoke.mjs. Buka halaman utama, pastikan satu heading terlihat, dan atur process.exitCode = 1 dengan pesan jelas jika tidak ada.
import { chromium } from "playwright"; const browser = await chromium.launch({ headless: true }); const page = await browser.newPage(); await page.goto(process.env.BASE_URL ?? "http://localhost:3000"); if (!(await page.getByRole("heading", { level: 1 }).isVisible())) { console.error("smoke: FAIL - no h1"); process.exitCode = 1; } await browser.close();Build, nyalakan server di latar belakang dengan outputnya di file, dan tunggu dengan loop pemeriksaan sebelum menjalankan skrip.
npm run build PORT=3000 npm start > server.log 2>&1 & for i in $(seq 1 30); do curl -sf -o /dev/null http://localhost:3000/ && break; sleep 1; done node scripts/smoke.mjsSalin perintah yang sama ke workflow. Tambahkan langkah terakhir dengan if: failure() yang menjalankan cat server.log, lalu rusak halaman dengan sengaja dan baca log di run.
- name: Server log on failure if: failure() run: cat server.log || true
Tiga pertanyaan sebelum lanjut
Pilih jawaban untuk melihat kenapa benar atau salah. Tidak ada yang disimpan atau dinilai, jadi tebak saja dengan bebas.
Jawab dalam hati, lalu cek
1.Mengapa memasang browser setelah dependensi npm, di job yang sama?Lihat jawabannya
Jawaban:Setiap versi Playwright membutuhkan binary browser tertentu. Memasang setelah dependensi berarti perintah install membaca versi yang benar-benar terpasang, sehingga build browser cocok dengannya.
2.Skrip smoke mencatat kegagalan dan terus berjalan alih-alih melempar error. Apa manfaatnya?Lihat jawabannya
Jawaban:Satu run melaporkan semua pengecekan yang rusak, dan exit code tetap bukan nol sehingga langkah workflow gagal. Anda memperbaiki beberapa masalah per push, bukan satu.
3.Perlukah browser Playwright di-cache di CI?Lihat jawabannya
Jawaban:Dokumentasi CI Playwright tidak menyarankannya, karena memulihkan cache memakan waktu sebanding dengan mengunduh, dan dependensi sistem tidak bisa di-cache. Jika tetap dilakukan, kunci dengan versi Playwright.
Bahasan mendalam terkait di situs ini
Sumber
Sumber primer yang diperiksa pada tanggal riset. Ikuti tautannya untuk versi terbaru.