Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
Seen two different version of it probably around 5 times over the weekend:
https://www.drupal.org/pift-ci-job/1294225
https://www.drupal.org/pift-ci-job/1293378
1) Drupal\Tests\media_library\FunctionalJavascript\MediaLibraryTest::testWidgetUpload
WebDriver\Exception\UnknownError: unknown error: Element is not clickable at point (188, 631)
(Session info: headless chrome=74.0.3729.157)
(Driver info: chromedriver=2.38.552522 (437e6fbedfa8762dec75e2c5b3ddb86763dc9dcb),platform=Linux 4.9.0-0.bpo.6-amd64 x86_64)
/var/www/html/vendor/instaclick/php-webdriver/lib/WebDriver/Exception.php:155
/var/www/html/vendor/instaclick/php-webdriver/lib/WebDriver/AbstractWebDriver.php:157
/var/www/html/vendor/instaclick/php-webdriver/lib/WebDriver/AbstractWebDriver.php:218
/var/www/html/vendor/instaclick/php-webdriver/lib/WebDriver/Container.php:224
/var/www/html/vendor/behat/mink-selenium2-driver/src/Selenium2Driver.php:775
/var/www/html/vendor/behat/mink-selenium2-driver/src/Selenium2Driver.php:763
/var/www/html/vendor/behat/mink/src/Element/NodeElement.php:153
/var/www/html/vendor/behat/mink/src/Element/NodeElement.php:161
/var/www/html/vendor/behat/mink/src/Element/TraversableElement.php:115
/var/www/html/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php:1055
And number 2:
https://www.drupal.org/pift-ci-job/1293997
1) Drupal\Tests\media_library\FunctionalJavascript\MediaLibraryTest::testWidgetOEmbed
Behat\Mink\Exception\ElementNotFoundException: Form field with id|name|label|value "Select Another video" not found.
/var/www/html/vendor/behat/mink/src/WebAssert.php:638
/var/www/html/vendor/behat/mink/src/WebAssert.php:710
/var/www/html/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php:1333
Proposed resolution
?
Remaining tasks
It is possible that it will not occur anymore. #2901792: Disable all animations in Javascript testing could solve the problem but we should track this issue.
There might be others but they become way way rarer once that patch is applied.
Comment | File | Size | Author |
---|---|---|---|
#53 | 3055648-53-X90.patch | 68.95 KB | bnjmnm |
#53 | 3055648-53.patch | 66.71 KB | bnjmnm |
#51 | 3055648-51-90X.patch | 70.06 KB | bnjmnm |
#51 | 3055648-51.patch | 67.81 KB | bnjmnm |
#51 | interdiff_47--51.txt | 29.64 KB | bnjmnm |
Comments
Comment #2
alexpottI think there might be another issue that addresses this by disable css transitions in tests
Comment #3
BerdirRight, forgot about that one #2901792: Disable all animations in Javascript testing
Comment #4
Krzysztof DomańskiA few of today:
https://www.drupal.org/pift-ci-job/1295045
https://www.drupal.org/pift-ci-job/1295055
https://www.drupal.org/pift-ci-job/1295053
https://www.drupal.org/pift-ci-job/1295722
Comment #5
gambryOne more here https://www.drupal.org/pift-ci-job/1295943 . Is #2829040: [meta] Known intermittent, random, and environment-specific test failures still a thing? Shall this issue be added to that list?
Comment #6
Krzysztof DomańskiThanks, I added this issue to the list.
Comment #7
Krzysztof DomańskiComment #8
Lendude@alexpott put a screenshot of the failing spot in slack and it is inside a dialog, so might also be worth taking another look at #2856047: Avoid random failures in JavascriptTestBase when testing functionality in a dialog
Comment #9
alexpottThis is now a follow-up of #2901792: Disable all animations in Javascript testing as that issue solves the majority of random fails that occur in MediaLibrary test. There might be others but they become way way rarer once that patch is applied. Postponing this issue on that one.
Comment #10
Krzysztof Domański#2901792: Disable all animations in Javascript testing has been committed.
Comment #11
Krzysztof DomańskiThe problem was also found a few months earlier (headless chrome=62.0.3202.94, chromedriver=2.33.506092):
https://www.drupal.org/pift-ci-job/1196544
Automatic re-testing. Updated 10 Feb 2019 at 14:53 CET.
Comment #12
Krzysztof DomańskiMaybe related to #3032275: Create a fault-tolerant method for interacting with links and fields in Javascript tests.
Comment #13
Krzysztof DomańskiI updated issue summary. It is possible that it will not occur anymore. #2901792: Disable all animations in Javascript testing could solve the problem but we should track this issue.
Comment #14
Krzysztof DomańskiComment #15
alexpottThis is not happening anymore.
Comment #16
alexpottCorrect status...
Comment #17
bnjmnmI ran into this twice today, once locally, once on a patch
I've run into this with Layout Builder, where occasionally
$assert_session->assertWaitOnAjaxRequest();
is not sufficient before calls to pageTextContains()/pageTextNotContains. Any uses of those functions directly following $assert_session->assertWaitOnAjaxRequest() have been changed to equivalents that make multiple attempts before failing.Comment #19
bnjmnmTest is further refactored to remove assertWaitOnAjaxRequest() wherever possible in favor of what changes are actually being looked for.
There were some instances where assertWaitOnAjaxRequest() was still required, but it is now supplemented with additional assertions that wait for changes that may occur after assertWaitOnAjaxRequest() is complete.
Comment #21
bnjmnmLets give it another try...
Comment #22
bnjmnmLooks like the patch times out in the early 200s so reducing the repeats to 200 and cleaned up a few redundant calls and moved a few assertions that were not in the same order as the original test.
Comment #23
bnjmnm🤷♂️
Comment #24
alexpottI still think we need to go through this test and remove all assertWaitOnAjaxRequest().
testWidgetUpload doesn't pass locally for me without the attached fix. My local setup is quite fast because I don't use any virtualisation.
Comment #25
bnjmnmA version with every assertWaitOnAjaxRequest() removed is on the way
Comment #26
alexpott@bnjmnm oh sorry - I've been working on that too :( so we can compare patches. When we both post.
Comment #27
alexpottI've tested this patch with and without a 2 second wait in index.php - doing that is a good way to prove that a slow AJAX request won't break a test. One of the thing I discovered was that the added \Drupal\Tests\media_library\FunctionalJavascript\MediaLibraryTest::waitForNoText() was not working as expected.
Comment #28
alexpottThis assert turned out to the just wrong. When you filter and then change view the Name field is reset.
Comment #29
bnjmnm@alexpott I'm all for working on this simultaneously and comparing patches. Based on your interdiffs it looks like we're targeting different things at the moment anyway. Thanks for jumping in on this huge patch.
Comment #30
bnjmnmRegarding the fail in #27 -- in earlier iterations of this patch I found that waiting for text to appear/not appear is not reliable after file uploads or "Save and Select/Insert", which is why those particular assertWaitOnAjaxRequest() calls hadn't been removed.
In the patch I'm working on, I think I've addressed the uncertainly when calling attachFileToField(), using
$this->addMediaFileToField()
instead. This ensures the file is actually uploaded before proceeding, something that the presence of text doesn't guarantee.These are the new methods
I'm now working on something similar for "Save and Select/Insert"
Comment #31
alexpott@bnjmnm for me this is just another instance of not waiting for something new!
Both bits of text are also on the previous form that asks for the alternate text.
Let's assert for somethings that's actually a result of pressing save and select.
Comment #32
alexpottFixing waitForText to not emit 20000 as the message. And to wait for the 20secs. It's seems a very long time to wait but it is also very surprising that the text '1 of 2 items selected' has not appeared after 10 seconds.
Comment #33
alexpottYet another set of asserts for things that are there before and after pressing on a button.
Comment #34
alexpottComment #35
alexpott#34 is finally green on sqlite with 50x - lets try with 200x.
Comment #37
alexpottAdding some instrumentation so we can see what's happening.
Comment #38
bnjmnmComment #39
oknateFrom slack:
And my reply:
the code probably needs to be updated to not use $assert_session->assertWaitOnAjaxRequest();
but rather wait until $assert_session->pageTextNotContains($png_image->filename); is TRUE
not 100% sure, but $assert_session->assertWaitOnAjaxRequest(); can sometimes return early, or have unintended interactions.
It looks like a lot of work has already been done here.
Comment #40
bnjmnmMost of the random fails can be addressed by replacing $assert_session->assertWaitOnAjaxRequest() with assertions that check for the presence/absence of elements. There is one aspect of this that can't be addressed in this manner, which has spun off into its own issue #3066447: [random test failure] Random failures building media library form after uploading image (WidgetUploadTest) -- there appear to be random failures when uploading files to the media widget multiple times within the same test. That underlying issue would need to be addressed before MediaLibraryTest can work consistently.
Comment #41
xjmComment #42
bnjmnmProbably should have done this when #40 was added, but it's more accurate to set this to postponed and waiting on #3066447: [random test failure] Random failures building media library form after uploading image (WidgetUploadTest). There are issues specific to making multiple file uploads in the same FunctionalJavascript test that cause intermittent failures. If the MediaLibararyTest is refactored to address all other intermittent failures, there will still be intermittent failures due to this upload issue, something that (as proven in the issue) is not due to the way MediaLibraryTest is written.
If issue #3066447 is not fixable, it may be possible to address this by splitting the tests in MediaLibararyTest into many smaller ones so there are fewer file uploads inside a single test method,
Comment #43
bnjmnmDiscussed this with @xjm and it was decided to not block this on #3066447: [random test failure] Random failures building media library form after uploading image (WidgetUploadTest) as the changes here will reduce the number of random failures, even though that issue will need to be addressed for them to be removed entirely.
I have a version of this patch with significantly fewer errors that was being tested in a burner issue to avoid clogging this one with dozens of trial/error patches. Once I get that rerolled I'll set this back to Needs Review.
Comment #44
oknateThere are other buttons too that don't have $assert_session->assertWaitOnAjaxRequest() that need the next interaction item to wait to appear.
Comment #45
bnjmnmThis addresses random errors in MySQL and Postgres. Unfortunately, there are still intermittent errors in SQLite that probably can't be addressed until #3066447: [random test failure] Random failures building media library form after uploading image (WidgetUploadTest) is completed. I added the WITH-DATABASE-CHECKS tests to help demonstrate where it is failing. After a certain amount of uploads (varies on each instance), the media item never gets added to the database. Once this happens, the test errors may report different points of failure (explained further in #3066447) but the root cause appears to be the media item never getting added to the database.
Still, this significantly reduces intermittent errors, and never relies solely on $assert_session->assertWaitOnAjaxRequest() before proceeding to a next step. Note that $assert_session->assertWaitOnAjaxRequest() is still in use in a few places as it appears to be necessary for form ids and label 's for attributes to match (this information is also in the comments). There may be a solution I overlooked, but I'm also in support of having that be a followup issue.
Comment #46
phenaproximaThis patch is a magnificent piece of work. It decreases the verbosity of MediaLibraryTest while increasing its reliability, and lays the groundwork for a trait that will enable other tests to meaningfully interact with the media library. I'm sure that a lot of my feedback is not valid, and a lot of it is certainly nitpicky -- give me a break, though: it was hard to find things to dislike here!
This could use a comment.
Oh my God...this is so much better and more readable. Thank you. 🙏
👍 I see why this was removed; our very next action is to visit a different URL, so there's no point in hiding the row weights.
We probably need a follow-up @todo for this...?
Perhaps we should change this to waiting for the expected element to have focus, instead of just removing the wait for AJAX?
Same here. Also, if we're going to wait for things to be focused, perhaps a helper method would be useful?
Same here. I'll stop calling these out in the rest of this review.
I notice that previously, we were waiting for the text, then waiting for another AJAX request. Perhaps we need another wait condition after the waitForText()?
👍 More precise: I like that.
This seems interesting -- why do we need the waitForNoText()?
Supernit: there are two spaces after the word "label's". Thank you, by the way, for documenting the individual uses of assertWaitOnAjaxRequest().
Same here.
And here.
And here.
And here.
This is interesting; why the new $page->fillField() call, and why does it differ from the existing $page->fillField() call?
Nit: No need to
use ($page)
, it will get passed to the closure as an argument. (The callback given to waitFor() is always given the element that waitFor() was called on.)Nit: $assert_session does not need to be its own variable.
Same here.
And here.
I would maybe rename this method to something like
switchToMediaType
or similar.Two spaces after "label's".
$assert_session doesn't need to be its own variable here.
Why not use $page->waitFor() here?
No need for $assert_session variable.
Couldn't we just use $assert_session->waitForField(), then
return $assert_session->fieldExists()
?This seems a bit superfluous. Couldn't we just do
$this->waitForFieldExists()->setValue()
in the test?I saw a call, elsewhere in the test, to $this->saveAs('select', FALSE)...but this method doesn't take a second argument. 🤔
Two spaces after "label's".
I would maybe rename this to openMediaLibraryForField().
Comment #47
bnjmnmRe #46
Ah, that was back when I thought the input/label id/for issue was specific to just that field (it is where it most often failed). That can return to its original form now that the unfortunately-needed assertWaitOnAjaxRequest() calls are back
Good catch, that is from a troubleshooting version of the patch with extra DB checking to after media is added to the database
3055648-45-WITH-DATABASE-CHECKS
Not needed here so the arg is removed.Comment #48
phenaproximaDidn't get all the way through the patch, but a closer read made me notice some more things about which I have small, easily-swatted-away questions.
Stuff like this should really be part of WebDriverTestBase. I think we should open an issue for it.
I think that this waitForText() assertion should be part of openMediaLibraryForField(). I can't think of any circumstance where we wouldn't want to assert the presence of that text as part of opening the media library.
I think it's a little awkward that openMediaLibraryForField() returns the menu by default. I think we should just not have a default value for that parameter (or at least default it to NULL), and make explicit the fact that we want to retrieve the menu once the media library is opened. IOW, this should be
$this->openMediaLibraryForField('field_unlimited_media', '.media-library-menu')
. Calling$this->openMediaLibraryForField('field_unlimited_media')
should not return any element, IMHO.Nice call on removing this assertWaitOnAjaxRequest() call. There is no reason to wait for AJAX after closing the modal; no AJAX request is triggered by that, as far as I know.
IMHO, waitForElementTextContains() should follow similar patterns to what we get from Mink. In other words, it shouldn't force you to use a CSS selector; it should be something like
$this->waitForElementTextContains('css', '.media-library-selected-count', '0 of 1 item selected')
.This seems interesting; why the change from a button value to a CSS selector?
I don't know how I feel about the "magic" of $this->switchToMediaType('One'), when the actual name of the media type is "Type One". I'd rather this (and all similar calls) was more explicit, i.e. $this->switchToMediaType('Type One').
These can be collapsed into one line:
$this->assertElementExistsAfterWait('css', '.media-library-open-button[name^="field_twin_media"][data-disabled-focus][disabled]')
.Why didn't this change to $this->waitForText()?
This should be a @todo.
This looks like a change in logic. Wouldn't we want to wait for the "Select $existing_media_name" field instead, to keep it in line with what it previously was?
Isn't this the name of a field? If so, wouldn't we want to wait for the field to exist, rather than some text? This feels a bit "coincidental" otherwise.
So, question about this. If we are waiting for a specific condition (the input 'id' to match the label 'for'), couldn't we use $this->assertJsCondition() or similar for that? Do we need to use assertWaitOnAjaxRequest()?
Also, question about the naming of assertElementExistsAfterWait() -- that seems to be a rather verbose name. Why not call it waitForElement(), for consistency with the other "wait" methods in this test?
Comment #49
phenaproximaNit: I think we can change
[checked="checked"]
to just[checked]
. That is a boolean attribute, so its value doesn't really matter. :)I think we should rename this to waitForElement(), which IMHO would be clearer and less verbose.
This should be mb_strtolower().
I'm not entirely clear on why we need this -- what is it adding? Can we get a comment? above it?
Ah, now I see why we can't wait for a particular condition instead of doing this: because we're waiting for all input IDs to match the 'for' attributes. Yeah, that'd be pretty impossible to "wait" for. I guess assertWaitOnAjaxRequest() is our only option. For now.
These should be renamed $selector and $locator for consistency with Mink.
I'm still not clear on why we don't use $page->waitFor() here? Something like:
Can we rename this waitForField(), for consistency?
This can be refactored: $this->waitForFieldExists($locator)->attachFile(). No need to use $page. Honestly, since it's so simple, we might be able to just remove this method entirely.
I'm a bit iffy on the magic string concatenation we're doing, but...it's probably fine for now. This is not, after all, an API.
Comment #50
phenaproximaI discussed this with @effulgentsia, @oknate, and @webchick in a scrum call today.
Here's the thing: this is blocking #3034242: Hide "Save and insert" and "Additional selected media" from users by default, which is a feature that we really need to land before alpha. @oknate brilliantly pointed out that this patch, in its current form, does exactly what it sets out to do -- namely, significantly reduce random failures in MediaLibraryTest. The changes I want are, compared to that, minor refactoring.
So, to unblock the feature, let's get this in now, as is, and everyone can breathe a sigh of relief and that feature can get in as soon as humanly possible. Then we'll open a follow-up to do further clean-up in MediaLibraryTest, which as I understand it can be done all the way through beta.
#47 is already green on all backends (the failure on SQLite is a known thing which has a separate issue, and is referenced in the patch), so this is ready to go now.
Comment #51
bnjmnmThis addresses all the points from #48 & #49 with a few exceptions:
#48.8 most existing uses of
$this->assertNotEmpty($assert_session->waitForText('foo'));
were not changed. This can definitely be addressed in a followup.#49.7 (first) will look into refactoring in a followup, the suggested approach simply didn't occur to me.
#49.2 (second) keeping
addMediaFileToField()
as I had to addassertWaitOnAjaxRequest()
for the same for/id issue. Otherwise - intermittently - the alt text field couldn't be found.Comment #53
bnjmnmThis is just a re-upload of #47, the version that was RTBC'd. Will open a followup to address the feedback received after that, so this can get in and stop these test failures.
Comment #54
phenaproximaGreat idea. RTBC once green-ish. (Failure in the SQLite run of the x90 patch is expected.)
Comment #55
bnjmnmFollowup: #3087227: [META] Split up and refactor MediaLibraryTest
Comment #56
larowlanMicronit (nanonit?)
I don't see assertWaitOnAjaxRequest being used here anymore? 🤔
As just comment changes, fine to go straight back to RTBC
Comment #57
larowlansorry, my eyes don't work today...i didn't read the untouched lines of the patch properly
Comment #58
phenaproximaYup. I just applied the patch locally and confirmed that each call to
assertWaitOnStupidUnreliableBS()
-- I mean,assertWaitOnAjaxRequest()
-- is accompanied by a comment. That was done at my request, so we'd know explicitly where and why we relied on an unreliable method. :)Comment #59
alexpottUpdating credit
Comment #60
alexpottCommitted and pushed 312ce8ecb3 to 9.0.x and a721bed4c0 to 8.9.x and bef49c3af9 to 8.8.x. Thanks!
Comment #64
alexpottUnfortunately this test is still failing quite a lot - maybe even more - for example https://www.drupal.org/pift-ci-job/1433935
Comment #66
xjm