From 715a4da4b49fc05ff31a84ff19580f4b33ba29c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Wed, 4 Dec 2024 09:18:27 +0100 Subject: [PATCH 1/2] PHP Config - Suites --- user_guide/configuration/suites.rst | 303 +++++++++++++++++++--------- 1 file changed, 206 insertions(+), 97 deletions(-) diff --git a/user_guide/configuration/suites.rst b/user_guide/configuration/suites.rst index c176e87..d88ea90 100644 --- a/user_guide/configuration/suites.rst +++ b/user_guide/configuration/suites.rst @@ -10,23 +10,42 @@ With suites you can configure Behat to test different kinds of features using different kinds of contexts and doing so in one run. Test suites are really powerful and ``behat.yml`` makes them that much more powerful: -.. code-block:: yaml - - # behat.yml - - default: - suites: - core_features: - paths: [ '%paths.base%/features/core' ] - contexts: [ CoreDomainContext ] - user_features: - paths: [ '%paths.base%/features/web' ] - filters: { role: user } - contexts: [ UserContext ] - admin_features: - paths: [ '%paths.base%/features/web' ] - filters: { role: admin } - contexts: [ AdminContext ] +.. code-block:: php + + withSuite( + (new Suite('core_features')) + ->withPaths('%paths.base%/features/core') + ->withContexts(CoreDomainContext::class) + ) + ->withSuite( + (new Suite('user_features')) + ->withFilter(new RoleFilter('user')) + ->withPaths('%paths.base%/features/web') + ->withContexts(UserContext::class) + ) + ->withSuite( + (new Suite('admin_features')) + ->withFilter(new RoleFilter('admin')) + ->withPaths('%paths.base%/features/web') + ->withContexts(AdminContext::class) + ) + ; + + return (new Config()) + ->withProfile($profile) + ; Suite Paths ----------- @@ -34,47 +53,86 @@ Suite Paths One of the most obvious settings of the suites is the ``paths`` configuration: -.. code-block:: yaml +.. code-block:: php - # behat.yml + withSuite( + (new Suite('core_features')) + ->withPaths( + '%paths.base%/features', + '%paths.base%/test/features', + '%paths.base%/vendor/.../features', + ) + ) + ; + + return (new Config()) + ->withProfile($profile) + ; As you might imagine, this option tells Behat where to search for test features. You could, for example, tell Behat to look into the ``features/web`` folder for features and test them with ``WebContext``: -.. code-block:: yaml +.. code-block:: php - # behat.yml + withSuite( + (new Suite('web_features')) + ->withPaths('%paths.base%/features/web') + ->withContexts(WebContext::class) + ) + ; -.. code-block:: yaml + return (new Config()) + ->withProfile($profile) + ; - # behat.yml +You then might want to also describe some API-specific features in +``features/api`` and test them with an API-specific ``ApiContext``. Easy: - default: - suites: - web_features: - paths: [ '%paths.base%/features/web' ] - contexts: [ WebContext ] - api_features: - paths: [ '%paths.base%/features/api' ] - contexts: [ ApiContext ] +.. code-block:: php + + withSuite( + (new Suite('web_features')) + ->withPaths('%paths.base%/features/web') + ->withContexts(WebContext::class) + ) + ->withSuite( + (new Suite('api_features')) + ->withPaths('%paths.base%/features/api') + ->withContexts(ApiContext::class) + ) + ; + + return (new Config()) + ->withProfile($profile) + ; This will cause Behat to: @@ -103,22 +161,36 @@ criteria. The Gherkin parser comes bundled with a set of cool filters such as *tags* and *name* filters. You can use these filters to run features with specific tag (or name) in specific contexts: -.. code-block:: yaml - - # behat.yml - - default: - suites: - web_features: - paths: [ '%paths.base%/features' ] - contexts: [ WebContext ] - filters: - tags: '@web' - api_features: - paths: [ '%paths.base%/features' ] - contexts: [ ApiContext ] - filters: - tags: '@api' +.. code-block:: php + + withSuite( + (new Suite('web_features')) + ->withFilter(new TagFilter('@web')) + ->withPaths('%paths.base%/features') + ->withContexts(WebContext::class) + ) + ->withSuite( + (new Suite('api_features')) + ->withFilter(new TagFilter('@api')) + ->withPaths('%paths.base%/features') + ->withContexts(ApiContext::class) + ) + ; + + return (new Config()) + ->withProfile($profile) + ; .. note:: @@ -132,22 +204,36 @@ in the same folder. How cool is that? But it gets even better, because Gherkin 4+ (used in Behat 3+) added a very special *role* filter. That means, you can now have nice actor-based suites: -.. code-block:: yaml - - # behat.yml - - default: - suites: - user_features: - paths: [ '%paths.base%/features' ] - contexts: [ UserContext ] - filters: - role: user - admin_features: - paths: [ '%paths.base%/features' ] - contexts: [ AdminContext ] - filters: - role: admin +.. code-block:: php + + withSuite( + (new Suite('user_features')) + ->withFilter(new RoleFilter('user')) + ->withPaths('%paths.base%/features') + ->withContexts(UserContext::class) + ) + ->withSuite( + (new Suite('api_features')) + ->withFilter(new RoleFilter('admin')) + ->withPaths('%paths.base%/features') + ->withContexts(AdminContext::class) + ) + ; + + return (new Config()) + ->withProfile($profile) + ; A Role filter takes a look into the feature description block: @@ -172,14 +258,22 @@ option to override the filters at the command line. This is achieved by specifying the filter in the gherkin configuration: -.. code-block:: yaml +.. code-block:: php + + withFilter(new TagFilter('~@wip')) + ; + + return (new Config()) + ->withProfile($profile) + ; In this instance, scenarios tagged as @wip will be ignored unless the CLI command is run with a custom filter, e.g.: @@ -203,20 +297,35 @@ against different contexts *or* the same contexts configured differently. This basically means that you can use the same subset of features to develop different layers of your application with Behat: -.. code-block:: yaml - - # behat.yml - - default: - suites: - domain_features: - paths: [ '%paths.base%/features' ] - contexts: [ DomainContext ] - web_features: - paths: [ '%paths.base%/features' ] - contexts: [ WebContext ] - filters: - tags: '@web' +.. code-block:: php + + withSuite( + (new Suite('domain_features')) + ->withPaths('%paths.base%/features') + ->withContexts(DomainContext::class) + ) + ->withSuite( + (new Suite('web_features')) + ->withFilter(new TagFilter('@web')) + ->withPaths('%paths.base%/features') + ->withContexts(WebContext::class) + ) + ; + + return (new Config()) + ->withProfile($profile) + ; In this case, Behat will first run all the features from the ``features/`` folder in ``DomainContext`` and then only those tagged with ``@web`` in From 218b760b7ad96f087dbe027fab79e8d4e6b4a589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Mon, 9 Dec 2024 09:24:28 +0100 Subject: [PATCH 2/2] remove parentheses on invocations --- user_guide/configuration/suites.rst | 76 +++++++++++++++++------------ 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/user_guide/configuration/suites.rst b/user_guide/configuration/suites.rst index d88ea90..724044f 100644 --- a/user_guide/configuration/suites.rst +++ b/user_guide/configuration/suites.rst @@ -23,30 +23,47 @@ really powerful and ``behat.yml`` makes them that much more powerful: use Behat\Config\Profile; use Behat\Config\Suite; - $profile = (new Profile('default')) + $profile = new Profile('default') ->withSuite( - (new Suite('core_features')) + new Suite('core_features') ->withPaths('%paths.base%/features/core') ->withContexts(CoreDomainContext::class) ) ->withSuite( - (new Suite('user_features')) + new Suite('user_features') ->withFilter(new RoleFilter('user')) ->withPaths('%paths.base%/features/web') ->withContexts(UserContext::class) ) ->withSuite( - (new Suite('admin_features')) + new Suite('admin_features') ->withFilter(new RoleFilter('admin')) ->withPaths('%paths.base%/features/web') ->withContexts(AdminContext::class) ) ; - return (new Config()) + return new Config() ->withProfile($profile) ; +.. note:: + + On PHP < 8.4, you need to wrap new invocations with parentheses before calling config object methods. + + .. code-block:: php + + // ... + // $profile = new Profile('default') + $profile = (new Profile('default')) + ->withSuite( + // new Suite('core_features') + (new Suite('core_features')) + ->withPaths('%paths.base%/features/core') + ->withContexts(CoreDomainContext::class) + ) + // ... + Suite Paths ----------- @@ -62,9 +79,9 @@ configuration: use Behat\Config\Profile; use Behat\Config\Suite; - $profile = (new Profile('default')) + $profile = new Profile('default') ->withSuite( - (new Suite('core_features')) + new Suite('core_features') ->withPaths( '%paths.base%/features', '%paths.base%/test/features', @@ -91,15 +108,15 @@ You could, for example, tell Behat to look into the use Behat\Config\Profile; use Behat\Config\Suite; - $profile = (new Profile('default')) + $profile = new Profile('default') ->withSuite( - (new Suite('web_features')) + new Suite('web_features') ->withPaths('%paths.base%/features/web') ->withContexts(WebContext::class) ) ; - return (new Config()) + return new Config() ->withProfile($profile) ; @@ -117,20 +134,20 @@ You then might want to also describe some API-specific features in use Behat\Config\Profile; use Behat\Config\Suite; - $profile = (new Profile('default')) + $profile = new Profile('default') ->withSuite( - (new Suite('web_features')) + new Suite('web_features') ->withPaths('%paths.base%/features/web') ->withContexts(WebContext::class) ) ->withSuite( - (new Suite('api_features')) + new Suite('api_features') ->withPaths('%paths.base%/features/api') ->withContexts(ApiContext::class) ) ; - return (new Config()) + return new Config() ->withProfile($profile) ; @@ -173,30 +190,25 @@ features with specific tag (or name) in specific contexts: use Behat\Config\Profile; use Behat\Config\Suite; - $profile = (new Profile('default')) + $profile = new Profile('default') ->withSuite( - (new Suite('web_features')) + new Suite('web_features') ->withFilter(new TagFilter('@web')) ->withPaths('%paths.base%/features') ->withContexts(WebContext::class) ) ->withSuite( - (new Suite('api_features')) + new Suite('api_features') ->withFilter(new TagFilter('@api')) ->withPaths('%paths.base%/features') ->withContexts(ApiContext::class) ) ; - return (new Config()) + return new Config() ->withProfile($profile) ; -.. note:: - - The ``@`` character is a special and requires the tag to be - put in quotes. - This configuration will tell Behat to run features and scenarios tagged as ``@web`` in ``WebContext`` and features and scenarios tagged as ``@api`` in ``ApiContext``. Even if they all are stored @@ -216,15 +228,15 @@ filter. That means, you can now have nice actor-based suites: use Behat\Config\Profile; use Behat\Config\Suite; - $profile = (new Profile('default')) + $profile = new Profile('default') ->withSuite( - (new Suite('user_features')) + new Suite('user_features') ->withFilter(new RoleFilter('user')) ->withPaths('%paths.base%/features') ->withContexts(UserContext::class) ) ->withSuite( - (new Suite('api_features')) + new Suite('api_features') ->withFilter(new RoleFilter('admin')) ->withPaths('%paths.base%/features') ->withContexts(AdminContext::class) @@ -267,11 +279,11 @@ This is achieved by specifying the filter in the gherkin configuration: use Behat\Config\Filter\TagFilter; use Behat\Config\Profile; - $profile = (new Profile('default')) + $profile = new Profile('default') ->withFilter(new TagFilter('~@wip')) ; - return (new Config()) + return new Config() ->withProfile($profile) ; @@ -309,21 +321,21 @@ develop different layers of your application with Behat: use Behat\Config\Profile; use Behat\Config\Suite; - $profile = (new Profile('default')) + $profile = new Profile('default') ->withSuite( - (new Suite('domain_features')) + new Suite('domain_features') ->withPaths('%paths.base%/features') ->withContexts(DomainContext::class) ) ->withSuite( - (new Suite('web_features')) + new Suite('web_features') ->withFilter(new TagFilter('@web')) ->withPaths('%paths.base%/features') ->withContexts(WebContext::class) ) ; - return (new Config()) + return new Config() ->withProfile($profile) ;