FriendsOfBehat / SymfonyExtension

:musical_score: Extension integrating Behat with Symfony.
MIT License
472 stars 62 forks source link

"behat.service_container" service is synthetic error when using context with page object class #99

Closed walterdolce closed 4 years ago

walterdolce commented 4 years ago

Hi, I started using this extension after I was made aware https://github.com/Behat/Symfony2Extension is no longer supported.

I have the majority of my context classes referencing Page Object classes in their constructor. The Page Object extension I'm using is https://github.com/sensiolabs/BehatPageObjectExtension.

I have the typical DemoContext working fine. But the other context is not.

I'm getting the following:

  The "behat.service_container" service is synthetic, it needs to be set at boot time before it can be used.  

Folder structure is as follows:

behat.yml
config/
   services_test.yaml
   # other config files
features/
   bootstrap/
      Page/
         # page object classes
   demo.feature
   suites/
      suite_a/
         # feature files
      suite_b/
         # feature files
src/
   # codebase files
tests/
   Behat/
      AccountPageContext.php
      DemoContext.php

This is the AccountPageContext class:

# tests/Behat/AccountPageContext.php
<?php
namespace App\Tests\Behat;

use Behat\Behat\Context\Context;
use Page\Account;

final class AccountPageContext implements Context
{
    private $account;

    public function __construct(Account $account)
    {
        $this->account = $account;
    }
# ...

This is the behat.yml configuration file:

# behat.yml
default:
  autoload:
    '': '%paths.base%/features/bootstrap'
  extensions:
    Behat\MinkExtension:
      base_url:  'http://localhost:8000'
      browser_name: 'chrome'
      sessions:
        default:
          goutte: ~
        javascript_session:
          chrome:
            api_url: 'http://localhost:9222'
        google_chrome:
          chrome:
            api_url: 'http://localhost:9222'
    FriendsOfBehat\SymfonyExtension: ~
    SensioLabs\Behat\PageObjectExtension:
      namespaces:
        element:
          -
  formatters:
    pretty: true
  suites:
    demo:
      paths:
        - '%paths.base%/features/demo.feature'
      contexts:
        - App\Tests\Behat\DemoContext
    accounts_management:
      paths:
        - '%paths.base%/features/suites/suite_a'
      contexts:
        - App\Tests\Behat\AccountPageContext

This is the services_test.yaml file:

# config/services_test.yaml
services:
  _defaults:
    autowire: true
    autoconfigure: true

  App\Tests\Behat\:
    resource: '../tests/Behat/*'

  Page\:
    resource: '../features/bootstrap/Page/*'

  SensioLabs\Behat\PageObjectExtension\PageObject\Factory\DefaultFactory:
    arguments:
      $pageParameters: []
  SensioLabs\Behat\PageObjectExtension\PageObject\Factory: '@SensioLabs\Behat\PageObjectExtension\PageObject\Factory\DefaultFactory'

  SensioLabs\Behat\PageObjectExtension\PageObject\Factory\CamelcasedClassNameResolver: ~
  SensioLabs\Behat\PageObjectExtension\PageObject\Factory\ClassNameResolver: '@SensioLabs\Behat\PageObjectExtension\PageObject\Factory\CamelcasedClassNameResolver'

The page object class, is simply defined as follows:

# features/bootstrap/Page/Account.php
<?php
namespace Page;

use SensioLabs\Behat\PageObjectExtension\PageObject\Page;

class Account extends Page
{
    protected $path = '/some-route';
}

And for completeness, this is the autoload-dev and require-dev sections of the composer.json file:

# composer.json

  "require-dev": {
    "behat/behat": "v3.5.0",
    "behat/mink": "dev-master#e6930b9c74693dff7f4e58577e1b1743399f3ff9",
    "behat/mink-goutte-driver": "v1.2.1",
    "dmore/behat-chrome-extension": "^1.1",
    "dmore/chrome-mink-driver": "2.7.0",
    "friends-of-behat/symfony-extension": "v2.0.8",
    "phpspec/phpspec": "4.2.4",
    "sensiolabs/behat-page-object-extension": "v2.3.0",
    # other dev dependencies...
  },

# ...

  "autoload-dev": {
    "psr-0": {
      "": "features/bootstrap"
    },
    "psr-4": {
      "App\\Tests\\": "tests/",
      "MyAppNamespace\\": "spec/MyAppNamespace/"
    }

When running bin/behat -s demo, everything should work just fine. When running bin/behat -s accounts_management, the same error should occur. I'm using Symfony 4 with Flex.

Let me know if there's any additional information needed for this.

walterdolce commented 4 years ago

I reverted to using Behat/Symfony2-Extension as with that everything works without problems.

pamil commented 4 years ago

That's an interesting case and very detailed report, thanks for that! Unfortunately, I don't have enough time in the nearest future to explore it.

If someone would like to help, creating a reproducer repo would make it even easier to start exploring this issue (https://symfony.com/doc/current/contributing/code/reproducer.html#reproducing-complex-bugs).

asoupper commented 4 years ago

I have the same error once I started to extend the Behatch RestContext class

pamil commented 4 years ago

The issue with SensioLabs/BehatPageObjectExtension is that its Page constructor extends Mink's NodeElement, which calls methods on Mink's Session in the constructor, which in the end tries to initialize it way before SymfonyExtension could set current behat.service_container instance.

Unless no change is made there, we won't be able to support it in SymfonyExtension. In Sylius, we use FriendsOfBehat/PageObjectExtension which is compatible with being registered as a service. I've added some tests in #105 to ensure it will not change.