Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Selecting option of select element #75

Closed
richardmiller-zz opened this issue Sep 8, 2011 · 4 comments
Closed

Selecting option of select element #75

richardmiller-zz opened this issue Sep 8, 2011 · 4 comments

Comments

@richardmiller-zz
Copy link

Is it possible to select the option by id|value|text etc. rather than just specify the value. As far as I can see when using the step relating to select elements you can specify the select element by id|name|label|value but the value given in the step is just set to that select element. I was expecting to be able to specify the option by id or text rather than having to know the actual value.

For example:

When I select "Test Option" from "testSelect"

I get the following error:

Input "testSelect" cannot take "Test Option" as a value (possible values: testValue).

It does not work specifying the id of the option element either.

@cordoval
Copy link

@richardmiller, I have the same problem

looking at this called from here

<?php
    /**
     * Selects option from select field with specified locator.
     *
     * @param   string  $locator    input id, name or label
     *
     * @throws  Behat\Mink\Exception\ElementNotFoundException
     */
    public function selectFieldOption($locator, $value)
    {
        $field = $this->findField($locator);

        if (null === $field) {
            throw new ElementNotFoundException(
                $this->getSession(), 'form field', 'id|name|label|value', $locator
            );
        }

        $field->selectOption($value);
    }

The selectOption is:

<?php
    /**
     * Selects current node specified option if it's a select field.
     *
     * @param   string  $option
     */
    public function selectOption($option)
    {
        $this->getSession()->getDriver()->selectOption($this->getXpath(), $option);
    }

The selectOption method at this level depends on the driver implementation:

<?php
vendor/behat/mink/src/Behat/Mink/Driver/DriverInterface.php
225:    function selectOption($xpath, $value);

vendor/behat/mink/src/Behat/Mink/Driver/GoutteDriver.php
313:     * @see     Behat\Mink\Driver\DriverInterface::selectOption()
315:    public function selectOption($xpath, $value)

vendor/behat/mink/src/Behat/Mink/Driver/SahiDriver.php
366:     * @see     Behat\Mink\Driver\DriverInterface::selectOption()
368:    public function selectOption($xpath, $value)

vendor/behat/mink/src/Behat/Mink/Driver/ZombieDriver.php
454:     * @see     Behat\Mink\Driver\DriverInterface::selectOption()
456:    public function selectOption($xpath, $value)

vendor/behat/mink/src/Behat/Mink/Behat/Context/BaseMinkContext.php
204:    public function selectOption($select, $option)

If we take sahi for instance we find this:

<?php
    /**
     * @see     Behat\Mink\Driver\DriverInterface::selectOption()
     */
    public function selectOption($xpath, $value)
    {
        $type = $this->getAttribute($xpath, 'type');

        if ('radio' === $type) {
            $this->selectRadioOption($xpath, $value);
        } else {
            $this->client->findByXPath($this->prepareXPath($xpath))->choose($value);
        }
    }

And most likely down to the bottom at this level all is implementation dependent.

Therefore the only place where we can swap is up the chain,

<?php
    /**
     * Selects option from select field with specified locator.
     *
     * @param   string  $locator    input id, name or label
     *
     * @throws  Behat\Mink\Exception\ElementNotFoundException
     */
    public function selectFieldOption($locator, $value)
    {
        $field = $this->findField($locator);

        if (null === $field) {
            throw new ElementNotFoundException(
                $this->getSession(), 'form field', 'id|name|label|value', $locator
            );
        }

        //  here we transform $value _if_ $value is the contents of the <option value="x">y</option> tags so $value == y
        //  into $value == x

        $field->selectOption($value);
    }

In order to rule out the ambiguity of this situation we will create another method on the base mink context class, since it seems it keeps BC and also simplifies the code.

<?php
    /**
     * Selects option label in select field with specified id|name|label|value.
     *
     * @When /^(?:|I )select label "(?P<optionLabel>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/
     */
    public function selectOption($select, $optionLabel)
    {
        $select = str_replace('\\"', '"', $select);
        $option = str_replace('\\"', '"', $optionLabel);
        $this->getSession()->getPage()->selectFieldOptionLabel($select, $optionLabel);
    }

And we write selectFieldOptionLabel as:

<?php
    /**
     * Selects option from select field with specified locator.
     *
     * @param   string  $locator    input id, name or label
     * @param   string  $optionLabel    label between option tags       
     * @throws  Behat\Mink\Exception\ElementNotFoundException
     */
    public function selectFieldOptionLabel($locator, $optionLabel)
    {
        $field = $this->findField($locator);

        if (null === $field) {
            throw new ElementNotFoundException(
                $this->getSession(), 'form field', 'id|name|label|value', $locator
            );
        }

        // get $value from $optionLabel
        $value = $field->fromLabelToValue($optionLabel);

        $field->selectOption($value);
    }

@richardmiller there is an optgroup or option named selectors on mink documentation here, in addition to this there is support for nested traversing ... thus we can reuse $field as below

perhaps we can use those to do something like:

<?php
 $optionItems = $field->findAll???();
 foreach $optionItems as $item {
    if($item->getText() == $optionLabel) {
       $valueOption = $item->getValue();
    }
 }

@cordoval
Copy link

@richardmiller

see below, can you please help?

<?php
 /**
     * Selects option from select field with specified locator.
     *
     * @param   string  $locator    input id, name or label
     *
     * @throws  Behat\Mink\Exception\ElementNotFoundException
     */
    public function selectFieldOption($locator, $value)
    {
        /* @var \Behat\Mink\Element\NodeElement $field */
        $field = $this->findField($locator);

        if (null === $field) {
            throw new ElementNotFoundException(
                $this->getSession(), 'form field', 'id|name|label|value', $locator
            );
        }

        /* @var \Behat\Mink\Selector\SelectorsHandler $handler */
        $handler = $this->getSession()->getSelectorsHandler();

        $optionElements = $this->findAll('named', array(
            'option', $handler->selectorToXpath('css', 'option')
        ));

        /* @var \Behat\Mink\Element\NodeElement $optionElements */
        foreach ($optionElements as $item) {
            if((string)$item->getText() == $value) {
                //$actualValue = $item->getValue();
                var_export('1');
            }
        }
        $field->selectOption($actualValue);
    }

When I uncomment the //$actualValue = $item->getValue() all stops working

we are almost there but there seems to be recursion I don't understand, can you hint me please?

@mintbridge
Copy link

Im not sure this is quite working properly, as it always returns the first option element in the select
If you change:
Behat@173c49d#L1R316
from $select->selectOption('ten'); to be $select->selectOption('thirty'); then i think the unit test will fail

@mintbridge
Copy link

It also throws an exception would you try to select an option that contains a space e.g.
When I select "Test 1" from "testselect"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants