wp-browser icon indicating copy to clipboard operation
wp-browser copied to clipboard

[SETUP ISSUE] Document and explore Bedrock compatibility

Open dorni1234 opened this issue 4 years ago ā€¢ 14 comments

Environment OS: Linux 5.4.10 PHP version: 7.4.1 Installed Codeception version: 3.1.2 Installed wp-browser version: 2.2.32 WordPress version: 5.3 Local development environment: Valet-Linux 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

paths:
    tests: tests
    output: tests/_output
    data: tests/_data
    support: tests/_support
    envs: tests/_envs
actor_suffix: Tester
extensions:
    enabled:
        - Codeception\Extension\RunFailed
    commands:
        - Codeception\Command\GenerateWPUnit
        - Codeception\Command\GenerateWPRestApi
        - Codeception\Command\GenerateWPRestController
        - Codeception\Command\GenerateWPRestPostTypeController
        - Codeception\Command\GenerateWPAjax
        - Codeception\Command\GenerateWPCanonical
        - Codeception\Command\GenerateWPXMLRPC
params:
    - .env.testing

Suite configuration file

# Codeception Test Suite Configuration
#
# Suite for unit or integration tests that require WordPress functions and classes.

actor: WpunitTester
modules:
    enabled:
        - WPDb
        - WPLoader
        - \Helper\Wpunit
    config:
        WPDb:
            dsn: 'mysql:host=%TEST_DB_HOST%;dbname=%TEST_DB_NAME%'
            user: '%TEST_DB_USER%'
            password: '%TEST_DB_PASSWORD%'
            dump: 'tests/_data/dump.sql'
            populate: true
            cleanup: false
            url: '%TEST_SITE_WP_DOMAIN%'
            tablePrefix: '%TEST_TABLE_PREFIX%'
        WPLoader:
            wpRootFolder: "%WP_ROOT_FOLDER%"
            dbName: "%TEST_DB_NAME%"
            dbHost: "%TEST_DB_HOST%"
            dbUser: "%TEST_DB_USER%"
            dbPassword: "%TEST_DB_PASSWORD%"
            tablePrefix: "%TEST_TABLE_PREFIX%"
            domain: "%TEST_SITE_WP_DOMAIN%"
            adminEmail: "%TEST_SITE_ADMIN_EMAIL%"
            title: "Site Title"
            theme: <themename>
            configFile: web/test-config.php
            pluginsFolder: '../app/plugins'
            plugins: ['woocommerce/woocommerce.php', 'advanced-custom-fields-pro/acf.php']
            activatePlugins: ['woocommerce/woocommerce.php', 'advanced-custom-fields-pro/acf.php']
            loadOnly: true

Describe the issue you're encountering I have a Bedrock setup in which I want to integrate tests. I set up WPUnit tests, but when I run them, the database given in DB_NAME in the Bedrock .env file is wiped clear (wp_post, wp_postmeta, wp_termmeta, wp_term_taxonomy empty etc.), even though I defined a different database in the variable TEST_DB_NAME in the .env.testing file.

I assume this to be a configuration error, but I cannot figure how to properly set up wpbrowser to have mercy on my database.

dorni1234 avatar Jan 16 '20 09:01 dorni1234

@dorni1234 thanks for reporting the issue. Iā€™m currently traveling and will look into this next week.

Are tests installed in Bedrock root directory? Any particular step I should take to reproduce other than default Bedrock project scaffolding?

lucatume avatar Jan 17 '20 02:01 lucatume

Yes, the tests directory is located in the root of the Bedrock project. And no, this is a regular Bedrock setup.

dorni1234 avatar Jan 17 '20 06:01 dorni1234

@dorni1234 Now I'm back at work I can see something a bit "off". Usually wpunit test suites, composed of test cases generated using codecept g:wpunit <suite> <case>, use the WPLoader module only w/ loadOnly: false (default value, hence usually not specified).

Could you provide an example of the test you're trying to run? I cannot quite grasp what kind of test you're trying to run and how.

lucatume avatar Jan 20 '20 11:01 lucatume

Sorry for the late reply. Yes, I see the logical error I made with loadOnly: true, I somehow still had the acceptance tests in mind that rely on the production contents being present in the database.

Nonetheless, even with loadOnly: false, the database specified in DB_NAME is wiped clean.

The test I run looks like this:

<?php

namespace HABTests;

class WoocommerceProductHelperTest extends \Codeception\TestCase\WPTestCase
{
    protected $product = [<Mock Data>];

    /**
     * @var \WpunitTester
     */
    protected $tester;
    
    public function setUp(): void
    {
        parent::setUp();
    }

    public function tearDown(): void
    {
        parent::tearDown();
    }

    public function testSetSku(): void
    {
        $wcProduct = new \WC_Product_Simple();
        $this->assertTrue(WoocommerceProductHelper::setSku($wcProduct, $this->product));
    }

    public function testSetDuplicateSku(): void
    {
        $wcProduct = new \WC_Product_Simple();
        WoocommerceProductHelper::setSku($wcProduct, $this->product);
        $wcProduct->save();
        $secondWcProduct = new \WC_Product_Simple();
        $this->assertFalse(WoocommerceProductHelper::setSku($secondWcProduct, $this->product));
    }
}

I run the test with vendor/bin/codecept run wpunit and the tests succeed.

Then, when I try to load the page of my development environment (using the database in DB_NAME), the site is devoid of any contents and uses the default Wordpress theme.

EDIT: I dumped the $wpdb object in the teardown function, and saw that it indeed used the prod database from DB_NAME.

I now implemented a workaround. In the test-config.php specified int the wpunit.suite.yml, I chaged the path of the application.php to test-application.php. And in the test-application.php, I edited the env variables used to define the database connection credentials.

So, I went from this:

Config::define('DB_NAME', env('DB_NAME'));
Config::define('DB_USER', env('DB_USER'));
Config::define('DB_PASSWORD', env('DB_PASSWORD'));
Config::define('DB_HOST', env('DB_HOST') ?: 'localhost');
Config::define('DB_CHARSET', 'utf8mb4');
Config::define('DB_COLLATE', '');

to this:

Config::define('DB_NAME', env('TEST_DB_NAME'));
Config::define('DB_USER', env('TEST_DB_USER'));
Config::define('DB_PASSWORD', env('TEST_DB_PASSWORD'));
Config::define('DB_HOST', env('TEST_DB_HOST') ?: 'localhost');
Config::define('DB_CHARSET', 'utf8mb4');
Config::define('DB_COLLATE', '');
$table_prefix = env('TEST_TABLE_PREFIX') ?: 'wp_';

And now my prod database is safe for now.

dorni1234 avatar Jan 21 '20 05:01 dorni1234

@dorni1234 thanks for the detailed information.

Usually the configFile is loaded to add some required parameters to the test configuration. Could you share what is in the test-config.php file?

lucatume avatar Jan 22 '20 14:01 lucatume

The test-config.php looks like this:

<?php
require_once(dirname(__DIR__) . '/vendor/autoload.php');
require_once(dirname(__DIR__) . '/config/test-application.php');

I followed the instructions from your blog post when setting it up to this point.

dorni1234 avatar Jan 23 '20 06:01 dorni1234

I've re-read the article and think there's space for improvement here:

  1. update the article
  2. add a Bedrock-specific setup guide

The article did work because, at the time of writing, the default environment file created, and used, by wp-browser, was the .env one. That would coincide with the one used by Bedrock and make things work.

Since this is not the case anymore the article and guide need an update.

I will update this issue when that is up and running.

lucatume avatar Jan 27 '20 15:01 lucatume

yay. I'd really like an update for the article https://www.theaveragedev.com/setting-wpbrowser-bedrock/

and or a section in the documentation for setting up all tests with bedrock.

on a current site and a new one.

chrillep avatar Mar 15 '20 19:03 chrillep

I will get to that, the problem is time, not will.

lucatume avatar Mar 16 '20 08:03 lucatume

I completely understand šŸ˜Š. I just want to say I really appreciate your efforts with this repo!

chrillep avatar Mar 18 '20 19:03 chrillep

I completely understand šŸ˜Š. I just want to say I really appreciate your efforts with this repo!

Thanks, I really appreciate. I'm currently working to move wp-browser own testing structure to Docker and containerization and am having a lot of epiphanies along the way. When that is done, it will be Documentation Day(s).

lucatume avatar Mar 19 '20 09:03 lucatume

Hi, anything new on this ? I'm stuck with using WPLoader in a bedrock context, using loadOnly: true. I have a separate .env.testing containing specific test values for wordpress constants (DB_NAME, DB_USER ...) but I can't find a solution to load them, as wp-load.php is requiring wp-config.php, which in turn points to /config/application.php .

I thought wp-config.php wasn't supposed to be loaded when using WPLoader, but apparently, this is the case.

I'm a bit lost...

LucasDemea avatar Oct 28 '21 11:10 LucasDemea

Hi @LucasDemea,

I've set up Bedrock installations for testing a number of times, but it's been a while I've done it and things might have changed.

Would you be willing to walk me through how you've set up your project and wp-browser and what you're trying to test and how?

Again not being intimate with Bedrock, why use loadOnly=true? Asking out of ignorance.

The more information you could provide, the easier it would be for me to explore the issue.

lucatume avatar Oct 29 '21 06:10 lucatume

Hi @lucatume I finally got this working, but I'm not sure it's the best way to do. I'm open to any advice.

I'm using WPLoader with loadOnly: true in functional tests because I need to use some wp core functions like get_bloginfo( 'name' ).

I didn't succeeded to use loadOnly: true without WPLoader loading the original wp-config.php.

I have a .env.testing where I mirror wp constants names :

# .env.testing
DB_DSN='mysql:host=localhost;dbname=tests'
DB_HOST='localhost'
DB_NAME='tests'
DB_PASSWORD='wordpress'
DB_USER='wordpress'
#...

I have a test-config.php where i setup some test specific configs:

// web/test-config.php 
use Env\Env;
// getenv (used by Env\Env by default seems to be disabled in codeception context. Therefore we must use another method to get env vars
Env::$options |= Env::USE_ENV_ARRAY;
define( 'WP_LOADER', true );

Then, in application.php I load .env.testing and I define constants only if they are not already defined. This is the part I feel is wrong somehow. I would have prefered not to change anything in this application.php, but as I can't get WPLoader to work without loading wp-config.php (and subsequent application.php), it's the only way I found for now. I would have prefered to use a different file than application.php for this.

// config/application.php
if (defined("WP_LOADER")) {
    $env_files = [ '.env.testing' ];
} else {
    $env_files = file_exists( $root_dir . '/.env.local' )
    ? [ '.env', '.env.local' ]
    : [ '.env' ];
}

//...

/**
 * DB settings
 */

if (!defined('DB_NAME')) {
Config::define('DB_NAME', env('DB_NAME'));
}
if (!defined('DB_USER')) {
Config::define('DB_USER', env('DB_USER'));
}
if (!defined('DB_PASSWORD')) {
Config::define('DB_PASSWORD', env('DB_PASSWORD'));
}
if (!defined('DB_HOST')) {
Config::define('DB_HOST', env('DB_HOST') ?: 'localhost');
}
if (!defined('DB_CHARSET')) {
Config::define('DB_CHARSET', 'utf8mb4');
}
if (!defined('DB_COLLATE')) {
Config::define('DB_COLLATE', '');
}

What I understand is that wordpress loads once, setting up the constants as expected, and then WPLoader requires application.php again, thus the need of these if (!defined(...)). If i don't use these conditions, Config::define() throws this exception: (here we can also see that WPLoader is loading wp-config.php)

In Config.php line 106:
                                                                                                                
  [Roots\WPConfig\Exceptions\ConstantAlreadyDefinedException]                                                   
  Aborted trying to redefine constant 'DB_NAME'. `define('DB_NAME', ...)` has already been occurred elsewhere.  
                                                                                                                

Exception trace:
  at /srv/www/site/current/vendor/roots/wp-config/src/Config.php:106
 Roots\WPConfig\Config::defined() at /srv/www/site/current/vendor/roots/wp-config/src/Config.php:26
 Roots\WPConfig\Config::define() at /srv/www/site/current/config/application.php:75
 require_once() at /srv/www/site/current/web/wp-config.php:14
 require_once() at /srv/www/site/current/web/wp/wp-load.php:55
 include_once() at /srv/www/site/current/vendor/lucatume/wp-browser/src/Codeception/Module/WPLoader.php:618
 Codeception\Module\WPLoader->bootstrapWP() at /srv/www/site/current/vendor/lucatume/wp-browser/src/Codeception/Module/WPLoader.php:470
 Codeception\Module\WPLoader->_loadWordpress() at /srv/www/site/current/vendor/symfony/event-dispatcher/EventDispatcher.php:230
...

Next, i set up my functional tests this way:

# functional.suite.yml
actor: FunctionalTester
modules:
  enabled:
    - WPDb
    - WPLoader
    - WPWebDriver
    - Asserts
    - \Helper\Functional
  config:
    WPDb:
      dsn: "%DB_DSN%"
      user: "%DB_USER%"
      password: "%DB_PASSWORD%"
      dump: "tests/_data/dump.sql"
      populate: true
      cleanup: false
      waitlock: 10
      url: "%WP_URL%"
      urlReplacement: true
      originalUrl: "%ORIGINAL_URL%"
      tablePrefix: "%DB_PREFIX%"
    WPWebDriver:
      url: "%WP_URL%"
      adminUsername: "%ADMIN_USERNAME%"
      adminPassword: "%ADMIN_PASSWORD%"
      adminPath: "%WP_ADMIN_PATH%"
      window_size: false
      port: 4444
      browser: chrome
      start: true
      capabilities:
        "goog:chromeOptions":
          args:
            [
              "--headless",
              "--no-sandbox",
              "--disable-gpu",
              "--user-agent=wp-browser",
              "allow-insecure-localhost",
              "--ignore-certificate-errors",
              "--disable-dev-shm-usage",
            ]
    WPFilesystem:
      wpRootFolder: "%WP_ROOT_FOLDER%"
      plugins: "../app/plugins"
      mu-plugins: "../app/mu-plugins"
      themes: "../app/themes"
      uploads: "../app/uploads"
    WPLoader:
      wpRootFolder: "%WP_ROOT_FOLDER%"
      dbName: "%DB_NAME%"
      dbHost: "%DB_HOST%"
      dbUser: "%DB_USER%"
      dbPassword: "%DB_PASSWORD%"
      tablePrefix: "%DB_PREFIX%"
      loadOnly: true
      domain: "%WP_DOMAIN%"
      configFile: "web/test-config.php"

LucasDemea avatar Oct 29 '21 09:10 LucasDemea