WebDriver tıklaması () ve JavaScript tıklaması ()


127

Hikaye:

Burada StackOverflow'da, selenium WebDriver "tıklama" komutuyla bir öğeyi tıklayamayacaklarını ve bir komut dosyası çalıştırarak bir JavaScript tıklamasıyla bunun üstesinden gelebileceklerini bildiren kullanıcılar gördüm.

Python'daki örnek:

element = driver.find_element_by_id("myid")
driver.execute_script("arguments[0].click();", element)

WebDriverJS / Protractor'daki örnek:

var elm = $("#myid");
browser.executeScript("arguments[0].click();", elm.getWebElement());

Soru:

Normal bir WebDriver tıklaması işe yaramadığında, "JavaScript aracılığıyla" tıklaması neden çalışıyor? Bu tam olarak ne zaman oluyor ve bu geçici çözümün dezavantajı (varsa) nedir?

Kişisel olarak bu geçici çözümü, neden yapmak zorunda olduğumu ve hangi sorunlara yol açabileceğini tam olarak anlamadan kullandım.

Yanıtlar:


151

Şu anda kabul edilen yanıtın önerdiğinin aksine, WebDriver'ın bir tıklama yapması ile bunu JavaScript'te yapması arasındaki fark söz konusu olduğunda PhantomJS'ye özgü hiçbir şey yoktur.

Fark

İki yöntem arasındaki temel fark tüm tarayıcılarda ortaktır ve oldukça basit bir şekilde açıklanabilir:

  • WebDriver: WebDriver tıklamayı yaptığında, gerçek bir kullanıcı tarayıcıyı kullandığında ne olacağını en iyi şekilde simüle etmeye çalışır. "Beni tıkla" yazan bir düğme olan bir A divöğesine ve şeffaf olan ancak boyutları olan ve zIndexA'yı tamamen kaplayacak şekilde ayarlanmış bir öğe B'ye sahip olduğunuzu varsayalım . Sonra WebDriver'a A'ya tıklamasını söylüyorsunuz. WebDriver B tıklamayı önce alacak şekilde tıklamayı simüle edin . Neden? B, A'yı kapsadığından ve eğer bir kullanıcı A'yı tıklamaya çalışırsa, o zaman B önce olayı alır. A'nın sonunda click olayını alıp almayacağı, B'nin olayı nasıl işlediğine bağlıdır. Her halükarda, bu durumda WebDriver ile davranış, gerçek bir kullanıcının A'ya tıklamaya çalışmasıyla aynıdır.

  • JavaScript: Şimdi, yapmak için JavaScript kullandığınızı varsayalım A.click(). Bu tıklama yöntemi, kullanıcı A'yı tıklatmaya çalıştığında gerçekte ne olduğunu yeniden üretmez. JavaScript, clickolayı doğrudan A'ya gönderir ve B herhangi bir olay almaz.

Bir WebDriver Tıklaması Çalışmadığında JavaScript Tıklaması Neden Çalışır?

Yukarıda bahsettiğim gibi WebDriver, gerçek bir kullanıcı bir tarayıcı kullandığında ne olacağını en iyi şekilde simüle etmeye çalışacaktır. Gerçek şu ki, DOM bir kullanıcının etkileşime giremeyeceği öğeler içerebilir ve WebDriver bu öğelere tıklamanıza izin vermez. Bahsettiğim örtüşen durumun yanı sıra, bu aynı zamanda görünmez öğelerin tıklanamamasını da gerektirir. Stack Overflow sorularında gördüğüm yaygın bir durum, DOM'da zaten var olan bir GUI öğesiyle etkileşim kurmaya çalışan ancak yalnızca başka bir öğe değiştirildiğinde görünür hale gelen bir kişidir. Bu bazen açılır menülerle olur: bir menü öğesi seçilmeden önce açılır menüyü açan önce düğmeye tıklamanız gerekir. Menü görünmeden önce birisi menü öğesini tıklatmaya çalışırsa,Kişi daha sonra bunu JavaScript ile yapmaya çalışırsa, işe yarayacaktır çünkü olay, görünürlükten bağımsız olarak doğrudan öğeye teslim edilir.

Tıklama için JavaScript'i Ne Zaman Kullanmalısınız?

Bir uygulamayı test etmek için Selenium kullanıyorsanız , bu soruya cevabım "neredeyse hiçbir zaman" olacaktır. Genel olarak Selenium testiniz, bir kullanıcının tarayıcıyla ne yapacağını yeniden üretmelidir. Açılır menü örneğini ele alırsak: Bir test, önce açılır menüyü açan düğmeyi ve ardından menü öğesini tıklamalıdır. GUI'de düğme görünmez olduğu için bir sorun varsa veya düğme menü öğelerini gösteremiyorsa veya benzer bir şey varsa, testiniz başarısız olur ve hatayı tespit etmiş olursunuz. Tıklamak için JavaScript kullanırsanız, bu hataları otomatik test yoluyla tespit edemezsiniz.

"Neredeyse hiçbir zaman" diyorum çünkü JavaScript kullanmanın mantıklı olduğu istisnalar olabilir. Yine de çok nadir olmaları gerekir.

Siteleri kopyalamak için Selenium kullanıyorsanız , kullanıcı davranışını yeniden oluşturmaya çalışmak o kadar kritik değildir. Dolayısıyla, GUI'yi atlamak için JavaScript kullanmak daha az sorun olur.


1
Çok daha iyi cevap, kabul edilen cevap bu olmalı. Yukarıdaki cevap, PhantomJS'ye özgü uç durumdan bahsediyor, bu çok daha doğru IMHO.
Ardesco

@Ardesco kesinlikle. Kabul edildi olarak işaretlendi. Mükemmel ve oldukça detaylı bir cevap.
alecxe

Ödülün planlandığı gibi Linh'e verilmesi, ancak başka bir harika cevap için size teşekkür etmek için yeni bir ödül başlatacağım. Teşekkürler.
alecxe

1
Çok iyi ve anlaşılır cevap. Tecrübelerime göre WebDriver, AngularJS sayfalarıyla birçok sorun yaşadı: Bazı öğelerle WebDriver yöntemleri gibi clickveya sendKeysçalıştı - ama her zaman değil. Yer belirleme sorunu veya başka bir istisna yoktu, test durumu daha fazla ilerlemedi. Günlük kaydı, eylemin yürütüldüğünü gösterdi. Bazen Actionyardım kullanmak . Elemana manuel olarak tıklarsam (test durumu durduktan sonra), her şey yolunda gitti. Biz de bu durumlarda ham JS'ye geçtik. Son 2 yıldır AngularJS ile çalışmadığım için işler şimdi daha iyi olabilir.
Würgspaß

1
@Alex Kullanışlı bir bağlantım yok. Cevabım özellikle Selenium deneyiminden ve genel olarak kullanıcı olaylarını simüle etmekten geliyor. Selenium'u 5 yıl önce kullanmaya başladım. Selenium'u kullandığım süre boyunca, bazı sorunları gidermek için Selenium'un kodunu okumak zorunda kaldım ve olay gönderimi hakkında pek çok hata raporu dosyaladım ve hataları Selenium geliştiricileriyle tartıştım. Amaç "olabildiğince iyi" olmaktır. Kesinlikle bu hedefe ulaşmasını engelleyen (şimdi düzeltilmiş) hatalarla karşılaştım. Bazı hatalar kalabilir.
Louis

30

Sürücü tarafından yürütülen tıklama, gerçek bir kullanıcının davranışını olabildiğince yakından simüle etmeye çalışırken, JavaScript , öğe etkileşimli olmasa bile olay HTMLElement.click()için varsayılan eylemi gerçekleştirir click.

Farklılıklar:

  • Sürücü , görünüme kaydırarak öğenin görünür olmasını sağlar ve öğenin etkileşimli olup olmadığını kontrol eder .

    Sürücü bir hata verecektir:

    • tıklamanın koordinatlarında üstteki öğe, hedeflenen öğe veya alt öğe olmadığında
    • öğe pozitif bir boyuta sahip olmadığında veya tamamen şeffafsa
    • elemanın devre dışı bırakılmış bir giriş veya düğme olduğunda (öznitelik / özellik disabledolduğu true)
    • elemanın devre dışı, fare işaretçisi sahip olduğunda (CSS pointer-eventsolan none)


    Bir JavaScript HTMLElement.click()her zaman varsayılan eylemi gerçekleştirir veya öğe devre dışı bırakılmışsa en iyi ihtimalle sessizce başarısız olur.

  • Odaklanabiliyorsa sürücünün öğeyi odak noktasına getirmesi bekleniyor .

    JavaScript HTMLElement.click()olmaz.

  • Sürücünün tüm olayları (fare imleci, fare düşürme, fareyi kaldırma, tıklama, ...) tıpkı gerçek bir kullanıcı gibi yayınlaması beklenir.

    Bir JavaScript HTMLElement.click()yalnızca clickolayı yayar . Sayfa, bu ekstra olaylara bağlı olabilir ve yayınlanmadıkları takdirde farklı davranabilir.

    Bunlar, Chrome ile bir tıklama için sürücü tarafından yayılan olaylardır:

    mouseover {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mousemove {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mousedown {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mouseup {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    click {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    

    Ve bu, bir JavaScript yerleştirmesiyle yayılan olaydır:

    click {target:#topic, clientX:0, clientY:0, isTrusted:false, ... }
  • JavaScript tarafından yayılan olay .click() güvenilir değildir ve varsayılan eylem başlatılmayabilir:

    https://developer.mozilla.org/en/docs/Web/API/Event/isTrusted
    https://googlechrome.github.io/samples/event-istrusted/index.html

    Bazı sürücülerin hala güvenilmeyen olaylar oluşturduğunu unutmayın. PhantomJS sürüm 2.1'den itibaren durum böyledir.

  • JavaScript tarafından yayılan etkinlik .click() , tıklamanın koordinatlarına sahip değildir .

    Özellikler clientX, clientY, screenX, screenY, layerX, layerYolarak ayarlanmıştır 0. Sayfa bunlara güvenebilir ve farklı davranabilir.


.click()Bazı verileri hurdaya çıkarmak için JavaScript kullanmak uygun olabilir , ancak bu bir test bağlamında değildir. Bir kullanıcının davranışını simüle etmediği için testin amacını geçersiz kılar. Bu nedenle, sürücüden tıklama başarısız olursa, gerçek bir kullanıcı da büyük olasılıkla aynı tıklamayı aynı koşullarda gerçekleştiremeyecektir.


Başarılı olmasını beklediğimizde sürücünün bir öğeyi tıklamamasına neden olan nedir?

  • Hedeflenen öğe, bir gecikme veya geçiş etkisi nedeniyle henüz görünür / etkileşimli değil.

    Bazı örnekler :

    https://developer.mozilla.org/fr/docs/Web (açılır gezinme menüsü) http://materializecss.com/side-nav.html (açılır kenar çubuğu)

    Workarrounds:

    Görünürlüğü, minimum boyutu veya sabit bir pozisyonu beklemek için bir garson ekleyin:

    // wait visible
    browser.wait(ExpectedConditions.visibilityOf(elem), 5000);
    
    // wait visible and not disabled
    browser.wait(ExpectedConditions.elementToBeClickable(elem), 5000);
    
    // wait for minimum width
    browser.wait(function minimumWidth() {
        return elem.getSize().then(size => size.width > 50);
    }, 5000);
    

    Başarılı olana kadar tıklamayı yeniden deneyin:

    browser.wait(function clickSuccessful() {
        return elem.click().then(() => true, (ex) => false);
    }, 5000);
    

    Animasyonun / geçişin süresiyle eşleşen bir gecikme ekleyin:

    browser.sleep(250);


  • Hedeflenen öğe , görünüme kaydırıldıktan sonra bir kayan öğe ile kaplanır :

    Sürücü, öğeyi görünür kılmak için otomatik olarak görünüme kaydırır. Sayfa bir kayan / yapışkan öğe içeriyorsa (menü, reklamlar, altbilgi, bildirim, çerez politikası ..), öğe kapanabilir ve artık görünür / etkileşimde bulunamaz.

    Örnek: https://twitter.com/?lang=en

    Geçici Çözümler:

    Kaydırmayı veya kayan öğeyi önlemek için pencerenin boyutunu daha büyük bir boyuta ayarlayın.

    Negatif Yofset ile öğenin üzerine gelin ve ardından tıklayın:

      browser.actions()
         .mouseMove(elem, {x: 0, y: -250})
         .click()
         .perform();
    

    Tıklamadan önce öğeyi pencerenin ortasına kaydırın:

    browser.executeScript(function scrollCenter(elem) {
      var win = elem.ownerDocument.defaultView || window,
        box = elem.getBoundingClientRect(),
        dy = box.top - (win.innerHeight - box.height) / 2;
      win.scrollTo(win.pageXOffset, win.pageYOffset + dy);
    }, element);
    
    element.click();
    

    Önlenemiyorsa yüzen öğeyi gizleyin:

    browser.executeScript(function scrollCenter(elem) {
      elem.style.display = 'none';
    }, element);
    

17

NOT: 'tıklama' diyelim son kullanıcı tıklamasıdır. 'js tıklama' JS üzerinden tıklanır

Normal bir WebDriver tıklaması işe yaramadığında, "JavaScript aracılığıyla" tıklaması neden çalışıyor?

Bunun gerçekleşmesi için 2 durum vardır:

I. PhamtomJS kullanıyorsanız

O zaman bu en yaygın bilinen davranıştır PhantomJS. Örneğin, bazı öğeler bazen tıklanamaz <div>. Bunun nedeni PhantomJS, tarayıcıların motorunu simüle etmek için orijinal yapılmış olmasıdır (ilk HTML + CSS -> hesaplama CSS -> oluşturma gibi). Ancak bu, bir son kullanıcının yolu olarak (görüntüleme, tıklama, sürükleme) etkileşime girmek anlamına gelmez. Bu nedenle PhamtomJS, son kullanıcı etkileşimi ile yalnızca kısmen desteklenir.

JS CLICK NEDEN ÇALIŞIR? Her iki tıklama için de, hepsi ortalama tıklama. 1 namlulu ve 2 tetikli bir silah gibidir . Görüntü alanından biri, JS'den biri. Yana PhamtomJStarayıcının motorunu simüle büyük bir JS tıklama mükemmel çalışması gerekir.

II. "Tıklama" olay işleyicisi kötü zaman diliminde bağlanmalıdır.

Örneğin, bir <div>

  • -> Bazı hesaplamalar yapıyoruz

  • -> sonra tıklama olayını <div>.

  • -> Artı bazı kötü açısal kodlamalarla (ör. Kapsamın döngüsünü düzgün şekilde ele almama)

Aynı sonuçla sonuçlanabiliriz. Tıklama çalışmaz çünkü WebdriverJS, tıklama olay işleyicisi olmadığında öğeyi tıklamaya çalışır.

JS CLICK NEDEN ÇALIŞIR? Js tıklama js'yi doğrudan tarayıcıya enjekte etmeye benzer. 2 yolla mümkündür,

İlk olarak devtools konsolu (evet, WebdriverJS, devtools'un konsoluyla iletişim kuruyor).

İkincisi , bir <script>etiketi doğrudan HTML'ye enjekte etmektir .

Her tarayıcı için davranış farklı olacaktır. Ancak ne olursa olsun, bu yöntemler düğmeye tıklamaktan daha karmaşıktır. Tıklama zaten orada olanı kullanıyor (son kullanıcılar tıklıyor), js tıklama arka kapıdan geçiyor.

Ve js için tıklama eşzamansız bir görev olarak görünecektir. Bu, ' tarayıcı asenkron görevi ve CPU görev zamanlaması ' gibi karmaşık bir konu ile ilgilidir (bir süre önce okuyun, makaleyi tekrar bulamıyorum). Kısaca, bu çoğunlukla js tıklamasının CPU'nun görev zamanlaması döngüsünü beklemesi gerekeceğinden ve tıklama olayının bağlanmasından sonra biraz daha yavaş çalışacağından sonuçlanacaktır. (Öğeyi bazen tıklanabilir, bazen tıklanabilir bulduğunuzda bu durumu anlayabilirsiniz.)

Bu tam olarak ne zaman oluyor ve bu geçici çözümün dezavantajı (varsa) nedir?

=> Yukarıda bahsedildiği gibi, her ikisi de tek bir amaç içindir, ancak hangi girişi kullanmakla ilgilidir:

  • Tıklama: tarayıcının varsayılan olarak sağladığı şeyi kullanıyor.
  • JS tıklama: arka kapıdan geçiyor.

=> Performans için, tarayıcılara dayandığı için söylemek zor. Ancak genel olarak:

  • Tıklama: daha hızlı anlamına gelmez, ancak yalnızca CPU yürütme görevinin zamanlama listesinde daha yüksek bir konuma işaret etti.
  • JS tıklaması: daha yavaş anlamına gelmez, sadece CPU görevinin zamanlama listesinin son konumunda oturum açtı.

=> Dezavantajlar:

  • Tıklama: PhamtomJS kullanmanız dışında herhangi bir dezavantajı yok gibi görünüyor.
  • JS tıklaması: sağlık için çok kötü. Görünümde olmayan bir şeye yanlışlıkla tıklayabilirsiniz. Bunu kullandığınızda, öğenin orada olduğundan ve son kullanıcının bakış açısı olarak görüntülenebilir ve tıklanabilir olduğundan emin olun.

PS, bir çözüm arıyorsanız.

  • PhantomJS mi kullanıyorsunuz? Bunun yerine Chrome'u başsız kullanmanızı önereceğim. Evet, Chrome'u Ubuntu'da başsız olarak kurabilirsiniz. Şey, tıpkı Chrome gibi çalışır, ancak yalnızca bir görünüme sahip değildir ve PhantomJS gibi daha az hatalı.
  • PhamtomJS kullanmıyor ama hala sorun mu yaşıyorsunuz? ExpectedCondition of Protractor ile kullanmanızı önereceğim browser.wait()( daha fazla bilgi için bunu kontrol edin )

(Kısaltmak istiyorum ama kötü sonuçlandı. Teori ile ilgili herhangi bir şeyi açıklamak karmaşıktır ...)

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.