8

I was just wondering if you could point out where the problem is here, if it's Behat, the CSS selector, or the Sahi Driver.

We have just upgraded to Behat 3 and are using Sahi Driver (most recent open source version). We have found that any Behat test that uses the pseudo-element first-child now seems to break.

Example:

Step:

And I follow "#the-list tr:first-child .row-title"

(which contains an anchor element with the class row-title on it, see HTML)

Error:

Link with id|title|alt|text "#the-list tr:first-child .row-title" not found. (Behat\Mink\Exception\ElementNotFoundException)

HTML:

<tbody id="the-list">
    <tr id="post-162382" class="post-162382 type-post status-publish format-standard hentry category-uncategorized alternate iedit author-other level-0">
        <th class="check-column" scope="row"></th>
        <td class="post-title page-title column-title">
            <strong>
                <a class="row-title" title="Edit “Post Title”" href="https://domain.com"></a>
            </strong>
            <div class="locked-info"></div>
            <div class="row-actions"></div>
            <div id="inline_162382" class="hidden"></div>
        </td>

CSSSelector.php (override we used with our old Behat, we left this file in)

/**
 * Makes all of the form field related steps allow CSS selectors.
 */
class CSSSelectorContext extends MinkContext
{
    /**
     * Finds an element via CSS or fails with a given error
     * 
     * @param $element string   A CSS selector string
     * @param $error Exception  An error to throw in case the element can not be found
     * @return object           An Element object
     */
    protected function findOrFail($element, $error){
        $element = $this->getSession()->getPage()->find('css', $element);
        if (!isset($element)){     
            throw $error;
        }
        return $element;
    }

    public function clickLink($link) {
        try {
            parent::clickLink($link);
            return;
        }catch (Exception $error){
            $link = $this->fixStepArgument($link);
            $link = $this->findOrFail($link, $error);
            $link->press();
        }
    }

When using the css selector in the Chrome console with jquery it selects the appropriate element. I went through the code and looked at the css -> xpath translations and then validated the xpath against the html that is produced on the site we are testing and it seems to be valid as well. The css selector also works with Goutte driver.

Generated XPath:

    find(function(){
        var count = 0;
        while (_sahi._byXPath("("+"\/\/html\/descendant-or-self::*[@id = 'the-list']\/descendant-or-self::*\/*[name() = 'tr' and (position() = 1)]\/descendant-or-self::*\/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' row-title ')]"+")["+(count+1)+"]")) count++;
        return count;
    })()

descendant-or-self::*[@id = 'the-list']/descendant-or-self::*/*[name() = 'tr' and (position() = 1)]/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' row-title ')]

//html/descendant-or-self::*[@id = 'the-list']/descendant-or-self::*/*[name() = 'tr' and (position() = 1)]/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' row-title ')]

When I change the CSS to:

Step:

And I follow "#the-list tr .row-title"

It works because I believe it just picks the first tr from a list of them anyway, but we want to be able to use first-child of course.

Thanks for your help!

BoltClock
  • 630,065
  • 150
  • 1,295
  • 1,284
sugarwaffle
  • 541
  • 4
  • 13
  • 1
    [This github issue](https://github.com/Behat/Mink/issues/268) seems to be talking about the same thing. Does it help at all? – Paul Richter Nov 26 '14 at 17:09
  • The issue https://github.com/symfony/symfony/issues/11803 is relevant, but it doesn't make sense because the Xpath that is generated by Symfony seems correct. – sugarwaffle Nov 26 '14 at 17:27
  • Have you tried "#the-list tr:nth-child(1) .row-title"? – miguel-svq Dec 20 '15 at 11:52
  • How about just doing it this way and positioning with css of necessary as a work around #the-list .row-title – Carol McKay Jan 19 '16 at 01:24
  • Sorry if a silly/patronising question but have you inspected the element through Firebug to rule out anything else overriding the rules and are you processing the CSS in any way - leading to, have you double checked the output CSS in additon to your development copy? – R Reveley Mar 04 '16 at 08:47
  • I am no longer using Behat (switched jobs) so I am not able to comment on this anymore and don't have time to investigate possible solutions/answers. Thanks for your efforts. – sugarwaffle Mar 29 '16 at 21:31

1 Answers1

0

Sorry for being late to the party

Your problem here is the fact that Minks own step "I follow"/"clickLink" doesn't accept the following:

  1. "#"s for ID's
  2. Anything other than an ID, Text, Title or Alternate Value.

I suggest using a "click on the" step instead of a "follow", something like this:

    /**
     * @Then /^(?:|I )click (?:|on )(?:|the )"([^"]*)"(?:|.*)$/
     */
    public
    function iClickOn($arg1)
    {
        $findName = $this->getSession()->getPage()->find("css", $arg1);
        if (!$findName) {
            throw new Exception($arg1 . " could not be found");
        } else {
            $findName->click();
        }
    }

You're using CSS right here, which will allow for this to be written:

Then I click on the "#the-list tr:first-child .row-title" link

It is a mistake I also made, and this is the solution we decided on then, and we haven't had to look back.

KyleFairns
  • 2,754
  • 1
  • 11
  • 33