From 9d70497b8b74166307fc559562cc7bd237d23958 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Tue, 21 Sep 2021 19:28:47 +0000 Subject: [PATCH] Build/Test Tools: Introduce the PHPUnit Polyfills package for easier cross branch testing. This backports the PHPUnit Polyfills package and related test infrastructure changes to make it easier for developers to continue testing on multiple versions WordPress while adding tests for newer versions of PHP, which require more modern PHPUnit practices. One of the changes included is the addition of wrappers for the new snake_case fixture methods in PHPUnit. This allows the native camelCase standard in PHPUnit to be used, but allows for developers to transition to the new naming conventions. Props hellofromTonya, jrf, SergeyBiryukov, johnbillion, netweb, schlessera, jeherve, lucatume, desrosj. Merges [51559,51560,51810-51813,51828] to the 5.7 branch. See #53911. git-svn-id: https://develop.svn.wordpress.org/branches/5.7@51839 602fd350-edb4-49c9-b593-d223f7449a82 --- .github/workflows/phpunit-tests.yml | 10 +- .github/workflows/test-coverage.yml | 18 ++- composer.json | 3 +- composer.lock | 67 ++++++++++- tests/phpunit/includes/bootstrap.php | 111 ++++++++++++++++++- tests/phpunit/includes/phpunit7/testcase.php | 79 +++++++++---- tests/phpunit/includes/testcase.php | 79 +++++++++---- 7 files changed, 313 insertions(+), 54 deletions(-) diff --git a/.github/workflows/phpunit-tests.yml b/.github/workflows/phpunit-tests.yml index 8545b4dbcd..0d2611b901 100644 --- a/.github/workflows/phpunit-tests.yml +++ b/.github/workflows/phpunit-tests.yml @@ -21,7 +21,6 @@ on: env: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: ${{ true }} - COMPOSER_INSTALL: ${{ false }} # Controls which NPM script to use for running PHPUnit tests. Options ar `php` and `php-composer`. PHPUNIT_SCRIPT: php LOCAL_PHP_MEMCACHED: ${{ false }} @@ -137,11 +136,9 @@ jobs: - name: Get composer cache directory id: composer-cache - if: ${{ env.COMPOSER_INSTALL == true || env.LOCAL_PHP == '8.0-fpm' }} run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache Composer dependencies - if: ${{ env.COMPOSER_INSTALL == true || env.LOCAL_PHP == '8.0-fpm' }} uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 env: cache-name: cache-composer-dependencies @@ -150,7 +147,6 @@ jobs: key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} - name: Install Composer dependencies - if: ${{ env.COMPOSER_INSTALL == true || env.LOCAL_PHP == '8.0-fpm' }} run: | docker-compose run --rm php composer --version @@ -160,6 +156,12 @@ jobs: if [ ${{ env.LOCAL_PHP }} == '8.0-fpm' ]; then docker-compose run --rm php composer install --ignore-platform-reqs echo "PHPUNIT_SCRIPT=php-composer" >> $GITHUB_ENV + elif [ ${{ env.LOCAL_PHP }} == '7.1-fpm' ]; then + docker-compose run --rm php composer update + git checkout -- composer.lock + elif [[ ${{ env.LOCAL_PHP }} == '5.6.20-fpm' || ${{ env.LOCAL_PHP }} == '7.0-fpm' ]]; then + docker-compose run --rm php composer require --dev phpunit/phpunit:"^5.7" --update-with-dependencies + git checkout -- composer.lock composer.json else docker-compose run --rm php composer install fi diff --git a/.github/workflows/test-coverage.yml b/.github/workflows/test-coverage.yml index abdc989681..8d7f8e9b1f 100644 --- a/.github/workflows/test-coverage.yml +++ b/.github/workflows/test-coverage.yml @@ -18,7 +18,6 @@ on: env: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: ${{ true }} - COMPOSER_INSTALL: ${{ false }} # Controls which NPM script to use for running PHPUnit tests. Options ar `php` and `php-composer`. PHPUNIT_SCRIPT: php LOCAL_PHP: '7.4-fpm' @@ -95,6 +94,23 @@ jobs: - name: Install Dependencies run: npm ci + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache Composer dependencies + uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 + env: + cache-name: cache-composer-dependencies + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + + - name: Install Composer dependencies + run: | + docker-compose run --rm php composer --version + docker-compose run --rm php composer install + - name: Docker debug information run: | docker -v diff --git a/composer.json b/composer.json index 4997175bfe..430c1069eb 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,8 @@ "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7.0", "wp-coding-standards/wpcs": "~2.3.0", "phpcompatibility/phpcompatibility-wp": "^2.1.0", - "phpunit/phpunit": "^7.5" + "phpunit/phpunit": "^7.5", + "yoast/phpunit-polyfills": "^1.0.1" }, "autoload-dev": { "files": [ diff --git a/composer.lock b/composer.lock index 007bbf83ea..e7dafe626b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "463db2b4afb439fb63d93173c0852e27", + "content-hash": "d8bcbf1466f6595287a44721f525844d", "packages": [], "packages-dev": [ { @@ -1827,6 +1827,69 @@ "wordpress" ], "time": "2020-05-13T23:57:56+00:00" + }, + { + "name": "yoast/phpunit-polyfills", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", + "reference": "f014fb21c2b0038fd329515d59025af42fb98715" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/f014fb21c2b0038fd329515d59025af42fb98715", + "reference": "f014fb21c2b0038fd329515d59025af42fb98715", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^0.5", + "php-parallel-lint/php-parallel-lint": "^1.3.0", + "yoast/yoastcs": "^2.1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, + "autoload": { + "files": [ + "phpunitpolyfills-autoload.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Team Yoast", + "email": "support@yoast.com", + "homepage": "https://yoast.com" + }, + { + "name": "Contributors", + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills/graphs/contributors" + } + ], + "description": "Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit cross-version compatible tests", + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills", + "keywords": [ + "phpunit", + "polyfill", + "testing" + ], + "support": { + "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", + "source": "https://github.com/Yoast/PHPUnit-Polyfills" + }, + "time": "2021-08-09T16:28:08+00:00" } ], "aliases": [], @@ -1838,5 +1901,5 @@ "php": ">=5.6" }, "platform-dev": [], - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.1.0" } diff --git a/tests/phpunit/includes/bootstrap.php b/tests/phpunit/includes/bootstrap.php index 36f54541b2..feb0ba8a5e 100644 --- a/tests/phpunit/includes/bootstrap.php +++ b/tests/phpunit/includes/bootstrap.php @@ -44,15 +44,122 @@ if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS && ! is_dir( ABSPATH ) $phpunit_version = tests_get_phpunit_version(); -if ( version_compare( $phpunit_version, '5.4', '<' ) || version_compare( $phpunit_version, '8.0', '>=' ) ) { +if ( version_compare( $phpunit_version, '5.7.21', '<' ) || version_compare( $phpunit_version, '8.0', '>=' ) ) { printf( - "Error: Looks like you're using PHPUnit %s. WordPress requires at least PHPUnit 5.4 and is currently only compatible with PHPUnit up to 7.x.\n", + "Error: Looks like you're using PHPUnit %s. WordPress requires at least PHPUnit 5.7.21 and is currently only compatible with PHPUnit up to 7.x.\n", $phpunit_version ); echo "Please use the latest PHPUnit version from the 7.x branch.\n"; exit( 1 ); } +/* + * Load the PHPUnit Polyfills autoloader. + * + * The PHPUnit Polyfills are a requirement for the WP test suite. + * + * For running the Core tests, the Make WordPress Core handbook contains step-by-step instructions + * on how to get up and running for a variety of supported workflows: + * {@link https://make.wordpress.org/core/handbook/testing/automated-testing/phpunit/#test-running-workflow-options} + * + * Plugin/theme integration tests can handle this in any of the following ways: + * - When using a full WP install: run `composer install` for the WP install prior to running the tests. + * - When using a partial WP test suite install: + * - Add a `yoast/phpunit-polyfills` (dev) requirement to the plugin/theme's own `composer.json` file. + * - And then: + * - Either load the PHPUnit Polyfills autoload file prior to running the WP core bootstrap file. + * - Or declare a `WP_TESTS_PHPUNIT_POLYFILLS_PATH` constant containing the absolute path to the + * root directory of the PHPUnit Polyfills installation. + * If the constant is used, it is strongly recommended to declare this constant in the plugin/theme's + * own test bootstrap file. + * The constant MUST be declared prior to calling this file. + */ +if ( ! class_exists( 'Yoast\PHPUnitPolyfills\Autoload' ) ) { + // Default location of the autoloader for WP core test runs. + $phpunit_polyfills_autoloader = dirname( dirname( dirname( __DIR__ ) ) ) . '/vendor/yoast/phpunit-polyfills/phpunitpolyfills-autoload.php'; + $phpunit_polyfills_error = false; + + // Allow for a custom installation location to be provided for plugin/theme integration tests. + if ( defined( 'WP_TESTS_PHPUNIT_POLYFILLS_PATH' ) ) { + $phpunit_polyfills_path = WP_TESTS_PHPUNIT_POLYFILLS_PATH; + + if ( is_string( WP_TESTS_PHPUNIT_POLYFILLS_PATH ) + && '' !== WP_TESTS_PHPUNIT_POLYFILLS_PATH + ) { + // Be tolerant to the path being provided including the filename. + if ( substr( $phpunit_polyfills_path, -29 ) !== 'phpunitpolyfills-autoload.php' ) { + $phpunit_polyfills_path = rtrim( $phpunit_polyfills_path, '/\\' ); + $phpunit_polyfills_path = $phpunit_polyfills_path . '/phpunitpolyfills-autoload.php'; + } + + $phpunit_polyfills_autoloader = $phpunit_polyfills_path; + } else { + $phpunit_polyfills_error = true; + } + } + + if ( $phpunit_polyfills_error || ! file_exists( $phpunit_polyfills_autoloader ) ) { + echo 'Error: The PHPUnit Polyfills library is a requirement for running the WP test suite.' . PHP_EOL; + if ( defined( 'WP_TESTS_PHPUNIT_POLYFILLS_PATH' ) ) { + printf( + 'The PHPUnit Polyfills autoload file was not found in "%s"' . PHP_EOL, + WP_TESTS_PHPUNIT_POLYFILLS_PATH + ); + echo 'Please verify that the file path provided in the WP_TESTS_PHPUNIT_POLYFILLS_PATH constant is correct.' . PHP_EOL; + echo 'The WP_TESTS_PHPUNIT_POLYFILLS_PATH constant should contain an absolute path to the root directory' + . ' of the PHPUnit Polyfills library.' . PHP_EOL; + } elseif ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) { + echo 'You need to run `composer install` before running the tests.' . PHP_EOL; + echo 'Once the dependencies are installed, you can run the tests using the Composer-installed version' + . ' of PHPUnit or using a PHPUnit phar file, but the dependencies do need to be installed' + . ' whichever way the tests are run.' . PHP_EOL; + } else { + echo 'If you are trying to run plugin/theme integration tests, make sure the PHPUnit Polyfills library' + . ' (https://github.com/Yoast/PHPUnit-Polyfills) is available and either load the autoload file' + . ' of this library in your own test bootstrap before calling the WP Core test bootstrap file;' + . ' or set the absolute path to the PHPUnit Polyfills library in a "WP_TESTS_PHPUNIT_POLYFILLS_PATH"' + . ' constant to allow the WP Core bootstrap to load the Polyfills.' . PHP_EOL . PHP_EOL; + echo 'If you are trying to run the WP Core tests, make sure to set the "WP_RUN_CORE_TESTS" constant' + . ' to 1 and run `composer install` before running the tests.' . PHP_EOL; + echo 'Once the dependencies are installed, you can run the tests using the Composer-installed' + . ' version of PHPUnit or using a PHPUnit phar file, but the dependencies do need to be' + . ' installed whichever way the tests are run.' . PHP_EOL; + } + exit( 1 ); + } + + require_once $phpunit_polyfills_autoloader; +} +unset( $phpunit_polyfills_autoloader, $phpunit_polyfills_error, $phpunit_polyfills_path ); + +/* + * Minimum version of the PHPUnit Polyfills package as declared in `composer.json`. + * Only needs updating when new polyfill features start being used in the test suite. + */ +$phpunit_polyfills_minimum_version = '1.0.1'; +if ( class_exists( '\Yoast\PHPUnitPolyfills\Autoload' ) + && ( defined( '\Yoast\PHPUnitPolyfills\Autoload::VERSION' ) === false + || version_compare( Yoast\PHPUnitPolyfills\Autoload::VERSION, $phpunit_polyfills_minimum_version, '<' ) ) +) { + printf( + 'Error: Version mismatch detected for the PHPUnit Polyfills.' + . ' Please ensure that PHPUnit Polyfills %s or higher is loaded. Found version: %s' . PHP_EOL, + $phpunit_polyfills_minimum_version, + defined( '\Yoast\PHPUnitPolyfills\Autoload::VERSION' ) ? Yoast\PHPUnitPolyfills\Autoload::VERSION : '1.0.0 or lower' + ); + if ( defined( 'WP_TESTS_PHPUNIT_POLYFILLS_PATH' ) ) { + printf( + 'Please ensure that the PHPUnit Polyfill installation in "%s" is updated to version %s or higher.' . PHP_EOL, + WP_TESTS_PHPUNIT_POLYFILLS_PATH, + $phpunit_polyfills_minimum_version + ); + } elseif ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) { + echo 'Please run `composer install` to install the latest version.' . PHP_EOL; + } + exit( 1 ); +} +unset( $phpunit_polyfills_minimum_version ); + // If running core tests, check if all the required PHP extensions are loaded before running the test suite. if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) { $required_extensions = array( diff --git a/tests/phpunit/includes/phpunit7/testcase.php b/tests/phpunit/includes/phpunit7/testcase.php index 9a8ddc12de..1174b85494 100644 --- a/tests/phpunit/includes/phpunit7/testcase.php +++ b/tests/phpunit/includes/phpunit7/testcase.php @@ -1,5 +1,21 @@