Static caches and state need to be reset after every browser request
To speed up its page requests Drupal makes heavy use of global static variables (in Drupal 7) and object properties (in Drupal 8) to store its current state. These caches are not typically cleared at the end of the request since a typical web request is short lived and the process disappears when the page is delivered.
If a Behat test is using DrupalContext then Drupal will be bootstrapped early on (in the BeforeSuiteScope step). This starts a request which is not short lived, but can live for several minutes while the tests run. During the lifetime of this request there will be steps executed that do requests of their own, changing the state of the Drupal site. This does not however update any of the statically cached data of the parent request, so this is totally unaware of the changes. This causes unexpected behaviour. I currently have a case where my database caches become corrupted because DatabaseCacheTagsChecksum::invalidateTags() keeps a local storage of which cache tags were invalidated, and this is not reset in time.
Simpletest takes this into account. After every request it calls WebTestBase::refreshVariables() which clears the static caches. We should do the same.
Now the tricky part is that requests can be done outside of the scope of DrupalContext. One of the most common ways to do a page request is MinkContext::visit() and currently there is no way to notify DrupalContext of this event.
What would be a good way of fixing this? I guess we should implement an event listener that fires whenever a request is done.
I think the best way to implement this would be 2 new hooks (perhaps @beforeRequest and @afterRequest) that any context could provide methods that would react, similar to @beforeScenario, @beforeNodeCreate etc. These would ideally go into the mink extension (the project, not this project's extension of that), since that would capture all requests, not just ones channeled through this code).
#179 is related here I think.
#179 is about an issue with the REQUEST_TIME constant being relied on in Drupal code that is executed by the test runner. Unfortunately (unlike static caches) we cannot change constants during runtime, so this can not be solved in this issue.
Hi, was this issue ever resolved? I see what looks like some related work in the MinkExtension queue - is it otherwise still outstanding?
This affects me in a test where, on a particular step (creating a node), I expect a cache tag to be invalidated but it doesn't. I tested the same steps manually and the invalidation is done correctly. Running something similar to FunctionalTestSetupTrait::refreshVariables(), just before that step, fixed the issue.
This was explored in https://github.com/Behat/MinkExtension/issues/222 but it is not possible to track when a browser request occurs. First of all the webdriver does not communicate this information so this is basically unfixable.
Secondly when doing BDD you should not be concerned about the website doing requests. The site might trigger a request at any time in the background through JS and this might not even result in visible changes in the page. If we need to start reacting on browser events we are not testing the user behavior any more, so we're not doing BDD and it is better to write a KernelTest instead of a Behat test.
We could look at other mechanisms to clear static caches though, but it would be hard to identify clear moments to do so. @AfterStep would just be clearing caches unnecessarily and affecting performance. @AfterScenario would be fine but wouldn't catch the problems related here.
I think the best solution would be to look at every case individually, for example if a specific cache needs invalidating after a node is created we could look into that in a separate ticket, but I have a feeling this will quickly become too implementation specific. For example the problem that @claudiu-cristea describes is specific to Drupal 8 and doesn't apply to Drupal 6 and 7 which don't have cache tags. This moves the responsibility away from Behat Extension into Drupal Driver territory.