Problem/Motivation
BrowserTestBase::initFrontPage() exists to work around a limitation in WebDriver where cookies cannot be set unless the domain in question has already been visited.
However, not all functional tests likely need to load the homepage, so maybe we can improve performance a tiny bit by loading an image instead of the homepage - this should set the domain without having to execute any PHP.
Steps to reproduce
Proposed resolution
Functional tests don't need this workaround at all, so completely remove the step from setup.
For functional javascript tests, we can visit an image instead.
Remaining tasks
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
Comments
Comment #3
longwaveCurious as to whether this makes any difference, I suspect there's not much in it. But perhaps we could remove
initFrontPage()altogether (including all subclass overrides) if we can assume the image is enough?Comment #4
longwaveNot even sure this is needed at all. The comment says
but even if I comment the
visit()out entirely then I can still place breakpoints inside Drupal and they are hit during a test. Perhaps the webdriver implementation no longer has this issue?Comment #5
mstrelan commentedAre you using xdebug.start_with_request = trigger? Because ddev uses on by default which I don't think requires the cookie. I'd like to not break the trigger mode as we use that a lot outside of ddev.
Comment #6
catchWe could at least only do the request when xdebug is enabled if it's only really for that?
Comment #7
smustgrave commentedBased on #5 should this be NW or what's next steps?
Comment #8
mstrelan commentedTried this out with a few scenarios, comments/results below:
xdebug.start_with_request = triggerwe still need to call$session->visit()for WebDriver testsThe bug that the comment points to (in #4) was marked fixed in 2014, two years before this appeared in coreThe bug is to add documentation for this scenario.I think we need to at least rename
initFrontPageto something likeinitCookieDomain, and optionally remove it from BTB and only include it in WDTB. Otherwise think it's fine.Comment #9
longwaveA small number of contrib tests call this so not sure we can just rename it: https://search.tresbien.tech/search?q=initFrontPage
I also wondered if DTT called this but it doesn't mention it: https://git.drupalcode.org/project/dtt/
Comment #10
mstrelan commentedI guess we could deprecate it then if we want to rename it?
Comment #11
mstrelan commentedI guess we can deprecate it then
Comment #12
catchI managed to open a duplicate at #3616208: Change initFrontPage() to visit robots.txt.
However that duplicate made me realise the jsonapi test here is real rather than random. I've rebased and pushed a commit that adds a front page request to that test method, and opened a follow-up issue to look into it properly #3616376: Remove front page warming step in UserTest::testCollectionFilterAccess - it's not making the test any worse, just more explicitly dependent on whatever side-effect it relies on.
Also created a stub CR here: https://www.drupal.org/node/3616377
Started to look at the deprecation but it was a bit more fiddly than I expected, so decided it was better to get to a fully green run before doing anything for that.
WebdriverTestBase will need to override ::setUp() and call its new method (whatever we call it) if we move it there out of BrowserTestBase. I think it's probably worth moving it out to save the 20ms or whatever it will be requesting the image on every test method in functional tests 20ms x hundreds is still a few seconds.
Comment #13
catchHad a go at the deprecation:
- deprecated ::initFrontPage()
- removed the call to it from BrowserTestBase
- moved the logic + comments to ::initMink() in WebDriverTestBase
One functional js test passed, see if the rest do.
Comment #14
catchOK one test was calling ::initFrontPage() for no reason twice.
Two tests were making assertions based on the front page (or any page) already having been visited, so added a drupalGet() to those.
Otherwise everything works, so that proves this is completely unnecessary in BrowserTestBase, I wonder how many millions of requests we've done over the years.
I think my last question is - do we want to detect
xdebug.start_with_request = triggerand only do the request when that's set? But we could maybe tackle that in a follow-up.Comment #15
mstrelan commentedDefinitely followup material as I think there are other conditions that might make this hard to detect, like if it is "default" instead of "trigger" then it depends on what
xdebug.modeis set to.Comment #16
catchYeah that makes sense, I'm also not entirely sure that's the only thing we need it for, there could be something else copying the xdebug pattern somewhere.
Comment #18
longwaveFixed UserTest, which was checking the wrong thing;
responseHeaderContains()checks the Mink response, but JSON:API tests use Guzzle directly, and we have special assertion methods for that.Comment #19
longwaveAlso fixed JsonApiFunctionalTest which similarly was calling Guzzle and then asserting the wrong thing via Mink. There might be other instances of this if
drupalGet()andhttpClient->request()calls are interleaved elsewhere in JSON:API tests, but this fixes the offenders we found here at least.Comment #20
catchNeeds a rebase.
Comment #21
longwaveSome of the tests that are newly tagged here will be converted by #3618901: Convert some FunctionalJavaScript tests to Functional tests
Comment #22
catchJob runtimes on the latest MR run look extremely good here. When profiling this is something like 2-300ms per test. Even though the what will become the first request with these removed will do some of the cache building that the front page visit would have done, it it's still probably 1-200ms saving per test method.
The slowest job was 2m45s, but 45s of that was runner setup time, these used to be well over 3m30s each.. #3614817: Reduce functional test job CPU and concurrency will bump those times up again slightly but we have at least a couple more issues left on #3615979: [meta] Reduce container rebuilds in the installer and functional/kernel tests to reduce times further, so we're going to end up with both marginally faster test times and a lot less CPU usage overall.
Comment #23
catchUpdated the title and issue summary a bit to match the current approach.
Comment #24
acbramley commentedJust coming here after noticing #3608414: Skip the pre-flight front-page HTTP request in BrowserKitTrait::setupMinkSession() when there is no XDEBUG_SESSION cookie is causing issues when using DrupalSelenium2Driver, @mstrelan pointed me here as it's similar.
Just wanted to point out we definitely do always need the visit in WebDriverTestBase otherwise anything calling executeScript early will fail with something like
Failed to read the 'sessionStorage' property from 'Window': Storage is disabled inside 'data:' URLs.In our case, we are testing that javascript errors correctly fail our JS tests, we have a PreCondition that clears out js_testing_log_test.errors in sessionStorage, but when using the DrupalSelenium2Driver, executeScript calls out to processJavascriptDeprecations which tries to evaluate js_testing_log_test.warnings and fails because there is no active document
Comment #25
longwaveCan we wrap that code in a try/catch, and document that if you want to use session storage early that you are responsible for navigating yourself? I think this would be preferable to forcing every Chrome test to load a page that it doesn't need to.
Comment #27
acbramley commented@longwave yeah we have something like that in our custom code:
$this->getSession()->executeScript("try { sessionStorage.removeItem('js_testing_log_test.errors'); } catch (e) {}");I'm not sure where we'd document the issue though
Comment #28
acbramley commentedThe good news is this patch allowed us to remove auto retries from our FunctionalJavascript test job :)
Comment #29
longwaveWe could just do it in the change record for this issue?
Comment #30
catchThe try/catch sounds good. In the change record sounds fine for documentation.
Comment #31
acbramley commentedShould we add a separate CR to explain that tests no longer visit a frontpage by default? Or fold it into the deprecation CR?
Comment #32
acbramley commentedUnfortunately it looks like we can't move the visit in WebDriverTestBase::initMink inside a conditional based on the existence of $cookies because drupalGet calls out to prepareRequest which sets a cookie so without the visit you get
Behat\Mink\Exception\DriverException: The driver is not started.Comment #33
catchI think we can use one CR for this, it's all pretty related.
I'm a bit confused where things sit between #25/#27 and #32, does #32 mean throwing the exception won't work?