카피 바라 모호성 해결


97

카피 바라의 모호성을 어떻게 해결합니까? 어떤 이유로 페이지에 동일한 값을 가진 링크가 필요하지만 오류가 발생하여 테스트를 만들 수 없습니다.

Failure/Error: click_link("#tag1")
     Capybara::Ambiguous:
       Ambiguous match, found 2 elements matching link "#tag1"

이것을 피할 수없는 이유는 디자인 때문입니다. 트윗 / 태그가 오른쪽에, 태그가 페이지 왼쪽에있는 트위터 페이지를 다시 만들려고합니다. 따라서 동일한 페이지에 동일한 링크 페이지가 표시되는 것은 불가피합니다.


코드도 게시 해 주시겠습니까?
Heena Hussain 2012 년

8
페이지의 두 요소에 동일한 ID를 할당해서는 안됩니다. 동일한 링크가있는 경우 요소에 ID를 할당하지 말고 대신 클래스를 사용하십시오.
Chris Salzberg

답변:


147

내 해결책은

first(:link, link).click

대신에

click_link(link)

6
이 문제가있는 경우 유용 할 수 있는 Capybara 업그레이드 가이드에 자세히 설명되어 있습니다.
Ritchie

1
Capybara 2.0부터는 꼭 필요한 경우가 아니면이 작업을 수행하지 마십시오. 아래 @Andrey의 답변과 위에 링크 된 업그레이드 가이드에서 모호한 일치에 대한 설명을 참조하십시오.
jim

4
특히, Capybara 2.0은 최소한의 필요한 시간 만 기다리면서 처리 속도가 다른 시스템에서 사양이 일관되게 통과 또는 실패 할 수 있도록하는 지능형 대기 로직을 ​​가지고 있습니다. first위에서 제안한대로 사용하면 수행중인 작업을 완전히 알지 못하는 경우 통과하지만 CI 빌드 또는 동료의 컴퓨터에서 실패하는 사양이 발생할 수 있습니다.
jim

1
좋은 토론은 다음을 참조하십시오 : robots.thoughtbot.com/…
jim

74

Capybara의 이러한 행동은 의도적이며 다른 대부분의 답변에서 제안한대로 수정해서는 안된다고 생각합니다.

2.0 이전 버전의 Capybara는 예외를 발생시키는 대신 첫 번째 요소를 반환했지만 나중에 Capybara의 메인테이너는 그것이 나쁜 생각이고 그것을 올리는 것이 낫다고 결정했습니다. 많은 상황에서 첫 번째 요소를 반환하면 개발자가 반환하고자하는 요소가 반환되지 않는 것으로 결정되었습니다.

여기에서 가장 많이 찬성 된 답변은 first또는 all대신 사용하는 것이 좋습니다 find.

  1. all그리고 first비록 페이지에 표시됩니다 같은 로케이터와 요소까지 기다리지 않는다 find대기 않습니다
  2. all(...).first그리고 first앞으로 이러한 로케이터와 다른 요소가 페이지에 표시 될 수 있다는 상황에서 당신을 보호하지 않으며 결과로 당신은 잘못된 요소를 찾을 수 있습니다

따라서 덜 모호한 다른 로케이터 를 선택하는 것이 좋습니다. 예를 들어 하나의 요소 만 일치하도록 ID, 클래스 또는 기타 css / xpath 로케이터별로 요소를 선택합니다.


모호성을 해결할 때 일반적으로 유용하다고 생각하는 몇 가지 로케이터는 다음과 같습니다.

  • find('ul > li:first-child')

    페이지에 first('ul > li')처음 li나타날 때까지 기다리는 것보다 더 유용 합니다.

  • click_link('Create Account', match: :first)

    first(:link, 'Create Account').click페이지에 하나 이상의 계정 만들기 링크가 나타날 때까지 기다리는 것보다 낫습니다 . 그러나 페이지에 두 번 나타나지 않는 고유 한 로케이터를 선택하는 것이 좋습니다.

  • fill_in('Password', with: 'secret', exact: true)

    exact: true Capybara에게 정확히 일치하는 항목 만 찾도록 지시합니다. 즉, "암호 확인"을 찾지 못합니다.


7
이것이 최고의 답변이어야합니다. 항상 Capybara에 내장 된 대기 기능을 사용할 선택기를 사용하십시오.
tgf 2014 년

감사. 나는 사용하려고 시도했지만 jQuery에서만 작동한다는 것을 깨달았습니다. 내가 찾던 것은 : first-child
Overload119


24

새로운 답변 :

다음과 같은 것을 시도 할 수 있습니다.

all('a').select {|elt| elt.text == "#tag1" }.first.click

사용 가능한 Capybara 구문을 더 잘 사용할 수있는 방법이있을 수 있습니다. 즉, 줄을 따라 가면서 all("a[text='#tag1']").first.click올바른 구문을 생각할 수 없으며 적절한 문서를 찾을 수 없습니다. 즉, 이상한 상황의 약간이 개 필요로 시작하는 말했습니다 <a>같은과 태그 id, class및 텍스트. find withinDOM의 적절한 세그먼트 를 수행 할 수 있으므로 다른 div의 자식 일 가능성이 있습니까? (HTML 소스를 보면 도움이 될 것입니다).


이전 답변 : (여기서 '# tag1'은 요소 id에 "tag1" 이 있음을 의미한다고 생각했습니다. )

어떤 링크를 클릭 하시겠습니까? 첫 번째 (또는 중요하지 않음)라면 할 수 있습니다.

find('#tag1').click

그렇지 않으면 할 수 있습니다

all('#tag1')[1].click

두 번째를 클릭합니다.


첫 번째 솔루션은 작동 할 수 있지만 이제 문제는 css ID로 오인 될 수 있다는 것입니다 .--------- 실패 / 오류 : find ( '# tag1'). click # 또는 all ( '# tag1 ') [0] .click Capybara :: ElementNotFound : css "# tag1"을 찾을 수 없음
neilmarion

find('#tag1')id가있는 하나의 요소 만 찾으려는 것을 의미합니다 tag1. ID를 가진 여러 요소가 있기 때문에 예외가 발생 tag1페이지가
안드레이 Botalov에게

당신은 할 수 있습니다 all(:xpath, '//a[text()="#tag1"]').first.click.
슈헤이 가가

9

다음을 사용하여 첫 번째 것을 찾을 수 있습니다 match.

find('.selector', match: :first).click

그러나 중요한 것은, 당신은 아마이 일을하지 않으려 는 이어질 것으로, 취성 시험을 중복 출력 코드 냄새를 무시하는 차례 리드에서 오탐 (false positive) 가 실패해야 할 때 하나의 일치를 제거하기 때문에, 작업을 계속 요소이지만 테스트는 행복하게 다른 것을 찾았습니다.

더 나은 방법은 다음을 사용하는 것입니다 within.

within('#sidebar') do
  find('.selector).click
end

이렇게하면 찾을 것으로 예상되는 요소를 찾는 동시에 Capybara의 자동 대기 및 자동 재시도 기능 (를 사용하면 손실 됨)을 계속 활용 find('.selector').click하여 의도가 무엇인지 훨씬 명확하게 알 수 있습니다.


7

여기에 기존 지식을 추가하려면 :

JS 테스트의 경우 Capybara는 두 개의 스레드 (하나는 RSpec, 하나는 Rails)와 두 번째 프로세스 (브라우저)를 동기화 상태로 유지해야합니다. 대부분의 매처 및 노드 찾기 방법에서 대기 (구성된 최대 대기 시간까지)하여이를 수행합니다.

Capybara에는 주로 기다리지 않는 메서드가 Node#all있습니다. 그것들을 사용하는 것은 간헐적으로 실패하기를 바라는 스펙을 말하는 것과 같습니다.

받아 들여지는 대답은 page.first('selector'). 을 Node#first사용Node#all 하기 때문에 적어도 JS 사양에서는 바람직하지 않습니다 .

즉, Capybara를 다음과 같이 구성 Node#first 하면 기다립니다.

# rails_helper.rb
Capybara.wait_on_first_by_default = true

이 옵션은 Capybara 2.5.0에서 추가 되었으며 기본적으로 false입니다.

Andrei가 언급했듯이 대신

find('selector', match: :first)

또는 선택기를 변경하십시오. 둘 다 구성 또는 드라이버에 관계없이 잘 작동합니다.

더 복잡하게하기 위해 이전 버전의 Capybara (또는 구성 옵션이 활성화 된 경우)에서는 #find모호함을 기꺼이 무시하고 첫 번째 일치하는 선택자를 반환합니다. 이것은 당신의 사양을 덜 명확하게 만들기 때문에 좋지 않습니다. 이것이 더 이상 기본 동작이 아닌 이유입니다. 세부 사항은 위에서 이미 논의 했으므로 생략하겠습니다.

추가 리소스 :


5

이 게시물 로 인해 "일치"옵션을 통해 수정할 수 있습니다.

Capybara.configure do |config|
  config.match = :prefer_exact
end

2

위의 모든 옵션을 고려하여 이것도 시도해 볼 수 있습니다.

find("a", text: text, match: :prefer_exact).click

오이를 사용하신다면 이거도 따라 가세요

다시 재사용하기위한 일반 단계가 될 수있는 시나리오 단계의 매개 변수로 텍스트를 전달할 수 있습니다.

같은 것 When a user clicks on "text" link

그리고 단계적 정의에서 When(/^(?:user) clicks on "([^"]*)" (?:link)$/) do |text|

이렇게하면 코드 줄을 최소화하여 동일한 단계를 재사용 할 수 있으며 새로운 오이 시나리오를 쉽게 작성할 수 있습니다.


0

오이의 모호한 오류를 피하기 위해.

해결책 1

first("#tag1").click

해결 방법 2

Cucumber features/filename.feature --guess
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.