Làm cách nào để Capybara kiểm tra khả năng hiển thị sau khi một số JS đã chạy?


82

Sau khi tải một trang, tôi có mã chạy và ẩn và hiển thị các mục khác nhau dựa trên dữ liệu được trả về bởi một xhr.

Kiểm tra tích hợp của tôi trông giống như sau:

it "should not show the blah" do
    page.find('#blah').visible?.should be_true
end 

Khi tôi truy cập trang theo cách thủ công trong bối cảnh chạy thử nghiệm này, #blah không hiển thị như tôi mong đợi. Tôi nghi ngờ rằng Capybara đang xem trạng thái ban đầu của trang (ẩn trong trường hợp này), đánh giá trạng thái của DOM và không kiểm tra được trước khi JS chạy.

Có, tôi đã đặt :js => truetrên khối mô tả chứa :)

Bất kì ý kiến ​​nào đều được đánh giá cao! Tôi hy vọng rằng tôi không phải cố tình trì hoãn ở đây, điều đó cảm thấy khó chịu và sẽ làm mọi thứ chậm lại.


1
Trình điều khiển là gì? HTML mong đợi sau khi XHR hoàn tất là gì?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Câu trả lời:


132

Tôi nghĩ rằng findcâu lệnh ở đây là câu lệnh có sự chờ đợi ngầm, vì vậy Capybara sẽ đợi cho đến khi phần tử nằm trên trang, nhưng sẽ không đợi phần tử đó hiển thị.

Ở đây, bạn muốn Capybara đợi phần tử hiển thị xuất hiện, điều này có thể đạt được bằng cách chỉ định visibletùy chọn:

expect(page).to have_selector('#blah', visible: true)

Tôi chưa thử, nhưng ignore_hidden_elementstùy chọn cấu hình cũng có thể hữu ích ở đây, nếu bạn muốn findluôn đợi các phần tử hiển thị.


6
trong trường hợp bất kỳ ai ban đầu bỏ lỡ ghi chú của @ Kevin (như tôi), bạn phải có js:truetrên khối chứa để điều này hoạt động.
Chris Beck,

3
Điều này thật tuyệt. Nó đã giúp tôi đến được: expect(page).to have_selector('#flash-message', visible: false, text: "Signed in Successfully")- cảm ơn vì đã đăng câu trả lời này
Chuck Bergeron

Tùy chọn hiển thị không có tác dụng đối với tôi khi kiểm tra khả năng hiển thị của phần tử trượt xuống jquery. Tôi đã phải sử dụng kỳ vọng (find ('# blah'). Hiển thị?). Thành be_falsey.
trueinViso

Tôi muốn một cái gì đó giống như is_visible? sau đó làm điều đó khác làm cái gì khác
user1735921

37

Đây là một cách khác để làm điều đó hoạt động hoàn toàn tốt đối với tôi:

find(:css, "#some_element").should be_visible

Đặc biệt đối với những phát hiện phức tạp hơn, chẳng hạn như

find(:css, "#comment_stream_list li[data-id='#{@id3}']").should_not be_visible

điều này sẽ khẳng định rằng một phần tử đã bị ẩn.


1
Tôi should_not be_visiblecó vẻ không ổn khi Capybara chạy wait_until { base.visible? }khi Element # hiển thị? đang được gọi.
Phương Nguyễn

1
@ phng-nguyn, #wait_until đã bị xóa khỏi các phiên bản gần đây của Capybara.
solidcell

3
Đây thực sự là một biến thể tốt hơn so với "page.should have_selector ...", bởi vì trong trường hợp nếu một văn bản không đạt, nó sẽ nói rằng phần tử thực sự ẩn rõ ràng, trong khi biến thể được đề cập chỉ gợi lên lỗi 'không có kết quả phù hợp' , đó là một chút bực bội.
installero

Điều này không giống với giải pháp được chấp nhận. Đối với mã này, Capybara sẽ chỉ đợi cho đến khi phần tử nằm trong DOM và sau đó kiểm tra khả năng hiển thị ngay lập tức. Nếu bạn đang mong đợi khả năng hiển thị thay đổi, điều này có thể thêm điều kiện đua vào thông số kỹ thuật.
johncip

1
Có ai biết nếu .should_not be_visiblebìa display: noneđược thiết lập bởi jQuery? Nó dường như không hiệu quả với tôi.
Antrikshy

20

Nếu bạn muốn kiểm tra xem một phần tử có trên trang nhưng không hiển thị hay không, visible: falsenó sẽ không hoạt động như bạn mong đợi. Đã khiến tôi bối rối một chút.

Đây là cách thực hiện:

# assert element is present, regardless of visibility
page.should have_css('#some_element', :visible => false)
# assert visible element is not present
page.should have_no_css('#some_element', :visible => true)

1
Bạn không thể sử dụng should_notvới capybara, vì ajax
Marc-André La xui xẻo

@ Marc-AndréLa xui xẻo, để kiểm tra ajax với capybara, hãy sử dụng Capybara.javascript_driver.
Zubin

1
với javascript_drive, have_csssẽ đợi toàn bộ khoảng thời gian chờ của bạn trước khi từ bỏ, vì nó dự kiến ​​sẽ tìm thấy phần tử. Ví dụ: bạn phải sử dụng should have_no_contentthay vì should_not have_content.
Marc-André Lauckyne

1
expect(page).not_to have_selector("#some_element", visible: true)hoạt động tốt đối với tôi khi sử dụng javascript_driver, mà không phải đợi toàn bộ thời gian chờ.
Jason Swett

1
Trên thực tế, kể từ nhận xét của tôi, điều này đã được thay đổi và bạn có thể (và nên) sử dụng should_notngay bây giờ, xin lỗi!
Marc-André Lauckyne

9

Sử dụng:

 Ruby:     ruby 1.9.3dev (2011-09-23 revision 33323) [i686-linux]
 Rails:    3.2.9
 Capybara: 2.0.3

Tôi có một ứng dụng Rails trong đó có một liên kết mà khi được nhấp vào sẽ gửi yêu cầu đăng AJAX và trả lại phản hồi JS.

Mã liên kết:

 link_to("Send Notification", notification_path(user_id: user_id), remote: true, method: :post)

Phản hồi JS (tệp .js.haml) sẽ chuyển đổi div ẩn sau trên trang mà liên kết tồn tại:

 #notification_status(style='display:none')

Nội dung tệp js.haml:

:plain
  var notificationStatusContainer = $('#notification_status');
  notificationStatusContainer.val("#{@notification_status_msg}");
  notificationStatusContainer.show();

Tôi đang thử nghiệm kịch bản gửi thông báo và hiển thị thông báo trạng thái thông báo cho người dùng bằng cách sử dụng Cucumber ( đá quý dưa chuột-rails với hỗ trợ Capybara được tích hợp sẵn )

Tôi đang cố gắng kiểm tra xem phần tử có id: notification_status hiển thị khi phản hồi thành công trong định nghĩa bước của tôi. Để làm được điều này, tôi đã thử các câu lệnh sau:

page.find('#notification_status').should be_visible
page.should have_selector('#notification_status', visible: true)
page.should have_css('#notification_status', visible: true)
page.find('#notification_status', visible: true)
page.find(:css, 'div#notification_status', visible: true)

Không có cách nào ở trên phù hợp với tôi và không thực hiện được bước của tôi. Trong số 5 đoạn mã được liệt kê ở trên, 4 đoạn mã cuối cùng không thành công với lỗi sau:

'expected to find css "#notification_status" but there were no matches. Also found "", which matched the selector but not all filters. (Capybara::ExpectationNotMet)'

điều này thật kỳ lạ vì câu lệnh sau đã được chuyển đúng cách:

page.has_selector?('#notification_status')

Và trên thực tế, tôi đã kiểm tra nguồn trang bằng cách sử dụng

  print page.html

mà đã xuất hiện

<div style='' id='notification_status'></div>

mà đã được mong đợi.

Cuối cùng, tôi tìm thấy liên kết này capybara khẳng định thuộc tính của một phần tử hiển thị cách kiểm tra thuộc tính của phần tử theo cách thô.

Tôi cũng tìm thấy trong tài liệu Capybara cho hiển thị? phương thức ( http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Element#visible%3F-instance_method ) thông tin sau:

 Not all drivers support CSS, so the result may be inaccurate.

Vì vậy, tôi đã đi đến kết luận rằng khi kiểm tra khả năng hiển thị của một phần tử không dựa vào kết quả của khả năng hiển thị của Capybara? khi sử dụng bộ chọn CSS và sử dụng giải pháp được đề xuất trong liên kết capybara xác nhận thuộc tính của một phần tử

Tôi đã nghĩ ra sau:

 module CustomMatchers
   def should_be_visible(css_selector)
    find(css_selector)['style'].should_not include('display:none', 'display: none')
   end
 end

 World(CustomMatchers)

Sử dụng:

should_be_visible('#notification_status')

8

Phương tiện hữu hình là gì không rõ ràng

Lỗi có thể do hiểu nhầm về những gì được coi là có thể nhìn thấy được hoặc không vì nó không rõ ràng, không phải trình điều khiển di động và không được ghi chép đầy đủ. Một số bài kiểm tra:

HTML:

<div id="visible-empty"                                                                   ></div>
<div id="visible-empty-background"      style="width:10px; height:10px; background:black;"></div>
<div id="visible-empty-background-same" style="width:10px; height:10px; background:white;"></div>
<div id="visible-visibility-hidden"     style="visibility:hidden;"                        >a</div>
<div id="visible-display-none"          style="display:none;"                             >a</div>

Điều duy nhất mà Rack test coi là vô hình là nội tuyến display: none(không phải CSS nội bộ vì nó không làm bộ chọn):

!all('#visible-empty',                 visible: true).empty? or raise
!all('#visible-empty-background',      visible: true).empty? or raise
!all('#visible-empty-background-same', visible: true).empty? or raise
!all('#visible-visibiility-hidden',    visible: true).empty? or raise
 all('#visible-display-none',          visible: true).empty? or raise

Poltergeist có một hành vi tương tự, nhưng nó có thể đối phó với style.displaythao tác CSS và Js nội bộ :

Capybara.current_driver = :poltergeist
!all('#visible-empty',                 visible: true).empty? or raise
!all('#visible-empty-background',      visible: true).empty? or raise
!all('#visible-empty-background-same', visible: true).empty? or raise
!all('#visible-visibiility-hidden',    visible: true).empty? or raise
 all('#visible-display-none',          visible: true).empty? or raise

Selenium hoạt động khá khác biệt: nếu coi một phần tử rỗng là vô hình và visibility-hiddencũng như display: none:

Capybara.current_driver = :selenium
 all('#visible-empty',                 visible: true).empty? or raise
!all('#visible-empty-background',      visible: true).empty? or raise
!all('#visible-empty-background-same', visible: true).empty? or raise
 all('#visible-visibiility-hidden',    visible: true).empty? or raise
 all('#visible-display-none',          visible: true).empty? or raise

Một quy tắc phổ biến khác là giá trị mặc định của visible:

  • nó đã từng là false(nhìn thấy cả yếu tố nhìn thấy và không nhìn thấy),
  • hiện tại là true
  • được kiểm soát bởi Capybara.ignore_hidden_elementstùy chọn.

Tham khảo .

Kiểm tra đầy đủ có thể chạy trên GitHub của tôi .


1
Câu trả lời tuyệt vời - cảm ơn vì nỗ lực bạn đã bỏ ra cho việc này. Kiểm tra khả năng hiển thị của các phần tử trong một bộ sử dụng nhiều trình điều khiển là không hề nhỏ.
Andy Triggs

1
"nó từng là false (nhìn thấy cả phần tử hiển thị và không nhìn thấy), hiện tại là true và được kiểm soát bởi tùy chọn Capybara.ignore_hiised_elements." Xem bài đăng trên blog này để biết thêm thông tin: elabs.se/blog/60-introductioning-capybara-2-1
rizidoro

5

Bạn có thể muốn xem bài đăng này , nó cung cấp một phương pháp mẫu để đợi cho đến khi tất cả các yêu cầu ajax hoàn tất:

def wait_for_ajax(timeout = Capybara.default_wait_time)
  page.wait_until(timeout) do
    page.evaluate_script 'jQuery.active == 0'
  end
end

5
Giải pháp này không tương thích trong tương lai, vì wait_untilđã bị xóa khỏi Capybara 2 .
parhamr

1
Sử dụngTimeout.timeout
Ian Vaughan

Sử dụng tốt hơnSelenium::WebDriver::Wait
Nakilon

nếu bạn chỉ sử dụng selen
Nickolay Kondratenko

2

Câu trả lời được chấp nhận hiện đã hơi lỗi thời vì cú pháp 'should' không được dùng nữa. Những ngày này, tốt hơn hết bạn nên làm điều gì đó dọc theo dòngexpect(page).not_to have_css('#blah', visible: :hidden)


1

Các câu trả lời khác ở đây là cách tốt nhất để "đợi" phần tử. Tuy nhiên, tôi thấy điều này không hiệu quả với trang web tôi đang làm việc. Về cơ bản, phần tử cần nhấp đã được hiển thị trước khi hàm đằng sau được tải đầy đủ. Đây là phần nhỏ của một giây nhưng tôi thấy bài kiểm tra của tôi chạy nhanh đến mức nó đã nhấp vào nút và không có gì xảy ra. Tôi đã xoay sở để giải quyết nó bằng cách thực hiện biểu thức boolean make-shift này:

if page.has_selector?('<css-that-appears-after-click>')
  puts ('<Some-message-you-want-printed-in-the-output>')
else
  find('<css-for-the-button-to-click-again>', :match == :first).trigger('click')
end

Về cơ bản, nó sử dụng thời gian chờ mặc định capybara để tìm kiếm thứ gì đó sẽ xuất hiện, nếu không có nó sẽ thử lại lần nhấp của bạn.

Một lần nữa tôi sẽ nói rằng should have_selectorphương pháp này nên được thử trước nhưng nếu nó không hoạt động, hãy thử cách này

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.