Bir E2E Test Yolculuğu Bölüm 1: STUI'den WebdriverIO'ya
Yayınlanan: 2019-11-21Not: Bu, #frontend@twiliosendgrid'den bir gönderidir. Diğer mühendislik gönderileri için teknik blog rulosuna gidin.
SendGrid'in ön uç mimarisi web uygulamalarımızda olgunlaşmaya başladığından, olağan birim ve entegrasyon test katmanımıza ek olarak başka bir test düzeyi eklemek istedik. Tarayıcı otomasyon araçlarıyla E2E (uçtan uca) test kapsamıyla yeni sayfalar ve özellikler oluşturmaya çalıştık.
Testi bir müşterinin bakış açısından otomatikleştirmek ve yığının herhangi bir bölümünde meydana gelebilecek büyük değişiklikler için mümkün olduğunda manuel regresyon testlerinden kaçınmak istedik. Şu hedefimiz vardı ve hala var : ön uç uygulamalarımız için tutarlı, hata ayıklanabilir, bakımı yapılabilir ve değerli E2E otomasyon testleri yazmanın ve CICD ile entegrasyon (sürekli entegrasyon ve sürekli dağıtım) için bir yol sağlamak.
E2E testi için ideal çözümümüzü tamamlayana kadar birden fazla teknik yaklaşım denedik. Üst düzeyde, bu yolculuğumuzu özetliyor:
- Kendi özel kurum içi Ruby Selenium çözümümüzü oluşturma, SiteTestUI aka STUI
- STUI'den Düğüm tabanlı WebdriverIO'ya geçiş
- Her iki kurulumdan da memnun olmamak ve sonunda Cypress'e geçiş yapmak
Bu blog gönderisi, size ve diğer geliştiricilere yardımcı kalıplar ve test stratejileri ile E2E testlerini nasıl bağlayacakları konusunda umutla rehberlik etmek için yol boyunca kullanılan yaklaşımların her biri ile deneyimlerimizi, öğrenilen dersleri ve ödünleri belgeleyen ve vurgulayan iki bölümden biridir.
Birinci bölüm, STUI ile olan erken mücadelelerimizi, WebdriverIO'ya nasıl geçiş yaptığımızı ve buna rağmen yine de STUI'ye benzer pek çok düşüş yaşadığımızı kapsar. WebdriverIO ile testleri nasıl yazdığımızı, bir kapsayıcıda çalıştırmak için testleri nasıl Dockerleştirdiğimizi ve sonunda testleri CICD sağlayıcımız olan Buildkite ile nasıl entegre ettiğimizi gözden geçireceğiz.
Bugün E2E testinde bulunduğumuz yere atlamak istiyorsanız, lütfen STUI ve WebdriverIO'dan Cypress'e son geçişimizden ve farklı ekipler arasında nasıl kurduğumuzdan geçerken ikinci bölüme geçin.
TLDR: Selenium sarmalayıcı çözümleri, STUI ve WebdriverIO ile benzer acıları ve mücadeleleri yaşadık ve sonunda Cypress'te alternatifler aramaya başladık. E2E testleri yazmak ve Docker ve Buildkite ile entegrasyon yapmak için bir dizi anlayışlı ders öğrendik.
İçindekiler:
E2E Testine İlk Giriş: siteTESUI, diğer adıyla STUI
STUI'den WebdriverIO'ya geçiş
Adım 1: WebdriverIO için Bağımlılıklara Karar Verme
2. Adım: Ortam Yapılandırmaları ve Komut Dosyaları
3. Adım: ENE Testlerini Yerel Olarak Uygulama
Adım 4: Tüm Testleri Dockerize Etme
Adım 5: CICD ile Entegrasyon
WebdriverIo ile ödünleşimler
Cypress'e geçmek
E2E Testine İlk Giriş: SiteTestUI, diğer adıyla STUI
İlk olarak bir tarayıcı otomasyon aracı ararken, SDET'lerimiz (test aşamasındaki yazılım geliştirme mühendisleri), Ruby ve Selenium, özellikle Rspec ve Gridium adlı özel bir Selenium çerçevesi ile oluşturulmuş kendi özel şirket içi çözümümüzü yapmaya daldılar. Tarayıcılar arası desteğine, QA (Kalite Güvencesi) mühendis test senaryolarımız için TestRail ile kendi özel entegrasyonlarımızı yapılandırma becerisine ve tüm ön uç ekiplerin tek bir yerde E2E testleri yazması ve olması için ideal depo oluşturma düşüncesine değer verdik. bir programa göre çalıştırın.
SDET'lerin bizim için oluşturduğu araçlarla ilk kez bazı E2E testleri yazmaya hevesli bir ön uç geliştirici olarak, daha önce yayınladığımız sayfalar için testler uygulamaya başladık ve kullanıcıların nasıl düzgün bir şekilde ayarlanacağını düşündük ve bölümlerine odaklanmak için verileri tohumladık. test etmek istediğimiz özellik. Yol boyunca, yardımcı işlevselliği düzenlemek için sayfa nesneleri oluşturmak ve sayfa bazında etkileşimde bulunmak istediğimiz öğelerin seçicilerini oluşturmak gibi bazı harika şeyler öğrendik ve bu yapıyı takip eden özellikleri oluşturmaya başladık:
Benzer kalıpları izleyerek aynı depoda farklı ekipler arasında kademeli olarak önemli test paketleri oluşturduk, ancak kısa süre sonra, yeni geliştiriciler ve STUI'ye tutarlı katkıda bulunanlar için ilerlememizi büyük ölçüde yavaşlatacak birçok hayal kırıklığı yaşadık, örneğin:
- Test takımlarını çalıştırmadan önce, tüm tarayıcı sürücülerini, Ruby Gem bağımlılıklarını ve doğru sürümleri kurmak için ciddi bir zaman ve çaba gerektirdi . Bazen testlerin neden birinin makinesinde ve başka birinin makinesinde çalıştığını ve kurulumlarının nasıl farklı olduğunu anlamak zorunda kaldık.
- Test paketleri çoğaldı ve tamamlanana kadar saatlerce çalıştı. Tüm ekipler aynı depoya katkıda bulunduğundan, tüm testleri seri olarak çalıştırmak, genel test paketinin çalışması için birkaç saat beklemek anlamına geliyordu ve birden fazla ekip yeni kodu zorlayarak potansiyel olarak başka bir yerde başka bir bozuk teste yol açtı.
- Kesintili CSS seçicileri ve karmaşık XPath seçicileri yüzünden hüsrana uğradık . Aşağıdaki resim, XPath kullanmanın işleri nasıl daha karmaşık hale getirebileceğini yeterince açıklıyor ve bunlar daha basit olanlardan bazıları.
- Hata ayıklama testleri acı vericiydi . Belirsiz hata çıktılarında hata ayıklamada sorun yaşıyorduk ve genellikle işlerin nerede ve nasıl başarısız olduğu hakkında hiçbir fikrimiz yoktu. Nerede başarısız olduğunu ve bundan hangi kodun sorumlu olduğunu anlamak için yalnızca testleri tekrar tekrar çalıştırabilir ve tarayıcıyı gözlemleyebiliriz. CICD'deki bir Docker ortamında, konsol çıktıları dışında bakacak pek bir şey olmadan bir test başarısız olduğunda, yerel olarak yeniden üretmek ve sorunu çözmek için mücadele ettik.
- Selenium bugları ve yavaşlığı ile karşılaştık. Sunucudan tarayıcıya gönderilen tüm istekler nedeniyle testler yavaş çalıştı ve bazen testlerimiz, sayfadaki birçok öğeyi seçmeye çalışırken veya test çalıştırmaları sırasında bilinmeyen nedenlerle tamamen çöküyordu.
- Testleri düzeltmek ve atlamak için daha fazla zaman harcandı ve bozuk programlanmış yapı testi çalıştırmaları göz ardı edilmeye başlandı. Testler, sistemdeki gerçek hataları gerçekten göstermede değer sağlamadı.
- Ön uç ekiplerimiz, ilgili web uygulaması olanlardan ayrı bir depoda var olduğu için E2E testlerinden kopuk hissettiler . Testler çalışırken genellikle her iki depoyu da aynı anda açmamız ve tarayıcı sekmelerine ek olarak kod tabanları arasında ileri geri bakmamız gerekiyordu.
- Ön uç ekipleri, günlük olarak JavaScript veya TypeScript'te kod yazmaktan Ruby'ye bağlam değiştirmeyi ve STUI'ye katkıda bulunurken test yazmayı yeniden öğrenmek zorunda kalmayı sevmiyorlardı.
- Teste katkıda bulunurken çoğumuz için ilk kez alındığından, oturum açmak için UI aracılığıyla durum oluşturma, API aracılığıyla yeterince sökme veya kurulum yapmama ve yeterli belgeye sahip olmama gibi birçok antipattern'e düştük. harika bir test yapan şey için takip etmek.
Tek bir depoda birçok farklı ekip için önemli sayıda E2E testi yazma ve yanımızda götürmek için bazı yararlı kalıplar öğrenme yönünde ilerlememize rağmen, genel geliştirici deneyimi, birden fazla başarısızlık noktası ve değerli, kararlı testlerin eksikliği ile ilgili baş ağrıları yaşadık. tüm yığınımızı doğrulamak için.
Testlerin yeniden kullanımını, yakınlığını ve sahipliğini teşvik etmek için kendi uygulama kodlarında bulunan JavaScript ile kendi kararlı E2E test takımlarını oluşturmak için diğer ön uç geliştiricileri ve QA'ları güçlendirmenin bir yolunu değerlendirdik. Bu bizi, özel Ruby Selenium kurum içi çözümü olan STUI'nin ilk yedeğimiz olarak tarayıcı otomasyon testleri için JavaScript tabanlı bir Selenium çerçevesi olan WebdriverIO'yu araştırmaya yöneltti.
Daha sonra düşüşlerini deneyimleyecek ve sonunda Cypress'e geçecektik (WebdriverIO işleri size çekici gelmiyorsa, burada Bölüm 2'ye hızlı ilerleyin), ancak her ekibin deposunda standartlaştırılmış altyapı kurma konusunda paha biçilmez bir deneyim kazandık, E2E testlerini önyüzümüz için CICD'ye entegre ettik ve diğerlerinin WebdriverIO'ya veya başka herhangi bir E2E test çözümüne kimin atlamak üzere olduğunu öğrenmesi için yolculuğumuzda belgelemeye değer teknik kalıpları benimsemek.
STUI'den WebdriverIO'ya geçiş
Yaşadığımız sıkıntıları gidermek için WebdriverIO'ya başlarken, her ön uç ekibinin Ruby Selenium yaklaşımıyla yazılmış mevcut otomasyon testlerini JavaScript veya TypeScript'teki WebdriverIO testlerine dönüştürmesini ve kararlılık, hız, geliştirici deneyimi ve genel bakımını karşılaştırmasını sağlayarak deneyler yaptık. testler.
Ön uç ekiplerin uygulama depolarında bulunan ve hem CICD hem de planlanmış ardışık düzenlerde çalışan E2E testlerine sahip ideal kurulumumuzu elde etmek için, benzer hedeflere sahip bir E2E test çerçevesi oluşturmak isteyen herhangi bir ekip için genel olarak geçerli olan aşağıdaki adımları yeniden özetledik. :
- Test çerçevesine bağlanmak için bağımlılıkları yükleme ve seçme
- Ortam yapılandırmaları ve komut dosyası komutları oluşturma
- Farklı ortamlara karşı yerel olarak geçen E2E testlerini uygulama
- Testleri dockerize etme
- Dockerized testleri CICD sağlayıcı ile entegre etme
Adım 1: WebdriverIO için Bağımlılıklara Karar Verme
WebdriverIO, geliştiricilere test çalıştırıcısını başlatmak için birçok çerçeve, raportör ve hizmet arasından seçim yapma esnekliği sağlar. Bu, ekiplerin başlamak için belirli kitaplıklara yerleşmeleri için çok fazla kurcalama ve araştırma gerektirdi.
WebdriverIO, ne kullanılacağı konusunda kuralcı olmadığından, genel çekirdek testler WebdriverIO API'sini kullanırken tutarlı olsa da, ön uç ekiplerinin değişen kitaplıklara ve yapılandırmalara sahip olmasının kapısını açtı.
Ön uç ekiplerinin her birinin tercihlerine göre özelleştirmesine izin vermeyi seçtik ve genellikle test çerçevesi olarak Mocha'yı, muhabir olarak Mochawesome'ı, Selenium Bağımsız hizmetini ve TypeScript desteğini kullanmaya karar verdik. Mocha ve Mochawesome'ı ekiplerimizin daha önce Mocha'ya aşinalığı ve deneyimi nedeniyle seçtik, ancak diğer ekipler de diğer alternatifleri kullanmaya karar verdi.
2. Adım: Ortam Yapılandırmaları ve Komut Dosyaları
WebdriverIO altyapısına karar verdikten sonra, WebdriverIO testlerimizin her ortam için farklı ayarlarla çalışması için bir yola ihtiyacımız vardı. Bu testleri nasıl gerçekleştirmek istediğimize ve neden onları desteklemek istediğimize ilişkin kullanım durumlarının çoğunu gösteren bir liste aşağıda verilmiştir:
- Localhost üzerinde çalışan bir Webpack dev sunucusuna karşı (yani http://localhost:8000) ve bu dev sunucu, test etme veya hazırlama gibi belirli bir ortam API'sine yönlendirilecektir (ör. https://testing.api.com veya https:// saging.api.com).
Niye ya? Bazen, öğelerle daha sağlam bir şekilde etkileşim kurmak için testlerimize daha spesifik seçiciler eklemek gibi yerel web uygulamamızda değişiklikler yapmamız gerekir veya yeni bir özellik geliştirme sürecindeydik ve mevcut otomasyon testlerini ayarlamamız ve doğrulamamız gerekiyordu. yeni kod değişikliklerimize karşı yerel olarak geçerdi. Uygulama kodu değiştiğinde ve henüz konuşlandırılmış ortama geçmediğimizde, testlerimizi yerel web uygulamamıza karşı çalıştırmak için bu komutu kullandık. - Test etme veya hazırlama gibi belirli bir ortam (ör. https://testing.app.com veya https://staging.app.com) için dağıtılan bir uygulamaya karşı
Niye ya? Diğer zamanlarda uygulama kodu değişmez, ancak bazı aksaklıkları gidermek için test kodumuzu değiştirmemiz gerekebilir veya herhangi bir ön uç değişikliği yapmadan testleri tamamen eklemek veya silmek için kendimizi yeterince güvende hissediyoruz. Testlerimizin CICD ardışık düzenlerinde nasıl çalıştığını daha yakından simüle etmek için dağıtılan uygulamaya karşı testleri yerel olarak güncellemek veya hata ayıklamak için bu komutu yoğun bir şekilde kullandık. - Test etme veya hazırlama gibi belirli bir ortam için dağıtılmış bir uygulamaya karşı bir Docker kapsayıcısında çalıştırma
Niye ya? Bu, CICD ardışık düzenleri içindir, bu nedenle, örneğin aşamalı olarak dağıtılan uygulamaya karşı bir Docker kapsayıcısında çalıştırılacak E2E testlerini tetikleyebilir ve üretime kod dağıtmadan önce veya özel bir işlem hattında zamanlanmış test çalıştırmalarında geçtiklerinden emin olabiliriz. Bu komutları başlangıçta ayarlarken, farklı ortam değişken değerlerine sahip Docker kapsayıcılarını döndürmek için çok sayıda deneme yanılma gerçekleştirdik ve CICD sağlayıcımız Buildkite ile bağlantı kurmadan önce uygun testlerin başarıyla yürütüldüğünü test ettik.
Bunu başarmak için, her ortam yapılandırma dosyasının temel dosyayla birleşeceği ve çalıştırılması istendiği gibi özelliklerin üzerine yazılacağı veya ekleneceği şekilde, paylaşılan özelliklere ve birçok ortama özel dosyaya sahip genel bir temel yapılandırma dosyası oluşturduk. Bir temel dosyaya ihtiyaç duymadan her ortam için bir dosyamız olabilirdi, ancak bu, ortak ayarlarda çok fazla tekrara neden olur. Bunu bizim için halletmek için deepmerge
gibi bir kitaplığı kullanmayı seçtik, ancak birleştirmenin iç içe nesneler veya dizilerle her zaman mükemmel olmadığını unutmamak önemlidir. Doğru şekilde birleşmeyen yinelenen özellikler olduğunda tanımsız davranışa yol açabileceğinden, ortaya çıkan çıktı yapılandırmalarını her zaman iki kez kontrol edin.
Ortak bir temel yapılandırma dosyası oluşturduk, wdio.conf.js
, bunun gibi:
Bir ortam API'sine işaret eden yerel bir web paketi geliştirme sunucusuna karşı E2E testlerini çalıştırmaya ilişkin ilk büyük kullanım durumumuza uymak için, aşağıdaki şekilde localhost yapılandırma dosyasını wdio.localhost.conf.js
:
Temel dosyayı birleştirdiğimize ve daha kompakt ve bakımı daha kolay hale getirmek için dosyaya localhost'a özgü özellikleri eklediğimize dikkat edin. Ayrıca, farklı türde tarayıcıları, yani yetenekleri başlatmak için Selenium Bağımsız hizmetini kullanıyoruz.
Dağıtılan bir web uygulamasına karşı E2E testleri çalıştırmanın ikinci kullanım durumu için, şuna benzer şekilde test etme ve uygulama yapılandırma dosyaları 'wdio.testing.conf.js' ve wdio.staging.conf.js
:
Burada, yapılandırma dosyalarına, evreleme konusunda özel kullanıcılara oturum açma kimlik bilgileri gibi bazı ekstra ortam değişkenleri ekledik ve "baseUrl" öğesini, dağıtılan hazırlama uygulaması URL'sini gösterecek şekilde güncelledik.
CICD sağlayıcımızın alanı içinde konuşlandırılmış bir web uygulamasına karşı bir Docker kapsayıcısında E2E testleri çalıştırmanın üçüncü kullanım durumu için, CICD yapılandırma dosyalarını , wdio.cicd.testing.conf.js
ve wdio.cicd.staging.conf.js
, şöyle:
Daha sonra Selenium Chrome, Selenium Hub ve uygulama kodunu ayrı servislerde bir Docker Compose dosyasına kuracağımız için Selenium Bağımsız hizmetini artık nasıl kullanmadığımıza dikkat edin. Bu yapılandırma, testlerimizi dağıtılan hazırlama uygulamasına karşı çalıştırmayı beklediğimizden, oturum açma kimlik bilgileri ve "baseUrl" gibi hazırlama yapılandırmasıyla aynı ortam değişkenlerini de gösterir ve tek fark, bu testlerin bir Docker kapsayıcısında yürütülmesi amaçlanmış olmasıdır. .
Bu ortam yapılandırma dosyaları oluşturulduğunda, testimizin temeli olarak hizmet edecek package.json
komut dosyası komutlarını özetledik. Bu örnekte, WebdriverIO ile UI testlerini belirtmek için komutların önüne "uitest" koyduk ve test dosyalarını da *.uitest.js
ile sonlandırdık. Hazırlama ortamı için bazı örnek komutlar şunlardır:
3. Adım: E2E Testlerini Yerel Olarak Uygulama
Tüm test komutları elimizdeyken, WebdriverIO testlerine dönüştürmemiz için STUI depomuzdaki testleri inceledik. Küçük ve orta ölçekli sayfa testlerine odaklandık ve her sayfa için tüm kullanıcı arayüzünü düzenli bir şekilde kapsamak için sayfa nesnesi desenini uygulamaya başladık.
Dosyaları bir dizi yardımcı işlevle veya nesne değişmezleriyle veya başka herhangi bir stratejiyle yapılandırabilirdik, ancak anahtar, sürdürülebilir testleri hızlı bir şekilde sunmanın ve buna bağlı kalmanın tutarlı bir yolunu bulmaktı. Belirli bir sayfa için UI akışı veya DOM öğeleri değiştiyse, testlerin tekrar geçmesini sağlamak için yalnızca onunla ilgili sayfa nesnesini ve muhtemelen test kodunu yeniden düzenlememiz gerekiyordu.
Sayfa nesnesi modelini, diğer tüm sayfa nesnelerinin içinden uzanacağı paylaşılan işlevselliğe sahip bir temel sayfa nesnesine sahip olarak uyguladık. Tarayıcıda bir sayfanın URL'sini "açmak" veya ziyaret etmek için tüm sayfa nesnelerimizde tutarlı bir API sağlamak için open gibi işlevlerimiz vardı. Bunun gibi bir şeye benziyordu:
Belirli sayfa nesnelerini uygulamak, temel Page
sınıfından genişletme ve etkileşimde bulunmak veya üzerinde iddiada bulunmak istediğimiz belirli öğelere seçiciler ve sayfada eylemler gerçekleştirmek için yardımcı işlevler eklemekle aynı modeli izledi.
Sayfanın özel rotasıyla super.open(...)
aracılığıyla open temel sınıfını nasıl kullandığımıza dikkat edin, böylece bu çağrıyla sayfayı ziyaret edebiliriz, SomePage.open()
. Ayrıca, SomePage.submitButton
veya SomePage.tableRows
gibi öğelere başvurabilmemiz ve WebdriverIO komutlarıyla bu öğelerle etkileşime geçebilmemiz veya bunlar üzerinde iddiada bulunabilmemiz için zaten başlatılmış olan sınıfı dışa aktardık. Sayfa nesnesinin bir kurucuda kendi üye özellikleriyle paylaşılması ve başlatılması gerekiyorsa, sınıfı doğrudan dışa aktarabilir ve sayfa nesnesini new SomePage(...constructorArgs)
ile test dosyalarında somutlaştırabiliriz.
Sayfa nesnelerini seçiciler ve bazı yardımcı işlevlerle yerleştirdikten sonra, E2E testlerini yazdık ve genel olarak bu test formülünü modelledik:
- Gerçek testleri çalıştırmadan önce test koşullarını beklenen başlangıç noktasına sıfırlamak için gerekenleri API'yi kurun veya yıkın .
- Test için özel bir kullanıcıda oturum açın, böylece sayfaları doğrudan ziyaret ettiğimizde oturum açık kalır ve kullanıcı arayüzünden geçmek zorunda kalmazdık. Oturum açma sayfamız için kullandığımız API çağrısını yapan ve sonunda oturumu açık tutmak ve korumalı API isteklerinin başlıklarını iletmek için gereken kimlik doğrulama belirtecimizi geri döndüren bir kullanıcı adı ve parola alan basit bir
login
yardımcısı işlevi oluşturduk. Diğer şirketler, hızlı bir şekilde tohum verileri ve konfigürasyonlarla yepyeni kullanıcılar oluşturmak için daha da fazla özel dahili uç noktaya veya araca sahip olabilir, ancak ne yazık ki, bizde yeterince ayrıntılı bir tane yoktu. Bunu eski moda bir şekilde yapar ve kullanıcı arayüzü aracılığıyla farklı konfigürasyonlara sahip ortamlarımızda özel test kullanıcıları oluşturur ve kaynakların çakışmasını önlemek ve testler paralel olarak yürütüldüğünde izole kalmak için genellikle farklı kullanıcıları olan sayfalar için testleri ayırırdık. Adanmış test kullanıcılarına başkaları tarafından dokunulmadığından emin olmak zorundaydık, aksi takdirde biri bilmeden biriyle kurcaladığında testler bozulurdu. - Bir son kullanıcı özellik/sayfa ile etkileşime girecekmiş gibi adımları otomatikleştirin. Tipik olarak, özellik akışımızı tutan sayfayı ziyaret eder ve son kullanıcının girişleri doldurma, düğmelere tıklama, modal veya banner'ların görünmesini bekleme ve değişen çıktılar için tabloları gözlemleme gibi üst düzey adımları izlemeye başlardık. eylemin bir sonucudur. Kullanışlı sayfa nesnelerimizi ve seçicilerimizi kullanarak, her adımı hızlı bir şekilde uyguladık ve yol boyunca akıl sağlığı kontrolleri olarak, belirli şeylerin beklendiği gibi davrandığından emin olmak için özellik akışı sırasında kullanıcının sayfada ne görmesi veya görmemesi gerektiği konusunda iddiada bulunduk. her adımdan önce ve sonra. Ayrıca yüksek değerli mutlu yol testleri ve bazen kolayca tekrarlanabilen yaygın hata durumlarını seçme konusunda bilinçliydik, alt seviye testlerinin geri kalanını birim ve entegrasyon testlerine erteledik.
İşte E2E testlerimizin genel düzeninin kaba bir örneği (bu strateji, denediğimiz diğer test çerçevelerine de uygulandı):
Ek bir not olarak, bu blog gönderisi dizisinde WebdriverIO ve E2E en iyi uygulamalarına ilişkin tüm ipuçlarını ve elde edilenleri ele almamayı seçtik, ancak bu konular hakkında gelecekteki bir blog gönderisinde konuşacağız, bu yüzden bizi izlemeye devam edin!
Adım 4: Tüm Testleri Dockerize Etme
Buluttaki yeni bir AWS makinesinde her Buildkite ardışık düzen adımını yürütürken, bu makinelerde Düğüm, tarayıcılar, uygulama kodumuz veya testleri gerçekten çalıştırmak için başka herhangi bir bağımlılık olmadığından, basitçe "npm run uitests:staging" komutunu çağıramadık. .
Bunu çözmek için, WebdriverIO testlerinin başarılı bir şekilde çalışması için Node, Selenium, Chrome ve uygulama kodu gibi tüm bağımlılıkları bir Docker kapsayıcısında topladık. Dockerfiles
ve docker-compose.yml
dosyalarına çevrilen tüm hizmetleri başlatmak ve çalıştırmak için gereken tüm hizmetleri bir araya getirmek için Docker ve Docker Compose'dan yararlandık ve işlerin yürümesi için Docker kapsayıcılarını yerel olarak döndürmeyle ilgili birçok deneme yaptık.
Daha fazla bağlam sağlamak için Docker'da uzman değildik, bu yüzden her şeyi nasıl bir araya getireceğimizi anlamak epey zaman aldı. WebdriverIO testlerini Dockerize etmenin birden çok yolu vardır ve birçok farklı hizmeti birlikte düzenlemeyi ve işler yolunda gidene kadar değişen Docker görüntüleri, Compose sürümleri ve öğreticileri gözden geçirmeyi zor bulduk.
Ekiplerimizin yapılandırmalarından biriyle eşleşen, çoğunlukla ayrıntılı dosyaları göstereceğiz ve bunun, sizin veya Selenium'u Dockerize Etme tabanlı testlerin genel sorunuyla uğraşan herkes için içgörü sağlayacağını umuyoruz.
Yüksek düzeyde, testlerimiz aşağıdakileri talep etti:
- Selenium , bir tarayıcıya karşı komutları yürütmek ve onunla iletişim kurmak için. İsteğe bağlı olarak birden çok örneği döndürmek için Selenium Hub'ı kullandık ve
selenium-hub
hizmeti için "selenium/hub" görüntüsünü docker-compose dosyasına indirdik. - Karşı çalıştırılacak bir tarayıcı . Selenium Chrome örneklerini getirdik ve
docker-compose.yml file
selenium-chrome
hizmeti için “selenium/node-chrome-debug” imajını yükledik. - Test dosyalarımızı kurulu diğer Node modülleriyle çalıştırmak için uygulama kodu . Npm paketlerini yüklemek ve
package.json
betiklerini çalıştırmak, test kodunu kopyalamak vedocker-compose.yml
dosyasındauitests
adlı test dosyalarını çalıştırmaya adanmış bir hizmet atamak için Node ile bir ortam sağlamak için yeni birDockerfile
oluşturduk.
WebdriverIO testlerini çalıştırmak için gerekli tüm uygulamamız ve test kodlarımızla bir hizmet getirmek için Dockerfile
adında bir Dockerfile.uitests
ve tüm node_modules
ve kodu bir Node ortamında görüntünün çalışma dizinine kopyaladık. Bu, uitests
Docker Compose hizmetimiz tarafından kullanılacaktı ve Dockerfile
kurulumunu aşağıdaki şekilde başardık:
WebdriverIO testlerinin çalışması için Selenium Hub, Chrome tarayıcı ve uygulama test kodunu bir araya getirmek için, docker-compose.uitests.yml
dosyasında Selenium selenium-hub
, Selenium selenium-chrom
e ve uitest
s servislerini özetledik. :
Selenium Hub ve Chrome görüntülerini ortam değişkenleri, depends_on
ve bağlantı noktalarını hizmetlere göstererek bağladık. Test uygulama kodu resmimiz, sonunda yukarı itilecek ve yönettiğimiz özel bir Docker kayıt defterinden çekilecektir.
CICD sırasında test kodu için Docker görüntüsünü, VERSION
ve PIPELINE_SUFFIX
gibi belirli ortam değişkenleriyle, görüntülere bir etiket ve daha özel adla başvurmak için oluştururduk. Ardından Selenium hizmetlerini başlatır ve WebdriverIO testlerini yürütmek için uitests
hizmeti aracılığıyla komutları yürütürdük.
Docker Compose dosyalarımızı oluştururken, görüntülerimizin uygun konfigürasyonlara sahip olduğunu ve Buildkite ile entegrasyondan önce sorunsuz çalıştığını yerel olarak test etmek için makinelerimizde yüklü olan Mac Docker ile docker-compose up
ve docker-compose down
gibi yardımcı komutlardan yararlandık. Etiketlenmiş görüntüleri oluşturmak, onları kayıt defterine göndermek, aşağı çekmek ve testleri ortam değişkeni değerlerine göre çalıştırmak için gereken tüm komutları belgeledik.
Adım 5: CICD ile Entegrasyon
Çalışan Docker komutlarını kurduktan ve testlerimiz bir Docker kapsayıcısında farklı ortamlarda başarılı bir şekilde çalıştıktan sonra, CICD sağlayıcımız Buildkite ile entegrasyona başladık.
Buildkite, depomuzun ardışık düzeni için kod veya Buildkite ayarları kullanıcı arabirimi aracılığıyla ayarlanan Bash komut dosyaları ve ortam değişkenleriyle AWS makinelerimizde bir .yml
dosyasındaki adımları yürütmenin yollarını sağladı.
Buildkite ayrıca, dışa aktarılan ortam değişkenleriyle ana dağıtım hattımızdan bu test hattını tetiklememize izin verdi ve bu test adımlarını, QA'larımızın izlemesi ve bakması için bir programda çalışacak diğer izole test boru hatları için yeniden kullanırdık.
Yüksek düzeyde, WebdriverIO ve sonraki Cypress için test Buildkite işlem hatlarımız aşağıdaki benzer adımları paylaştı:
- Docker görüntülerini ayarlayın . Testler için gereken Docker görüntülerini derleyin, etiketleyin ve daha sonraki bir adımda indirebilmemiz için kayıt defterine iletin.
- Ortam değişkeni yapılandırmalarına dayalı testleri çalıştırın . Belirli yapı için etiketli Docker görüntülerini aşağı çekin ve ayarlanmış ortam değişkenlerinden seçilen test takımlarını çalıştırmak için konuşlandırılmış bir ortama karşı uygun komutları yürütün.
Burada, "UITests Docker Görüntüsü Oluştur" adımında Docker görüntülerinin ayarlanmasını ve "Web sürücüsü testlerini Chrome'a karşı çalıştır" adımında testleri çalıştırmayı gösteren bir pipeline.uitests.yml
dosyasının yakın bir örneği verilmiştir:
Dikkat edilmesi gereken bir şey, ilk adım olan "UITests Docker Görüntüsü Oluştur" ve test için Docker görüntülerini nasıl kurduğudur. Tüm uygulama test koduyla uitests
hizmetini oluşturmak için Docker Compose build
komutunu kullandı ve onu latest
ve ${VERSION}
ortam değişkeni ile etiketledi, böylece gelecekte aynı görüntüyü bu derleme için uygun etiketle indirebiliriz. adım.
Her adım, AWS bulutunda bir yerde farklı bir makinede yürütülebilir, bu nedenle etiketler, belirli Buildkite çalışması için görüntüyü benzersiz şekilde tanımlar. Görüntüyü etiketledikten sonra, yeniden kullanılmak üzere en son ve sürüm etiketli görüntüyü özel Docker kayıt defterimize yükledik.
"Webdriver testlerini Chrome'a karşı çalıştır" adımında ilk adımda oluşturduğumuz, etiketlediğimiz ve ittiğimiz imajı aşağı çekiyoruz ve Selenium Hub, Chrome ve test servislerini başlatıyoruz. $UITESTENV
ve $UITESTSUITE
gibi ortam değişkenlerine dayanarak, npm run uitest:
gibi çalıştırılacak komut türünü ve --suite $UITESTSUITE
gibi bu belirli Buildkite derlemesi için çalıştırılacak test takımlarını seçer ve seçerdik.
Bu ortam değişkenleri, Buildkite ardışık düzen ayarları aracılığıyla belirlenir veya hangi test takımlarının hangi ortama karşı çalıştırılacağını belirlemek için bir Buildkite seçim alanını ayrıştıran bir Bash betiğinden dinamik olarak tetiklenir.
Burada, aynı pipeline.uitests.yml
düzen.uitests.yml dosyasını yeniden kullanan ancak ardışık düzenin tetiklendiği ortam değişkenleri ayarlanmış olan özel bir test işlem hattında tetiklenen WebdriverIO testlerine bir örnek verilmiştir. Bu derleme başarısız oldu ve Artifacts
sekmesine ve Logs
sekmesi altındaki konsol çıktısına bakmamız için hata ekran görüntüleri vardı. pipeline.uitests.yml
(https://Gist.github.com/alfredlucero/71032a82f3a72cb2128361c08edbcff2#file-pipeline-uitests-yml-L38) içindeki artifact_paths
, 'wdio.conf.js'de 'mochawesome' için ekran görüntüsü ayarlarını hatırlayın. ' dosyası (https://Gist.github.com/alfredlucero/4ee280be0e0674048974520b79dc993a#file-wdio-conf-js-L39) ve 'docker-compose.uitests.yml' içindeki 'uitests' hizmetindeki birimlerin montajı (https://Gist.github.com/alfredlucero/d2df4533a4a49d5b2f2c4a0eb5590ff8#file-docker-compose-yml-L32)?
Doğrudan indirmemiz ve aşağıda gösterildiği gibi hata ayıklama testlerine yardımcı olmak için hemen görmemiz için Buildkite UI aracılığıyla erişilebilecek ekran görüntülerini bağlayabildik.
Buildkite ardışık düzen ayarlarında önceden yapılandırılmış ortam değişkenleri dışında, pipeline.uitests.yml
hattı.uitests.yml dosyasını kullanan belirli bir sayfa için bir zamanlamada ayrı bir ardışık düzende çalışan WebdriverIO testlerinin başka bir örneği, altta görüntülenir.
Her CICD sağlayıcısının, belirli sözdizimli .yml
dosyaları, GUI ayarları, Bash komut dosyaları veya başka herhangi bir yolla yeni kodda birleştirirken adımları bir tür dağıtım sürecine entegre etmek için farklı işlevselliklere ve yöntemlere sahip olduğunu unutmamak önemlidir.
Jenkins'ten Buildkite'a geçtiğimizde, ekiplerin kendi kod tabanlarında kendi ardışık düzenlerini tanımlama, talep üzerine ölçeklendirme makineleri arasında adımları paralelleştirme ve okunması daha kolay komutlar kullanma becerisini büyük ölçüde geliştirdik.
Kullanabileceğiniz CICD sağlayıcısından bağımsız olarak, testleri entegre etme stratejileri, Docker görüntülerini ayarlamada ve taşınabilirlik ve esneklik için ortam değişkenlerine dayalı testleri çalıştırmada benzer olacaktır.
WebdriverIO ile ödünleşimler
Önemli sayıda özel Ruby Selenium çözüm testini WebdriverIO testlerine dönüştürdükten ve Docker ve Buildkite ile entegre ettikten sonra, bazı alanlarda gelişme kaydettik, ancak yine de eski sisteme benzer mücadeleler hissettik ve bu da bizi Cypress ile bir sonraki ve son durağımıza götürdü. E2E test çözümümüz.
Özel Ruby Selenium çözümüne kıyasla WebdriverIO deneyimlerimizden bulduğumuz bazı profesyonellerin listesi:
- Testler, Ruby yerine tamamen JavaScript veya TypeScript ile yazılmıştır . Bu, diller arasında daha az bağlam geçişi ve E2E testleri yazdığımız her seferde Ruby'yi yeniden öğrenmek için daha az zaman harcanması anlamına geliyordu.
- Testleri, Ruby paylaşımlı bir depoda değil, uygulama koduyla bir araya getirdik. Artık diğer ekiplerin testlerinin başarısız olmasına bağımlı hissetmedik ve depolarımızdaki özelliklerimiz için E2E testlerini daha doğrudan sahiplendik.
- Tarayıcılar arası test seçeneğini takdir ettik . WebdriverIO ile, Chrome, Firefox ve IE gibi farklı yeteneklere veya tarayıcılara karşı testleri hızlandırabildik, ancak kullanıcılarımızın %80'inden fazlası Chrome aracılığıyla uygulamamızı ziyaret ettiğinden, esas olarak testlerimizi Chrome'a karşı çalıştırmaya odaklandık.
- Üçüncü taraf hizmetleriyle entegrasyon olanağını değerlendirdik . WebdriverIO belgeleri, uygulamamızı tüm cihazlarda ve tarayıcılarda kapsamaya yardımcı olmak için BrowserStack ve SauceLabs gibi üçüncü taraf hizmetlerle nasıl entegre edileceğini açıkladı.
- Kendi test çalıştırıcımızı, muhabirimizi ve hizmetlerimizi seçme esnekliğine sahiptik . WebdriverIO, ne kullanılacağı konusunda kuralcı değildi, bu nedenle her ekip Mocha ve Chai veya Jest ve diğer hizmetler gibi şeyleri kullanıp kullanmama konusunda karar verme özgürlüğüne sahipti. Bu, takımların birbirlerinin düzeninden uzaklaşmaya başlaması ve bizim seçeceğimiz seçeneklerin her birini denememiz için önemli miktarda zaman alması nedeniyle bir dolandırıcılık olarak da yorumlanabilir.
- WebdriverIO API'si, CLI ve belgeler, testler yazmak ve Docker ve CIC D ile entegre olmak için yeterince kullanışlıydı . Birçok farklı yapılandırma dosyamız olabilir, özellikleri gruplayabilir, komut satırı aracılığıyla testler yürütebilir ve sayfa nesne kalıbını izleyerek testler yazabiliriz. Bununla birlikte, belgeler daha net olabilirdi ve bir sürü garip hatayı araştırmak zorunda kaldık. Yine de, testlerimizi Ruby Selenium çözümünden dönüştürebildik.
Önceki Ruby Selenium çözümünde eksik olduğumuz birçok alanda ilerleme kaydettik, ancak aşağıdaki gibi WebdriverIO ile tam anlamıyla ilerlememizi engelleyen birçok gösterici ile karşılaştık:
- WebdriverIO hala Selenium tabanlı olduğundan, eski Ruby Selenium çözümümüzle bize olumsuz geri dönüşleri hatırlatan birçok garip zaman aşımı, çökme ve hata yaşadık. Bazen, sayfadaki birçok öğeyi seçtiğimizde testlerimiz tamamen çökebilir ve testler istediğimizden daha yavaş çalışır. Testler yazarken birçok Github sorunu aracılığıyla geçici çözümler bulmamız veya belirli metodolojilerden kaçınmamız gerekiyordu.
- Genel geliştirici deneyimi yetersizdi . Belgeler, komutlara bazı üst düzey genel bakış sağladı, ancak onu kullanmanın tüm yollarını açıklamak için yeterli örnek vermedi. Ruby ile E2E testleri yazmaktan kaçındık ve sonunda JavaScript veya TypeScript'te testler yazabildik, ancak WebdriverIO API ile uğraşmak biraz kafa karıştırıcıydı. Bazı yaygın örnekler, tekil ve çoğul öğeler için
$
ve$$
kullanımı, bir öğenin görünmemesini beklemek için$('...').waitForVisible(9000, true)
ve diğer sezgisel olmayan komutlardır. Bir sürü lapa lapa seçiciyle karşılaştık ve her şey için açıkça$(...).waitForVisible()
yapmak zorunda kaldık. - Hata ayıklama testleri, geliştiriciler ve QA'lar için son derece acı verici ve sıkıcıydı. Whenever tests failed, we only had screenshots, which would often be blank or not capturing the right moment for us to deduce what went wrong, and vague console error messages that did not point us in the right direction of how to solve the problem and even where the issue occurred. We often had to re-run the tests many times and stare closely at the Chrome browser running the tests to hopefully put things together as to where in the code our tests failed. We used things like
browser.debug()
but it often did not work or did not provide enough information. We gradually gathered a bunch of console error messages and mapped them to possible solutions over time but it took lots of pain and headache to get there. - WebdriverIO tests were tough to set up with Docker . We struggled with trying to incorporate it into Docker as there were many tutorials and ways to do things in articles online, but it was hard to figure out a way that worked in general. Hooking up 2 to 3 services together with all these configurations led to long trial and error experiments and the documentation did not guide us enough in how to do that.
- Choosing the test runner, reporter, assertions, and services demanded lots of research time upfront . Since WebdriverIO was flexible enough to allow other options, many teams had to spend plenty of time to even have a solid WebdriverIO infrastructure after experimenting with a lot of different choices and each team can have a completely different setup that doesn't transfer over well for shared knowledge and reuse.
To summarize our WebdriverIO and STUI comparison, we analyzed the overall developer experience (related to tools, writing tests, debugging, API, documentation, etc.), test run times, test passing rates, and maintenance as displayed in this table:
Moving On to Cypress
At the end of the day, our WebdriverIO tests were still flaky and tough to maintain. More time was still spent debugging tests in dealing with weird Selenium issues, vague console errors, and somewhat useful screenshots than actually reaping the benefits of seeing tests fail for when the backend or frontend encountered issues.
We appreciated cross-browser testing and implementing tests in JavaScript, but if our tests could not pass consistently without much headache for even Chrome, then it became no longer worth it and we would then simply have a STUI 2.0.
With WebdriverIO we still strayed from the crucial aspect of providing a way to write consistent, debuggable, maintainable, and valuable E2E automation tests for our frontend applications in our original goal. Overall, we learned a lot about integrating with Buildkite and Docker, using page objects, and outlining tests in a structured way that will transfer over to our final solution with Cypress.
If we felt it was necessary to run our tests in multiple browsers and against various third-party services, we could always circle back to having some tests written with WebdriverIO, or if we needed something fully custom, we would revisit the STUI solution.
Ultimately, neither solution met our main goal for E2E tests, so follow us on our journey in how we migrated from STUI and WebdriverIO to Cypress in part 2 of the blog post series.