Extjs kodunu bir tarayıcıda, tercihen selenyum ile test etmek için herhangi bir öneriniz var mı?


92

Üst düzey web sitesi testlerini yürütmek için büyük bir başarıyla selenyum kullanıyoruz (modül düzeyinde kapsamlı python belge testlerine ek olarak). Ancak şimdi birçok sayfa için extj kullanıyoruz ve ızgaralar gibi karmaşık bileşenler için Selenium testlerini dahil etmenin zor olduğu görülüyor.

Extjs tabanlı web sayfaları için otomatik testler yazmada başarılı olan var mı? Pek çok Google, benzer sorunları olan insanları bulur, ancak çok az yanıtı vardır. Teşekkürler!


Ext JS'deki iyi insanlar, bu konuyu buradaki bloglarında yayınlayacak kadar nazik davrandılar . Umarım bu yardımcı olur.
NBRed5

Yanıtlar:


173

ExtJS'yi Selenium ile test etmedeki en büyük engel, ExtJS'nin standart HTML öğelerini oluşturmaması ve Selenium IDE'nin saf bir şekilde (ve haklı olarak) yalnızca dekor görevi gören öğeleri hedefleyen komutlar oluşturmasıdır - ExtJS'ye tüm masaüstünde yardımcı olan gereksiz öğeler - bak ve hisset. İşte bir ExtJS uygulamasına karşı otomatik Selenium testi yazarken topladığım birkaç ipucu ve püf noktası.

Genel ipuçları

Öğeleri Bulma

Firefox'ta Selenium IDE ile kullanıcı eylemlerini kaydederek Selenium test senaryoları oluştururken, Selenium kaydedilen eylemleri HTML öğelerinin kimliklerine dayandıracaktır. Bununla birlikte, çoğu tıklanabilir öğe için, ExtJS, kod değişikliği yapılmamış olsa bile, aynı sayfaya sonraki bir ziyarette büyük olasılıkla değişebilecek "ext-gen-345" gibi oluşturulmuş kimlikleri kullanır. Bir test için kullanıcı eylemlerini kaydettikten sonra, oluşturulan kimliklere bağlı olan bu tür tüm eylemlerin üzerinden geçmek ve bunları değiştirmek için manuel bir çaba gösterilmesi gerekir. Yapılabilecek iki tür değiştirme vardır:

Bir Kimlik Bulucuyu bir CSS veya XPath Bulucu ile Değiştirme

CSS bulucuları "css =" ile başlar ve XPath yer belirleyicileri "//" ile başlar ("xpath =" öneki isteğe bağlıdır). CSS bulucuları daha az ayrıntılıdır ve okunması daha kolaydır ve XPath buluculara göre tercih edilmelidir. Ancak, bir CSS bulucu tarafından kesilemediği için XPath konumlandırıcılarının kullanılması gereken durumlar olabilir.

JavaScript Yürütme

ExtJS tarafından gerçekleştirilen karmaşık oluşturma nedeniyle bazı öğeler basit fare / klavye etkileşimlerinden daha fazlasını gerektirir. Örneğin, Ext.form.CombBox gerçekten bir <select>öğe değil, belge ağacının altında bir yerde bulunan ayrı bir açılır listeye sahip bir metin girişidir. Bir ComboBox seçimini düzgün bir şekilde simüle etmek için, önce açılır oka bir tıklamayı simüle etmek ve ardından görünen listeyi tıklamak mümkündür. Ancak, bu öğeleri CSS veya XPath konumlandırıcıları aracılığıyla bulmak zahmetli olabilir. Bir alternatif, ComoBox bileşeninin kendisini bulmak ve seçimi simüle etmek için üzerinde yöntemler çağırmaktır:

var combo = Ext.getCmp('genderComboBox'); // returns the ComboBox components
combo.setValue('female'); // set the value
combo.fireEvent('select'); // because setValue() doesn't trigger the event

Selenium'da runScriptkomut, yukarıdaki işlemi daha kısa bir biçimde gerçekleştirmek için kullanılabilir:

with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); }

AJAX ile Başa Çıkma ve Yavaş Oluşturma

Selenium, bir kullanıcı eylemi sayfa geçişlerine veya yeniden yüklemelere neden olduğunda sayfa yüklemelerini beklemeye yönelik tüm komutlar için "* AndWait" aromalarına sahiptir. Bununla birlikte, AJAX getirmeleri gerçek sayfa yüklemelerini içermediğinden, bu komutlar senkronizasyon için kullanılamaz. Çözüm, AJAX ilerleme göstergesinin varlığı / yokluğu veya bir ızgaradaki satırların görünümü, ek bileşenler, bağlantılar vb. Gibi görsel ipuçlarından yararlanmaktır. Örneğin:

Command: waitForElementNotPresent
Target: css=div:contains('Loading...')

Bazen bir öğe, bir kullanıcı eylemi bir görünüm değişikliğine neden olduktan sonra ExtJS'nin bileşenleri ne kadar hızlı işlediğine bağlı olarak yalnızca belirli bir süre sonra görünecektir. Komutla keyfi gecikmeler kullanmak yerine pauseideal yöntem, ilgi unsurunun bizim kavrayışımıza girmesini beklemektir. Örneğin, görünmesini bekledikten sonra bir öğeye tıklamak için:

Command: waitForElementPresent
Target: css=span:contains('Do the funky thing')
Command: click
Target: css=span:contains('Do the funky thing')

Testlerin farklı tarayıcılarda veya farklı makinelerde çalıştırılmasından kaynaklanan zamanlama farklılıkları test senaryolarını kesintiye uğratacağından, rastgele duraklamalara güvenmek iyi bir fikir değildir.

Tıklanamayan Öğeler

Bazı öğeler clickkomutla tetiklenemez . Bunun nedeni, olay dinleyicisinin aslında kapsayıcıda olması, alt öğelerindeki fare olaylarını izlemesi ve sonunda ana öğeye kadar köpürtülmesidir. Sekme kontrolü bir örnektir. Bir sekmeyi tıklamak için mouseDown, sekme etiketinde bir etkinliği simüle etmeniz gerekir :

Command: mouseDownAt
Target: css=.x-tab-strip-text:contains('Options')
Value: 0,0

Alan Doğrulama

Doğrulama için ilişkili normal ifadelere veya vtiplere sahip olan form alanları (Ext.form. * Bileşenleri) validationDelay, kullanıcı metni girdikten sonra veya alan kaybettiğinde belirli bir gecikmeyle ( varsayılan olarak 250 ms'ye ayarlanan özelliğe bakın) doğrulamayı tetikler. odak - veya bulanıklaştırır ( validateOnDelayözelliğe bakın ). Bir alana bir metin girmek üzere Selenium türü komutunu verdikten sonra alan doğrulamasını tetiklemek için aşağıdakilerden birini yapmanız gerekir:

  • Gecikmeli Doğrulamayı Tetikleme

    Alan anahtar oluşturma olaylarını aldığında ExtJS doğrulama gecikme zamanlayıcısını kapatır. Bu zamanlayıcıyı tetiklemek için, basit bir kukla anahtarlama olayı yayınlayın (ExtJS bunu göz ardı ettiği için hangi anahtarı kullandığınız önemli değildir), ardından validationDelay'den daha uzun kısa bir duraklama:

    Command: keyUp
    Target: someTextArea
    Value: x
    Command: pause
    Target: 500
    
  • Anında Doğrulamayı Tetikleme

    Anında doğrulamayı tetiklemek için alana bir bulanıklık olayı enjekte edebilirsiniz:

    Command: runScript
    Target: someComponent.nameTextField.fireEvent("blur")
    

Doğrulama Sonuçlarını Kontrol Etme

Doğrulamanın ardından, bir hata alanının olup olmadığını kontrol edebilirsiniz:

Command: verifyElementNotPresent   
Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))]

Command: verifyElementPresent   
Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))]

"Display: none" kontrolünün gerekli olduğuna dikkat edin, çünkü bir hata alanı gösterildikten sonra gizlenmesi gerekir, ExtJS hata alanını DOM ağacından tamamen kaldırmak yerine gizleyecektir.

Öğeye Özgü İpuçları

Bir Dahili Form Düğmesine Tıklama

  • seçenek 1

    Komut: Hedefi tıklayın: css = button: içerir ('Kaydet')

    Düğmeyi başlığıyla seçer

  • seçenek 2

    Komut: Hedefe tıklayın: css = # kaydetme seçenekleri düğmesi

    Düğmeyi kimliğine göre seçer

Ext.form.ComboBox'tan Değer Seçme

Command: runScript
Target: with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); }

Öncelikle değeri ayarlar ve ardından gözlemci olması durumunda select olayını açıkça tetikler.



5

Bu blog bana çok yardımcı oldu. Konu hakkında oldukça fazla şey yazdı ve hala aktif gibi görünüyor. Adam ayrıca iyi tasarımı takdir ediyor gibi görünüyor.

Temel olarak sorgu yapmak için javascript göndermekten ve dahili olarak dahili uygulamanızda yaptığınız gibi şeyleri geri almak için Ext.ComponentQuery.query yöntemini kullanmaktan bahsediyor. Bu şekilde, xtypes ve itemIds'ı kullanabilirsiniz ve otomatik olarak oluşturulan çılgın şeylerin herhangi birini ayrıştırmaya çalışmaktan endişelenmenize gerek kalmaz.

Bu makaleyi özellikle çok yararlı buldum .

Yakında burada biraz daha ayrıntılı bir şey yayınlayabilirim - yine de bunu nasıl düzgün bir şekilde yapacağımı anlamaya çalışıyorum


4

ExtJs web uygulamamı selenyum ile test ediyorum. En büyük sorunlardan biri, onunla bir şeyler yapmak için ızgaradaki bir öğeyi seçmekti.

Bunun için helper yöntemini yazdım (ExtJ'ler ile daha kolay etkileşim için yararlı yöntemler koleksiyonu olan SeleniumExtJsUtils sınıfında):

/**
 * Javascript needed to execute in order to select row in the grid
 * 
 * @param gridId Grid id
 * @param rowIndex Index of the row to select
 * @return Javascript to select row
 */
public static String selectGridRow(String gridId, int rowIndex) {
    return "Ext.getCmp('" + gridId + "').getSelectionModel().selectRow(" + rowIndex + ", true)";
}

ve bir satır seçmem gerektiğinde, arardım:

selenium.runScript( SeleniumExtJsUtils.selectGridRow("<myGridId>", 5) );

Bunun çalışması için kimliğimi şebekede ayarlamam ve ExtJ'lerin kendi kimliğini oluşturmasına izin vermemeliyim.


Ext.ComponentQuery.query'de xtype'ı kullanarak ızgarayı bulabilmeniz gerekir (ızgaradan genişlettiğinizi ve kendi ızgaranız için xtype'ı tanımladığınızı varsayarak) Bu konuda daha aşağıya bazı şeyler koydum. Ayrıca, bir satır için tanımlayıcı bir değer içeren td'yi bulmak için xpath kullanarak öğelere tıklayabileceğinizi de buldum
td'yi JonnyRaa

4

Bu elemanın görünür olduğunu tespit etmek için cümleci kullanırsınız: not(contains(@style, "display: none")

Bunu kullanmak daha iyi:

visible_clause = "not(ancestor::*[contains(@style,'display: none')" +
    " or contains(@style, 'visibility: hidden') " + 
    " or contains(@class,'x-hide-display')])"

hidden_clause = "parent::*[contains(@style,'display: none')" + 
    " or contains(@style, 'visibility: hidden')" + 
    " or contains(@class,'x-hide-display')]"

3

Extjs testi ile yaşadığınız problem türleri hakkında daha fazla bilgi verebilir misiniz?

Yararlı bulduğum bir Selenium uzantısı waitForCondition . Sorununuz Ajax olaylarıyla ilgili bir sorun gibi görünüyorsa, olayların gerçekleşmesini beklemek için waitForCondition'ı kullanabilirsiniz.


3

Ext JS web sayfalarını, Ext JS ızgaralarında olduğu gibi oluşturdukları karmaşık HTML nedeniyle test etmek zor olabilir.

HTML5 Robot , dinamik olmayan özniteliklere ve koşullara dayalı olarak bileşenlerin güvenilir bir şekilde nasıl aranacağına ve etkileşime gireceğine yönelik bir dizi en iyi uygulamayı kullanarak bununla ilgilenir. Daha sonra, etkileşime girmeniz gereken tüm HTML, Ext JS ve Sencha Touch bileşenleri ile bunu yapmak için kısayollar sağlar. 2 çeşittir:

  1. Java - Tüm modern tarayıcılar için yerleşik web sürücüsü desteğine sahip tanıdık Selenium ve JUnit tabanlı API.
  2. Gwen - Kendi entegre geliştirme ortamıyla birlikte gelen tarayıcı testlerini hızlı ve kolay bir şekilde oluşturmak ve sürdürmek için insan tarzı bir dil. Bunların tümü Java API'ye dayanmaktadır.

Örneğin, "Foo" metnini içeren Ext JS ızgara satırını bulmak istiyorsanız, Java'da aşağıdakileri yapabilirsiniz:

findExtJsGridRow("Foo");

... ve Gwen'de şunları yapabilirsiniz:

extjsgridrow by text "Foo"

Ext JS'ye özgü bileşenlerle nasıl çalışılacağına dair hem Java hem de Gwen için çok sayıda belge vardır . Dokümantasyon ayrıca, tüm bu Ext JS bileşenleri için ortaya çıkan HTML'yi de ayrıntılarıyla açıklamaktadır, bu da sizin de yararlı olabilir.


2

Sayfadaki ızgara kimliği aracılığıyla ızgara getirme için yararlı ipuçları: Bu API'den daha kullanışlı işlevi genişletebileceğinizi düşünüyorum.

   sub get_grid_row {
        my ($browser, $grid, $row)  = @_;


        my $script = "var doc = this.browserbot.getCurrentWindow().document;\n" .
            "var grid = doc.getElementById('$grid');\n" .
            "var table = grid.getElementsByTagName('table');\n" .
            "var result = '';\n" .
            "var row = 0;\n" . 
            "for (var i = 0; i < table.length; i++) {\n" .
            "   if (table[i].className == 'x-grid3-row-table') {\n".
            "       row++;\n" . 
            "       if (row == $row) {\n" .
            "           var cols_len = table[i].rows[0].cells.length;\n" .
            "           for (var j = 0; j < cols_len; j++) {\n" .
            "               var cell = table[i].rows[0].cells[j];\n" .
            "               if (result.length == 0) {\n" .
            "                   result = getText(cell);\n" .
            "               } else { \n" .
            "                   result += '|' + getText(cell);\n" .
            "               }\n" .
            "           }\n" .
            "       }\n" .
            "   }\n" .
            "}\n" .
            "result;\n";

        my $result = $browser->get_eval($script);
        my @res = split('\|', $result);
        return @res;
    }

2

Özel HTML veri özellikleriyle daha kolay test

Gönderen Sencha belgelerinde :

Bir itemId, herhangi bir nesne referansı olmadığında bir bileşene referans almanın alternatif bir yolu olarak kullanılabilir. Ext.getCmp ile bir kimlik kullanmak yerine, Ext.container.Container.getComponent ile itemId kullanın, bu da itemId'leri veya id'leri alır. İtemId'ler, kapsayıcının dahili MixedCollection indeksi olduğundan, itemId kapsamı yerel olarak kapsayıcıya göre ayarlanır; böylece Ext.ComponentManager ile benzersiz bir kimlik gerektiren olası çakışmalar önlenir.

Ext.AbstractComponent'In onBoxReadyyöntemini geçersiz kılarak , eğer varsa testIdAttrbileşenin itemIddeğerine özel bir veri özniteliği (adı her bileşenin özel özelliğinden gelen) ayarlıyorum . Ekle Testing.overrides.AbstractComponentsizin için sınıf application.jsdosyasının requiresdizisi.

/**
 * Overrides the Ext.AbstracComponent's onBoxReady
 * method to add custom data attributes to the
 * component's dom structure.
 *
 * @author Brian Wendt
 */
Ext.define('Testing.overrides.AbstractComponent', {
  override: 'Ext.AbstractComponent',


  onBoxReady: function () {
    var me = this,
      el = me.getEl();


    if (el && el.dom && me.itemId) {
      el.dom.setAttribute(me.testIdAttr || 'data-selenium-id', me.itemId);
    }


    me.callOverridden(arguments);
  }
});

Bu yöntem, geliştiricilere kodlarında açıklayıcı bir tanımlayıcıyı yeniden kullanmanın ve bu tanımlayıcıların sayfa her oluşturulduğunda kullanılabilir olmasını sağlamanın bir yolunu sağlar. Artık açıklayıcı olmayan, dinamik olarak oluşturulmuş kimlikler arasında arama yapmaya gerek yok.


2

Selenyum kullanan ve extj'lerle ilgili sorunlarla karşılaşan bir test çerçevesi geliştiriyoruz (çünkü istemci tarafında oluşturma). DOM hazır olduğunda bir öğeyi aramayı yararlı buluyorum.

public static boolean waitUntilDOMIsReady(WebDriver driver) {
    def maxSeconds = DEFAULT_WAIT_SECONDS * 10
    for (count in 1..maxSeconds) {
        Thread.sleep(100)
        def ready = isDOMReady(driver);
        if (ready) {
            break;
        }
    }
}

public static boolean isDOMReady(WebDriver driver){
    return driver.executeScript("return document.readyState");
}

1

Resmi HTML olmayan karmaşık UI için xPath her zaman güvenebileceğiniz bir şeydir, ancak ExtJ'leri kullanan farklı UI uygulamaları söz konusu olduğunda biraz karmaşıktır.

Belirli bir elemanın xpath'ini test etmek için Firebug ve Firexpath'i firefox uzantıları olarak kullanabilir ve tam xpath'i parametre olarak selenyum'a geçirebilirsiniz.

Örneğin java kodunda:

String fullXpath = "xpath=//div[@id='mainDiv']//div[contains(@class,'x-grid-row')]//table/tbody/tr[1]/td[1]//button"

selenium.click(fullXpath);

1

ExtJS uygulamasını WebDriver kullanarak test ederken bir sonraki yaklaşımı kullandım: Alanı etiketin metnine göre aradım ve @foretiketten öznitelik aldım . Örneğin, bir etiketimiz var

<label id="dynamic_id_label" class="TextboxLabel" for="textField_which_I_am_lloking_for">
Name Of Needed Label
<label/>

Ve WebDriver'a bazı girdiler göstermemiz gerekiyor: //input[@id=(//label[contains(text(),'Name Of Needed Label')]/@for)] .

Böylece, @foröznitelikten kimliği seçecek ve onu daha fazla kullanacaktır. Bu muhtemelen en basit durumdur, ancak size öğeyi bulmanız için bir yol sunar. Etiketiniz olmadığında bu çok daha zordur, ancak sonra bazı elementler bulmanız ve xpath'inizi kardeşler, iniş / çıkış elementleri arayarak yazmanız gerekir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.