diff --git a/src/Plugin/ProjectBrowserSource/Recipes.php b/src/Plugin/ProjectBrowserSource/Recipes.php index bf9b5a1e61b49b119449ab8267af44a642e8ecea..cdffcbe4affe75afda46f58e67e1a92c034d27a1 100644 --- a/src/Plugin/ProjectBrowserSource/Recipes.php +++ b/src/Plugin/ProjectBrowserSource/Recipes.php @@ -122,6 +122,10 @@ final class Recipes extends ProjectBrowserSourceBase { url: $url ?? NULL, ); } + // Sort the $projects array by the 'title' property in ascending order. + usort($projects, function (Project $a, Project $b) { + return strcasecmp($a->title, $b->title); + }); $this->cacheBin->set($this->getPluginId(), $projects); } diff --git a/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php b/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php index 58e87f9f09096fcb322ad247d3be533c508911ca..c4168321bbcc1ce7456dea491a595d42b215c391 100644 --- a/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php +++ b/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php @@ -154,6 +154,10 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase { // If we reload, the installation status should be remembered. $this->getSession()->reload(); + $this->inputSearchField('image', TRUE); + $submit_button = $assert_session->waitForElementVisible('css', ".search__search-submit"); + $this->assertNotEmpty($submit_button); + $submit_button->click(); $card = $assert_session->waitForElementVisible('css', '.pb-project:contains("Image media type")'); $this->assertNotEmpty($card); $assert_installed($card); diff --git a/tests/src/Kernel/RecipesSourceTest.php b/tests/src/Kernel/RecipesSourceTest.php index 32f993ffd5eec73ef3462fcfbddf7cbeb9101a92..cd8818901be7caa2cb868b592367aedb8fa50123 100644 --- a/tests/src/Kernel/RecipesSourceTest.php +++ b/tests/src/Kernel/RecipesSourceTest.php @@ -162,4 +162,56 @@ class RecipesSourceTest extends KernelTestBase { $this->assertSame($expected_recipe_names, $found_recipe_names); } + /** + * Tests sorting of discovered recipes by case-insensitive name. + */ + public function testRecipeSortingByRecipeName(): void { + $this->setSetting('extension_discovery_scan_tests', TRUE); + + /** @var \Drupal\project_browser\Plugin\ProjectBrowserSourceInterface $source */ + $source = $this->container->get(ProjectBrowserSourceManager::class) + ->createInstance('recipes'); + + // Generate fake recipes with varying case names. + $generated_recipes = [ + 'deltaRecipe' => '{"name": "drupal/delta_recipe"}', + 'betaRecipe' => '{"name": "drupal/beta_recipe"}', + 'AlphaRecipe' => '{"name": "drupal/alpha_recipe"}', + 'GammaRecipe' => '{"name": "drupal/gamma_recipe"}', + ]; + + $installed_recipes_dir = uniqid(FileSystem::getOsTemporaryDirectory() . '/'); + $file_system = new SymfonyFilesystem(); + $file_system->mkdir($installed_recipes_dir); + + foreach ($generated_recipes as $recipe_name => $composer_json_content) { + $recipe_dir = $installed_recipes_dir . '/' . $recipe_name; + $file_system->mkdir($recipe_dir); + file_put_contents($recipe_dir . '/composer.json', $composer_json_content); + file_put_contents($recipe_dir . '/recipe.yml', "name: $recipe_name"); + } + + $this->setSetting('project_browser_recipe_directories', [$installed_recipes_dir]); + + // Fetch discovered recipes. + /** @var \Drupal\project_browser\ProjectBrowser\ProjectsResultsPage $projects */ + $projects = $this->container->get(ProjectBrowserSourceManager::class) + ->createInstance('recipes') + ->getProjects(); + $found_recipes = array_column($projects->list, 'title'); + + $generated_recipe_titles = array_keys($generated_recipes); + // Filter the discovered recipe titles to include only those that + // were generated during the test. + $found_generated_titles = array_values(array_intersect($found_recipes, $generated_recipe_titles)); + + // Sort the expected titles using case-insensitive sorting. + usort($generated_recipe_titles, 'strcasecmp'); + + $this->assertSame($generated_recipe_titles, $found_generated_titles); + + // Clean up. + $file_system->remove($installed_recipes_dir); + } + }