2015-01-20 14 views
18

Tôi đã sử dụng selenium (với python bindings và thông qua protractor chủ yếu) trong một thời gian khá dài và mỗi khi tôi cần thiết để thực thi một mã javascript, tôi đã sử dụng phương pháp execute_script(). Ví dụ, for scrolling the page (python):Hiểu thực thi kịch bản async trong Selenium

driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") 

Hoặc, cho infinite scrolling inside an another element (thước đo góc):

var div = element(by.css('div.table-scroll')); 
var lastRow = element(by.css('table#myid tr:last-of-type')); 

browser.executeScript("return arguments[0].offsetTop;", lastRow.getWebElement()).then(function (offset) { 
    browser.executeScript('arguments[0].scrollTop = arguments[1];', div.getWebElement(), offset).then(function() { 
     // assertions 

    }); 
}); 

Hoặc, để có được một dictionary of all element attributes (python):

driver.execute_script('var items = {}; for (index = 0; index < arguments[0].attributes.length; ++index) { items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value }; return items;', element) 

Tuy nhiên, API WebDriver cũng có execute_async_script() mà tôi chưa từng sử dụng.

Bao gồm các trường hợp sử dụng nào? Khi nào tôi nên sử dụng execute_async_script() thay vì execute_script() thông thường?

Câu hỏi này đặc biệt về selen, nhưng không thuyết phục về ngôn ngữ.

Trả lời

13

Đây là reference với hai API (cũng nó Javadoc, nhưng các chức năng đều giống nhau), và đây là một đoạn trích từ nó làm nổi bật sự khác biệt

[executeAsyncScript] Thực hiện một mảnh không đồng bộ của JavaScript trong ngữ cảnh của khung hoặc cửa sổ hiện được chọn. Không giống như thực thi JavaScript đồng bộ, các tập lệnh được thực thi bằng phương thức này phải báo hiệu rõ ràng rằng chúng được hoàn thành bằng cách gọi hàm gọi lại được cung cấp. Lệnh gọi lại này luôn được tiêm vào hàm thực thi làm đối số cuối cùng.

Về cơ bản, execSync chặn các hành động khác đang được trình duyệt selen thực hiện, trong khi execAsync không chặn và gọi số callback khi hoàn tất.


Vì bạn đã làm việc với thước đo góc, tôi sẽ sử dụng nó làm ví dụ. thước đo sử dụng executeAsyncScript trong cả getwaitForAngular

Trong waitForAngular, thước đo cần phải đợi cho đến khi góc thông báo rằng tất cả các sự kiện giải quyết. Bạn không thể sử dụng executeScript vì điều đó cần phải trả về giá trị ở cuối (mặc dù tôi đoán bạn có thể triển khai một vòng lặp bận rộn thăm dò liên tục góc cạnh cho đến khi hoàn thành). Cách nó hoạt động là thước đo góc cung cấp một cuộc gọi lại, mà Angular gọi một khi tất cả các sự kiện đã được giải quyết, và điều đó yêu cầu executeAsyncScript. Mã số here

Trong get, thước đo góc cần phải thăm dò ý kiến ​​cho đến khi toàn cầu window.angular được đặt bởi Angular. Một cách để làm điều đó là driver.wait(function() {driver.executeScript('return window.angular')}, 5000), nhưng cách đó thước đo góc sẽ đập vào trình duyệt sau mỗi vài ms. Thay vào đó, chúng tôi thực hiện việc này (đã được đơn giản hóa):

functions.testForAngular = function(attempts, callback) { 
    var check = function(n) { 
    if (window.angular) { 
     callback('good'); 
    } else if (n < 1) { 
     callback('timedout'); 
    } else { 
     setTimeout(function() {check(n - 1);}, 1000); 
    } 
    }; 
    check(attempts); 
}; 

Một lần nữa, yêu cầu đó phải có giá trị trả lại ngay lập tức.Mã here


Tất cả trong tất cả, sử dụng executeAsyncScript khi bạn quan tâm đến một giá trị trả về trong một kịch bản gọi điện thoại, nhưng mà giá trị trả về sẽ không có sẵn ngay lập tức. Điều này đặc biệt cần thiết nếu bạn không thể thăm dò kết quả, nhưng phải có kết quả bằng cách sử dụng gọi lại hoặc lời hứa (mà bạn phải dịch để gọi lại cho chính mình).

+0

Cảm ơn bạn đã liên kết đến javaDoc - có một số mẫu được đề cập. Cá nhân bạn có cần phải thực thi một tập lệnh không đồng bộ không? Nếu có, bạn có thể mô tả (các) ca sử dụng không? Việc đó thật sự hữu ích. – alecxe

+0

Đã thêm một số ví dụ. Hy vọng rằng có ý nghĩa. – hankduan

+0

Tuyệt vời, đây là một cuộc hành trình thú vị vào kịch bản phía khách hàng của thước đo góc và nội bộ khác! Cảm ơn một lần nữa. Về lý thuyết, hãy tưởng tượng: nếu tôi thử nghiệm một ứng dụng góc với các ràng buộc python selen - tôi sẽ cần tải các kịch bản lệnh phía máy khách tương tự (hoặc giống nhau) và gọi các hàm 'testForAngular()' và 'waitForAngular()' không đồng bộ theo thứ tự để kiểm tra và chờ cho Angular "trở nên ổn định". Chính xác? – alecxe

20

Khi nào tôi nên sử dụng execute_async_script() thay vì thường lệ execute_script()?

Khi nói đến điều kiện kiểm tra ở phía trình duyệt, bài kiểm tra bạn có thể thực hiện với execute_async_script có thể được thực hiện với execute_script. Ngay cả khi những gì bạn đang kiểm tra là không đồng bộ. Tôi biết bởi vì ngày xửa ngày xưa có lỗi với execute_async_script làm cho các thử nghiệm của tôi thất bại nếu tập lệnh trả lại kết quả quá nhanh. Theo như tôi có thể nói, lỗi đã biến mất ngay bây giờ vì vậy tôi đã sử dụng execute_async_script nhưng trong nhiều tháng trước, tôi đã sử dụng execute_script cho các tác vụ mà ở đó execute_async_script sẽ tự nhiên hơn. Ví dụ, thực hiện một kiểm tra đòi hỏi phải nạp một module với RequireJS để thực hiện việc kiểm tra:

driver.execute_script(""" 
// Reset in case it's been used already. 
window.__selenium_test_check = undefined; 
require(["foo"], function (foo) { 
    window.__selenium_test_check = foo.computeSomething(); 
}); 
""") 

result = driver.wait(lambda driver: 
    driver.execute_script("return window.__selenium_test_check;")) 

Cuộc gọi require là không đồng bộ. Vấn đề với điều này mặc dù, bên cạnh việc rò rỉ một biến vào không gian toàn cầu, là nó nhân các yêu cầu mạng. Mỗi cuộc gọi execute_script là một yêu cầu mạng. Phương thức wait hoạt động bằng cách bỏ phiếu: nó chạy thử nghiệm cho đến khi giá trị trả về là đúng. Điều này có nghĩa là một yêu cầu mạng cho mỗi séc rằng wait thực hiện (trong mã ở trên).

Khi bạn thử nghiệm tại địa phương, đó không phải là vấn đề lớn. Nếu bạn phải đi qua mạng bởi vì bạn đang có các trình duyệt được cung cấp bởi một dịch vụ như Sauce Labs (mà tôi sử dụng, vì vậy tôi đang nói từ kinh nghiệm), mỗi yêu cầu mạng sẽ làm chậm bộ kiểm thử của bạn. Vì vậy, việc sử dụng execute_async_script không chỉ cho phép viết một bài kiểm tra trông tự nhiên hơn (gọi một cuộc gọi lại, như chúng ta thường làm với mã không đồng bộ, thay vì bị rò rỉ vào không gian toàn cục), nhưng nó cũng giúp thực hiện các bài kiểm tra của bạn.

result = driver.execute_async_script(""" 
var done = arguments[0]; 
require(["foo"], function (foo) { 
    done(foo.computeSomething()); 
}); 
""") 

Con đường tôi nhìn thấy nó bây giờ là nếu một thử nghiệm đang diễn ra để móc vào mã không đồng bộ ở phía trình duyệt để có được một kết quả, tôi sử dụng execute_async_script. Nếu nó sẽ làm một cái gì đó mà không có phương pháp không đồng bộ có sẵn, tôi sử dụng execute_script.

+0

Tuyệt vời. 1 để đi vào chi tiết về thời điểm nó vẫn thích hợp để sử dụng 'execute' trên' executeAsync'. Tôi sẽ thêm các caveat: lỗi này có, đối với tôi (sử dụng trình điều khiển web selenium và javascript) dường như trở lại. – GrayedFox

Các vấn đề liên quan