Pelajaran ini punya latihan. Latihannya berjalan di sandbox Academy Anda — proyek TestForge sungguhan berisi ShopMini, yang disimpan terpisah dari dasbor dan daftar proyek Anda.
Otomasi QAPelajaran 10 dari 12
EnglishKarya penutup: terbitkan hasil ke TestForge
Hasilkan JUnit XML, unggah lewat /api/v1/junit, dan baca run yang baru saja Anda buat.
15 mntOtomasi QAPraktik
Menutup lingkarannya
Segala yang sejauh ini menghasilkan centang hijau yang lalu lenyap. Pelajaran ini melekatkan hasil Anda pada case yang dijalankannya, sehingga pertanyaan yang benar-benar diajukan sebuah tim — apakah ini memburuk, pengujian mana yang paling sering gagal, seperti apa bulan lalu — punya tempat untuk dijawab.
Tiga langkah: hasilkan JUnit XML, POST ia, baca run-nya kembali.
1. Hasilkan JUnit XML
// playwright.config.ts
reporter: [
["list"],
["junit", { outputFile: "results/junit.xml" }],
],
JUnit XML adalah format yang dipahami setiap alat CI dan sistem test management. Ia bukan khas Playwright — pytest, JUnit, NUnit, dan Jest semuanya menghasilkannya, dan itulah sebabnya TestForge menelan ini alih-alih format milik satu vendor.
Kalau Anda mem-shard ke beberapa job, gabungkan dulu. Empat shard menghasilkan empat berkas XML dan endpoint-nya menginginkan satu run:
npx playwright merge-reports --reporter junit ./blob-report > results/junit.xml
2. Dapatkan dua hal yang dibutuhkan unggahannya
Slug proyek Anda. Buka proyek sandbox Anda di TestForge dan baca dari URL-nya
— /projects/academy-3f2a9b1c berarti slug-nya academy-3f2a9b1c. Slug
sandbox diturunkan dari akun Anda, jadi milik Anda bukan yang tercetak di sini.
Salin milik Anda sendiri.
Sebuah API key. Settings → API Keys → buat satu, lalu salin segera. Taruh di
penyimpanan rahasia CI Anda sebagai TF_API_KEY, jangan pernah di repositori.
3. Unggah
curl -X POST \
"$TF_BASE_URL/api/v1/junit?project=$TF_PROJECT&name=CI%20run&source=playwright" \
-H "Authorization: Bearer $TF_API_KEY" \
-H "Content-Type: application/xml" \
--data-binary @results/junit.xml
Parameter query-nya:
| Parameter | Artinya |
|---|---|
project | Wajib. Slug proyek Anda |
name | Nama run-nya. Bawaannya sebuah timestamp — setel sesuatu yang terbaca |
source | Framework-nya, misalnya playwright. Ditampilkan pada run-nya |
origin | Tempat ia berjalan, misalnya CI · GitHub Actions. Teks bebas, 120 karakter |
env | Nama environment opsional, untuk memisahkan run staging dan produksi |
Response yang berhasil memberi tahu Anda apa yang terjadi:
{
"runId": "run_8fd21a",
"runUrl": "/projects/academy-3f2a9b1c/runs/run_8fd21a",
"matched": 12,
"automated": 12,
"unmatched": ["logs out from the account menu"],
"summary": { "passed": 11, "failed": 1, "skipped": 0 }
}
unmatched adalah kolom yang harus dibaca. Pengujian itu berjalan, dan
hasilnya dibuang karena tidak ada apa pun di proyek Anda yang bersesuaian
dengannya.
4. Pencocokan: bagian yang sebenarnya menentukan apakah ini bekerja
Endpoint-nya mencocokkan setiap pengujian di XML-nya ke sebuah case di proyek Anda, dengan urutan ini:
- Anotasi
TC-<SLUG>-<nomor>di dalam nama pengujiannya, dengan<SLUG>adalah slug proyek Anda dan<nomor>adalah nomor case itu di dalam proyek. Dicocokkan tanpa membedakan huruf besar-kecil. - Kalau itu gagal, kecocokan judul yang persis — nama pengujiannya, dengan id TC apa pun dihapus, dibandingkan dengan judul case-nya tanpa membedakan huruf besar-kecil.
Jadi untuk proyek dengan slug academy-3f2a9b1c dan case bernomor 12:
test("TC-ACADEMY-3F2A9B1C-12 a valid login lands on the dashboard", async ({ page }) => {
// juga bekerja, kalau ada case yang berjudul persis seperti ini
test("a valid login lands on the dashboard", async ({ page }) => {
Pelajaran-pelajaran sebelumnya di track ini menulis TC-12 demi keringkasan.
Bentuk itu tidak cocok — slug-nya bagian dari polanya, karena nomor case hanya
unik di dalam satu proyek. TC-12 telanjang jatuh ke aturan judul, dan aturan
judulnya lalu membandingkan seluruh string termasuk "TC-12", jadi ia tidak
cocok dengan apa pun kecuali ada case yang harfiah berjudul begitu.
Lebih baik anotasinya daripada kecocokan judul. Judul disunting demi kejernihan,
dan suite yang mencocokkan pada prosa diam-diam berhenti cocok pada hari
seseorang memperbaiki sebuah judul case. Sebuah id adalah kontrak — argumen yang
sama dengan yang dibuat pelajaran locator tentang data-testid.
Slug-nya panjang dan Anda sebaiknya tidak mengetikkannya ke dalam 400 nama pengujian. Taruh di satu tempat:
// tc.ts
const SLUG = process.env.TF_PROJECT!.toUpperCase();
export const tc = (n: number, title: string) => `TC-${SLUG}-${n} ${title}`;
test(tc(12, "a valid login lands on the dashboard"), async ({ page }) => {
5. Sambungkan ke workflow-nya
- run: npx playwright test
- name: Publish results to TestForge
if: ${{ !cancelled() }}
run: |
curl -sS -X POST \
"$TF_BASE_URL/api/v1/junit?project=$TF_PROJECT&name=$GITHUB_REF_NAME%20%23$GITHUB_RUN_NUMBER&source=playwright&origin=CI%20%C2%B7%20GitHub%20Actions" \
-H "Authorization: Bearer $TF_API_KEY" \
-H "Content-Type: application/xml" \
--data-binary @results/junit.xml
env:
TF_BASE_URL: ${{ secrets.TF_BASE_URL }}
TF_API_KEY: ${{ secrets.TF_API_KEY }}
TF_PROJECT: ${{ secrets.TF_PROJECT }}
if: !cancelled() lagi, dan di sini ia lebih penting daripada untuk
artifact. Bawaannya adalah melewati sebuah langkah ketika langkah sebelumnya
gagal — jadi dengan bawaannya, satu-satunya run yang pernah sampai ke TestForge
adalah yang lulus, dan riwayat yang isinya cuma hijau lebih buruk daripada tanpa
riwayat sama sekali.
Ketika ia tidak bekerja
| Status | Artinya | Perbaikan |
|---|---|---|
| 401 | Key keliru atau hilang | Periksa header Authorization: Bearer … dan bahwa key-nya tersalin utuh |
| 404 | Proyek tidak ditemukan, atau Anda bukan anggotanya | Periksa slug-nya terhadap URL; pastikan key-nya milik akun yang punya akses |
| 400 | XML-nya gagal diurai, atau tidak memuat pengujian | Pastikan berkasnya tidak kosong dan bahwa reporter junit-nya memang berjalan |
| 422 | Terurai dengan baik, tidak ada yang cocok dengan sebuah case | Masalah penamaan di atas — response-nya mendaftar nama yang tidak cocok |
404-nya layak dibaca dua kali: proyek yang tidak bisa Anda lihat dilaporkan sama dengan yang tidak ada. Itu disengaja — ia menghindari mengonfirmasi slug mana yang ada kepada orang yang bukan anggota — dan artinya "key keliru" dan "slug keliru" tampak identik dari luar. Pelajaran otomasi API membuat poin yang persis sama tentang 403 versus 404; ini dia di dalam produk yang sedang Anda integrasikan.
422 adalah kegagalan pertama yang paling umum, dan ia kabar baik: unggahannya bekerja dari ujung ke ujung, dan hanya penamaannya yang keliru.
Latihannya
Terhadap proyek sandbox Anda, dari ujung ke ujung:
- Tambahkan reporter
junitdan pastikanresults/junit.xmlmuncul secara lokal. - Buka sandbox Anda, catat slug-nya dari URL dan nomor salah satu case yang
ditanamkan, lalu ganti nama satu pengujian supaya membawa
TC-<SLUG>-<n>. - Unggah dengan
curldi atas. Bacamatcheddanunmatcheddi response-nya. - Dapatkan 422 dengan sengaja — unggah berkas yang tidak satu pun nama pengujiannya cocok dengan apa pun — lalu baca error-nya. Setelah itu betulkan penamaannya dan unggah lagi.
- Buka
runUrldi TestForge. Pastikan run-nya ada, case-nya menampilkan hasilnya, dan riwayat case-nya kini punya sebuah entri. - Tambahkan langkah unggahnya ke workflow dari pelajaran sebelumnya dan biarkan CI membuat sebuah run.
Langkah kelima adalah karya penutupnya. Sebuah run yang Anda hasilkan dari pengujian yang Anda tulis, terlekat pada sebuah case, dengan riwayat yang masih akan ada di sana bulan depan — itulah lingkaran yang selama ini dibangun seluruh track ini.
Apa yang bisa Anda lakukan sekarang yang sebelumnya tidak
Begitu hasilnya menumpuk, riwayat run menjawab hal-hal yang tidak bisa dijawab centang hijau:
- Case mana yang paling sering gagal — daftar kelabilan, dan bahan mentah pelajaran berikutnya.
- Apakah sebuah perbaikan bertahan, karena case-nya punya sebelum dan sesudah.
- Apakah sebuah run merah itu regresi atau peristiwa perawatan. Empat puluh case merah sekaligus setelah perubahan login adalah masalah suite; satu case merah pada build yang menyentuh fiturnya adalah cacat. Pelajaran locator meminta Anda mencatat perbedaan itu dengan jujur; di sinilah ia jadi terlihat.
- Apa yang disampaikan kepada orang. Pelajaran pelaporan di T2 menginginkan rekomendasi rilis dalam bahasa yang bisa ditindaklanjuti product owner. "Suite-nya lulus" bukan itu; "case checkout sudah hijau selama sebelas build, dua yang merah adalah perbaikan locator yang sudah diketahui" itulah.
Untuk portofolio Anda
Ini hal yang nyata dan bisa diperagakan: sebuah repositori dengan sebuah suite, sebuah workflow yang menjalankannya di setiap pull request, dan sebuah proyek test management dengan riwayat yang menumpuk. Ia lebih meyakinkan daripada sertifikat apa pun, karena seorang hiring manager bisa membukanya.
Pelajaran portofolio di track Beyond Functional melanjutkan ini secara langsung.
Selanjutnya: pengujian labil — cara menemukan penyebab dari yang segera akan mulai ditunjukkan riwayat run ini kepada Anda, dan cara mengarantina dengan jujur alih-alih mencoba ulang selamanya.
Uji pemahaman Anda
3 pertanyaan. Tidak perlu akun, dan tidak ada yang dikirim ke mana pun selain ke pemeriksa jawaban.
1. Sebuah unggahan mengembalikan 422 dengan daftar nama pengujian yang tidak cocok. Apa yang terjadi?
2. Kenapa langkah unggahnya sebaiknya berjalan dengan `if: !cancelled()` alih-alih dengan bawaannya?
3. Pernyataan mana tentang pencocokan hasil ke case yang benar?(pilih semua yang sesuai)