İçeriğe geç
← Yazılar

5 Ekim 2026 · 4 dk okuma

Pest tarayıcı testleri bitince Playwright neden kapanmıyor?

Bu sitenin hesap sayfalarında karanlık mod, sayfa değiştirince kendiliğinden aydınlık moda dönüyordu. Hatayı düzelttim ve bir daha geri gelmesin diye ilk tarayıcı testimi yazdım: Pest'in tarayıcı eklentisi, arkada Playwright ile gerçek bir Chromium açıyor ve sayfada gezip kontrol ediyor.

Testler yeşil geçti. Ama terminal geri gelmedi.

Belirti: Testler bitiyor, komut bitmiyor

php artisan test çıktısını tail gibi bir komuta bağladığımda (pipe), test özeti ekrana geliyor ama komut sonsuza kadar bekliyordu. Çıktıyı bir dosyaya yönlendirince komut bitiyordu, ama arkada bir şey kalıyordu:

bash
pgrep -a -x node | grep "playwright run-server"

Her test çalıştırması geride bir playwright run-server süreci bırakıyordu. Daha da ilginci, listede iki gün önceden kalma dört süreç daha vardı. Başka bir projemde tarayıcı testlerini çalıştırdığım günden beri sessizce açık bekliyorlardı. Hata kayıtlarındaki ölçümlere göre bu süreçlerin her biri yaklaşık 180 MB bellek tutuyor1 pestphp/pest #1754'teki yorumlara göre bir makinede bir günün sonunda 65 süreç ve yaklaşık 8 GB birikmiş..

Teşhis: Kim kimi kapatıyor?

Pest, test bitince Playwright sunucusunu durdurmaya çalışıyor. Durdurduğu sürecin numarasını ve arkada kalan süreci yan yana koyunca durum netleşti:

txt
php (pest)
 └─ sh -c ./node_modules/.bin/playwright run-server ...   ← Pest bunu kapatıyor (pid 172083)
     └─ node ./node_modules/.bin/playwright run-server    ← asıl sunucu (pid 172084)

Pest sunucuyu doğrudan başlatmıyor, bir kabuğun (sh) içinden başlatıyor. Test bitince kapatma sinyalini de sadece o kabuğa gönderiyor. Kabuk kapanıyor, asıl Playwright süreci ise sahipsiz kalıp çalışmaya devam ediyor.

Neden: Tek bir kelime eksik

Pest, Playwright'ı Symfony Process'in fromShellCommandline() metoduyla, yani düz bir komut metniyle başlatıyor. PHP böyle bir metni sh -c "…" ile çalıştırır. Symfony, komutun başına exec kelimesini sadece komut bir dizi (array) olarak verildiğinde ekliyor. Belgeleri de sinyallerin sorunsuz iletilmesi için dizi kullanmayı öneriyor2 Symfony Process belgeleri.

exec, kabuğa "kendin kenara çekil, yerine bu komutu çalıştır" der. Kabuk süreci Playwright'a dönüşür ve kapatma sinyali doğrudan doğru yere gider.

İşin can alıcı kısmı da burada: Ubuntu'da /bin/sh aslında dash. Benim makinemdeki dash, exec yazılmadığında Playwright'ı kendi yerine değil, kendi alt süreci olarak başlattı. Hata kaydındaki analize göre macOS'ta /bin/sh bu durumda kendini Playwright ile değiştiriyor, yani hata orada hiç görünmüyor3 Aynı nedenle Laravel Sail, Debian tabanlı Docker imajları ve WSL2'de de görülüyor.. Klasik "bende çalışıyor" durumu.

Terminalin takılmasının sebebi de aynı. Sahipsiz kalan süreç, çıktı borusunun (pipe) ucunu hâlâ açık tutuyor. tail, borunun kapandığını hiç göremediği için sonsuza kadar bekliyor.

Çözüm: Bir yama

Pest'in komutu değiştirmek için bir ayarı yok, bu yüzden paketi yamadım. Değişiklik tek kelime:

diff
-'.'.DIRECTORY_SEPARATOR.'node_modules'.DIRECTORY_SEPARATOR.'.bin'.DIRECTORY_SEPARATOR.'playwright run-server ...',
+'exec .'.DIRECTORY_SEPARATOR.'node_modules'.DIRECTORY_SEPARATOR.'.bin'.DIRECTORY_SEPARATOR.'playwright run-server ...',

Yamayı vendor/ klasöründe elle değiştirmek yerine cweagans/composer-patches ile uyguluyorum. Böylece her composer install'da, CI dahil, kendiliğinden uygulanıyor:

json
"extra": {
    "patches": {
        "pestphp/pest-plugin-browser": {
            "Stop the Playwright server itself, not only the sh wrapper around it": "patches/pest-plugin-browser-stop-playwright.patch"
        }
    }
}

Bir artısı daha var: Pest bir gün bu satırı değiştirirse yama uygulanamaz ve kurulum açıkça hata verir. Düzeltme sessizce kaybolmaz, ben de yamayı kaldırmam gerektiğini anlarım.

Yamadan sonra üç farklı şekilde denedim: doğrudan pest, php artisan test ve pipe'lı php artisan test | tail. Üçünde de testler bitince Playwright kapandı, terminal hemen geri geldi.

Herkesin sorunu mu?

Evet. Hatayı yazmadan önce Pest'in GitHub'ına baktım; birebir aynı sorun 16 Temmuz 2026'da bildirilmiş ve hâlâ açık: pestphp/pest #1754. Teşhis bizimkiyle aynı: dash, eksik exec ve pipe'ın takılması.

Düzelten bir PR da var, ama henüz birleştirilmemiş: pest-plugin-browser #254. O da bizim yaptığımızı yapıyor: komutun başına exec ekliyor. Ondan önce açılmış #169 ve #211 de bekliyor.

Bir de yakın bir akrabası var: CI bir çalıştırmayı iptal ettiğinde gönderilen SIGTERM sinyalinde de sunucu açık kalıyor (pestphp/pest #1825). Bizim yamamız bunu çözmüyor; o durumda Pest'in kapatma kodu hiç çalışmıyor.

Bu hatadan öğrendiklerim

  • Testlerin yeşil olması her şeyin yolunda olduğu anlamına gelmiyor. Hiçbir test bu süreçleri yakalamadı. İki gün boyunca kimse fark etmedi.
  • sh her yerde aynı değil. macOS'ta görünmeyen bir hata Ubuntu'da her çalıştırmada ortaya çıkabiliyor.
  • Arka plan süreci başlatıyorsan, kapatırken neyi kapattığından emin ol. Kabuğu kapatmak, içindekini kapatmak demek değil.
  • pkill -f ile dikkat. Aradığın kelime kendi komut satırında da geçtiği için pkill -f "playwright run-server" kendi kabuğunu da kapatabilir. Süreç adına göre filtrelemek daha güvenli: pgrep -x node.

PR birleştiğinde yamayı kaldıracağım. O zamana kadar bu yazı, aynı sorunla karşılaşan birine bir arama kadar uzakta olsun... :)

Kadir
5 Ekim 2026

Kenara düşülen notlar

yorumlar · henüz yok

Yorum yazmak için giriş yap ya da kayıt ol.