lucatume / wp-browser

The easy and reliable way to test WordPress with Codeception. 10 years of proven success.
https://wpbrowser.wptestkit.dev/
MIT License
606 stars 86 forks source link

[SETUP ISSUE] Teardown error — $wpdb is null #716

Closed Genyus closed 7 months ago

Genyus commented 7 months ago

Environment OS: macOS 14.2 PHP version: 8.2 Installed Codeception version: 5.1.2 Installed wp-browser version: 4.1.6 WordPress version: 6.5 Local development environment: Lando WordPress structure and management: Bedrock

Did you use the codecept init wpbrowser command? Yes

Did you take a look at Codeception and wp-browser documentation? Yes

Codeception configuration file

namespace: Tests
support_namespace: Support
paths:
    tests: tests
    output: tests/_output
    data: tests/Support/Data
    support: tests/Support
    envs: tests/_envs
actor_suffix: Tester
extensions:
    commands:
      - "Codeception\\Command\\GenerateWPUnit"
      - "Codeception\\Command\\GenerateWPRestApi"
      - "Codeception\\Command\\GenerateWPRestController"
      - "Codeception\\Command\\GenerateWPRestPostTypeController"
      - "Codeception\\Command\\GenerateWPAjax"
      - "Codeception\\Command\\GenerateWPCanonical"
      - "Codeception\\Command\\GenerateWPXMLRPC"
      - "lucatume\\WPBrowser\\Command\\RunOriginal"
      - "lucatume\\WPBrowser\\Command\\RunAll"
    enabled:
        - Codeception\Extension\RunFailed
params:
  - tests/.env

Suite configuration file If you're encountering an issue with a specific suite, please provide its configuration file.

# 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: ''

Test environment file

# 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=web/wp

# 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:///Users/gary/Sites/mysite/app/public/tests/Support/Data/data.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://tech.mysite.lndo.site
WORDPRESS_DOMAIN=tech.mysite.lndo.site

# The username and password of the administrator user of the WordPress site used in end-to-end tests.
WORDPRESS_ADMIN_USER=admin
WORDPRESS_ADMIN_PASSWORD=password

# The host and port of the ChromeDriver server that will be used in end-to-end tests.
CHROMEDRIVER_HOST=localhost
CHROMEDRIVER_PORT=4444

# Salts
AUTH_KEY=
SECURE_AUTH_KEY=
LOGGED_IN_KEY=
NONCE_KEY=
AUTH_SALT=
SECURE_AUTH_SALT=
LOGGED_IN_SALT=
NONCE_SALT=

Describe the issue you're encountering This is my first time using WPBrowser and after a bit of trial and error due to my Bedrock setup, I've been able to get it running my initial tests. However, an error gets thrown during teardown where it attempts to clear the database, but the $wpdb object is null. I've configured the test database to use SQLite and the db appears to be correctly created and populated, but the teardown method is unable to access the corresponding object. My assumption was that it would pick up the database defined by the WPLoader module, but clearly I've misconfigured something, somewhere.

I've included the output of a test run with --debug enabled below,

Output

> codecept run 'Integration' '--debug'
Codeception PHP Testing Framework v5.1.2 https://stand-with-ukraine.pp.ua

  [Core bootstrap] Installing...
  [Core bootstrap] Running as single site... To run multisite, use -c tests/phpunit/multisite.xml
PHP Warning:  Constant SQLITE_MAIN_FILE already defined in /Users/gary/Sites/mysite/app/public/web/app/mu-plugins/sqlite-database-integration/load.php on line 15
  [Core bootstrap] Warning: Constant SQLITE_MAIN_FILE already defined in /Users/gary/Sites/mysite/app/public/web/app/mu-plugins/sqlite-database-integration/load.php on line 15
  Activating plugins: 
  WordPress status: {
    "rootDir": "/Users/gary/Sites/mysite/app/public/web/wp/",
    "version": {
        "wpVersion": "6.5",
        "wpDbVersion": "57155",
        "tinymceVersion": "49110-20201110",
        "requiredPhpVersion": "7.0.0",
        "requiredMySqlVersion": "5.5.5"
    },
    "constants": {
        "WP_ENV": "development",
        "WP_ENVIRONMENT_TYPE": "development",
        "WP_HOME": "https://tech.mysite.lndo.site",
        "WP_SITEURL": "https://tech.mysite.lndo.site/wp",
        "CONTENT_DIR": "/app",
        "WP_CONTENT_DIR": "/Users/gary/Sites/mysite/app/public/web/app",
        "WP_CONTENT_URL": "https://tech.mysite.lndo.site/app",
        "DB_NAME": "wordpress",
        "DB_USER": "wordpress",
        "DB_PASSWORD": "wordpress",
        "DB_HOST": "database",
        "DB_CHARSET": "utf8mb4",
        "DB_COLLATE": "",
        "AUTH_KEY": "",
        "SECURE_AUTH_KEY": "",
        "LOGGED_IN_KEY": "",
        "NONCE_KEY": "",
        "AUTH_SALT": "",
        "SECURE_AUTH_SALT": "",
        "LOGGED_IN_SALT": "",
        "NONCE_SALT": "",
        "AUTOMATIC_UPDATER_DISABLED": true,
        "DISABLE_WP_CRON": false,
        "DISALLOW_FILE_EDIT": true,
        "DISALLOW_FILE_MODS": false,
        "WP_MEMORY_LIMIT": "256M",
        "WP_DEBUG_DISPLAY": true,
        "WP_DEBUG_LOG": true,
        "SCRIPT_DEBUG": true,
        "WP_ALLOW_MULTISITE": false,
        "MULTISITE": false,
        "SUBDOMAIN_INSTALL": true,
        "DOMAIN_CURRENT_SITE": "mysite.lndo.site",
        "PATH_CURRENT_SITE": "/",
        "SITE_ID_CURRENT_SITE": 1,
        "BLOG_ID_CURRENT_SITE": 1,
        "WP_DEFAULT_THEME": "mysite",
        "COOKIE_DOMAIN": ".mysite.lndo.site",
        "COOKIEPATH": "/",
        "HEADLESS_MODE_CLIENT_URL": "https://hq.mysite.local",
        "SAVEQUERIES": true,
        "WP_DEBUG": true,
        "ABSPATH": "/Users/gary/Sites/mysite/app/public/web/wp/"
    },
    "globals": {
        "root_dir": "/Users/gary/Sites/mysite/app/public",
        "webroot_dir": "/Users/gary/Sites/mysite/app/public/web",
        "dotenv": {},
        "table_prefix": "wp_",
        "base": "/",
        "env_config": "/Users/gary/Sites/mysite/app/public/config/environments/development.php"
    }
}

Tests.Integration Tests (3) ---------------------------------------------------------------------------------------------------------------------------------------------------------
Modules: \lucatume\WPBrowser\Module\WPLoader
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
✔ ContentClassifierTest: Test_factory(0.04s)
✔ ContentClassifierTest: Test_classification(0.01s)
✔ TribeTest: Eventbrite markup formatted(0.01s)

In functions.php line 114:

  [PHPUnit\Framework\Error\Warning (2)]     
  Attempt to read property "posts" on null  

Exception trace:
  at /Users/gary/Sites/mysite/app/public/vendor/lucatume/wp-browser/includes/core-phpunit/includes/functions.php:114
 Codeception\Subscriber\ErrorHandler->errorHandler() at /Users/gary/Sites/mysite/app/public/vendor/lucatume/wp-browser/includes/core-phpunit/includes/functions.php:114
 _delete_all_data() at /Users/gary/Sites/mysite/app/public/vendor/lucatume/wp-browser/includes/core-phpunit/includes/abstract-testcase.php:93
 WP_UnitTestCase_Base::tear_down_after_class() at n/a:n/a
 ReflectionMethod->invokeArgs() at /Users/gary/Sites/mysite/app/public/vendor/lucatume/wp-browser/src/TestCase/WPTestCase.php:303
 lucatume\WPBrowser\TestCase\WPTestCase::__callStatic() at /Users/gary/Sites/mysite/app/public/vendor/lucatume/wp-browser/src/TestCase/WPTestCasePHPUnitMethodsTrait.php:56
 lucatume\WPBrowser\TestCase\WPTestCase::tearDownAfterClass() at /Users/gary/Sites/mysite/app/public/vendor/codeception/codeception/src/Codeception/Subscriber/BeforeAfterTest.php:50
 Codeception\Subscriber\BeforeAfterTest->executeMethods() at /Users/gary/Sites/mysite/app/public/vendor/codeception/codeception/src/Codeception/Subscriber/BeforeAfterTest.php:38
 Codeception\Subscriber\BeforeAfterTest->afterClass() at /Users/gary/Sites/mysite/app/public/vendor/symfony/event-dispatcher/EventDispatcher.php:206
 Symfony\Component\EventDispatcher\EventDispatcher->callListeners() at /Users/gary/Sites/mysite/app/public/vendor/symfony/event-dispatcher/EventDispatcher.php:56
 Symfony\Component\EventDispatcher\EventDispatcher->dispatch() at /Users/gary/Sites/mysite/app/public/vendor/codeception/codeception/src/Codeception/SuiteManager.php:153
 Codeception\SuiteManager->run() at /Users/gary/Sites/mysite/app/public/vendor/codeception/codeception/src/Codeception/Codecept.php:260
 Codeception\Codecept->runSuite() at /Users/gary/Sites/mysite/app/public/vendor/codeception/codeception/src/Codeception/Codecept.php:216
 Codeception\Codecept->run() at /Users/gary/Sites/mysite/app/public/vendor/codeception/codeception/src/Codeception/Command/Run.php:646
 Codeception\Command\Run->runSuites() at /Users/gary/Sites/mysite/app/public/vendor/codeception/codeception/src/Codeception/Command/Run.php:467
 Codeception\Command\Run->execute() at /Users/gary/Sites/mysite/app/public/vendor/lucatume/wp-browser/src/Command/RunAll.php:28
 lucatume\WPBrowser\Command\RunAll->execute() at /Users/gary/Sites/mysite/app/public/vendor/symfony/console/Command/Command.php:279
 Symfony\Component\Console\Command\Command->run() at /Users/gary/Sites/mysite/app/public/vendor/symfony/console/Application.php:1031
 Symfony\Component\Console\Application->doRunCommand() at /Users/gary/Sites/mysite/app/public/vendor/symfony/console/Application.php:318
 Symfony\Component\Console\Application->doRun() at /Users/gary/Sites/mysite/app/public/vendor/symfony/console/Application.php:169
 Symfony\Component\Console\Application->run() at /Users/gary/Sites/mysite/app/public/vendor/codeception/codeception/src/Codeception/Application.php:112
 Codeception\Application->run() at /Users/gary/Sites/mysite/app/public/vendor/codeception/codeception/app.php:45
 {closure}() at /Users/gary/Sites/mysite/app/public/vendor/codeception/codeception/app.php:46
 require() at /Users/gary/Sites/mysite/app/public/vendor/codeception/codeception/codecept:7
 include() at /Users/gary/Sites/mysite/app/public/vendor/bin/codecept:119

run [-o|--override OVERRIDE] [-e|--ext EXT] [--report] [--html [HTML]] [--xml [XML]] [--phpunit-xml [PHPUNIT-XML]] [--colors] [--no-colors] [--silent] [--steps] [-d|--debug] [--shard SHARD] [--filter FILTER] [--grep GREP] [--bootstrap [BOOTSTRAP]] [--no-redirect] [--coverage [COVERAGE]] [--coverage-html [COVERAGE-HTML]] [--coverage-xml [COVERAGE-XML]] [--coverage-text [COVERAGE-TEXT]] [--coverage-crap4j [COVERAGE-CRAP4J]] [--coverage-cobertura [COVERAGE-COBERTURA]] [--coverage-phpunit [COVERAGE-PHPUNIT]] [--no-exit] [-g|--group GROUP] [-s|--skip SKIP] [-x|--skip-group SKIP-GROUP] [--env ENV] [-f|--fail-fast [FAIL-FAST]] [--no-rebuild] [--seed SEED] [--no-artifacts] [--] [<suite> [<test>]]

COMMAND DID NOT FINISH PROPERLY.
Script codecept run handling the test event returned with error code 125

To Reproduce

lucatume commented 7 months ago

Thanks @Genyus for taking the time to open an issue and complete the report. I will look into this next and either come back with a solution, or with questions to debug further.

lucatume commented 7 months ago

Hi @Genyus,

I'm working on this and found some issues with Bedrock + default setup.

Did you choose yes at this question during vendor/bin/codecept init wpbrowser:

You can use a portable configuration based on PHP built-in server, Chromedriver and SQLite.
? Do you want to use this configuration? (y/n)

I've pushed what fixes I've applied so far on the v4-fix-716 branch, if you want you can test this out with:

composer require --dev lucatume/wp-browser:dev-v4-fix-716

I could run the Integration suite successfully on that branch, but the EndToEnd one fails the second test, the Admin login.

Can you run the EndToEnd suite?

I'm using a setup similar to yours, with Lando to serve the Bedrock installation.

Genyus commented 7 months ago

I tried to choose yes during my early attempts, but I always got theAborted trying to redefine constant 'WP_SITEURL'. error (that I see is now resolved in the fix branch), so had to select no and then figure out the missing settings the hard way.

To eliminate any conflicts caused by existing project configuration, I created a completely fresh Bedrock + Lando install, installed WPBrowser from your new branch and tried again. After resolving a few local issues (e.g. not having Chrome installed), I was able to complete the setup and get the same results as you — Integration suite passed, EndToEnd failed.

With a working instance available, I compared my previous setup to see what was different, but couldn't find anything significant. I disabled all my tests and copied in the sample one, which worked fine, so I restored mine one at a time until I found the culprit — turns out that I hadn't converted it from a Codeception unit test to a WPBrowser test case. 🤦🏾‍♂️

With that resolved, I then had a dig around the E2E test suite to see if I could figure out why that wasn't working and eventually discovered the two-fold cause:

  1. In a default WP install, the server root and WP root directories are the same, but that's not the case for Bedrock installs, as the WP root is one level down in the wp directory. To fix, I created a new SERVER_ROOT_DIR environment variable in tests/.env, and modified the default one:
    SERVER_ROOT_DIR=web
    WORDPRESS_ROOT_DIR=${SERVER_ROOT_DIR}/wp

    I then updated the BuiltInServerController config in codeception.yml to use this new value:

    docroot: '%SERVER_ROOT_DIR%'

    And finally, I modified the WPWebDriver config in tests/EndToEndSuite.yml to set the correct admin path for Bedrock:

    adminPath: '/wp/wp-admin'
  2. The WP_HOME environment variable is picked up from the main .env file and so requests to the test server were being redirected to the wrong URL. This meant I had to toggle the WP_HOME value depending on whether I was accessing the regular or test site. After reviewing the relevant documentation, I decided to implement a slightly simpler check for whether the site is being loaded in a test environment inconfig/development.php:
    // Handle WPBrowser test configuration
    if (getenv('WORDPRESS_URL')) {
    // Reset default URLs
    Config::define('WP_HOME', getenv('WORDPRESS_URL'));
    Config::define('WP_SITEURL', Config::get('WP_HOME') . substr(env('WP_SITEURL'), strlen(env('WP_HOME')))); // Retain any appended path in WP_SITEURL, e.g. '/wp'
    }

With these changes in place, all tests now pass successfully 🥳

lucatume commented 7 months ago

@Genyus thanks for your feedback, I've built on it and, after a bit of iteration, removed the steps that would require modification of the config/environments/development.php file.

Here is the result of the setup on a clean Bedrock installation

I will merge #718, and the transpiled #717, when all tests pass.

Genyus commented 7 months ago

Thanks for implementing such a swift and comprehensive fix, much appreciated 🙏🏾