Nhấp chuột WebDriver () so với nhấp chuột JavaScript ()


126

Câu chuyện:

Ở đây trên StackOverflow, tôi đã thấy người dùng báo cáo rằng họ không thể nhấp vào một phần tử thông qua lệnh "click" selenium WebDriver và có thể làm việc xung quanh nó với một lần nhấp JavaScript bằng cách thực thi tập lệnh.

Ví dụ trong Python:

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

Ví dụ trong WebDriverJS / Thước đo góc:

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

Câu hỏi:

Tại sao nhấp vào "qua JavaScript" hoạt động khi nhấp chuột WebDriver thông thường không? Khi chính xác điều này xảy ra và nhược điểm của cách giải quyết này (nếu có) là gì?

Cá nhân tôi đã sử dụng cách giải quyết này mà không hiểu đầy đủ lý do tại sao tôi phải làm điều đó và nó có thể dẫn đến những vấn đề gì.

Câu trả lời:


150

Trái với những gì câu trả lời hiện được chấp nhận cho thấy, không có gì cụ thể đối với PhantomJS khi nói đến sự khác biệt giữa việc WebDriver thực hiện nhấp chuột và thực hiện bằng JavaScript.

Sự khác biệt

Sự khác biệt cơ bản giữa hai phương pháp là phổ biến cho tất cả các trình duyệt và có thể được giải thích khá đơn giản:

  • WebDriver: Khi WebDriver thực hiện nhấp chuột, nó sẽ cố gắng hết sức có thể để mô phỏng những gì xảy ra khi người dùng thực sự sử dụng trình duyệt. Giả sử bạn có một phần tử A là nút có nội dung "Nhấp vào tôi" và phần tử B là divphần tử trong suốt nhưng có kích thước và zIndexđược đặt sao cho nó hoàn toàn bao phủ A. Sau đó, bạn báo cho WebDriver nhấp vào A. WebDriver sẽ mô phỏng lần nhấp để B nhận được lần nhấp đầu tiên . Tại sao? Bởi vì B bao trùm A và nếu người dùng cố gắng nhấp vào A, thì B sẽ nhận sự kiện trước. Việc A có nhận được sự kiện nhấp hay không phụ thuộc vào cách B xử lý sự kiện. Ở mọi mức độ, hành vi với WebDriver trong trường hợp này giống như khi người dùng thực sự cố gắng nhấp vào A.

  • JavaScript: Bây giờ, giả sử bạn sử dụng JavaScript để làm A.click(). Phương pháp nhấp này không tái tạo những gì thực sự xảy ra khi người dùng cố gắng nhấp vào A. JavaScript gửi clicksự kiện trực tiếp đến A và B sẽ không nhận được bất kỳ sự kiện nào.

Tại sao nhấp chuột JavaScript hoạt động khi nhấp vào WebDriver không?

Như tôi đã đề cập ở trên, WebDriver sẽ cố gắng mô phỏng tốt nhất có thể những gì xảy ra khi người dùng thực sự đang sử dụng trình duyệt. Thực tế của vấn đề là DOM có thể chứa các yếu tố mà người dùng không thể tương tác và WebDriver sẽ không cho phép bạn nhấp vào các yếu tố này. Bên cạnh trường hợp chồng chéo tôi đã đề cập, điều này cũng đòi hỏi các yếu tố vô hình không thể được nhấp vào. Một trường hợp phổ biến tôi thấy trong các câu hỏi Stack Overflow là một người nào đó đang cố gắng tương tác với một phần tử GUI đã tồn tại trong DOM nhưng chỉ hiển thị khi một số phần tử khác bị thao túng. Điều này đôi khi xảy ra với các menu thả xuống: trước tiên bạn phải nhấp vào nút để hiển thị danh sách thả xuống trước khi có thể chọn một mục menu. Nếu ai đó cố gắng nhấp vào mục menu trước khi menu hiển thị,Nếu sau đó người đó cố gắng làm điều đó với JavaScript, nó sẽ hoạt động vì sự kiện được gửi trực tiếp đến phần tử, bất kể khả năng hiển thị.

Khi nào bạn nên sử dụng JavaScript để nhấp?

Nếu bạn đang sử dụng Selenium để thử nghiệm một ứng dụng , câu trả lời của tôi cho câu hỏi này là "gần như không bao giờ". Nhìn chung, bài kiểm tra Selen của bạn sẽ tái tạo những gì người dùng sẽ làm với trình duyệt. Lấy ví dụ về menu thả xuống: một bài kiểm tra nên nhấp vào nút hiển thị trình đơn thả xuống trước, sau đó nhấp vào mục menu. Nếu có vấn đề với GUI vì nút này là vô hình hoặc nút không hiển thị các mục menu hoặc một cái gì đó tương tự, thì thử nghiệm của bạn sẽ thất bại và bạn sẽ phát hiện ra lỗi. Nếu bạn sử dụng JavaScript để nhấp xung quanh, bạn sẽ không thể phát hiện các lỗi này thông qua kiểm tra tự động.

Tôi nói "gần như không bao giờ" bởi vì có thể có ngoại lệ khi sử dụng JavaScript. Họ nên rất hiếm, mặc dù.

Nếu bạn đang sử dụng Selenium để quét các trang web , thì việc cố gắng tái tạo hành vi người dùng là không quan trọng. Vì vậy, sử dụng JavaScript để bỏ qua GUI là một vấn đề ít hơn.


1
Câu trả lời tốt hơn nhiều, đây nên là một trong những chấp nhận. Câu trả lời ở trên là nói về một trường hợp cạnh dành riêng cho PhantomJS, đây là IMHO chính xác hơn nhiều.
Ardesco

@Ardesco chắc chắn. Đánh dấu là chấp nhận. Hoàn hảo và một câu trả lời khá chi tiết.
alecxe

Trao tiền thưởng cho Linh theo kế hoạch, nhưng tôi sẽ bắt đầu một cái mới để cảm ơn bạn vì một câu trả lời tuyệt vời khác. Cảm ơn.
alecxe

1
Câu trả lời rất hay và dễ hiểu. Theo kinh nghiệm của tôi, WebDriver đã có rất nhiều vấn đề với các trang AngularJS: Với một số yếu tố, các phương thức WebDriver thích clickhoặc sendKeyshoạt động - nhưng không phải lúc nào cũng vậy. Không có vấn đề định vị hoặc ngoại lệ khác, trường hợp thử nghiệm đơn giản là không tiến triển thêm nữa. Ghi nhật ký cho thấy rằng hành động đã được thực hiện. Đôi khi sử dụng Actiongiúp. Nếu tôi nhấp vào phần tử bằng tay (sau khi trường hợp kiểm tra đã dừng), mọi thứ đều hoạt động tốt. Vì vậy, chúng tôi đã chuyển sang JS thô trong những dịp đó. Tôi đã không làm việc với AngularJS trong 2 năm qua, vì vậy mọi thứ có thể tốt hơn bây giờ.
Wurgspaß

1
@Alex Tôi không có một liên kết tiện dụng. Câu trả lời của tôi bắt nguồn từ kinh nghiệm với Selenium nói riêng và với việc mô phỏng các sự kiện của người dùng nói chung. Tôi đã bắt đầu sử dụng Selenium 5 năm trước. Trong thời gian tôi sử dụng Selenium, tôi đã phải đọc mã của Selenium để khắc phục một số vấn đề và tôi đã gửi khá nhiều báo cáo lỗi về việc gửi sự kiện và thảo luận về các lỗi với các nhà phát triển Selenium. "tốt nhất có thể" là mục tiêu. Tôi chắc chắn đã gặp phải (bây giờ đã sửa) các lỗi ngăn nó đạt được mục tiêu đó. Một số lỗi có thể vẫn còn.
Louis

30

Nhấp chuột được thực hiện bởi trình điều khiển cố gắng mô phỏng hành vi của người dùng thực càng gần càng tốt trong khi JavaScript HTMLElement.click()thực hiện hành động mặc định cho clicksự kiện, ngay cả khi phần tử không tương tác.

Sự khác biệt là:

  • Trình điều khiển đảm bảo rằng phần tử được hiển thị bằng cách cuộn nó vào dạng xem và kiểm tra xem phần tử đó có tương tác được không .

    Trình điều khiển sẽ đưa ra một lỗi:

    • khi phần tử trên cùng ở tọa độ của nhấp chuột không phải là phần tử được nhắm mục tiêu hoặc hậu duệ
    • khi phần tử không có kích thước dương hoặc nếu nó hoàn toàn trong suốt
    • khi nguyên tố này là một đầu vào hoặc nút khuyết tật (thuộc tính / tài sản disabledtrue)
    • khi phần tử có con trỏ chuột bị tắt (CSS pointer-eventsnone)


    Một JavaScript HTMLElement.click()sẽ luôn thực hiện hành động mặc định hoặc tốt nhất sẽ âm thầm thất bại nếu phần tử bị vô hiệu hóa.

  • Trình điều khiển dự kiến ​​sẽ đưa yếu tố vào trọng tâm nếu nó có thể lấy nét .

    Một JavaScript HTMLElement.click()sẽ không.

  • Trình điều khiển dự kiến ​​sẽ phát ra tất cả các sự kiện (mousemove, mousedown, mouseup, click, ...) giống như một người dùng thực sự.

    Một JavaScript HTMLElement.click()chỉ phát ra clicksự kiện. Trang có thể dựa vào các sự kiện bổ sung này và có thể hoạt động khác đi nếu chúng không được phát ra.

    Đây là những sự kiện được trình điều khiển phát ra cho một lần nhấp với Chrome:

    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, ... }

    Và đây là sự kiện được phát ra bằng cách tiêm JavaScript:

    click {target:#topic, clientX:0, clientY:0, isTrusted:false, ... }
  • Sự kiện được phát ra bởi JavaScript .click() không đáng tin cậy và hành động mặc định có thể không được gọi:

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

    Lưu ý rằng một số trình điều khiển vẫn đang tạo ra các sự kiện không đáng tin cậy. Đây là trường hợp với PhantomJS kể từ phiên bản 2.1.

  • Sự kiện được phát ra bởi JavaScript .click() không có tọa độ của nhấp chuột .

    Các thuộc tính clientX, clientY, screenX, screenY, layerX, layerYđược đặt thành 0. Các trang có thể dựa vào họ và có thể hành xử khác nhau.


Có thể sử dụng JavaScript .click()để loại bỏ một số dữ liệu, nhưng nó không nằm trong bối cảnh thử nghiệm. Nó đánh bại mục đích của thử nghiệm vì nó không mô phỏng hành vi của người dùng. Vì vậy, nếu nhấp chuột từ trình điều khiển không thành công, thì người dùng thực sự rất có thể cũng sẽ không thực hiện cùng một nhấp chuột trong cùng điều kiện.


Điều gì làm cho trình điều khiển không nhấp vào một yếu tố khi chúng ta mong đợi nó thành công?

  • Phần tử được nhắm mục tiêu chưa hiển thị / có thể tương tác do độ trễ hoặc hiệu ứng chuyển tiếp.

    Vài ví dụ :

    https://developer.mozilla.org/fr/docs/Web (menu điều hướng thả xuống) http: // m Materializecss.com/side-nav.html (thanh bên thả xuống)

    Cách giải quyết:

    Thêm người phục vụ để chờ tầm nhìn, kích thước tối thiểu hoặc vị trí ổn định:

    // 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);

    Thử lại để nhấp cho đến khi thành công:

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

    Thêm một độ trễ phù hợp với thời lượng của hình ảnh động / chuyển tiếp:

    browser.sleep(250);


  • Phần tử được nhắm mục tiêu kết thúc được bao phủ bởi phần tử nổi sau khi cuộn vào dạng xem:

    Trình điều khiển tự động cuộn phần tử vào chế độ xem để hiển thị. Nếu trang chứa phần tử nổi / dính (menu, quảng cáo, chân trang, thông báo, chính sách cookie ..), phần tử có thể được che phủ và sẽ không còn hiển thị / tương tác.

    Ví dụ: https://twitter.com/?lang=en

    Cách giải quyết:

    Đặt kích thước của cửa sổ thành một cửa sổ lớn hơn để tránh cuộn hoặc phần tử nổi.

    Chuyển qua phần tử có phần Ybù âm và sau đó nhấp vào phần tử :

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

    Di chuyển phần tử đến giữa cửa sổ trước khi nhấp:

    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();

    Ẩn phần tử nổi nếu không thể tránh được:

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

17

LƯU Ý: hãy gọi 'nhấp chuột' là nhấp chuột của người dùng cuối. 'js click' là nhấp qua JS

Tại sao nhấp vào "qua JavaScript" hoạt động khi nhấp chuột WebDriver thông thường không?

Có 2 trường hợp để điều này xảy ra:

I. Nếu bạn đang sử dụng PhạmtomJS

Sau đó, đây là hành vi phổ biến nhất được biết đến của PhantomJS. Một số yếu tố đôi khi không thể nhấp vào, ví dụ <div>. Điều này là do PhantomJSbản gốc được tạo để mô phỏng công cụ của các trình duyệt (như HTML + CSS ban đầu -> tính toán CSS -> kết xuất). Nhưng nó không có nghĩa là được tương tác như một cách của người dùng cuối (xem, nhấp, kéo). Do đó, PhamtomJSchỉ được hỗ trợ một phần với tương tác của người dùng cuối.

TẠI SAO KHÔNG NHẤP VÀO CÔNG VIỆC? Đối với một trong hai nhấp chuột, tất cả chúng đều có nghĩa là nhấp chuột. Nó giống như một khẩu súng với 1 nòng2 cò súng . Một từ khung nhìn, một từ JS. Vì PhamtomJStuyệt vời trong việc mô phỏng công cụ của trình duyệt, một nhấp chuột JS sẽ hoạt động hoàn hảo.

II. Trình xử lý sự kiện của "nhấp chuột" phải liên kết trong khoảng thời gian xấu.

Ví dụ: chúng tôi có một <div>

  • -> Chúng tôi thực hiện một số tính toán

  • -> sau đó chúng tôi liên kết sự kiện nhấp vào <div>.

  • -> Cộng với một số mã hóa xấu của góc (ví dụ: không xử lý đúng chu kỳ của phạm vi)

Chúng tôi có thể kết thúc với cùng một kết quả. Nhấp vào sẽ không hoạt động, vì WebdoJS cố gắng nhấp vào phần tử khi nó không có trình xử lý sự kiện nhấp.

TẠI SAO KHÔNG NHẤP VÀO CÔNG VIỆC? Nhấp chuột Js giống như tiêm js trực tiếp vào trình duyệt. Có thể với 2 cách,

Nắm tay là thông qua bảng điều khiển devtools (vâng, WebdoJS không giao tiếp với bảng điều khiển của devtools).

Thứ hai là tiêm một <script>thẻ trực tiếp vào HTML.

Đối với mỗi trình duyệt, hành vi sẽ khác nhau. Nhưng bất kể, các phương pháp này phức tạp hơn so với nhấp vào nút. Nhấp chuột đang sử dụng những gì đã có (nhấp chuột của người dùng cuối), nhấp chuột js sẽ thông qua cửa hậu.

Và đối với nhấp chuột js sẽ xuất hiện là một nhiệm vụ không đồng bộ. Điều này có liên quan với một chủ đề phức tạp về ' tác vụ không đồng bộ của trình duyệt và lập lịch tác vụ CPU ' (đọc lại một lúc không thể tìm lại bài viết). Nói tóm lại, điều này chủ yếu sẽ dẫn đến việc nhấp chuột js sẽ cần chờ một chu kỳ lập lịch tác vụ của CPU và nó sẽ được chạy chậm hơn một chút sau khi ràng buộc sự kiện nhấp chuột. (Bạn có thể biết trường hợp này khi bạn tìm thấy phần tử đôi khi có thể nhấp, đôi khi không.)

Khi chính xác điều này xảy ra và nhược điểm của cách giải quyết này (nếu có) là gì?

=> Như đã đề cập ở trên, cả hai đều có nghĩa cho một mục đích, nhưng về việc sử dụng lối vào nào:

  • Bấm: đang sử dụng những gì cung cấp theo mặc định của trình duyệt.
  • Nhấp chuột vào JS: đang đi qua cửa hậu.

=> Về hiệu suất, thật khó để nói vì nó phụ thuộc vào trình duyệt. Nhưng nói chung:

  • Bấm: không có nghĩa là nhanh hơn mà chỉ ký vị trí cao hơn trong danh sách lịch biểu của tác vụ thực thi CPU.
  • Nhấp chuột vào JS: không có nghĩa là chậm hơn mà chỉ có nó đăng nhập vào vị trí cuối cùng của danh sách lịch trình của tác vụ CPU.

=> Nhược điểm:

  • Nhấp chuột: dường như không có bất kỳ nhược điểm nào ngoại trừ bạn đang sử dụng PhạmtomJS.
  • Nhấp chuột vào JS: rất xấu cho sức khỏe. Bạn có thể vô tình nhấp vào cái gì đó không có trên màn hình. Khi bạn sử dụng phần này, hãy đảm bảo phần tử ở đó và có sẵn để xem và nhấp vào làm điểm nhìn của người dùng cuối.

PS nếu bạn đang tìm kiếm một giải pháp.

  • Sử dụng PhantomJS? Tôi sẽ đề nghị sử dụng Chrome không đầu thay thế. Có, bạn có thể thiết lập Chrome không đầu trên Ubuntu. Điều này chạy giống như Chrome nhưng nó chỉ không có chế độ xem và ít lỗi hơn như PhantomJS.
  • Không sử dụng PhạmtomJS nhưng vẫn gặp vấn đề? Tôi sẽ đề nghị sử dụng ExpectedCondition of Protractor với browser.wait()( kiểm tra điều này để biết thêm thông tin )

(Tôi muốn làm cho nó ngắn gọn, nhưng kết thúc tồi tệ. Mọi thứ liên quan đến lý thuyết đều phức tạp để giải thích ...)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.