Problem/Motivation

Validation messages for errors in the block configuration forms of do not get displayed because of #2897377: $form['#attributes']['data-drupal-selector'] is set to a random value so can't be used for its intended purpose.

Proposed resolution

Set the $form['#id'] explicitly so the messages will be displayed.

Remaining tasks

Review

User interface changes

the error messages will show.

API changes

None

Data model changes

None

CommentFileSizeAuthor
#45 2968110-45.patch8.15 KBtedbow
#45 interdiff-44-45.txt1.73 KBtedbow
#44 2968110-43.patch8.22 KBtedbow
#44 interdiff-reroll-44.txt2.3 KBtedbow
#41 interdiff-39-40.patch885 bytestedbow
#41 2968110-41-x30.patch10.16 KBtedbow
#39 2968110-39-x30.patch10.12 KBtedbow
#39 interdiff-34-39.txt3.88 KBtedbow
#34 2968110-34.patch7.14 KBtedbow
#34 interdiff-31-34.txt935 bytestedbow
#34 2968110-34-x30.patch9.04 KBtedbow
#31 2968110-31.patch7.09 KBtedbow
#31 interdiff-28-31.txt1.57 KBtedbow
#31 2968110-31-x30.patch9 KBtedbow
#28 2968110-28.patch6.55 KBtedbow
#28 interdiff-26-27.txt1.98 KBtedbow
#26 2968110-26.patch7.07 KBtedbow
#26 interdiff-20-26.txt4.87 KBtedbow
#26 2968110-26_x30.patch8.98 KBtedbow
#20 interdiff-19-20.txt2.17 KBtedbow
#20 2968110-20.patch10.07 KBtedbow
#19 2968110-19.patch10.48 KBtedbow
#19 interdiff-17-19.txt1.93 KBtedbow
#17 2968110-16-debug.patch10.4 KBtedbow
#17 2968110-16-debug.patch10.4 KBtedbow
#15 2968110-15-debug.patch10.38 KBtedbow
#13 2968110-13.patch9.99 KBtedbow
#13 interdiff-11-23.txt1.39 KBtedbow
#11 interdiff-9-11.txt3.06 KBtedbow
#11 2968110-11.patch9.98 KBtedbow
#9 2968110-9.patch23.08 KBtedbow
#9 2968110-9-TEST_ONLY-FAIL.patch5.47 KBtedbow
#7 2968110-7.patch7.75 KBtedbow
#7 2968110-7-TEST_ONLY-FAIL.patch5.44 KBtedbow
#3 2968110-3.patch2.31 KBtedbow
#3 interdiff-2-3.txt4.1 KBtedbow
#2 2968110-2.patch1.79 KBtedbow
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

tedbow created an issue. See original summary.

tedbow’s picture

Status: Active » Needs review
Issue tags: +Needs tests
FileSize
1.79 KB

Here is a patch

  1. The validation messages work.
  2. For some reason the messages aren't at the top even that they have -1000 weight as set by \Drupal\Core\Ajax\AjaxFormHelperTrait::ajaxSubmit
  3. Had to add a work around for this #2897377: $form['#attributes']['data-drupal-selector'] is set to a random value so can't be used for its intended purpose. Could we add this to AjaxFormHelperTrait?
  4. Needs tests. Should convert \Drupal\Tests\layout_builder\Functional\LayoutBuilderTest to a Javascript test to be able to test this?
tedbow’s picture

Title: Layout Builder's AddBlockForm doesn't display validation errors on submit » Layout Builder's ConfigureBlockFormBase forms do not display validation errors on submit
FileSize
4.1 KB
2.31 KB
  1. Realized that UpdateBlockForm also was not showing validation messages so I moved the fix logic up to \Drupal\layout_builder\Form\ConfigureBlockFormBase
  2. Also I am not sure why the messages weren't showing up at the top. From what I could tell they should have been at the top because they have the lowest weight
      '#type' => 'status_messages',
      '#weight' => -1000,
    

    So it somehow seems like a form #weight bug but I am probably missing something
    So I updated \Drupal\Core\Ajax\AjaxFormHelperTrait to actually move status_messages to the beginning of the array.

    I am not sure why I had to update that but couldn't figure out why it wasn't ordering correctly. \Drupal\settings_tray\Block\BlockEntitySettingTrayForm doesn't have this problem but I can't see the difference.

bkosborne’s picture

This works well for me, thanks for the patch. Would RTBC but I guess still needs a test.

I also looked into the weight issue and couldn't figure out the problem. The form is rendered via \Drupal::service('renderer')->renderRoot() before being inserted into the AJAX response. Maybe in other circumstances, the form is processed further to do something with the weights which is skipped in this scenario?

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tim.plunkett’s picture

Status: Needs review » Needs work

NW for tests

tedbow’s picture

Here is a patch with tests:

  1. It tests that messages appear when you add and update a block
  2. It asserts that the message are at the top of the form
  3. It copies some functions from InlineBlockTestBase. We should probably have a LayoutBuilderTestBase but I am going to look at #2924201: Resolve random failure in LayoutBuilderTest so that it can be added to HEAD now to see if we can finish that up.
  4. I didn't provide a interdiff but the TEST_ONLY patch is the same as the interdiff in this case.

Status: Needs review » Needs work

The last submitted patch, 7: 2968110-7.patch, failed testing. View results

tedbow’s picture

Forgot @group 😜

Status: Needs review » Needs work

The last submitted patch, 9: 2968110-9.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
FileSize
9.98 KB
3.06 KB

Whoops #9 was not clean. Reuploading

Just running the 1 test.

Status: Needs review » Needs work

The last submitted patch, 11: 2968110-11.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
FileSize
1.39 KB
9.99 KB

I am not sure why this is failing. Extending the wait for the element that is causing the fail. But I don't think that will help.

Status: Needs review » Needs work

The last submitted patch, 13: 2968110-13.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
FileSize
10.38 KB

since I can't get it to fail locally I putting some debug messages to see if the dialog is actually closed or not

Status: Needs review » Needs work

The last submitted patch, 15: 2968110-15-debug.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
FileSize
10.4 KB
10.4 KB
+++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
@@ -0,0 +1,153 @@
+    if ($assert_session->waitForElement('css', $messages_locator)) {
+      $this->fail('what change to get here?');

Hmm. I don't understand why waitForElement() didn't return NULL here again.

Status: Needs review » Needs work

The last submitted patch, 17: 2968110-16-debug.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
FileSize
1.93 KB
10.48 KB
+++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
@@ -0,0 +1,153 @@
+      if ($assert_session->waitForElement('css', '#drupal-off-canvas')) {
+        $this->fail('the canvas is still open');
+      }
+      else {
+        $this->fail('the canvas is closed');

What? Even though the required title field is still to "" it the off-canvas dialog is still being closed.

Wonder if it could be problem that contextual link in the test is actually not opening in the off-canvas dialog?

Changing the assert to actually look for the elements in the off-canvas dialog.

tedbow’s picture

  1. +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
    @@ -60,9 +60,9 @@ public function testValidationMessage() {
    -    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '.block-categories'));
    +    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas .block-categories'));
    

    Leaving these changes in because it is a more explicit assertion

  2. +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
    @@ -73,10 +73,10 @@ public function testValidationMessage() {
    -    $this->clickLink('Manage layout');
    +    $this->drupalGet($field_ui_prefix . '/display-layout/default');
    

    I have feeling this is what actually fixed the test. I ran into this in #2957425: Allow the inline creation of non-reusable Custom Blocks in the layout builder when clicking on the link was not the same for some reason as using drupalGet()

tim.plunkett’s picture

Status: Needs review » Needs work
Issue tags: -Needs tests +Blocks-Layouts
  1. +++ b/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
    @@ -176,6 +177,16 @@ public function doBuildForm(array $form, FormStateInterface $form_state, Section
           $form['actions']['submit']['#ajax']['callback'] = '::ajaxSubmit';
    +      // static::ajaxSubmit() requires data-drupal-selector to be the same
    +      // between the various Ajax requests. A bug in
    +      // \Drupal\Core\Form\FormBuilder prevents that from happening unless
    +      // $form['#id'] is also the same. Normally, #id is set to a unique HTML ID
    +      // via Html::getUniqueId(), but here we bypass that in order to work
    +      // around the data-drupal-selector bug. This is okay so long as we assume
    +      // that this form only ever occurs once on a page.
    +      // @todo Remove this workaround once https://www.drupal.org/node/2897377
    +      // is fixed.
    +      $form['#id'] = Html::getId($form_state->getBuildInfo()['form_id']);
    

    I've seen this copied around a couple times now. Is this the actual fix?

  2. +++ b/core/lib/Drupal/Core/Ajax/AjaxFormHelperTrait.php
    @@ -27,10 +27,15 @@
    -      $form['status_messages'] = [
    -        '#type' => 'status_messages',
    -        '#weight' => -1000,
    -      ];
    +      $form = array_merge(
    +        [
    +          'status_messages' => [
    +            '#type' => 'status_messages',
    +            '#weight' => -1000,
    +          ],
    +        ],
    +        $form
    +      );
    

    Or is this the fix? I feel like we should be clear here, and I don't understand this change

andrewmacpherson’s picture

Priority: Normal » Major
Issue tags: +Accessibility, +Layout Builder stable blocker

Promoting to major as this is needed for WCAG level A - see SC 3.3.1 Error Identification.

Where will the errors be displayed - in the off-canvas dialog?

tedbow’s picture

re #21
1) is the actual fix to get the messages to show.

Without 2) the messages will show up at the bottom of the form. Not sure why. My guess is the sorting already has happened at this point so simply setting the weight will not work.

tedbow’s picture

Status: Needs work » Needs review
tim.plunkett’s picture

Status: Needs review » Needs work
  1. +++ b/core/lib/Drupal/Core/Ajax/AjaxFormHelperTrait.php
    @@ -27,10 +27,15 @@
    +      $form = array_merge(
    +        [
    +          'status_messages' => [
    +            '#type' => 'status_messages',
    +            '#weight' => -1000,
    +          ],
    +        ],
    +        $form
    +      );
    

    Any reason not to use array_unshift() instead?

  2. +++ b/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
    @@ -176,6 +177,16 @@ public function doBuildForm(array $form, FormStateInterface $form_state, Section
    +      // static::ajaxSubmit() requires data-drupal-selector to be the same
    +      // between the various Ajax requests. A bug in
    +      // \Drupal\Core\Form\FormBuilder prevents that from happening unless
    +      // $form['#id'] is also the same. Normally, #id is set to a unique HTML ID
    +      // via Html::getUniqueId(), but here we bypass that in order to work
    +      // around the data-drupal-selector bug. This is okay so long as we assume
    +      // that this form only ever occurs once on a page.
    +      // @todo Remove this workaround once https://www.drupal.org/node/2897377
    +      // is fixed.
    +      $form['#id'] = Html::getId($form_state->getBuildInfo()['form_id']);
    

    Can this whole comment be made an @todo instead of just the last line, and be sure to indent subsequent comment lines two more spaces

Also NW for a reroll since the drupalci.yml changes conflict and should be removed anyway.

tedbow’s picture

Status: Needs work » Needs review
Issue tags: -Accessibility +accessibility
FileSize
8.98 KB
4.87 KB
7.07 KB

re #25
1. fixed
2. fixed

And

  1. +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
    @@ -0,0 +1,139 @@
    +    // @todo Remove after https://www.drupal.org/project/drupal/issues/2901792.
    +    'no_transitions_css',
    

    We don't actually need this if we have proper waits. the test module has been removed.
    @see #3020142: Test module no_transitions_css has invalid hook_page_attachments

  2. +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
    @@ -0,0 +1,139 @@
    +  protected function assertSaveLayout() {
    +    $assert_session = $this->assertSession();
    +    $assert_session->linkExists('Save Layout');
    +    // Go to the Save Layout page. Currently there are random test failures if
    +    // 'clickLink()' is used.
    +    // @todo Convert tests that extend this class to NightWatch tests in
    +    // https://www.drupal.org/node/2984161
    +    $link = $this->getSession()->getPage()->findLink('Save Layout');
    +    $this->drupalGet($link->getAttribute('href'));
    +    $this->assertNotEmpty($assert_session->waitForElement('css', '.messages--status'));
    

    I don't think we need the work around this method provides. @tim.plunkett ran into this same problem in another test and figure out it was problem with a link or button being out of the viewport. I copied this \Drupal\Tests\layout_builder\FunctionalJavascript\InlineBlockTestBase::assertSaveLayout but only needed there because adding more inline block pushes the link out of the viewport. This test is only adding 1 block so shouldn't be a problem. Will confirm with a 30x patch.

tim.plunkett’s picture

  1. +++ b/core/lib/Drupal/Core/Ajax/AjaxFormHelperTrait.php
    @@ -27,10 +27,15 @@
    +      array_unshift(
    +        $form,
    +        [
    +          'status_messages' => [
    +            '#type' => 'status_messages',
    +            '#weight' => -1000,
    +          ],
    +        ]
    +      );
    

    Just for readability, can this be changed to

    +      array_unshift($form, [
    +        'status_messages' => [
    +          '#type' => 'status_messages',
    +          '#weight' => -1000,
    +        ],
    +      ]);
    
  2. +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
    @@ -0,0 +1,117 @@
    +  protected function waitForNoElement($selector, $timeout = 10000) {
    

    This is no longer used in the patch, it can be removed.

tedbow’s picture

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

Thanks!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 28: 2968110-28.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
FileSize
9 KB
1.57 KB
7.09 KB

Looks like random fail because we weren't waiting for canvas to close.

The last submitted patch, 31: 2968110-31-x30.patch, failed testing. View results

Kristen Pol’s picture

Does this need manual testing?

tedbow’s picture

@Kristen Pol sure! just used the layout and add/configure any block. remove the title(or other required field). You should see the validation error message in the off-canvas dialog.

The last patch failed here is another x30 patch

ariane’s picture

Patch 2968110-34.patch in #34 works well with core version 8.6.7

Thanks @tedbow!

Status: Needs review » Needs work

The last submitted patch, 34: 2968110-34.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review

#36 is because aborted a test. I mean to retest the x30 patch from #34 but selected the wrong 1 twice.

Re-queued the x30 times patch a few times to be sure we got the random fail.

The last submitted patch, 34: 2968110-34-x30.patch, failed testing. View results

tedbow’s picture

ok so now the x30 test that was passing is now failing

+++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
@@ -0,0 +1,119 @@
+    $this->waitForNoElement('#drupal-off-canvas');
+    $assert_session->assertWaitOnAjaxRequest();
+    $assert_session->linkExists('Save Layout');
+    $page->clickLink('Save Layout');

All failing right here when trying to save the layout.
with

1) Drupal\Tests\layout_builder\FunctionalJavascript\BlockFormMessagesTest::testValidationMessage
WebDriver\Exception\UnknownError: unknown error: Element ... is not clickable at point (60, 571). Other element would receive the click: ...
(Session info: headless chrome=62.0.3202.94)
(Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.9.0-0.bpo.6-amd64 x86_64)

This is a common cause of random failures 😟

And it seems to not happen locally much. So something is happening that is making a link not clickable because another element would get the click.

My theory is something monetarily in the way and the time is different depending on something in the state of Drupalci, so it is very hard to fix.

What if we just tried a number of times click the link. Like we do with visibility in \Drupal\FunctionalJavascriptTests\JSWebAssert::waitForElementVisible().

Here is a x30 patch with clickElementWhenClickable(). which should be moved to a trait if this a solution.

Status: Needs review » Needs work

The last submitted patch, 39: 2968110-39-x30.patch, failed testing. View results

tedbow’s picture

yay! A totally different random error in #39.

While #34 seem to fail about 1/3 of the time #39 failed 1 out of 30.

This

+++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
@@ -0,0 +1,147 @@
+    $this->clickElementWhenClickable($page->findLink('Save Layout'));
+    $this->assertNotEmpty($assert_session->waitForElement('css', 'div:contains("The layout has been saved")'));

This is where it failed.

This the same random error I had to put a very strange fix in for in \Drupal\Tests\layout_builder\FunctionalJavascript\InlineBlockTestBase::assertSaveLayout()

@tim.plunkett ran into this same problem recently and solved it my just reloading the page.

Trying that here

Status: Needs review » Needs work

The last submitted patch, 41: interdiff-39-40.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review

#42 set it to Needs Work because use a ".patch" extension for the interdiff file. Whoops

tedbow’s picture

Ok the patches before had unrelated changes

tedbow’s picture

  1. it looks the whole problem with the message appearing at the bottom of the form can be solved with $form['#sorted'] = FALSE;
  2. Added a todo to #3032275: Create a fault-tolerant method for interacting with links and fields in Javascript tests for the work around here for random test failures
tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community
  1. +++ b/core/lib/Drupal/Core/Ajax/AjaxFormHelperTrait.php
    @@ -31,6 +31,7 @@ public function ajaxSubmit(array &$form, FormStateInterface $form_state) {
    +      $form['#sorted'] = FALSE;
    

    This is such a clean fix now. Nice!

  2. +++ b/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
    @@ -179,6 +180,15 @@ public function doBuildForm(array $form, FormStateInterface $form_state, Section
    +      //   workaround in https://www.drupal.org/node/2897377.
    +      $form['#id'] = Html::getId($form_state->getBuildInfo()['form_id']);
    

    Note that this workaround also exists in Settings Tray module

  • xjm committed 72e0a4d on 8.7.x
    Issue #2968110 by tedbow, tim.plunkett, Kristen Pol, bkosborne,...
xjm’s picture

Status: Reviewed & tested by the community » Fixed

Committed to 8.7.x. Thanks!

tedbow’s picture

🎉 thanks @xjm and all those you worked on this!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

andrewmacpherson’s picture

Issue tags: -accessibility (duplicate tag) +Accessibility

fixing accessibility tag