Skip to content

[RFC] Add Support for PHP File Configuration #1539

@loic425

Description

@loic425

Description

Currently, Behat supports configuration through YAML files. While YAML is straightforward for many use cases, offering support for PHP configuration files could bring added flexibility and advantages, such as:

  • Enhanced readability for developers familiar with PHP syntax.
  • Leveraging PHP logic (e.g., conditions, constants, or reusable configurations).
  • Improved IDE support and type checking.

Proposal

Introduce support for configuring Behat using PHP files alongside the existing YAML configuration. This would involve:

  • Parsing configurations from a behat.php file if present.
  • Maintaining backward compatibility with YAML configuration files (behat.yml, behat.yaml).
  • Providing a basic example of a PHP configuration file in the documentation.

Benefits

  • Greater flexibility in defining configurations.
  • Ability to dynamically generate configurations based on environment or context.
  • Seamless integration with PHP constants, variables, and classes.

Example

Here’s an example of what a PHP configuration file (behat.php) could look like:

use Behat\Config\Config;

return new Config([
    'default' => [
        'gherkin' => [
            'filters' => [
                'tags' => '~@php8'
            ],
        ],
    ],
]);

Implementation Notes

  • Extend the Behat configuration loader to check for behat.php.
  • Update the documentation to explain the new option and its use cases.

Future helpers

We can do everything with a simple array. But to improve the DX, we can add some helpers to the Config object.

Importing Configuration Files

To make configurations modular and reusable, the PHP file should support importing other files.

It's already possible with the previous proposal:

use Behat\Config\Config;

return new Config([
    'imports' => [
        __DIR__.'/other-config.php'
    ],
])

But we need some helpers to improve the DX.

For instance:

use Behat\Config\Config;

$config = new Config();
$config->import('config/suites.php');

return $config;

We can import several configuration files with the same "import" method.

use Behat\Config\Config;

$config = new Config();
$config->import([
    'config/extensions.php', 
    'config/suites.php',
]);

return $config;

We can also introduce more smart imports.

use Behat\Config\Config;

$config = new Config();
$config->import('config/**/**.php');

return $config;

Adding suites

Here's is just a proposal, it needs to be discussed.

use App\Tests\Behat\Context\FirstContext;
use App\Tests\Behat\Context\SecondContext;
use Behat\Config\Config;
use Behat\Config\Profile;
use Behat\Config\Suite;

$defaultProfile = (new Profile('default'))
    ->withSuite($adminDashboardSuite);
;

$defaultProfile->withSuite(
    new Suite(
        name: 'admin_dashboard', 
        settings: [
            'contexts' => [
                FirstContext::class,
                SecondContext::class,
            ],
            'filters' => [
                'tags' => '@admin&&@dashboard'
            ],
        ],
    )
);

return new (Config())
    ->withProfile($defaultProfile)
;

or using more helpers

use App\Tests\Behat\Context\FirstContext;
use App\Tests\Behat\Context\SecondContext;
use Behat\Config\Config;
use Behat\Config\Profile;
use Behat\Config\Suite;

$adminDashboardSuite = (new Suite(name: 'admin_dashboard'))
    ->withFilters(['tags' => ['@admin&&@dashboard']])
    ->withContexts(
        FirstContext::class, 
        SecondContext::class
    )
;

$defaultProfile = (new Profile('default'))
    ->withSuite($adminDashboardSuite)
;

return (new Config())
    ->withProfile($defaultProfile)
;

Overall solution

The main config file

use Behat\Config\Config;
use Behat\Config\Extension;
use Behat\Config\Profile;
use FriendsOfBehat\MinkDebugExtension;
use Robertfausk\Behat\PantherExtension;

$defaultProfile = (new profile('default'))
    ->import('config/suites/**/**.php')
    ->withFormatters([
        'pretty' => [
            'verbose' => true,
            'paths' => false,
            'snippets' => false,
        ],
    ])
    ->withExtension(new Extension(PantherExtension::class))
    ->withExtension(new Extension(MinkDebugExtension::class, [
        'directory' => 'etc/build',
        'clean_start' => true,
        'screenshot' => true,
    ]))
;

return (new Config())->withProfile($defaultProfile);

A first suite config file

// config/suites/admin_dashboard.php
use App\Tests\Behat\Context\FirstContext;
use App\Tests\Behat\Context\SecondContext;
use Behat\Config\Config;
use Behat\Config\Profile;
use Behat\Config\Suite;

use App\Tests\Behat\Context\FirstContext;
use App\Tests\Behat\Context\SecondContext;
use Behat\Config\Config;
use Behat\Config\Profile;
use Behat\Config\Suite;

$suite = (new Suite(name: 'admin_dashboard'))
    ->withFilters(['tags' => ['@admin&&@dashboard']])
    ->withContexts(
        FirstContext::class,
        SecondContext::class,
    )
;

return (new Config())
    ->withProfile((new Profile('default'))
        ->withSuite($suite)
    )
;

Maybe that would be better like this. It could be a shortcut to add suites.

use App\Tests\Behat\Context\FirstContext;
use App\Tests\Behat\Context\SecondContext;
use Behat\Config\Config;
use Behat\Config\Suite;

$suite = (new Suite(name: 'admin_dashboard'))
    ->withFilters(['tags' => ['@admin&&@dashboard']])
    ->withContexts(
        FirstContext::class,
        SecondContext::class,
    )
;

$config = (new Config())
    ->withSuite(suite: $suite, profile: 'default')
;

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions