drupalextension icon indicating copy to clipboard operation
drupalextension copied to clipboard

Expanding/clicking collapsed fieldsets

Open RoSk0 opened this issue 4 years ago • 5 comments

Faced with an issue that it's impossible/tricky to click on an element which is not a link. Counting that we have a lot of those in Drupal UI it feels natural to have a step definition in this great module.

This is a feature/support request to be able to expand collapsed element, like Menu settings on a
screenshot with something like When I expand "Menu settings" fieldset.

I would appreciate any help or pointers to how this could be archived.

RoSk0 avatar Jun 14 '21 00:06 RoSk0

There's a few options. If running in javascript, then you can go the verbose route, and say:

...
And I click "Menu Settings"
And I fill field...

if not running in JS, the fields should already be available that are hidden in that fieldset.

Alternatively, a custom step definition that does the actual clicking behind the scenes would work

/**
 * @When I expand :link
 */
 public function assertExpandFieldset($link)
{
    $this->clickLink($link);
}

jhedstrom avatar Jun 17 '21 18:06 jhedstrom

Thanks Jonathan!

The detail here is that those aren't links, and Then I click "foo" in Drupal\DrupalExtension\Context\MinkContext::assertClick() uses Mink Extension's clickLink(). I believe that only works on tags of type <a>?

In Seven theme in D9, the expandable sections on eg a node edit form for a collapsible section (whether in the main content edit column or the sidebar) are a <details> element with the clickable label being the contents text in the <summary> container (inside the first span, with more text following). They are themed to look like links (bold, blue colour).

image

<details class="path-form js-form-wrapper form-wrapper seven-details" data-drupal-selector="edit-path-0" id="edit-path-0">
    <summary role="button" aria-controls="edit-path-0" aria-expanded="false" aria-pressed="false" class="seven-details__summary">
    <span>URL alias</span>
    <span class="summary"> (Automatic alias)</span>
    </summary>
    <div class="seven-details__wrapper details-wrapper">
    <div class="js-form-item form-item js-form-type-checkbox form-type-checkbox js-form-item-path-0-pathauto form-item-path-0-pathauto">
        <input data-drupal-selector="edit-path-0-pathauto" aria-describedby="edit-path-0-pathauto--description" type="checkbox" id="edit-path-0-pathauto" name="path[0][pathauto]" value="1" checked="checked" class="form-checkbox">
        <label for="edit-path-0-pathauto" class="option">Generate automatic URL alias</label>
        <!-- END OUTPUT from 'core/themes/seven/templates/classy/form/form-element-label.html.twig' -->
        <div id="edit-path-0-pathauto--description" class="description">
            Uncheck this to create a custom alias below. <a href="/admin/config/search/path/patterns">Configure URL alias patterns.</a>
        </div>
    </div>
    <div class="js-form-item form-item js-form-type-textfield form-type-textfield js-form-item-path-0-alias form-item-path-0-alias form-disabled">
        <label for="edit-path-0-alias">URL alias</label>
        <input data-drupal-selector="edit-path-0-alias" aria-describedby="edit-path-0-alias--description" type="text" id="edit-path-0-alias" name="path[0][alias]" value="/section/level-2-page/level-3-page/level-4-page" size="60" maxlength="255" class="form-text" data-drupal-states="{&quot;disabled&quot;:{&quot;input[name=\u0022path[0][pathauto]\u0022]&quot;:{&quot;checked&quot;:true}}}" disabled="">
        <div id="edit-path-0-alias--description" class="description">
            Specify an alternative path by which this data can be accessed. For example, type "/about" when writing an about page.
        </div>
    </div>
</div>
</details>

I started with this in our FeatureContext, but it's over-specific to the node form sidebar at present. Maybe we should target details > summary by text content instead.

  /**
   * Click an element by CSS selector.
   *
   * @Given I click the :arg1 element
   */
  public function iClickTheElement($selector) {
    $page = $this->getSession()->getPage();
    $element = $page->find('css', $selector);

    if (empty($element)) {
      throw new Exception("No html element found for the selector ('$selector')");
    }

    $element->click();
  }

  /**
   * Expand a details section in node edit meta (sidebar) section.
   *
   * @Given I expand node form details :details
   */
  public function iExpandNodeFormSidebarDetails($details) {
    // Eg: "Path", "rabbit-hole-settings", etc.
    // Not all modules set a class for this; submit patches if not present.
    $className = strtolower("${details}-form");
    $this->iClickTheElement(".node-form .entity-meta .${className}");
  }

xurizaemon avatar Jun 17 '21 18:06 xurizaemon

The real question here is:

  • is there existing functionality to do this in a way that's reasonably Behat-ish, and
  • if there's no existing StepDefinition to do this (Then I expand details for "blah"), would you consider a MR/pull req to add that to this extension?

xurizaemon avatar Jun 17 '21 19:06 xurizaemon

Ah, I didn't realize those weren't links. Running in JS, the And I click :link I thought that worked with elements other than a but perhaps not...

I'd certainly review a new step definition that adds this capability. Since it's JS-specific, we'd probably want to add the $this->waitForAjaxToFinish() call after clicking the element to avoid timing issues...

jhedstrom avatar Jun 17 '21 20:06 jhedstrom

PR is in #594.

It seems like $this->waitForAjaxToFinish() doesn't do the trick, nor did $this->getSession()->wait();. I used usleep() for 100ms instead - I guess what's happening there is a CSS animation so there's no Drupal ajaxing to poll for. Input welcome on that, I'm not delighted with it (but it does seem to work).

xurizaemon avatar Jul 05 '21 09:07 xurizaemon