diff --git a/.env.testing.example b/.env.testing.example new file mode 100644 index 000000000..43d3f7642 --- /dev/null +++ b/.env.testing.example @@ -0,0 +1,17 @@ +# WP-Browser configuration +# https://wpbrowser.wptestkit.dev/ +# Copy to .env.testing and adjust for your environment. +# These defaults match the reusable codecoverage workflow (MySQL service on 33306, MYSQL_DATABASE=tests-wordpress). + +WP_ROOT_FOLDER="wordpress" + +TEST_DB_HOST="127.0.0.1" +TEST_DB_PORT="33306" +TEST_DB_USER="root" +TEST_DB_PASSWORD="password" + +TEST_DB_NAME="tests-wordpress" +TEST_TABLE_PREFIX="wp_" + +TEST_SITE_WP_DOMAIN="localhost:8888" +TEST_SITE_ADMIN_EMAIL="admin@example.org" diff --git a/.github/workflows/codecoverage-main.yml b/.github/workflows/codecoverage-main.yml index 7f7ef20fe..8d5a0c1a2 100644 --- a/.github/workflows/codecoverage-main.yml +++ b/.github/workflows/codecoverage-main.yml @@ -13,179 +13,29 @@ on: - main workflow_dispatch: -jobs: +permissions: + contents: read - codecoverage: +jobs: + get-repo-name: runs-on: ubuntu-latest - - services: - mysql: - image: mysql:5.7 # Password auth did not work on 8.0 on PHP 7.3, it did seem to work for PHP 7.4+ - env: # These are the same username and password as the wp-env container defaults - MYSQL_ROOT_PASSWORD: password - MYSQL_DATABASE: tests-wordpress - ports: # This mapping matches the .wp-env.json configuration - - 33306:3306 - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 - - strategy: - matrix: # Supported PHP versions - php: [ '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4' ] - + outputs: + repository-name: ${{ steps.repo-name.outputs.name }} steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - fetch-depth: 0 # attempting to get all branch names. - - # TODO: a DEPLOY_KEY is needed to enable gh-pages for the first time (the branch can be created and pushed but - # it will not be reachable as a website). - # Consider @see https://github.com/peaceiris/actions-gh-pages - # - name: Check does gh-pages branch need to be created - # run: | - # git branch -l; - # if [[ $(git branch -l gh-pages) == "" ]]; then - # gh_pages_branch_needed=true; - # echo "gh-pages branch is needed"; - # else - # gh_pages_branch_needed=false - # echo "gh-pages branch already exists"; - # fi - # echo "GH_PAGES_BRANCH_NEEDED=$gh_pages_branch_needed" >> $GITHUB_ENV; - # mkdir gh-pages - # - # - name: Maybe create gh-pages branch - # if: ${{ env.GH_PAGES_BRANCH_NEEDED }} - # uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 - # with: - # github_token: ${{ secrets.GITHUB_TOKEN }} - # publish_dir: ./gh-pages - # force_orphan: true - # allow_empty_commit: true - # commit_message: "🤖 Creating gh-pages branch" - - - name: Checkout GitHub Pages branch for code coverage report - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - ref: gh-pages - path: gh-pages - - - name: Install PHP - uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0 - with: - php-version: ${{ matrix.php }} - coverage: xdebug - tools: composer, jaschilz/php-coverage-badger - extensions: zip - - - name: Read .env.testing - uses: c-py/action-dotenv-to-setenv@925b5d99a3f1e4bd7b4e9928be4e2491e29891d9 # v5 - with: - env-file: .env.testing - - - name: Run composer install - continue-on-error: true - run: composer install -v - - - name: Allow writing to wp-content - if: ${{ hashFiles('wp-content') != '' }} # TODO: This may be incorrect since it's a directory. - run: sudo chmod -R a+w wp-content - - # On main, there will be a previous coverage report. On PRs we create a new directory using the commit SHA. - - name: Clear previous code coverage - if: ${{ (matrix.php == '7.3') && (github.ref == 'refs/heads/main') }} - run: | - rm -rf gh-pages/phpunit || true; - mkdir gh-pages/phpunit || true; + - name: Extract repository name + id: repo-name + run: echo "name=$(echo ${{ github.repository }} | cut -d'/' -f2)" >> $GITHUB_OUTPUT - - name: Run unit tests - if: ${{ hashFiles('tests/phpunit/bootstrap.php') != '' }} # Only run unit tests if they are present. - run: XDEBUG_MODE=coverage vendor/bin/phpunit --bootstrap tests/phpunit/bootstrap.php --coverage-php tests/_output/unit.cov --debug - - - name: Run wpunit tests - run: XDEBUG_MODE=coverage vendor/bin/codecept run wpunit --coverage tests/_output/wpunit.cov --debug - - # For PRs, we'll generate the coverage report on each pushed commit - - name: Merge code coverage for PR - if: ${{ matrix.php == '7.3' && github.event_name == 'pull_request' }} - run: | - vendor/bin/phpcov merge --clover clover.xml tests/_output/; - vendor/bin/phpcov merge --clover gh-pages/${{ github.event.pull_request.head.sha }}/phpunit/clover.xml --php gh-pages/${{ github.event.pull_request.head.sha }}/phpunit/phpunit.cov --html gh-pages/${{ github.event.pull_request.head.sha }}/phpunit/html/ tests/_output/; - - # On main, we want it output to a different path - - name: Merge code coverage for main - if: ${{ (matrix.php == '7.3') && (github.ref == 'refs/heads/main') }} - run: | - vendor/bin/phpcov merge --clover clover.xml tests/_output/; - vendor/bin/phpcov merge --clover gh-pages/phpunit/clover.xml --php gh-pages/phpunit/phpunit.cov --html gh-pages/phpunit/html/ tests/_output/; - - # This makes the coverage percentage available in `{{ steps.coverage-percentage.outputs.coverage-rounded }}`. - - name: Check test coverage - if: ${{ matrix.php == '7.3' }} - uses: johanvanhelden/gha-clover-test-coverage-check@2543c79a701f179bd63aa14c16c6938c509b2cec # v1 - id: coverage-percentage - with: - percentage: 25 - exit: false - filename: clover.xml - rounded-precision: "0" - - # See: https://github.blog/2009-12-29-bypassing-jekyll-on-github-pages/ - - name: Add `.nojekyll` file so code coverage report successfully deploys to gh-pages - if: ${{ (matrix.php == '7.3') }} - working-directory: gh-pages - run: | - touch .nojekyll - git add -- .nojekyll * - - - name: Update README coverage badge - if: ${{ (matrix.php == '7.3') && (github.ref == 'refs/heads/main') }} # only commit on main, on the PHP version we're using in production. - run: php-coverage-badger clover.xml gh-pages/phpunit/coverage.svg - - - name: Generate PR coverage badge - if: ${{ (matrix.php == '7.3') && github.event_name == 'pull_request' }} - run: php-coverage-badger clover.xml gh-pages/${{ github.event.pull_request.head.sha }}/phpunit/coverage.svg - - - name: Commit code coverage to gh-pages - if: ${{ matrix.php == '7.3' }} - uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 - with: - repository: gh-pages - branch: gh-pages - commit_message: ${{ format('🤖 Save code coverage report to gh-pages {0}%', steps.coverage-percentage.outputs.coverage-rounded) }} - commit_options: "" - env: - GITHUB_TOKEN: "${{ github.token }}" - - - name: Add coverage badge to PR comment - if: ${{ matrix.php == '7.3' && github.event_name == 'pull_request' }} - run: | - echo "[![Code Coverage ](https://newfold-labs.github.io/wp-module-performance/${{ github.event.pull_request.head.sha }}/phpunit/coverage.svg)](https://newfold-labs.github.io/wp-module-performance/${{ github.event.pull_request.head.sha }}/phpunit/html/)" >> coverage-comment.md - echo "" >> coverage-comment.md - echo "" >> coverage-comment.md - - - name: Add coverage report link to PR comment - if: ${{ matrix.php == '7.3' && github.event_name == 'pull_request' }} - run: | - echo "${{ format('[project coverage report {0}%](https://newfold-labs.github.io/wp-module-performance/{1}/phpunit/html/) @ {2}', steps.coverage-percentage.outputs.coverage-rounded, github.event.pull_request.head.sha, github.event.pull_request.head.sha) }}" >> coverage-comment.md - echo "" >> coverage-comment.md - echo "" >> coverage-comment.md - - - name: Add phpcov uncovered lines report to PR comment - if: ${{ matrix.php == '7.3' && github.event_name == 'pull_request' }} - continue-on-error: true # phpcov can fail if there are no uncovered lines - run: | - BRANCHED_COMMIT=$(git rev-list origin..HEAD | tail -n 1); - echo "BRANCHED_COMMIT=$BRANCHED_COMMIT" - git diff $BRANCHED_COMMIT...${{ github.event.pull_request.head.sha }} > branch.diff; - cat branch.diff; - OUTPUT=${vendor/bin/phpcov patch-coverage --path-prefix $(pwd) ./gh-pages/${{ github.event.pull_request.head.sha }}/phpunit/phpunit.cov branch.diff || true} - echo $OUTPUT; - echo "$OUTPUT" >> coverage-comment.md - - - name: Add coverage PR comment - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2.8.2 - if: ${{ matrix.php == '7.3' && github.event_name == 'pull_request' }} - with: - message-id: coverage-report - message-path: coverage-comment.md + codecoverage: + needs: get-repo-name + permissions: + contents: write + pull-requests: write + uses: newfold-labs/workflows/.github/workflows/reusable-codecoverage.yml@main + with: + php-versions: '["7.4", "8.0", "8.1", "8.2", "8.3", "8.4"]' + coverage-php-version: '7.4' + repository-name: ${{ needs.get-repo-name.outputs.repository-name }} + minimum-coverage: 25 + secrets: + repo_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 262021003..a06f41c07 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +.env.testing .vscode /node_modules /tests/_output diff --git a/codeception.dist.yml b/codeception.dist.yml index 615b541f4..ee1e207b5 100644 --- a/codeception.dist.yml +++ b/codeception.dist.yml @@ -15,6 +15,10 @@ params: coverage: enabled: true include: - - /includes/* -# - /upgrades/* -bootstrap: bootstrap.php + - includes/* + exclude: + - tests/* + - vendor/* + - build/* + - src/* + - languages/* diff --git a/tests/_data/.gitkeep b/tests/_data/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/tests/wpunit.suite.yml b/tests/wpunit.suite.yml index 0f7427225..19a5fe75d 100644 --- a/tests/wpunit.suite.yml +++ b/tests/wpunit.suite.yml @@ -16,7 +16,8 @@ modules: domain: "%TEST_SITE_WP_DOMAIN%" adminEmail: "%TEST_SITE_ADMIN_EMAIL%" - title: "wp-module-data" + adminEmailFallback: "admin@example.org" + title: "wp-module-performance" plugins: [] activatePlugins: [] diff --git a/tests/wpunit/ExampleWPUnitTest.php b/tests/wpunit/ExampleWPUnitTest.php deleted file mode 100644 index b6b3cf993..000000000 --- a/tests/wpunit/ExampleWPUnitTest.php +++ /dev/null @@ -1,12 +0,0 @@ -assertTrue( class_exists( Performance::class ), 'Performance class should exist' ); + $this->assertTrue( class_exists( PerformanceFeature::class ), 'PerformanceFeature class should exist' ); + $this->assertTrue( class_exists( Permissions::class ), 'Permissions class should exist' ); + $this->assertTrue( class_exists( RestApi::class ), 'RestApi class should exist' ); + $this->assertTrue( class_exists( Constants::class ), 'Data\Constants class should exist' ); + $this->assertTrue( class_exists( Cache\Cache::class ), 'Cache\Cache class should exist' ); + } + + /** + * Verify WordPress factory is available. + * + * @return void + */ + public function test_wordpress_factory_available() { + $this->assertTrue( function_exists( 'get_option' ) ); + $this->assertNotEmpty( get_option( 'blogname' ) ); + } + + /** + * Performance constants are defined. + * + * @return void + */ + public function test_performance_constants() { + $this->assertSame( 'nfd_purge_all', Performance::PURGE_ALL ); + $this->assertSame( 'nfd_purge_url', Performance::PURGE_URL ); + $this->assertSame( 'nfd-performance', Performance::PAGE_SLUG ); + } +} diff --git a/tests/wpunit/PermissionsWPUnitTest.php b/tests/wpunit/PermissionsWPUnitTest.php new file mode 100644 index 000000000..651d57c95 --- /dev/null +++ b/tests/wpunit/PermissionsWPUnitTest.php @@ -0,0 +1,55 @@ +assertSame( 'manage_options', Permissions::ADMIN ); + $this->assertSame( 'upload_files', Permissions::UPLOAD_FILES ); + $this->assertSame( 'edit_posts', Permissions::EDIT_POSTS ); + $this->assertSame( 'manage_media_library', Permissions::MANAGE_MEDIA_LIBRARY ); + } + + /** + * Rest_is_authorized_admin returns false when not logged in. + * + * @return void + */ + public function test_rest_is_authorized_admin_when_logged_out() { + wp_set_current_user( 0 ); + $this->assertFalse( Permissions::rest_is_authorized_admin() ); + } + + /** + * Rest_is_authorized_admin returns true for administrator. + * + * @return void + */ + public function test_rest_is_authorized_admin_when_administrator() { + $user_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); + wp_set_current_user( $user_id ); + $this->assertTrue( Permissions::rest_is_authorized_admin() ); + } + + /** + * Rest_can_upload_media returns true for administrator. + * + * @return void + */ + public function test_rest_can_upload_media_for_administrator() { + $user_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); + wp_set_current_user( $user_id ); + $this->assertTrue( Permissions::rest_can_upload_media() ); + } +} diff --git a/tests/wpunit/RestApiWPUnitTest.php b/tests/wpunit/RestApiWPUnitTest.php new file mode 100644 index 000000000..2fa4dcc12 --- /dev/null +++ b/tests/wpunit/RestApiWPUnitTest.php @@ -0,0 +1,32 @@ +get_routes(); + $found = array_filter( + array_keys( $routes ), + function ( $route ) { + return strpos( $route, 'newfold-performance' ) !== false; + } + ); + $this->assertNotEmpty( $found, 'Expected newfold-performance routes to be registered' ); + } +} diff --git a/tests/wpunit/_bootstrap.php b/tests/wpunit/_bootstrap.php index b3d9bbc7f..b81855e68 100644 --- a/tests/wpunit/_bootstrap.php +++ b/tests/wpunit/_bootstrap.php @@ -1 +1,10 @@