<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Richard A. Allen</title>
    <description>The latest articles on DEV Community by Richard A. Allen (@drupalista).</description>
    <link>https://dev.to/drupalista</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1390418%2Ff953823c-8310-4d70-a0fb-f648ae95dd91.jpg</url>
      <title>DEV Community: Richard A. Allen</title>
      <link>https://dev.to/drupalista</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/drupalista"/>
    <language>en</language>
    <item>
      <title>Setting up for Drupal's Functional JavaScript tests</title>
      <dc:creator>Richard A. Allen</dc:creator>
      <pubDate>Sat, 08 Jun 2024 06:06:43 +0000</pubDate>
      <link>https://dev.to/drupalista/drupal-functionaljavascript-testing-1fo7</link>
      <guid>https://dev.to/drupalista/drupal-functionaljavascript-testing-1fo7</guid>
      <description>&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.drupal.org/docs/develop/automated-testing/phpunit-in-drupal/phpunit-browser-test-tutorial" rel="noopener noreferrer"&gt;PHPUnit Browser test tutorial&lt;/a&gt;, Drupal.org, 26 January 2024&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.drupal.org/docs/develop/automated-testing/phpunit-in-drupal/running-phpunit-javascript-tests" rel="noopener noreferrer"&gt;Running PHPUnit JavaScript tests&lt;/a&gt;, Drupal.org, 8 June 2024&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.drupal.org/docs/automated-testing/phpunit-in-drupal/phpunit-javascript-test-writing-tutorial" rel="noopener noreferrer"&gt;PHPUnit JavaScript test writing tutorial&lt;/a&gt;, Drupal.org, 24 July 2022&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mink.behat.org/en/latest/index.html" rel="noopener noreferrer"&gt;Mink documentation&lt;/a&gt;, Behat.org, latest version&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/lando/php/issues/77" rel="noopener noreferrer"&gt;Inspiration for custom Dockerfile I'm using in Lando&lt;/a&gt;, Github, 2023&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.drupal.org/project/drupal/issues/3405976" rel="noopener noreferrer"&gt;D.O. issue #3405976: Transaction autocommit during shutdown relies on unreliable object destruction order (xdebug 3.3+ enabled)&lt;/a&gt;, Drupal.org, created 2023, updated 3 June 2024.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  About you
&lt;/h3&gt;

&lt;p&gt;You are a Drupal, Symfony, or any kind of PHP dev and are looking for help with a peculiar aspect of unit testing (see title above), a tale from the crypts, or nap time story that will put you to sleep. Probably a combination of all of those. Otherwise you should probably move along ;)&lt;/p&gt;

&lt;h3&gt;
  
  
  The context
&lt;/h3&gt;

&lt;p&gt;I'm testing a OAuth implementation between Drupal and SoundCloud and using Drupal's functional suite to do so. The rest of my module is using either kernel or regular unit tests. But for OAuth it's either a mock (see tests for &lt;a href="https://packagist.org/packages/martin1982/oauth2-soundcloud" rel="noopener noreferrer"&gt;Martin1982\OAuth2&lt;/a&gt; on Packagist), or a live call.&lt;/p&gt;

&lt;p&gt;I already looked at &lt;a href="https://github.com/Martin1982/oauth2-soundcloud/blob/24ac2edc9151bde477bc8841e49a6421d2a449ff/tests/Provider/SoundCloudTest.php" rel="noopener noreferrer"&gt;some mocking methods&lt;/a&gt; and I don't like them, too fake; I know, hot take. The SoundCloud service decommissions your access if you do not use it. Baking a live OAuth call into the testing helps keep the access alive (otherwise you'd have to wait months for re-authorization).&lt;/p&gt;

&lt;p&gt;I'm aiming to TDD the heck out of a contrib module I'm doing for fun, and so leaving stones unturned (in testing) is not an option. &lt;em&gt;This is our definition of fun in the development department.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not trying to say one way (mocking) is better than the other (live call), or that there is a right answer. I'm not going to Joel Spolsky this post either. I'm just going with my gut feeling and documenting the process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this post
&lt;/h3&gt;

&lt;p&gt;I already lost the opportunity to document other fixes/discoveries/tips I've done so far with regards to "functional javascript" unit testing today, and so that's why I am starting this post.&lt;/p&gt;

&lt;p&gt;I know that not in a week, but rather by tomorrow I'll forget the details because they're too many to keep track of. Not a bug of this business, just a feature. Documenting stuff somewhere is how we deal with this ... loss of context.&lt;/p&gt;

&lt;p&gt;Also the sooner I can start dumping my browser tabs somewhere else other than a session saver or OneNote, the faster that I can close them up. Marie Kondo would not approve of the amount of tabs I have open, and neither do I! The thing I hate about dumping an entire browser session is that I'll barely revisit those while hunting for a resource. And OneNote just gets out of control, &lt;em&gt;too... many... notes&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Needless to say, you should know this is a &lt;em&gt;raw&lt;/em&gt; post. There is no editing. There is no shiny &lt;a href="https://www.denofgeek.com/movies/how-george-lucas-prevented-spaceballs-merchandise/" rel="noopener noreferrer"&gt;merchandising&lt;/a&gt; material, alt coins or artificial intelligence involved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anyways.
&lt;/h3&gt;

&lt;p&gt;Before PHPUnit was having trouble connecting to Chrome. A quick telnet in the Lando appserver container confirmed that Chrome was indeed up and reachable by the PHP container:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fepwuwfpn4pd05x3iid.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fepwuwfpn4pd05x3iid.png" alt="telnet lando"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And before that I dealt with&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

/app/docroot/web/core/tests/Drupal/FunctionalJavascriptTests/WebDriverTestBase.php:146
The "chromeOptions" array key is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use "goog:chromeOptions instead.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The link (with fix) to that notice is &lt;a href="https://www.drupal.org/node/3422624" rel="noopener noreferrer"&gt;https://www.drupal.org/node/3422624&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I prefer to use environment variables to configure the unit testing because they're easier to access than &lt;code&gt;phpunit.xml&lt;/code&gt;. While I've set them before in the Lando config file, setting things in Lando means that you have to rebuild and restart the whole stack for environmental changes to take effect. Time, it just adds up, man.&lt;/p&gt;

&lt;p&gt;Instead I put it in a bash helper called by Lando tooling. This is the env var:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# The "chromeOptions" array key is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0.&lt;/span&gt;
&lt;span class="c"&gt;# Use "goog:chromeOptions instead. See https://www.drupal.org/node/3422624&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MINK_DRIVER_ARGS_WEBDRIVER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'["chrome", {"browserName": "chrome", "goog:chromeOptions": {"args": ["--disable-gpu","--headless", "--no-sandbox", "--disable-dev-shm-usage"]}}, "http://chrome:9515"]'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Fixing the (second) connectivity issue
&lt;/h3&gt;

&lt;p&gt;My Lando chrome spec needed to be updated to add the allowed origins flag to the chromedriver:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

  &lt;span class="na"&gt;chrome&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;compose&lt;/span&gt;
    &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;drupalci/webdriver-chromedriver:production&lt;/span&gt;
      &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chromedriver --log-path=/tmp/chromedriver.log --verbose --allowed-origins=* --whitelisted-ips=&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Note that there is a myriad chromedriver images out there, and that the drupalci happens to be the one mentioned by either Lando or &lt;a href="https://www.drupal.org/docs/develop/automated-testing/phpunit-in-drupal/running-phpunit-javascript-tests#docker-compose" rel="noopener noreferrer"&gt;Drupal.org&lt;/a&gt; documentation (maybe).&lt;/p&gt;

&lt;p&gt;Credit for that fix is in Github, thanks to user &lt;a href="https://github.com/wodby/docker4drupal/issues/491#issuecomment-1195192823" rel="noopener noreferrer"&gt;@Niklan&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Access is denied and invalid cookie domain
&lt;/h3&gt;

&lt;p&gt;Mink is reporting &lt;code&gt;Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5nl5zxnkcgpl1lyxgqs0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5nl5zxnkcgpl1lyxgqs0.png" alt="mink log"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PHPUnit is reporting &lt;code&gt;&lt;br&gt;
Test Skipped (Drupal\Tests\musica\FunctionalJavascript\FooTest::testMyFirstJavasScriptTest)&lt;br&gt;
An unexpected error occurred while starting Mink: invalid cookie domain&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71bsaubzbzuzpqp5dmxe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71bsaubzbzuzpqp5dmxe.png" alt="phpunit log"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  T.B.C., 6/7/24
&lt;/h3&gt;

&lt;p&gt;I still have 30 or so browser tabs open (lol) and have to hunt this one down.&lt;/p&gt;

&lt;p&gt;Love spending time on testing infrastructure instead of "actual code" (sarcasm). &lt;/p&gt;

&lt;p&gt;It's well past beyond midnight and tomorrow is another day. I'll come back to update this post as I move along.&lt;/p&gt;

&lt;p&gt;T.B.C. ...&lt;/p&gt;
&lt;h3&gt;
  
  
  Invalid cookie domain, 6/8/24
&lt;/h3&gt;

&lt;p&gt;This seems to be highly correlated to env vars &lt;code&gt;SIMPLETEST_BASE_URL&lt;/code&gt; and &lt;code&gt;BROWSERTEST_OUTPUT_BASE_URL&lt;/code&gt;. I changed the first from secure &lt;code&gt;https&lt;/code&gt; to plain-text &lt;code&gt;http&lt;/code&gt;. The URL belongs to the Lando project hosting the Docker  and Drupal stack.&lt;/p&gt;

&lt;p&gt;Here is what my environment variables for PHPUnit are looking like now:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# Variables by integration tests.
export SIMPLETEST_BASE_URL="http://d10ee.lndo.site"
export SIMPLETEST_DB="mysql://drupalX:drupalX@database/drupal10_simpletest"
export BROWSERTEST_OUTPUT_DIRECTORY="$SITES_PATH/simpletest/browser_output"
export BROWSERTEST_OUTPUT_BASE_URL="http://d10ee.lndo.site"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This feels good, this is a great start to my weekend. The Chrome webdriver logs went from displaying &lt;em&gt;nada&lt;/em&gt; to basically a million lines of verbose output? It's doing a lot of something!&lt;/p&gt;

&lt;p&gt;Another good thing that happened is that the &lt;code&gt;invalid cookie domain&lt;/code&gt; error in the PHPUnit logs went away (when run with the &lt;code&gt;--debug&lt;/code&gt; flag), and I got a hit in the breakpoint for one of the tests. Both dummy tests I have in place were getting skipped before and so no test function breakpoints were getting hit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7stjkn70r1ev7zyzv5k4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7stjkn70r1ev7zyzv5k4.png" alt="phpunit log"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now here's an interesting error that I've never seen before while doing Unit or Kernel tests in Drupal:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PHPUnit\Framework\Exception: PHP Fatal error:  Uncaught AssertionError: Transaction $stack was not empty.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;All I have for my dummy test is the following:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

  &lt;span class="cd"&gt;/**
   * Stub.
   */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testCancelExpressionInRule&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'dumb assertion'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;I'll be interesting to see where that error is coming from. I've never done &lt;em&gt;this&lt;/em&gt; particular kind of test in Drupal (Functional JavaScript through PHPUnit), so I'll be learning something new and sharing it here.&lt;/p&gt;

&lt;p&gt;T.B.C., see you later today!&lt;/p&gt;
&lt;h3&gt;
  
  
  Test Class Structure, 6/8/24 1:44pm
&lt;/h3&gt;

&lt;p&gt;I want to make a brief note about how the Functional JavaScript test is structured.&lt;/p&gt;

&lt;p&gt;When I declare my test, the class looks something like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;span class="na"&gt;#[CoversNothing]&lt;/span&gt;
&lt;span class="na"&gt;#[Group('javascript')]&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FooTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;WebDriverTestBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The covers nothing group is used because as far as I understand, Functional and Functional JavaScript tests are not able to cover anything (hence they cover nothing). The group is arbitrary and I use it to fine-tune which tests get run.&lt;/p&gt;

&lt;p&gt;Note the extension of &lt;code&gt;WebDriverTestBase&lt;/code&gt;. This is an abstract class in Drupal core, which itself extends &lt;code&gt;BrowserTestBase&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;span class="cd"&gt;/**
 * Runs a browser test using a driver that supports JavaScript.
 *
 * Base class for testing browser interaction implemented in JavaScript.
 *
 * @ingroup testing
 */&lt;/span&gt;
&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebDriverTestBase&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BrowserTestBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;WebDriverTestBase&lt;/code&gt; is located at &lt;code&gt;core/tests/Drupal/FunctionalJavascriptTests/WebDriverTestBase.php&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BrowserTestBase&lt;/code&gt; itself extends &lt;code&gt;PHPUnit\Framework\TestCase&lt;/code&gt;, which as the namespace indicates comes from PHPUnit itself.&lt;/p&gt;

&lt;p&gt;So the inheritance hierarchy looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PHPUnit\Framework\TestCase -&amp;gt; BrowserTestBase -&amp;gt; WebDriverTestBase -&amp;gt; YourFooBarTest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The reason why I bring this up is because the &lt;code&gt;BrowserTestBase-&amp;gt;setUp()&lt;/code&gt; method is interesting:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

  &lt;span class="cd"&gt;/**
   * {@inheritdoc}
   */&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setUpAppRoot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nb"&gt;chdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Allow tests to compare MarkupInterface objects via assertEquals().&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerComparator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MarkupInterfaceComparator&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setupBaseUrl&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Install Drupal test site.&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;prepareEnvironment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;installDrupal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Setup Mink. Register Mink exceptions to cause test failures instead of&lt;/span&gt;
    &lt;span class="c1"&gt;// errors.&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerFailureType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MinkException&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;initMink&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Set up the browser test output file.&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;initBrowserOutputFile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Ensure that the test is not marked as risky because of no assertions. In&lt;/span&gt;
    &lt;span class="c1"&gt;// PHPUnit 6 tests that only make assertions using $this-&amp;gt;assertSession()&lt;/span&gt;
    &lt;span class="c1"&gt;// can be marked as risky.&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addToAssertionCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;In particular, &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

    // Install Drupal test site.
    $this-&amp;gt;prepareEnvironment();
    $this-&amp;gt;installDrupal();


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Why is this interesting? Well, on the Chrome driver logs I'm seeing the following:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[1717864444.039][DEBUG]: DevTools WebSocket Response: Page.getFrameTree (id=30) (session_id=DFB171623C6AD0FD50AE0D2C08195426) 0A012DB02731872ED0B91131E95AB5F4 {
   "frameTree": {
      "frame": {
         "adFrameStatus": {
            "adFrameType": "none"
         },
         "crossOriginIsolatedContextType": "NotIsolated",
         "domainAndRegistry": "lndo.site",
         "gatedAPIFeatures": [  ],
         "id": "0A012DB02731872ED0B91131E95AB5F4",
         "loaderId": "D4966004B7AA6D4BA7B903A2FC1BE098",
         "mimeType": "text/html",
         "secureContextType": "InsecureScheme",
         "securityOrigin": "http://d10ee.lndo.site",
         "url": "http://d10ee.lndo.site/core/install.php"
      }
   }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This is odd because as I highlighted above, the Functional JavaScript test, by capacity of it's inheritance model is supposed to &lt;code&gt;$this-&amp;gt;installDrupal();&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Basically PHPUnit installs it's own database scheme, separate from whatever the default Lando/DDev/Docker database is for your Drupal instance. And it does it for each test suite, at the bare minimum. Not 100% sure if it does it for each single test case, but it works along those broad outlines. The finer-grained details of how many times the database is installed is not relevant here, just the fact that PHPUnit installs the database at least once is.&lt;/p&gt;

&lt;p&gt;When I see &lt;code&gt;install.php&lt;/code&gt; it means that something is still probably amiss in the PHPUnit configuration... because the test cases should be visiting an already-installed Drupal instance, not a yet-to-be installed instance.&lt;/p&gt;

&lt;p&gt;Digging into it.&lt;/p&gt;

&lt;p&gt;C.U. later&lt;/p&gt;
&lt;h3&gt;
  
  
  Wholly molly: Transaction $stack was not empty
&lt;/h3&gt;

&lt;p&gt;Well I didn't see this one coming, certainly out of leftfield it came.&lt;/p&gt;

&lt;p&gt;The full error (minus stack trace) is: &lt;code&gt;PHPUnit\Framework\Exception: PHP Fatal error:  Uncaught AssertionError: Transaction $stack was not empty. Active stack: 666487f8d33255.42467631\drupal_transaction in /app/docroot/web/core/lib/Drupal/Core/Database/Transaction/TransactionManagerBase.php:99&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Luckily the first Google result is for &lt;a href="https://www.drupal.org/project/drupal/issues/3405976" rel="noopener noreferrer"&gt;D.O. issue #3405976: Transaction autocommit during shutdown relies on unreliable object destruction order (xdebug 3.3+ enabled)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scrolling through the comments I see Mondrake mention that a fix is to &lt;a href="https://www.drupal.org/project/drupal/issues/3405976#comment-15621320" rel="noopener noreferrer"&gt;disable xdebug's develop mode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's see, what does my Lando say:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

  &lt;span class="na"&gt;appserver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="c1"&gt;# Lies, deception: tell Lando it's 8.2 instead of 8.3.&lt;/span&gt;
    &lt;span class="c1"&gt;# https://github.com/lando/php/issues/77.&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php:8.2&lt;/span&gt;

    &lt;span class="c1"&gt;# https://docs.lando.dev/config/php.html#configuration&lt;/span&gt;
    &lt;span class="na"&gt;xdebug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;debug,develop,coverage"&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../lando/resources/php.ini&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Container:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

www-data@31a2e4846210:/app/docroot&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$XDEBUG_MODE&lt;/span&gt;
debug,develop,coverage


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;I'm definitely not gonna spend a dollar or two in electricity rebuilding the Docker stack, times are tight!&lt;/p&gt;

&lt;p&gt;I go to my trusty Bash test runner for PHPUnit and change &lt;code&gt;XDEBUG_MODE&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# From this :&lt;/span&gt;
&lt;span class="c"&gt;# export XDEBUG_MODE="debug,develop,coverage"&lt;/span&gt;

&lt;span class="c"&gt;# To this :&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;XDEBUG_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"debug"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Coverage hasn't been working at all for me lately, so I'll leave it disabled until I get to that particular bone another day.&lt;/p&gt;
&lt;h4&gt;
  
  
  Fixing XDebug fatal error
&lt;/h4&gt;

&lt;p&gt;Before:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

PHPUnit 10.5.20 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.7
Configuration: /app/docroot/web/core/phpunit.xml.dist

E

Time: 00:37.061, Memory: 12.00 MB

Foo &lt;span class="o"&gt;(&lt;/span&gt;Drupal&lt;span class="se"&gt;\T&lt;/span&gt;ests&lt;span class="se"&gt;\m&lt;/span&gt;usica&lt;span class="se"&gt;\F&lt;/span&gt;unctionalJavascript&lt;span class="se"&gt;\F&lt;/span&gt;oo&lt;span class="o"&gt;)&lt;/span&gt;
 ✘ Cancel expression &lt;span class="k"&gt;in &lt;/span&gt;rule
   ┐
   ├ PHPUnit&lt;span class="se"&gt;\F&lt;/span&gt;ramework&lt;span class="se"&gt;\E&lt;/span&gt;xception: PHP Fatal error:  Uncaught AssertionError: Transaction &lt;span class="nv"&gt;$stack&lt;/span&gt; was not empty. Active stack: 666487f8d33255.42467631&lt;span class="se"&gt;\d&lt;/span&gt;rupal_transaction &lt;span class="k"&gt;in&lt;/span&gt; /app/docroot/web/core/lib/Drupal/Core/Database/Transaction/TransactionManagerBase.php:99
   ├ Stack trace:
...
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;After&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

PHPUnit 10.5.20 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.7
Configuration: /app/docroot/web/core/phpunit.xml.dist

.F                                                                  2 / 2 &lt;span class="o"&gt;(&lt;/span&gt;100%&lt;span class="o"&gt;)&lt;/span&gt;

Time: 01:03.459, Memory: 12.00 MB

Foo &lt;span class="o"&gt;(&lt;/span&gt;Drupal&lt;span class="se"&gt;\T&lt;/span&gt;ests&lt;span class="se"&gt;\m&lt;/span&gt;usica&lt;span class="se"&gt;\F&lt;/span&gt;unctionalJavascript&lt;span class="se"&gt;\F&lt;/span&gt;oo&lt;span class="o"&gt;)&lt;/span&gt;
 ✔ Cancel expression &lt;span class="k"&gt;in &lt;/span&gt;rule
 ✘ My first javas script &lt;span class="nb"&gt;test&lt;/span&gt;
   ┐
   ├ Behat&lt;span class="se"&gt;\M&lt;/span&gt;ink&lt;span class="se"&gt;\E&lt;/span&gt;xception&lt;span class="se"&gt;\U&lt;/span&gt;nsupportedDriverActionException: Status code is not available from Drupal&lt;span class="se"&gt;\F&lt;/span&gt;unctionalJavascriptTests&lt;span class="se"&gt;\D&lt;/span&gt;rupalSelenium2Driver
...
FAILURES!
Tests: 2, Assertions: 5, Failures: 1.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Notice the test result goes from &lt;code&gt;E&lt;/code&gt; to &lt;code&gt;.F&lt;/code&gt;, which in PHPUnit lingo means the first unit test ran! I must say I was surprised when I saw that dot "pop up".&lt;/p&gt;

&lt;p&gt;If you're wondering what version of Xdebug you're running, just do &lt;code&gt;php -v&lt;/code&gt;, like so:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

www-data@31a2e4846210:/app/docroot$ php -v
PHP 8.3.7 (cli) (built: Jun  6 2024 01:39:14) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.7, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.7, Copyright (c), by Zend Technologies
    with Xdebug v3.4.0alpha2-dev, Copyright (c) 2002-2024, by Derick Rethans


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The D.O. issue mentions Xdebug 3.3+, and I'm on 3.4.x, so the version matches the description, along with the database-related fatal error stack trace. Another win for today.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With the last fix for Xdebug addressed, and all the kinks of getting Chrome up and running for the Drupal Functional JavaScript tests (I really wish they changed the name to something shorter), I am going to wrap up this post.&lt;/p&gt;

&lt;p&gt;With this part of the testing infrastructure fully operational I can now finally go around my business of &lt;em&gt;actually writing software&lt;/em&gt; as opposed to &lt;em&gt;infrastructure as software&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I'm sure these errors will pop up someday again and I'll be glad I posted this here for my future self.&lt;/p&gt;

&lt;p&gt;If you have any questions or feedback, make sure to use the comments below!&lt;/p&gt;

&lt;p&gt;I will leave here the bash test runner I've been referencing through the post:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Here is the current Landofile &lt;code&gt;.lando.yml&lt;/code&gt; I am using. Notice I am not using Lando's default PHP image. This is because my current version of Lando does not support the latest Lando PHP recipe, so I had to cook my own PHP image in order to get the latest PHP.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If you really want or need to build your own Docker container like I'm doing, just check out the Lando issue I'm referencing at &lt;a href="https://github.com/lando/php/issues/77" rel="noopener noreferrer"&gt;https://github.com/lando/php/issues/77&lt;/a&gt;. It contains pretty much the &lt;code&gt;Dockerfile&lt;/code&gt; I'm using in the &lt;code&gt;build&lt;/code&gt; parameter. I'm not pushing it (the image is massive), so you'll literally have to build instead of pulling if you go that route.&lt;/p&gt;

&lt;p&gt;For the Lando tooling in &lt;code&gt;.lando.base.yml&lt;/code&gt;, the relevant config is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

  &lt;span class="c1"&gt;# Call PHPUnit from the directory that contains Drupal core /vendor.&lt;/span&gt;
  &lt;span class="c1"&gt;# It's where bootstrap.php expects to be called from.&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Debug PHPUnit&lt;/span&gt;
    &lt;span class="na"&gt;dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/app/docroot&lt;/span&gt;
    &lt;span class="na"&gt;cmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;appserver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./test-lando&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's it for today, &lt;a href="https://youtu.be/SnKPz2acsBk?si=D70z8rxqtggZWfuz" rel="noopener noreferrer"&gt;Brooklyn sends its regards&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>drupal</category>
      <category>docker</category>
      <category>php</category>
      <category>phpunit</category>
    </item>
  </channel>
</rss>
