Environment variables not loaded into `putenv` via ParamsLoader · Issue #6776 · Codeception/Codeception · GitHub
Skip to content

Environment variables not loaded into putenv via ParamsLoader #6776

Open

Description

@iainsaxon

What are you trying to achieve?

I am writing tests for a Craft 4 project using codeception/codeception and codeception/module-yii2 and found an issue while running functional tests where environment variables are unavailable when an internal request is made.

My project uses symfony/dotenv to handle loading of environment variables.

In my Craft config files I use environment variables to alter functionality, eg a config/site.php:

<?php

use craft\helpers\App;

$myEnvVar = App::env('VARIABLE_NAME');

Running functional tests like the following resulted in unexpected behaviour and errors on the site caused by missing environment variables.

<?php

namespace functional;

use FunctionalTester;

class LoginCest
{

    public function tryLoggingIn(FunctionalTester $I)
    {
        $I->amOnPage('/account/login');
    }
}

The value of $myEnvVar should always be what I set in the environment variable.

What do you get instead?

When I breakpoint my config file and Codeception first starts the $myEnvVar is whatever I provided in the .env however after the functional test starts and an internal request is made this $myEnvVar is now null.

After much debugging I found the issue was a combination of the Codeception Yii2 connector class resetting the $_SERVER where the .env files were loaded (see: https://github.com/Codeception/module-yii2/blob/master/src/Codeception/Lib/Connector/Yii2.php#L288), Craft's App::env() function not using the $_ENV array as a fallback (see: https://github.com/craftcms/cms/blob/5.x/src/helpers/App.php#L121) and the ParamsLoader not enabling usePutenv (see https://github.com/Codeception/Codeception/blob/5.1/src/Codeception/Lib/ParamsLoader.php#L166).

The workaround was to load the environment variables in my own Codeception bootstrap file and enable usePutenv for Dotenv:

$symfonyDotEnv = new SymfonyDotenv();
$symfonyDotEnv->usePutenv(true);
$values = $symfonyDotEnv->parse(self::getFileContents($file), $file);
$symfonyDotEnv->populate($values);

If I bypassed my own bootstrap file and altered the Codeception ParamsLoader to the above the functional tests worked as expected because the variables were kept in PHP's putenv and unaffected by the Yii2 connector reseting $_SERVER variables.

Should the ParamsLoader be using usePutenv(true) by default or would it be possible to add an option in the codeception.yml to enable this behaviour as a workaround for frameworks that do not use the $_ENV for environment variables?

Alternatively it might be good to add a notice on the Codeception documentation advising developers that this could be an issue when implementing functional tests in some frameworks and how to work around it.

Details

  • Codeception version: 5.1.2
  • PHP Version: 8.2
  • Operating System: Debian Bookworm via ddev
  • Installation type: Composer
  • List of installed packages
codeception/codeception            5.1.2
codeception/lib-asserts            2.1.0 
codeception/lib-innerbrowser       3.1.3
codeception/lib-web                1.0.6 
codeception/module-asserts         3.0.0
codeception/module-phpbrowser      3.0.1
codeception/module-yii2            1.1.10
craftcms/cms                       4.9.4
symfony/browser-kit                6.0.19
symfony/dotenv                     5.4.39
yiisoft/yii2                       2.0.48.1
  • Suite configuration:
actor: Tester
paths:
    tests: tests/codeception
    log: tests/codeception/_output
    data: tests/codeception/_data
    support: tests/codeception/_support
    output: tests/codeception/_output
    envs: tests/codeception/_envs
bootstrap: _bootstrap.php
params:
    - .env
    - tests/codeception/.env
modules:
    config:
        \craft\test\Craft:
            configFile: "tests/codeception/_craft/config/test.php"
            entryUrl: "https://mytestsite.localhost/index.php"
            projectConfig: {}
            migrations: []
            plugins: []
            cleanup: true
            transaction: true
            fullMock: false
            dbSetup: { clean: false, setupCraft: false }

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions