From bb268e424cacfcedd9daf084d14796450595ca03 Mon Sep 17 00:00:00 2001 From: Luca Tumedei Date: Fri, 28 Jul 2023 14:57:13 -0700 Subject: [PATCH] feat(setup) theme project --- src/Project/ContentProject.php | 194 +++++++++++++ src/Project/PluginProject.php | 198 ++----------- src/Project/ProjectInterface.php | 2 +- src/Project/SiteProject.php | 2 +- src/Project/ThemeProject.php | 191 ++++++++++-- src/Template/Wpbrowser.php | 14 +- .../Codeception/Template/WpbrowserTest.php | 226 ++++++++++++++- ...fold_for_child_theme_correctly__0.snapshot | 272 ++++++++++++++++++ ...lugin_with_non_plugin_php_file__0.snapshot | 192 ++++++++++++- ...ith_non_plugin_php_file_custom__0.snapshot | 116 +++++++- ...or_plugin_with_plugin_php_file__0.snapshot | 192 ++++++++++++- ...in_with_plugin_php_file_custom__0.snapshot | 116 +++++++- ...d_scaffold_for_theme_correctly__0.snapshot | 271 +++++++++++++++++ ...old_for_theme_custom_correctly__0.snapshot | 256 +++++++++++++++++ .../WPBrowser/Project/PluginProjectTest.php | 1 - .../WPBrowser/Project/ThemeProjectTest.php | 116 ++++++++ 16 files changed, 2137 insertions(+), 222 deletions(-) create mode 100644 src/Project/ContentProject.php create mode 100644 tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_child_theme_correctly__0.snapshot create mode 100644 tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_theme_correctly__0.snapshot create mode 100644 tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_theme_custom_correctly__0.snapshot create mode 100644 tests/unit/lucatume/WPBrowser/Project/ThemeProjectTest.php diff --git a/src/Project/ContentProject.php b/src/Project/ContentProject.php new file mode 100644 index 000000000..414da2f52 --- /dev/null +++ b/src/Project/ContentProject.php @@ -0,0 +1,194 @@ +|false + */ + abstract public static function parseDir(string $workDir): array|false; + + abstract protected function scaffoldEndToEndActivationCest(): void; + + abstract protected function scaffoldIntegrationActivationTest(): void; + + protected function getFreeLocalhostPort( + string $docRoot + ): int { + try { + $process = new Process(['php', '-S', 'localhost:0', '-t', $docRoot]); + $process->start(); + do { + if (!$process->isRunning() && $process->getExitCode() !== 0) { + throw new RuntimeException($process->getErrorOutput() ?: $process->getOutput()); + } + $output = $process->getErrorOutput(); + $port = preg_match('~localhost:(\d+)~', $output, $matches) ? $matches[1] : null; + } while ($port === null); + return (int)$port; + } catch (Exception $e) { + throw new RuntimeException( + 'Could not start PHP built-in server to find free localhost port: ' . $e->getMessage() + ); + } finally { + if (isset($process)) { + $process->stop(); + } + } + } + + public function getTestEnv(): ?TestEnvironment + { + return $this->testEnvironment; + } + + private function getAfterSuccessClosure(bool $activated): Closure + { + $basename = basename($this->workDir); + return function () use ($basename, $activated): void { + if ($activated) { + $this->scaffoldEndToEndActivationCest(); + $this->scaffoldIntegrationActivationTest(); + } + $this->say("The {$this->getProjectType()} has been linked into the " . + "tests/_wordpress/wp-content/{$this->getProjectType()}s/$basename directory."); + $this->say("If your {$this->getProjectType()} requires additional plugins and themes, place them in the " . + 'tests/_wordpress/wp-content/plugins and ' . + 'tests/_wordpress/wp-content/themes directories.'); + }; + } + + public function setup() + { + try { + $this->say('You can use a portable configuration based on PHP built-in server, Chromedriver ' . + 'and SQLite.'); + $useDefaultConfiguration = $this->ask('Do you want to use this configuration?', true); + + if (!$useDefaultConfiguration) { + $this->say('Review and update the tests/.env file to configure your testing environment.'); + $this->testEnvironment = new TestEnvironment(); + return; + } + + $wpRootDir = $this->workDir . '/tests/_wordpress'; + $dataDir = $this->workDir . '/tests/_wordpress/data'; + + if (!is_dir($dataDir) && !(mkdir($dataDir, 0777, true) && is_dir($dataDir))) { + throw new RuntimeException("Could not create WordPress data directory $dataDir."); + } + + $db = new SQLiteDatabase('tests/_wordpress/data', 'db.sqlite'); + + $this->sayInfo('Installing WordPress in tests/_wordpress ...'); + Installation::scaffold($wpRootDir); + // Remove the directory used to store the WordPress installation. + FS::rrmdir(Source::getWordPressVersionsCacheDir()); + $installation = new Installation($wpRootDir); + $installation->configure($db); + $serverLocalhostPort = $this->getFreeLocalhostPort($this->workDir); + $installation->install( + "http://localhost:$serverLocalhostPort", + 'admin', + 'password', + 'admin@exmaple.com', + $this->getName() . ' Test' + ); + + // Symlink the project into the WordPress plugins or themes directory. + $this->symlinkProjectInContentDir($wpRootDir); + + $activated = $this->activate($wpRootDir, $serverLocalhostPort); + + $tmpDumpFile = tempnam(sys_get_temp_dir(), 'wpb'); + + if ($tmpDumpFile === false) { + throw new RuntimeException('Could not create temporary file to store database dump.'); + } + + $db->dump($tmpDumpFile); + FS::mkdirp($this->workDir . '/tests/Support/Data'); + if (!rename($tmpDumpFile, $this->workDir . '/tests/Support/Data/dump.sql')) { + throw new RuntimeException( + "Could not move database dump from $tmpDumpFile to tests/Support/Data/dump.sql." + ); + } + $this->sayInfo('Created database dump in tests/Support/Data/dump.sql.'); + } catch (Exception $e) { + throw new RuntimeException('Could not create database dump: ' . $e->getMessage()); + } + + $this->sayInfo('Adding Chromedriver binary as a development dependency ...'); + $composer = new Composer($this->workDir . '/composer.json'); + $composer->requireDev(['webdriver-binary/binary-chromedriver' => '*']); + $composer->allowPluginsFromPackage('webdriver-binary/binary-chromedriver'); + $composer->update('webdriver-binary/binary-chromedriver'); + $this->say(); + + $chromedriverPort = $this->getFreeLocalhostPort($this->workDir); + + $testEnvironment = new TestEnvironment; + $testEnvironment->wpRootDir = FS::relativePath($this->workDir, $wpRootDir); + $testEnvironment->dbUrl = 'sqlite://%codecept_root_dir%/tests/_wordpress/data/db.sqlite'; + $testEnvironment->testTablePrefix = 'test_'; + $testEnvironment->wpTablePrefix = 'wp_'; + $testEnvironment->wpUrl = "http://localhost:$serverLocalhostPort"; + $testEnvironment->wpDomain = "localhost:$serverLocalhostPort"; + $testEnvironment->chromeDriverHost = 'localhost'; + $testEnvironment->chromeDriverPort = $chromedriverPort; + $testEnvironment->envFileContents = <<extensionsEnabled = [ + ChromeDriverController::class => [ + 'port' => "%CHROMEDRIVER_PORT%", + ], + BuiltInServerController::class => [ + 'workers' => 5, + 'port' => "%BUILTIN_SERVER_PORT%", + 'docroot' => FS::relativePath($this->workDir, $wpRootDir) + ] + + ]; + $testEnvironment->customCommands[] = DevStart::class; + $testEnvironment->customCommands[] = DevStop::class; + $testEnvironment->customCommands[] = DevInfo::class; + $testEnvironment->customCommands[] = DevRestart::class; + + $testEnvironment->afterSuccess = $this->getAfterSuccessClosure($activated); + + $this->testEnvironment = $testEnvironment; + } +} diff --git a/src/Project/PluginProject.php b/src/Project/PluginProject.php index 33730339a..945b9ece5 100644 --- a/src/Project/PluginProject.php +++ b/src/Project/PluginProject.php @@ -2,41 +2,36 @@ namespace lucatume\WPBrowser\Project; -use Codeception\InitTemplate; -use Exception; -use lucatume\WPBrowser\Command\DevInfo; -use lucatume\WPBrowser\Command\DevRestart; -use lucatume\WPBrowser\Command\DevStart; -use lucatume\WPBrowser\Command\DevStop; use lucatume\WPBrowser\Exceptions\InvalidArgumentException; use lucatume\WPBrowser\Exceptions\RuntimeException; -use lucatume\WPBrowser\Extension\BuiltInServerController; -use lucatume\WPBrowser\Extension\ChromeDriverController; use lucatume\WPBrowser\Process\Loop; +use lucatume\WPBrowser\Process\ProcessException; +use lucatume\WPBrowser\Process\WorkerException; use lucatume\WPBrowser\TestCase\WPTestCase; -use lucatume\WPBrowser\Utils\Composer; use lucatume\WPBrowser\Utils\Filesystem as FS; use lucatume\WPBrowser\Utils\Strings; use lucatume\WPBrowser\WordPress\CodeExecution\CodeExecutionFactory; -use lucatume\WPBrowser\WordPress\Database\SQLiteDatabase; -use lucatume\WPBrowser\WordPress\Installation; -use lucatume\WPBrowser\WordPress\Source; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Process\Process; +use Throwable; -class PluginProject extends InitTemplate implements ProjectInterface +class PluginProject extends ContentProject { public const ERR_PLUGIN_NOT_FOUND = 1; private string $pluginFile; private string $pluginName; - private ?TestEnvironment $testEnvironment; - private $projectType = 'plugin'; + private string $pluginDir; + + protected function getProjectType(): string + { + return 'plugin'; + } public function __construct(InputInterface $input, OutputInterface $output, protected string $workDir) { parent::__construct($input, $output); - $pluginNameAndFile = self::findPluginNameAndFile($workDir); + $pluginNameAndFile = self::parseDir($workDir); + $this->pluginDir = basename($this->workDir); if ($pluginNameAndFile === false) { throw new InvalidArgumentException( @@ -53,7 +48,7 @@ public function getType(): string return 'plugin'; } - public function getPluginsString(): string + public function getActivationString(): string { return basename($this->workDir) . '/' . basename($this->pluginFile); } @@ -61,7 +56,7 @@ public function getPluginsString(): string /** * @return array{0: string, 1: string}|false */ - public static function findPluginNameAndFile(string $workDir): array|false + public static function parseDir(string $workDir): array|false { $pluginFile = null; $pluginName = null; @@ -86,133 +81,13 @@ public static function findPluginNameAndFile(string $workDir): array|false } } - if (empty($pluginFile) || !($realpath = realpath($pluginFile))) { + if (empty($pluginName) || empty($pluginFile) || !($realpath = realpath($pluginFile))) { return false; } return [$realpath, $pluginName]; } - public function setup(): void - { - - try { - $this->say('You can use a portable configuration based on PHP built-in server, Chromedriver ' . - 'and SQLite.'); - $useDefaultConfiguration = $this->ask('Do you want to use this configuration?', true); - - if (!$useDefaultConfiguration) { - $this->say('Review and update the tests/.env file to configure your testing environment.'); - $this->testEnvironment = new TestEnvironment(); - return; - } - - $wpRootDir = $this->workDir . '/tests/_wordpress'; - $dataDir = $this->workDir . '/tests/_wordpress/data'; - - if (!is_dir($dataDir) && !(mkdir($dataDir, 0777, true) && is_dir($dataDir))) { - throw new RuntimeException("Could not create WordPress data directory $dataDir."); - } - - $db = new SQLiteDatabase('tests/_wordpress/data', 'db.sqlite'); - - $this->sayInfo('Installing WordPress in tests/_wordpress ...'); - Installation::scaffold($wpRootDir); - // Remove the directory used to store the WordPress installation. - FS::rrmdir(Source::getWordPressVersionsCacheDir()); - $installation = new Installation($wpRootDir); - $installation->configure($db); - $serverLocalhostPort = $this->getFreeLocalhostPort($this->workDir); - $installation->install( - "http://localhost:$serverLocalhostPort", - 'admin', - 'password', - 'admin@exmaple.com', - $this->getName() . ' Test' - ); - - $basename = basename($this->workDir); - FS::symlink($this->workDir, $wpRootDir . '/wp-content/plugins/' . $basename); - - $activated = $this->activate($wpRootDir, $serverLocalhostPort); - - $tmpDumpFile = tempnam(sys_get_temp_dir(), 'wpb'); - - if ($tmpDumpFile === false) { - throw new RuntimeException('Could not create temporary file to store database dump.'); - } - - $db->dump($tmpDumpFile); - FS::mkdirp($this->workDir . '/tests/Support/Data'); - if (!rename($tmpDumpFile, $this->workDir . '/tests/Support/Data/dump.sql')) { - throw new RuntimeException( - "Could not move database dump from $tmpDumpFile to tests/Support/Data/dump.sql." - ); - } - $this->sayInfo('Created database dump in tests/Support/Data/dump.sql.'); - } catch (\Exception $e) { - throw new RuntimeException('Could not create database dump: ' . $e->getMessage()); - } - - $this->sayInfo('Adding Chromedriver binary as a development dependency ...'); - $composer = new Composer($this->workDir . '/composer.json'); - $composer->requireDev(['webdriver-binary/binary-chromedriver' => '*']); - $composer->allowPluginsFromPackage('webdriver-binary/binary-chromedriver'); - $composer->update('webdriver-binary/binary-chromedriver'); - $this->say(); - - $chromedriverPort = $this->getFreeLocalhostPort($this->workDir); - - $testEnvironment = new TestEnvironment; - $testEnvironment->wpRootDir = FS::relativePath($this->workDir, $wpRootDir); - $testEnvironment->dbUrl = 'sqlite://%codecept_root_dir%/tests/_wordpress/data/db.sqlite'; - $testEnvironment->testTablePrefix = 'test_'; - $testEnvironment->wpTablePrefix = 'wp_'; - $testEnvironment->wpUrl = "http://localhost:$serverLocalhostPort"; - $testEnvironment->wpDomain = "localhost:$serverLocalhostPort"; - $testEnvironment->chromeDriverHost = 'localhost'; - $testEnvironment->chromeDriverPort = $chromedriverPort; - $testEnvironment->envFileContents = <<extensionsEnabled = [ - ChromeDriverController::class => [ - 'port' => "%CHROMEDRIVER_PORT%", - ], - BuiltInServerController::class => [ - 'workers' => 5, - 'port' => "%BUILTIN_SERVER_PORT%", - 'docroot' => FS::relativePath($this->workDir, $wpRootDir) - ] - - ]; - $testEnvironment->customCommands[] = DevStart::class; - $testEnvironment->customCommands[] = DevStop::class; - $testEnvironment->customCommands[] = DevInfo::class; - $testEnvironment->customCommands[] = DevRestart::class; - - $testEnvironment->afterSuccess = function () use ($basename, $activated): void { - if ($activated) { - $this->scaffoldEndToEndActivationCest(); - $this->scaffoldIntegrationActivationTest(); - } - $this->say('The plugin has been linked into the ' . - "tests/_wordpress/wp-content/plugins/$basename directory."); - $this->say("If your {$this->projectType} requires additional plugins and themes, place them in the " . - 'tests/_wordpress/wp-content/plugins and ' . - 'tests/_wordpress/wp-content/themes directories.'); - }; - - $this->testEnvironment = $testEnvironment; - } - - public function getTestEnv(): ?TestEnvironment - { - return $this->testEnvironment; - } - public function getName(): string { return $this->pluginName; @@ -223,38 +98,18 @@ public function getPluginFilePathName(): string return $this->pluginFile; } - private function getFreeLocalhostPort( - string $docRoot - ): int { - try { - $process = new Process(['php', '-S', 'localhost:0', '-t', $docRoot]); - $process->start(); - do { - if (!$process->isRunning() && $process->getExitCode() !== 0) { - throw new RuntimeException($process->getErrorOutput() ?: $process->getOutput()); - } - $output = $process->getErrorOutput(); - $port = preg_match('~localhost:(\d+)~', $output, $matches) ? $matches[1] : null; - } while ($port === null); - return (int)$port; - } catch (Exception $e) { - throw new RuntimeException( - 'Could not start PHP built-in server to find free localhost port: ' . $e->getMessage() - ); - } finally { - if (isset($process)) { - $process->stop(); - } - } - } - + /** + * @throws WorkerException + * @throws Throwable + * @throws ProcessException + */ protected function activate(string $wpRootDir, int $serverLocalhostPort): bool { $codeExec = new CodeExecutionFactory($wpRootDir, 'localhost:' . $serverLocalhostPort); $pluginString = basename(dirname($this->pluginFile)) . '/' . basename($this->pluginFile); $activatePlugin = $codeExec->toActivatePlugin($pluginString, false); $activationResult = Loop::executeClosure($activatePlugin)->getReturnValue(); - if ($activationResult instanceof \Throwable) { + if ($activationResult instanceof Throwable) { $message = $activationResult->getMessage(); $this->sayWarning('Could not activate plugin: ' . $message); $this->say('This might happen because the plugin has unmet dependencies; wp-browser configuration ' . @@ -268,7 +123,7 @@ protected function activate(string $wpRootDir, int $serverLocalhostPort): bool return true; } - private function scaffoldEndToEndActivationCest(): void + protected function scaffoldEndToEndActivationCest(): void { $cestCode = Strings::renderString( <<< EOT @@ -308,7 +163,7 @@ public function test_it_deactivates_activates_correctly(EndToEndTester \$I): voi } } - private function scaffoldIntegrationActivationTest(): void + protected function scaffoldIntegrationActivationTest(): void { $testCode = Strings::renderString( <<< EOT @@ -351,7 +206,7 @@ public function test_plugin_active(): void } EOT, [ - 'pluginString' => $this->getPluginsString() + 'pluginString' => $this->getActivationString() ] ); @@ -359,4 +214,9 @@ public function test_plugin_active(): void throw new RuntimeException('Could not write tests/Integration/SampleTest.php.'); } } + + protected function symlinkProjectInContentDir(string $wpRootDir): void + { + FS::symlink($this->workDir, $wpRootDir . "/wp-content/plugins/" . $this->pluginDir); + } } diff --git a/src/Project/ProjectInterface.php b/src/Project/ProjectInterface.php index ddf909e16..c64808888 100644 --- a/src/Project/ProjectInterface.php +++ b/src/Project/ProjectInterface.php @@ -8,5 +8,5 @@ public function getType(): string; public function getTestEnv(): ?TestEnvironment; - public function setup() : void; + public function setup(); } diff --git a/src/Project/SiteProject.php b/src/Project/SiteProject.php index 852c1b994..0db13ed2d 100644 --- a/src/Project/SiteProject.php +++ b/src/Project/SiteProject.php @@ -18,7 +18,7 @@ public function getType(): string return 'site'; } - public function setup(): void + public function setup() { // TODO: Implement setup() method. } diff --git a/src/Project/ThemeProject.php b/src/Project/ThemeProject.php index 6d672e6a0..5d25199fb 100644 --- a/src/Project/ThemeProject.php +++ b/src/Project/ThemeProject.php @@ -1,26 +1,42 @@ themeDir = basename($workDir); + $this->basename = basename($workDir); + $themeInfo = self::parseDir($workDir); + + if ($themeInfo === false) { + throw new InvalidArgumentException( + sprintf( + 'The directory "%s" does not seem to be a valid theme directory.', + $workDir + ), + self::ERR_INVALID_THEME_DIR + ); + } + + [$this->name] = $themeInfo; } public function getType(): string @@ -28,18 +44,159 @@ public function getType(): string return 'theme'; } - public function getThemeString(): string + public function getActivationString(): string + { + return $this->basename; + } + + protected function getProjectType(): string + { + return 'theme'; + } + + public function getName(): string + { + return $this->name; + } + + /** + * @return array{0: string}|false + * @throws RuntimeException + */ + public static function parseDir(string $workDir): array|false + { + if (!is_file($workDir . '/style.css')) { + return false; + } + + $styleCssContents = file_get_contents($workDir . '/style.css'); + + if (empty($styleCssContents)) { + return false; + } + + preg_match('/Theme Name:\\s(.*?)$/um', $styleCssContents, $matches); + + if (!isset($matches[1])) { + return false; + } + + $name = $matches[1]; + + return [$name]; + } + + protected function symlinkProjectInContentDir(string $wpRootDir): void { - return $this->themeDir; + FS::symlink($this->workDir, $wpRootDir . "/wp-content/themes/" . $this->basename); } - public function setup(): void + /** + * @throws WorkerException + * @throws Throwable + * @throws ProcessException + */ + protected function activate(string $wpRootDir, int $serverLocalhostPort): bool { - // TODO: Implement setup() method. + $codeExec = new CodeExecutionFactory($wpRootDir, 'localhost:' . $serverLocalhostPort); + $switchTheme = $codeExec->toSwitchTheme(Strings::slug($this->basename), false); + $activationResult = Loop::executeClosure($switchTheme)->getReturnValue(); + if ($activationResult instanceof Throwable) { + $message = $activationResult->getMessage(); + $this->sayWarning('Could not activate plugin: ' . $message); + $this->say('This might happen because the theme has unmet dependencies; wp-browser configuration ' . + 'will continue, but you will need to manually activate the theme and update the dump in ' . + 'tests/Support/Data/dump.sql.'); + return false; + } + + $this->sayInfo('Theme activated.'); + + return true; } - public function getTestEnv(): ?TestEnvironment + protected function scaffoldEndToEndActivationCest(): void { - return new TestEnvironment(); + $cestCode = Strings::renderString( + <<< EOT +loginAsAdmin(); + \$I->amOnAdminPage('/themes.php'); + + \$I->seeElement('.theme.active[data-slug="{{basename}}"]'); } } + +EOT, + [ + 'basename' => Strings::slug($this->basename) + ] + ); + + if (!file_put_contents($this->workDir . '/tests/EndToEnd/ActivationCest.php', $cestCode, LOCK_EX)) { + throw new RuntimeException('Could not write tests/EndToEnd/ActivationCest.php.'); + } + } + + protected function scaffoldIntegrationActivationTest(): void + { + $testCode = Strings::renderString( + <<< EOT +post->create_and_get(); + + \$this->assertInstanceOf(\WP_Post::class, \$post); + } + + public function test_theme_active(): void + { + \$this->assertTrue(wp_get_theme()->stylesheet === '{{stylesheet}}'); + } +} +EOT, + [ + 'stylesheet' => $this->getActivationString() + ] + ); + + if (!file_put_contents($this->workDir . '/tests/Integration/SampleTest.php', $testCode, LOCK_EX)) { + throw new RuntimeException('Could not write tests/Integration/SampleTest.php.'); + } + } + +} diff --git a/src/Template/Wpbrowser.php b/src/Template/Wpbrowser.php index 291dd8677..7e8d8c709 100644 --- a/src/Template/Wpbrowser.php +++ b/src/Template/Wpbrowser.php @@ -39,7 +39,6 @@ public function setup(): void $this->say('Initializing wp-browser for a ' . $project->getType() . ' project.'); $this->say('You can quit this process at any time with CTRL+C.'); - $this->say(''); $input = $this->input; $namespace = $input->hasOption('namespace') ? $input->getOption('namespace') : null; @@ -54,7 +53,6 @@ public function setup(): void $this->createDirs(); $this->sayInfo('Created tests directory and sub-directories.'); - $this->say(); try { $project->setup(); @@ -128,11 +126,11 @@ private function createIntegrationSuite(ProjectInterface $project): void { $plugins = ''; if ($project instanceof PluginProject) { - $plugins = $project->getPluginsString(); + $plugins = "'{$project->getActivationString()}'"; } $theme = ''; if ($project instanceof ThemeProject) { - $theme = $project->getThemeString(); + $theme = $project->getActivationString(); } $suiteConfig = <<createSuite('Integration', 'Integration', $suiteConfig); $bootstrapContents = <<input, $this->output, $workDir); } - if (PluginProject::findPluginNameAndFile($workDir)) { + if (PluginProject::parseDir($workDir)) { return new PluginProject($this->input, $this->output, $workDir); } diff --git a/tests/unit/Codeception/Template/WpbrowserTest.php b/tests/unit/Codeception/Template/WpbrowserTest.php index add77abd0..c8175c205 100644 --- a/tests/unit/Codeception/Template/WpbrowserTest.php +++ b/tests/unit/Codeception/Template/WpbrowserTest.php @@ -10,6 +10,40 @@ class WpbrowserTest extends \Codeception\Test\Unit use TmpFilesCleanup; use SnapshotAssertions; + private function mockComposerBin(string $directory): void + { + $binCode = <<< EOT +#!/bin/sh +touch composer.lock +mkdir -p ./vendor/bin +touch ./vendor/bin/chromedriver +EOT; + if (!file_put_contents($directory . '/composer', $binCode)) { + throw new \RuntimeException("Could not create mock composer binary in $directory."); + } + + if (!chmod($directory . '/composer', 0755)) { + throw new \RuntimeException("Could not make mock composer binary in $directory executable."); + } + } + + private function replaceRandomPorts(array $expected, array $actual, string $file): array + { + if (!str_ends_with($file, 'tests/.env')) { + return [$expected, $actual]; + } + + $expected = explode("\n", + preg_replace('/\\d{3,}$/um', '{port}', implode("\n", $expected)) + ); + + $actual = explode("\n", + preg_replace('/\\d{3,}$/um', '{port}', implode("\n", $actual)) + ); + + return [$expected, $actual]; + } + /** * It should scaffold for plugin with plugin.php file * @@ -33,12 +67,14 @@ public function should_scaffold_for_plugin_with_plugin_php_file(): void ] ]); + $this->mockComposerBin($projectDir . '/plugin_89'); + $command = [ PHP_BINARY, codecept_root_dir("vendor/bin/codecept"), 'init', 'wpbrowser', - '--path=' . Fs::relativePath(codecept_root_dir(), $projectDir . '/plugin_89'), + '--path=' . $projectDir . '/plugin_89' ]; $process = new Process($command); @@ -61,6 +97,7 @@ public function should_scaffold_for_plugin_with_plugin_php_file(): void FS::rrmdir($projectDir . '/plugin_89/vendor'); unlink($projectDir . '/plugin_89/composer.lock'); unlink($projectDir . '/plugin_89/tests/Support/Data/dump.sql'); + unlink($projectDir . '/plugin_89/composer'); // Random ports will change: visit the data to replace the random ports with a placeholder. $this->assertMatchesDirectorySnapshot($projectDir . '/plugin_89', @@ -90,12 +127,14 @@ public function should_scaffold_for_plugin_with_non_plugin_php_file(): void ] ]); + $this->mockComposerBin($projectDir . '/plugin_89'); + $command = [ PHP_BINARY, codecept_root_dir("vendor/bin/codecept"), 'init', 'wpbrowser', - '--path=' . Fs::relativePath(codecept_root_dir(), $projectDir . '/plugin_89'), + '--path=' . $projectDir . '/plugin_89' ]; $process = new Process($command, null); @@ -119,6 +158,7 @@ public function should_scaffold_for_plugin_with_non_plugin_php_file(): void FS::rrmdir($projectDir . '/plugin_89/var'); unlink($projectDir . '/plugin_89/composer.lock'); unlink($projectDir . '/plugin_89/tests/Support/Data/dump.sql'); + unlink($projectDir . '/plugin_89/composer'); // Random ports will change: visit the data to replace the random ports with a placeholder. $this->assertMatchesDirectorySnapshot($projectDir . '/plugin_89', @@ -153,7 +193,7 @@ public function should_scaffold_for_plugin_with_plugin_php_file_custom(): void codecept_root_dir("vendor/bin/codecept"), 'init', 'wpbrowser', - '--path=' . Fs::relativePath(codecept_root_dir(), $projectDir . '/plugin_89'), + '--path=' . $projectDir . '/plugin_89' ]; $process = new Process($command); @@ -199,7 +239,7 @@ public function should_scaffold_for_plugin_with_non_plugin_php_file_custom(): vo codecept_root_dir("vendor/bin/codecept"), 'init', 'wpbrowser', - '--path=' . Fs::relativePath(codecept_root_dir(), $projectDir . '/plugin_89'), + '--path=' . $projectDir . '/plugin_89' ]; $process = new Process($command); @@ -217,20 +257,180 @@ public function should_scaffold_for_plugin_with_non_plugin_php_file_custom(): vo fn() => $this->replaceRandomPorts(...func_get_args())); } - private function replaceRandomPorts(array $expected, array $actual, string $file): array + /** + * It should scaffold for theme correctly + * + * @test + */ + public function should_scaffold_for_theme_correctly(): void { - if (!str_ends_with($file, 'tests/.env')) { - return [$expected, $actual]; - } + $composerFileCode = <<< EOT +{ + "name": "acme/theme-23", + "type": "wordpress-theme", + "require": {}, + "require-dev": {} +} +EOT; - $expected = explode("\n", - preg_replace('/\\d{3,}$/um', '{port}', implode("\n", $expected)) + $projectDir = FS::tmpDir('project_factory_', [ + 'theme_23' => [ + 'style.css' => "/*\nTheme Name: Theme 23\n*/", + 'composer.json' => $composerFileCode + ] + ]); + + $this->mockComposerBin($projectDir . '/theme_23'); + + $command = [ + PHP_BINARY, + codecept_root_dir("vendor/bin/codecept"), + 'init', + 'wpbrowser', + '--path=' . $projectDir . '/theme_23' + ]; + $process = new Process($command); + + $process->setInput( + "yes\n" // Yes, use recommended setup. ); - $actual = explode("\n", - preg_replace('/\\d{3,}$/um', '{port}', implode("\n", $actual)) + $process->mustRun(); + + // Remove the generated files that are not needed for the snapshot. + FS::rrmdir($projectDir . '/theme_23/tests/Support/_generated'); + + $this->assertFileExists($projectDir . '/theme_23/vendor/bin/chromedriver'); + $this->assertFileExists($projectDir . '/theme_23/composer.lock'); + $this->assertFileExists($projectDir . '/theme_23/tests/_wordpress/wp-config.php'); + $this->assertFileExists($projectDir . '/theme_23/tests/Support/Data/dump.sql'); + + // Remove generated or downloaded files that are not needed for the snapshot. + FS::rrmdir($projectDir . '/theme_23/tests/_wordpress'); + FS::rrmdir($projectDir . '/theme_23/vendor'); + unlink($projectDir . '/theme_23/composer.lock'); + unlink($projectDir . '/theme_23/tests/Support/Data/dump.sql'); + unlink($projectDir . '/theme_23/composer'); + + // Random ports will change: visit the data to replace the random ports with a placeholder. + $this->assertMatchesDirectorySnapshot($projectDir . '/theme_23', + fn() => $this->replaceRandomPorts(...func_get_args())); + } + + /** + * It should scaffold for child theme correctly + * + * @test + */ + public function should_scaffold_for_child_theme_correctly(): void + { + $composerFileCode = <<< EOT +{ + "name": "acme/theme-23", + "type": "wordpress-theme", + "require": {}, + "require-dev": {} +} +EOT; + + $projectDir = FS::tmpDir('project_factory_', [ + 'theme_23' => [ + 'style.css' => <<< EOT +/* +Theme Name: Theme 23 +Template: twentytwenty +*/ +EOT , + 'composer.json' => $composerFileCode + ] + ]); + + $this->mockComposerBin($projectDir . '/theme_23'); + + $command = [ + PHP_BINARY, + codecept_root_dir("vendor/bin/codecept"), + 'init', + 'wpbrowser', + '--path=' . $projectDir . '/theme_23' + ]; + $process = new Process($command); + + $process->setInput( + "yes\n" // Yes, use recommended setup. ); - return [$expected, $actual]; + $process->mustRun(); + + // Remove the generated files that are not needed for the snapshot. + FS::rrmdir($projectDir . '/theme_23/tests/Support/_generated'); + + $this->assertFileExists($projectDir . '/theme_23/vendor/bin/chromedriver'); + $this->assertFileExists($projectDir . '/theme_23/composer.lock'); + $this->assertFileExists($projectDir . '/theme_23/tests/_wordpress/wp-config.php'); + $this->assertFileExists($projectDir . '/theme_23/tests/Support/Data/dump.sql'); + + // Remove generated or downloaded files that are not needed for the snapshot. + FS::rrmdir($projectDir . '/theme_23/tests/_wordpress'); + FS::rrmdir($projectDir . '/theme_23/vendor'); + unlink($projectDir . '/theme_23/composer.lock'); + unlink($projectDir . '/theme_23/tests/Support/Data/dump.sql'); + unlink($projectDir . '/theme_23/composer'); + + // Random ports will change: visit the data to replace the random ports with a placeholder. + $this->assertMatchesDirectorySnapshot($projectDir . '/theme_23', + fn() => $this->replaceRandomPorts(...func_get_args())); + } + + /** + * It should scaffold for theme custom correctly + * + * @test + */ + public function should_scaffold_for_theme_custom_correctly(): void + { + $composerFileCode = <<< EOT +{ + "name": "acme/theme-23", + "type": "wordpress-theme", + "require": {}, + "require-dev": {} +} +EOT; + + $projectDir = FS::tmpDir('project_factory_', [ + 'theme_23' => [ + 'style.css' => <<< EOT +/* +Theme Name: Theme 23 +*/ +EOT , + 'composer.json' => $composerFileCode + ] + ]); + + $this->mockComposerBin($projectDir . '/theme_23'); + + $command = [ + PHP_BINARY, + codecept_root_dir("vendor/bin/codecept"), + 'init', + 'wpbrowser', + '--path=' . $projectDir . '/theme_23' + ]; + $process = new Process($command); + + $process->setInput( + "no\n" // No, do not use recommended setup. + ); + + $process->mustRun(); + + // Remove the generated files that are not needed for the snapshot. + FS::rrmdir($projectDir . '/theme_23/tests/Support/_generated'); + + // Random ports will change: visit the data to replace the random ports with a placeholder. + $this->assertMatchesDirectorySnapshot($projectDir . '/theme_23', + fn() => $this->replaceRandomPorts(...func_get_args())); } } diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_child_theme_correctly__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_child_theme_correctly__0.snapshot new file mode 100644 index 000000000..f06bfac92 --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_child_theme_correctly__0.snapshot @@ -0,0 +1,272 @@ +>>> /tests/EndToEnd.suite.yml >>> +# Integration suite configuration +# +# Run integration and "WordPress unit" tests. + +actor: EndToEndTester +bootstrap: _bootstrap.php +modules: + enabled: + - lucatume\WPBrowser\Module\WPWebDriver + - lucatume\WPBrowser\Module\WPDb + - lucatume\WPBrowser\Module\WPFilesystem + - lucatume\WPBrowser\Module\WPLoader + config: + lucatume\WPBrowser\Module\WPWebDriver: + url: '%WORDPRESS_URL%' + adminUsername: '%WORDPRESS_ADMIN_USER%' + adminPassword: '%WORDPRESS_ADMIN_PASSWORD%' + adminPath: '/wp-admin' + browser: chrome + host: '%CHROMEDRIVER_HOST%' + port: '%CHROMEDRIVER_PORT%' + window_size: 1200x1000 + capabilities: + chromeOptions: + args: ["--disable-gpu", "--proxy-server='direct://'", "--proxy-bypass-list=*"] + lucatume\WPBrowser\Module\WPDb: + dbUrl: '%WORDPRESS_DB_URL%' + dump: 'tests/Support/Data/dump.sql' + populate: true + cleanup: true + reconnect: false + url: '%WORDPRESS_URL%' + urlReplacement: false + tablePrefix: '%WORDPRESS_TABLE_PREFIX%' + lucatume\WPBrowser\Module\WPFilesystem: + wpRootFolder: '%WORDPRESS_ROOT_DIR%' + lucatume\WPBrowser\Module\WPLoader: + loadOnly: true + wpRootFolder: "%WORDPRESS_ROOT_DIR%" + dbUrl: '%WORDPRESS_DB_URL%' + domain: '%WORDPRESS_DOMAIN%' + +<<< /tests/EndToEnd.suite.yml <<< + +>>> /tests/Integration/_bootstrap.php >>> +>> /tests/Integration.suite.yml >>> +# Integration suite configuration +# +# Run integration and "WordPress unit" tests. + +actor: IntegrationTester +bootstrap: _bootstrap.php +modules: + enabled: + - lucatume\WPBrowser\Module\WPLoader + config: + lucatume\WPBrowser\Module\WPLoader: + wpRootFolder: "%WORDPRESS_ROOT_DIR%" + dbUrl: '%WORDPRESS_DB_URL%' + wpDebug: true + tablePrefix: '%TEST_TABLE_PREFIX%' + domain: '%WORDPRESS_DOMAIN%' + adminEmail: 'admin@%WORDPRESS_DOMAIN%' + title: 'Integration Tests' + plugins: [] + theme: 'theme_23' +<<< /tests/Integration.suite.yml <<< + +>>> /tests/Support/IntegrationTester.php >>> +>> /tests/Support/EndToEndTester.php >>> +>> /tests/Support/Data/.gitkeep >>> + +<<< /tests/Support/Data/.gitkeep <<< + +>>> /tests/EndToEnd/_bootstrap.php >>> +` command + * to run WP-CLI commands on the WordPress site and database used by the EndToEnd suite. + * E.g.: + * `vendor/bin/codecept wp:cli EndToEnd db import tests/Support/Data/dump.sql` to load dump file. + * `vendor/bin/codecept wp:cli EndToEnd plugin activate woocommerce` to activate the WooCommerce plugin. + * `vendor/bin/codecept wp:cli EndToEnd user create alice alice@example.com --role=administrator` to create a new user. + * `vendor/bin/codecept wp:cli EndToEnd db export tests/Support/Data/dump.sql` to update the dump file. + */ +<<< /tests/EndToEnd/_bootstrap.php <<< + +>>> /tests/.env >>> +# The path to the WordPress root directory, the one containing the wp-load.php file. +# This can be a relative path from the directory that contains the codeception.yml file, +# or an absolute path. +WORDPRESS_ROOT_DIR=tests/_wordpress + +# Tests will require a MySQL database to run. +# The database will be created if it does not exist. +# Do not use a database that contains important data! +WORDPRESS_DB_URL=sqlite://%codecept_root_dir%/tests/_wordpress/data/db.sqlite + +# The Integration suite will use this table prefix for the WordPress tables. +TEST_TABLE_PREFIX=test_ + +# This table prefix used by the WordPress site in end-to-end tests. +WORDPRESS_TABLE_PREFIX=wp_ + +# The URL and domain of the WordPress site used in end-to-end tests. +WORDPRESS_URL=http://localhost:57503 +WORDPRESS_DOMAIN=localhost:57503 + +# The username and password of the administrator user of the WordPress site used in end-to-end tests. +WORDPRESS_ADMIN_USER=admin +WORDPRESS_ADMIN_PASSWORD=password + +# The host and port of the ChromeDriver server that will be used in end-to-end tests. +CHROMEDRIVER_HOST=localhost +CHROMEDRIVER_PORT=57509 + +# The port on which the PHP built-in server will serve the WordPress installation. +BUILTIN_SERVER_PORT=57503 +<<< /tests/.env <<< + +>>> /tests/_output/.gitignore >>> +* +!.gitignore + +<<< /tests/_output/.gitignore <<< + +>>> /codeception.yml >>> +namespace: Tests +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/Support/Data + support: tests/Support + envs: tests/_envs +actor_suffix: Tester +params: + - tests/.env +extensions: + enabled: + - Codeception\Extension\RunFailed + - lucatume\WPBrowser\Extension\ChromeDriverController + - lucatume\WPBrowser\Extension\BuiltInServerController + config: + lucatume\WPBrowser\Extension\ChromeDriverController: + port: '%CHROMEDRIVER_PORT%' + lucatume\WPBrowser\Extension\BuiltInServerController: + workers: 5 + port: '%BUILTIN_SERVER_PORT%' + docroot: tests/_wordpress + commands: + - lucatume\WPBrowser\Command\RunOriginal + - lucatume\WPBrowser\Command\RunAll + - lucatume\WPBrowser\Command\GenerateWPUnit + - lucatume\WPBrowser\Command\DbExport + - lucatume\WPBrowser\Command\DbImport + - lucatume\WPBrowser\Command\DevStart + - lucatume\WPBrowser\Command\DevStop + - lucatume\WPBrowser\Command\DevInfo + - lucatume\WPBrowser\Command\DevRestart + +<<< /codeception.yml <<< + +>>> /style.css >>> +/* +Theme Name: Theme 23 +Template: twentytwenty +*/ +<<< /style.css <<< + +>>> /composer.json >>> +{ + "name": "acme/theme-23", + "type": "wordpress-theme", + "require": {}, + "require-dev": { + "webdriver-binary/binary-chromedriver": "*" + }, + "config": { + "allow-plugins": { + "webdriver-binary/binary-chromedriver": true + } + } +} +<<< /composer.json <<< \ No newline at end of file diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_non_plugin_php_file__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_non_plugin_php_file__0.snapshot index 0287c103c..3571ffaed 100644 --- a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_non_plugin_php_file__0.snapshot +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_non_plugin_php_file__0.snapshot @@ -1,3 +1,103 @@ +>>> /tests/EndToEnd.suite.yml >>> +# Integration suite configuration +# +# Run integration and "WordPress unit" tests. + +actor: EndToEndTester +bootstrap: _bootstrap.php +modules: + enabled: + - lucatume\WPBrowser\Module\WPWebDriver + - lucatume\WPBrowser\Module\WPDb + - lucatume\WPBrowser\Module\WPFilesystem + - lucatume\WPBrowser\Module\WPLoader + config: + lucatume\WPBrowser\Module\WPWebDriver: + url: '%WORDPRESS_URL%' + adminUsername: '%WORDPRESS_ADMIN_USER%' + adminPassword: '%WORDPRESS_ADMIN_PASSWORD%' + adminPath: '/wp-admin' + browser: chrome + host: '%CHROMEDRIVER_HOST%' + port: '%CHROMEDRIVER_PORT%' + window_size: 1200x1000 + capabilities: + chromeOptions: + args: ["--disable-gpu", "--proxy-server='direct://'", "--proxy-bypass-list=*"] + lucatume\WPBrowser\Module\WPDb: + dbUrl: '%WORDPRESS_DB_URL%' + dump: 'tests/Support/Data/dump.sql' + populate: true + cleanup: true + reconnect: false + url: '%WORDPRESS_URL%' + urlReplacement: false + tablePrefix: '%WORDPRESS_TABLE_PREFIX%' + lucatume\WPBrowser\Module\WPFilesystem: + wpRootFolder: '%WORDPRESS_ROOT_DIR%' + lucatume\WPBrowser\Module\WPLoader: + loadOnly: true + wpRootFolder: "%WORDPRESS_ROOT_DIR%" + dbUrl: '%WORDPRESS_DB_URL%' + domain: '%WORDPRESS_DOMAIN%' + +<<< /tests/EndToEnd.suite.yml <<< + +>>> /tests/Integration/SampleTest.php >>> +post->create_and_get(); + + $this->assertInstanceOf(\WP_Post::class, $post); + } + + public function test_plugin_active(): void + { + $this->assertTrue(is_plugin_active('plugin_89/main-file.php')); + } +} +<<< /tests/Integration/SampleTest.php <<< + +>>> /tests/Integration/_bootstrap.php >>> +>> /tests/Integration.suite.yml >>> # Integration suite configuration # @@ -18,7 +118,7 @@ modules: adminEmail: 'admin@%WORDPRESS_DOMAIN%' title: 'Integration Tests' plugins: ['plugin_89/main-file.php'] - theme: '' + theme: '' <<< /tests/Integration.suite.yml <<< >>> /tests/Support/IntegrationTester.php >>> @@ -54,10 +154,92 @@ class IntegrationTester extends \Codeception\Actor <<< /tests/Support/IntegrationTester.php <<< +>>> /tests/Support/EndToEndTester.php >>> +>> /tests/Support/Data/.gitkeep >>> <<< /tests/Support/Data/.gitkeep <<< +>>> /tests/EndToEnd/_bootstrap.php >>> +` command + * to run WP-CLI commands on the WordPress site and database used by the EndToEnd suite. + * E.g.: + * `vendor/bin/codecept wp:cli EndToEnd db import tests/Support/Data/dump.sql` to load dump file. + * `vendor/bin/codecept wp:cli EndToEnd plugin activate woocommerce` to activate the WooCommerce plugin. + * `vendor/bin/codecept wp:cli EndToEnd user create alice alice@example.com --role=administrator` to create a new user. + * `vendor/bin/codecept wp:cli EndToEnd db export tests/Support/Data/dump.sql` to update the dump file. + */ +<<< /tests/EndToEnd/_bootstrap.php <<< + +>>> /tests/EndToEnd/ActivationCest.php >>> +loginAsAdmin(); + $I->amOnPluginsPage(); + + $I->seePluginActivated('plugin-89'); + + $I->deactivatePlugin('plugin-89'); + + $I->seePluginDeactivated('plugin-89'); + + $I->activatePlugin('plugin-89'); + + $I->seePluginActivated('plugin-89'); + } +} + +<<< /tests/EndToEnd/ActivationCest.php <<< + >>> /tests/.env >>> # The path to the WordPress root directory, the one containing the wp-load.php file. # This can be a relative path from the directory that contains the codeception.yml file, @@ -76,8 +258,8 @@ TEST_TABLE_PREFIX=test_ WORDPRESS_TABLE_PREFIX=wp_ # The URL and domain of the WordPress site used in end-to-end tests. -WORDPRESS_URL=http://localhost:59473 -WORDPRESS_DOMAIN=localhost:59473 +WORDPRESS_URL=http://localhost:57807 +WORDPRESS_DOMAIN=localhost:57807 # The username and password of the administrator user of the WordPress site used in end-to-end tests. WORDPRESS_ADMIN_USER=admin @@ -85,10 +267,10 @@ WORDPRESS_ADMIN_PASSWORD=password # The host and port of the ChromeDriver server that will be used in end-to-end tests. CHROMEDRIVER_HOST=localhost -CHROMEDRIVER_PORT=59500 +CHROMEDRIVER_PORT=57816 # The port on which the PHP built-in server will serve the WordPress installation. -BUILTIN_SERVER_PORT=59473 +BUILTIN_SERVER_PORT=57807 <<< /tests/.env <<< >>> /tests/_output/.gitignore >>> diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_non_plugin_php_file_custom__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_non_plugin_php_file_custom__0.snapshot index ae4ce678f..73c343ac5 100644 --- a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_non_plugin_php_file_custom__0.snapshot +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_non_plugin_php_file_custom__0.snapshot @@ -3,6 +3,66 @@ /* Plugin Name: Plugin 89 */ <<< /main.php <<< +>>> /tests/EndToEnd.suite.yml >>> +# Integration suite configuration +# +# Run integration and "WordPress unit" tests. + +actor: EndToEndTester +bootstrap: _bootstrap.php +modules: + enabled: + - lucatume\WPBrowser\Module\WPWebDriver + - lucatume\WPBrowser\Module\WPDb + - lucatume\WPBrowser\Module\WPFilesystem + - lucatume\WPBrowser\Module\WPLoader + config: + lucatume\WPBrowser\Module\WPWebDriver: + url: '%WORDPRESS_URL%' + adminUsername: '%WORDPRESS_ADMIN_USER%' + adminPassword: '%WORDPRESS_ADMIN_PASSWORD%' + adminPath: '/wp-admin' + browser: chrome + host: '%CHROMEDRIVER_HOST%' + port: '%CHROMEDRIVER_PORT%' + window_size: 1200x1000 + capabilities: + chromeOptions: + args: ["--disable-gpu", "--proxy-server='direct://'", "--proxy-bypass-list=*"] + lucatume\WPBrowser\Module\WPDb: + dbUrl: '%WORDPRESS_DB_URL%' + dump: 'tests/Support/Data/dump.sql' + populate: true + cleanup: true + reconnect: false + url: '%WORDPRESS_URL%' + urlReplacement: false + tablePrefix: '%WORDPRESS_TABLE_PREFIX%' + lucatume\WPBrowser\Module\WPFilesystem: + wpRootFolder: '%WORDPRESS_ROOT_DIR%' + lucatume\WPBrowser\Module\WPLoader: + loadOnly: true + wpRootFolder: "%WORDPRESS_ROOT_DIR%" + dbUrl: '%WORDPRESS_DB_URL%' + domain: '%WORDPRESS_DOMAIN%' + +<<< /tests/EndToEnd.suite.yml <<< + +>>> /tests/Integration/_bootstrap.php >>> +>> /tests/Integration.suite.yml >>> # Integration suite configuration # @@ -23,7 +83,7 @@ modules: adminEmail: 'admin@%WORDPRESS_DOMAIN%' title: 'Integration Tests' plugins: ['plugin_89/main.php'] - theme: '' + theme: '' <<< /tests/Integration.suite.yml <<< >>> /tests/Support/IntegrationTester.php >>> @@ -59,10 +119,64 @@ class IntegrationTester extends \Codeception\Actor <<< /tests/Support/IntegrationTester.php <<< +>>> /tests/Support/EndToEndTester.php >>> +>> /tests/Support/Data/.gitkeep >>> <<< /tests/Support/Data/.gitkeep <<< +>>> /tests/EndToEnd/_bootstrap.php >>> +` command + * to run WP-CLI commands on the WordPress site and database used by the EndToEnd suite. + * E.g.: + * `vendor/bin/codecept wp:cli EndToEnd db import tests/Support/Data/dump.sql` to load dump file. + * `vendor/bin/codecept wp:cli EndToEnd plugin activate woocommerce` to activate the WooCommerce plugin. + * `vendor/bin/codecept wp:cli EndToEnd user create alice alice@example.com --role=administrator` to create a new user. + * `vendor/bin/codecept wp:cli EndToEnd db export tests/Support/Data/dump.sql` to update the dump file. + */ +<<< /tests/EndToEnd/_bootstrap.php <<< + >>> /tests/.env >>> # The path to the WordPress root directory, the one containing the wp-load.php file. # This can be a relative path from the directory that contains the codeception.yml file, diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_plugin_php_file__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_plugin_php_file__0.snapshot index d0c7c04a8..388e3f96f 100644 --- a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_plugin_php_file__0.snapshot +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_plugin_php_file__0.snapshot @@ -3,6 +3,106 @@ /* Plugin Name: Plugin 89 */ <<< /plugin.php <<< +>>> /tests/EndToEnd.suite.yml >>> +# Integration suite configuration +# +# Run integration and "WordPress unit" tests. + +actor: EndToEndTester +bootstrap: _bootstrap.php +modules: + enabled: + - lucatume\WPBrowser\Module\WPWebDriver + - lucatume\WPBrowser\Module\WPDb + - lucatume\WPBrowser\Module\WPFilesystem + - lucatume\WPBrowser\Module\WPLoader + config: + lucatume\WPBrowser\Module\WPWebDriver: + url: '%WORDPRESS_URL%' + adminUsername: '%WORDPRESS_ADMIN_USER%' + adminPassword: '%WORDPRESS_ADMIN_PASSWORD%' + adminPath: '/wp-admin' + browser: chrome + host: '%CHROMEDRIVER_HOST%' + port: '%CHROMEDRIVER_PORT%' + window_size: 1200x1000 + capabilities: + chromeOptions: + args: ["--disable-gpu", "--proxy-server='direct://'", "--proxy-bypass-list=*"] + lucatume\WPBrowser\Module\WPDb: + dbUrl: '%WORDPRESS_DB_URL%' + dump: 'tests/Support/Data/dump.sql' + populate: true + cleanup: true + reconnect: false + url: '%WORDPRESS_URL%' + urlReplacement: false + tablePrefix: '%WORDPRESS_TABLE_PREFIX%' + lucatume\WPBrowser\Module\WPFilesystem: + wpRootFolder: '%WORDPRESS_ROOT_DIR%' + lucatume\WPBrowser\Module\WPLoader: + loadOnly: true + wpRootFolder: "%WORDPRESS_ROOT_DIR%" + dbUrl: '%WORDPRESS_DB_URL%' + domain: '%WORDPRESS_DOMAIN%' + +<<< /tests/EndToEnd.suite.yml <<< + +>>> /tests/Integration/SampleTest.php >>> +post->create_and_get(); + + $this->assertInstanceOf(\WP_Post::class, $post); + } + + public function test_plugin_active(): void + { + $this->assertTrue(is_plugin_active('plugin_89/plugin.php')); + } +} +<<< /tests/Integration/SampleTest.php <<< + +>>> /tests/Integration/_bootstrap.php >>> +>> /tests/Integration.suite.yml >>> # Integration suite configuration # @@ -23,7 +123,7 @@ modules: adminEmail: 'admin@%WORDPRESS_DOMAIN%' title: 'Integration Tests' plugins: ['plugin_89/plugin.php'] - theme: '' + theme: '' <<< /tests/Integration.suite.yml <<< >>> /tests/Support/IntegrationTester.php >>> @@ -59,10 +159,92 @@ class IntegrationTester extends \Codeception\Actor <<< /tests/Support/IntegrationTester.php <<< +>>> /tests/Support/EndToEndTester.php >>> +>> /tests/Support/Data/.gitkeep >>> <<< /tests/Support/Data/.gitkeep <<< +>>> /tests/EndToEnd/_bootstrap.php >>> +` command + * to run WP-CLI commands on the WordPress site and database used by the EndToEnd suite. + * E.g.: + * `vendor/bin/codecept wp:cli EndToEnd db import tests/Support/Data/dump.sql` to load dump file. + * `vendor/bin/codecept wp:cli EndToEnd plugin activate woocommerce` to activate the WooCommerce plugin. + * `vendor/bin/codecept wp:cli EndToEnd user create alice alice@example.com --role=administrator` to create a new user. + * `vendor/bin/codecept wp:cli EndToEnd db export tests/Support/Data/dump.sql` to update the dump file. + */ +<<< /tests/EndToEnd/_bootstrap.php <<< + +>>> /tests/EndToEnd/ActivationCest.php >>> +loginAsAdmin(); + $I->amOnPluginsPage(); + + $I->seePluginActivated('plugin-89'); + + $I->deactivatePlugin('plugin-89'); + + $I->seePluginDeactivated('plugin-89'); + + $I->activatePlugin('plugin-89'); + + $I->seePluginActivated('plugin-89'); + } +} + +<<< /tests/EndToEnd/ActivationCest.php <<< + >>> /tests/.env >>> # The path to the WordPress root directory, the one containing the wp-load.php file. # This can be a relative path from the directory that contains the codeception.yml file, @@ -81,8 +263,8 @@ TEST_TABLE_PREFIX=test_ WORDPRESS_TABLE_PREFIX=wp_ # The URL and domain of the WordPress site used in end-to-end tests. -WORDPRESS_URL=http://localhost:58995 -WORDPRESS_DOMAIN=localhost:58995 +WORDPRESS_URL=http://localhost:57775 +WORDPRESS_DOMAIN=localhost:57775 # The username and password of the administrator user of the WordPress site used in end-to-end tests. WORDPRESS_ADMIN_USER=admin @@ -90,10 +272,10 @@ WORDPRESS_ADMIN_PASSWORD=password # The host and port of the ChromeDriver server that will be used in end-to-end tests. CHROMEDRIVER_HOST=localhost -CHROMEDRIVER_PORT=59024 +CHROMEDRIVER_PORT=57784 # The port on which the PHP built-in server will serve the WordPress installation. -BUILTIN_SERVER_PORT=58995 +BUILTIN_SERVER_PORT=57775 <<< /tests/.env <<< >>> /tests/_output/.gitignore >>> diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_plugin_php_file_custom__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_plugin_php_file_custom__0.snapshot index b3644fb21..cd2d53bcc 100644 --- a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_plugin_php_file_custom__0.snapshot +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_plugin_with_plugin_php_file_custom__0.snapshot @@ -3,6 +3,66 @@ /* Plugin Name: Plugin 89 */ <<< /plugin.php <<< +>>> /tests/EndToEnd.suite.yml >>> +# Integration suite configuration +# +# Run integration and "WordPress unit" tests. + +actor: EndToEndTester +bootstrap: _bootstrap.php +modules: + enabled: + - lucatume\WPBrowser\Module\WPWebDriver + - lucatume\WPBrowser\Module\WPDb + - lucatume\WPBrowser\Module\WPFilesystem + - lucatume\WPBrowser\Module\WPLoader + config: + lucatume\WPBrowser\Module\WPWebDriver: + url: '%WORDPRESS_URL%' + adminUsername: '%WORDPRESS_ADMIN_USER%' + adminPassword: '%WORDPRESS_ADMIN_PASSWORD%' + adminPath: '/wp-admin' + browser: chrome + host: '%CHROMEDRIVER_HOST%' + port: '%CHROMEDRIVER_PORT%' + window_size: 1200x1000 + capabilities: + chromeOptions: + args: ["--disable-gpu", "--proxy-server='direct://'", "--proxy-bypass-list=*"] + lucatume\WPBrowser\Module\WPDb: + dbUrl: '%WORDPRESS_DB_URL%' + dump: 'tests/Support/Data/dump.sql' + populate: true + cleanup: true + reconnect: false + url: '%WORDPRESS_URL%' + urlReplacement: false + tablePrefix: '%WORDPRESS_TABLE_PREFIX%' + lucatume\WPBrowser\Module\WPFilesystem: + wpRootFolder: '%WORDPRESS_ROOT_DIR%' + lucatume\WPBrowser\Module\WPLoader: + loadOnly: true + wpRootFolder: "%WORDPRESS_ROOT_DIR%" + dbUrl: '%WORDPRESS_DB_URL%' + domain: '%WORDPRESS_DOMAIN%' + +<<< /tests/EndToEnd.suite.yml <<< + +>>> /tests/Integration/_bootstrap.php >>> +>> /tests/Integration.suite.yml >>> # Integration suite configuration # @@ -23,7 +83,7 @@ modules: adminEmail: 'admin@%WORDPRESS_DOMAIN%' title: 'Integration Tests' plugins: ['plugin_89/plugin.php'] - theme: '' + theme: '' <<< /tests/Integration.suite.yml <<< >>> /tests/Support/IntegrationTester.php >>> @@ -59,10 +119,64 @@ class IntegrationTester extends \Codeception\Actor <<< /tests/Support/IntegrationTester.php <<< +>>> /tests/Support/EndToEndTester.php >>> +>> /tests/Support/Data/.gitkeep >>> <<< /tests/Support/Data/.gitkeep <<< +>>> /tests/EndToEnd/_bootstrap.php >>> +` command + * to run WP-CLI commands on the WordPress site and database used by the EndToEnd suite. + * E.g.: + * `vendor/bin/codecept wp:cli EndToEnd db import tests/Support/Data/dump.sql` to load dump file. + * `vendor/bin/codecept wp:cli EndToEnd plugin activate woocommerce` to activate the WooCommerce plugin. + * `vendor/bin/codecept wp:cli EndToEnd user create alice alice@example.com --role=administrator` to create a new user. + * `vendor/bin/codecept wp:cli EndToEnd db export tests/Support/Data/dump.sql` to update the dump file. + */ +<<< /tests/EndToEnd/_bootstrap.php <<< + >>> /tests/.env >>> # The path to the WordPress root directory, the one containing the wp-load.php file. # This can be a relative path from the directory that contains the codeception.yml file, diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_theme_correctly__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_theme_correctly__0.snapshot new file mode 100644 index 000000000..02330edde --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_theme_correctly__0.snapshot @@ -0,0 +1,271 @@ +>>> /tests/EndToEnd.suite.yml >>> +# Integration suite configuration +# +# Run integration and "WordPress unit" tests. + +actor: EndToEndTester +bootstrap: _bootstrap.php +modules: + enabled: + - lucatume\WPBrowser\Module\WPWebDriver + - lucatume\WPBrowser\Module\WPDb + - lucatume\WPBrowser\Module\WPFilesystem + - lucatume\WPBrowser\Module\WPLoader + config: + lucatume\WPBrowser\Module\WPWebDriver: + url: '%WORDPRESS_URL%' + adminUsername: '%WORDPRESS_ADMIN_USER%' + adminPassword: '%WORDPRESS_ADMIN_PASSWORD%' + adminPath: '/wp-admin' + browser: chrome + host: '%CHROMEDRIVER_HOST%' + port: '%CHROMEDRIVER_PORT%' + window_size: 1200x1000 + capabilities: + chromeOptions: + args: ["--disable-gpu", "--proxy-server='direct://'", "--proxy-bypass-list=*"] + lucatume\WPBrowser\Module\WPDb: + dbUrl: '%WORDPRESS_DB_URL%' + dump: 'tests/Support/Data/dump.sql' + populate: true + cleanup: true + reconnect: false + url: '%WORDPRESS_URL%' + urlReplacement: false + tablePrefix: '%WORDPRESS_TABLE_PREFIX%' + lucatume\WPBrowser\Module\WPFilesystem: + wpRootFolder: '%WORDPRESS_ROOT_DIR%' + lucatume\WPBrowser\Module\WPLoader: + loadOnly: true + wpRootFolder: "%WORDPRESS_ROOT_DIR%" + dbUrl: '%WORDPRESS_DB_URL%' + domain: '%WORDPRESS_DOMAIN%' + +<<< /tests/EndToEnd.suite.yml <<< + +>>> /tests/Integration/_bootstrap.php >>> +>> /tests/Integration.suite.yml >>> +# Integration suite configuration +# +# Run integration and "WordPress unit" tests. + +actor: IntegrationTester +bootstrap: _bootstrap.php +modules: + enabled: + - lucatume\WPBrowser\Module\WPLoader + config: + lucatume\WPBrowser\Module\WPLoader: + wpRootFolder: "%WORDPRESS_ROOT_DIR%" + dbUrl: '%WORDPRESS_DB_URL%' + wpDebug: true + tablePrefix: '%TEST_TABLE_PREFIX%' + domain: '%WORDPRESS_DOMAIN%' + adminEmail: 'admin@%WORDPRESS_DOMAIN%' + title: 'Integration Tests' + plugins: [] + theme: 'theme_23' +<<< /tests/Integration.suite.yml <<< + +>>> /tests/Support/IntegrationTester.php >>> +>> /tests/Support/EndToEndTester.php >>> +>> /tests/Support/Data/.gitkeep >>> + +<<< /tests/Support/Data/.gitkeep <<< + +>>> /tests/EndToEnd/_bootstrap.php >>> +` command + * to run WP-CLI commands on the WordPress site and database used by the EndToEnd suite. + * E.g.: + * `vendor/bin/codecept wp:cli EndToEnd db import tests/Support/Data/dump.sql` to load dump file. + * `vendor/bin/codecept wp:cli EndToEnd plugin activate woocommerce` to activate the WooCommerce plugin. + * `vendor/bin/codecept wp:cli EndToEnd user create alice alice@example.com --role=administrator` to create a new user. + * `vendor/bin/codecept wp:cli EndToEnd db export tests/Support/Data/dump.sql` to update the dump file. + */ +<<< /tests/EndToEnd/_bootstrap.php <<< + +>>> /tests/.env >>> +# The path to the WordPress root directory, the one containing the wp-load.php file. +# This can be a relative path from the directory that contains the codeception.yml file, +# or an absolute path. +WORDPRESS_ROOT_DIR=tests/_wordpress + +# Tests will require a MySQL database to run. +# The database will be created if it does not exist. +# Do not use a database that contains important data! +WORDPRESS_DB_URL=sqlite://%codecept_root_dir%/tests/_wordpress/data/db.sqlite + +# The Integration suite will use this table prefix for the WordPress tables. +TEST_TABLE_PREFIX=test_ + +# This table prefix used by the WordPress site in end-to-end tests. +WORDPRESS_TABLE_PREFIX=wp_ + +# The URL and domain of the WordPress site used in end-to-end tests. +WORDPRESS_URL=http://localhost:57469 +WORDPRESS_DOMAIN=localhost:57469 + +# The username and password of the administrator user of the WordPress site used in end-to-end tests. +WORDPRESS_ADMIN_USER=admin +WORDPRESS_ADMIN_PASSWORD=password + +# The host and port of the ChromeDriver server that will be used in end-to-end tests. +CHROMEDRIVER_HOST=localhost +CHROMEDRIVER_PORT=57478 + +# The port on which the PHP built-in server will serve the WordPress installation. +BUILTIN_SERVER_PORT=57469 +<<< /tests/.env <<< + +>>> /tests/_output/.gitignore >>> +* +!.gitignore + +<<< /tests/_output/.gitignore <<< + +>>> /codeception.yml >>> +namespace: Tests +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/Support/Data + support: tests/Support + envs: tests/_envs +actor_suffix: Tester +params: + - tests/.env +extensions: + enabled: + - Codeception\Extension\RunFailed + - lucatume\WPBrowser\Extension\ChromeDriverController + - lucatume\WPBrowser\Extension\BuiltInServerController + config: + lucatume\WPBrowser\Extension\ChromeDriverController: + port: '%CHROMEDRIVER_PORT%' + lucatume\WPBrowser\Extension\BuiltInServerController: + workers: 5 + port: '%BUILTIN_SERVER_PORT%' + docroot: tests/_wordpress + commands: + - lucatume\WPBrowser\Command\RunOriginal + - lucatume\WPBrowser\Command\RunAll + - lucatume\WPBrowser\Command\GenerateWPUnit + - lucatume\WPBrowser\Command\DbExport + - lucatume\WPBrowser\Command\DbImport + - lucatume\WPBrowser\Command\DevStart + - lucatume\WPBrowser\Command\DevStop + - lucatume\WPBrowser\Command\DevInfo + - lucatume\WPBrowser\Command\DevRestart + +<<< /codeception.yml <<< + +>>> /style.css >>> +/* +Theme Name: Theme 23 +*/ +<<< /style.css <<< + +>>> /composer.json >>> +{ + "name": "acme/theme-23", + "type": "wordpress-theme", + "require": {}, + "require-dev": { + "webdriver-binary/binary-chromedriver": "*" + }, + "config": { + "allow-plugins": { + "webdriver-binary/binary-chromedriver": true + } + } +} +<<< /composer.json <<< \ No newline at end of file diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_theme_custom_correctly__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_theme_custom_correctly__0.snapshot new file mode 100644 index 000000000..f6787f758 --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__should_scaffold_for_theme_custom_correctly__0.snapshot @@ -0,0 +1,256 @@ +>>> /composer >>> +#!/bin/sh +touch composer.lock +mkdir -p ./vendor/bin +touch ./vendor/bin/chromedriver +<<< /composer <<< + +>>> /tests/EndToEnd.suite.yml >>> +# Integration suite configuration +# +# Run integration and "WordPress unit" tests. + +actor: EndToEndTester +bootstrap: _bootstrap.php +modules: + enabled: + - lucatume\WPBrowser\Module\WPWebDriver + - lucatume\WPBrowser\Module\WPDb + - lucatume\WPBrowser\Module\WPFilesystem + - lucatume\WPBrowser\Module\WPLoader + config: + lucatume\WPBrowser\Module\WPWebDriver: + url: '%WORDPRESS_URL%' + adminUsername: '%WORDPRESS_ADMIN_USER%' + adminPassword: '%WORDPRESS_ADMIN_PASSWORD%' + adminPath: '/wp-admin' + browser: chrome + host: '%CHROMEDRIVER_HOST%' + port: '%CHROMEDRIVER_PORT%' + window_size: 1200x1000 + capabilities: + chromeOptions: + args: ["--disable-gpu", "--proxy-server='direct://'", "--proxy-bypass-list=*"] + lucatume\WPBrowser\Module\WPDb: + dbUrl: '%WORDPRESS_DB_URL%' + dump: 'tests/Support/Data/dump.sql' + populate: true + cleanup: true + reconnect: false + url: '%WORDPRESS_URL%' + urlReplacement: false + tablePrefix: '%WORDPRESS_TABLE_PREFIX%' + lucatume\WPBrowser\Module\WPFilesystem: + wpRootFolder: '%WORDPRESS_ROOT_DIR%' + lucatume\WPBrowser\Module\WPLoader: + loadOnly: true + wpRootFolder: "%WORDPRESS_ROOT_DIR%" + dbUrl: '%WORDPRESS_DB_URL%' + domain: '%WORDPRESS_DOMAIN%' + +<<< /tests/EndToEnd.suite.yml <<< + +>>> /tests/Integration/_bootstrap.php >>> +>> /tests/Integration.suite.yml >>> +# Integration suite configuration +# +# Run integration and "WordPress unit" tests. + +actor: IntegrationTester +bootstrap: _bootstrap.php +modules: + enabled: + - lucatume\WPBrowser\Module\WPLoader + config: + lucatume\WPBrowser\Module\WPLoader: + wpRootFolder: "%WORDPRESS_ROOT_DIR%" + dbUrl: '%WORDPRESS_DB_URL%' + wpDebug: true + tablePrefix: '%TEST_TABLE_PREFIX%' + domain: '%WORDPRESS_DOMAIN%' + adminEmail: 'admin@%WORDPRESS_DOMAIN%' + title: 'Integration Tests' + plugins: [] + theme: 'theme_23' +<<< /tests/Integration.suite.yml <<< + +>>> /tests/Support/IntegrationTester.php >>> +>> /tests/Support/EndToEndTester.php >>> +>> /tests/Support/Data/.gitkeep >>> + +<<< /tests/Support/Data/.gitkeep <<< + +>>> /tests/EndToEnd/_bootstrap.php >>> +` command + * to run WP-CLI commands on the WordPress site and database used by the EndToEnd suite. + * E.g.: + * `vendor/bin/codecept wp:cli EndToEnd db import tests/Support/Data/dump.sql` to load dump file. + * `vendor/bin/codecept wp:cli EndToEnd plugin activate woocommerce` to activate the WooCommerce plugin. + * `vendor/bin/codecept wp:cli EndToEnd user create alice alice@example.com --role=administrator` to create a new user. + * `vendor/bin/codecept wp:cli EndToEnd db export tests/Support/Data/dump.sql` to update the dump file. + */ +<<< /tests/EndToEnd/_bootstrap.php <<< + +>>> /tests/.env >>> +# The path to the WordPress root directory, the one containing the wp-load.php file. +# This can be a relative path from the directory that contains the codeception.yml file, +# or an absolute path. +WORDPRESS_ROOT_DIR=var/wordpress + +# Tests will require a MySQL database to run. +# The database will be created if it does not exist. +# Do not use a database that contains important data! +WORDPRESS_DB_URL=mysql://User:Pa55word@localhost:3306/test + +# The Integration suite will use this table prefix for the WordPress tables. +TEST_TABLE_PREFIX=test_ + +# This table prefix used by the WordPress site in end-to-end tests. +WORDPRESS_TABLE_PREFIX=wp_ + +# The URL and domain of the WordPress site used in end-to-end tests. +WORDPRESS_URL=http://wordpress.test +WORDPRESS_DOMAIN=wordpress.test + +# The username and password of the administrator user of the WordPress site used in end-to-end tests. +WORDPRESS_ADMIN_USER=admin +WORDPRESS_ADMIN_PASSWORD=password + +# The host and port of the ChromeDriver server that will be used in end-to-end tests. +CHROMEDRIVER_HOST=localhost +CHROMEDRIVER_PORT=4444 +<<< /tests/.env <<< + +>>> /tests/_output/.gitignore >>> +* +!.gitignore + +<<< /tests/_output/.gitignore <<< + +>>> /codeception.yml >>> +namespace: Tests +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/Support/Data + support: tests/Support + envs: tests/_envs +actor_suffix: Tester +params: + - tests/.env +extensions: + enabled: + - Codeception\Extension\RunFailed + config: { } + commands: + - lucatume\WPBrowser\Command\RunOriginal + - lucatume\WPBrowser\Command\RunAll + - lucatume\WPBrowser\Command\GenerateWPUnit + - lucatume\WPBrowser\Command\DbExport + - lucatume\WPBrowser\Command\DbImport + +<<< /codeception.yml <<< + +>>> /style.css >>> +/* +Theme Name: Theme 23 +*/ +<<< /style.css <<< + +>>> /composer.json >>> +{ + "name": "acme/theme-23", + "type": "wordpress-theme", + "require": {}, + "require-dev": {} +} +<<< /composer.json <<< \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Project/PluginProjectTest.php b/tests/unit/lucatume/WPBrowser/Project/PluginProjectTest.php index ee3ba9840..f6cb57996 100644 --- a/tests/unit/lucatume/WPBrowser/Project/PluginProjectTest.php +++ b/tests/unit/lucatume/WPBrowser/Project/PluginProjectTest.php @@ -10,7 +10,6 @@ use lucatume\WPBrowser\Tests\Traits\UopzFunctions; use lucatume\WPBrowser\Utils\Filesystem as FS; use Symfony\Component\Console\Input\ArrayInput; -use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\NullOutput; use tad\Codeception\SnapshotAssertions\SnapshotAssertions; diff --git a/tests/unit/lucatume/WPBrowser/Project/ThemeProjectTest.php b/tests/unit/lucatume/WPBrowser/Project/ThemeProjectTest.php new file mode 100644 index 000000000..726005399 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Project/ThemeProjectTest.php @@ -0,0 +1,116 @@ +expectException(InvalidArgumentException::class); + $this->expectExceptionCode(ThemeProject::ERR_INVALID_THEME_DIR); + + new ThemeProject(new ArrayInput([]), new NullOutput(), __DIR__ . '/not-a-dir'); + } + + /** + * It should throw if style.css does not exist + * + * @test + */ + public function should_throw_if_style_css_does_not_exist(): void + { + $projectDir = FS::tmpDir('theme_project_', []); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionCode(ThemeProject::ERR_INVALID_THEME_DIR); + + new ThemeProject(new ArrayInput([]), new NullOutput(), $projectDir); + } + + /** + * It should throw if style.css does not define Theme Name + * + * @test + */ + public function should_throw_if_style_css_does_not_define_theme_name(): void + { + $projectDir = FS::tmpDir('theme_project_', [ + 'style.css' => <<expectException(InvalidArgumentException::class); + $this->expectExceptionCode(ThemeProject::ERR_INVALID_THEME_DIR); + + new ThemeProject(new ArrayInput([]), new NullOutput(), $projectDir); + } + + /** + * It should build correctly on theme directory + * + * @test + */ + public function should_build_correctly_on_theme_directory(): void + { + $projectDir = FS::tmpDir('theme_project_', [ + 'style.css' => <<assertEquals(basename($projectDir), $themeProject->getActivationString()); + $this->assertEquals('Some Theme', $themeProject->getName()); + $this->assertEquals('theme', $themeProject->getType()); + } + + /** + * It should build correctly on child theme directory + * + * @test + */ + public function should_build_correctly_on_child_theme_directory(): void + { + $projectDir = FS::tmpDir('theme_project_', [ + 'style.css' => <<assertEquals(basename($projectDir), $themeProject->getActivationString()); + $this->assertEquals('Some Theme', $themeProject->getName()); + $this->assertEquals('theme', $themeProject->getType()); + } +}