Recipe tests currently need to determine the path of the recipe under test manually using approaches like dirname($dir, 3); or dirname((new \ReflectionObject($this))->getFileName(), 4);. Both approaches fail when the recipe path is a symlink because the real path of the recipe gets resolved, and if the recipe has dependencies on external (contrib) recipes, they are not found by the Recipe system.
This issue was raised in the context of automated QA on GitLab CI ( ✨ Add recipes path handling Active ). While copying recipes instead of symlinking is a valid solution on GitLab CI where code under test should not be modified, it is a major problem in local development environments that leverage symlinks to reduce copy-pasting while developers work—environments such as DDEV Drupal Contrib creates.
Today at DrupalCon 2025 Vienna, /me, @alexpott and @phenaproxima talked about this problem and we thought that a realpath() is missing somewhere. We also agreed that there is still no need for flexibility like
✨
Expand Drupal\Core\Recipe\RecipeDiscovery to allow discovering available recipes, likely for use in Project Browser
Active
in recipe discovery. However it quickly turned out that we weren't right and the problem is not a missing realpath(). Moreover, the problem only impacts tests because ddev drush recipe /var/www/html/recipes/[recipe_name] works just fine, so we have to provide a solution for this at the tests level.
dirname($dir, 3) or dirname((new \ReflectionObject($this))->getFileName(), 4) to retrieve the recipe pathAdd a getRecipePath() helper method to RecipeTestTrait that extracts the recipe name from the test class namespace and constructs the path relative to Drupal root without resolving symlinks:
protected function getRecipePath(): string { $rc = new \ReflectionObject($this); [, , $recipe_name] = explode('\\', $rc->getNamespaceName()); return dirname(\Drupal::root()) . '/recipes/' . $recipe_name; }
This approach avoids symlink resolution issues while maintaining consistency with Drupal's standard recipe directory structure.
\Composer\InstalledVersions::getInstallPath('drupal/ai_recipe_llm_optimized_content') - Other than this would have also required knowing or guessing the recipe's name, composer also stores the resolved path of the symlinkdebug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) - LLM suggested solution, but because tests run in a browser, this leads nowhereNone.
None.
A new protected method getRecipePath() will be added to Drupal\FunctionalTests\Core\Recipe\RecipeTestTrait:
None.
Recipe tests can now use the getRecipePath() helper method from RecipeTestTrait to retrieve the path of the recipe under test without resolving symlinks. This improves support for local development environments that use symlinked recipes, such as DDEV Drupal Contrib setups.
Active
11.0 🔥
recipe system
The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.
Not all content is available!
It's likely this issue predates Contrib.social: some issue and comment data are missing.
No activities found.