Page MenuHomePhabricator

Broken / flaky Selenium / WebdriverIO test: Page should be protectable: mw.loader.using is not available / WebDriverError: element click intercepted
Open, HighPublic

Description

This build has a very strange failure. Near the bottom of the console is this error:

------------------------------------------------------------------
[chrome 120.0.6099.224 linux #0-6] Running: chrome (v120.0.6099.224) on linux
[chrome 120.0.6099.224 linux #0-6] Session ID: bf895109c1a8bd684f0e4436040627f2
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] » tests/selenium/specs/page.js
[chrome 120.0.6099.224 linux #0-6] Page
[chrome 120.0.6099.224 linux #0-6]    ✓ should be previewable @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should be creatable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be re-creatable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be editable @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should have history @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should be deletable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be restorable
[chrome 120.0.6099.224 linux #0-6]    ? should be protectable (1x retries)
[chrome 120.0.6099.224 linux #0-6]    ✖ "before each" hook for Page
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] 7 passing (53.4s)
[chrome 120.0.6099.224 linux #0-6] 1 failing
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] 1) Page "before each" hook for Page
[chrome 120.0.6099.224 linux #0-6] mw.loader.using is not available
[chrome 120.0.6099.224 linux #0-6] Error: mw.loader.using is not available
[chrome 120.0.6099.224 linux #0-6]     at async waitForModuleState (file:///workspace/src/tests/selenium/wdio-mediawiki/Util.js:56:3)
[chrome 120.0.6099.224 linux #0-6]     at async isTargetNotWikitext (file:///workspace/src/tests/selenium/wdio-mediawiki/Util.js:22:2)
[chrome 120.0.6099.224 linux #0-6]     at async Context.<anonymous> (file:///workspace/src/tests/selenium/specs/page.js:27:8)
------------------------------------------------------------------
[chrome 120.0.6099.224 linux #0-6] Running: chrome (v120.0.6099.224) on linux
[chrome 120.0.6099.224 linux #0-6] Session ID: 61a3124ebc394c8e10f39a297eab0385
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] » tests/selenium/specs/page.js
[chrome 120.0.6099.224 linux #0-6] Page
[chrome 120.0.6099.224 linux #0-6]    ✓ should be previewable @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should be creatable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be re-creatable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be editable @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should have history @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should be deletable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be restorable
[chrome 120.0.6099.224 linux #0-6]    ? should be protectable (1x retries)
[chrome 120.0.6099.224 linux #0-6]    ✖ "before each" hook for Page
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] 7 passing (54.4s)
[chrome 120.0.6099.224 linux #0-6] 1 failing
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] 1) Page "before each" hook for Page
[chrome 120.0.6099.224 linux #0-6] mw.loader.using is not available
[chrome 120.0.6099.224 linux #0-6] Error: mw.loader.using is not available
[chrome 120.0.6099.224 linux #0-6]     at async waitForModuleState (file:///workspace/src/tests/selenium/wdio-mediawiki/Util.js:56:3)
[chrome 120.0.6099.224 linux #0-6]     at async isTargetNotWikitext (file:///workspace/src/tests/selenium/wdio-mediawiki/Util.js:22:2)
[chrome 120.0.6099.224 linux #0-6]     at async Context.<anonymous> (file:///workspace/src/tests/selenium/specs/page.js:27:8)
------------------------------------------------------------------

“mw.loader.using is not available” is the message I added in a patch for T297346; I’m not sure what it means in this case. Did MediaWiki JS take longer than whatever the timeout is to initialize itself? Or was there an error on the page? It hardly looks like it would be specific to this particular test – but then again, it apparently happened exactly the same way twice?

There’s also another set of messages further up about the same test suite (page.js):

[0-6] RUNNING in chrome - file:///tests/selenium/specs/page.js
[0-6] 2025-11-28T14:08:27.164Z ERROR webdriver: WebDriverError: element click intercepted: Element <span class="oo-ui-labelElement-label" id="ooui-1" role="textbox" aria-readonly="true">...</span> is not clickable at point (361, 10). Other element would receive the click: <div class="vector-sticky-header-context-bar-primary" aria-hidden="true">...</div>
[0-6]   (Session info: chrome=120.0.6099.224) when running "element/522AA77585C5A5D10AC3A4387BEA44FA_element_1054/click" with method "POST"
[0-6] RETRYING in chrome - file:///tests/selenium/specs/page.js
[0-6] RUNNING in chrome - file:///tests/selenium/specs/page.js
[0-6] 2025-11-28T14:09:24.414Z ERROR webdriver: WebDriverError: element click intercepted: Element <span class="oo-ui-labelElement-label" id="ooui-1" role="textbox" aria-readonly="true">...</span> is not clickable at point (361, 10). Other element would receive the click: <div class="vector-sticky-header-context-bar-primary" aria-hidden="true">...</div>
[0-6]   (Session info: chrome=120.0.6099.224) when running "element/4253AAAD33EDFEA34FCEFB53073BE7F4_element_1038/click" with method "POST"
[0-6] FAILED in chrome - file:///tests/selenium/specs/page.js (1 retries)

It’s not obvious to me how they could be related, but at the same time, it seems quite unlikely that the same test would fail twice with the same pair of messages purely coincidentally.

Event Timeline

This repeated build failed in exactly the same way – this might be brokenness rather than flakiness…

Change #1212615 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] DNM: Empty change to test CI

https://gerrit.wikimedia.org/r/1212615

This repeated build failed in exactly the same way – this might be brokenness rather than flakiness…

Eh, not quite – it’s a different job (quibble-vendor vs. quibble-with-gated-extensions). But it sounds like it fails a lot more often than it should.

Change #1212615 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] DNM: Empty change to test CI

https://gerrit.wikimedia.org/r/1212615

CI passed on this change, but in addition to the builds linked in the task description and earlier comment, I’ve seen the same test failure in:

Change #1212615 abandoned by Lucas Werkmeister (WMDE):

[mediawiki/extensions/Wikibase@master] DNM: Empty change to test CI

https://gerrit.wikimedia.org/r/1212615

Daimona triaged this task as High priority.Dec 1 2025, 2:16 PM
Daimona added a project: MediaWiki-Core-Tests.
Daimona subscribed.

Seen this a bunch of times over the last few days in CampaignEvents as well, the last one being https://integration.wikimedia.org/ci/job/quibble-with-gated-extensions-selenium-php83/439/console for r1203476.

I wouldn't be surprised if it really were "just" slower to load than whatever timeout is configured, this seems to be a recurrent pattern in CI lately. Off the top of my head, I'm familiar with T389863 and T380061. As with all previous times, I would argue that 5 seconds to do basic initialization is not just a sign that something is "slow" and we could just increase the timeouts, but rather that it is seriously struggling, possibly due to an underlying issue that needs to be looked into. Maybe it's just lack of resources, but I don't really know and my previous attempts at understanding have been mostly in vain.

I have no idea abut the mw.loader.using issue but the issue up the page indicates that some setup (beforeEach) script is not executing correctly.

It sounds like the user is logged and is trying to click something that's behind the Vector 2022 sticky header which then causes some issues in the test itself. I'd suggest fixing that and seeing if that addresses the later issue.
Here's the sticky header in question (with some opacity thrown in) to show how it might interfere with clicks to the tool menu (and protect item for example):

Screenshot 2025-12-01 at 12.01.28 PM.png (211×1 px, 88 KB)

I think adding a scrollIntoView call on the element in question should address this.

The “element click intercepted” also happened in this build without an associated “mw.loader.using is not available” error (as far as I can tell). (It’s not actually clear to me if that error caused the build to fail, or if it failed for unrelated reasons.)

Ok, I think I finally figured out the issue from this video of this build:

The final frame screenshot isn’t very helpful, but partway through, we can see this:

Page-should-be-protectable-2025-12-03T14-37-15-989Z.jpg (1×1 px, 173 KB)

And the code looks like this:

ProtectPage.protect()
async protect( title, reason ) {
	await this.open( title );
	await this.reason.setValue( reason );
	await this.confirmProtectionEdit.click();
	await this.allowOnlyAdministrators.click();
	await this.submit.click();
}

So we’ve scrolled down to enter the protection reason, and then the “Allow all users” dropdown (where we want to select “Allow only administrators” instead) is covered by the sticky header.

Let’s see if scrolling that into view helps.

Change #1214527 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/core@master] selenium: Scroll ProtectPage elements into view

https://gerrit.wikimedia.org/r/1214527

On a successful run, the video looks like this: Edit: scratch that, this is a successful run with my attempted fix above. I’m skeptical that the attempted fix is actually correct, but still, using it as an example for how the browser test sometimes passes without any fix is quite silly.

Page-should-be-protectable-2025-12-03T14-55-27-332Z.jpg (1×1 px, 161 KB)

I don’t know what’s causing the slight difference in scroll position (and therefore the flakiness). Possibly there’s a race condition related to when the sticky header shows itself.

Change #1214527 merged by jenkins-bot:

[mediawiki/core@master] selenium: Scroll ProtectPage elements into view

https://gerrit.wikimedia.org/r/1214527

Let’s see if that helps. Please comment here if you still see either of the errors mentioned in the task description!

Sadly, I'm still seeing the error mentioned here: https://integration.wikimedia.org/ci/job/quibble-with-gated-extensions-selenium-php83/1922/console

That being said, watching the video, it seems that protecting the page actually worked as expected. But then when trying to edit the protected page, the error might be occurring? Though I have not yet compared it to the video of a successful run.

Noooooooo 😭

Yeah, the console output looks consistent with that description – the “element click intercepted” error is no longer there but the mw.loader.using wait still times out. Possibly they weren’t related after all? I don’t know.

But watching the video, I noticed the final page view is logged out (of course – otherwise it wouldn’t get the protection error), and I wondered how the test logs out, given that I didn’t notice a logout in the video. It turns out it does this:

// Logout                                                                                                                                                                                                                                                                                                                                                                             
await browser.deleteAllCookies();

What if this deletes not just the cookies, but also the local storage, and thus wipes the ResourceLoader cache, which might then make the next wait for mediawiki.base take too long? (The WebDriver spec doesn’t seem to say anything about that command affecting local storage, but I wouldn’t rule it out yet.) It might be better to log out through MediaWiki, either via the logout link or using the API?

[...]
It turns out it does this:

// Logout                                                                                                                                                                                                                                                                                                                                                                             
await browser.deleteAllCookies();

What if this deletes not just the cookies, but also the local storage, and thus wipes the ResourceLoader cache, which might then make the next wait for mediawiki.base take too long? (The WebDriver spec doesn’t seem to say anything about that command affecting local storage, but I wouldn’t rule it out yet.) It might be better to log out through MediaWiki, either via the logout link or using the API?

Might be worth a shot. Though I noticed that basically everyone seems to log out by deleting cookies:
https://codesearch.wmcloud.org/search/?q=%5BlL%5Dog+%3Fout&files=selenium&excludeFiles=&repos=

Almost all of them seem to use await browser.deleteAllCookies();, which is curious to me because only browser.deleteCookies seems to be documented: https://webdriver.io/docs/api/browser/deleteCookies - Maybe if browser.deleteAllCookies(); is an internal method then that would be consistent with it maybe performing unexpected behavior (clearing localstorage?).

Almost all of them seem to use await browser.deleteAllCookies();, which is curious to me because only browser.deleteCookies seems to be documented: https://webdriver.io/docs/api/browser/deleteCookies - Maybe if browser.deleteAllCookies(); is an internal method then that would be consistent with it maybe performing unexpected behavior (clearing localstorage?).

It’s documented under WebDriver protocol (after loading that link, you might have to click into your address bar and press Enter again to actually jump to the right place); I can’t tell if there’s a difference between deleteCookies() and deleteAllCookies() (I’m not even sure where they’re defined).

Change #1216767 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/core@master] selenium: Log out via API

https://gerrit.wikimedia.org/r/1216767

Change #1216767 merged by jenkins-bot:

[mediawiki/core@master] selenium: Log out via special page

https://gerrit.wikimedia.org/r/1216767

It might be better to log out through MediaWiki, either via the logout link or using the API?

Done (using Special:UserLogout, as it seemed easier – note that we need to log out of the browser session which is separate from the apiClient where we make most API requests!); let’s hope it helps.

(What might also help is having the contents of the browser console when the test fails, e.g. if ResourceLoader logs an error… is there any way to access that? I don’t see it in the job console nor in the artifacts.)

Sill seen. I saved this build forever.

https://integration.wikimedia.org/ci/job/quibble-with-gated-extensions-selenium-php83/3313/console
https://gerrit.wikimedia.org/r/c/mediawiki/vendor/+/1218845

[chrome 120.0.6099.224 linux #0-6] » tests/selenium/specs/page.js
[chrome 120.0.6099.224 linux #0-6] Page
[chrome 120.0.6099.224 linux #0-6]    ✓ should be previewable @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should be creatable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be re-creatable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be editable @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should have history @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should be deletable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be restorable
[chrome 120.0.6099.224 linux #0-6]    ? should be protectable (1x retries)
[chrome 120.0.6099.224 linux #0-6]    ✖ "before each" hook for Page
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] 7 passing (49.9s)
[chrome 120.0.6099.224 linux #0-6] 1 failing
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] 1) Page "before each" hook for Page
[chrome 120.0.6099.224 linux #0-6] mw.loader.using is not available
[chrome 120.0.6099.224 linux #0-6] Error: mw.loader.using is not available
[chrome 120.0.6099.224 linux #0-6]     at async waitForModuleState (file:///workspace/src/tests/selenium/wdio-mediawiki/Util.js:56:3)
[chrome 120.0.6099.224 linux #0-6]     at async isTargetNotWikitext (file:///workspace/src/tests/selenium/wdio-mediawiki/Util.js:22:2)
[chrome 120.0.6099.224 linux #0-6]     at async Context.<anonymous> (file:///workspace/src/tests/selenium/specs/page.js:28:8)

That build actually has two failing tests:

------------------------------------------------------------------
[chrome 120.0.6099.224 linux #0-6] Running: chrome (v120.0.6099.224) on linux
[chrome 120.0.6099.224 linux #0-6] Session ID: 6363cba71584604912fbd043eb1ef7b9
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] » tests/selenium/specs/page.js
[chrome 120.0.6099.224 linux #0-6] Page
[chrome 120.0.6099.224 linux #0-6]    ✓ should be previewable @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should be creatable
[chrome 120.0.6099.224 linux #0-6]    ? should be re-creatable
[chrome 120.0.6099.224 linux #0-6]    ✖ "before each" hook for Page
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] 2 passing (19.4s)
[chrome 120.0.6099.224 linux #0-6] 1 failing
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] 1) Page "before each" hook for Page
[chrome 120.0.6099.224 linux #0-6] mw.loader.using is not available
[chrome 120.0.6099.224 linux #0-6] Error: mw.loader.using is not available
[chrome 120.0.6099.224 linux #0-6]     at async waitForModuleState (file:///workspace/src/tests/selenium/wdio-mediawiki/Util.js:56:3)
[chrome 120.0.6099.224 linux #0-6]     at async isTargetNotWikitext (file:///workspace/src/tests/selenium/wdio-mediawiki/Util.js:22:2)
[chrome 120.0.6099.224 linux #0-6]     at async Context.<anonymous> (file:///workspace/src/tests/selenium/specs/page.js:28:8)
------------------------------------------------------------------
[chrome 120.0.6099.224 linux #0-6] Running: chrome (v120.0.6099.224) on linux
[chrome 120.0.6099.224 linux #0-6] Session ID: f79719280635badb85fff5994ddf0eeb
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] » tests/selenium/specs/page.js
[chrome 120.0.6099.224 linux #0-6] Page
[chrome 120.0.6099.224 linux #0-6]    ✓ should be previewable @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should be creatable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be re-creatable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be editable @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should have history @daily
[chrome 120.0.6099.224 linux #0-6]    ✓ should be deletable
[chrome 120.0.6099.224 linux #0-6]    ✓ should be restorable
[chrome 120.0.6099.224 linux #0-6]    ? should be protectable (1x retries)
[chrome 120.0.6099.224 linux #0-6]    ✖ "before each" hook for Page
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] 7 passing (49.9s)
[chrome 120.0.6099.224 linux #0-6] 1 failing
[chrome 120.0.6099.224 linux #0-6]
[chrome 120.0.6099.224 linux #0-6] 1) Page "before each" hook for Page
[chrome 120.0.6099.224 linux #0-6] mw.loader.using is not available
[chrome 120.0.6099.224 linux #0-6] Error: mw.loader.using is not available
[chrome 120.0.6099.224 linux #0-6]     at async waitForModuleState (file:///workspace/src/tests/selenium/wdio-mediawiki/Util.js:56:3)
[chrome 120.0.6099.224 linux #0-6]     at async isTargetNotWikitext (file:///workspace/src/tests/selenium/wdio-mediawiki/Util.js:22:2)
[chrome 120.0.6099.224 linux #0-6]     at async Context.<anonymous> (file:///workspace/src/tests/selenium/specs/page.js:28:8)
------------------------------------------------------------------
// Logout                                                                                                                                                                                                                                                                                                                                                                             
await browser.deleteAllCookies();

What if this deletes not just the cookies, but also the local storage, and thus wipes the ResourceLoader cache, which might then make the next wait for mediawiki.base take too long?

Well, I just noticed that the beforeEach() hook also has a deleteAllCookies() call 🤦 so if that’s really problematic then my change above won’t have helped much. Unfortunately I can’t figure out why that call is there – it dates all the way back to Create users and pages for Selenium tests using action API (from 2017!), but isn’t explained in there AFAICT; there’s a comment on PS26 that this patch set “deletes cookies before every test”, but I don’t see an explanation for it.

Apart from that I still can’t make much sense of the error. But I notice that the screenshot and video of the “Page should be re-creatable” test (both of which look successful, so I think the retry overwrote whatever recordings the first failure left) show several signs of JavaScript being run (“The page has been created” notice, some kind of sidebar that I don’t know but vaguely recall seeing before), and the screenshot and video of the “Page should be protectable” test show nothing of the sort, so I think it’s plausible that this page view, for whatever reason, really doesn’t have JavaScript / ResourceLoader loaded (as opposed to the alternative that we’re just not detecting it properly).

Mh, maybe I got something wrong, but it seems like webdriver now has a way to access the browsers logs: https://webdriver.io/docs/best-practices/browser-logs/

Maybe we could use that to figure out what is going on? Though not sure if there is a good way to say: "print the logs in the event that the test failed" like in Cypress.

Mh, maybe I got something wrong, but it seems like webdriver now has a way to access the browsers logs: https://webdriver.io/docs/best-practices/browser-logs/

It seems easier with Bidi, which we aren't using yet (T396148). For webdriver classic it seems we need to add wdio/jsonwp-service, but that shouldn't be too difficult I hope.

Maybe we could use that to figure out what is going on? Though not sure if there is a good way to say: "print the logs in the event that the test failed" like in Cypress.

I think we can use the afterTest hook and check the result. We're currently doing this to add -failed to the name of screenshots for failed tests: https://gerrit.wikimedia.org/g/mediawiki/core/+/ec5cd6e2d38cd235606e69d172d97bffdcf18cb8/tests/selenium/wdio-mediawiki/wdio-defaults.conf.js#266