Nightwatch.js ile Uçtan Uca Testler Yazmak
Girizgah
Yazdığımız kod parçacıklarının planladığımız şekilde davranışlar sergileyip sergilemediklerinin kontrolünü birim (unit) testlerle sağlayabiliyoruz. Fakat ekseriyetle birbirinden bağımsız şekilde yazılan bu testler projenin tamamının çalışırlığı konusunda bize pek fikir vermiyor.
Örneğin projeye yeni bir özellik eklediğimizde, ona temas eden diğer özelliklerin hâla çalışır durumda olup olmadığını bilemiyor, kimi zaman da kötü sürprizlerle karşılaşabiliyoruz. Yapılan her değişiklikten sonra, tüm projeyi baştan ayağa son kullanıcı gibi test etmek de oldukça maliyetli olacağından ilk akla gelen bu süreci otomatikleştirmek oluyor. Tam bu noktada uçtan uca (end-to-end / E2E) testler imdadımıza yetişiyor.
Uçtan uca testler için farklı ekosistemlerde farklı çözümler var. Ben bu yazıda web projeleri için oldukça kullanışlı, Node.js üzerinde çalışan Nightwatch.js çatısından bahsedip ufak bir test örneği yazacağım.
Kurulum
Nightwatch.js’i kullanabilmek için Node.js’in bilgisayarımızda kurulu olması gerekiyor. Package.json
dosyamızı varsayılan bilgilerle hızlı bir şekilde doldurarak kuruluma başlıyoruz.
npm init -y
Hemen ardından NPM üzerinden nightwatch
paketini kuruyoruz. -D
parametresiyle bu paketin bir geliştirme ortamı bağımlılığı olduğunu belirtiyoruz.
npm i -D nightwatch
Nightwatch.js, yazdığımız testleri tarayıcı üzerinde çalıştırıyor. Bu nedenle testlerimizde alacağımız aksiyonları tarayıcıların anlayabilmesi için ilgili tarayıcı motorlarının sürücü olarak yüklenmesi gerekiyor. Bu sayede biz tek bir test yazacağız ama o test tüm tarayıcı motorları tarafından yorumlanıp çalışabilecek durumda olacak.
Chrome, Firefox, Safari ve Edge için tarayıcılarla birlikte bu sürücülerin de ayrı ayrı kurulması gerekiyor. Ben testlerimi şu an için Firefox’ta yapacağımdan yalnızca Gecko motorunun sürücüsünü kuruyorum.
npm i -D geckodriver
Her şey yoluda gittiyse eğer package.json
dosyamızın buna benzer bir hâl alması lazım.
İlk Test
Kurulumdan sonra hızlıca ilk testimizi yazmaya başlayabiliriz. Tiyatro Günlüğü isimli blog sitem için bir test yazacağım. Bunun için basitçe dizin yapımı ve test dosyamı oluşturuyorum.
mkdir -p tests/tiyatrogunlugu.com && cd tests/tiyatrogunlugu.com
touch index.js
Hemen ardından bir objeyi CommonJS formatında dışarı aktarıyorum. Objemizin anahtarı testimizin ismi, değeri ise browser
isminde tek bir argüman alan fonksiyon oluyor. Bundan sonra tüm işimiz bu browser objesi üzerinde olacak. Testimizin tüm kurallarını browser objesi içerisinde zincirleyerek tanımlayacağız.
module.exports = {
'Erişim testi': browser => {
browser
.url('https://tiyatrogunlugu.com/')
.waitForElementVisible('body')
.end();
}
};
İlk testimizde https://tiyatrogunlugu.com/
adresine bir istek yaptık ve body
elementinin görünür olmasını bekledik. Testimizi çalıştırdığımızda tarayıcımız kendiliğinden açılacak, testi sürdürecek ve tamamlandığında kapanacak.
Yazdığımız testi Nightwatch ile çalıştırabiliriz artık.
nightwatch index.js
İlk testimizi çalıştırdıktan sonra nightwatch.conf.js
isimli bir yapılandırma dosyası ve tests_output
isimli bir dizin kendiliğinden oluşacak. Her testin sonucu XML formatında bu dizine kaydolacak. Aksi belirtilmediği sürece test esnasında oluşabilecek hatalar da tarayıcı bazlı olarak bu dizine loglanacak.
Yapılandırma dosyasında şu an için bir değişiklik yapmaya gerek yok. Test yapılacak tarayıcının değiştirilmesi, dinlenecek portların belirlenmesi gibi ayarlar bu dosyadan yapılabiliyor.
Testi Geliştirmek
İlk testle yalnızca sitenin erişilebilir olup olmadığını kontrol etmiş olduk. Bu elbette işe yarar bir test senaryosu değil. Etkili bir kullanım için testimiz içerisinde kimi iddialarda bulunmamız ve bu iddialar sonucunda aldığımız yanıtlarla testimizi sürdürmemiz gerekiyor.
Bazı test çatıları bu iddia durumlarını tek başına sağlayamıyor ve yardımcı araçlara ihtiyaç duyuyor. Mocha ve Chai örneğinde olduğu gibi. Fakat Nightwatch.js bir iddia (assertion) kütüphanesini de içerisinde barındırıyor. Şimdi testimizi hızlıca sitedeki arama fonksiyonunu kontrol edecek hâle getirelim.
module.exports = {
'Arama fonksiyonu testi': browser => {
browser
.url('https://tiyatrogunlugu.com/')
.waitForElementVisible('body')
.assert.visible('.search-field')
.setValue('.search-field', 'haluk bilginer')
.click('.search-submit')
.assert.containsText('.page-title', 'haluk bilginer')
.end();
}
};
Testi okuması oldukça kolay. İlk olarak yine siteye istek yapıyor ve body
elementinin görünür olmasını bekliyoruz. Ardından aynı şekilde search-field
sınıfına sahip elementi bekliyoruz. Bu sınıf, siteki arama kutusunu işaret ediyor.
Bir elemente erişmek için istersek CSS seçicilerini (#searchBox
veya .searchBox
gibi) kullanabiliyoruz. İstersek de doğrudan XPath kimliklerinden (input[type=text]
gibi) erişim sağlayabiliyoruz.
Arama kutusu görünür olduktan sonra içerisine istediğimiz bir metni yazıyor ve formu gönderecek butonun tıklama özelliğini tetiklettiriyoruz. Daha sonra gelen sayfada ise arama formuna girdiğimiz metnin sayfa başlığında yer alıyor olmasını bekliyoruz. Burada önemli husus her bir kuralın her zaman bir öncekine bağlı olması. Yani testinizle ortaya attığınız bir iddia sağlanmıyorsa sonrakilerin bir önemi kalmıyor ve testiniz başarısız olmuş oluyor.
describe('Tiyatro Günlüğü', () => {
test('Erişim testi', browser => {
browser
.url('https://tiyatrogunlugu.com/')
.waitForElementVisible('body')
}); test('Arama fonksiyonu testi', browser => {
let searchText = 'haluk bilginer';
let searchBox = '.search-field';
let searchButton = '.search-submit';
let resultDiv = '.page-title'; browser
.assert.visible(searchBox)
.setValue(searchBox, searchText)
.click(searchButton)
.assert.containsText(resultDiv, searchText)
.end();
});
});
Popüler test çatılarındaki gibi testleri gruplamak ve isimlendirmek de Nightwatch.js ile mümkün. Yazdığınız test zinciri end()
fonksiyonunu görene kadar farklı isimlerle de olsa çalışmaya devam edecektir.
Diğer Marifetler
Nightwatch.js çok güçlü bir API’ı beraberinde sunuyor. Gerçek bir kullanıcının alabileceği tüm aksiyonları, çerez oluşturma / okuma, oturum yönetimi gibi kompleks işlemleri dahi simüle etmeye olanak sağlıyor. Ben çok sevdiğim iki tanesinden söz edip kalan onlarcası için API belgesini okumayı şiddetle tavsiye edeceğim.
Ekran Görüntüsü Alma
Testimizin istediğiniz bir anında tarayıcının o anki ekran görüntüsünü kaydedebiliyoruz. Tanım zincirine saveScreenshot
fonksiyonunu eklemek ve argüman olarak ekran görüntüsünün kaydedileceği yolu yazmak çalışması için yeterli. Özellikle netameli görülen yerlerde, test tamamlandıktan sonra olan biteni gözden geçirmek için çok kullanışlı bir özellik.
.saveScreenshot('./screenshots/result.png')
Çözünürlük Değiştirme
Diyelim ki tüm testlerimizi masaüstü sitede yaptık ama testin bir yerinde özel olarak mobil sitedeki bir fonksiyonu da kontrol etmek istiyoruz. setWindowSize
fonksiyonuyla test esnasında pratik bir şekilde çözünürlük değiştirebiliyoruz.
.setWindowSize(768, 1000)
Son Sözler
Nightwatch.js marifetli ve kullanışlı bir test çatısı. Asgari şartların sağlandığı bir test ortamını neredeyse sıfır yapılandırmayla kullanıma hazır hâle getiriyor. Gündelik dile benzer söz dizimiyle konuşur gibi test yazmaya imkân tanıyor. Hazırlanabilecek test senaryoları tamamen testi yazanın hayal gücüne kalmış durumda. Periyodik olarak kontrol edilmesi gereken senaryolarda âdeta ilaç oluyor. Continuous integration süreçlerine de dahil olabildiği için neredeyse tamamı otomatikleştirilmiş bir test sürecine sahip oluyoruz.
Son olarak yazdığım ufak testin GitHub deposunu ve faydalı gördüğüm birkaç bağlantıyı paylaşarak bitiriyorum.
Kaynaklar
https://nightwatchjs.org/api
https://github.com/nightwatchjs/nightwatch
https://stackoverflow.com/questions/tagged/nightwatch.js
https://medium.com/@shikha140791/introduction-to-nightwatch-js-e7f25f8fa214