diff --git a/inc/container.php b/inc/container.php index 8d3438f..3db6f18 100644 --- a/inc/container.php +++ b/inc/container.php @@ -24,6 +24,7 @@ use Syde\WpPhpUnitIntegration\ShutdownFunctionRegisterer; use Syde\WpPhpUnitIntegration\SymfonyProcessFactory; use Syde\WpPhpUnitIntegration\Task\ActivateTestedPlugin; +use Syde\WpPhpUnitIntegration\Task\ActivateTestedPluginDependencies; use Syde\WpPhpUnitIntegration\Task\ActivateTestedTheme; use Syde\WpPhpUnitIntegration\Task\Bundle\Cleanup; use Syde\WpPhpUnitIntegration\Task\Bundle\Load; @@ -130,6 +131,7 @@ $contextual = (match ($container->get(PackageTypeDetector::class)->determine()) { PackageType::Plugin => [ $container->get(SymlinkTestedPlugin::class), + $container->get(ActivateTestedPluginDependencies::class), $container->get(ActivateTestedPlugin::class), ], PackageType::Theme => [ @@ -155,6 +157,10 @@ $container->get(PackageRootPath::class), $container->get(WpCli::class), ), + ActivateTestedPluginDependencies::class => static fn (ContainerInterface $container): ActivateTestedPluginDependencies => new ActivateTestedPluginDependencies( + $container->get(PackageRootPath::class), + $container->get(WpCli::class), + ), ActivateTestedTheme::class => static fn (ContainerInterface $container): ActivateTestedTheme => new ActivateTestedTheme( $container->get(PackageRootPath::class), $container->get(WpCli::class), diff --git a/src/Task/ActivateTestedPluginDependencies.php b/src/Task/ActivateTestedPluginDependencies.php new file mode 100644 index 0000000..a140e91 --- /dev/null +++ b/src/Task/ActivateTestedPluginDependencies.php @@ -0,0 +1,52 @@ +packageRootPath->path()); + + foreach ($this->requiredPlugins($testedPluginName) as $requiredPlugin) { + $this->wpCli->run(['plugin', 'activate', $requiredPlugin]); + } + } + + /** + * @return string[] + */ + private function requiredPlugins(string $pluginName): array + { + $requiredPluginsField = json_decode( + $this->wpCli->run([ + 'plugin', + 'get', + $pluginName, + '--field=requires_plugins', + '--format=json', + ]), + flags: JSON_THROW_ON_ERROR, + ); + + if (!is_string($requiredPluginsField) || $requiredPluginsField === '') { + return []; + } + + return array_filter( + array_map('trim', explode(',', $requiredPluginsField)), + ); + } +} diff --git a/src/WpCli.php b/src/WpCli.php index e2c0837..6d2cbfc 100644 --- a/src/WpCli.php +++ b/src/WpCli.php @@ -20,7 +20,7 @@ public function __construct( /** * @param string[] $args */ - public function run(array $args): void + public function run(array $args): string { $extendedArgs = [ $this->wpCliPath->path(), @@ -29,14 +29,19 @@ public function run(array $args): void '--skip-themes', '--path=' . $this->wordPressPath->path(), ]; + $output = ''; $this->symfonyProcessFactory->create($extendedArgs)->run( - static function (string $type, string $data): void { + static function (string $type, string $data) use (&$output): void { if ($type === Process::ERR) { // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped throw new Exception($data); } + + $output .= $data; } ); + + return $output; } } diff --git a/tests/phpunit/Functional/Task/ActivateTestedPluginDependenciesTest.php b/tests/phpunit/Functional/Task/ActivateTestedPluginDependenciesTest.php new file mode 100644 index 0000000..6e5a6f7 --- /dev/null +++ b/tests/phpunit/Functional/Task/ActivateTestedPluginDependenciesTest.php @@ -0,0 +1,138 @@ +filesystem->mkdir($this->workspace . '/acme'); + + $wpCli = $this->createMock(WpCli::class); + $wpCli + ->expects($this->once()) + ->method('run') + ->with( + [ + 'plugin', + 'get', + 'acme', + '--field=requires_plugins', + '--format=json', + ], + ) + ->willReturn('""'); + + (new ActivateTestedPluginDependencies( + $this->localDependencyPath($this->workspace . '/acme'), + $wpCli, + ))->execute(); + } + + /** + * @param list, 1: string}> $wpCliArgsReturnMap + */ + #[DataProvider('wpCliArgsReturnMapProvider')] + public function testRequiredPluginsAreActivated(array $wpCliArgsReturnMap): void + { + $this->filesystem->mkdir($this->workspace . '/acme'); + + $wpCli = $this->createMock(WpCli::class); + $wpCli + ->expects($this->exactly(count($wpCliArgsReturnMap))) + ->method('run') + ->willReturnMap($wpCliArgsReturnMap); + + (new ActivateTestedPluginDependencies( + $this->localDependencyPath($this->workspace . '/acme'), + $wpCli, + ))->execute(); + } + + public static function wpCliArgsReturnMapProvider(): \Generator + { + yield [ + [ + [ + [ + 'plugin', + 'get', + 'acme', + '--field=requires_plugins', + '--format=json', + ], + '"woocommerce"', + ], + [ + [ + 'plugin', + 'activate', + 'woocommerce', + ], + '', + ], + ], + ]; + + yield [ + [ + [ + [ + 'plugin', + 'get', + 'acme', + '--field=requires_plugins', + '--format=json', + ], + '"woocommerce,, ,"', + ], + [ + [ + 'plugin', + 'activate', + 'woocommerce', + ], + '', + ], + ], + ]; + + yield [ + [ + [ + [ + 'plugin', + 'get', + 'acme', + '--field=requires_plugins', + '--format=json', + ], + '"woocommerce, woocommerce-subscriptions"', + ], + [ + [ + 'plugin', + 'activate', + 'woocommerce', + ], + '', + ], + [ + [ + 'plugin', + 'activate', + 'woocommerce-subscriptions', + ], + '', + ], + ], + ]; + } +}