Làm thế nào để lấy nút cha trong Capybara?


85

Tôi đang làm việc với nhiều plugin jQuery, thường tạo các phần tử DOM mà không có id hoặc các thuộc tính nhận dạng khác và cách duy nhất để lấy chúng trong Capybara (ví dụ: nhấp chuột) - là lấy hàng xóm của họ (một đứa con khác của tổ tiên) . Nhưng tôi không tìm thấy ở đâu Capybara hỗ trợ những thứ như vậy chẳng hạn:

find('#some_button').parent.fill_in "Name:", :with => name

?


Ngoài ra, nó sẽ rất hữu ích cho tôi, nếu bạn cho biết, Capybara có tạo nhấp chuột vào các phần tử có {display: hidden} không, và có cách nào để tìm các phần tử trong một số phạm vi, nơi display! = Hidden không?
sandrew

Đây là một câu hỏi riêng biệt, nhưng nó phụ thuộc vào trình điều khiển mà bạn đang sử dụng. webrat sẽ vui vẻ tìm thấy những thứ ẩn, nhưng selen không vui bằng việc nhấp vào các mục mà bạn không thể nhìn thấy.
jamuraa

Câu trả lời:


111

Tôi thực sự thấy câu trả lời của jamuraa hữu ích, nhưng việc sử dụng xpath đầy đủ khiến tôi gặp ác mộng về một chuỗi trong trường hợp của tôi, vì vậy tôi vui vẻ sử dụng khả năng nối các tìm kiếm trong Capybara, cho phép tôi kết hợp lựa chọn css và xpath. Ví dụ của bạn sau đó sẽ giống như sau:

find('#some_button').find(:xpath,".//..").fill_in "Name:", :with => name

Cập nhật Capybara 2.0 : find(:xpath,".//..")rất có thể sẽ Ambiguous matchxảy ra lỗi. Trong trường hợp đó, hãy sử dụng first(:xpath,".//..")thay thế.


Cảm ơn vì ý tưởng đó - tôi chưa bao giờ nghĩ đến điều đó! Tôi đang thực hiện el.parent cho một phần tử td mà tôi tìm thấy với find (: css), nhưng vì một số lý do tôi không hiểu, el.parent đã trả về # <Capybara :: Document>. el.find (: xpath, ".// ..") mặt khác trả về # <Capybara :: Element tag = "tr">, đó là những gì tôi cần.
Tyler Rick

Một cách khác để tìm một cách đệ quy một nút cha nhất định là sử dụng bộ chọn tổ tiên hoặc tự của xpath. Hãy xem stackoverflow.com/questions/1362466/…
vrish88

25
Bạn không cần .//..phải tìm cha mẹ - chỉ ..cần đủ, và điều đó cũng không bao giờ mơ hồ.
Eamon Nerbonne

ty! Tôi biết nhận xét này là một chút muộn để đảng, nhưng tôi ngưng tụ nó xuống như sau sau khi đọc chỉnh sửa, và bình luận Eamon của: el.first (: xpath, '..')
aschyiel

39

Không có cách nào để làm điều này với capybara và CSS. Tuy nhiên, tôi đã sử dụng XPath trước đây để thực hiện mục tiêu này, tuy nhiên, nó có cách để lấy phần tử mẹ và được hỗ trợ bởi Capybara:

find(:xpath, '//*[@id="some_button"]/..').fill_in "Name:", :with => name

2
Khi tôi thực hiện một tìm kiếm xpath tương tự, tôi gặp lỗi Nokogiri nói rằng biểu thức không hợp lệ. Tôi thêm một trước mặt dấu của braket vuông mở trong biểu thức để sửa chữa các biểu hiện:find(:xpath, '//*[@id="some_button"]/..')
Andrew Ferk

35

Tôi thấy những điều sau đây hoạt động:

find(:xpath, '..')

Capybara đã được cập nhật để hỗ trợ điều này.

https://github.com/jnicklas/capybara/pull/505


1
Đối với tôi, có vẻ như bạn đang trả lời / hoàn thành một câu trả lời trước đó ở đây ("Cái này" cái gì "không hoạt động"?). Sẽ tốt hơn nếu đó là một câu trả lời đầy đủ và độc lập. Vì vậy, tôi khuyên bạn nên chỉnh sửa nó. ;-)
helenov

Có thể xác nhận. Với Capybara 2.14.4 mới nhất, đây là cách thích hợp để lấy nút cha.
fny 25/07/17

10

Nếu bạn tình cờ gặp phải điều này khi cố gắng tìm cách tìm bất kỳ nút cha nào (như trong tổ tiên ) (như được gợi ý trong nhận xét của @ vrish88 về câu trả lời của @Pascal Lindelauf):

find('#some_button').find(:xpath, 'ancestor::div[@id="some_div_id"]')

5

Câu trả lời này liên quan đến cách thao tác một phần tử anh em, đó là điều mà tôi tin rằng câu hỏi ban đầu đang ám chỉ đến

Giả thuyết câu hỏi của bạn hoạt động với một chỉnh sửa nhỏ. Nếu trường được tạo động trông giống như thế này và không có id:

<div>
  <input></input>
  <button>Test</button>
</div>

Khi đó truy vấn của bạn sẽ là:

find('button', text: 'Test').find(:xpath, "..").find('input').set('whatever')

Nếu đầu vào được tạo động đi kèm với một phần tử id (hãy cẩn thận với những phần tử này mặc dù như trong góc, chúng sẽ không thay đổi dựa trên việc thêm và xóa phần tử) thì nó sẽ giống như sau:

find('button', text: 'Test').find(:xpath, "..").fill_in('#input_1', with: 'whatever')

Hy vọng rằng sẽ giúp.


4

Tôi đang sử dụng một cách tiếp cận khác bằng cách tìm phần tử mẹ trước tiên bằng cách sử dụng văn bản trong phần tử mẹ này:

find("<parent element>", text: "text within your #some_button").fill_in "Name:", with: name

Có thể điều này hữu ích trong một tình huống tương tự.


1
Đây là một lựa chọn tuyệt vời. Tôi xác định phạm vi hành động ui cho một phần của trang có chứa một số văn bản cụ thể là một trường hợp sử dụng phổ biến đối với tôi.
clemensp

2

Tôi cần tìm tổ tiên có lớp css, mặc dù không xác định được nếu tổ tiên mục tiêu có một hoặc nhiều lớp css, vì vậy tôi không thấy cách nào để thực hiện truy vấn xpath xác định. Thay vào đó, tôi đã làm việc này:

def find_ancestor_with_class(field, cssClass)
  ancestor = field
  loop do
    ancestor = ancestor.find(:xpath, '..')
    break if ancestor.nil?

    break if ancestor.has_css? cssClass
  end

  ancestor
end

Cảnh báo: sử dụng điều này một cách tiết kiệm, nó có thể khiến bạn mất rất nhiều thời gian trong các bài kiểm tra, vì vậy hãy đảm bảo rằng tổ tiên chỉ cách chúng ta vài bước.


Tăng tốc: thay thế lần nghỉ thứ hai của bạn bằng break if ancestor[:class].split(" ").include?(css_class).
hakunin

@hakunin Tôi tò mò bạn đang thấy tốc độ tăng đến mức nào? Có ý nghĩa?
kross

Không thể kiểm tra ngay bây giờ, nhưng has_css dường như mất một giây, trong khi việc đối sánh lớp dường như ngay lập tức.
hakunin

Capybara hiện nay có một ancestor(selector)phương pháp xây dựng trong See. Github.com/teamcapybara/capybara/commit/...
Tyler Rick

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.