.//a[./@href][(((./@id = 'Number 3, Contact' or normalize-space(string(.)) = 'Number 3, Contact') or ./@title = 'Number 3, Contact') or .//img[./@alt = 'Number 3, Contact'])
I wanted to make sure that my page does not have this link:
<a href="/contacts/5">Number 3, Contact</a>
But because it *does* have this Delete link, it found the text in title, and the test failed:
<a href="/contacts/5" data-confirm="Are you sure?" data-method="delete" rel="nofollow" title="Delete Number 3, Contact">Delete</a>
My workaround is to write the xpath myself:
it { should_not have_xpath("//a[contains(text(), 'Number 3, Contact')]/@href") }
When I read "has_link", I think of specifying the actual, underlined, blue * link*. I would rather specify qualifiers (id, title, img-alt, href) as additional options. Probably too late for that discussion, but it would help if the docs listed *all* the elements that the locator includes in its searches.
And I would love it if there was a way to turn on "extra info" for failing tests so that, for example,
expected link "Number 3, Contact" not to return anything
could become
expected link "Number 3, Contact" not to return anything, but found a matching link at this xpath: /html/body/div/section/div/div[2]/div[4]/table/tbody/tr[5]/td[3]/a[2]
Digging that out of a console-based debugger is painful!
On Sat, Sep 15, 2012 at 2:22 AM, mcbsys <mcbsyst...@gmail.com> wrote:
> Probably too late for that discussion, but it would help
> if the docs listed all the elements that the locator includes in its
> searches.
> expected link "Number 3, Contact" not to return anything
> could become
> expected link "Number 3, Contact" not to return anything, but found a
> matching link at this xpath:
> /html/body/div/section/div/div[2]/div[4]/table/tbody/tr[5]/td[3]/a[2]
On master, it's
expected not to find link "Number 3, Contact", but there was 1 match
which is marginally better. I don't see a reason why we couldn't also
provide an xpath, but it gets a little tricky if there's more than one
match.
Re. the documentation, I could probably fix *has_no_link?* with moderate confidence, but the whole set of matchers needs review, and I'm still pretty lost when I try to read through the code. I picked the random example of has_select, where the doc
which matches on what to me is a pretty opaque combination of id, name, placeholder, label, for, label (again), and disabled.
Do you want me to do a pull for the *has_no_link?* line? I think that should be:
"Checks if the page or current node has no link with the given text, id, title, or img alt attribute."
Probably *has_link?* would be:
"Checks if the page or current node has a link with the given text, id, title, or img alt attribute."
> I don't see a reason why we couldn't also provide an xpath, but it gets > a little tricky if there's more than one match.
Thanks for considering this! Hopefully you have the array of xpaths that you could dump? e.g.
expected not to find link "Number 3, Contact", but there were 2 matches with xpaths /html/body/div/section/div/div[2]/div[4]/table/tbody/tr[5]/td[3]/a[2] /html/body/div/section/div/div[2]/div[4]/table/tbody/tr[6]/td[3]/a[2]
On Friday, September 14, 2012 5:40:56 PM UTC-7, Jo Liss wrote:
> On Sat, Sep 15, 2012 at 2:22 AM, mcbsys <mcbsy...@gmail.com <javascript:>> > wrote: > > Probably too late for that discussion, but it would help > > if the docs listed all the elements that the locator includes in its > > searches.
> Hm, seems like the documentation is indeed off, at least here:
> > expected link "Number 3, Contact" not to return anything
> > could become
> > expected link "Number 3, Contact" not to return anything, but found a > > matching link at this xpath: > > /html/body/div/section/div/div[2]/div[4]/table/tbody/tr[5]/td[3]/a[2]
> On master, it's
> expected not to find link "Number 3, Contact", but there was 1 match
> which is marginally better. I don't see a reason why we couldn't also > provide an xpath, but it gets a little tricky if there's more than one > match.
So to search on exact link text, optionally with an exact href, I added this to my spec_helper.rb:
def has_exact_link?(locator, options={}) if options[:href] xpath = "//a[text()='#{locator}' and @href='#{options[:href]}']" options.delete :href else xpath = "//a[text()='#{locator}']/@href" end has_xpath?(xpath, options) end
Then I can call:
it { should have_exact_link("Number 3, Contact") } # check exact text only it { should have_exact_link("Number 3, Contact", href: "/accounts/5") } # also check href
To my surprise it seems to work! Is that the best way to write it? The only drawback is that by deleting :href from options, the test output shows options = {}. But I wanted to be sure that options did not include the href that I handled in the xpath.
I thought about using
it { should have_selector('a', text: "Number 3, Contact", href: "/accounts/5" }
but it seems that silently discards the href option. (Here's where I wish I could inspect the generated xpath query!)
> After extended time with the debugger, I found out that the reason my test > was failing is because has_no_link also searches for the text in the title > and img (alt) attributes (source<https://github.com/jnicklas/xpath/blob/master/lib/xpath/html.rb#L14>). > So this test:
> it { should_not have_link("Number 3, Contact") }
> became this xpath:
> .//a[./@href][(((./@id = 'Number 3, Contact' > or normalize-space(string(.)) = 'Number 3, Contact') > or ./@title = 'Number 3, Contact') > or .//img[./@alt = 'Number 3, Contact'])
> I wanted to make sure that my page does not have this link:
> <a href="/contacts/5">Number 3, Contact</a>
> But because it *does* have this Delete link, it found the text in title, > and the test failed:
> <a href="/contacts/5" data-confirm="Are you sure?" data-method="delete" > rel="nofollow" title="Delete Number 3, Contact">Delete</a>
> My workaround is to write the xpath myself:
> it { should_not have_xpath("//a[contains(text(), 'Number 3, > Contact')]/@href") }
> When I read "has_link", I think of specifying the actual, underlined, blue > *link*. I would rather specify qualifiers (id, title, img-alt, href) as > additional options. Probably too late for that discussion, but it would > help if the docs listed *all* the elements that the locator includes in > its searches.
> And I would love it if there was a way to turn on "extra info" for failing > tests so that, for example,
> expected link "Number 3, Contact" not to return anything
> could become
> expected link "Number 3, Contact" not to return anything, but found a > matching link at this xpath: > /html/body/div/section/div/div[2]/div[4]/table/tbody/tr[5]/td[3]/a[2]
> Digging that out of a console-based debugger is painful!
Just finished updating a test suite where 40 passing tests used have_link. After replacing have_link with have_exact_link, 20 tests failed. Some of those were due to the substring matching (now I have to search for "Edit contact" not just "Edit"). But many were actually succeeding by finding the wrong link due to have_link's broad search criteria.
On Saturday, September 15, 2012 6:10:19 PM UTC-7, mcbsys wrote:
> So to search on exact link text, optionally with an exact href, I added > this to my spec_helper.rb:
> def has_exact_link?(locator, options={}) > if options[:href] > xpath = "//a[text()='#{locator}' and @href='#{options[:href]}']" > options.delete :href > else > xpath = "//a[text()='#{locator}']/@href" > end > has_xpath?(xpath, options) > end
> Then I can call:
> it { should have_exact_link("Number 3, Contact") } # check exact text > only > it { should have_exact_link("Number 3, Contact", href: "/accounts/5") } > # also check href
> To my surprise it seems to work! Is that the best way to write it? The > only drawback is that by deleting :href from options, the test output shows > options = {}. But I wanted to be sure that options did not include the href > that I handled in the xpath.
> I thought about using
> it { should have_selector('a', text: "Number 3, Contact", href: > "/accounts/5" }
> but it seems that silently discards the href option. (Here's where I wish > I could inspect the generated xpath query!)
> Thanks,
> Mark
> On Friday, September 14, 2012 5:22:09 PM UTC-7, mcbsys wrote:
>> After extended time with the debugger, I found out that the reason my >> test was failing is because has_no_link also searches for the text in the >> title and img (alt) attributes (source<https://github.com/jnicklas/xpath/blob/master/lib/xpath/html.rb#L14>). >> So this test:
>> it { should_not have_link("Number 3, Contact") }
>> became this xpath:
>> .//a[./@href][(((./@id = 'Number 3, Contact' >> or normalize-space(string(.)) = 'Number 3, Contact') >> or ./@title = 'Number 3, Contact') >> or .//img[./@alt = 'Number 3, Contact'])
>> I wanted to make sure that my page does not have this link:
>> <a href="/contacts/5">Number 3, Contact</a>
>> But because it *does* have this Delete link, it found the text in title, >> and the test failed:
>> <a href="/contacts/5" data-confirm="Are you sure?" data-method="delete" >> rel="nofollow" title="Delete Number 3, Contact">Delete</a>
>> My workaround is to write the xpath myself:
>> it { should_not have_xpath("//a[contains(text(), 'Number 3, >> Contact')]/@href") }
>> When I read "has_link", I think of specifying the actual, underlined, >> blue *link*. I would rather specify qualifiers (id, title, img-alt, >> href) as additional options. Probably too late for that discussion, but it >> would help if the docs listed *all* the elements that the locator >> includes in its searches.
>> And I would love it if there was a way to turn on "extra info" for >> failing tests so that, for example,
>> expected link "Number 3, Contact" not to return anything
>> could become
>> expected link "Number 3, Contact" not to return anything, but found a >> matching link at this xpath: >> /html/body/div/section/div/div[2]/div[4]/table/tbody/tr[5]/td[3]/a[2]
>> Digging that out of a console-based debugger is painful!
> Just finished updating a test suite where 40 passing tests used have_link.
> After replacing have_link with have_exact_link, 20 tests failed. Some of
> those were due to the substring matching (now I have to search for "Edit
> contact" not just "Edit"). But many were actually succeeding by finding the
> wrong link due to have_link's broad search criteria.
> Mark
> On Saturday, September 15, 2012 6:10:19 PM UTC-7, mcbsys wrote:
>> So to search on exact link text, optionally with an exact href, I added
>> this to my spec_helper.rb:
>> def has_exact_link?(locator, options={})
>> if options[:href]
>> xpath = "//a[text()='#{locator}' and @href='#{options[:href]}']"
>> options.delete :href
>> else
>> xpath = "//a[text()='#{locator}']/@href"
>> end
>> has_xpath?(xpath, options)
>> end
>> Then I can call:
>> it { should have_exact_link("Number 3, Contact") } # check exact text
>> only
>> it { should have_exact_link("Number 3, Contact", href: "/accounts/5") }
>> # also check href
>> To my surprise it seems to work! Is that the best way to write it? The
>> only drawback is that by deleting :href from options, the test output shows
>> options = {}. But I wanted to be sure that options did not include the href
>> that I handled in the xpath.
>> I thought about using
>> it { should have_selector('a', text: "Number 3, Contact", href:
>> "/accounts/5" }
>> but it seems that silently discards the href option. (Here's where I wish
>> I could inspect the generated xpath query!)
>> Thanks,
>> Mark
>> On Friday, September 14, 2012 5:22:09 PM UTC-7, mcbsys wrote:
>>> Hi,
>>> According to the doc, has_no_link "Checks if the page or current node has
>>> no link with the given text or id."
>>> After extended time with the debugger, I found out that the reason my
>>> test was failing is because has_no_link also searches for the text in the
>>> title and img (alt) attributes (source). So this test:
>>> it { should_not have_link("Number 3, Contact") }
>>> became this xpath:
>>> .//a[./@href][(((./@id = 'Number 3, Contact'
>>> or normalize-space(string(.)) = 'Number 3, Contact')
>>> or ./@title = 'Number 3, Contact')
>>> or .//img[./@alt = 'Number 3, Contact'])
>>> I wanted to make sure that my page does not have this link:
>>> <a href="/contacts/5">Number 3, Contact</a>
>>> But because it does have this Delete link, it found the text in title,
>>> and the test failed:
>>> <a href="/contacts/5" data-confirm="Are you sure?" data-method="delete"
>>> rel="nofollow" title="Delete Number 3, Contact">Delete</a>
>>> My workaround is to write the xpath myself:
>>> it { should_not have_xpath("//a[contains(text(), 'Number 3,
>>> Contact')]/@href") }
>>> When I read "has_link", I think of specifying the actual, underlined,
>>> blue link. I would rather specify qualifiers (id, title, img-alt, href) as
>>> additional options. Probably too late for that discussion, but it would help
>>> if the docs listed all the elements that the locator includes in its
>>> searches.
>>> And I would love it if there was a way to turn on "extra info" for
>>> failing tests so that, for example,
>>> expected link "Number 3, Contact" not to return anything
>>> could become
>>> expected link "Number 3, Contact" not to return anything, but found a
>>> matching link at this xpath:
>>> /html/body/div/section/div/div[2]/div[4]/table/tbody/tr[5]/td[3]/a[2]
>>> Digging that out of a console-based debugger is painful!
On Thursday, September 20, 2012 12:03:04 AM UTC-7, jnicklas wrote:
> This is exactly why we will raise an error in the future if more than > one match is found.
> /Jonas
> On Thu, Sep 20, 2012 at 1:36 AM, mcbsys <mcbsy...@gmail.com <javascript:>> > wrote: > > I've updated has_exact_link and posted it here: > > http://stackoverflow.com/a/12469159/550712.
> > Just finished updating a test suite where 40 passing tests used > have_link. > > After replacing have_link with have_exact_link, 20 tests failed. Some of > > those were due to the substring matching (now I have to search for "Edit > > contact" not just "Edit"). But many were actually succeeding by finding > the > > wrong link due to have_link's broad search criteria.
> > Mark
> > On Saturday, September 15, 2012 6:10:19 PM UTC-7, mcbsys wrote:
> >> So to search on exact link text, optionally with an exact href, I added > >> this to my spec_helper.rb:
> >> def has_exact_link?(locator, options={}) > >> if options[:href] > >> xpath = "//a[text()='#{locator}' and > @href='#{options[:href]}']" > >> options.delete :href > >> else > >> xpath = "//a[text()='#{locator}']/@href" > >> end > >> has_xpath?(xpath, options) > >> end
> >> Then I can call:
> >> it { should have_exact_link("Number 3, Contact") } # check exact text > >> only > >> it { should have_exact_link("Number 3, Contact", href: "/accounts/5") > } > >> # also check href
> >> To my surprise it seems to work! Is that the best way to write it? The > >> only drawback is that by deleting :href from options, the test output > shows > >> options = {}. But I wanted to be sure that options did not include the > href > >> that I handled in the xpath.
> >> I thought about using
> >> it { should have_selector('a', text: "Number 3, Contact", href: > >> "/accounts/5" }
> >> but it seems that silently discards the href option. (Here's where I > wish > >> I could inspect the generated xpath query!)
> >> Thanks,
> >> Mark
> >> On Friday, September 14, 2012 5:22:09 PM UTC-7, mcbsys wrote:
> >>> Hi,
> >>> According to the doc, has_no_link "Checks if the page or current node > has > >>> no link with the given text or id."
> >>> After extended time with the debugger, I found out that the reason my > >>> test was failing is because has_no_link also searches for the text in > the > >>> title and img (alt) attributes (source). So this test:
> >>> it { should_not have_link("Number 3, Contact") }
> >>> When I read "has_link", I think of specifying the actual, underlined, > >>> blue link. I would rather specify qualifiers (id, title, img-alt, > href) as > >>> additional options. Probably too late for that discussion, but it > would help > >>> if the docs listed all the elements that the locator includes in its > >>> searches.
> >>> And I would love it if there was a way to turn on "extra info" for > >>> failing tests so that, for example,
> >>> expected link "Number 3, Contact" not to return anything
> >>> could become
> >>> expected link "Number 3, Contact" not to return anything, but found > a > >>> matching link at this xpath: