diff --git a/.gitattributes b/.gitattributes index ae572008c..d14377d98 100644 --- a/.gitattributes +++ b/.gitattributes @@ -18,3 +18,5 @@ /todo.txt export-ignore /var export-ignore /vendor export-ignore + +*.php diff=php diff --git a/CHANGELOG.md b/CHANGELOG.md index 49cd99064..26bb0b17f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] Unreleased +### Fixed + +- Correctly activate themes during bootstrap. + +#### Changed + +- Lay the groundwork for version 3.5 automated building. + ## [4.0.10] 2023-10-14; ### Added diff --git a/Makefile b/Makefile index 23bbfeb5f..589cf7822 100644 --- a/Makefile +++ b/Makefile @@ -47,4 +47,13 @@ clean_procs: pgrep -f 'php -S' | xargs kill pgrep chromedriver | xargs kill rm -f var/_output/*.pid var/_output/*.running + set -o allexport && source tests/.env && set +o allexport && docker compose down .PHONY: clean_procs + +build_35: + rm -rf vendor composer.lock + composer require --dev rector/rector -W + vendor/bin/rector --config=config/rector-35.php + rm -rf vendor composer.lock composer.json + cp config/composer-35.json composer.json +.PHONY: build_35 diff --git a/bin/setup-wp.php b/bin/setup-wp.php index 1404b11f0..3439a39ee 100644 --- a/bin/setup-wp.php +++ b/bin/setup-wp.php @@ -93,6 +93,12 @@ $installation->runWpCliCommandOrThrow(['theme', 'install', 'twentytwenty', '--activate']); } +echo "Checking TwentyTwentyOne theme in $wpRootDir ...\n"; +if (!is_dir($wpRootDir . '/wp-content/themes/twentytwentyone')) { + echo "Installing TwentyTwentyOne theme in $wpRootDir ...\n"; + $installation->runWpCliCommandOrThrow(['theme', 'install', 'twentytwentyone', '--activate']); +} + echo "Installing required test plugins in $wpRootDir ...\n"; $installation->runWpCliCommandOrThrow(['plugin', 'install', 'woocommerce', 'akismet', 'hello-dolly']); diff --git a/codeception.dist.yml b/codeception.dist.yml index c50d76c11..91b4ad5d5 100644 --- a/codeception.dist.yml +++ b/codeception.dist.yml @@ -45,3 +45,6 @@ extensions: - "lucatume\\WPBrowser\\Command\\DevInfo" - "lucatume\\WPBrowser\\Command\\DbImport" - "lucatume\\WPBrowser\\Command\\DbExport" +snapshot: + refresh: true + version: "%WPBROWSER_VERSION%" diff --git a/composer.json b/composer.json index eb409fc6e..9aaf3c445 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "require": { "php": "^8.0", "ext-pdo": "*", + "ext-mysqli": "*", "ext-fileinfo": "*", "ext-json": "*", "ext-curl": "*", @@ -39,13 +40,14 @@ "ifsnop/mysqldump-php": "^2.12" }, "require-dev": { - "ext-mysqli": "*", "lucatume/codeception-snapshot-assertions": "^1.0.0", "gumlet/php-image-resize": "^1.6", "szepeviktor/phpstan-wordpress": "^1.3", + "phpstan/phpstan": "*", "phpstan/extension-installer": "^1.3", "phpstan/phpstan-symfony": "^1.3", - "squizlabs/php_codesniffer": "^3.7" + "squizlabs/php_codesniffer": "^3.7", + "rector/rector": "^0.18.5" }, "autoload": { "psr-4": { @@ -58,12 +60,14 @@ }, "files": [ "src/version-4-aliases.php", - "src/Deprecated/deprecated-functions.php" + "src/Deprecated/deprecated-functions.php", + "src/functions.php" ] }, "autoload-dev": { "psr-4": { - "lucatume\\WPBrowser\\Tests\\": "tests/_support" + "lucatume\\WPBrowser\\Tests\\": "tests/_support", + "lucatume\\Rector\\": "config/rector/src" } }, "extra": { diff --git a/config/composer-35.json b/config/composer-35.json new file mode 100644 index 000000000..290b54a65 --- /dev/null +++ b/config/composer-35.json @@ -0,0 +1,101 @@ +{ + "name": "lucatume/wp-browser", + "type": "library", + "description": "A set of Codeception modules to test WordPress projects.", + "keywords": [ + "wordpress", + "codeception" + ], + "homepage": "https://github.com/lucatume/wp-browser", + "license": "MIT", + "authors": [ + { + "name": "theAverageDev (Luca Tumedei)", + "email": "luca@theaveragedev.com", + "homepage": "https://theaveragedev.com", + "role": "Developer" + } + ], + "minimum-stability": "dev", + "prefer-stable": true, + "require": { + "php": ">=7.1 <8.0", + "ext-pdo": "*", + "ext-mysqli": "*", + "ext-fileinfo": "*", + "ext-json": "*", + "ext-curl": "*", + "ext-zip": "*", + "composer-runtime-api": "^2.2", + "codeception/codeception": "^4", + "codeception/module-asserts": "^1.0", + "codeception/module-phpbrowser": "^1.0", + "codeception/module-webdriver": "^1.0", + "codeception/module-db": "^1.0", + "codeception/module-filesystem": "^1.0", + "codeception/module-cli": "^1.0", + "symfony/process": ">=3.4.47 <7.0", + "symfony/filesystem": ">=3.4.47 <7.0", + "vlucas/phpdotenv": "^4.3", + "ifsnop/mysqldump-php": "^2.12" + }, + "require-dev": { + "gumlet/php-image-resize": "^1.6", + "szepeviktor/phpstan-wordpress": "^0.7", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan-symfony": "^0.12.44", + "squizlabs/php_codesniffer": "^3.7", + "lucatume/codeception-snapshot-assertions": "^0.4" + }, + "autoload": { + "psr-4": { + "lucatume\\WPBrowser\\": [ + "src/", + "src/Deprecated" + ], + "Hautelook\\Phpass\\": "includes/Hautelook/Phpass", + "lucatume\\WPBrowser\\Opis\\Closure\\" : "includes/opis/closure/src" + }, + "files": [ + "src/version-4-aliases.php", + "src/Deprecated/deprecated-functions.php", + "src/functions.php", + "src/shim.php" + ] + }, + "autoload-dev": { + "psr-4": { + "lucatume\\WPBrowser\\Tests\\": "tests/_support" + } + }, + "extra": { + "_hash": "484f861f69198089cab0e642f27e5653" + }, + "config": { + "platform": { + "php": "7.1" + }, + "allow-plugins": { + "phpstan/extension-installer": true, + "webdriver-binary/binary-chromedriver": true + } + }, + "scripts": { + "stan": [ + "phpstan analyse --memory-limit=4G --no-progress --no-interaction --ansi -c config/phpstan.neon.dist" + ], + "stan-pro": [ + "phpstan analyse --memory-limit=4G --no-progress --no-interaction --ansi -c config/phpstan.neon.dist --pro --watch" + ], + "cs": [ + "phpcs --standard=config/phpcs.xml src" + ], + "cs-fix": [ + "phpcbf --standard=config/phpcs.xml src" + ] + }, + "suggest": { + "ext-sqlite3": "For SQLite database support.", + "ext-pdo_sqlite": "For SQLite database support." + } +} diff --git a/config/containers/php/Dockerfile b/config/containers/php/Dockerfile deleted file mode 100644 index e1adc0662..000000000 --- a/config/containers/php/Dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -ARG PHP_VERSION=8.0 -ARG COMPOSER_VERSION=2 - -FROM composer:${COMPOSER_VERSION} AS composer - -FROM wordpress:6.2.1-php${PHP_VERSION}-apache - -ARG USER_UID=33 -ARG USER_GID=33 -ARG USER_NAME=www-data -ARG TARGET=wordpress - -# Install wp-cli -ADD https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar /usr/local/bin/wp -RUN chmod a+rx /usr/local/bin/wp - -# Install required extensions, remove the ini file that would enable uopz for Apache: it will be loaded on the -ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ -RUN chmod a+x /usr/local/bin/install-php-extensions && \ - chmod -R a+rwx /usr/local/etc/php/conf.d && \ - install-php-extensions gd xdebug pdo pdo_mysql mysqli zip pcntl sockets - -# If the target is `codeception`, then install the uopz extension. -RUN if [ "${TARGET}" = "codeception" ]; then install-php-extensions uopz; fi - -# Install required utils -RUN apt-get update && \ - apt-get install -y default-mysql-client curl git zip unzip && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* && \ - rm /usr/local/bin/install-php-extensions - -# Set up PHP defaults -COPY php.ini /usr/local/etc/php/conf.d/999-php-custom.ini -# Make the PHP configuration world-accessible. - -# Copy over Composer -COPY --from=composer /usr/bin/composer /usr/local/bin/composer - -COPY bashrc_scripts.sh /etc/bashrc_scripts.sh -RUN chmod a+x /etc/bashrc_scripts.sh && echo ". /etc/bashrc_scripts.sh" >> /etc/bash.bashrc -COPY xdebug-on.sh /usr/local/bin/xdebug-on -COPY xdebug-off.sh /usr/local/bin/xdebug-off -RUN chmod a+x /usr/local/bin/xdebug-on && chmod a+x /usr/local/bin/xdebug-off - -# Ensure the gropup and user exist. -RUN getent group ${USER_GID} || groupadd -g ${USER_GID} ${USER_NAME} -RUN getent passwd ${USER_UID} || useradd -u ${USER_UID} -g ${USER_GID} -m -s /bin/bash ${USER_NAME} - -# Create a Chrome mock where expected. -RUN if [ "${TARGET}" = "codeception" ]; then \ - mkdir -p /usr/bin && \ - echo '#!/bin/bash' > /usr/bin/google-chrome && \ - echo 'echo 'Google Chrome 116.0.5845.96'' >> /usr/bin/google-chrome && \ - chmod a+x /usr/bin/google-chrome; \ - fi diff --git a/config/containers/php/bashrc_scripts.sh b/config/containers/php/bashrc_scripts.sh deleted file mode 100644 index 093e0c276..000000000 --- a/config/containers/php/bashrc_scripts.sh +++ /dev/null @@ -1,4 +0,0 @@ -alias c="php vendor/bin/codecept" -alias cr="php vendor/bin/codecept run" -alias xon="xdebug-on" -alias xoff="xdebug-off" diff --git a/config/containers/php/php.ini b/config/containers/php/php.ini deleted file mode 100644 index 2ca3075d1..000000000 --- a/config/containers/php/php.ini +++ /dev/null @@ -1,19 +0,0 @@ -date.timezone="Europe/Paris" -always_populate_raw_post_data=-1 -memory_limit=512M -file_uploads=On -upload_max_filesize=128M -post_max_size=128M -max_execution_time=300 -opcache.optimization_level=0 -xdebug.remote_enable=1 -xdebug.remote_autostart=1 -xdebug.remote_host=host.docker.internal -xdebug.remote_port=9009 -xdebug.mode=debug,develop,coverage -xdebug.start_with_request=yes -xdebug.client_port=9009 -xdebug.client_host=host.docker.internal -xdebug.log_level=0 -uopz.disable=0 -uopz.exit=1 diff --git a/config/containers/php/xdebug-off.sh b/config/containers/php/xdebug-off.sh deleted file mode 100644 index c6a38a9c0..000000000 --- a/config/containers/php/xdebug-off.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env sh - -xdebug_config_file="$(php --ini | grep xdebug | cut -d, -f1)" -sed -i '/^zend_extension/ s/zend_extension/;zend_extension/g' "$xdebug_config_file" -# Kill the oldest php-fpm process, the manager. -pkill -o -USR2 php-fpm -# Restart the php-fpm server and php-fpm when used as a module, ignore errors if not running. -/etc/init.d/apache2 reload >/dev/null 2>&1 -php -v diff --git a/config/containers/php/xdebug-on.sh b/config/containers/php/xdebug-on.sh deleted file mode 100644 index 25426e646..000000000 --- a/config/containers/php/xdebug-on.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env sh - -xdebug_config_file="$(php --ini | grep xdebug | cut -d, -f1)" -sed -i '/^;zend_extension/ s/;zend_extension/zend_extension/g' "$xdebug_config_file" -# Kill the oldest php-fpm process, the manager. -pkill -o -USR2 php-fpm -# Restart the php-fpm server and php-fpm when used as a module, ignore errors if not running. -/etc/init.d/apache2 reload >/dev/null 2>&1 -php -v diff --git a/config/rector-35.php b/config/rector-35.php new file mode 100644 index 000000000..ca297f133 --- /dev/null +++ b/config/rector-35.php @@ -0,0 +1,85 @@ +paths([ + dirname(__DIR__) . '/includes', + dirname(__DIR__) . '/src', + dirname(__DIR__) . '/tests', + ]); + + $rectorConfig->ruleWithConfiguration(RenameClassRector::class, [ + 'Symfony\Contracts\EventDispatcher\Event' => 'Symfony\Component\EventDispatcher\Event', + 'Psr\EventDispatcher\EventDispatcherInterface' => 'Symfony\Component\EventDispatcher\EventDispatcherInterface' + ]); + $rectorConfig->ruleWithConfiguration(RenamePropertyRector::class, [ + new RenameProperty( + 'lucatume\WPBrowser\TestCase\WPTestCase', + 'backupStaticAttributesExcludeList', + 'backupStaticAttributesBlacklist' + ), + new RenameProperty( + 'lucatume\WPBrowser\TestCase\WPTestCase', + 'backupGlobalsExcludeList', + 'backupGlobalsBlacklist' + ) + ]); + $rectorConfig->ruleWithConfiguration(RenameMethodRector::class, [ + new MethodCallRename('PHPUnit\Framework\Assert', 'assertMatchesRegularExpression', 'assertRegExp'), + new MethodCallRename('PHPUnit\Framework\Assert', 'assertDoesNotMatchRegularExpression', 'assertNotRegExp'), + new MethodCallRename('PHPUnit\Framework\Assert', 'assertFileDoesNotExist', 'assertFileNotExists') + ]); + + $rectorConfig->rule(SwapEventDispatcherEventNameParameters::class); + + $rectorConfig->sets([DowngradeLevelSetList::DOWN_TO_PHP_71]); + $rectorConfig->skip([DowngradeParameterTypeWideningRector::class]); + + $rectorConfig->ruleWithConfiguration(RemoveTypeHinting::class, [ + 'lucatume\WPBrowser\Module\WPDb' => [ + '_cleanup' => [ + // from: public function _cleanup(string $databaseKey = null, array $databaseConfig = null): void + // to: public function _cleanup($databaseKey = null, $databaseConfig = null) + RemoveTypeHinting::REMOVE_ALL => true + ], + '_loadDump' => [ + // from: public function _loadDump(string $databaseKey = null, array $databaseConfig = null): void + // public function _loadDump($databaseKey = null, $databaseConfig = null) + RemoveTypeHinting::REMOVE_ALL => true + ], + 'loadDumpUsingDriver' => [ + // from: protected function loadDumpUsingDriver(string $databaseKey): void + // to: protected function loadDumpUsingDriver($databaseKey) + RemoveTypeHinting::REMOVE_ALL => true + ] + ], + 'lucatume\WPBrowser\Module\WPFilesystem' => [ + // from: public function _failed(TestInterface $test, Exception $fail): void + // to: public function _failed(TestInterface $test, Exception $fail) + '_failed' => [ + RemoveTypeHinting::REMOVE_RETURN_TYPE_HINTING => true, + RemoveTypeHinting::REMOVE_PARAM_TYPE_HINTING => ['fail'] + ], + // from: public function assertDirectoryExists(string $directory, string $message = ''): void + // to: protected function assertDirectoryExists($directory, $message = '') + 'assertDirectoryExists' => [ + RemoveTypeHinting::REMOVE_ALL => true + ] + ] + ]); +}; diff --git a/config/rector/src/RemoveTypeHinting.php b/config/rector/src/RemoveTypeHinting.php new file mode 100644 index 000000000..eae8e13e4 --- /dev/null +++ b/config/rector/src/RemoveTypeHinting.php @@ -0,0 +1,110 @@ +configuration + ) + ] + ); + } + + public function getNodeTypes(): array + { + return [Class_::class, ClassMethod::class]; + } + + /** + * @param Class_|ClassMethod $node + */ + public function refactor(Node $node): ?Node + { + return $node instanceof Class_ ? $this->handleClassNode($node) : $this->handleMethodNode($node); + } + + public function configure(array $configuration): void + { + $this->configuration = $configuration; + } + + private function handleClassNode(Class_ $node): Class_ + { + $className = $node->namespacedName ? $node->namespacedName->toString() : $node->name->toString(); + if (isset($this->configuration[$className])) { + $this->currentClass = $node; + } else { + $this->currentClass = null; + } + return $node; + } + + private function handleMethodNode(ClassMethod $node): ?ClassMethod + { + if ($this->currentClass === null) { + return null; + } + + $className = $this->currentClass->namespacedName ? $this->currentClass->namespacedName->toString( + ) : $node->name->toString(); + $methodName = $node->name->toString(); + + if (!(isset($this->configuration[$className][$methodName]))) { + return null; + } + + $methodConfig = $this->configuration[$className][$methodName]; + $removeAll = isset($methodConfig[self::REMOVE_ALL]); + + foreach ($node->params as $param) { + if ($removeAll) { + $param->type = null; + continue; + } + + if (!$param->var instanceof Node\Expr\Variable) { + continue; + } + + $paramName = $param->var->name instanceof Node\Identifier ? + $param->var->name->toString() + : $param->var->name; + + if (!in_array($paramName, $methodConfig[self::REMOVE_PARAM_TYPE_HINTING] ?? [], true)) { + continue; + } + + $param->type = null; + } + + $removeReturnTypeHinting = isset($methodConfig[self::REMOVE_RETURN_TYPE_HINTING]); + if ($removeAll || $removeReturnTypeHinting) { + $node->returnType = null; + } + + return $node; + } +} diff --git a/config/rector/src/SwapEventDispatcherEventNameParameters.php b/config/rector/src/SwapEventDispatcherEventNameParameters.php new file mode 100644 index 000000000..45cd2e7a3 --- /dev/null +++ b/config/rector/src/SwapEventDispatcherEventNameParameters.php @@ -0,0 +1,62 @@ +dispatch($event, $eventName);', + '$eventDispatcher->dispatch($eventName, $event);' + ) + ] + ); + } + + public function getNodeTypes(): array + { + return [MethodCall::class]; + } + + /** + * @param MethodCall $node + */ + public function refactor(Node $node): ?Node + { + $methodCallName = $this->getName($node->name); + if ($methodCallName !== 'dispatch') { + return null; + } + + if (!$this->isObjectType( + $node->var, + new ObjectType('Symfony\Component\EventDispatcher\EventDispatcherInterface') + )) { + return null; + } + + $args = $node->args; + + if (!($args[0] instanceof Node\Arg && $args[1] instanceof Node\Arg + && $args[0]->value?->name === 'event' + && $args[1]->value?->name === 'name')) { + return null; + } + + $node->args = [$args[1], $args[0]]; + + return $node; + } +} diff --git a/includes/opis/closure/src/SerializableClosure.php b/includes/opis/closure/src/SerializableClosure.php index f422b342b..c80482dc6 100644 --- a/includes/opis/closure/src/SerializableClosure.php +++ b/includes/opis/closure/src/SerializableClosure.php @@ -15,7 +15,7 @@ /** * Provides a wrapper for serialization of closures */ -class SerializableClosure +class SerializableClosure implements Serializable { /** * @var Closure Wrapped closure @@ -635,4 +635,18 @@ protected function mapByReference(&$data) } } + public function serialize(): ?string + { + return \serialize($this->__serialize()); + } + + /** + * @param string $data + * @return void + */ + public function unserialize($data): void + { + $unserialized = \unserialize($data, ['allowed_classes' => true]); + $this->__unserialize($unserialized); + } } diff --git a/src/Adapters/Symfony/Component/Process/Process.php b/src/Adapters/Symfony/Component/Process/Process.php new file mode 100644 index 000000000..ce3a18790 --- /dev/null +++ b/src/Adapters/Symfony/Component/Process/Process.php @@ -0,0 +1,77 @@ + + */ + private $options = []; + /** + * @param string[] $command + * @param array|null $env + * @param array|null $options + */ + public function __construct( + array $command, + string $cwd = null, + array $env = null, + mixed $input = null, + ?float $timeout = 60, + array $options = null + ) { + if (method_exists($this, 'inheritEnvironmentVariables')) { + parent::__construct($command, $cwd, $env, $input, $timeout, $options); //@phpstan-ignore-line + $this->inheritEnvironmentVariables(true); + } + + parent::__construct($command, $cwd, $env, $input, $timeout); + } + + public function getStartTime(): float + { + if (method_exists(parent::class, 'getStartTime')) { + return parent::getStartTime(); + } + + if (!$this->isStarted()) { + throw new LogicException('Start time is only available after process start.'); + } + + $startTimeReflectionProperty = new \ReflectionProperty(SymfonyProcess::class, 'starttime'); + $startTimeReflectionProperty->setAccessible(true); + /** @var float $startTime */ + $startTime = $startTimeReflectionProperty->getValue($this); + + return $startTime; + } + + /** + * @param string $name + * @param array $arguments + * @return void + */ + public function __call(string $name, array $arguments) + { + if ($name === 'setOptions') { + $this->options = $arguments[0] ?? []; + } + return; + } + + public function __destruct() + { + if (($this->options['create_new_console'] ?? false) || method_exists($this, 'setOptions')) { + parent::__destruct(); + return; + } + + $closeMethodReflection = new \ReflectionMethod(SymfonyProcess::class, 'close'); + $closeMethodReflection->setAccessible(true); + $closeMethodReflection->invoke($this); + } +} diff --git a/src/Command/RunAll.php b/src/Command/RunAll.php index 36211976c..46c8284d6 100644 --- a/src/Command/RunAll.php +++ b/src/Command/RunAll.php @@ -5,9 +5,9 @@ use Codeception\Command\Run; use Codeception\CustomCommandInterface; use Exception; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Process\Process; class RunAll extends Run implements CustomCommandInterface { diff --git a/src/Events/Dispatcher.php b/src/Events/Dispatcher.php index c82a483ad..cadfad696 100644 --- a/src/Events/Dispatcher.php +++ b/src/Events/Dispatcher.php @@ -87,8 +87,25 @@ public static function addListener(string $eventName, callable $listener, int $p */ public static function dispatch(string $name, mixed $origin = null, array $context = []): ?object { + $eventDispatcher = self::getEventDispatcher(); + + if (!$eventDispatcher) { + return null; + } + $event = new Event($name, $context, $origin); - return self::getEventDispatcher()?->dispatch($event, $name); + try { + $dispatchMethodReflection = new \ReflectionMethod($eventDispatcher, 'dispatch'); + $firstParameterReflection = $dispatchMethodReflection->getParameters()[0] ?? null; + $firstParameterType = $firstParameterReflection ? $firstParameterReflection->getType() : null; + if ($firstParameterType instanceof \ReflectionNamedType && $firstParameterType->getName() === 'object') { + return $eventDispatcher->dispatch($event, $name); + } + + return $eventDispatcher->dispatch($name, $event); //@phpstan-ignore-line + } catch (\ReflectionException $e) { + return null; + } } } diff --git a/src/Extension/DockerComposeController.php b/src/Extension/DockerComposeController.php index ff78dff55..37bc929b1 100644 --- a/src/Extension/DockerComposeController.php +++ b/src/Extension/DockerComposeController.php @@ -3,9 +3,8 @@ namespace lucatume\WPBrowser\Extension; use Codeception\Exception\ExtensionException; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Process\Exception\ProcessFailedException; -use Symfony\Component\Process\Process; use Symfony\Component\Yaml\Yaml; use Throwable; @@ -150,7 +149,8 @@ public function getInfo(): array ...$this->getCommand($this->config), 'config' ]); - $dockerComposeConfig = $process->mustRun()->getOutput(); + $process->mustRun(); + $dockerComposeConfig = $process->getOutput(); return [ 'status' => 'up', diff --git a/src/Generators/Tables.php b/src/Generators/Tables.php index 8ccfbc7d2..5b2d4bdcf 100644 --- a/src/Generators/Tables.php +++ b/src/Generators/Tables.php @@ -99,9 +99,9 @@ private function templates(string $table): string * @param int $blogId The blog ID. * @param array $data The blog data. * - * @return string The SQL query. + * @return string[] The SQL queries to scaffold the blog tables. */ - public function getBlogScaffoldQuery(string $prefix, int $blogId, array $data): string + public function getBlogScaffoldQueries(string $prefix, int $blogId, array $data): array { $template = $this->templates('new-blog'); $data = array_merge([ @@ -124,7 +124,14 @@ public function getBlogScaffoldQuery(string $prefix, int $blogId, array $data): $data['home'] = $data['home'] ?? $data['siteurl']; $data['template'] = $data['template'] ?? $data['stylesheet']; - return Strings::renderString($template, $data); + return array_values( + array_map( + 'trim', + array_filter( + explode('-- break --', Strings::renderString($template, $data)) + ) + ) + ); } /** @@ -133,9 +140,9 @@ public function getBlogScaffoldQuery(string $prefix, int $blogId, array $data): * @param string $tablePrefix The database table prefix. * @param int $blogId The blog ID. * - * @return string SQL code. + * @return string[] The SQL queries to drop the blog tables. */ - public function getBlogDropQuery(string $tablePrefix, int $blogId): string + public function getBlogDropQueries(string $tablePrefix, int $blogId): array { $template = $this->templates('drop-blog-tables'); $data = [ @@ -143,6 +150,11 @@ public function getBlogDropQuery(string $tablePrefix, int $blogId): string 'blog_id' => $blogId ]; - return Strings::renderString($template, $data); + return array_values( + array_map( + 'trim', + array_filter(explode('-- break --', Strings::renderString($template, $data))) + ) + ); } } diff --git a/src/Generators/mysql/drop-blog-tables.handlebars b/src/Generators/mysql/drop-blog-tables.handlebars index 390590e99..233fa1a68 100644 --- a/src/Generators/mysql/drop-blog-tables.handlebars +++ b/src/Generators/mysql/drop-blog-tables.handlebars @@ -1,10 +1,19 @@ DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_commentmeta`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_comments`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_links`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_options`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_postmeta`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_posts`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_term_relationships`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_term_taxonomy`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_termmeta`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_terms`; diff --git a/src/Generators/mysql/new-blog.handlebars b/src/Generators/mysql/new-blog.handlebars index 4fac93430..67eae2002 100644 --- a/src/Generators/mysql/new-blog.handlebars +++ b/src/Generators/mysql/new-blog.handlebars @@ -8,7 +8,7 @@ PRIMARY KEY (`meta_id`), KEY `comment_id` (`comment_id`), KEY `meta_key` (`meta_key`(191)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - +-- break -- -- Create syntax for TABLE '{{prefix}}{{blog_id}}_comments' CREATE TABLE `{{prefix}}{{blog_id}}_comments` ( `comment_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, @@ -33,7 +33,7 @@ KEY `comment_date_gmt` (`comment_date_gmt`), KEY `comment_parent` (`comment_parent`), KEY `comment_author_email` (`comment_author_email`(10)) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - +-- break -- -- Create syntax for TABLE '{{prefix}}{{blog_id}}_links' CREATE TABLE `{{prefix}}{{blog_id}}_links` ( `link_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, @@ -52,7 +52,7 @@ CREATE TABLE `{{prefix}}{{blog_id}}_links` ( PRIMARY KEY (`link_id`), KEY `link_visible` (`link_visible`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - +-- break -- -- Create syntax for TABLE '{{prefix}}{{blog_id}}_options' CREATE TABLE `{{prefix}}{{blog_id}}_options` ( `option_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, @@ -62,7 +62,7 @@ CREATE TABLE `{{prefix}}{{blog_id}}_options` ( PRIMARY KEY (`option_id`), UNIQUE KEY `option_name` (`option_name`) ) ENGINE=InnoDB AUTO_INCREMENT=128 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - +-- break -- -- Create syntax for TABLE '{{prefix}}{{blog_id}}_postmeta' CREATE TABLE `{{prefix}}{{blog_id}}_postmeta` ( `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, @@ -73,7 +73,7 @@ PRIMARY KEY (`meta_id`), KEY `post_id` (`post_id`), KEY `meta_key` (`meta_key`(191)) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - +-- break -- -- Create syntax for TABLE '{{prefix}}{{blog_id}}_posts' CREATE TABLE `{{prefix}}{{blog_id}}_posts` ( `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, @@ -105,7 +105,7 @@ KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`), KEY `post_parent` (`post_parent`), KEY `post_author` (`post_author`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - +-- break -- -- Create syntax for TABLE '{{prefix}}{{blog_id}}_term_relationships' CREATE TABLE `{{prefix}}{{blog_id}}_term_relationships` ( `object_id` bigint(20) unsigned NOT NULL DEFAULT '0', @@ -114,7 +114,7 @@ CREATE TABLE `{{prefix}}{{blog_id}}_term_relationships` ( PRIMARY KEY (`object_id`,`term_taxonomy_id`), KEY `term_taxonomy_id` (`term_taxonomy_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - +-- break -- -- Create syntax for TABLE '{{prefix}}{{blog_id}}_term_taxonomy' CREATE TABLE `{{prefix}}{{blog_id}}_term_taxonomy` ( `term_taxonomy_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, @@ -127,7 +127,7 @@ PRIMARY KEY (`term_taxonomy_id`), UNIQUE KEY `term_id_taxonomy` (`term_id`,`taxonomy`), KEY `taxonomy` (`taxonomy`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - +-- break -- -- Create syntax for TABLE '{{prefix}}{{blog_id}}_terms' CREATE TABLE `{{prefix}}{{blog_id}}_terms` ( `term_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, @@ -138,7 +138,7 @@ PRIMARY KEY (`term_id`), KEY `slug` (`slug`(191)), KEY `name` (`name`(191)) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - +-- break -- CREATE TABLE `{{prefix}}{{blog_id}}_termmeta` ( `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `term_id` bigint(20) unsigned NOT NULL DEFAULT '0', @@ -148,7 +148,7 @@ PRIMARY KEY (`meta_id`), KEY `term_id` (`term_id`), KEY `meta_key` (`meta_key`(191)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - +-- break -- INSERT INTO `{{prefix}}{{blog_id}}_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES (1, 'siteurl', '{{siteurl}}', 'yes'), diff --git a/src/Generators/sqlite/drop-blog-tables.handlebars b/src/Generators/sqlite/drop-blog-tables.handlebars index 390590e99..233fa1a68 100644 --- a/src/Generators/sqlite/drop-blog-tables.handlebars +++ b/src/Generators/sqlite/drop-blog-tables.handlebars @@ -1,10 +1,19 @@ DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_commentmeta`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_comments`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_links`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_options`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_postmeta`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_posts`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_term_relationships`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_term_taxonomy`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_termmeta`; +-- break -- DROP TABLE IF EXISTS `{{prefix}}{{blog_id}}_terms`; diff --git a/src/Generators/sqlite/new-blog.handlebars b/src/Generators/sqlite/new-blog.handlebars index 3405b97e5..eb3c00cd7 100644 --- a/src/Generators/sqlite/new-blog.handlebars +++ b/src/Generators/sqlite/new-blog.handlebars @@ -6,13 +6,13 @@ create table {{prefix}}{{blog_id}}_commentmeta meta_key text default NULL, meta_value text ); - +-- break -- create index commetmeta_comment_id_blog_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_commentmeta (comment_id); - +-- break -- create index commentmeta_meta_key_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_commentmeta (meta_key); - +-- break -- create table {{prefix}}{{blog_id}}_comments ( comment_ID integer not null @@ -32,25 +32,26 @@ create table {{prefix}}{{blog_id}}_comments comment_parent integer default '0' not null, user_id integer default '0' not null ); - +-- break -- create index comments_comment_approved_date_gmt_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_comments (comment_approved, comment_date_gmt); - +-- break -- create index comments_comment_author_email_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_comments (comment_author_email); - +-- break -- create index comments_comment_date_gmt_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_comments (comment_date_gmt); - +-- break -- create index comments_comment_parent_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_comments (comment_parent); - +-- break -- create index comments_comment_post_ID_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_comments (comment_post_ID); - +-- break -- INSERT INTO {{prefix}}{{blog_id}}_comments (comment_post_ID, comment_author, comment_author_email, comment_author_url, comment_author_IP, comment_date, comment_date_gmt, comment_content, comment_karma, comment_approved, comment_agent, comment_type, comment_parent, user_id) VALUES (1, 'A WordPress Commenter', 'wapuu@wordpress.example', 'http://example.com/', '', '2023-07-21 15:34:46', '2023-07-21 15:34:46', 'Hi, this is a comment. To get started with moderating, editing, and deleting comments, please visit the Comments screen in the dashboard. Commenter avatars come from Gravatar.', 0, '1', '', 'comment', 0, 0); +-- break -- create table {{prefix}}{{blog_id}}_links ( link_id integer not null @@ -68,10 +69,10 @@ create table {{prefix}}{{blog_id}}_links link_notes text not null, link_rss text default '' not null ); - +-- break -- create index links_link_visible_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_links (link_visible); - +-- break -- create table {{prefix}}{{blog_id}}_options ( option_id integer not null @@ -80,116 +81,219 @@ create table {{prefix}}{{blog_id}}_options option_value text not null, autoload text default 'yes' not null ); - +-- break -- create index options_autoload_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_options (autoload); - +-- break -- create unique index option_name_17 on {{prefix}}{{blog_id}}_options (option_name); - +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('siteurl', '{{siteurl}}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('home', '{{home}}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('blogname', 'Test', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('blogdescription', '', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('users_can_register', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('admin_email', 'admin@example.com', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('start_of_week', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('use_balanceTags', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('use_smilies', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('require_name_email', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('comments_notify', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('posts_per_rss', '10', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('rss_use_excerpt', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('mailserver_url', 'mail.example.com', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('mailserver_login', 'login@example.com', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('mailserver_pass', 'password', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('mailserver_port', '110', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('default_category', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('default_comment_status', 'open', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('default_ping_status', 'open', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('default_pingback_flag', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('posts_per_page', '10', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('date_format', 'F j, Y', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('time_format', 'g:i a', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('links_updated_date_format', 'F j, Y g:i a', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('comment_moderation', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('moderation_notify', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('permalink_structure', '/%year%/%monthnum%/%day%/%postname%/', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('rewrite_rules', 'a:96:{s:11:"^wp-json/?$";s:22:"index.php?rest_route=/";s:14:"^wp-json/(.*)?";s:33:"index.php?rest_route=/$matches[1]";s:21:"^index.php/wp-json/?$";s:22:"index.php?rest_route=/";s:24:"^index.php/wp-json/(.*)?";s:33:"index.php?rest_route=/$matches[1]";s:17:"^wp-sitemap\.xml$";s:23:"index.php?sitemap=index";s:17:"^wp-sitemap\.xsl$";s:36:"index.php?sitemap-stylesheet=sitemap";s:23:"^wp-sitemap-index\.xsl$";s:34:"index.php?sitemap-stylesheet=index";s:48:"^wp-sitemap-([a-z]+?)-([a-z\d_-]+?)-(\d+?)\.xml$";s:75:"index.php?sitemap=$matches[1]&sitemap-subtype=$matches[2]&paged=$matches[3]";s:34:"^wp-sitemap-([a-z]+?)-(\d+?)\.xml$";s:47:"index.php?sitemap=$matches[1]&paged=$matches[2]";s:47:"category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$";s:52:"index.php?category_name=$matches[1]&feed=$matches[2]";s:42:"category/(.+?)/(feed|rdf|rss|rss2|atom)/?$";s:52:"index.php?category_name=$matches[1]&feed=$matches[2]";s:23:"category/(.+?)/embed/?$";s:46:"index.php?category_name=$matches[1]&embed=true";s:35:"category/(.+?)/page/?([0-9]{1,})/?$";s:53:"index.php?category_name=$matches[1]&paged=$matches[2]";s:17:"category/(.+?)/?$";s:35:"index.php?category_name=$matches[1]";s:44:"tag/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$";s:42:"index.php?tag=$matches[1]&feed=$matches[2]";s:39:"tag/([^/]+)/(feed|rdf|rss|rss2|atom)/?$";s:42:"index.php?tag=$matches[1]&feed=$matches[2]";s:20:"tag/([^/]+)/embed/?$";s:36:"index.php?tag=$matches[1]&embed=true";s:32:"tag/([^/]+)/page/?([0-9]{1,})/?$";s:43:"index.php?tag=$matches[1]&paged=$matches[2]";s:14:"tag/([^/]+)/?$";s:25:"index.php?tag=$matches[1]";s:45:"type/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$";s:50:"index.php?post_format=$matches[1]&feed=$matches[2]";s:40:"type/([^/]+)/(feed|rdf|rss|rss2|atom)/?$";s:50:"index.php?post_format=$matches[1]&feed=$matches[2]";s:21:"type/([^/]+)/embed/?$";s:44:"index.php?post_format=$matches[1]&embed=true";s:33:"type/([^/]+)/page/?([0-9]{1,})/?$";s:51:"index.php?post_format=$matches[1]&paged=$matches[2]";s:15:"type/([^/]+)/?$";s:33:"index.php?post_format=$matches[1]";s:12:"robots\.txt$";s:18:"index.php?robots=1";s:13:"favicon\.ico$";s:19:"index.php?favicon=1";s:48:".*wp-(atom|rdf|rss|rss2|feed|commentsrss2)\.php$";s:18:"index.php?feed=old";s:20:".*wp-app\.php(/.*)?$";s:19:"index.php?error=403";s:18:".*wp-register.php$";s:23:"index.php?register=true";s:32:"feed/(feed|rdf|rss|rss2|atom)/?$";s:27:"index.php?&feed=$matches[1]";s:27:"(feed|rdf|rss|rss2|atom)/?$";s:27:"index.php?&feed=$matches[1]";s:8:"embed/?$";s:21:"index.php?&embed=true";s:20:"page/?([0-9]{1,})/?$";s:28:"index.php?&paged=$matches[1]";s:41:"comments/feed/(feed|rdf|rss|rss2|atom)/?$";s:42:"index.php?&feed=$matches[1]&withcomments=1";s:36:"comments/(feed|rdf|rss|rss2|atom)/?$";s:42:"index.php?&feed=$matches[1]&withcomments=1";s:17:"comments/embed/?$";s:21:"index.php?&embed=true";s:44:"search/(.+)/feed/(feed|rdf|rss|rss2|atom)/?$";s:40:"index.php?s=$matches[1]&feed=$matches[2]";s:39:"search/(.+)/(feed|rdf|rss|rss2|atom)/?$";s:40:"index.php?s=$matches[1]&feed=$matches[2]";s:20:"search/(.+)/embed/?$";s:34:"index.php?s=$matches[1]&embed=true";s:32:"search/(.+)/page/?([0-9]{1,})/?$";s:41:"index.php?s=$matches[1]&paged=$matches[2]";s:14:"search/(.+)/?$";s:23:"index.php?s=$matches[1]";s:47:"author/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$";s:50:"index.php?author_name=$matches[1]&feed=$matches[2]";s:42:"author/([^/]+)/(feed|rdf|rss|rss2|atom)/?$";s:50:"index.php?author_name=$matches[1]&feed=$matches[2]";s:23:"author/([^/]+)/embed/?$";s:44:"index.php?author_name=$matches[1]&embed=true";s:35:"author/([^/]+)/page/?([0-9]{1,})/?$";s:51:"index.php?author_name=$matches[1]&paged=$matches[2]";s:17:"author/([^/]+)/?$";s:33:"index.php?author_name=$matches[1]";s:69:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/feed/(feed|rdf|rss|rss2|atom)/?$";s:80:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&feed=$matches[4]";s:64:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/(feed|rdf|rss|rss2|atom)/?$";s:80:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&feed=$matches[4]";s:45:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/embed/?$";s:74:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&embed=true";s:57:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/page/?([0-9]{1,})/?$";s:81:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&paged=$matches[4]";s:39:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/?$";s:63:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]";s:56:"([0-9]{4})/([0-9]{1,2})/feed/(feed|rdf|rss|rss2|atom)/?$";s:64:"index.php?year=$matches[1]&monthnum=$matches[2]&feed=$matches[3]";s:51:"([0-9]{4})/([0-9]{1,2})/(feed|rdf|rss|rss2|atom)/?$";s:64:"index.php?year=$matches[1]&monthnum=$matches[2]&feed=$matches[3]";s:32:"([0-9]{4})/([0-9]{1,2})/embed/?$";s:58:"index.php?year=$matches[1]&monthnum=$matches[2]&embed=true";s:44:"([0-9]{4})/([0-9]{1,2})/page/?([0-9]{1,})/?$";s:65:"index.php?year=$matches[1]&monthnum=$matches[2]&paged=$matches[3]";s:26:"([0-9]{4})/([0-9]{1,2})/?$";s:47:"index.php?year=$matches[1]&monthnum=$matches[2]";s:43:"([0-9]{4})/feed/(feed|rdf|rss|rss2|atom)/?$";s:43:"index.php?year=$matches[1]&feed=$matches[2]";s:38:"([0-9]{4})/(feed|rdf|rss|rss2|atom)/?$";s:43:"index.php?year=$matches[1]&feed=$matches[2]";s:19:"([0-9]{4})/embed/?$";s:37:"index.php?year=$matches[1]&embed=true";s:31:"([0-9]{4})/page/?([0-9]{1,})/?$";s:44:"index.php?year=$matches[1]&paged=$matches[2]";s:13:"([0-9]{4})/?$";s:26:"index.php?year=$matches[1]";s:58:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/attachment/([^/]+)/?$";s:32:"index.php?attachment=$matches[1]";s:68:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/attachment/([^/]+)/trackback/?$";s:37:"index.php?attachment=$matches[1]&tb=1";s:88:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/attachment/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$";s:49:"index.php?attachment=$matches[1]&feed=$matches[2]";s:83:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/attachment/([^/]+)/(feed|rdf|rss|rss2|atom)/?$";s:49:"index.php?attachment=$matches[1]&feed=$matches[2]";s:83:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/attachment/([^/]+)/comment-page-([0-9]{1,})/?$";s:50:"index.php?attachment=$matches[1]&cpage=$matches[2]";s:64:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/attachment/([^/]+)/embed/?$";s:43:"index.php?attachment=$matches[1]&embed=true";s:53:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)/embed/?$";s:91:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&embed=true";s:57:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)/trackback/?$";s:85:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&tb=1";s:77:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$";s:97:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&feed=$matches[5]";s:72:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)/(feed|rdf|rss|rss2|atom)/?$";s:97:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&feed=$matches[5]";s:65:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)/page/?([0-9]{1,})/?$";s:98:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&paged=$matches[5]";s:72:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)/comment-page-([0-9]{1,})/?$";s:98:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&cpage=$matches[5]";s:61:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)(?:/([0-9]+))?/?$";s:97:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&page=$matches[5]";s:47:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/([^/]+)/?$";s:32:"index.php?attachment=$matches[1]";s:57:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/([^/]+)/trackback/?$";s:37:"index.php?attachment=$matches[1]&tb=1";s:77:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$";s:49:"index.php?attachment=$matches[1]&feed=$matches[2]";s:72:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/([^/]+)/(feed|rdf|rss|rss2|atom)/?$";s:49:"index.php?attachment=$matches[1]&feed=$matches[2]";s:72:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/([^/]+)/comment-page-([0-9]{1,})/?$";s:50:"index.php?attachment=$matches[1]&cpage=$matches[2]";s:53:"[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/([^/]+)/embed/?$";s:43:"index.php?attachment=$matches[1]&embed=true";s:64:"([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/comment-page-([0-9]{1,})/?$";s:81:"index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&cpage=$matches[4]";s:51:"([0-9]{4})/([0-9]{1,2})/comment-page-([0-9]{1,})/?$";s:65:"index.php?year=$matches[1]&monthnum=$matches[2]&cpage=$matches[3]";s:38:"([0-9]{4})/comment-page-([0-9]{1,})/?$";s:44:"index.php?year=$matches[1]&cpage=$matches[2]";s:27:".?.+?/attachment/([^/]+)/?$";s:32:"index.php?attachment=$matches[1]";s:37:".?.+?/attachment/([^/]+)/trackback/?$";s:37:"index.php?attachment=$matches[1]&tb=1";s:57:".?.+?/attachment/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$";s:49:"index.php?attachment=$matches[1]&feed=$matches[2]";s:52:".?.+?/attachment/([^/]+)/(feed|rdf|rss|rss2|atom)/?$";s:49:"index.php?attachment=$matches[1]&feed=$matches[2]";s:52:".?.+?/attachment/([^/]+)/comment-page-([0-9]{1,})/?$";s:50:"index.php?attachment=$matches[1]&cpage=$matches[2]";s:33:".?.+?/attachment/([^/]+)/embed/?$";s:43:"index.php?attachment=$matches[1]&embed=true";s:16:"(.?.+?)/embed/?$";s:41:"index.php?pagename=$matches[1]&embed=true";s:20:"(.?.+?)/trackback/?$";s:35:"index.php?pagename=$matches[1]&tb=1";s:40:"(.?.+?)/feed/(feed|rdf|rss|rss2|atom)/?$";s:47:"index.php?pagename=$matches[1]&feed=$matches[2]";s:35:"(.?.+?)/(feed|rdf|rss|rss2|atom)/?$";s:47:"index.php?pagename=$matches[1]&feed=$matches[2]";s:28:"(.?.+?)/page/?([0-9]{1,})/?$";s:48:"index.php?pagename=$matches[1]&paged=$matches[2]";s:35:"(.?.+?)/comment-page-([0-9]{1,})/?$";s:48:"index.php?pagename=$matches[1]&cpage=$matches[2]";s:24:"(.?.+?)(?:/([0-9]+))?/?$";s:47:"index.php?pagename=$matches[1]&page=$matches[2]";}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('hack_file', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('blog_charset', 'UTF-8', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('moderation_keys', '', 'no'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('active_plugins', 'a:0:{}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('category_base', '', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('ping_sites', 'http://rpc.pingomatic.com/', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('comment_max_links', '2', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('gmt_offset', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('default_email_category', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('recently_edited', '', 'no'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('template', '{{template}}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('stylesheet', '{{stylesheet}}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('comment_registration', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('html_type', 'text/html', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('use_trackback', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('default_role', 'subscriber', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('db_version', '53496', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('uploads_use_yearmonth_folders', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('upload_path', '', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('blog_public', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('default_link_category', '2', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('show_on_front', 'posts', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('tag_base', '', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('show_avatars', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('avatar_rating', 'G', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('upload_url_path', '', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('thumbnail_size_w', '150', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('thumbnail_size_h', '150', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('thumbnail_crop', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('medium_size_w', '300', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('medium_size_h', '300', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('avatar_default', 'mystery', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('large_size_w', '1024', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('large_size_h', '1024', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('image_default_link_type', 'none', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('image_default_size', '', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('image_default_align', '', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('close_comments_for_old_posts', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('close_comments_days_old', '14', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('thread_comments', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('thread_comments_depth', '5', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('page_comments', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('comments_per_page', '50', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('default_comments_page', 'newest', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('comment_order', 'asc', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('sticky_posts', 'a:0:{}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('widget_categories', 'a:0:{}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('widget_text', 'a:0:{}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('widget_rss', 'a:0:{}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('uninstall_plugins', 'a:0:{}', 'no'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('timezone_string', '', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('page_for_posts', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('page_on_front', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('default_post_format', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('link_manager_enabled', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('finished_splitting_shared_terms', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('site_icon', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('medium_large_size_w', '768', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('medium_large_size_h', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('wp_page_for_privacy_policy', '0', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('show_comments_cookies_opt_in', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('admin_email_lifespan', '1705505686', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('disallowed_keys', '', 'no'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('comment_previously_approved', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('auto_plugin_theme_update_emails', 'a:0:{}', 'no'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('auto_update_core_dev', 'enabled', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('auto_update_core_minor', 'enabled', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('auto_update_core_major', 'enabled', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('wp_force_deactivated_plugins', 'a:0:{}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('WPLANG', 'en_US', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('{{prefix}}{{blog_id}}user_roles', 'a:5:{s:13:"administrator";a:2:{s:4:"name";s:13:"Administrator";s:12:"capabilities";a:61:{s:13:"switch_themes";b:1;s:11:"edit_themes";b:1;s:16:"activate_plugins";b:1;s:12:"edit_plugins";b:1;s:10:"edit_users";b:1;s:10:"edit_files";b:1;s:14:"manage_options";b:1;s:17:"moderate_comments";b:1;s:17:"manage_categories";b:1;s:12:"manage_links";b:1;s:12:"upload_files";b:1;s:6:"import";b:1;s:15:"unfiltered_html";b:1;s:10:"edit_posts";b:1;s:17:"edit_others_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:10:"edit_pages";b:1;s:4:"read";b:1;s:8:"level_10";b:1;s:7:"level_9";b:1;s:7:"level_8";b:1;s:7:"level_7";b:1;s:7:"level_6";b:1;s:7:"level_5";b:1;s:7:"level_4";b:1;s:7:"level_3";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:17:"edit_others_pages";b:1;s:20:"edit_published_pages";b:1;s:13:"publish_pages";b:1;s:12:"delete_pages";b:1;s:19:"delete_others_pages";b:1;s:22:"delete_published_pages";b:1;s:12:"delete_posts";b:1;s:19:"delete_others_posts";b:1;s:22:"delete_published_posts";b:1;s:20:"delete_private_posts";b:1;s:18:"edit_private_posts";b:1;s:18:"read_private_posts";b:1;s:20:"delete_private_pages";b:1;s:18:"edit_private_pages";b:1;s:18:"read_private_pages";b:1;s:12:"delete_users";b:1;s:12:"create_users";b:1;s:17:"unfiltered_upload";b:1;s:14:"edit_dashboard";b:1;s:14:"update_plugins";b:1;s:14:"delete_plugins";b:1;s:15:"install_plugins";b:1;s:13:"update_themes";b:1;s:14:"install_themes";b:1;s:11:"update_core";b:1;s:10:"list_users";b:1;s:12:"remove_users";b:1;s:13:"promote_users";b:1;s:18:"edit_theme_options";b:1;s:13:"delete_themes";b:1;s:6:"export";b:1;}}s:6:"editor";a:2:{s:4:"name";s:6:"Editor";s:12:"capabilities";a:34:{s:17:"moderate_comments";b:1;s:17:"manage_categories";b:1;s:12:"manage_links";b:1;s:12:"upload_files";b:1;s:15:"unfiltered_html";b:1;s:10:"edit_posts";b:1;s:17:"edit_others_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:10:"edit_pages";b:1;s:4:"read";b:1;s:7:"level_7";b:1;s:7:"level_6";b:1;s:7:"level_5";b:1;s:7:"level_4";b:1;s:7:"level_3";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:17:"edit_others_pages";b:1;s:20:"edit_published_pages";b:1;s:13:"publish_pages";b:1;s:12:"delete_pages";b:1;s:19:"delete_others_pages";b:1;s:22:"delete_published_pages";b:1;s:12:"delete_posts";b:1;s:19:"delete_others_posts";b:1;s:22:"delete_published_posts";b:1;s:20:"delete_private_posts";b:1;s:18:"edit_private_posts";b:1;s:18:"read_private_posts";b:1;s:20:"delete_private_pages";b:1;s:18:"edit_private_pages";b:1;s:18:"read_private_pages";b:1;}}s:6:"author";a:2:{s:4:"name";s:6:"Author";s:12:"capabilities";a:10:{s:12:"upload_files";b:1;s:10:"edit_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:4:"read";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:12:"delete_posts";b:1;s:22:"delete_published_posts";b:1;}}s:11:"contributor";a:2:{s:4:"name";s:11:"Contributor";s:12:"capabilities";a:5:{s:10:"edit_posts";b:1;s:4:"read";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:12:"delete_posts";b:1;}}s:10:"subscriber";a:2:{s:4:"name";s:10:"Subscriber";s:12:"capabilities";a:2:{s:4:"read";b:1;s:7:"level_0";b:1;}}}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('post_count', '1', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('widget_block', 'a:6:{i:2;a:1:{s:7:"content";s:19:"";}i:3;a:1:{s:7:"content";s:154:"

Recent Posts

";}i:4;a:1:{s:7:"content";s:227:"

Recent Comments

";}i:5;a:1:{s:7:"content";s:146:"

Archives

";}i:6;a:1:{s:7:"content";s:150:"

Categories

";}s:12:"_multiwidget";i:1;}', 'yes'); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_options (option_name, option_value, autoload) VALUES ('sidebars_widgets', 'a:4:{s:19:"wp_inactive_widgets";a:0:{}s:9:"sidebar-1";a:3:{i:0;s:7:"block-2";i:1;s:7:"block-3";i:2;s:7:"block-4";}s:9:"sidebar-2";a:2:{i:0;s:7:"block-5";i:1;s:7:"block-6";}s:13:"array_version";i:3;}', 'yes'); +-- break -- create table {{prefix}}{{blog_id}}_postmeta ( meta_id integer not null @@ -198,14 +302,15 @@ create table {{prefix}}{{blog_id}}_postmeta meta_key text default NULL, meta_value text ); - +-- break -- create index postmeta_meta_key_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_postmeta (meta_key); - +-- break -- create index postmeta_post_id_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_postmeta (post_id); - +-- break -- INSERT INTO {{prefix}}{{blog_id}}_postmeta (post_id, meta_key, meta_value) VALUES (2, '_wp_page_template', 'default'); +-- break -- create table {{prefix}}{{blog_id}}_posts ( ID integer not null @@ -233,20 +338,21 @@ create table {{prefix}}{{blog_id}}_posts post_mime_type text default '' not null, comment_count integer default '0' not null ); - +-- break -- create index posts_post_author_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_posts (post_author); - +-- break -- create index posts_post_name_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_posts (post_name); - +-- break -- create index posts_post_parent_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_posts (post_parent); - +-- break -- create index posts_type_status_date_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_posts (post_type, post_status, post_date, ID); - +-- break -- INSERT INTO {{prefix}}{{blog_id}}_posts (post_author, post_date, post_date_gmt, post_content, post_title, post_excerpt, post_status, comment_status, ping_status, post_password, post_name, to_ping, pinged, post_modified, post_modified_gmt, post_content_filtered, post_parent, guid, menu_order, post_type, post_mime_type, comment_count) VALUES (2, '2023-07-21 15:34:46', '2023-07-21 15:34:46', 'Welcome to Test. This is your first post. Edit or delete it, then start writing!', 'Hello world!', '', 'publish', 'open', 'open', '', 'hello-world', '', '', '2023-07-21 15:34:46', '2023-07-21 15:34:46', '', 0, 'http://test1.example.com/?p=1', 0, 'post', '', 1); +-- break -- INSERT INTO {{prefix}}{{blog_id}}_posts (post_author, post_date, post_date_gmt, post_content, post_title, post_excerpt, post_status, comment_status, ping_status, post_password, post_name, to_ping, pinged, post_modified, post_modified_gmt, post_content_filtered, post_parent, guid, menu_order, post_type, post_mime_type, comment_count) VALUES (2, '2023-07-21 15:34:46', '2023-07-21 15:34:46', '

This is an example page. It''s different from a blog post because it will stay in one place and will show up in your site navigation (in most themes). Most people start with an About page that introduces them to potential site visitors. It might say something like this:

@@ -266,6 +372,7 @@ INSERT INTO {{prefix}}{{blog_id}}_posts (post_author, post_date, post_date_gmt,

As a new WordPress user, you should go to your dashboard to delete this page and create new pages for your content. Have fun!

', 'Sample Page', '', 'publish', 'closed', 'open', '', 'sample-page', '', '', '2023-07-21 15:34:46', '2023-07-21 15:34:46', '', 0, 'http://test1.example.com/?page_id=2', 0, 'page', '', 0); +-- break -- create table {{prefix}}{{blog_id}}_term_relationships ( object_id integer default 0 not null, @@ -273,11 +380,12 @@ create table {{prefix}}{{blog_id}}_term_relationships term_order integer default 0 not null, primary key (object_id, term_taxonomy_id) ); - +-- break -- create index term_relationships_term_taxonomy_id_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_term_relationships (term_taxonomy_id); - +-- break -- INSERT INTO {{prefix}}{{blog_id}}_term_relationships (object_id, term_taxonomy_id, term_order) VALUES (1, 1, 0); +-- break -- create table {{prefix}}{{blog_id}}_term_taxonomy ( term_taxonomy_id integer not null @@ -288,14 +396,15 @@ create table {{prefix}}{{blog_id}}_term_taxonomy parent integer default 0 not null, count integer default 0 not null ); - +-- break -- create index term_taxonomy_taxonomy_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_term_taxonomy (taxonomy); - +-- break -- create unique index term_id_taxonomy_13 on {{prefix}}{{blog_id}}_term_taxonomy (term_id, taxonomy); - +-- break -- INSERT INTO {{prefix}}{{blog_id}}_term_taxonomy (term_id, taxonomy, description, parent, count) VALUES (1, 'category', '', 0, 1); +-- break -- create table {{prefix}}{{blog_id}}_termmeta ( meta_id integer not null @@ -304,13 +413,13 @@ create table {{prefix}}{{blog_id}}_termmeta meta_key text default NULL, meta_value text ); - +-- break -- create index termmeta_meta_key_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_termmeta (meta_key); - +-- break -- create index termmeta_term_id_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_termmeta (term_id); - +-- break -- create table {{prefix}}{{blog_id}}_terms ( term_id integer not null @@ -319,11 +428,11 @@ create table {{prefix}}{{blog_id}}_terms slug text default '' not null, term_group integer default 0 not null ); - +-- break -- create index terms_name_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_terms (name); - +-- break -- create index terms_slug_{{prefix}}{{blog_id}} on {{prefix}}{{blog_id}}_terms (slug); - +-- break -- INSERT INTO {{prefix}}{{blog_id}}_terms (name, slug, term_group) VALUES ('Uncategorized', 'uncategorized', 0); diff --git a/src/ManagedProcess/ChromeDriver.php b/src/ManagedProcess/ChromeDriver.php index c0d4e4919..5055b1ceb 100644 --- a/src/ManagedProcess/ChromeDriver.php +++ b/src/ManagedProcess/ChromeDriver.php @@ -2,9 +2,9 @@ namespace lucatume\WPBrowser\ManagedProcess; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Exceptions\RuntimeException; use lucatume\WPBrowser\Utils\Composer; -use Symfony\Component\Process\Process; class ChromeDriver implements ManagedProcessInterface { diff --git a/src/ManagedProcess/ManagedProcessTrait.php b/src/ManagedProcess/ManagedProcessTrait.php index bdf68131e..4d2bddd93 100644 --- a/src/ManagedProcess/ManagedProcessTrait.php +++ b/src/ManagedProcess/ManagedProcessTrait.php @@ -2,9 +2,9 @@ namespace lucatume\WPBrowser\ManagedProcess; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Exceptions\RuntimeException; use Symfony\Component\Process\Exception\ProcessFailedException; -use Symfony\Component\Process\Process; /** * @property string $prettyName diff --git a/src/ManagedProcess/PhpBuiltInServer.php b/src/ManagedProcess/PhpBuiltInServer.php index 57b70d5a2..516629731 100644 --- a/src/ManagedProcess/PhpBuiltInServer.php +++ b/src/ManagedProcess/PhpBuiltInServer.php @@ -2,10 +2,12 @@ namespace lucatume\WPBrowser\ManagedProcess; +use CurlHandle; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Exceptions\RuntimeException; use lucatume\WPBrowser\Utils\Arr; use lucatume\WPBrowser\Utils\Filesystem; -use Symfony\Component\Process\Process; +use lucatume\WPBrowser\Utils\Ports; class PhpBuiltInServer implements ManagedProcessInterface { @@ -14,6 +16,7 @@ class PhpBuiltInServer implements ManagedProcessInterface public const ERR_DOC_ROOT_NOT_FOUND = 1; public const ERR_PORT_ALREADY_IN_USE = 2; public const ERR_ENV = 3; + public const ERR_CHECK = 4; public const PID_FILE_NAME = 'php-built-in-server.pid'; private string $prettyName = 'PHP Built-in Server'; @@ -52,9 +55,17 @@ public function doStart(): void '-S', "localhost:$this->port", '-t', - Filesystem::realpath($this->docRoot), + Filesystem::realpath($this->docRoot) ?: $this->docRoot, $routerPathname ]; + + if (Ports::isPortOccupied($this->port)) { + throw new RuntimeException( + 'Port ' . $this->port . ' is already in use.', + self::ERR_PORT_ALREADY_IN_USE + ); + } + $process = new Process( $command, $this->docRoot, @@ -62,8 +73,7 @@ public function doStart(): void ); $process->setOptions(['create_new_console' => true]); $process->start(); - $confirmPort = $this->readPortFromProcessOutput($process); - if ($confirmPort === null || !(is_numeric($confirmPort) && (int)$confirmPort > 0)) { + if (!$this->confirmServerRunningOnPort($process)) { $error = new RuntimeException( 'Could not start PHP Built-in server: ' . $process->getErrorOutput(), ManagedProcessInterface::ERR_START @@ -71,7 +81,6 @@ public function doStart(): void $this->stop(); throw $error; } - $this->port = (int)$confirmPort; $this->process = $process; } @@ -80,29 +89,21 @@ public function getPort(): int return $this->port; } - private function readPortFromProcessOutput(Process $process): ?int + private function confirmServerRunningOnPort(Process $process): bool { - for ($attempts = 0; $attempts < 30; $attempts++) { - // The Server log is written to STDERR. - $output = $process->getErrorOutput(); - $matches = []; - preg_match('/^.*localhost:(?\d+).*$/m', $output, $matches); - - if (!isset($matches['port'])) { - usleep(100000); - continue; + $attempts = 0; + do { + if ($process->getExitCode() !== null) { + return false; } - if ($process->getExitCode() !== null) { - throw new RuntimeException( - "PHP Built-in server could not start: port already in use.", - self::ERR_PORT_ALREADY_IN_USE - ); + if ($process->isRunning() && Ports::isPortOccupied($this->port)) { + return true; } - return (int)$matches['port']; - } + usleep(100000); + } while ($attempts++ < 30); - return null; + return false; } } diff --git a/src/Module/WPCLI.php b/src/Module/WPCLI.php index 0b47875db..e21b2ccfb 100644 --- a/src/Module/WPCLI.php +++ b/src/Module/WPCLI.php @@ -143,7 +143,7 @@ public function cli(string|array $command = ['core', 'version'], ?array $env = n $cliProcess = new CliProcess($command, $config['path'], $env, $input, $config['timeout']); - $this->debugSection('command', $cliProcess->getCommandLine()); + $this->debugSection('WPCLI command', $cliProcess->getCommandLine()); try { $cliProcess->run(); @@ -160,13 +160,13 @@ public function cli(string|array $command = ['core', 'version'], ?array $env = n $this->lastCliProcess = $cliProcess; - $this->debugSection('STDOUT', $cliProcess->getOutput()); - $this->debugSection('STDERR', $cliProcess->getErrorOutput()); + $this->debugSection('WPCLI STDOUT', $cliProcess->getOutput()); + $this->debugSection('WPCLI STDERR', $cliProcess->getErrorOutput()); /** @var int $exitCode The process terminated at this stage. */ $exitCode = $cliProcess->getExitCode(); - $this->debugSection('exit code', print_r($exitCode, true)); + $this->debugSection('WPCLI exit code', print_r($exitCode, true)); if ($config['throw'] && $exitCode !== 0) { throw new ModuleException( @@ -182,11 +182,6 @@ public function cli(string|array $command = ['core', 'version'], ?array $env = n return $exitCode; } - protected function debugSection(string $title, mixed $message): void - { - parent::debugSection("WPCLI $title", $message); - } - /** * @throws ModuleException */ diff --git a/src/Module/WPDb.php b/src/Module/WPDb.php index 327c21a2b..55335aacc 100644 --- a/src/Module/WPDb.php +++ b/src/Module/WPDb.php @@ -28,6 +28,8 @@ use lucatume\WPBrowser\Utils\WP; use PDO; use PDOException; +use ReflectionException; +use ReflectionMethod; use RuntimeException; /** @@ -184,13 +186,6 @@ class WPDb extends Db */ protected Driver $driver; - /** - * A map from the database keys to the drivers for them. - * - * @var array - */ - public array $drivers = []; - /** * Whether the database has been previously populated or not. * @@ -3310,6 +3305,10 @@ public function haveBlogInDatabase(string $domainOrPath, array $overrides = [], ); } + // A table DROP and INSERT will trigger a schema change and will trigger a transaction commit. + // Reconnecting now is a good insurance against schema change related errors. + $this->reconnectCurrentDatabase(); + return $blogId; } @@ -3369,15 +3368,21 @@ protected function scaffoldBlogTables(int $blogId, string $domainOrPath, bool $i $tables = new Tables(get_class($this->drivers[$this->currentDatabase])); - $dropQuery = $tables->getBlogDropQuery($this->config['tablePrefix'], $blogId); - $pdoStatement = $pdo->prepare($dropQuery); - $this->debugSection('Query', $pdoStatement->queryString); - $pdo->exec($dropQuery); + $dropQueries = $tables->getBlogDropQueries($this->config['tablePrefix'], $blogId); + foreach ($dropQueries as $dropQuery) { + $this->debugSection('Query', $dropQuery); + if ($pdo->exec($dropQuery) === false) { + throw new ModuleException($this, 'Failed to drop blog tables: ' . ($pdo->errorInfo()[2] ?? 'n/a')); + } + } - $scaffoldQuery = $tables->getBlogScaffoldQuery($this->config['tablePrefix'], $blogId, $data); - $pdoStatement = $pdo->prepare($scaffoldQuery); - $this->debugSection('Query', $pdoStatement->queryString); - $pdo->exec($scaffoldQuery); + $scaffoldQueries = $tables->getBlogScaffoldQueries($this->config['tablePrefix'], $blogId, $data); + foreach ($scaffoldQueries as $scaffoldQuery) { + $this->debugSection('Query', $scaffoldQuery); + if ($pdo->exec($scaffoldQuery) === false) { + throw new ModuleException($this, 'Failed to scaffold blog tables: ' . ($pdo->errorInfo()[2] ?? 'n/a')); + } + } $this->scaffoldedBlogIds[] = $blogId; } @@ -4905,4 +4910,25 @@ public function seeSiteTransientInDatabase(string $transient, mixed $value = nul $this->seeOptionInDatabase($transient, $value); $this->useBlog($currentBlogId); } + + private function reconnectCurrentDatabase(): void + { + $allDbConfigs = $this->getDatabases(); + if (!isset($allDbConfigs[$this->currentDatabase])) { + return; + } + $currentDatabaseConfig = $allDbConfigs[$this->currentDatabase]; + + try { + $disconnectMethodReflection = new ReflectionMethod($this, 'disconnect'); + $connectMethodReflection = new ReflectionMethod($this, 'connect'); + $disconnectMethodReflection->setAccessible(true); + $connectMethodReflection->setAccessible(true); + $this->debugSection('WPDb', 'Reconnecting to database ' . $this->currentDatabase); + $disconnectMethodReflection->invoke($this, $this->currentDatabase); + $connectMethodReflection->invoke($this, $this->currentDatabase, $currentDatabaseConfig); + } catch (ReflectionException $e) { + // Do nothing, the attempt was not successful. + } + } } diff --git a/src/Module/WPFilesystem.php b/src/Module/WPFilesystem.php index 588730a75..32c0843da 100644 --- a/src/Module/WPFilesystem.php +++ b/src/Module/WPFilesystem.php @@ -246,17 +246,17 @@ public function _after(TestInterface $test): void * $I->seeFileFound('shop.log'); * ``` * - * @param string|null $path The path, relative to the site uploads folder. + * @param string|int|null $path The path, relative to the site uploads folder. * * * @throws Exception If the path is a date string and is not parsable by the `strtotime` function. */ - public function amInUploadsPath(string $path = null): void + public function amInUploadsPath(string|int $path = null): void { if (null === $path) { $path = $this->config['uploads']; - } elseif (is_dir($this->config['uploads'] . FS::unleadslashit($path))) { - $path = $this->config['uploads'] . FS::unleadslashit($path); + } elseif (is_dir($this->config['uploads'] . FS::unleadslashit((string)$path))) { + $path = $this->config['uploads'] . FS::unleadslashit((string)$path); } else { // time based? $path = $this->config['uploads'] . $this->buildDateFrag($path); @@ -374,7 +374,11 @@ private function buildDateFrag(string|int|DateTimeInterface $date): string */ public function dontSeeUploadedFileFound(string $file, int|string $date = null): void { - Assert::assertFileDoesNotExist($this->getUploadsPath($file, $date)); + if (method_exists(Assert::class, 'assertFileDoesNotExist')) { + Assert::assertFileDoesNotExist($this->getUploadsPath($file, $date)); + } else { + Assert::assertFileNotExists($this->getUploadsPath($file, $date)); + } } /** diff --git a/src/Module/WPLoader.php b/src/Module/WPLoader.php index 1b146a856..76c69e1bd 100644 --- a/src/Module/WPLoader.php +++ b/src/Module/WPLoader.php @@ -8,7 +8,6 @@ namespace lucatume\WPBrowser\Module; use Closure; -use Codeception\Command\Shared\ConfigTrait; use Codeception\Events; use Codeception\Exception\ModuleConfigException; use Codeception\Exception\ModuleException; @@ -52,8 +51,6 @@ */ class WPLoader extends Module { - use ConfigTrait; - public const EVENT_BEFORE_INSTALL = 'wploader.before_install'; public const EVENT_BEFORE_LOADONLY = 'wploader.before_loadonly'; public const EVENT_AFTER_LOADONLY = 'wploader.after_loadonly'; @@ -447,6 +444,8 @@ private function loadWordPress(bool $loadOnly = false): void $this->installAndBootstrapInstallation(); } + wp_cache_flush(); + $this->factoryStore = new FactoryStore(); if (Debug::isEnabled()) { diff --git a/src/MonkeyPatch/FileStreamWrapper.php b/src/MonkeyPatch/FileStreamWrapper.php index e793b5d81..2a7594150 100644 --- a/src/MonkeyPatch/FileStreamWrapper.php +++ b/src/MonkeyPatch/FileStreamWrapper.php @@ -457,7 +457,11 @@ private function patchFile(string $absPath): string [$fileContents, $openedPath] = $patcher->patch($fileContents, $absPath); - $fileResource = fopen('php://temp', 'rb+', false, $this->context); + if ($this->context !== null) { + $fileResource = fopen('php://temp', 'rb+', false, $this->context); + } else { + $fileResource = fopen('php://temp', 'rb+'); + } if ($fileResource === false) { throw new MonkeyPatchingException("Could not open temporary file for writing."); @@ -479,6 +483,15 @@ private function patchFile(string $absPath): string */ private function openFile(string $absPath, string $mode, bool $useIncludePath): void { + if (!file_exists($absPath) && !is_dir(dirname($absPath))) { + /* + * The file open operation will never succeed, so we don't even try. + * The `w`, `c` and `x` modes will create the file if it does not exist, + * but will not create the directory structure to it + */ + return; + } + if (isset($this->context)) { $handle = fopen($absPath, $mode, $useIncludePath, $this->context); } else { @@ -486,7 +499,8 @@ private function openFile(string $absPath, string $mode, bool $useIncludePath): } if (!is_resource($handle)) { - throw new MonkeyPatchingException("Could not open file $absPath."); + return; + // throw new MonkeyPatchingException("Could not open file $absPath."); } $this->fileResource = $handle; diff --git a/src/Process/Loop.php b/src/Process/Loop.php index a085160d1..cf2dc1f75 100644 --- a/src/Process/Loop.php +++ b/src/Process/Loop.php @@ -158,11 +158,11 @@ static function (Worker $w) use ($exitedWorkersIds, $runningWorkersIds): bool { return null; } - $busyResourcesIds = array_merge( + $busyResourcesIds = count($this->running) ? array_merge( ...array_map(static function (Running $rw): array { return $rw->getRequiredResourcesIds(); }, array_values($this->running)) - ); + ) : []; foreach ($notStartedWorkers as $w) { if (count(array_intersect($w->getRequiredResourcesIds(), $busyResourcesIds)) === 0) { diff --git a/src/Process/SerializableThrowable.php b/src/Process/SerializableThrowable.php index d4c3864f9..ef935dda3 100644 --- a/src/Process/SerializableThrowable.php +++ b/src/Process/SerializableThrowable.php @@ -78,13 +78,11 @@ public function __unserialize(array $data): void { $this->throwable = $data['throwable']; $this->colorize = $data['colorize']; - Property::setPrivateProperties($this->throwable, [ - 'message' => $data['message'], - 'trace' => $this->prettyPrintTrace($data['trace']), - 'file' => $data['file'], - 'line' => $data['line'], - 'code' => $data['code'], - ]); + $this->message = $data['message']; + $this->code = $data['code']; + $this->file = $data['file']; + $this->line = $data['line']; + $this->trace = $data['trace']; } /** @@ -92,10 +90,18 @@ public function __unserialize(array $data): void */ public function getThrowable(int $options = 0): Throwable { + $errorClass = $this->throwable instanceof \Error ? \Error::class : \Exception::class; + Property::setPropertiesForClass($this->throwable, $errorClass, [ + 'message' => $this->message, + 'code' => $this->code, + 'file' => $this->file, + 'line' => $this->line, + 'trace' => $this->prettyPrintTrace($this->trace) + ]); + if ($options & self::RELATIVE_PAHTNAMES) { $this->makeTraceFilesRelative(); } - return $this->throwable; } @@ -159,7 +165,8 @@ protected function makeTraceFilesRelative(): void $traceEntry['line'] = 1; $relativePathnameTrace[$k] = $traceEntry; } - Property::setPrivateProperties($this->throwable, [ + $errorClass = $this->throwable instanceof \Error ? \Error::class : \Exception::class; + Property::setPropertiesForClass($this->throwable, $errorClass, [ 'file' => $relativeFile, 'trace' => $relativePathnameTrace, ]); diff --git a/src/Process/Worker/WorkerProcess.php b/src/Process/Worker/WorkerProcess.php index 239c7faf8..832d308c7 100644 --- a/src/Process/Worker/WorkerProcess.php +++ b/src/Process/Worker/WorkerProcess.php @@ -2,9 +2,9 @@ namespace lucatume\WPBrowser\Process\Worker; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Process\ProcessException; use lucatume\WPBrowser\Utils\Property; -use Symfony\Component\Process\Process; class WorkerProcess extends Process { diff --git a/src/Project/ContentProject.php b/src/Project/ContentProject.php index cab7f40bd..4f59ebc85 100644 --- a/src/Project/ContentProject.php +++ b/src/Project/ContentProject.php @@ -13,6 +13,7 @@ use lucatume\WPBrowser\Extension\BuiltInServerController; use lucatume\WPBrowser\Extension\ChromeDriverController; use lucatume\WPBrowser\Utils\ChromedriverInstaller; +use lucatume\WPBrowser\Utils\Codeception; use lucatume\WPBrowser\Utils\Filesystem as FS; use lucatume\WPBrowser\Utils\Random; use lucatume\WPBrowser\WordPress\Database\SQLiteDatabase; @@ -56,11 +57,15 @@ private function getAfterSuccessClosure(bool $activated): Closure $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 " . + $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.'); + 'tests/_wordpress/wp-content/themes directories.' + ); }; } @@ -69,8 +74,10 @@ private function getAfterSuccessClosure(bool $activated): Closure */ public function setup(): void { - $this->say('You can use a portable configuration based on PHP built-in server, Chromedriver ' . - 'and SQLite.'); + $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) { @@ -81,6 +88,7 @@ public function setup(): void $wpRootDir = $this->workDir . '/tests/_wordpress'; $dataDir = $this->workDir . '/tests/_wordpress/data'; + $dataDirRelativePath = Codeception::dataDir(); if (!is_dir($dataDir) && !(mkdir($dataDir, 0777, true) && is_dir($dataDir))) { throw new RuntimeException("Could not create WordPress data directory $dataDir."); @@ -115,13 +123,13 @@ public function setup(): void } $db->dump($tmpDumpFile); - FS::mkdirp($this->workDir . '/tests/Support/Data'); - if (!rename($tmpDumpFile, $this->workDir . '/tests/Support/Data/dump.sql')) { + FS::mkdirp($this->workDir . '/' . $dataDirRelativePath); + if (!rename($tmpDumpFile, $this->workDir . '/' . $dataDirRelativePath . '/dump.sql')) { throw new RuntimeException( - "Could not move database dump from $tmpDumpFile to tests/Support/Data/dump.sql." + "Could not move database dump from $tmpDumpFile to '.$dataDirRelativePath.'/dump.sql." ); } - $this->sayInfo('Created database dump in tests/Support/Data/dump.sql.'); + $this->sayInfo('Created database dump in ' . $dataDirRelativePath . '/dump.sql.'); $this->sayInfo('Installing Chromedriver ...'); $chromedriverPath = (new ChromedriverInstaller())->install(); @@ -150,7 +158,7 @@ public function setup(): void 'env' => [ 'DATABASE_TYPE' => 'sqlite', 'DB_ENGINE' => 'sqlite', - 'DB_DIR' => implode(DIRECTORY_SEPARATOR, ['%codecept_root_dir%','tests','Support','Data']), + 'DB_DIR' => '%codecept_root_dir%' . DIRECTORY_SEPARATOR . $dataDirRelativePath, 'DB_FILE' => 'db.sqlite' ] ] diff --git a/src/Project/SiteProject.php b/src/Project/SiteProject.php index 3b35f2e47..3d0f677f2 100644 --- a/src/Project/SiteProject.php +++ b/src/Project/SiteProject.php @@ -12,6 +12,7 @@ use lucatume\WPBrowser\Extension\BuiltInServerController; use lucatume\WPBrowser\Extension\ChromeDriverController; use lucatume\WPBrowser\Utils\ChromedriverInstaller; +use lucatume\WPBrowser\Utils\Codeception; use lucatume\WPBrowser\Utils\Filesystem as FS; use lucatume\WPBrowser\Utils\Random; use lucatume\WPBrowser\WordPress\Database\SQLiteDatabase; @@ -82,7 +83,8 @@ public function setup(): void return; } - $dataDir = $this->workDir . '/tests/Support/Data'; + $dataDir = Codeception::dataDir($this->workDir); + $dataDirRelativePath = Codeception::dataDir(); if (!is_dir($dataDir) && !(mkdir($dataDir, 0777, true) && is_dir($dataDir))) { throw new RuntimeException("Could not create WordPress data directory $dataDir."); @@ -111,13 +113,13 @@ public function setup(): void } $db->dump($tmpDumpFile); - FS::mkdirp($this->workDir . '/tests/Support/Data'); - if (!rename($tmpDumpFile, $this->workDir . '/tests/Support/Data/dump.sql')) { + FS::mkdirp($this->workDir . '/' . $dataDirRelativePath); + if (!rename($tmpDumpFile, $this->workDir . '/' . $dataDirRelativePath . '/dump.sql')) { throw new RuntimeException( - "Could not move database dump from $tmpDumpFile to tests/Support/Data/dump.sql." + "Could not move database dump from $tmpDumpFile to '.$dataDirRelativePath.'/dump.sql." ); } - $this->sayInfo('Created database dump in tests/Support/Data/dump.sql.'); + $this->sayInfo('Created database dump in ' . $dataDirRelativePath . '/dump.sql.'); $this->sayInfo('Installing Chromedriver ...'); $chromedriverPath = (new ChromedriverInstaller())->install(); @@ -146,7 +148,7 @@ public function setup(): void 'env' => [ 'DATABASE_TYPE' => 'sqlite', 'DB_ENGINE' => 'sqlite', - 'DB_DIR' => implode(DIRECTORY_SEPARATOR, ['%codecept_root_dir%', 'tests', 'Support', 'Data']), + 'DB_DIR' => '%codecept_root_dir%' . DIRECTORY_SEPARATOR . $dataDirRelativePath, 'DB_FILE' => 'db.sqlite' ] ] @@ -160,7 +162,7 @@ public function setup(): void $this->testEnvironment->wpRootDir = '.'; $this->testEnvironment->dbUrl = 'sqlite://' . implode( DIRECTORY_SEPARATOR, - ['%codecept_root_dir%', 'tests', 'Support', 'Data', 'db.sqlite'] + ['%codecept_root_dir%', $dataDirRelativePath, 'db.sqlite'] ); $this->testEnvironment->afterSuccess = function (): void { diff --git a/src/Project/ThemeProject.php b/src/Project/ThemeProject.php index c6333ae94..af89e0e82 100644 --- a/src/Project/ThemeProject.php +++ b/src/Project/ThemeProject.php @@ -100,7 +100,7 @@ protected function symlinkProjectInContentDir(string $wpRootDir): void protected function activate(string $wpRootDir, int $serverLocalhostPort): bool { $codeExec = new CodeExecutionFactory($wpRootDir, 'localhost:' . $serverLocalhostPort); - $switchTheme = $codeExec->toSwitchTheme(Strings::slug($this->basename), false); + $switchTheme = $codeExec->toSwitchTheme($this->basename, false); $activationResult = Loop::executeClosure($switchTheme)->getReturnValue(); if ($activationResult instanceof Throwable) { $message = $activationResult->getMessage(); diff --git a/src/Template/Wpbrowser.php b/src/Template/Wpbrowser.php index 8db89f99c..595b82326 100644 --- a/src/Template/Wpbrowser.php +++ b/src/Template/Wpbrowser.php @@ -85,7 +85,7 @@ public function createGlobalConfig(): void /** @var TestEnvironment $testEnv */ $testEnv = $this->testEnvironment; $basicConfig = [ - 'support_namespace' => $this->supportNamespace, + 'support_namespace' => $this->supportNamespace ?? 'Support', 'paths' => [ 'tests' => 'tests', 'output' => $this->outputDir, diff --git a/src/TestCase/WPTestCase.php b/src/TestCase/WPTestCase.php index e45d655e2..7b15e7e68 100644 --- a/src/TestCase/WPTestCase.php +++ b/src/TestCase/WPTestCase.php @@ -38,6 +38,8 @@ class WPTestCase extends Unit 'wp_meta_keys', // WooCommerce. 'woocommerce', + // Additional globals. + '_wp_registered_theme_features' ]; // Backup, and reset, static class attributes between tests. @@ -45,12 +47,24 @@ class WPTestCase extends Unit // A list of static attributes that should not be backed up as they are wired to explode when doing so. protected $backupStaticAttributesExcludeList = [ + // WordPress + 'WP_Block_Type_Registry' => ['instance'], + // wp-browser + 'lucatume\WPBrowser\Events\Dispatcher' => ['eventDispatcher'], + self::class => ['coreTestCaseMap'], + // Codeception + 'Codeception\Util\Annotation' => ['reflectedClasses'], // WooCommerce. 'WooCommerce' => ['_instance'], 'Automattic\WooCommerce\Internal\Admin\FeaturePlugin' => ['instance'], 'Automattic\WooCommerce\RestApi\Server' => ['instance'] ]; + /** + * @var array + */ + protected array $additionalGlobalsBackup = []; + /** * @var array */ @@ -75,15 +89,36 @@ public static function setUpBeforeClass(): void self::getCoreTestCase()->set_up_before_class(); } + protected function backupAdditionalGlobals(): void + { + foreach ([ + '_wp_registered_theme_features' + ] as $key + ) { + if (isset($GLOBALS[$key])) { + $this->additionalGlobalsBackup = $GLOBALS[$key]; + } + } + } protected function setUp(): void { parent::setUp(); $this->set_up(); //@phpstan-ignore-line magic __call + $this->backupAdditionalGlobals(); + } + + protected function restoreAdditionalGlobals(): void + { + foreach ($this->additionalGlobalsBackup as $key => $value) { + $GLOBALS[$key] = $value; + unset($this->additionalGlobalsBackup[$key]); + } } protected function tearDown(): void { + $this->restoreAdditionalGlobals(); $this->tear_down(); //@phpstan-ignore-line magic __call parent::tearDown(); } diff --git a/src/Traits/DockerComposeUserTrait.php b/src/Traits/DockerComposeUserTrait.php deleted file mode 100644 index a18e7e24b..000000000 --- a/src/Traits/DockerComposeUserTrait.php +++ /dev/null @@ -1,14 +0,0 @@ -mustRun(); - } -} diff --git a/src/Utils/ChromedriverInstaller.php b/src/Utils/ChromedriverInstaller.php index e53615471..adcd88750 100644 --- a/src/Utils/ChromedriverInstaller.php +++ b/src/Utils/ChromedriverInstaller.php @@ -1,13 +1,17 @@ output->writeln("Fetching Chromedriver version URL ..."); - $downloadUrl = $this->fetchChromedriverVersionUrl(); - $zipFilePathname = rtrim(sys_get_temp_dir(), '\\/') . '/' . basename($downloadUrl); + $zipFilePathname = $this->useEnvZipFile ? + Env::get('WPBROWSER_CHROMEDRIVER_ZIP_FILE', null) + : null; + $cacheDir = FS::cacheDir() . '/chromedriver'; + $executableFileName = $dir . '/' . $this->getExecutableFileName(); - if (is_file($zipFilePathname) && !unlink($zipFilePathname)) { - throw new RuntimeException( - "Could not remove existing zip file $zipFilePathname", - self::ERR_REMOVE_EXISTING_ZIP_FILE - ); + if (!(is_string($zipFilePathname) && is_file($zipFilePathname))) { + $downloadUrl = $this->fetchChromedriverVersionUrl(); + if (!is_dir($cacheDir) && !(mkdir($cacheDir, 0777, true) && is_dir($cacheDir))) { + throw new RuntimeException("Could not create Chromedriver cache directory $cacheDir."); + } + $zipFilePathname = rtrim($cacheDir, '\\/') . '/chromedriver.zip'; + if (is_file($zipFilePathname) && !unlink($zipFilePathname)) { + throw new RuntimeException( + "Could not remove existing zip file $zipFilePathname", + self::ERR_REMOVE_EXISTING_ZIP_FILE + ); + } + $this->output->writeln('Downloading Chromedriver to ' . $zipFilePathname . ' ...'); + $zipFilePathname = Download::fileFromUrl($downloadUrl, $zipFilePathname); + $this->output->writeln('Downloaded Chromedriver to ' . $zipFilePathname); } - $zipFilePathname = Download::fileFromUrl($downloadUrl, $zipFilePathname); - $this->output->writeln('Downloaded Chromedriver to ' . $zipFilePathname); - - $executableFileName = $dir . '/' . $this->getExecutableFileName(); - if (is_file($executableFileName) && !unlink($executableFileName)) { throw new RuntimeException( "Could not remove existing executable file $executableFileName", @@ -101,19 +114,9 @@ public function install(string $dir = null): string ); } - $extractedPath = Zip::extractTo($zipFilePathname, sys_get_temp_dir()); - - if (!rename( - "$extractedPath/chromedriver-$this->platform/" . $this->getExecutableFileName(), - $executableFileName - )) { - throw new RuntimeException( - "Could not move Chromedriver to $executableFileName", - self::ERR_MOVE_BINARY - ); - } + Zip::extractFile($zipFilePathname, $this->getExecutableFileName(), $executableFileName); - if (chmod($executableFileName, 0755) === false) { + if (!chmod($executableFileName, 0755)) { throw new RuntimeException( "Could not make Chromedriver executable", self::ERR_BINARY_CHMOD @@ -272,10 +275,18 @@ private function checkVersion(mixed $version): string return $matches['major']; } + private function fetchChromedriverVersionUrl(): string + { + return useMemoString( + fn() => $this->unmemoizedFetchChromedriverVersionUrl(), + [$this->platform, $this->milestone] + ); + } + /** * @throws JsonException */ - private function fetchChromedriverVersionUrl(): string + private function unmemoizedFetchChromedriverVersionUrl(): string { $milestoneDownloads = file_get_contents( 'https://googlechromelabs.github.io/chrome-for-testing/latest-versions-per-milestone-with-downloads.json' @@ -349,4 +360,9 @@ public function getPlatform(): string { return $this->platform; } + + public function useEnvZipFile(bool $useEnvZipFile): void + { + $this->useEnvZipFile = $useEnvZipFile; + } } diff --git a/src/Utils/Codeception.php b/src/Utils/Codeception.php new file mode 100644 index 000000000..fe5c74587 --- /dev/null +++ b/src/Utils/Codeception.php @@ -0,0 +1,28 @@ +=') + ? implode(DIRECTORY_SEPARATOR, ['tests', 'Support', 'Data']) + : 'tests' . DIRECTORY_SEPARATOR . '_data'; + + return $rootDir ? rtrim($rootDir, '\\/') . DIRECTORY_SEPARATOR . $relDataPath + : $relDataPath; + } + + public static function supportDir(string $rootDir = null): string + { + $relSupportPath = version_compare(Codecept::VERSION, '5.0.0', '>=') + ? implode(DIRECTORY_SEPARATOR, ['tests', 'Support']) + : 'tests' . DIRECTORY_SEPARATOR . '_support'; + + return $rootDir ? rtrim($rootDir, '\\/') . DIRECTORY_SEPARATOR . $relSupportPath + : $relSupportPath; + } +} diff --git a/src/Utils/Composer.php b/src/Utils/Composer.php index f0847c0f6..c8dbb8742 100644 --- a/src/Utils/Composer.php +++ b/src/Utils/Composer.php @@ -5,9 +5,9 @@ namespace lucatume\WPBrowser\Utils; use JsonException; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Exceptions\RuntimeException; use StdClass; -use Symfony\Component\Process\Process; class Composer { diff --git a/src/Utils/Db.php b/src/Utils/Db.php index b2c6feb48..6bba16bd5 100644 --- a/src/Utils/Db.php +++ b/src/Utils/Db.php @@ -12,13 +12,13 @@ use Closure; use InvalidArgumentException; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Utils\Db as DbUtils; use lucatume\WPBrowser\Utils\Filesystem as FS; use PDO; use PDOException; use PDOStatement; use RuntimeException; -use Symfony\Component\Process\Process; use function array_replace; class Db diff --git a/src/Utils/DockerCompose.php b/src/Utils/DockerCompose.php index 93186366d..e52e139f5 100644 --- a/src/Utils/DockerCompose.php +++ b/src/Utils/DockerCompose.php @@ -2,10 +2,10 @@ namespace lucatume\WPBrowser\Utils; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Exceptions\InvalidArgumentException; use lucatume\WPBrowser\Exceptions\RuntimeException; use Symfony\Component\Process\Exception\ProcessFailedException; -use Symfony\Component\Process\Process; class DockerCompose { diff --git a/src/Utils/Memo.php b/src/Utils/Memo.php new file mode 100644 index 000000000..59315a8e4 --- /dev/null +++ b/src/Utils/Memo.php @@ -0,0 +1,34 @@ +> + */ + private static $cache = []; + + public static function get(string $key, string $subKey, mixed $default = null): mixed + { + if (isset(self::$cache[$key]) + && is_array(self::$cache[$key]) + && isset(self::$cache[$key][$subKey])) { + return self::$cache[$key][$subKey]; + } + + return $default; + } + + public static function set(string $key, string $subKey, mixed $result): void + { + self::$cache[$key] = []; + self::$cache[$key][$subKey] = $result; + } + + public static function reset(): void + { + self::$cache = []; + } +} diff --git a/src/Utils/Ports.php b/src/Utils/Ports.php new file mode 100644 index 000000000..1d34ee954 --- /dev/null +++ b/src/Utils/Ports.php @@ -0,0 +1,15 @@ +start(); + $attempts = 0; + $testedPorts = []; + while ($attempts++ < 10) { 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 (Throwable $e) { - throw new RuntimeException( - 'Could not start PHP built-in server to find free localhost port: ' . $e->getMessage() - ); - } finally { - if (isset($process)) { - $process->stop(); + $port = random_int(1025, 65535); + } while (in_array($port, $testedPorts, true)); + + $testedPorts[] = $port; + + if (!Ports::isPortOccupied($port)) { + return $port; } } + + throw new RuntimeException( + 'Could not start PHP built-in server to find free localhost port after many attempts.' + ); } } diff --git a/src/Utils/Zip.php b/src/Utils/Zip.php index fead38806..53c1da88f 100644 --- a/src/Utils/Zip.php +++ b/src/Utils/Zip.php @@ -1,4 +1,5 @@ open($zipFile) !== true) { + throw new RuntimeException("Could not open {$zipFile}."); + } + + if (($fileIndex = $zip->locateName($filename, ZipArchive::FL_NODIR)) === false) { + throw new RuntimeException("Could not locate {$filename} in {$zipFile}."); + } + + if (($name = $zip->getNameIndex($fileIndex)) === false) { + throw new RuntimeException("Could not get name for {$fileIndex} in {$zipFile}."); + } + + if (!copy("zip://{$zipFile}#{$name}", $destinationFileName)) { + throw new RuntimeException("Could not copy {$name} from {$zipFile} to {$destinationFileName}."); + } + + return $destinationFileName; + } } diff --git a/src/WordPress/CliProcess.php b/src/WordPress/CliProcess.php index cb168574b..60aeefe4f 100644 --- a/src/WordPress/CliProcess.php +++ b/src/WordPress/CliProcess.php @@ -2,10 +2,10 @@ namespace lucatume\WPBrowser\WordPress; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Exceptions\RuntimeException; use lucatume\WPBrowser\Utils\Download; use lucatume\WPBrowser\Utils\Filesystem as FS; -use Symfony\Component\Process\Process; class CliProcess extends Process { diff --git a/src/WordPress/Database/MysqlDatabase.php b/src/WordPress/Database/MysqlDatabase.php index 4b341888d..2bf8d11b7 100644 --- a/src/WordPress/Database/MysqlDatabase.php +++ b/src/WordPress/Database/MysqlDatabase.php @@ -313,6 +313,9 @@ public function import(string $dumpFilePath): int if (str_ends_with($line, ';')) { try { $modified = $pdo->exec($line); + if ($modified === false) { + throw new Exception($pdo->errorInfo()[2]); + } } catch (Exception $e) { fclose($dumpFileHandle); throw new DbException("Failed to execute query: " . $e->getMessage(), DbException::FAILED_QUERY); diff --git a/src/WordPress/Database/SQLiteDatabase.php b/src/WordPress/Database/SQLiteDatabase.php index ce7e17a50..731d53ecb 100644 --- a/src/WordPress/Database/SQLiteDatabase.php +++ b/src/WordPress/Database/SQLiteDatabase.php @@ -5,6 +5,8 @@ use lucatume\WPBrowser\WordPress\DbException; use lucatume\WPBrowser\WordPress\WPConfigFile; use PDO; +use PDOException; +use PDOStatement; use SQLite3; class SQLiteDatabase implements DatabaseInterface @@ -84,7 +86,7 @@ public function getTablePrefix(): string } /** - * @throws \PDOException if the attempt to connect to the requested database fails. + * @throws PDOException if the attempt to connect to the requested database fails. */ public function getPDO(): PDO { @@ -137,6 +139,14 @@ public function useDb(string $dbName): DatabaseInterface public function query(string $query, array $params = []): int { $stmt = $this->getPDO()->prepare($query); + + if (!$stmt instanceof PDOStatement) { + throw new DbException( + "Could not prepare `{$query}`: " . $this->getPDO()->errorInfo()[2], + DbException::PREPARE_FAILED + ); + } + $stmt->execute($params); return $stmt->rowCount(); } @@ -159,6 +169,14 @@ public function updateOption(string $name, mixed $value): int $query = "INSERT OR REPLACE INTO {$this->tablePrefix}options (option_name, option_value, autoload)" . " VALUES (:name, :value, :autoload)"; $stmt = $this->getPDO()->prepare($query); + + if (!$stmt instanceof PDOStatement) { + throw new DbException( + "Could not prepare `{$query}`: " . $this->getPDO()->errorInfo()[2], + DbException::PREPARE_FAILED + ); + } + $stmt->execute([':name' => $name, ':value' => $value, ':autoload' => 'yes']); return $stmt->rowCount(); } @@ -170,6 +188,14 @@ public function getOption(string $name, mixed $default = null): mixed { $query = "SELECT option_value FROM {$this->tablePrefix}options WHERE option_name = :name"; $stmt = $this->getPDO()->prepare($query); + + if (!$stmt instanceof PDOStatement) { + throw new DbException( + "Could not prepare `{$query}`: " . $this->getPDO()->errorInfo()[2], + DbException::PREPARE_FAILED + ); + } + $stmt->execute([':name' => $name]); $value = $stmt->fetchColumn(); if ($value === false) { diff --git a/src/WordPress/DbException.php b/src/WordPress/DbException.php index 0a751628e..d56f1a080 100644 --- a/src/WordPress/DbException.php +++ b/src/WordPress/DbException.php @@ -14,4 +14,5 @@ class DbException extends Exception public const DUMP_FILE_NOT_READABLE = 7; public const TABLE_PREFIX_NOT_FOUND = 8; public const FAILED_DUMP = 9; + public const PREPARE_FAILED = 10; } diff --git a/src/WordPress/FileRequests/FileRequest.php b/src/WordPress/FileRequests/FileRequest.php index 78c7a4fe2..3fbf2445d 100644 --- a/src/WordPress/FileRequests/FileRequest.php +++ b/src/WordPress/FileRequests/FileRequest.php @@ -143,6 +143,12 @@ public function execute(): array if (($errno & $this->errorLevel) === 0) { return true; } + + // Ignore E_WARNING from `fopen` calls: they are used by some plugins to try and check if a file exists. + if ($errno === E_WARNING && str_starts_with($errstr, 'fopen')) { + return true; + } + throw new ErrorException($errstr, 0, $errno, $errfile, $errline); }, E_ALL); diff --git a/src/WordPress/Installation.php b/src/WordPress/Installation.php index b09688114..49ed0fad8 100644 --- a/src/WordPress/Installation.php +++ b/src/WordPress/Installation.php @@ -4,6 +4,7 @@ use DirectoryIterator; use FilesystemIterator; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Process\ProcessException; use lucatume\WPBrowser\Process\WorkerException; use lucatume\WPBrowser\Utils\Filesystem as FS; @@ -17,9 +18,7 @@ use lucatume\WPBrowser\WordPress\Traits\WordPressChecks; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; -use SplFileInfo; use Symfony\Component\Process\Exception\ProcessFailedException; -use Symfony\Component\Process\Process; use Throwable; class Installation diff --git a/src/WordPress/InstallationState/Multisite.php b/src/WordPress/InstallationState/Multisite.php index b387fce3c..904d6255a 100644 --- a/src/WordPress/InstallationState/Multisite.php +++ b/src/WordPress/InstallationState/Multisite.php @@ -20,7 +20,6 @@ class Multisite implements InstallationStateInterface use ScaffoldedStateTrait; use ConfiguredStateTrait; use InstalledTrait; - use InstallationChecks; /** * @throws DbException diff --git a/src/WordPress/InstallationState/Single.php b/src/WordPress/InstallationState/Single.php index 15b282e6e..798e3e000 100644 --- a/src/WordPress/InstallationState/Single.php +++ b/src/WordPress/InstallationState/Single.php @@ -23,7 +23,6 @@ class Single implements InstallationStateInterface use ConfiguredStateTrait; use ScaffoldedStateTrait; use InstalledTrait; - use InstallationChecks; /** * @throws DbException diff --git a/src/WordPress/Source.php b/src/WordPress/Source.php index 9aa77eab0..3692bdbbb 100644 --- a/src/WordPress/Source.php +++ b/src/WordPress/Source.php @@ -5,11 +5,18 @@ use lucatume\WPBrowser\Utils\Download; use lucatume\WPBrowser\Utils\Filesystem as FS; use lucatume\WPBrowser\Utils\Zip; +use lucatume\WPBrowser\Utils\Env; class Source { public static function getForVersion(string $version = 'latest'): string { + $envSourceDir = Env::get('WPBROWSER_WORDPRESS_SOURCE_DIR', null); + + if (is_string($envSourceDir) && is_dir($envSourceDir . DIRECTORY_SEPARATOR . $version)) { + return $envSourceDir . DIRECTORY_SEPARATOR . $version; + } + $cacheDir = FS::cacheDir(); $versionsCacheDir = $cacheDir . '/wordpress/'; $sourceDir = $versionsCacheDir . $version; diff --git a/src/functions.php b/src/functions.php new file mode 100644 index 000000000..edc1e791a --- /dev/null +++ b/src/functions.php @@ -0,0 +1,47 @@ + $dependencies + */ +function useMemo(callable|array|string $callback, array $dependencies = []): mixed +{ + if (!is_callable($callback)) { + throw new InvalidArgumentException('The callback is not callable.'); + } + + /** @noinspection DebugFunctionUsageInspection */ + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); + $key = md5(serialize($backtrace)); + + $cached = Memo::get($key, serialize($dependencies), '__not_cached'); + + if ($cached !== '__not_cached') { + return $cached; + } + + $result = $callback(); + + Memo::set($key, serialize($dependencies), $result); + + return $result; +} + +/** + * @param callable|array{0: string, 1: string}|string $callback + * @param array $dependencies + */ +function useMemoString(callable|array|string $callback, array $dependencies = []): string +{ + $result = useMemo($callback, $dependencies); + if (!is_string($result)) { + throw new RuntimeException('The result of the callback is not a string.'); + } + return $result; +} diff --git a/src/shim.php b/src/shim.php new file mode 100644 index 000000000..92d5d457c --- /dev/null +++ b/src/shim.php @@ -0,0 +1,17 @@ + $projectDir . '/plugin_89/vendor/bin']); + $process = new Process($command, null, [ + 'COMPOSER_BIN_DIR' => $projectDir . '/plugin_89/vendor/bin' + ]); $process->setInput( "yes\n" // Yes, use recommended setup. @@ -96,21 +106,24 @@ public function should_scaffold_for_plugin_with_plugin_php_file(): void $process->mustRun(); // Remove the generated files that are not needed for the snapshot. - FS::rrmdir($projectDir . '/plugin_89/tests/Support/_generated'); + FS::rrmdir($projectDir . '/plugin_89/' . Codeception::supportDir() . '/_generated'); $this->assertFileExists($projectDir . '/plugin_89/vendor/bin/chromedriver'); $this->assertFileExists($projectDir . '/plugin_89/tests/_wordpress/wp-config.php'); - $this->assertFileExists($projectDir . '/plugin_89/tests/Support/Data/dump.sql'); + $this->assertFileExists($projectDir . '/plugin_89/' . Codeception::dataDir() . '/dump.sql'); // Remove generated or downloaded files that are not needed for the snapshot. FS::rrmdir($projectDir . '/plugin_89/tests/_wordpress'); FS::rrmdir($projectDir . '/plugin_89/vendor'); - unlink($projectDir . '/plugin_89/tests/Support/Data/dump.sql'); + FS::rrmdir($projectDir . '/plugin_89/var'); + unlink($projectDir . '/plugin_89/' . Codeception::dataDir() . '/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', - fn() => $this->replaceRandomPorts(...func_get_args())); + $this->assertMatchesDirectorySnapshot( + $projectDir . '/plugin_89', + fn() => $this->replaceRandomPorts(...func_get_args()) + ); } /** @@ -158,22 +171,24 @@ public function should_scaffold_for_plugin_with_non_plugin_php_file(): void $process->mustRun(); // Remove the generated files that are not needed for the snapshot. - FS::rrmdir($projectDir . '/plugin_89/tests/Support/_generated'); + FS::rrmdir($projectDir . '/plugin_89/' . Codeception::supportDir() . '/_generated'); $this->assertFileExists($projectDir . '/plugin_89/vendor/bin/chromedriver'); $this->assertFileExists($projectDir . '/plugin_89/tests/_wordpress/wp-config.php'); - $this->assertFileExists($projectDir . '/plugin_89/tests/Support/Data/dump.sql'); + $this->assertFileExists($projectDir . '/plugin_89/' . Codeception::dataDir() . '/dump.sql'); // Remove generated or downloaded files that are not needed for the snapshot. FS::rrmdir($projectDir . '/plugin_89/tests/_wordpress'); FS::rrmdir($projectDir . '/plugin_89/vendor'); FS::rrmdir($projectDir . '/plugin_89/var'); - unlink($projectDir . '/plugin_89/tests/Support/Data/dump.sql'); + unlink($projectDir . '/plugin_89/' . Codeception::dataDir() . '/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', - fn() => $this->replaceRandomPorts(...func_get_args())); + $this->assertMatchesDirectorySnapshot( + $projectDir . '/plugin_89', + fn() => $this->replaceRandomPorts(...func_get_args()) + ); } /** @@ -219,11 +234,19 @@ public function should_scaffold_for_plugin_with_plugin_php_file_custom(): void $process->mustRun(); // Remove the generated files that are not needed for the snapshot. - FS::rrmdir($projectDir . '/plugin_89/tests/Support/_generated'); + FS::rrmdir($projectDir . '/plugin_89/' . Codeception::supportDir() . '/_generated'); + FS::rrmdir($projectDir . '/plugin_89/tests/_wordpress'); + FS::rrmdir($projectDir . '/plugin_89/vendor'); + FS::rrmdir($projectDir . '/plugin_89/var'); + $dataDir = Codeception::dataDir($projectDir . '/plugin_89'); + file_exists($dataDir . "/dump.sql") && unlink($dataDir . "/dump.sql"); + // Random ports will change: visit the data to replace the random ports with a placeholder. - $this->assertMatchesDirectorySnapshot($projectDir . '/plugin_89', - fn() => $this->replaceRandomPorts(...func_get_args())); + $this->assertMatchesDirectorySnapshot( + $projectDir . '/plugin_89', + fn() => $this->replaceRandomPorts(...func_get_args()) + ); } /** @@ -269,11 +292,18 @@ public function should_scaffold_for_plugin_with_non_plugin_php_file_custom(): vo $process->mustRun(); // Remove the generated files that are not needed for the snapshot. - FS::rrmdir($projectDir . '/plugin_89/tests/Support/_generated'); + FS::rrmdir($projectDir . '/plugin_89/' . Codeception::supportDir() . '/_generated'); + FS::rrmdir($projectDir . '/plugin_89/tests/_wordpress'); + FS::rrmdir($projectDir . '/plugin_89/vendor'); + FS::rrmdir($projectDir . '/plugin_89/var'); + $dataDir = Codeception::dataDir($projectDir . '/plugin_89'); + file_exists($dataDir . "/dump.sql") && unlink($dataDir . "/dump.sql"); // Random ports will change: visit the data to replace the random ports with a placeholder. - $this->assertMatchesDirectorySnapshot($projectDir . '/plugin_89', - fn() => $this->replaceRandomPorts(...func_get_args())); + $this->assertMatchesDirectorySnapshot( + $projectDir . '/plugin_89', + fn() => $this->replaceRandomPorts(...func_get_args()) + ); } /** @@ -321,21 +351,24 @@ public function should_scaffold_for_theme_correctly(): void $process->mustRun(); // Remove the generated files that are not needed for the snapshot. - FS::rrmdir($projectDir . '/theme_23/tests/Support/_generated'); + FS::rrmdir($projectDir . '/theme_23/' . Codeception::supportDir() . '/_generated'); $this->assertFileExists($projectDir . '/theme_23/vendor/bin/chromedriver'); $this->assertFileExists($projectDir . '/theme_23/tests/_wordpress/wp-config.php'); - $this->assertFileExists($projectDir . '/theme_23/tests/Support/Data/dump.sql'); + $this->assertFileExists($projectDir . '/theme_23/' . Codeception::dataDir() . '/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/tests/Support/Data/dump.sql'); + FS::rrmdir($projectDir . '/theme_23/var'); + unlink($projectDir . '/theme_23/' . Codeception::dataDir() . '/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())); + $this->assertMatchesDirectorySnapshot( + $projectDir . '/theme_23', + fn() => $this->replaceRandomPorts(...func_get_args()) + ); } /** @@ -388,21 +421,24 @@ public function should_scaffold_for_child_theme_correctly(): void $process->mustRun(); // Remove the generated files that are not needed for the snapshot. - FS::rrmdir($projectDir . '/theme_23/tests/Support/_generated'); + FS::rrmdir($projectDir . '/theme_23/' . Codeception::supportDir() . '/_generated'); $this->assertFileExists($projectDir . '/theme_23/vendor/bin/chromedriver'); $this->assertFileExists($projectDir . '/theme_23/tests/_wordpress/wp-config.php'); - $this->assertFileExists($projectDir . '/theme_23/tests/Support/Data/dump.sql'); + $this->assertFileExists($projectDir . '/theme_23/' . Codeception::dataDir() . '/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/tests/Support/Data/dump.sql'); + FS::rrmdir($projectDir . '/theme_23/var'); + unlink($projectDir . '/theme_23/' . Codeception::dataDir() . '/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())); + $this->assertMatchesDirectorySnapshot( + $projectDir . '/theme_23', + fn() => $this->replaceRandomPorts(...func_get_args()) + ); } /** @@ -454,11 +490,18 @@ public function should_scaffold_for_theme_custom_correctly(): void $process->mustRun(); // Remove the generated files that are not needed for the snapshot. - FS::rrmdir($projectDir . '/theme_23/tests/Support/_generated'); + FS::rrmdir($projectDir . '/theme_23/' . Codeception::supportDir() . '/_generated'); + FS::rrmdir($projectDir . '/theme_23/tests/_wordpress'); + FS::rrmdir($projectDir . '/theme_23/vendor'); + FS::rrmdir($projectDir . '/theme_23/var'); + $dataDir = Codeception::dataDir($projectDir . '/theme_23'); + file_exists($dataDir . "/dump.sql") && unlink($dataDir . "/dump.sql"); // 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())); + $this->assertMatchesDirectorySnapshot( + $projectDir . '/theme_23', + fn() => $this->replaceRandomPorts(...func_get_args()) + ); } /** @@ -520,24 +563,26 @@ public function should_scaffold_for_single_site_correctly(): void $this->assertDirectoryExists($projectDir . '/site/wp-content/mu-plugins/sqlite-database-integration'); $this->assertFileExists($projectDir . '/site/wp-content/db.php'); - $this->assertFileExists($projectDir . '/site/tests/Support/Data/dump.sql'); - $this->assertFileExists($projectDir . '/site/tests/Support/Data/db.sqlite'); + $this->assertFileExists($projectDir . '/site/' . Codeception::dataDir() . '/dump.sql'); + $this->assertFileExists($projectDir . '/site/' . Codeception::dataDir() . '/db.sqlite'); $this->assertFileExists($projectDir . '/site/tests/EndToEnd/ActivationCest.php'); $this->assertFileExists($projectDir . '/site/tests/Integration/SampleTest.php'); $this->assertFileExists($projectDir . '/site/codeception.yml'); // Remove the generated files that are not needed for the snapshot. - FS::rrmdir($projectDir . '/site/tests/Support/_generated'); + FS::rrmdir($projectDir . '/site/' . Codeception::supportDir() . '/_generated'); // Remove the binary sqlite file and the dump file. - unlink($projectDir . '/site/tests/Support/Data/db.sqlite'); - unlink($projectDir . '/site/tests/Support/Data/dump.sql'); + unlink($projectDir . '/site/' . Codeception::dataDir() . '/db.sqlite'); + unlink($projectDir . '/site/' . Codeception::dataDir() . '/dump.sql'); $this->assertMatchesStringSnapshot(file_get_contents($projectDir . '/site/codeception.yml')); // Random ports will change: visit the data to replace the random ports with a placeholder. - $this->assertMatchesDirectorySnapshot($projectDir . '/site/tests', + $this->assertMatchesDirectorySnapshot( + $projectDir . '/site/tests', function (array $expected, array $actual, string $file) { return $this->replaceRandomPorts($expected, $actual, $file); - }); + } + ); } /** @@ -599,24 +644,26 @@ public function should_scaffold_for_multi_site_correctly(): void $this->assertDirectoryExists($projectDir . '/site/wp-content/mu-plugins/sqlite-database-integration'); $this->assertFileExists($projectDir . '/site/wp-content/db.php'); - $this->assertFileExists($projectDir . '/site/tests/Support/Data/dump.sql'); - $this->assertFileExists($projectDir . '/site/tests/Support/Data/db.sqlite'); + $this->assertFileExists($projectDir . '/site/' . Codeception::dataDir() . '/dump.sql'); + $this->assertFileExists($projectDir . '/site/' . Codeception::dataDir() . '/db.sqlite'); $this->assertFileExists($projectDir . '/site/tests/EndToEnd/ActivationCest.php'); $this->assertFileExists($projectDir . '/site/tests/Integration/SampleTest.php'); $this->assertFileExists($projectDir . '/site/codeception.yml'); // Remove the generated files that are not needed for the snapshot. - FS::rrmdir($projectDir . '/site/tests/Support/_generated'); + FS::rrmdir($projectDir . '/site/' . Codeception::supportDir() . '/_generated'); // Remove the binary sqlite file and the dump file. - unlink($projectDir . '/site/tests/Support/Data/db.sqlite'); - unlink($projectDir . '/site/tests/Support/Data/dump.sql'); + unlink($projectDir . '/site/' . Codeception::dataDir() . '/db.sqlite'); + unlink($projectDir . '/site/' . Codeception::dataDir() . '/dump.sql'); $this->assertMatchesStringSnapshot(file_get_contents($projectDir . '/site/codeception.yml')); // Random ports will change: visit the data to replace the random ports with a placeholder. - $this->assertMatchesDirectorySnapshot($projectDir . '/site/tests', + $this->assertMatchesDirectorySnapshot( + $projectDir . '/site/tests', function (array $expected, array $actual, string $file) { return $this->replaceRandomPorts($expected, $actual, $file); - }); + } + ); } /** @@ -626,14 +673,9 @@ function (array $expected, array $actual, string $file) { */ public function should_scaffold_correctly_on_site_with_non_default_structure(): void { - $composerFileCode = <<< EOT -{ - "name": "acme/site-project", - "type": "project", - "require": {}, - "require-dev": {} -} -EOT; + if (PHP_VERSION < 8.0) { + $this->markTestSkipped('This test requires PHP 8.0 or higher.'); + } $projectDir = FS::tmpDir('setup_'); $dbName = Random::dbName(); @@ -661,10 +703,12 @@ public function should_scaffold_correctly_on_site_with_non_default_structure(): $process->mustRun(); // Remove some hashed files. - FS::rrmdir($projectDir . '/tests/Support/_generated'); + FS::rrmdir($projectDir . '/' . Codeception::supportDir() . '/_generated'); // Random ports will change: visit the data to replace the random ports with a placeholder. - $this->assertMatchesDirectorySnapshot($projectDir . '/tests', - fn() => $this->replaceRandomPorts(...func_get_args())); + $this->assertMatchesDirectorySnapshot( + $projectDir . '/tests', + fn() => $this->replaceRandomPorts(...func_get_args()) + ); } } diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_child_theme_correctly__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_child_theme_correctly__0.snapshot new file mode 100644 index 000000000..e665dea47 --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_child_theme_correctly__0.snapshot @@ -0,0 +1,358 @@ +>>> /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%' + path: '/' + window_size: 1200x1000 + capabilities: + "goog:chromeOptions": + args: + - "--headless" + - "--disable-gpu" + - "--disable-dev-shm-usage" + - "--proxy-server='direct://'" + - "--proxy-bypass-list=*" + - "--no-sandbox" + 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_theme_active(): void + { + $this->assertTrue(wp_get_theme()->stylesheet === 'theme_23'); + } +} +<<< /tests/Integration/SampleTest.php <<< + +>>> /tests/Integration/_bootstrap.php >>> +>> /tests/_support/IntegrationTester.php >>> +>> /tests/_support/EndToEndTester.php >>> +>> /tests/_support/Helper/EndToEnd.php >>> +>> /tests/_support/Helper/Integration.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/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->amOnAdminPage('/themes.php'); + + $I->seeElement('.theme.active[data-slug="theme-23"]'); + } +} + +<<< /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, +# 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:62160 +WORDPRESS_DOMAIN=localhost:62160 + +# 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=20672 + +# The port on which the PHP built-in server will serve the WordPress installation. +BUILTIN_SERVER_PORT=62160 + +<<< /tests/.env <<< + +>>> /tests/_output/.gitkeep >>> + +<<< /tests/_output/.gitkeep <<< + +>>> /tests/_data/.gitkeep >>> + +<<< /tests/_data/.gitkeep <<< + +>>> /codeception.yml >>> +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/_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: '%WORDPRESS_ROOT_DIR%' + env: + DATABASE_TYPE: sqlite + DB_ENGINE: sqlite + DB_DIR: '%codecept_root_dir%/tests/_data' + DB_FILE: db.sqlite + 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 + - lucatume\WPBrowser\Command\ChromedriverUpdate + +<<< /codeception.yml <<< + +>>> /style.css >>> +/* +Theme Name: Theme 23 +Template: twentytwenty +*/ +<<< /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/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_multi_site_correctly__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_multi_site_correctly__0.snapshot new file mode 100644 index 000000000..a0d8afd72 --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_multi_site_correctly__0.snapshot @@ -0,0 +1,310 @@ +>>> /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%' + path: '/' + window_size: 1200x1000 + capabilities: + "goog:chromeOptions": + args: + - "--headless" + - "--disable-gpu" + - "--disable-dev-shm-usage" + - "--proxy-server='direct://'" + - "--proxy-bypass-list=*" + - "--no-sandbox" + 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%' + +<<< /EndToEnd.suite.yml <<< + +>>> /Integration/SampleTest.php >>> +post->create_and_get(); + + $this->assertInstanceOf(\WP_Post::class, $post); + } + + public function test_default_users(): void + { + $this->assertEquals(0, wp_get_current_user()->ID); + + wp_set_current_user(1); + + $this->assertEquals(1, wp_get_current_user()->ID); + $this->assertEquals('admin', wp_get_current_user()->user_login); + } +} +<<< /Integration/SampleTest.php <<< + +>>> /Integration/_bootstrap.php >>> +>> /_support/IntegrationTester.php >>> +>> /_support/EndToEndTester.php >>> +>> /_support/Helper/EndToEnd.php >>> +>> /_support/Helper/Integration.php >>> +>> /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: '' +<<< /Integration.suite.yml <<< + +>>> /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. + */ +<<< /EndToEnd/_bootstrap.php <<< + +>>> /EndToEnd/ActivationCest.php >>> +amOnPage('/'); + $I->seeElement('body'); + } + + public function test_can_login_as_admin(EndToEndTester $I): void + { + $I->loginAsAdmin(); + $I->amOnAdminPage('/'); + $I->seeElement('body.wp-admin'); + } +} + +<<< /EndToEnd/ActivationCest.php <<< + +>>> /.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 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/_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:9750 +WORDPRESS_DOMAIN=localhost:9750 + +# 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=51597 + +# The port on which the PHP built-in server will serve the WordPress installation. +BUILTIN_SERVER_PORT=9750 + +<<< /.env <<< + +>>> /_output/.gitkeep >>> + +<<< /_output/.gitkeep <<< + +>>> /_data/.gitkeep >>> + +<<< /_data/.gitkeep <<< \ No newline at end of file diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_multi_site_correctly__0.snapshot.txt b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_multi_site_correctly__0.snapshot.txt new file mode 100644 index 000000000..e8f855ebd --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_multi_site_correctly__0.snapshot.txt @@ -0,0 +1,38 @@ +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/_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: '%WORDPRESS_ROOT_DIR%' + env: + DATABASE_TYPE: sqlite + DB_ENGINE: sqlite + DB_DIR: '%codecept_root_dir%/tests/_data' + DB_FILE: db.sqlite + 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 + - lucatume\WPBrowser\Command\ChromedriverUpdate diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_plugin_with_non_plugin_php_file__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_plugin_with_non_plugin_php_file__0.snapshot new file mode 100644 index 000000000..8b32b45fa --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_plugin_with_non_plugin_php_file__0.snapshot @@ -0,0 +1,364 @@ +>>> /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%' + path: '/' + window_size: 1200x1000 + capabilities: + "goog:chromeOptions": + args: + - "--headless" + - "--disable-gpu" + - "--disable-dev-shm-usage" + - "--proxy-server='direct://'" + - "--proxy-bypass-list=*" + - "--no-sandbox" + 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/_support/IntegrationTester.php >>> +>> /tests/_support/EndToEndTester.php >>> +>> /tests/_support/Helper/EndToEnd.php >>> +>> /tests/_support/Helper/Integration.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: ['plugin_89/main-file.php'] + theme: '' +<<< /tests/Integration.suite.yml <<< + +>>> /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, +# 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:19743 +WORDPRESS_DOMAIN=localhost:19743 + +# 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=64617 + +# The port on which the PHP built-in server will serve the WordPress installation. +BUILTIN_SERVER_PORT=19743 + +<<< /tests/.env <<< + +>>> /tests/_output/.gitkeep >>> + +<<< /tests/_output/.gitkeep <<< + +>>> /tests/_data/.gitkeep >>> + +<<< /tests/_data/.gitkeep <<< + +>>> /codeception.yml >>> +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/_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: '%WORDPRESS_ROOT_DIR%' + env: + DATABASE_TYPE: sqlite + DB_ENGINE: sqlite + DB_DIR: '%codecept_root_dir%/tests/_data' + DB_FILE: db.sqlite + 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 + - lucatume\WPBrowser\Command\ChromedriverUpdate + +<<< /codeception.yml <<< + +>>> /composer.json >>> +{ + "name": "acme/plugin-89", + "type": "wordpress-plugin", + "require": {}, + "require-dev": {} +} +<<< /composer.json <<< + +>>> /main-file.php >>> +>> /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%' + path: '/' + window_size: 1200x1000 + capabilities: + "goog:chromeOptions": + args: + - "--headless" + - "--disable-gpu" + - "--disable-dev-shm-usage" + - "--proxy-server='direct://'" + - "--proxy-bypass-list=*" + - "--no-sandbox" + 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.php')); + } +} +<<< /tests/Integration/SampleTest.php <<< + +>>> /tests/Integration/_bootstrap.php >>> +>> /tests/_support/IntegrationTester.php >>> +>> /tests/_support/EndToEndTester.php >>> +>> /tests/_support/Helper/EndToEnd.php >>> +>> /tests/_support/Helper/Integration.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: ['plugin_89/main.php'] + theme: '' +<<< /tests/Integration.suite.yml <<< + +>>> /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, +# 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:15161 +WORDPRESS_DOMAIN=localhost:15161 + +# 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=59343 + +# The port on which the PHP built-in server will serve the WordPress installation. +BUILTIN_SERVER_PORT=15161 + +<<< /tests/.env <<< + +>>> /tests/_output/.gitkeep >>> + +<<< /tests/_output/.gitkeep <<< + +>>> /tests/_data/.gitkeep >>> + +<<< /tests/_data/.gitkeep <<< + +>>> /codeception.yml >>> +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/_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: '%WORDPRESS_ROOT_DIR%' + env: + DATABASE_TYPE: sqlite + DB_ENGINE: sqlite + DB_DIR: '%codecept_root_dir%/tests/_data' + DB_FILE: db.sqlite + 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 + - lucatume\WPBrowser\Command\ChromedriverUpdate + +<<< /codeception.yml <<< + +>>> /composer.json >>> +{ + "name": "acme/plugin-89", + "type": "wordpress-plugin", + "require": {}, + "require-dev": {} +} +<<< /composer.json <<< \ No newline at end of file diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_plugin_with_plugin_php_file__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_plugin_with_plugin_php_file__0.snapshot new file mode 100644 index 000000000..253291183 --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_plugin_with_plugin_php_file__0.snapshot @@ -0,0 +1,364 @@ +>>> /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%' + path: '/' + window_size: 1200x1000 + capabilities: + "goog:chromeOptions": + args: + - "--headless" + - "--disable-gpu" + - "--disable-dev-shm-usage" + - "--proxy-server='direct://'" + - "--proxy-bypass-list=*" + - "--no-sandbox" + 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/_support/IntegrationTester.php >>> +>> /tests/_support/EndToEndTester.php >>> +>> /tests/_support/Helper/EndToEnd.php >>> +>> /tests/_support/Helper/Integration.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: ['plugin_89/plugin.php'] + theme: '' +<<< /tests/Integration.suite.yml <<< + +>>> /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, +# 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:17866 +WORDPRESS_DOMAIN=localhost:17866 + +# 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=41473 + +# The port on which the PHP built-in server will serve the WordPress installation. +BUILTIN_SERVER_PORT=17866 + +<<< /tests/.env <<< + +>>> /tests/_output/.gitkeep >>> + +<<< /tests/_output/.gitkeep <<< + +>>> /tests/_data/.gitkeep >>> + +<<< /tests/_data/.gitkeep <<< + +>>> /codeception.yml >>> +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/_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: '%WORDPRESS_ROOT_DIR%' + env: + DATABASE_TYPE: sqlite + DB_ENGINE: sqlite + DB_DIR: '%codecept_root_dir%/tests/_data' + DB_FILE: db.sqlite + 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 + - lucatume\WPBrowser\Command\ChromedriverUpdate + +<<< /codeception.yml <<< + +>>> /composer.json >>> +{ + "name": "acme/plugin-89", + "type": "wordpress-plugin", + "require": {}, + "require-dev": {} +} +<<< /composer.json <<< \ No newline at end of file diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_plugin_with_plugin_php_file_custom__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_plugin_with_plugin_php_file_custom__0.snapshot new file mode 100644 index 000000000..a5dbf80eb --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_plugin_with_plugin_php_file_custom__0.snapshot @@ -0,0 +1,364 @@ +>>> /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%' + path: '/' + window_size: 1200x1000 + capabilities: + "goog:chromeOptions": + args: + - "--headless" + - "--disable-gpu" + - "--disable-dev-shm-usage" + - "--proxy-server='direct://'" + - "--proxy-bypass-list=*" + - "--no-sandbox" + 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/_support/IntegrationTester.php >>> +>> /tests/_support/EndToEndTester.php >>> +>> /tests/_support/Helper/EndToEnd.php >>> +>> /tests/_support/Helper/Integration.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: ['plugin_89/plugin.php'] + theme: '' +<<< /tests/Integration.suite.yml <<< + +>>> /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, +# 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:24026 +WORDPRESS_DOMAIN=localhost:24026 + +# 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=36951 + +# The port on which the PHP built-in server will serve the WordPress installation. +BUILTIN_SERVER_PORT=24026 + +<<< /tests/.env <<< + +>>> /tests/_output/.gitkeep >>> + +<<< /tests/_output/.gitkeep <<< + +>>> /tests/_data/.gitkeep >>> + +<<< /tests/_data/.gitkeep <<< + +>>> /codeception.yml >>> +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/_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: '%WORDPRESS_ROOT_DIR%' + env: + DATABASE_TYPE: sqlite + DB_ENGINE: sqlite + DB_DIR: '%codecept_root_dir%/tests/_data' + DB_FILE: db.sqlite + 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 + - lucatume\WPBrowser\Command\ChromedriverUpdate + +<<< /codeception.yml <<< + +>>> /composer.json >>> +{ + "name": "acme/plugin-89", + "type": "wordpress-plugin", + "require": {}, + "require-dev": {} +} +<<< /composer.json <<< \ No newline at end of file diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_single_site_correctly__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_single_site_correctly__0.snapshot new file mode 100644 index 000000000..572dc25bf --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_single_site_correctly__0.snapshot @@ -0,0 +1,310 @@ +>>> /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%' + path: '/' + window_size: 1200x1000 + capabilities: + "goog:chromeOptions": + args: + - "--headless" + - "--disable-gpu" + - "--disable-dev-shm-usage" + - "--proxy-server='direct://'" + - "--proxy-bypass-list=*" + - "--no-sandbox" + 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%' + +<<< /EndToEnd.suite.yml <<< + +>>> /Integration/SampleTest.php >>> +post->create_and_get(); + + $this->assertInstanceOf(\WP_Post::class, $post); + } + + public function test_default_users(): void + { + $this->assertEquals(0, wp_get_current_user()->ID); + + wp_set_current_user(1); + + $this->assertEquals(1, wp_get_current_user()->ID); + $this->assertEquals('admin', wp_get_current_user()->user_login); + } +} +<<< /Integration/SampleTest.php <<< + +>>> /Integration/_bootstrap.php >>> +>> /_support/IntegrationTester.php >>> +>> /_support/EndToEndTester.php >>> +>> /_support/Helper/EndToEnd.php >>> +>> /_support/Helper/Integration.php >>> +>> /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: '' +<<< /Integration.suite.yml <<< + +>>> /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. + */ +<<< /EndToEnd/_bootstrap.php <<< + +>>> /EndToEnd/ActivationCest.php >>> +amOnPage('/'); + $I->seeElement('body'); + } + + public function test_can_login_as_admin(EndToEndTester $I): void + { + $I->loginAsAdmin(); + $I->amOnAdminPage('/'); + $I->seeElement('body.wp-admin'); + } +} + +<<< /EndToEnd/ActivationCest.php <<< + +>>> /.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 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/_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:17156 +WORDPRESS_DOMAIN=localhost:17156 + +# 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=30456 + +# The port on which the PHP built-in server will serve the WordPress installation. +BUILTIN_SERVER_PORT=17156 + +<<< /.env <<< + +>>> /_output/.gitkeep >>> + +<<< /_output/.gitkeep <<< + +>>> /_data/.gitkeep >>> + +<<< /_data/.gitkeep <<< \ No newline at end of file diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_single_site_correctly__0.snapshot.txt b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_single_site_correctly__0.snapshot.txt new file mode 100644 index 000000000..e8f855ebd --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_single_site_correctly__0.snapshot.txt @@ -0,0 +1,38 @@ +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/_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: '%WORDPRESS_ROOT_DIR%' + env: + DATABASE_TYPE: sqlite + DB_ENGINE: sqlite + DB_DIR: '%codecept_root_dir%/tests/_data' + DB_FILE: db.sqlite + 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 + - lucatume\WPBrowser\Command\ChromedriverUpdate diff --git a/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_theme_correctly__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_theme_correctly__0.snapshot new file mode 100644 index 000000000..6370c41ae --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_theme_correctly__0.snapshot @@ -0,0 +1,357 @@ +>>> /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%' + path: '/' + window_size: 1200x1000 + capabilities: + "goog:chromeOptions": + args: + - "--headless" + - "--disable-gpu" + - "--disable-dev-shm-usage" + - "--proxy-server='direct://'" + - "--proxy-bypass-list=*" + - "--no-sandbox" + 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_theme_active(): void + { + $this->assertTrue(wp_get_theme()->stylesheet === 'theme_23'); + } +} +<<< /tests/Integration/SampleTest.php <<< + +>>> /tests/Integration/_bootstrap.php >>> +>> /tests/_support/IntegrationTester.php >>> +>> /tests/_support/EndToEndTester.php >>> +>> /tests/_support/Helper/EndToEnd.php >>> +>> /tests/_support/Helper/Integration.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/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->amOnAdminPage('/themes.php'); + + $I->seeElement('.theme.active[data-slug="theme-23"]'); + } +} + +<<< /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, +# 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:16536 +WORDPRESS_DOMAIN=localhost:16536 + +# 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=55746 + +# The port on which the PHP built-in server will serve the WordPress installation. +BUILTIN_SERVER_PORT=16536 + +<<< /tests/.env <<< + +>>> /tests/_output/.gitkeep >>> + +<<< /tests/_output/.gitkeep <<< + +>>> /tests/_data/.gitkeep >>> + +<<< /tests/_data/.gitkeep <<< + +>>> /codeception.yml >>> +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/_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: '%WORDPRESS_ROOT_DIR%' + env: + DATABASE_TYPE: sqlite + DB_ENGINE: sqlite + DB_DIR: '%codecept_root_dir%/tests/_data' + DB_FILE: db.sqlite + 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 + - lucatume\WPBrowser\Command\ChromedriverUpdate + +<<< /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/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_theme_custom_correctly__0.snapshot b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_theme_custom_correctly__0.snapshot new file mode 100644 index 000000000..ec70776ce --- /dev/null +++ b/tests/unit/Codeception/Template/__snapshots__/WpbrowserTest__3.5__should_scaffold_for_theme_custom_correctly__0.snapshot @@ -0,0 +1,364 @@ +>>> /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%' + path: '/' + window_size: 1200x1000 + capabilities: + "goog:chromeOptions": + args: + - "--headless" + - "--disable-gpu" + - "--disable-dev-shm-usage" + - "--proxy-server='direct://'" + - "--proxy-bypass-list=*" + - "--no-sandbox" + 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_theme_active(): void + { + $this->assertTrue(wp_get_theme()->stylesheet === 'theme_23'); + } +} +<<< /tests/Integration/SampleTest.php <<< + +>>> /tests/Integration/_bootstrap.php >>> +>> /tests/_support/IntegrationTester.php >>> +>> /tests/_support/EndToEndTester.php >>> +>> /tests/_support/Helper/EndToEnd.php >>> +>> /tests/_support/Helper/Integration.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/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->amOnAdminPage('/themes.php'); + + $I->seeElement('.theme.active[data-slug="theme-23"]'); + } +} + +<<< /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, +# 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:14852 +WORDPRESS_DOMAIN=localhost:14852 + +# 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=48584 + +# The port on which the PHP built-in server will serve the WordPress installation. +BUILTIN_SERVER_PORT=14852 + +<<< /tests/.env <<< + +>>> /tests/_output/.gitkeep >>> + +<<< /tests/_output/.gitkeep <<< + +>>> /tests/_data/.gitkeep >>> + +<<< /tests/_data/.gitkeep <<< + +>>> /codeception.yml >>> +support_namespace: Support +paths: + tests: tests + output: tests/_output + data: tests/_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: '%WORDPRESS_ROOT_DIR%' + env: + DATABASE_TYPE: sqlite + DB_ENGINE: sqlite + DB_DIR: '%codecept_root_dir%/tests/_data' + DB_FILE: db.sqlite + 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 + - lucatume\WPBrowser\Command\ChromedriverUpdate + +<<< /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/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 index b6df4dd10..60a5492fc 100644 --- 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 @@ -50,6 +50,46 @@ modules: <<< /tests/EndToEnd.suite.yml <<< +>>> /tests/Integration/SampleTest.php >>> +post->create_and_get(); + + $this->assertInstanceOf(\WP_Post::class, $post); + } + + public function test_theme_active(): void + { + $this->assertTrue(wp_get_theme()->stylesheet === 'theme_23'); + } +} +<<< /tests/Integration/SampleTest.php <<< + >>> /tests/Integration/_bootstrap.php >>> >> /tests/EndToEnd/ActivationCest.php >>> +loginAsAdmin(); + $I->amOnAdminPage('/themes.php'); + + $I->seeElement('.theme.active[data-slug="theme-23"]'); + } +} + +<<< /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, @@ -197,8 +257,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:52118 -WORDPRESS_DOMAIN=localhost:52118 +WORDPRESS_URL=http://localhost:49167 +WORDPRESS_DOMAIN=localhost:49167 # The username and password of the administrator user of the WordPress site used in end-to-end tests. WORDPRESS_ADMIN_USER=admin @@ -206,10 +266,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=52138 +CHROMEDRIVER_PORT=29046 # The port on which the PHP built-in server will serve the WordPress installation. -BUILTIN_SERVER_PORT=52118 +BUILTIN_SERVER_PORT=49167 <<< /tests/.env <<< 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 index 141cd6d20..f5533da6c 100644 --- 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 @@ -50,6 +50,46 @@ modules: <<< /tests/EndToEnd.suite.yml <<< +>>> /tests/Integration/SampleTest.php >>> +post->create_and_get(); + + $this->assertInstanceOf(\WP_Post::class, $post); + } + + public function test_theme_active(): void + { + $this->assertTrue(wp_get_theme()->stylesheet === 'theme_23'); + } +} +<<< /tests/Integration/SampleTest.php <<< + >>> /tests/Integration/_bootstrap.php >>> >> /tests/EndToEnd/ActivationCest.php >>> +loginAsAdmin(); + $I->amOnAdminPage('/themes.php'); + + $I->seeElement('.theme.active[data-slug="theme-23"]'); + } +} + +<<< /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, @@ -197,8 +257,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:52071 -WORDPRESS_DOMAIN=localhost:52071 +WORDPRESS_URL=http://localhost:7039 +WORDPRESS_DOMAIN=localhost:7039 # The username and password of the administrator user of the WordPress site used in end-to-end tests. WORDPRESS_ADMIN_USER=admin @@ -206,10 +266,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=52090 +CHROMEDRIVER_PORT=48529 # The port on which the PHP built-in server will serve the WordPress installation. -BUILTIN_SERVER_PORT=52071 +BUILTIN_SERVER_PORT=7039 <<< /tests/.env <<< diff --git a/tests/unit/_bootstrap.php b/tests/unit/_bootstrap.php index 4444c4a59..c38378f27 100644 --- a/tests/unit/_bootstrap.php +++ b/tests/unit/_bootstrap.php @@ -1,4 +1,14 @@ FS::realpath(FS::cacheDir() . '/wordpress'), + 'WPBROWSER_CHROMEDRIVER_ZIP_FILE' => FS::realpath(FS::cacheDir() . '/chromedriver/chromedriver.zip') + ] +); diff --git a/tests/unit/lucatume/WPBrowser/Command/RunAllTest.php b/tests/unit/lucatume/WPBrowser/Command/RunAllTest.php index 364f2b0e6..419b4175d 100644 --- a/tests/unit/lucatume/WPBrowser/Command/RunAllTest.php +++ b/tests/unit/lucatume/WPBrowser/Command/RunAllTest.php @@ -6,13 +6,13 @@ use Codeception\Configuration; use Codeception\Test\Unit; use Exception; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Command\RunAll; use lucatume\WPBrowser\Tests\Traits\ClassStubs; use lucatume\WPBrowser\Tests\Traits\UopzFunctions; use PHPUnit\Framework\Assert; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\BufferedOutput; -use Symfony\Component\Process\Process; use tad\Codeception\SnapshotAssertions\SnapshotAssertions; class RunAllTest extends Unit diff --git a/tests/unit/lucatume/WPBrowser/Command/__snapshots__/RunAllTest__3.5__test_description_and_command_name__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Command/__snapshots__/RunAllTest__3.5__test_description_and_command_name__0.snapshot.txt new file mode 100644 index 000000000..201292dbd --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Command/__snapshots__/RunAllTest__3.5__test_description_and_command_name__0.snapshot.txt @@ -0,0 +1 @@ +run - Runs all the test suites, each in a separate process. \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Events/DispatcherTest.php b/tests/unit/lucatume/WPBrowser/Events/DispatcherTest.php index c2f5431e9..05af2c6a9 100644 --- a/tests/unit/lucatume/WPBrowser/Events/DispatcherTest.php +++ b/tests/unit/lucatume/WPBrowser/Events/DispatcherTest.php @@ -6,7 +6,6 @@ use Codeception\Events; use Codeception\Test\Unit; use lucatume\WPBrowser\Tests\Traits\UopzFunctions; -use lucatume\WPBrowser\Utils\Property; use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcher; diff --git a/tests/unit/lucatume/WPBrowser/Module/Support/DbDumpTest.php b/tests/unit/lucatume/WPBrowser/Events/Module/Support/DbDumpTest.php similarity index 95% rename from tests/unit/lucatume/WPBrowser/Module/Support/DbDumpTest.php rename to tests/unit/lucatume/WPBrowser/Events/Module/Support/DbDumpTest.php index 1b3d7bec8..fe6e85a29 100644 --- a/tests/unit/lucatume/WPBrowser/Module/Support/DbDumpTest.php +++ b/tests/unit/lucatume/WPBrowser/Events/Module/Support/DbDumpTest.php @@ -31,8 +31,8 @@ public function it_should_not_replace_the_site_domain_if_site_domain_is_same(): $sql = $sut->replaceSiteDomainInSqlString($sql); - Assert::assertMatchesRegularExpression('~.*original.dev.*~', $sql); - Assert::assertDoesNotMatchRegularExpression('/.*some-wp.dev.*/', $sql); + $this->assertRegExp('~.*original.dev.*~', $sql); + $this->assertNotRegExp('/.*some-wp.dev.*/', $sql); } /** @@ -52,8 +52,8 @@ public function it_should_replace_the_site_domain_in_dump(): void $sql = $sut->replaceSiteDomainInSqlString($sql); - Assert::assertMatchesRegularExpression('/.*some-wp.dev.*/', $sql); - Assert::assertDoesNotMatchRegularExpression('~.*original.dev/wp.*~', $sql); + $this->assertRegExp('/.*some-wp.dev.*/', $sql); + $this->assertNotRegExp('~.*original.dev/wp.*~', $sql); } /** @@ -75,8 +75,8 @@ public function it_should_replace_https_schema_with_http(): void $sql = $sut->replaceSiteDomainInSqlString($sql); - Assert::assertMatchesRegularExpression('~.*http:\\/\\/some-wp.dev.*~', $sql); - Assert::assertDoesNotMatchRegularExpression('~.*https:\\/\\/original.dev/wp.*~', $sql); + $this->assertRegExp('~.*http:\\/\\/some-wp.dev.*~', $sql); + $this->assertNotRegExp('~.*https:\\/\\/original.dev/wp.*~', $sql); } /** @@ -98,8 +98,8 @@ public function it_should_replace_http_schema_with_https(): void $sql = $sut->replaceSiteDomainInSqlString($sql); - Assert::assertMatchesRegularExpression('~.*https:\\/\\/some-wp.dev.*~', $sql); - Assert::assertDoesNotMatchRegularExpression('~.*https:\\/\\/original.dev/wp.*~', $sql); + $this->assertRegExp('~.*https:\\/\\/some-wp.dev.*~', $sql); + $this->assertNotRegExp('~.*https:\\/\\/original.dev/wp.*~', $sql); } /** @@ -132,7 +132,7 @@ public function it_should_not_replace_domain_in_sites_and_blogs_table_if_domain_ $sql = $sut->replaceSiteDomainInMultisiteSqlString($sut->replaceSiteDomainInSqlString($sql)); - Assert::assertMatchesRegularExpression('~.*original.dev/wp.*~', $sql); + $this->assertRegExp('~.*original.dev/wp.*~', $sql); } /** @@ -165,8 +165,8 @@ public function it_should_replace_domain_in_sites_and_blogs_table_if_domain_is_n $sql = $sut->replaceSiteDomainInMultisiteSqlString($sut->replaceSiteDomainInSqlString($sql)); - Assert::assertMatchesRegularExpression('~.*some-wp.dev.*~', $sql); - Assert::assertDoesNotMatchRegularExpression('~.*original.dev/wp.*~', $sql); + $this->assertRegExp('~.*some-wp.dev.*~', $sql); + $this->assertNotRegExp('~.*original.dev/wp.*~', $sql); } /** diff --git a/tests/unit/lucatume/WPBrowser/Module/WPBrowserMethodsTest.php b/tests/unit/lucatume/WPBrowser/Events/Module/WPBrowserMethodsTest.php similarity index 100% rename from tests/unit/lucatume/WPBrowser/Module/WPBrowserMethodsTest.php rename to tests/unit/lucatume/WPBrowser/Events/Module/WPBrowserMethodsTest.php diff --git a/tests/unit/lucatume/WPBrowser/Module/WPCLITest.php b/tests/unit/lucatume/WPBrowser/Events/Module/WPCLITest.php similarity index 98% rename from tests/unit/lucatume/WPBrowser/Module/WPCLITest.php rename to tests/unit/lucatume/WPBrowser/Events/Module/WPCLITest.php index 2f64735e9..0488d4bfb 100644 --- a/tests/unit/lucatume/WPBrowser/Module/WPCLITest.php +++ b/tests/unit/lucatume/WPBrowser/Events/Module/WPCLITest.php @@ -24,9 +24,18 @@ class WPCLITest extends Unit use TmpFilesCleanup; protected $backupGlobals = false; - private static ?Installation $installation = null; - protected bool $cleanupTmpAfterTest = false; - private array $cleanupAfter = []; + /** + * @var \lucatume\WPBrowser\WordPress\Installation|null + */ + private static $installation; + /** + * @var bool + */ + protected $cleanupTmpAfterTest = false; + /** + * @var mixed[] + */ + private $cleanupAfter = []; public function _before(): void { @@ -66,6 +75,10 @@ public function _after() */ public static function removeInstallation(): void { + if (!self::$installation instanceof Installation) { + return; + } + FS::rrmdir(self::$installation->getWpRootDir()); } @@ -408,10 +421,11 @@ public function strictArgsInlineValuesProvider(): array * * @test * @dataProvider strictArgsInlineValuesProvider + * @param mixed $configValue */ public function should_allow_overriding_strict_args_in_command_line( string $strictArg, - mixed $configValue, + $configValue, string $inlineValue ): void { $wpcli = $this->module([ diff --git a/tests/unit/lucatume/WPBrowser/Module/WPDbTest.php b/tests/unit/lucatume/WPBrowser/Events/Module/WPDbTest.php similarity index 98% rename from tests/unit/lucatume/WPBrowser/Module/WPDbTest.php rename to tests/unit/lucatume/WPBrowser/Events/Module/WPDbTest.php index 9ccddb27f..c375be975 100644 --- a/tests/unit/lucatume/WPBrowser/Module/WPDbTest.php +++ b/tests/unit/lucatume/WPBrowser/Events/Module/WPDbTest.php @@ -8,6 +8,7 @@ use Codeception\Test\Unit; use lucatume\WPBrowser\Module\Support\DbDump; use lucatume\WPBrowser\Tests\Traits\LoopIsolation; +use lucatume\WPBrowser\Tests\Traits\TmpFilesCleanup; use lucatume\WPBrowser\Tests\Traits\UopzFunctions; use lucatume\WPBrowser\Utils\Env; use lucatume\WPBrowser\Utils\Filesystem as FS; @@ -21,11 +22,18 @@ class WPDbTest extends Unit { use UopzFunctions; use LoopIsolation; + use TmpFilesCleanup; protected $backupGlobals = false; - private array $config = [ + /** + * @var mixed[] + */ + private $config = [ ]; - private static ?PDO $pdo; + /** + * @var \PDO|null + */ + private static $pdo; /** * @before diff --git a/tests/unit/lucatume/WPBrowser/Module/WPFilesystemTest.php b/tests/unit/lucatume/WPBrowser/Events/Module/WPFilesystemTest.php similarity index 94% rename from tests/unit/lucatume/WPBrowser/Module/WPFilesystemTest.php rename to tests/unit/lucatume/WPBrowser/Events/Module/WPFilesystemTest.php index df46feaaa..6edf81a4d 100644 --- a/tests/unit/lucatume/WPBrowser/Module/WPFilesystemTest.php +++ b/tests/unit/lucatume/WPBrowser/Events/Module/WPFilesystemTest.php @@ -7,17 +7,24 @@ use Codeception\Lib\ModuleContainer; use Codeception\Test\Unit; use DateTime; +use lucatume\WPBrowser\Tests\Traits\TmpFilesCleanup; use lucatume\WPBrowser\Utils\Filesystem as FS; use lucatume\WPBrowser\Utils\Strings; +use PHPUnit\Framework\Assert; use PHPUnit\Framework\AssertionFailedError; class WPFilesystemTest extends Unit { + use TmpFilesCleanup; + /** * @var ModuleContainer */ - protected ModuleContainer $moduleContainer; - protected array $config = []; + protected $moduleContainer; + /** + * @var mixed[] + */ + protected $config = []; protected $backupGlobals = false; protected $nowUploads; @@ -449,7 +456,7 @@ public function it_should_allow_to_delete_upload_files(): void $sut->deleteUploadedFile('test_1/test_2/file.txt'); $sut->dontSeeUploadedFileFound('test_1/test_2/file.txt'); - $this->assertFileDoesNotExist($wpRoot . '/wp-content/uploads/test_1/test_2/file.txt'); + $this->assertFileNotExists($wpRoot . '/wp-content/uploads/test_1/test_2/file.txt'); } /** @@ -479,8 +486,8 @@ public function it_should_allow_to_delete_upload_file_using_date(): void $sut->seeUploadedFileFound("$Y/$m/file.txt"); $sut->deleteUploadedFile("$Y/$m/file.txt"); - $sut->dontSeeUploadedFileFound(file: "$Y/$m/file.txt"); - $this->assertFileDoesNotExist($wpRoot . "/wp-content/uploads/$Y/$m/file.txt"); + $sut->dontSeeUploadedFileFound("$Y/$m/file.txt"); + $this->assertFileNotExists($wpRoot . "/wp-content/uploads/$Y/$m/file.txt"); } /** @@ -506,11 +513,11 @@ public function it_should_allow_cleaning_the_uploads_dir(): void $sut->cleanUploadsDir('test_1'); $this->assertFileExists($wpRoot . '/wp-content/uploads/test_1'); - $this->assertFileDoesNotExist($wpRoot . '/wp-content/uploads/test_1/file.txt'); + $this->assertFileNotExists($wpRoot . '/wp-content/uploads/test_1/file.txt'); $sut->cleanUploadsDir(); - $this->assertFileDoesNotExist($wpRoot . '/wp-content/uploads/test_1'); + $this->assertFileNotExists($wpRoot . '/wp-content/uploads/test_1'); } /** @@ -549,12 +556,12 @@ public function it_should_allow_cleaning_upload_dirs_by_date(): void $this->assertFileExists($wpRoot . "/wp-content/uploads/$Y/$m"); $this->assertFileExists($wpRoot . "/wp-content/uploads/$Y/$m/test_1"); $this->assertFileExists($wpRoot . "/wp-content/uploads/$Y/$m/file.txt"); - $this->assertFileDoesNotExist($wpRoot . "/wp-content/uploads/$Y/$m/test_1/test_2"); + $this->assertFileNotExists($wpRoot . "/wp-content/uploads/$Y/$m/test_1/test_2"); $sut->cleanUploadsDir('/', time()); $this->assertFileExists($wpRoot . "/wp-content/uploads/$Y/$m"); - $this->assertFileDoesNotExist($wpRoot . "/wp-content/uploads/$Y/$m/test_1"); + $this->assertFileNotExists($wpRoot . "/wp-content/uploads/$Y/$m/test_1"); } /** @@ -586,7 +593,7 @@ public function it_should_allow_copying_dirs_to_the_uploads_dir(): void $dest = $wpRoot . '/wp-content/uploads/folder2'; $this->assertFileExists($src); - $this->assertFileDoesNotExist($dest); + $this->assertFileNotExists($dest); $sut->copyDirToUploads($src, 'folder2'); @@ -625,7 +632,7 @@ public function it_should_allow_copying_dirs_to_the_uploads_dir_by_date(): void $dest = $wpRoot . "/wp-content/uploads/$Y/$m/folder2"; $this->assertFileExists($src); - $this->assertFileDoesNotExist($dest); + $this->assertFileNotExists($dest); $sut->copyDirToUploads($src, 'folder2', time()); @@ -655,7 +662,7 @@ public function it_should_allow_writing_to_uploads_file(): void $dest = $wpRoot . '/wp-content/uploads/some-file.txt'; - $this->assertFileDoesNotExist($dest); + $this->assertFileNotExists($dest); $sut->writeToUploadedFile('some-file.txt', 'foo'); @@ -691,7 +698,7 @@ public function it_should_allow_writing_to_uploads_file_by_date(): void $dest = $wpRoot . "/wp-content/uploads/$Y/$m/some-file.txt"; - $this->assertFileDoesNotExist($dest); + $this->assertFileNotExists($dest); $sut->writeToUploadedFile('some-file.txt', 'foo', time()); @@ -720,7 +727,7 @@ public function it_should_allow_opening_an_uploaded_file(): void $dest = $wpRoot . '/wp-content/uploads/some-file.txt'; - $this->assertFileDoesNotExist($dest); + $this->assertFileNotExists($dest); $sut->writeToUploadedFile('some-file.txt', 'foo'); $sut->openUploadedFile('some-file.txt'); @@ -757,7 +764,7 @@ public function it_should_allow_opening_an_uploaded_file_by_date(): void $dest = $wpRoot . "/wp-content/uploads/$Y/$m/some-file.txt"; - $this->assertFileDoesNotExist($dest); + $this->assertFileNotExists($dest); $sut->writeToUploadedFile('some-file.txt', 'foo', 'today'); $sut->openUploadedFile('some-file.txt', 'today'); @@ -810,7 +817,7 @@ public function it_should_allow_being_in_a_plugin_path(): void $sut->deletePluginFile('plugin1/some-file.txt'); - $this->assertFileDoesNotExist($pluginFolder . '/some-file.txt'); + $this->assertFileNotExists($pluginFolder . '/some-file.txt'); $sut->dontSeePluginFileFound('plugin1/some-file.txt'); @@ -826,7 +833,7 @@ public function it_should_allow_being_in_a_plugin_path(): void $sut->cleanPluginDir('plugin1'); - $this->assertFileDoesNotExist($pluginFolder . '/some-file.txt'); + $this->assertFileNotExists($pluginFolder . '/some-file.txt'); } /** @@ -873,7 +880,7 @@ public function it_should_allow_being_in_a_themes_path(): void $sut->deleteThemeFile('theme1/some-file.txt'); - $this->assertFileDoesNotExist($themeFolder . '/some-file.txt'); + $this->assertFileNotExists($themeFolder . '/some-file.txt'); $sut->dontSeeThemeFileFound('theme1/some-file.txt'); @@ -889,7 +896,7 @@ public function it_should_allow_being_in_a_themes_path(): void $sut->cleanThemeDir('theme1'); - $this->assertFileDoesNotExist($themeFolder . '/some-file.txt'); + $this->assertFileNotExists($themeFolder . '/some-file.txt'); } /** @@ -936,7 +943,7 @@ public function it_should_allow_being_in_a_mu_plugin_path(): void $sut->deleteMuPluginFile('muplugin1/some-file.txt'); - $this->assertFileDoesNotExist($mupluginFolder . '/some-file.txt'); + $this->assertFileNotExists($mupluginFolder . '/some-file.txt'); $sut->dontSeeMuPluginFileFound('muplugin1/some-file.txt'); @@ -952,7 +959,7 @@ public function it_should_allow_being_in_a_mu_plugin_path(): void $sut->cleanMuPluginDir('muplugin1'); - $this->assertFileDoesNotExist($mupluginFolder . '/some-file.txt'); + $this->assertFileNotExists($mupluginFolder . '/some-file.txt'); } /** @@ -995,8 +1002,8 @@ public function it_should_allow_having_a_plugin_with_code(): void $sut->_after(new class extends Unit { }); - $this->assertFileDoesNotExist($pluginFile); - $this->assertFileDoesNotExist($pluginFolder); + $this->assertFileNotExists($pluginFile); + $this->assertFileNotExists($pluginFolder); } /** @@ -1038,7 +1045,7 @@ public function it_should_allow_having_a_single_file_plugin_with_code(): void $sut->_after(new class extends Unit { }); - $this->assertFileDoesNotExist($pluginFile); + $this->assertFileNotExists($pluginFile); $this->assertFileExists($pluginsFolder); } @@ -1083,7 +1090,7 @@ public function it_should_allow_having_a_mu_plugin_with_code(): void $sut->_after(new class extends Unit { }); - $this->assertFileDoesNotExist($muPluginFile); + $this->assertFileNotExists($muPluginFile); $this->assertFileExists($muPluginFolder); } @@ -1135,8 +1142,8 @@ public function it_should_allow_having_a_theme_with_code(): void $sut->_after(new class extends Unit { }); - $this->assertFileDoesNotExist($themeStyleFile); - $this->assertFileDoesNotExist($themeIndexFile); + $this->assertFileNotExists($themeStyleFile); + $this->assertFileNotExists($themeIndexFile); } /** @@ -1191,9 +1198,9 @@ public function it_should_allow_having_a_theme_with_code_and_functions_file(): v $sut->_after(new class extends Unit { }); - $this->assertFileDoesNotExist($themeStyleFile); - $this->assertFileDoesNotExist($themeIndexFile); - $this->assertFileDoesNotExist($themeFunctionsFile); + $this->assertFileNotExists($themeStyleFile); + $this->assertFileNotExists($themeIndexFile); + $this->assertFileNotExists($themeFunctionsFile); } /** @@ -1238,8 +1245,8 @@ public function should_allow_opening_php_tag_when_having_plugin(): void $sut->_after(new class extends Unit { }); - $this->assertFileDoesNotExist($pluginFile); - $this->assertFileDoesNotExist($pluginFolder); + $this->assertFileNotExists($pluginFile); + $this->assertFileNotExists($pluginFolder); } /** @@ -1285,7 +1292,7 @@ public function should_allow_the_opening_php_tag_when_having_a_mu_plugin(): void $sut->_after(new class extends Unit { }); - $this->assertFileDoesNotExist($muPluginFile); + $this->assertFileNotExists($muPluginFile); $this->assertFileExists($muPluginFolder); } @@ -1342,9 +1349,9 @@ public function should_allow_the_opening_php_tag_when_having_a_theme(): void $sut->_after(new class extends Unit { }); - $this->assertFileDoesNotExist($themeStyleFile); - $this->assertFileDoesNotExist($themeIndexFile); - $this->assertFileDoesNotExist($themeFunctionsFile); + $this->assertFileNotExists($themeStyleFile); + $this->assertFileNotExists($themeIndexFile); + $this->assertFileNotExists($themeFunctionsFile); } public function plugin_path_with_diff_path_separators_data_provider(): array @@ -1397,7 +1404,7 @@ public function should_allow_using_different_directory_separators_to_have_plugin $sut->_after(new class extends Unit { }); - $this->assertFileDoesNotExist($pluginFile); + $this->assertFileNotExists($pluginFile); $this->assertFileExists($pluginsFolder); } diff --git a/tests/unit/lucatume/WPBrowser/Module/WPLoader/FiltersTest.php b/tests/unit/lucatume/WPBrowser/Events/Module/WPLoader/FiltersTest.php similarity index 100% rename from tests/unit/lucatume/WPBrowser/Module/WPLoader/FiltersTest.php rename to tests/unit/lucatume/WPBrowser/Events/Module/WPLoader/FiltersTest.php diff --git a/tests/unit/lucatume/WPBrowser/Module/WPLoaderTest.php b/tests/unit/lucatume/WPBrowser/Events/Module/WPLoaderTest.php similarity index 96% rename from tests/unit/lucatume/WPBrowser/Module/WPLoaderTest.php rename to tests/unit/lucatume/WPBrowser/Events/Module/WPLoaderTest.php index d1aba1c2d..baab47f62 100644 --- a/tests/unit/lucatume/WPBrowser/Module/WPLoaderTest.php +++ b/tests/unit/lucatume/WPBrowser/Events/Module/WPLoaderTest.php @@ -49,16 +49,28 @@ class WPLoaderTest extends Unit /** * @var UnitTester */ - protected UnitTester $tester; + protected $tester; /** * @var array */ - protected array $config; - private ?string $previousCwd = null; - private ?string $homeEnvBackup = null; - private ?string $homeServerBackup = null; - private ?ModuleContainer $mockModuleContainer = null; + protected $config; + /** + * @var string|null + */ + private $previousCwd; + /** + * @var string|null + */ + private $homeEnvBackup; + /** + * @var string|null + */ + private $homeServerBackup; + /** + * @var \Codeception\Lib\ModuleContainer|null + */ + private $mockModuleContainer; /** * @after @@ -774,7 +786,7 @@ public function should_not_throw_when_load_only_true_and_using_db_module( ); $wpLoader = $this->module(); - $mockDbModule = $this->createStub($dbModuleClass); + $mockDbModule = $this->createMock($dbModuleClass); $this->mockModuleContainer->mock($dbModuleName, $mockDbModule); $this->assertInIsolation(static function () use ($wpLoader, $wpRootDir) { @@ -810,11 +822,11 @@ public function should_throw_if_using_with_wp_db_and_not_load_only( ]; $wpLoader = $this->module(); - $mockDbModule = $this->createStub($dbModuleClass); + $mockDbModule = $this->createMock($dbModuleClass); $this->mockModuleContainer->mock($dbModuleName, $mockDbModule); $this->expectException(ModuleConfigException::class); - $this->expectExceptionMessageMatches( + $this->expectExceptionMessageRegExp( '/The WPLoader module is not being used to only load ' . 'WordPress, but to also install it/' ); @@ -851,7 +863,7 @@ public function should_not_throw_if_using_db_module_and_load_only_true( Installation::scaffold($wpRootDir, '6.1.1')->configure($db); $wpLoader = $this->module(); - $mockDbModule = $this->createStub($dbModuleClass); + $mockDbModule = $this->createMock($dbModuleClass); $this->mockModuleContainer->mock($dbModuleName, $mockDbModule); $ok = $this->assertInIsolation(static function () use ($wpLoader) { @@ -953,7 +965,7 @@ public function should_throw_module_exception_on_error_during_bootstrap(): void Installation::scaffold($wpRootDir, 'latest'); $this->expectException(ModuleException::class); - $this->expectExceptionMessageMatches('/WordPress bootstrap failed/'); + $this->expectExceptionMessageRegExp('/WordPress bootstrap failed/'); $wpLoader = $this->module(); $this->assertInIsolation(static function () use ($wpLoader, $wpRootDir) { @@ -987,11 +999,14 @@ public function should_install_and_bootstrap_single_installation(): void ], 'plugins' => [ 'akismet/akismet.php', - 'hello-dolly/hello.php', - 'woocommerce/woocommerce.php', + 'hello-dolly/hello.php' ], 'theme' => 'twentytwenty', ]; + if (PHP_VERSION >= 7.4) { + // WooCommerce has a minimum PHP version of 7.4.0 required. + $this->config['plugins'][] = 'woocommerce/woocommerce.php'; + } $installation = Installation::scaffold($wpRootDir, 'latest'); $this->copyOverContentFromTheMainInstallation($installation); @@ -1007,11 +1022,14 @@ public function should_install_and_bootstrap_single_installation(): void $wpLoader->_initialize(); - Assert::assertEquals([ + $expectedActivePlugins = [ 'akismet/akismet.php', - 'hello-dolly/hello.php', - 'woocommerce/woocommerce.php', - ], get_option('active_plugins')); + 'hello-dolly/hello.php' + ]; + if (PHP_VERSION >= 7.4) { + $expectedActivePlugins[] = 'woocommerce/woocommerce.php'; + } + Assert::assertEquals($expectedActivePlugins, get_option('active_plugins')); Assert::assertEquals([ 'before_install', 'after_install', @@ -1040,7 +1058,9 @@ public function should_install_and_bootstrap_single_installation(): void $wpLoader->getThemesFolder('/some-file.php') ); WPAssert::assertTableExists('posts'); - WPAssert::assertTableExists('woocommerce_order_items'); + if (PHP_VERSION >= 7.4) { + WPAssert::assertTableExists('woocommerce_order_items'); + } WPAssert::assertUpdatesDisabled(); return [ @@ -1076,12 +1096,15 @@ public function should_install_and_bootstrap_multisite_installation(): void ], 'plugins' => [ 'akismet/akismet.php', - 'hello-dolly/hello.php', - 'woocommerce/woocommerce.php', + 'hello-dolly/hello.php' ], 'theme' => 'twentytwenty', 'multisite' => true, ]; + if (PHP_VERSION >= 7.4) { + // WooCommerce has a minimum PHP version of 7.4.0 required. + $this->config['plugins'][] = 'woocommerce/woocommerce.php'; + } $installation = Installation::scaffold($wpRootDir, 'latest'); $this->copyOverContentFromTheMainInstallation($installation); @@ -1097,11 +1120,14 @@ public function should_install_and_bootstrap_multisite_installation(): void $wpLoader->_initialize(); - Assert::assertEquals([ + $expectedActivePlugins = [ 'akismet/akismet.php', - 'hello-dolly/hello.php', - 'woocommerce/woocommerce.php', - ], array_keys(get_site_option('active_sitewide_plugins'))); + 'hello-dolly/hello.php' + ]; + if (PHP_VERSION >= 7.4) { + $expectedActivePlugins[] = 'woocommerce/woocommerce.php'; + } + Assert::assertEquals($expectedActivePlugins, array_keys(get_site_option('active_sitewide_plugins'))); Assert::assertEquals([ 'before_install', 'after_install', @@ -1131,7 +1157,9 @@ public function should_install_and_bootstrap_multisite_installation(): void $wpLoader->getThemesFolder('/some-file.php') ); WPAssert::assertTableExists('posts'); - WPAssert::assertTableExists('woocommerce_order_items'); + if (PHP_VERSION >= 7.4) { + WPAssert::assertTableExists('woocommerce_order_items'); + } WPAssert::assertUpdatesDisabled(); return [ @@ -1359,11 +1387,14 @@ public function should_correctly_activate_child_theme_in_single_installation(): ], 'plugins' => [ 'akismet/akismet.php', - 'hello-dolly/hello.php', - 'woocommerce/woocommerce.php', + 'hello-dolly/hello.php' ], 'theme' => 'some-child-theme' ]; + if (PHP_VERSION >= 7.4) { + // WooCommerce has a minimum PHP version of 7.4.0 required. + $this->config['plugins'][] = 'woocommerce/woocommerce.php'; + } $db = (new MysqlDatabase($dbName, $dbUser, $dbPassword, $dbHost))->create(); $installation = Installation::scaffold($wpRootDir, 'latest') ->configure($db) @@ -1425,12 +1456,15 @@ public function should_correctly_activate_child_theme_in_multisite_installation( ], 'plugins' => [ 'akismet/akismet.php', - 'hello-dolly/hello.php', - 'woocommerce/woocommerce.php', + 'hello-dolly/hello.php' ], 'theme' => 'twentytwenty-child', 'multisite' => true, ]; + if (PHP_VERSION >= 7.4) { + // WooCommerce has a minimum PHP version of 7.4.0 required. + $this->config['plugins'][] = 'woocommerce/woocommerce.php'; + } $db = (new MysqlDatabase($dbName, $dbUser, $dbPassword, $dbHost))->create(); $installation = Installation::scaffold($wpRootDir, 'latest') ->configure($db, InstallationStateInterface::MULTISITE_SUBFOLDER); @@ -1770,7 +1804,9 @@ public function should_initialize_correctly_with_sqlite_database_in_load_only_mo */ public function should_correctly_load_the_module_on_a_bedrock_installation(): void { - $this->markTestSkipped(); + if (PHP_VERSION < 8.0) { + $this->markTestSkipped(); + } $wpRootDir = FS::tmpDir('wploader_'); $dbName = Random::dbName(); $dbHost = Env::get('WORDPRESS_DB_HOST'); diff --git a/tests/unit/lucatume/WPBrowser/Module/WPQueriesTest.php b/tests/unit/lucatume/WPBrowser/Events/Module/WPQueriesTest.php similarity index 98% rename from tests/unit/lucatume/WPBrowser/Module/WPQueriesTest.php rename to tests/unit/lucatume/WPBrowser/Events/Module/WPQueriesTest.php index 696134f41..3dd524236 100644 --- a/tests/unit/lucatume/WPBrowser/Module/WPQueriesTest.php +++ b/tests/unit/lucatume/WPBrowser/Events/Module/WPQueriesTest.php @@ -18,13 +18,24 @@ class WPQueriesTest extends Unit { use UopzFunctions; - use TmpFilesCleanup; - protected bool $cleanupTmpAfterTest = false; - private static ?string $wpRootDir = null; + /** + * @var bool + */ + protected $cleanupTmpAfterTest = false; + /** + * @var string|null + */ + private static $wpRootDir; protected $backupGlobals = false; - private array $config = []; - private ?wpdb $wpdb; + /** + * @var mixed[] + */ + private $config = []; + /** + * @var \wpdb|null + */ + private $wpdb; private function makeInstance(): WPQueries { @@ -54,6 +65,16 @@ private function makeInstance(): WPQueries return $wpQueries; } + /** + * @afterClass + */ + public static function removeTmpDirAfterTestCase(): void + { + if (file_exists(self::$wpRootDir)) { + FS::rrmdir(self::$wpRootDir); + } + } + /** * It should throw if wpdb cannot be found at initialize time * diff --git a/tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPCLITest__should_allow_running_commands_with_debug_or_not__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPCLITest__3.5__should_allow_running_commands_with_debug_or_not__0.snapshot.txt similarity index 100% rename from tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPCLITest__should_allow_running_commands_with_debug_or_not__0.snapshot.txt rename to tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPCLITest__3.5__should_allow_running_commands_with_debug_or_not__0.snapshot.txt diff --git a/tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPCLITest__should_allow_running_commands_with_debug_or_not__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPCLITest__should_allow_running_commands_with_debug_or_not__0.snapshot.txt new file mode 100644 index 000000000..f3b5af39e --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPCLITest__should_allow_running_commands_with_debug_or_not__0.snapshot.txt @@ -0,0 +1 @@ +6.1.1 diff --git a/tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__Db_module_loadOnly_false__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__Db_module_loadOnly_false__0.snapshot.txt similarity index 100% rename from tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__Db_module_loadOnly_false__0.snapshot.txt rename to tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__Db_module_loadOnly_false__0.snapshot.txt diff --git a/tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__Db_module_loadOnly_true__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__Db_module_loadOnly_true__0.snapshot.txt similarity index 100% rename from tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__Db_module_loadOnly_true__0.snapshot.txt rename to tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__Db_module_loadOnly_true__0.snapshot.txt diff --git a/tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__WPDb_module_loadOnly_false__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__WPDb_module_loadOnly_false__0.snapshot.txt similarity index 100% rename from tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__WPDb_module_loadOnly_false__0.snapshot.txt rename to tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__WPDb_module_loadOnly_false__0.snapshot.txt diff --git a/tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__WPDb_module_loadOnly_true__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__WPDb_module_loadOnly_true__0.snapshot.txt similarity index 100% rename from tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__WPDb_module_loadOnly_true__0.snapshot.txt rename to tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__WPDb_module_loadOnly_true__0.snapshot.txt diff --git a/tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__no_db_module_loadOnly_false__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__no_db_module_loadOnly_false__0.snapshot.txt similarity index 100% rename from tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__no_db_module_loadOnly_false__0.snapshot.txt rename to tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__no_db_module_loadOnly_false__0.snapshot.txt diff --git a/tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__no_db_module_loadOnly_true__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__no_db_module_loadOnly_true__0.snapshot.txt similarity index 100% rename from tests/unit/lucatume/WPBrowser/Module/__snapshots__/WPLoaderTest__test_exit_messages__no_db_module_loadOnly_true__0.snapshot.txt rename to tests/unit/lucatume/WPBrowser/Events/Module/__snapshots__/WPLoaderTest__test_exit_messages__no_db_module_loadOnly_true__0.snapshot.txt diff --git a/tests/unit/lucatume/WPBrowser/Extension/BuiltInServerControllerTest.php b/tests/unit/lucatume/WPBrowser/Extension/BuiltInServerControllerTest.php index 694f6cbb4..800137c10 100644 --- a/tests/unit/lucatume/WPBrowser/Extension/BuiltInServerControllerTest.php +++ b/tests/unit/lucatume/WPBrowser/Extension/BuiltInServerControllerTest.php @@ -321,10 +321,26 @@ public function should_correctly_produce_information(): void $this->assertFileExists(PhpBuiltInServer::getPidFile()); - $this->assertMatchesStringSnapshot(var_export($extension->getInfo(), true)); + $this->assertEquals([ + 'running' => 'yes', + 'pidFile' => 'var/_output/php-built-in-server.pid', + 'port' => 8923, + 'docroot' => ltrim(str_replace(getcwd(), '', __DIR__),DIRECTORY_SEPARATOR), + 'workers' => 5, + 'url' => 'http://localhost:8923/', + 'env' => [], + ], $extension->getInfo()); $extension->stop($this->output); - $this->assertMatchesStringSnapshot(var_export($extension->getInfo(), true)); + $this->assertEquals([ + 'running' => 'no', + 'pidFile' => 'var/_output/php-built-in-server.pid', + 'port' => 8923, + 'docroot' => ltrim(str_replace(getcwd(), '', __DIR__), DIRECTORY_SEPARATOR), + 'workers' => 5, + 'url' => 'http://localhost:8923/', + 'env' => [], + ], $extension->getInfo()); } } diff --git a/tests/unit/lucatume/WPBrowser/Extension/ChromeDriverControllerTest.php b/tests/unit/lucatume/WPBrowser/Extension/ChromeDriverControllerTest.php index ae592ab9d..ecda70ecd 100644 --- a/tests/unit/lucatume/WPBrowser/Extension/ChromeDriverControllerTest.php +++ b/tests/unit/lucatume/WPBrowser/Extension/ChromeDriverControllerTest.php @@ -223,11 +223,19 @@ public function should_correctly_produce_information(): void $this->assertFileExists(ChromeDriver::getPidFile()); - $this->assertMatchesStringSnapshot(var_export($extension->getInfo(), true)); + $this->assertEquals([ + 'running' => 'yes', + 'pidFile' => 'var/_output/chromedriver.pid', + 'port' => 4444, + ], $extension->getInfo()); $extension->stop($this->output); - $this->assertMatchesStringSnapshot(var_export($extension->getInfo(), true)); + $this->assertEquals([ + 'running' => 'no', + 'pidFile' => 'var/_output/chromedriver.pid', + 'port' => 4444, + ], $extension->getInfo()); } /** diff --git a/tests/unit/lucatume/WPBrowser/Extension/DockerComposeControllerTest.php b/tests/unit/lucatume/WPBrowser/Extension/DockerComposeControllerTest.php index 5652a987f..736049862 100644 --- a/tests/unit/lucatume/WPBrowser/Extension/DockerComposeControllerTest.php +++ b/tests/unit/lucatume/WPBrowser/Extension/DockerComposeControllerTest.php @@ -3,68 +3,30 @@ namespace lucatume\WPBrowser\Extension; -use Closure; use Codeception\Event\SuiteEvent; use Codeception\Exception\ExtensionException; use Codeception\Lib\Console\Output; use Codeception\Suite; use Codeception\Test\Unit; use Exception; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; +use lucatume\WPBrowser\Tests\Traits\ClassStubs; use lucatume\WPBrowser\Tests\Traits\UopzFunctions; use lucatume\WPBrowser\Utils\Composer; use stdClass; -use Symfony\Component\Process\Process; use Symfony\Component\Yaml\Yaml; use tad\Codeception\SnapshotAssertions\SnapshotAssertions; -class MockDockerComposeProcess extends Process -{ - public static array $instances; - public static ?Closure $mustRunCallback = null; - public static ?Closure $outputCallback = null; - - public function __construct( - array $command, - string $cwd = null, - array $env = null, - mixed $input = null, - ?float $timeout = 60 - ) { - self::$instances[] = [ - 'command' => $command, - 'cwd' => $cwd, - 'env' => $env, - 'input' => $input, - 'timeout' => $timeout - ]; - } - - public function mustRun(callable $callback = null, array $env = []): static - { - return self::$mustRunCallback ? (self::$mustRunCallback)() : $this; - } - - public function stop(float $timeout = 10, int $signal = null): ?int - { - return 0; - } - - public function start(callable $callback = null, array $env = []) - { - } - - public function getOutput(): string - { - return self::$outputCallback ? (self::$outputCallback)() : ''; - } -} - class DockerComposeControllerTest extends Unit { use UopzFunctions; use SnapshotAssertions; + use ClassStubs; - private Output $output; + /** + * @var \Codeception\Lib\Console\Output + */ + private $output; /** * @before @@ -86,13 +48,6 @@ public function _before() // Silence output. $this->output = new Output(['verbosity' => Output::VERBOSITY_QUIET]); $this->uopzSetMock(Output::class, $this->output); - MockDockerComposeProcess::$instances = []; - MockDockerComposeProcess::$mustRunCallback = null; - } - - public function _after() - { - MockDockerComposeProcess::$instances = []; } public function notArrayOfStringsProvider(): array @@ -113,8 +68,9 @@ public function notArrayOfStringsProvider(): array * * @test * @dataProvider notArrayOfStringsProvider + * @param mixed $suites */ - public function should_throw_if_suite_configuration_parameter_is_not_array_of_strings(mixed $suites): void + public function should_throw_if_suite_configuration_parameter_is_not_array_of_strings($suites): void { $config = ['suites' => $suites]; $options = []; @@ -135,8 +91,16 @@ public function should_throw_if_suite_configuration_parameter_is_not_array_of_st */ public function should_not_run_any_command_if_already_running(): void { - $this->uopzSetMock(Process::class, MockDockerComposeProcess::class); file_put_contents(DockerComposeController::getRunningFile(), 'yes'); + $constructed = 0; + $this->uopzSetMock( + Process::class, + $this->makeEmptyClass(Process::class, [ + '__construct' => static function (...$args) use (&$constructed) { + $constructed++; + } + ]) + ); $config = ['suites' => ['end2end']]; $options = []; @@ -146,7 +110,7 @@ public function should_not_run_any_command_if_already_running(): void $mockSuite = $this->make(Suite::class, ['getName' => 'end2end']); $extension->onModuleInit($this->make(SuiteEvent::class, ['getSuite' => $mockSuite])); - $this->assertCount(0, MockDockerComposeProcess::$instances); + $this->assertEquals(0, $constructed); } /** @@ -156,7 +120,15 @@ public function should_not_run_any_command_if_already_running(): void */ public function should_up_stack_correctly(): void { - $this->uopzSetMock(Process::class, MockDockerComposeProcess::class); + $constructCommands = []; + $this->uopzSetMock( + Process::class, + $this->makeEmptyClass(Process::class, [ + '__construct' => static function ($command, ...$args) use (&$constructCommands) { + $constructCommands[] = $command; + } + ]) + ); $config = ['suites' => ['end2end'], 'compose-file' => 'docker-compose.yml']; $options = []; @@ -168,7 +140,7 @@ public function should_up_stack_correctly(): void $this->assertEquals( ['docker', 'compose', '-f', 'docker-compose.yml', 'up', '--wait'], - MockDockerComposeProcess::$instances[0]['command'] + $constructCommands[0] ); $this->assertFileExists(DockerComposeController::getRunningFile()); } @@ -180,7 +152,7 @@ public function should_up_stack_correctly(): void */ public function should_throw_if_config_compose_file_is_not_valid_existing_file(): void { - $this->uopzSetMock(Process::class, MockDockerComposeProcess::class); + $this->uopzSetMock(Process::class, $this->makeEmptyClass(Process::class, [])); $config = ['suites' => ['end2end'], 'compose-file' => 'not-a-file.yml']; $options = []; @@ -202,7 +174,7 @@ public function should_throw_if_config_compose_file_is_not_valid_existing_file() */ public function should_throw_if_config_env_file_is_not_valid_file(): void { - $this->uopzSetMock(Process::class, MockDockerComposeProcess::class); + $this->uopzSetMock(Process::class, $this->makeEmptyClass(Process::class, [])); $config = ['suites' => ['end2end'], 'compose-file' => 'docker-compose.yml', 'env-file' => 'not-an-env-file']; $options = []; @@ -224,7 +196,16 @@ public function should_throw_if_config_env_file_is_not_valid_file(): void */ public function should_correctly_handle_stack_lifecycle(): void { - $this->uopzSetMock(Process::class, MockDockerComposeProcess::class); + $constructed = 0; + $this->uopzSetMock( + Process::class, + $this->makeEmptyClass(Process::class, [ + '__construct' => static function () use (&$constructed) { + $constructed++; + }, + 'stop' => 0 + ]) + ); $config = ['suites' => ['end2end'], 'compose-file' => 'docker-compose.yml']; $options = []; @@ -234,7 +215,7 @@ public function should_correctly_handle_stack_lifecycle(): void $extension->onModuleInit($this->make(SuiteEvent::class, ['getSuite' => $mockSuite])); - $this->assertCount(1, MockDockerComposeProcess::$instances); + $this->assertEquals(1, $constructed); $this->assertFileExists(DockerComposeController::getRunningFile()); $extension->stop($this->output); @@ -251,19 +232,22 @@ public function should_correctly_handle_stack_lifecycle(): void */ public function should_throw_if_docker_compose_start_fails(): void { - $this->uopzSetMock(Process::class, MockDockerComposeProcess::class); + $this->uopzSetMock( + Process::class, + $this->makeEmptyClass(Process::class, [ + 'mustRun' => static function () { + throw new Exception('something went wrong'); + } + ]) + ); $config = ['suites' => ['end2end'], 'compose-file' => 'docker-compose.yml']; - $options = []; - MockDockerComposeProcess::$mustRunCallback = static function (): void { - throw new Exception('something went wrong'); - }; - $extension = new DockerComposeController($config, $options); + $extension = new DockerComposeController($config, []); $mockSuite = $this->make(Suite::class, ['getName' => 'end2end']); $this->expectException(ExtensionException::class); - $this->expectExceptionMessageMatches('/Failed to start Docker Compose/'); + $this->expectExceptionMessageRegExp('/Failed to start Docker Compose/'); $extension->onModuleInit($this->make(SuiteEvent::class, ['getSuite' => $mockSuite])); } @@ -275,7 +259,7 @@ public function should_throw_if_docker_compose_start_fails(): void */ public function should_throw_if_running_file_cannot_be_written(): void { - $this->uopzSetMock(Process::class, MockDockerComposeProcess::class); + $this->uopzSetMock(Process::class, $this->makeEmptyClass(Process::class, [])); $config = ['suites' => ['end2end'], 'compose-file' => 'docker-compose.yml']; $options = []; @@ -297,7 +281,6 @@ public function should_throw_if_running_file_cannot_be_written(): void */ public function should_throw_if_stack_stopping_fails(): void { - $this->uopzSetMock(Process::class, MockDockerComposeProcess::class); $config = ['suites' => ['end2end'], 'compose-file' => 'docker-compose.yml']; $options = []; @@ -307,15 +290,19 @@ public function should_throw_if_stack_stopping_fails(): void $extension->onModuleInit($this->make(SuiteEvent::class, ['getSuite' => $mockSuite])); - $this->assertCount(1, MockDockerComposeProcess::$instances); $this->assertFileExists(DockerComposeController::getRunningFile()); - MockDockerComposeProcess::$mustRunCallback = static function (): void { - throw new Exception('something went wrong'); - }; + $this->uopzSetMock( + Process::class, + $this->makeEmptyClass(Process::class, [ + 'mustRun' => static function () { + throw new Exception('something went wrong'); + } + ]) + ); $this->expectException(ExtensionException::class); - $this->expectExceptionMessageMatches('/Failed to stop Docker Compose/'); + $this->expectExceptionMessageRegExp('/Failed to stop Docker Compose/'); $extension->stop($this->output); } @@ -327,7 +314,12 @@ public function should_throw_if_stack_stopping_fails(): void */ public function should_throw_if_running_file_cannot_be_removed_while_stopping(): void { - $this->uopzSetMock(Process::class, MockDockerComposeProcess::class); + $this->uopzSetMock( + Process::class, + $this->makeEmptyClass(Process::class, [ + 'stop' => 0 + ]) + ); $config = ['suites' => ['end2end'], 'compose-file' => 'docker-compose.yml']; $options = []; @@ -337,7 +329,6 @@ public function should_throw_if_running_file_cannot_be_removed_while_stopping(): $extension->onModuleInit($this->make(SuiteEvent::class, ['getSuite' => $mockSuite])); - $this->assertCount(1, MockDockerComposeProcess::$instances); $this->assertFileExists(DockerComposeController::getRunningFile()); $this->uopzSetFunctionReturn('unlink', false); @@ -355,7 +346,15 @@ public function should_throw_if_running_file_cannot_be_removed_while_stopping(): */ public function should_produce_information_correctly(): void { - $this->uopzSetMock(Process::class, MockDockerComposeProcess::class); + $this->uopzSetMock( + Process::class, + $this->makeEmptyClass(Process::class, [ + 'getOutput' => static function () { + return Yaml::dump(['services' => ['foo' => ['ports' => ['8088:80']]]]); + }, + 'stop' => 0 + ]) + ); $config = ['suites' => ['end2end'], 'compose-file' => 'docker-compose.yml']; $options = []; @@ -367,14 +366,13 @@ public function should_produce_information_correctly(): void $this->assertFileExists(DockerComposeController::getRunningFile()); - MockDockerComposeProcess::$outputCallback = function (): string { - return Yaml::dump(['services' => ['foo' => ['ports' => ['8088:80']]]]); - }; - - $this->assertMatchesStringSnapshot(var_export($extension->getInfo(), true)); + $this->assertEquals( + ['status' => 'up', 'config' => ['services' => ['foo' => ['ports' => [0 => '8088:80']]]]], + $extension->getInfo() + ); $extension->stop($this->output); - $this->assertMatchesStringSnapshot(var_export($extension->getInfo(), true)); + $this->assertEquals(['status' => 'down', 'config' => ''], $extension->getInfo()); } } diff --git a/tests/unit/lucatume/WPBrowser/Extension/EventDispatcherBridgeTest.php b/tests/unit/lucatume/WPBrowser/Extension/EventDispatcherBridgeTest.php index 37b054669..33413e4a1 100644 --- a/tests/unit/lucatume/WPBrowser/Extension/EventDispatcherBridgeTest.php +++ b/tests/unit/lucatume/WPBrowser/Extension/EventDispatcherBridgeTest.php @@ -6,6 +6,7 @@ use Codeception\Event\SuiteEvent; use Codeception\Events; use Codeception\Exception\ExtensionException; +use Codeception\Suite; use Codeception\Test\Unit; use lucatume\WPBrowser\Events\Dispatcher; use lucatume\WPBrowser\Extension\EventDispatcherBridge; @@ -13,7 +14,6 @@ use PHPUnit\Framework\Assert; use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcher; -use UnitTester; class EventDispatcherBridgeTest extends Unit { @@ -34,7 +34,8 @@ public function should_throw_if_event_dispatcher_cannot_be_found_in_trace(): voi $this->expectException(ExtensionException::class); $this->expectExceptionMessage('Could not find the application event dispatcher.'); - $eventDispatcherBridge->onModuleInit(new SuiteEvent()); + $suite = PHP_VERSION >= 8.0 ? null : new Suite; + $eventDispatcherBridge->onModuleInit(new SuiteEvent($suite)); } /** @@ -59,7 +60,8 @@ function (EventDispatcherInterface $setEventDispatcher) use ( }); $eventDispatcherBridge = new EventDispatcherBridge([], []); - $eventDispatcherBridge->onSuiteInit(new SuiteEvent()); + $suite = PHP_VERSION >= 8.0 ? null : new Suite; + $eventDispatcherBridge->onSuiteInit(new SuiteEvent($suite)); } /** @@ -88,7 +90,8 @@ public function should_immediately_call_previous_event_dispatcher_listeners_on_t $this->uopzSetStaticMethodReturn(Dispatcher::class, 'setEventDispatcher', null); $eventDispatcherBridge = new EventDispatcherBridge([], []); - $eventDispatcherBridge->onSuiteBefore(new SuiteEvent()); + $suite = PHP_VERSION >= 8.0 ? null : new Suite; + $eventDispatcherBridge->onSuiteBefore(new SuiteEvent($suite)); $this->assertEquals(2, $calls); } @@ -113,7 +116,8 @@ function ($eventDispatcher) use (&$setEventDispatcher) { } , true); $eventDispatcherBridge = new EventDispatcherBridge([], []); - $eventDispatcherBridge->onSuiteBefore(new SuiteEvent()); + $suite = PHP_VERSION >= 8.0 ? null : new Suite; + $eventDispatcherBridge->onSuiteBefore(new SuiteEvent($suite)); $this->assertSame($eventDispatcher, $setEventDispatcher); } diff --git a/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/BuiltInServerControllerTest__should_correctly_produce_information__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/BuiltInServerControllerTest__should_correctly_produce_information__0.snapshot.txt deleted file mode 100644 index 15874343c..000000000 --- a/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/BuiltInServerControllerTest__should_correctly_produce_information__0.snapshot.txt +++ /dev/null @@ -1,11 +0,0 @@ -array ( - 'running' => 'yes', - 'pidFile' => 'var/_output/php-built-in-server.pid', - 'port' => 8923, - 'docroot' => 'tests/unit/lucatume/WPBrowser/Extension', - 'workers' => 5, - 'url' => 'http://localhost:8923/', - 'env' => - array ( - ), -) \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/BuiltInServerControllerTest__should_correctly_produce_information__1.snapshot.txt b/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/BuiltInServerControllerTest__should_correctly_produce_information__1.snapshot.txt deleted file mode 100644 index 27933fadb..000000000 --- a/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/BuiltInServerControllerTest__should_correctly_produce_information__1.snapshot.txt +++ /dev/null @@ -1,11 +0,0 @@ -array ( - 'running' => 'no', - 'pidFile' => 'var/_output/php-built-in-server.pid', - 'port' => 8923, - 'docroot' => 'tests/unit/lucatume/WPBrowser/Extension', - 'workers' => 5, - 'url' => 'http://localhost:8923/', - 'env' => - array ( - ), -) \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/ChromeDriverControllerTest__should_correctly_produce_information__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/ChromeDriverControllerTest__should_correctly_produce_information__0.snapshot.txt deleted file mode 100644 index cad258c57..000000000 --- a/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/ChromeDriverControllerTest__should_correctly_produce_information__0.snapshot.txt +++ /dev/null @@ -1,5 +0,0 @@ -array ( - 'running' => 'yes', - 'pidFile' => 'var/_output/chromedriver.pid', - 'port' => 4444, -) \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/ChromeDriverControllerTest__should_correctly_produce_information__1.snapshot.txt b/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/ChromeDriverControllerTest__should_correctly_produce_information__1.snapshot.txt deleted file mode 100644 index e80f5f3c5..000000000 --- a/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/ChromeDriverControllerTest__should_correctly_produce_information__1.snapshot.txt +++ /dev/null @@ -1,5 +0,0 @@ -array ( - 'running' => 'no', - 'pidFile' => 'var/_output/chromedriver.pid', - 'port' => 4444, -) \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/DockerComposeControllerTest__3.5__should_produce_information_correctly__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/DockerComposeControllerTest__3.5__should_produce_information_correctly__0.snapshot.txt new file mode 100644 index 000000000..66c8071c0 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/DockerComposeControllerTest__3.5__should_produce_information_correctly__0.snapshot.txt @@ -0,0 +1,4 @@ +array ( + 'status' => 'down', + 'config' => '', +) \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/DockerComposeControllerTest__should_produce_information_correctly__0.snapshot.txt b/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/DockerComposeControllerTest__should_produce_information_correctly__0.snapshot.txt index df8f51ddb..66c8071c0 100644 --- a/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/DockerComposeControllerTest__should_produce_information_correctly__0.snapshot.txt +++ b/tests/unit/lucatume/WPBrowser/Extension/__snapshots__/DockerComposeControllerTest__should_produce_information_correctly__0.snapshot.txt @@ -1,16 +1,4 @@ array ( - 'status' => 'up', - 'config' => - array ( - 'services' => - array ( - 'foo' => - array ( - 'ports' => - array ( - 0 => '8088:80', - ), - ), - ), - ), + 'status' => 'down', + 'config' => '', ) \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Lib/Generator/__snapshots__/WPUnitTest__3.5__should_correctly_add_the_tester_property_if_actor_is_set_in_the_settings__0.snapshot.php b/tests/unit/lucatume/WPBrowser/Lib/Generator/__snapshots__/WPUnitTest__3.5__should_correctly_add_the_tester_property_if_actor_is_set_in_the_settings__0.snapshot.php new file mode 100644 index 000000000..b2a6d1d46 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Lib/Generator/__snapshots__/WPUnitTest__3.5__should_correctly_add_the_tester_property_if_actor_is_set_in_the_settings__0.snapshot.php @@ -0,0 +1,34 @@ +post->create_and_get(); + + $this->assertInstanceOf(\WP_Post::class, $post); + } +} diff --git a/tests/unit/lucatume/WPBrowser/Lib/Generator/__snapshots__/WPUnitTest__3.5__should_scaffold_the_test_case__0.snapshot.php b/tests/unit/lucatume/WPBrowser/Lib/Generator/__snapshots__/WPUnitTest__3.5__should_scaffold_the_test_case__0.snapshot.php new file mode 100644 index 000000000..999dbdab7 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Lib/Generator/__snapshots__/WPUnitTest__3.5__should_scaffold_the_test_case__0.snapshot.php @@ -0,0 +1,30 @@ +post->create_and_get(); + + $this->assertInstanceOf(\WP_Post::class, $post); + } +} diff --git a/tests/unit/lucatume/WPBrowser/ManagedProcess/ChromedriverTest.php b/tests/unit/lucatume/WPBrowser/ManagedProcess/ChromedriverTest.php index 24e1d9034..f6cdc5bfd 100644 --- a/tests/unit/lucatume/WPBrowser/ManagedProcess/ChromedriverTest.php +++ b/tests/unit/lucatume/WPBrowser/ManagedProcess/ChromedriverTest.php @@ -4,10 +4,10 @@ namespace lucatume\WPBrowser\ManagedProcess; use Codeception\Test\Unit; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Exceptions\RuntimeException; use lucatume\WPBrowser\Tests\Traits\UopzFunctions; use lucatume\WPBrowser\Utils\Composer; -use Symfony\Component\Process\Process; class ChromedriverTest extends Unit { @@ -88,21 +88,12 @@ public function should_throw_if_binary_cannot_be_started_with_arguments(): void */ public function should_throw_if_pid_is_not_integer_on_start(): void { - $mockProcess = new class(['chromedriver']) extends Process { - public function getOutput(): string - { - return 'ChromeDriver was started successfully.'; - } - public function getPid(): ?int - { - return null; - } - - public function stop(float $timeout = 10, ?int $signal = null): ?int - { - return 5; - } - }; + $mockProcess = $this->makeEmpty(Process::class, [ + 'getOutput' => 'ChromeDriver was started successfully.', + 'getPid' => null, + 'isRunning' => true, + 'stop' => 5 + ]); $this->uopzSetMock(Process::class, $mockProcess); $chromedriver = new ChromeDriver(3456, ['--url-base=wd/hub', '--headless']); @@ -120,17 +111,11 @@ public function stop(float $timeout = 10, ?int $signal = null): ?int */ public function should_throw_if_pif_file_cannot_be_written_on_start(): void { - $mockProcess = new class(['chromedriver']) extends Process { - public function getOutput(): string - { - return 'ChromeDriver was started successfully.'; - } - public function getPid(): ?int - { - return 2389; - } - - }; + $mockProcess = $this->makeEmpty(Process::class,[ + 'getOutput' => 'ChromeDriver was started successfully.', + 'isRunning' => true, + 'getPid' => 2389, + ]); $this->uopzSetMock(Process::class, $mockProcess); $chromedriver = new ChromeDriver(3456, ['--url-base=wd/hub', '--headless']); diff --git a/tests/unit/lucatume/WPBrowser/ManagedProcess/PhpBuiltInServerTest.php b/tests/unit/lucatume/WPBrowser/ManagedProcess/PhpBuiltInServerTest.php index c34fffa2c..d8d7157d3 100644 --- a/tests/unit/lucatume/WPBrowser/ManagedProcess/PhpBuiltInServerTest.php +++ b/tests/unit/lucatume/WPBrowser/ManagedProcess/PhpBuiltInServerTest.php @@ -4,10 +4,11 @@ namespace lucatume\WPBrowser\ManagedProcess; use Codeception\Test\Unit; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Exceptions\RuntimeException; use lucatume\WPBrowser\Tests\Traits\TmpFilesCleanup; use lucatume\WPBrowser\Tests\Traits\UopzFunctions; -use Symfony\Component\Process\Process; +use lucatume\WPBrowser\Utils\Random; class PhpBuiltinServerProcessMock extends Process { @@ -99,7 +100,7 @@ public function should_throw_if_env_is_not_associative_array(mixed $env): void $this->expectException(RuntimeException::class); $this->expectExceptionCode(PhpBuiltInServer::ERR_ENV); - new PhpBuiltInServer(__DIR__, 0, $env); + new PhpBuiltInServer(__DIR__, 2389, $env); } /** @@ -109,9 +110,10 @@ public function should_throw_if_env_is_not_associative_array(mixed $env): void */ public function should_start_php_built_in_server_with_specified_workers(): void { + $port = Random::openLocalhostPort(); $this->uopzSetMock(Process::class, PhpBuiltinServerProcessMock::class); - $server = new PhpBuiltInServer(__DIR__, 0, [ + $server = new PhpBuiltInServer(__DIR__, $port, [ 'PHP_CLI_SERVER_WORKERS' => 3, ]); $server->start(); @@ -127,9 +129,10 @@ public function should_start_php_built_in_server_with_specified_workers(): void */ public function should_start_on_random_port_if_not_specified(): void { + $port = Random::openLocalhostPort(); $this->uopzSetMock(Process::class, PhpBuiltinServerProcessMock::class); - $server = new PhpBuiltInServer(__DIR__, 0); + $server = new PhpBuiltInServer(__DIR__, $port); $server->start(); $this->assertCount(1, PhpBuiltinServerProcessMock::$instances); @@ -143,17 +146,17 @@ public function should_start_on_random_port_if_not_specified(): void */ public function should_throw_if_specified_port_already_in_use(): void { - $this->uopzSetMock(Process::class, PhpBuiltinServerProcessMock::class); + $port = Random::openLocalhostPort(); - $startServer = new PhpBuiltInServer(__DIR__, 0); - $startServer->start(); + $previousServer = new PhpBuiltInServer(__DIR__, $port); + $previousServer->start(); - // Remove the PID file to allow starting another one. + // Remove the PID file to make sure the second server will attempt a start. if (!unlink(PhpBuiltInServer::getPidFile())) { - throw new \RuntimeException('Could not remove PID file.'); + throw new \RuntimeException('Could not delete PID file.'); } - $server = new PhpBuiltInServer(__DIR__, $startServer->getPort()); + $server = new PhpBuiltInServer(__DIR__, $port); $this->expectException(RuntimeException::class); $this->expectExceptionCode(PhpBuiltInServer::ERR_PORT_ALREADY_IN_USE); diff --git a/tests/unit/lucatume/WPBrowser/Process/Protocol/ResponseTest.php b/tests/unit/lucatume/WPBrowser/Process/Protocol/ResponseTest.php index 22f6c2178..c128025a6 100644 --- a/tests/unit/lucatume/WPBrowser/Process/Protocol/ResponseTest.php +++ b/tests/unit/lucatume/WPBrowser/Process/Protocol/ResponseTest.php @@ -48,16 +48,18 @@ public function testContstrucortAndGettersSerializableThrowable(): void public function testFromStderrWithNoSeparator(): void { - $stderrBufferString = '[17-Mar-2023 16:54:06 Europe/Paris] PHP Compile error: Cannot use output buffering in output buffering display handlers in Unknown on line 0'; + $stderrBufferString = '[17-Mar-2023 16:54:06 Europe/Paris] PHP Parse error: Expected T_CLASS or string, got foo in Unknown on line 0'; $response = Response::fromStderr($stderrBufferString); - $this->assertInstanceOf(CompileError::class, $response->getReturnValue()); + $this->assertInstanceOf(\ParseError::class, $response->getReturnValue()); $this->assertEquals(1, $response->getExitValue()); } public function testFromStderrWithSeparatorAndValidPayload(): void { - $returnValue = new SerializableClosure(static fn() => "success"); + $returnValue = new SerializableClosure(static function () { + return "success"; + }); $telemetry = ["memoryPeakUsage" => 123456]; $payload = Parser::encode([$returnValue, $telemetry]); $separator = Response::$stderrValueSeparator; @@ -89,7 +91,9 @@ public function testGetPayload(): void public function testGetStderrLength(): void { $separator = Response::$stderrValueSeparator; - $payload = Parser::encode([new SerializableClosure(static fn() => "success"), ['foo' => 'bar']]); + $payload = Parser::encode([new SerializableClosure(static function () { + return "success"; + }), ['foo' => 'bar']]); $stderrBufferString = "Error message{$separator}{$payload}"; $response = Response::fromStderr($stderrBufferString); @@ -98,7 +102,9 @@ public function testGetStderrLength(): void } public function testFromStderrWithNoiseAfterPayload():void{ - $returnValue = new SerializableClosure(static fn() => "success"); + $returnValue = new SerializableClosure(static function () { + return "success"; + }); $telemetry = ["memoryPeakUsage" => 123456]; $payload = Parser::encode([$returnValue, $telemetry]); $separator = Response::$stderrValueSeparator; diff --git a/tests/unit/lucatume/WPBrowser/Process/StderrStreamTest.php b/tests/unit/lucatume/WPBrowser/Process/StderrStreamTest.php index 0ddc9f419..9e6f87159 100644 --- a/tests/unit/lucatume/WPBrowser/Process/StderrStreamTest.php +++ b/tests/unit/lucatume/WPBrowser/Process/StderrStreamTest.php @@ -11,10 +11,10 @@ use Error; use ErrorException; use Generator; +use lucatume\WPBrowser\Exceptions\RuntimeException; use lucatume\WPBrowser\Process\StderrStream; use lucatume\WPBrowser\WordPress\InstallationException; use ParseError; -use PHPUnit\TextUI\RuntimeException; use tad\Codeception\SnapshotAssertions\SnapshotAssertions; class StderrStreamTest extends Unit @@ -95,7 +95,7 @@ public function fromStreamDataProvider(): Generator ]; $nestedException = <<installAndBootstrapInstallation() @@ -177,10 +177,12 @@ public function fromStreamDataProvider(): Generator E_CORE_WARNING ]; - yield 'Compile error in stream' => [ - '[17-Mar-2023 16:54:06 Europe/Paris] PHP Compile error: Cannot use output buffering in output buffering display handlers in /src/Process/Worker/worker-script.php on line 15', - CompileError::class - ]; + if (PHP_VERSION >= 7.3) { + yield 'Compile error in stream' => [ + '[17-Mar-2023 16:54:06 Europe/Paris] PHP Compile error: Cannot use output buffering in output buffering display handlers in /src/Process/Worker/worker-script.php on line 15', + CompileError::class + ]; + } yield 'Compile warning in stream' => [ '[17-Mar-2023 16:54:06 Europe/Paris] PHP Compile warning: Cannot use output buffering in output buffering display handlers in /src/Process/Worker/worker-script.php on line 15', diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Compile error in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Compile error in stream__0.snapshot.json new file mode 100644 index 000000000..0226cd43f --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Compile error in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Compile error", + "message": "Cannot use output buffering in output buffering display handlers", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Compile warning in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Compile warning in stream__0.snapshot.json new file mode 100644 index 000000000..6379c96a6 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Compile warning in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Compile warning", + "message": "Cannot use output buffering in output buffering display handlers", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Core error in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Core error in stream__0.snapshot.json new file mode 100644 index 000000000..11ea5cd3a --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Core error in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Core error", + "message": "Unknown: Cannot use output buffering in output buffering display handlers", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Core warning in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Core warning in stream__0.snapshot.json new file mode 100644 index 000000000..80f37a9e5 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Core warning in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Core warning", + "message": "Unknown: Cannot use output buffering in output buffering display handlers", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Deprecated in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Deprecated in stream__0.snapshot.json new file mode 100644 index 000000000..dfc901acf --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Deprecated in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Deprecated", + "message": "Methods with the same name as their class will not be constructors in a future version of PHP; Foo has a deprecated constructor", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Exception in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Exception in stream__0.snapshot.json new file mode 100644 index 000000000..dbe87aee1 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Exception in stream__0.snapshot.json @@ -0,0 +1,24 @@ +[ + { + "isException": true, + "exceptionClass": "RuntimeException", + "date": "17-Mar-2023", + "time": "16:23:28", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught RuntimeException: This file is not meant to be executed directly.", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 12, + "trace": [ + { + "date": "17-Mar-2023", + "time": "16:23:28", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 12 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Exception with line breaks in message__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Exception with line breaks in message__0.snapshot.json new file mode 100644 index 000000000..cab57f5e8 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Exception with line breaks in message__0.snapshot.json @@ -0,0 +1,24 @@ +[ + { + "isException": true, + "exceptionClass": "Codeception\\Exception\\ModuleException", + "date": "01-Apr-2023", + "time": "19:14:58", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught Codeception\\Exception\\ModuleException: lucatume\\WPBrowser\\Module\\WPLoader: WordPress bootstrap failed.\n[01-Apr-2023 19:14:58 Europe\/Paris] PHP Fatal error: Uncaught Codeception\\Exception\\ModuleException: lucatume\\WPBrowser\\Module\\WPLoader: WordPress bootstrap failed.\nError: Looks like you're using PHPUnit 5.0.0. WordPress requires at least PHPUnit 5.7.21.\nPlease use the latest PHPUnit version supported for the PHP version you are running the tests on.", + "file": "\/src\/Module\/WPLoader.php", + "line": 475, + "trace": [ + { + "date": "01-Apr-2023", + "time": "19:14:58", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/src\/Module\/WPLoader.php", + "line": 475 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Fatal error from isolatedAssertion__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Fatal error from isolatedAssertion__0.snapshot.json new file mode 100644 index 000000000..367c81d88 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Fatal error from isolatedAssertion__0.snapshot.json @@ -0,0 +1,78 @@ +[ + { + "isException": true, + "exceptionClass": "lucatume\\WPBrowser\\WordPress\\InstallationException", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught lucatume\\WPBrowser\\WordPress\\InstallationException: WordPress is not installed.", + "file": "\/src\/WordPress\/InstallationException.php", + "line": 54, + "trace": [ + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "do_action", + "args": "'shutdown'", + "file": "\/var\/tmp\/wploader_4affd42539aa6da4efba7a0de0de5319\/wp-includes\/load.php", + "line": 1124 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "WP_Hook->do_action", + "args": "Array", + "file": "\/var\/tmp\/wploader_4affd42539aa6da4efba7a0de0de5319\/wp-includes\/plugin.php", + "line": 517 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "WP_Hook->apply_filters", + "args": "'', Array", + "file": "\/var\/tmp\/wploader_4affd42539aa6da4efba7a0de0de5319\/wp-includes\/class-wp-hook.php", + "line": 332 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "call_user_func_array", + "args": "'wp_ob_end_flush...', Array", + "file": "\/var\/tmp\/wploader_4affd42539aa6da4efba7a0de0de5319\/wp-includes\/class-wp-hook.php", + "line": 308 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "ob_end_flush", + "args": "", + "file": "\/var\/tmp\/wploader_4affd42539aa6da4efba7a0de0de5319\/wp-includes\/functions.php", + "line": 5279 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\WordPress\\InstallationException::becauseWordPressIsNotInstalled", + "args": "", + "file": "\/src\/WordPress\/LoadSandbox.php", + "line": 78 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/src\/WordPress\/InstallationException.php", + "line": 54 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Fatal error in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Fatal error in stream__0.snapshot.json new file mode 100644 index 000000000..37ba2f5e0 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Fatal error in stream__0.snapshot.json @@ -0,0 +1,33 @@ +[ + { + "isException": true, + "exceptionClass": "Error", + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught Error: Class \"lucatume\\WPBrowser\\Utils\\ErrorHandling\" not found", + "file": "\/src\/Process\/SerializableThrowable.php", + "line": 24, + "trace": [ + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Process\\SerializableThrowable->__construct", + "args": "Object(Error)", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 18 + }, + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/src\/Process\/SerializableThrowable.php", + "line": 24 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Namespaced exception in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Namespaced exception in stream__0.snapshot.json new file mode 100644 index 000000000..a19571227 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Namespaced exception in stream__0.snapshot.json @@ -0,0 +1,24 @@ +[ + { + "isException": true, + "exceptionClass": "PHPUnit\\Framework\\MockObject\\RuntimeException", + "date": "17-Mar-2023", + "time": "16:32:35", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught PHPUnit\\Framework\\MockObject\\RuntimeException: Mocking did not work.", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 15, + "trace": [ + { + "date": "17-Mar-2023", + "time": "16:32:35", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 15 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Notice in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Notice in stream__0.snapshot.json new file mode 100644 index 000000000..8608329f4 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Notice in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Notice", + "message": "Undefined variable: foo", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Parse error in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Parse error in stream__0.snapshot.json new file mode 100644 index 000000000..7c5b5a42c --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Parse error in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Parse error", + "message": "syntax error, unexpected '$'", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Recoverable error in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Recoverable error in stream__0.snapshot.json new file mode 100644 index 000000000..9fa3c3374 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Recoverable error in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Recoverable error", + "message": "Object of class stdClass could not be converted to string", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Runtime notice in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Runtime notice in stream__0.snapshot.json new file mode 100644 index 000000000..cc4f2ef31 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Runtime notice in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Runtime notice", + "message": "Undefined variable: foo", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Runtime warning in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Runtime warning in stream__0.snapshot.json new file mode 100644 index 000000000..6f977cda9 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Runtime warning in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Runtime warning", + "message": "count(): Parameter must be an array or an object that implements Countable", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Strict standards in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Strict standards in stream__0.snapshot.json new file mode 100644 index 000000000..31fe6da58 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Strict standards in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Strict Standards", + "message": "Declaration of Foo::bar() should be compatible with Bar::bar()", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User deprecated in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User deprecated in stream__0.snapshot.json new file mode 100644 index 000000000..923e4451a --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User deprecated in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "User deprecated", + "message": "Cannot use output buffering in output buffering display handlers", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User error in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User error in stream__0.snapshot.json new file mode 100644 index 000000000..36587a5f1 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User error in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "User error", + "message": "Cannot use output buffering in output buffering display handlers", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User notice in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User notice in stream__0.snapshot.json new file mode 100644 index 000000000..f648ba4b5 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User notice in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "User notice", + "message": "Cannot use output buffering in output buffering display handlers", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User warning in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User warning in stream__0.snapshot.json new file mode 100644 index 000000000..e92a0b531 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__User warning in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "User warning", + "message": "Cannot use output buffering in output buffering display handlers", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Warning in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Warning in stream__0.snapshot.json new file mode 100644 index 000000000..b0420f9c2 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Warning in stream__0.snapshot.json @@ -0,0 +1,42 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "type": "Warning", + "message": "Undefined array key \"__composer_autoload_file\"", + "file": "\/src\/Process\/Protocol\/Control.php ", + "line": 16, + "trace": [ + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "{main}", + "args": "", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 0 + }, + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Process\\Protocol\\Request::fromPayload", + "args": "$encodedPayload = 'JDIzNzcNCmE6NDp7czoxMjoiYXV0b2xvYWRGaWxlIjtzOjUwOiIvVXNlcnMvbHVjYXR1bWUvb3NzL3dwLWJyb3dzZXIvdmVuZG9yL2F1dG9sb2FkLnBocCI7czoxMjoicmVxdWlyZUZpbGVzIjthOjE6e2k6MDtzOjg0OiIvVXNlcnMvbHVjYXR1bWUvb3NzL3dwLWJyb3dzZXIvdGVzdHMvdW5pdC9sdWNhdHVtZS9XUEJyb3dzZXIvTW9kdWxlL1dQTG9hZGVyVGVzdC5waHAiO31zOjM6ImN3ZCI7czo4MDoiL1VzZXJzL2x1Y2F0dW1lL29zcy93cC1icm93c2VyL3Zhci90bXAvd3Bsb2FkZXJfMDU1ZDhmMDYxZWM5NDhkY2VlM2Y4YWM5OTIzYzIxMzIiO3M6MTc6ImNvZGVjZXB0aW9uQ29uZmlnIjthOjE3OntzOjU6ImFjdG9yIjtzOjY6IlRlc3RlciI7czo1OiJwYXRocyI7YTo1Ontz'...", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 13 + }, + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Process\\Protocol\\Control->__construct", + "args": "$controlArray = ['autoloadFile' => '\/vendor\/autoload.php', 'requireFiles' => [0 => '\/tests\/unit\/lucatume\/WPBrowser\/Module\/WPLoaderTest.php'], 'cwd' => '\/var\/tmp\/wploader_055d8f061ec948dcee3f8ac9923c2132', 'codeceptionConfig' => ['actor' => 'Tester', 'paths' => [...], 'settings' => [...], 'params' => [...], 'bootstrap' => '_bootstrap.php', 'coverage' => [...], 'wpFolder' => 'var\/wordpress', 'extensions' => [...], 'actor_suffix' => 'Tester', 'support_namespace' => NULL, 'namespace' => '', 'include' => [...], 'extends' => NULL, 'suites' => [...], 'modules' => [...], 'groups' => [...], 'gherkin' => [...]]]", + "file": "\/src\/Process\/Protocol\/Request.php", + "line": 54 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Weird error in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Weird error in stream__0.snapshot.json new file mode 100644 index 000000000..4ca21f868 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__Weird error in stream__0.snapshot.json @@ -0,0 +1,14 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Weird error", + "message": "Cannot use output buffering in output buffering display handlers", + "file": "\/src\/Process\/Worker\/worker-script.php ", + "line": 15, + "trace": [] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__all the things in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__all the things in stream__0.snapshot.json new file mode 100644 index 000000000..9bb566631 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__all the things in stream__0.snapshot.json @@ -0,0 +1,193 @@ +[ + { + "isException": true, + "exceptionClass": "Error", + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught Error: Class \"lucatume\\WPBrowser\\Utils\\ErrorHandling\" not found", + "file": "\/src\/Process\/SerializableThrowable.php", + "line": 24, + "trace": [ + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Process\\SerializableThrowable->__construct", + "args": "Object(Error)", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 18 + }, + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/src\/Process\/SerializableThrowable.php", + "line": 24 + } + ] + }, + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "type": "Warning", + "message": "Undefined array key \"__composer_autoload_file\"", + "file": "\/src\/Process\/Protocol\/Control.php ", + "line": 16, + "trace": [ + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "{main}", + "args": "", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 0 + }, + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Process\\Protocol\\Request::fromPayload", + "args": "$encodedPayload = 'JDIzNzcNCmE6NDp7czoxMjoiYXV0b2xvYWRGaWxlIjtzOjUwOiIvVXNlcnMvbHVjYXR1bWUvb3NzL3dwLWJyb3dzZXIvdmVuZG9yL2F1dG9sb2FkLnBocCI7czoxMjoicmVxdWlyZUZpbGVzIjthOjE6e2k6MDtzOjg0OiIvVXNlcnMvbHVjYXR1bWUvb3NzL3dwLWJyb3dzZXIvdGVzdHMvdW5pdC9sdWNhdHVtZS9XUEJyb3dzZXIvTW9kdWxlL1dQTG9hZGVyVGVzdC5waHAiO31zOjM6ImN3ZCI7czo4MDoiL1VzZXJzL2x1Y2F0dW1lL29zcy93cC1icm93c2VyL3Zhci90bXAvd3Bsb2FkZXJfMDU1ZDhmMDYxZWM5NDhkY2VlM2Y4YWM5OTIzYzIxMzIiO3M6MTc6ImNvZGVjZXB0aW9uQ29uZmlnIjthOjE3OntzOjU6ImFjdG9yIjtzOjY6IlRlc3RlciI7czo1OiJwYXRocyI7YTo1Ontz'...", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 13 + }, + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Process\\Protocol\\Control->__construct", + "args": "$controlArray = ['autoloadFile' => '\/vendor\/autoload.php', 'requireFiles' => [0 => '\/tests\/unit\/lucatume\/WPBrowser\/Module\/WPLoaderTest.php'], 'cwd' => '\/var\/tmp\/wploader_055d8f061ec948dcee3f8ac9923c2132', 'codeceptionConfig' => ['actor' => 'Tester', 'paths' => [...], 'settings' => [...], 'params' => [...], 'bootstrap' => '_bootstrap.php', 'coverage' => [...], 'wpFolder' => 'var\/wordpress', 'extensions' => [...], 'actor_suffix' => 'Tester', 'support_namespace' => NULL, 'namespace' => '', 'include' => [...], 'extends' => NULL, 'suites' => [...], 'modules' => [...], 'groups' => [...], 'gherkin' => [...]]]", + "file": "\/src\/Process\/Protocol\/Request.php", + "line": 54 + } + ] + }, + { + "isException": true, + "exceptionClass": "RuntimeException", + "date": "17-Mar-2023", + "time": "16:23:28", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught RuntimeException: This file is not meant to be executed directly.", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 12, + "trace": [ + { + "date": "17-Mar-2023", + "time": "16:23:28", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 12 + } + ] + }, + { + "isException": true, + "exceptionClass": "PHPUnit\\Framework\\MockObject\\RuntimeException", + "date": "17-Mar-2023", + "time": "16:32:35", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught PHPUnit\\Framework\\MockObject\\RuntimeException: Mocking did not work.", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 15, + "trace": [ + { + "date": "17-Mar-2023", + "time": "16:32:35", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 15 + } + ] + }, + { + "isException": true, + "exceptionClass": "lucatume\\WPBrowser\\Exceptions\\RuntimeException", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught lucatume\\WPBrowser\\Exceptions\\RuntimeException: For Reasons", + "file": "\/includes\/core-phpunit\/includes\/bootstrap.php", + "line": 261, + "trace": [ + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Opis\\Closure\\SerializableClosure->__invoke", + "args": "", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 15 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "call_user_func_array", + "args": "Object(Closure), Array", + "file": "\/vendor\/opis\/closure\/src\/SerializableClosure.php", + "line": 109 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Module\\WPLoader->_initialize", + "args": "", + "file": "closure:\/\/static function () use ($rootDir, $wpLoader1) {\n $wpLoader1->_initialize();\n \\PHPUnit\\Framework\\Assert::assertEquals($rootDir . '\/test\/wordpress\/', $wpLoader1->_getConfig('wpRootFolder'));\n \\PHPUnit\\Framework\\Assert::assertEquals($rootDir . '\/test\/wordpress\/', $wpLoader1->getWpRootFolder());\n \\PHPUnit\\Framework\\Assert::assertEquals($rootDir . '\/test\/wordpress\/', $wpLoader1->getWpRootFolder());", + "line": 3 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Module\\WPLoader->_loadWordpress", + "args": "", + "file": "\/src\/Module\/WPLoader.php", + "line": 368 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Module\\WPLoader->installAndBootstrapInstallation", + "args": "", + "file": "\/src\/Module\/WPLoader.php", + "line": 426 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "require", + "args": "", + "file": "\/src\/Module\/WPLoader.php", + "line": 652 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/includes\/core-phpunit\/includes\/bootstrap.php", + "line": 261 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__empty stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__empty stream__0.snapshot.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__empty stream__0.snapshot.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__nested exception and random noise in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__nested exception and random noise in stream__0.snapshot.json new file mode 100644 index 000000000..61631e5f8 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__nested exception and random noise in stream__0.snapshot.json @@ -0,0 +1,78 @@ +[ + { + "isException": true, + "exceptionClass": "lucatume\\WPBrowser\\Exceptions\\RuntimeException", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught lucatume\\WPBrowser\\Exceptions\\RuntimeException: For Reasons", + "file": "\/includes\/core-phpunit\/includes\/bootstrap.php", + "line": 261, + "trace": [ + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Opis\\Closure\\SerializableClosure->__invoke", + "args": "", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 15 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "call_user_func_array", + "args": "Object(Closure), Array", + "file": "\/vendor\/opis\/closure\/src\/SerializableClosure.php", + "line": 109 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Module\\WPLoader->_initialize", + "args": "", + "file": "closure:\/\/static function () use ($rootDir, $wpLoader1) {\n $wpLoader1->_initialize();\n \\PHPUnit\\Framework\\Assert::assertEquals($rootDir . '\/test\/wordpress\/', $wpLoader1->_getConfig('wpRootFolder'));\n \\PHPUnit\\Framework\\Assert::assertEquals($rootDir . '\/test\/wordpress\/', $wpLoader1->getWpRootFolder());\n \\PHPUnit\\Framework\\Assert::assertEquals($rootDir . '\/test\/wordpress\/', $wpLoader1->getWpRootFolder());", + "line": 3 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Module\\WPLoader->_loadWordpress", + "args": "", + "file": "\/src\/Module\/WPLoader.php", + "line": 368 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Module\\WPLoader->installAndBootstrapInstallation", + "args": "", + "file": "\/src\/Module\/WPLoader.php", + "line": 426 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "require", + "args": "", + "file": "\/src\/Module\/WPLoader.php", + "line": 652 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/includes\/core-phpunit\/includes\/bootstrap.php", + "line": 261 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__nested exception in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__nested exception in stream__0.snapshot.json new file mode 100644 index 000000000..61631e5f8 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__nested exception in stream__0.snapshot.json @@ -0,0 +1,78 @@ +[ + { + "isException": true, + "exceptionClass": "lucatume\\WPBrowser\\Exceptions\\RuntimeException", + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught lucatume\\WPBrowser\\Exceptions\\RuntimeException: For Reasons", + "file": "\/includes\/core-phpunit\/includes\/bootstrap.php", + "line": 261, + "trace": [ + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Opis\\Closure\\SerializableClosure->__invoke", + "args": "", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 15 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "call_user_func_array", + "args": "Object(Closure), Array", + "file": "\/vendor\/opis\/closure\/src\/SerializableClosure.php", + "line": 109 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Module\\WPLoader->_initialize", + "args": "", + "file": "closure:\/\/static function () use ($rootDir, $wpLoader1) {\n $wpLoader1->_initialize();\n \\PHPUnit\\Framework\\Assert::assertEquals($rootDir . '\/test\/wordpress\/', $wpLoader1->_getConfig('wpRootFolder'));\n \\PHPUnit\\Framework\\Assert::assertEquals($rootDir . '\/test\/wordpress\/', $wpLoader1->getWpRootFolder());\n \\PHPUnit\\Framework\\Assert::assertEquals($rootDir . '\/test\/wordpress\/', $wpLoader1->getWpRootFolder());", + "line": 3 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Module\\WPLoader->_loadWordpress", + "args": "", + "file": "\/src\/Module\/WPLoader.php", + "line": 368 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Module\\WPLoader->installAndBootstrapInstallation", + "args": "", + "file": "\/src\/Module\/WPLoader.php", + "line": 426 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "require", + "args": "", + "file": "\/src\/Module\/WPLoader.php", + "line": 652 + }, + { + "date": "17-Mar-2023", + "time": "16:54:06", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/includes\/core-phpunit\/includes\/bootstrap.php", + "line": 261 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and exception in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and exception in stream__0.snapshot.json new file mode 100644 index 000000000..dbe87aee1 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and exception in stream__0.snapshot.json @@ -0,0 +1,24 @@ +[ + { + "isException": true, + "exceptionClass": "RuntimeException", + "date": "17-Mar-2023", + "time": "16:23:28", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught RuntimeException: This file is not meant to be executed directly.", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 12, + "trace": [ + { + "date": "17-Mar-2023", + "time": "16:23:28", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 12 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and fatal error in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and fatal error in stream__0.snapshot.json new file mode 100644 index 000000000..37ba2f5e0 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and fatal error in stream__0.snapshot.json @@ -0,0 +1,33 @@ +[ + { + "isException": true, + "exceptionClass": "Error", + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught Error: Class \"lucatume\\WPBrowser\\Utils\\ErrorHandling\" not found", + "file": "\/src\/Process\/SerializableThrowable.php", + "line": 24, + "trace": [ + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Process\\SerializableThrowable->__construct", + "args": "Object(Error)", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 18 + }, + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/src\/Process\/SerializableThrowable.php", + "line": 24 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and namespaced exception in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and namespaced exception in stream__0.snapshot.json new file mode 100644 index 000000000..a19571227 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and namespaced exception in stream__0.snapshot.json @@ -0,0 +1,24 @@ +[ + { + "isException": true, + "exceptionClass": "PHPUnit\\Framework\\MockObject\\RuntimeException", + "date": "17-Mar-2023", + "time": "16:32:35", + "timezone": "Europe\/Paris", + "type": "Fatal error", + "message": "Uncaught PHPUnit\\Framework\\MockObject\\RuntimeException: Mocking did not work.", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 15, + "trace": [ + { + "date": "17-Mar-2023", + "time": "16:32:35", + "timezone": "Europe\/Paris", + "call": "n\/a", + "args": "n\/a", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 15 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and warning in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and warning in stream__0.snapshot.json new file mode 100644 index 000000000..b0420f9c2 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise and warning in stream__0.snapshot.json @@ -0,0 +1,42 @@ +[ + { + "isException": false, + "exceptionClass": "", + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "type": "Warning", + "message": "Undefined array key \"__composer_autoload_file\"", + "file": "\/src\/Process\/Protocol\/Control.php ", + "line": 16, + "trace": [ + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "{main}", + "args": "", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 0 + }, + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Process\\Protocol\\Request::fromPayload", + "args": "$encodedPayload = 'JDIzNzcNCmE6NDp7czoxMjoiYXV0b2xvYWRGaWxlIjtzOjUwOiIvVXNlcnMvbHVjYXR1bWUvb3NzL3dwLWJyb3dzZXIvdmVuZG9yL2F1dG9sb2FkLnBocCI7czoxMjoicmVxdWlyZUZpbGVzIjthOjE6e2k6MDtzOjg0OiIvVXNlcnMvbHVjYXR1bWUvb3NzL3dwLWJyb3dzZXIvdGVzdHMvdW5pdC9sdWNhdHVtZS9XUEJyb3dzZXIvTW9kdWxlL1dQTG9hZGVyVGVzdC5waHAiO31zOjM6ImN3ZCI7czo4MDoiL1VzZXJzL2x1Y2F0dW1lL29zcy93cC1icm93c2VyL3Zhci90bXAvd3Bsb2FkZXJfMDU1ZDhmMDYxZWM5NDhkY2VlM2Y4YWM5OTIzYzIxMzIiO3M6MTc6ImNvZGVjZXB0aW9uQ29uZmlnIjthOjE3OntzOjU6ImFjdG9yIjtzOjY6IlRlc3RlciI7czo1OiJwYXRocyI7YTo1Ontz'...", + "file": "\/src\/Process\/Worker\/worker-script.php", + "line": 13 + }, + { + "date": "17-Mar-2023", + "time": "10:21:16", + "timezone": "Europe\/Paris", + "call": "lucatume\\WPBrowser\\Process\\Protocol\\Control->__construct", + "args": "$controlArray = ['autoloadFile' => '\/vendor\/autoload.php', 'requireFiles' => [0 => '\/tests\/unit\/lucatume\/WPBrowser\/Module\/WPLoaderTest.php'], 'cwd' => '\/var\/tmp\/wploader_055d8f061ec948dcee3f8ac9923c2132', 'codeceptionConfig' => ['actor' => 'Tester', 'paths' => [...], 'settings' => [...], 'params' => [...], 'bootstrap' => '_bootstrap.php', 'coverage' => [...], 'wpFolder' => 'var\/wordpress', 'extensions' => [...], 'actor_suffix' => 'Tester', 'support_namespace' => NULL, 'namespace' => '', 'include' => [...], 'extends' => NULL, 'suites' => [...], 'modules' => [...], 'groups' => [...], 'gherkin' => [...]]]", + "file": "\/src\/Process\/Protocol\/Request.php", + "line": 54 + } + ] + } +] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise in stream__0.snapshot.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__3.5__testParsesStreamCorrectly__random noise in stream__0.snapshot.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__all the things in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__all the things in stream__0.snapshot.json index 505bbf41e..9bb566631 100644 --- a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__all the things in stream__0.snapshot.json +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__all the things in stream__0.snapshot.json @@ -116,12 +116,12 @@ }, { "isException": true, - "exceptionClass": "PHPUnit\\TextUI\\RuntimeException", + "exceptionClass": "lucatume\\WPBrowser\\Exceptions\\RuntimeException", "date": "17-Mar-2023", "time": "16:54:06", "timezone": "Europe\/Paris", "type": "Fatal error", - "message": "Uncaught PHPUnit\\TextUI\\RuntimeException: For Reasons", + "message": "Uncaught lucatume\\WPBrowser\\Exceptions\\RuntimeException: For Reasons", "file": "\/includes\/core-phpunit\/includes\/bootstrap.php", "line": 261, "trace": [ diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__nested exception and random noise in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__nested exception and random noise in stream__0.snapshot.json index ae2fa6f54..61631e5f8 100644 --- a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__nested exception and random noise in stream__0.snapshot.json +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__nested exception and random noise in stream__0.snapshot.json @@ -1,12 +1,12 @@ [ { "isException": true, - "exceptionClass": "PHPUnit\\TextUI\\RuntimeException", + "exceptionClass": "lucatume\\WPBrowser\\Exceptions\\RuntimeException", "date": "17-Mar-2023", "time": "16:54:06", "timezone": "Europe\/Paris", "type": "Fatal error", - "message": "Uncaught PHPUnit\\TextUI\\RuntimeException: For Reasons", + "message": "Uncaught lucatume\\WPBrowser\\Exceptions\\RuntimeException: For Reasons", "file": "\/includes\/core-phpunit\/includes\/bootstrap.php", "line": 261, "trace": [ diff --git a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__nested exception in stream__0.snapshot.json b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__nested exception in stream__0.snapshot.json index ae2fa6f54..61631e5f8 100644 --- a/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__nested exception in stream__0.snapshot.json +++ b/tests/unit/lucatume/WPBrowser/Process/__snapshots__/StderrStreamTest__testParsesStreamCorrectly__nested exception in stream__0.snapshot.json @@ -1,12 +1,12 @@ [ { "isException": true, - "exceptionClass": "PHPUnit\\TextUI\\RuntimeException", + "exceptionClass": "lucatume\\WPBrowser\\Exceptions\\RuntimeException", "date": "17-Mar-2023", "time": "16:54:06", "timezone": "Europe\/Paris", "type": "Fatal error", - "message": "Uncaught PHPUnit\\TextUI\\RuntimeException: For Reasons", + "message": "Uncaught lucatume\\WPBrowser\\Exceptions\\RuntimeException: For Reasons", "file": "\/includes\/core-phpunit\/includes\/bootstrap.php", "line": 261, "trace": [ diff --git a/tests/unit/lucatume/WPBrowser/TestCase/WPTestCaseTest.php b/tests/unit/lucatume/WPBrowser/TestCase/WPTestCaseTest.php deleted file mode 100644 index e3a70af5f..000000000 --- a/tests/unit/lucatume/WPBrowser/TestCase/WPTestCaseTest.php +++ /dev/null @@ -1,64 +0,0 @@ - Env::get('WORDPRESS_ROOT_DIR'), - 'dbName' => Env::get('WORDPRESS_DB_NAME'), - 'dbHost' => Env::get('WORDPRESS_DB_HOST'), - 'dbUser' => Env::get('WORDPRESS_DB_USER'), - 'dbPassword' => Env::get('WORDPRESS_DB_PASSWORD'), - 'plugins' => ['woocommerce/woocommerce.php'], - ]; - $wpLoaderModule = new WPLoader($moduleContainer, $config); - - $this->assertInIsolation(static function () use ($wpLoaderModule): void { - // Initialize the module, load WordPress. - $wpLoaderModule->_initialize(); - - $testCase = new WooCommerceLoadTestCase(); - $metadata = new Metadata(); - $metadata->setServices(['di' => new Di()]); - $testCase->setMetadata($metadata); - - // Run the first test. - $testCase->setName('testWordPressLoadedCorrectly'); - $wrapper = new TestCaseWrapper($testCase); - $wrapper->test(); - - // Run the second test. - $testCase->setName('testWooCommerceIsActivated'); - $wrapper = new TestCaseWrapper($testCase); - $wrapper->test(); - - // Run the third test. - $testCase->setName('testWooCommerceFunctionsExist'); - $wrapper = new TestCaseWrapper($testCase); - $wrapper->test(); - }); - } -} diff --git a/tests/unit/lucatume/WPBrowser/Utils/ChromedriverInstallerTest.php b/tests/unit/lucatume/WPBrowser/Utils/ChromedriverInstallerTest.php index d0a359823..ddb567b8b 100644 --- a/tests/unit/lucatume/WPBrowser/Utils/ChromedriverInstallerTest.php +++ b/tests/unit/lucatume/WPBrowser/Utils/ChromedriverInstallerTest.php @@ -5,11 +5,13 @@ use lucatume\WPBrowser\Exceptions\InvalidArgumentException; use lucatume\WPBrowser\Exceptions\RuntimeException; +use lucatume\WPBrowser\Tests\Traits\TmpFilesCleanup; use lucatume\WPBrowser\Tests\Traits\UopzFunctions; class ChromedriverInstallerTest extends \Codeception\Test\Unit { use UopzFunctions; + use TmpFilesCleanup; /** * It should throw if detected platform is not supported @@ -158,6 +160,7 @@ public function should_throw_if_it_cannot_get_milestone_downloads(): void }, true); $ci = new ChromedriverInstaller(null, 'linux64', codecept_data_dir('bins/chrome-mock')); + $ci->useEnvZipFile(false); $this->expectException(RuntimeException::class); $this->expectExceptionCode(ChromedriverInstaller::ERR_FETCH_MILESTONE_DOWNLOADS); @@ -177,6 +180,7 @@ public function should_throw_if_response_is_not_valid_json(): void }, true); $ci = new ChromedriverInstaller(null, 'linux64', codecept_data_dir('bins/chrome-mock')); + $ci->useEnvZipFile(false); $this->expectException(RuntimeException::class); $this->expectExceptionCode(ChromedriverInstaller::ERR_DECODE_MILESTONE_DOWNLOADS); @@ -198,6 +202,7 @@ public function should_throw_if_download_url_for_chrome_version_cannot_be_found_ }, true); $ci = new ChromedriverInstaller(null, 'linux64', codecept_data_dir('bins/chrome-mock')); + $ci->useEnvZipFile(false); $this->expectException(RuntimeException::class); $this->expectExceptionCode(ChromedriverInstaller::ERR_DOWNLOAD_URL_NOT_FOUND); @@ -213,12 +218,12 @@ public function should_throw_if_download_url_for_chrome_version_cannot_be_found_ public function should_throw_if_existing_zip_file_cannot_be_removed(): void { $this->uopzSetFunctionReturn('sys_get_temp_dir', codecept_output_dir()); - touch(codecept_output_dir('chromedriver-linux64.zip')); $this->uopzSetFunctionReturn('unlink', function (string $file): bool { - return $file === codecept_output_dir('chromedriver-linux64.zip') ? false : unlink($file); + return preg_match('~chromedriver\\.zip$~' ,$file) ? false : unlink($file); }, true); $ci = new ChromedriverInstaller(null, 'linux64', codecept_data_dir('bins/chrome-mock')); + $ci->useEnvZipFile(false); $this->expectException(RuntimeException::class); $this->expectExceptionCode(ChromedriverInstaller::ERR_REMOVE_EXISTING_ZIP_FILE); @@ -247,25 +252,6 @@ public function should_throw_if_existing_binary_cannot_be_removed(): void $ci->install($dir); } - /** - * It should throw if new binary cannot be moved in place - * - * @test - */ - public function should_throw_if_new_binary_cannot_be_moved_in_place(): void - { - $dir = Filesystem::tmpDir('chromedriver_installer_'); - $this->uopzSetFunctionReturn('sys_get_temp_dir', codecept_output_dir()); - $this->uopzSetFunctionReturn('rename', false); - - $ci = new ChromedriverInstaller(null, 'linux64', codecept_data_dir('bins/chrome-mock')); - - $this->expectException(RuntimeException::class); - $this->expectExceptionCode(ChromedriverInstaller::ERR_MOVE_BINARY); - - $ci->install($dir); - } - /** * It should throw if new binary cannot be made executable * @@ -302,6 +288,5 @@ public function should_correctly_install_chromedriver(): void $this->assertEquals($dir . '/chromedriver', $executablePath); $this->assertFileExists($executablePath); - $this->assertFileExists($tmpDir . '/chromedriver-linux64.zip'); } } diff --git a/tests/unit/lucatume/WPBrowser/Utils/ComposerTest.php b/tests/unit/lucatume/WPBrowser/Utils/ComposerTest.php index a9ef57b72..c4a13d62b 100644 --- a/tests/unit/lucatume/WPBrowser/Utils/ComposerTest.php +++ b/tests/unit/lucatume/WPBrowser/Utils/ComposerTest.php @@ -3,11 +3,11 @@ namespace lucatume\WPBrowser\Utils; +use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process; use lucatume\WPBrowser\Exceptions\RuntimeException; use lucatume\WPBrowser\Tests\Traits\ClassStubs; use lucatume\WPBrowser\Tests\Traits\UopzFunctions; use PHPUnit\Framework\Assert; -use Symfony\Component\Process\Process; use lucatume\WPBrowser\Utils\Filesystem as FS; class ComposerTest extends \Codeception\Test\Unit @@ -47,7 +47,11 @@ public function should_throw_if_trying_to_build_on_non_readable_file(): void */ public function should_throw_if_trying_to_build_on_non_json_file(): void { - $this->expectException(\JsonException::class); + if (PHP_VERSION >= 8.0 ) { + $this->expectException(\JsonException::class); + } else { + $this->expectException(\Exception::class); + } new Composer(__FILE__); } diff --git a/tests/unit/lucatume/WPBrowser/Utils/SerializerTest.php b/tests/unit/lucatume/WPBrowser/Utils/SerializerTest.php index 8a1fe6ca6..2beee5d73 100644 --- a/tests/unit/lucatume/WPBrowser/Utils/SerializerTest.php +++ b/tests/unit/lucatume/WPBrowser/Utils/SerializerTest.php @@ -13,7 +13,7 @@ use Serializable; use Throwable; -class TestSerializableObject implements Serializable +class TestSerializableObject { public string $foo = 'bar'; public int $number = 23; @@ -29,16 +29,6 @@ public function __unserialize(array $data): void $this->{$key} = $value; } } - - public function serialize() - { - return serialize($this->__serialize()); - } - - public function unserialize(string $data) - { - $this->__unserialize(unserialize($data)); - } } class SerializerTest extends Unit diff --git a/tests/unit/lucatume/WPBrowser/Utils/chromedriver b/tests/unit/lucatume/WPBrowser/Utils/chromedriver new file mode 100755 index 000000000..b61e6c4f6 Binary files /dev/null and b/tests/unit/lucatume/WPBrowser/Utils/chromedriver differ diff --git a/tests/unit/lucatume/WPBrowser/WordPress/InstallationState/ConfiguredTest.php b/tests/unit/lucatume/WPBrowser/WordPress/InstallationState/ConfiguredTest.php index 1c1bbbde2..0399bf959 100644 --- a/tests/unit/lucatume/WPBrowser/WordPress/InstallationState/ConfiguredTest.php +++ b/tests/unit/lucatume/WPBrowser/WordPress/InstallationState/ConfiguredTest.php @@ -46,7 +46,7 @@ public function should_throw_when_building_on_non_existing_root_directory(): voi */ public function should_throw_when_building_on_empty_root_directory(): void { - $wpRootDir = Fs::tmpDir('configured_',); + $wpRootDir = Fs::tmpDir('configured_'); $this->expectException(InstallationException::class); $this->expectExceptionCode(InstallationException::STATE_EMPTY); @@ -336,7 +336,7 @@ public function should_throw_if_installation_request_fails_with_output(): void $this->expectException(InstallationException::class); $this->expectExceptionCode(InstallationException::INSTALLATION_FAIL); - $this->expectExceptionMessageMatches('/errors occurred/'); + $this->expectExceptionMessageRegExp('/errors occurred/'); $configured->install('https://wp.local', 'admin', @@ -368,7 +368,7 @@ public function should_throw_if_installation_request_fails_with_throwable(): voi $this->expectException(InstallationException::class); $this->expectExceptionCode(InstallationException::INSTALLATION_FAIL); - $this->expectExceptionMessageMatches('/Something is amiss/'); + $this->expectExceptionMessageRegExp('/Something is amiss/'); $configured->install('https://wp.local', 'admin', diff --git a/tests/unit/lucatume/WPBrowser/WordPress/InstallationState/__snapshots__/ScaffoldedTest__3.5__should_allow_configuring_an_installation_using_custom_configuration__0.snapshot.php b/tests/unit/lucatume/WPBrowser/WordPress/InstallationState/__snapshots__/ScaffoldedTest__3.5__should_allow_configuring_an_installation_using_custom_configuration__0.snapshot.php new file mode 100644 index 000000000..5925fa7e4 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/WordPress/InstallationState/__snapshots__/ScaffoldedTest__3.5__should_allow_configuring_an_installation_using_custom_configuration__0.snapshot.php @@ -0,0 +1,98 @@ +markTestSkipped('PHP 8.0 required.'); + } + $db = new MysqlDatabase( Random::dbName(), Env::get('WORDPRESS_DB_USER'), diff --git a/tests/unit/lucatume/WPBrowser/WordPress/__snapshots__/WpConfigFileGeneratorTest__3.5__should_correctly_produce_a_wp_config_php_file_contents_provided_db_and_configuration_data__0.snapshot.php b/tests/unit/lucatume/WPBrowser/WordPress/__snapshots__/WpConfigFileGeneratorTest__3.5__should_correctly_produce_a_wp_config_php_file_contents_provided_db_and_configuration_data__0.snapshot.php new file mode 100644 index 000000000..c78729263 --- /dev/null +++ b/tests/unit/lucatume/WPBrowser/WordPress/__snapshots__/WpConfigFileGeneratorTest__3.5__should_correctly_produce_a_wp_config_php_file_contents_provided_db_and_configuration_data__0.snapshot.php @@ -0,0 +1,94 @@ +assertEquals(1, useMemo(__NAMESPACE__ . '\__test_useMemo_function')); + } + foreach (range(2, 4) as $k) { + $this->assertEquals($k, useMemo(__NAMESPACE__ . '\__test_useMemo_function', [$k])); + } + } + + public function test_useMemo_with_static_method(): void + { + foreach (range(1, 3) as $k) { + $this->assertEquals(1, useMemo([__CLASS__, '_test_useMemoStaticMethod'])); + } + foreach (range(2, 4) as $k) { + $this->assertEquals($k, useMemo([__CLASS__, '_test_useMemoStaticMethod'], [$k])); + } + } + + public function useMemoInstanceMethod(): int + { + static $calls = 1; + + return $calls++; + } + + public function test_useMemo_with_instance_method(): void + { + foreach (range(1, 3) as $k) { + $this->assertEquals(1, useMemo([$this, 'useMemoInstanceMethod'])); + } + foreach (range(2, 4) as $k) { + $this->assertEquals($k, useMemo([$this, 'useMemoInstanceMethod'], [$k])); + } + } + + public function test_useMemo_with_closure(): void + { + $zorps = 0; + $closure = function () use (&$zorps) { + static $calls = 1; + return $calls++; + }; + + foreach (range(1, 3) as $k) { + $this->assertEquals(1, useMemo($closure)); + } + foreach (range(2, 4) as $k) { + $this->assertEquals($k, useMemo($closure, [$k])); + } + } + + public function test_useMemo_with_invocable_object(): void + { + foreach (range(1, 3) as $k) { + $object = new _UseMemoInvocableObject(); + $this->assertEquals(1, useMemo($object)); + } + foreach (range(2, 4) as $k) { + $this->assertEquals($k, useMemo($object, [$k])); + } + } + + public function test_useMemoString_throws_if_result_not_string(): void + { + $this->expectException(RuntimeException::class); + useMemoString(function () { + return 1; + }); + } + + public function test_useMemo_throws_if_callback_is_not_callable_string(): void + { + $this->expectException(InvalidArgumentException::class); + useMemo('not_a_function'); + } + + public function test_useMemo_throws_if_callback_is_not_callable_array(): void + { + $this->expectException(InvalidArgumentException::class); + useMemo([__CLASS__, 'not_a_method']); + } +} diff --git a/tests/_support/TestCase/WooCommerceLoadTestCase.php b/tests/wploadersuite/WooCommerceLoadTest.php similarity index 82% rename from tests/_support/TestCase/WooCommerceLoadTestCase.php rename to tests/wploadersuite/WooCommerceLoadTest.php index 8b2fd21ce..cd6c955b0 100644 --- a/tests/_support/TestCase/WooCommerceLoadTestCase.php +++ b/tests/wploadersuite/WooCommerceLoadTest.php @@ -1,10 +1,8 @@