craftcms / cms

Build bespoke content experiences with Craft.
https://craftcms.com
Other
3.28k stars 635 forks source link

[5.x]: Using `GeneralConfig`'s `defaultCpLanguage('string')` method breaks Codeception tests #15445

Closed iainsaxon closed 3 months ago

iainsaxon commented 3 months ago

What happened?

Codeception tests fail if using GeneralConfig::create()-> defaultCpLanguage('en-GB').

Description

I'm setting up Codeception for a Craft 5 site using this repository's tests as a starting point and then altering it as needed.

If our config/general.php file is using the newer GeneralConfig::create() pattern and we use the defaultCpLanguage method with a string value the tests will fail with the following error (more detailed tracestack below):

Fatal error: Uncaught Error: Call to a member function getI18n() on null in /var/www/html/vendor/craftcms/cms/src/helpers/Localization.php:39

This is because the Localization helper uses Craft::$app->getI18n() which is not initialised in Codeception so early on in the testing process.

Does the GeneralConfig class or Localization helper need to check first if the i18n service is available before trying to use it?

Steps to reproduce

  1. Use the project's config directory in the Codeception bootstrap file, eg:
<?php

use craft\test\TestSetup;

ini_set('date.timezone', 'UTC');

// Use the current installation of Craft
define('CRAFT_TESTS_PATH', __DIR__);
define('CRAFT_STORAGE_PATH', __DIR__ . '/_craft/storage');
define('CRAFT_TEMPLATES_PATH', __DIR__ . '/../../templates');
define('CRAFT_CONFIG_PATH', __DIR__ . '/../../config');
define('CRAFT_MIGRATIONS_PATH', __DIR__ . '/_craft/migrations');
define('CRAFT_TRANSLATIONS_PATH', __DIR__ . '/../../translations');

include_once __DIR__ . '/../../config/bootstrap.php';

TestSetup::configureCraft();
  1. Have the following in the config/general.php:
<?php

use craft\config\GeneralConfig;

return GeneralConfig::create()
    ...
    ->defaultCpLanguage('en-GB')
    ;
  1. Add the tests/unit.suite.yml file:
actor: UnitTester
modules:
    enabled:
        - \craft\test\Craft
        # Don't delete any other enabled modules.
  1. Include a simple Unit Test like the documentation suggests:
<?php

namespace codeception\unit;

use Codeception\Test\Unit;

use codeception\_support\UnitTester;
use Craft;

class ExampleTest extends Unit
{
    /**
     * @var UnitTester
     */
    protected $tester;

    public function testExample()
    {
        Craft::$app->setEdition(Craft::Pro);

        $this->assertSame(
            Craft::Pro,
            Craft::$app->getEdition());
    }
}
  1. Run the Codeception tests and it will fail because of the Localization helper.
  2. Comment out or remove the config/general.php line where the defaultCpLanguage method is called.
  3. Run the tests again and it should pass (or at the least will not fail due to the Localization helper.

Expected behavior

Tests should work using the project's general config file.

Actual behavior

Tests fail with:

Fatal error: Uncaught Error: Call to a member function getI18n() on null in /var/www/html/vendor/craftcms/cms/src/helpers/Localization.php on line 39

Error: Call to a member function getI18n() on null in /var/www/html/vendor/craftcms/cms/src/helpers/Localization.php on line 39

Call Stack:
    0.0154     377184   1. {main}() /var/www/html/vendor/bin/codecept:0
    0.0599     377704   2. include('/var/www/html/vendor/codeception/codeception/codecept') /var/www/html/vendor/bin/codecept:119
    0.0600     378048   3. require('/var/www/html/vendor/codeception/codeception/app.php') /var/www/html/vendor/codeception/codeception/codecept:7
    0.0950     673264   4. {closure:/var/www/html/vendor/codeception/codeception/app.php:7-46}() /var/www/html/vendor/codeception/codeception/app.php:46
    0.1025     992976   5. Codeception\Application->registerCustomCommands() /var/www/html/vendor/codeception/codeception/app.php:38
    0.1025     992976   6. Codeception\Application->readCustomCommandsFromConfig() /var/www/html/vendor/codeception/codeception/src/Codeception/Application.php:31
    0.1036     998120   7. Codeception\Configuration::config($configFile = ???) /var/www/html/vendor/codeception/codeception/src/Codeception/Application.php:63
    0.1075    1075576   8. Codeception\Configuration::loadBootstrap($bootstrap = '_bootstrap.php', $path = '/var/www/html/tests/codeception/') /var/www/html/vendor/codeception/codeception/src/Codeception/Configuration.php:276
    0.1076    1076184   9. require_once('/var/www/html/tests/codeception/_bootstrap.php') /var/www/html/vendor/codeception/codeception/src/Codeception/Configuration.php:298
    0.1096    1090856  10. craft\test\TestSetup::configureCraft() /var/www/html/tests/codeception/_bootstrap.php:17
    0.1167    1360048  11. craft\services\Config->getConfigFromFile($filename = 'general') /var/www/html/vendor/craftcms/cms/src/test/TestSetup.php:359
    0.1167    1360144  12. craft\services\Config->_configFromFileInternal($path = '/var/www/html/tests/codeception/../../config/general.php') /var/www/html/vendor/craftcms/cms/src/services/Config.php:281
    0.1168    1361232  13. include('/var/www/html/config/general.php') /var/www/html/vendor/craftcms/cms/src/services/Config.php:289
    0.1214    1567352  14. craft\config\GeneralConfig->defaultCpLanguage($value = 'en-GB') /var/www/html/config/general.php:27
    0.1216    1567448  15. craft\helpers\Localization::normalizeLanguage($language = 'en-GB') /var/www/html/vendor/craftcms/cms/src/config/GeneralConfig.php:4004

Craft CMS version

5.2.2

PHP version

8.2.20

Operating system and version

Debian Bookworm via ddev

Database type and version

Postgres 15

Image driver and version

NA

Installed plugins and versions

NA

brandonkelly commented 3 months ago

Thanks for reporting that! Fixed now for the next Craft 4 and 5 releases.

To get the fix early, change your craftcms/cms requirement in composer.json to:

"craftcms/cms": "5.x-dev as 5.2.9",

and then run composer update.

brandonkelly commented 3 months ago

Craft 4.10.8 and 5.2.10 are out with that fix. Thanks again!