Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

using "Behatch\Context\RestContext" cause The service has a dependency on a non-existent service "behatch.http_call.request" #111

Open
masoud91 opened this issue Mar 7, 2020 · 9 comments

Comments

@masoud91
Copy link

masoud91 commented Mar 7, 2020

Hey guys, Thanks for your awesome work.
I'm trying to use Behatch RestContext in my context but I get the following error:

The service "App\Tests\Behat\FeatureContext" has a dependency on a non-existent service "behatch.http_call.request".

Am I wrong somewhere?

This is my configuration:
symfony: 4.4
composer.json:

"require-dev": {
        "behat/behat": "^3.6",
        "behat/mink": "^1.7@dev",
        "behat/mink-browserkit-driver": "^1.3",
        "behat/mink-extension": "^2.3",
        "behatch/contexts": "^3.3",
        "coduo/php-matcher": "^4.0",
        "doctrine/doctrine-fixtures-bundle": "^3.3",
        "friends-of-behat/symfony-extension": "^2.0.0",
        "fzaninotto/faker": "^1.9",
        "symfony/debug-pack": "*",
        "symfony/maker-bundle": "^1.0",
        "symfony/profiler-pack": "*",
        "symfony/test-pack": "*"
    }

behat.yml

default:
    suites:
        default:
            contexts:
                - Behat\MinkExtension\Context\MinkContext
                - behatch:context:browser
                - behatch:context:debug
                - behatch:context:system
                - behatch:context:json
                - behatch:context:table
                - behatch:context:rest
                - behatch:context:xml

    extensions:
        FriendsOfBehat\SymfonyExtension: ~
        Behatch\Extension: ~
        Behat\MinkExtension:
            base_url:  'http://localhost:8000'
            sessions:
                symfony:
                    symfony: ~

service_test.yml

services:
    _defaults:
        autowire: true
        autoconfigure: true

    App\Tests\Behat\FeatureContext:
        public: true
        arguments:
            - '@behatch.http_call.request'
            - '@App\DataFixtures\AppFixtures'
            - '@doctrine.orm.default_entity_manager'

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

app/tests/Behat/FeatureContext.php

<?php

namespace App\Tests\Behat;

use Behatch\Context\RestContext;
use Coduo\PHPMatcher\Factory\SimpleFactory;
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\Tools\SchemaTool;


/**
 * This context class contains the definitions of the steps used by the demo
 * feature file. Learn how to get started with Behat and BDD on Behat's website.
 *
 * @see http://behat.org/en/latest/quick_start.html
 */
final class FeatureContext extends RestContext
{

    /**
     * @var \App\DataFixtures\AppFixtures
     */
    private $fixtures;

    /**
     * @var \Coduo\PHPMatcher\Matcher
     */
    private $matcher;

    /**
     * @var \Doctrine\ORM\EntityManagerInterface
     */
    private $em;

    public function __construct(
        \Behatch\HttpCall\Request $request,
        \App\DataFixtures\AppFixtures $fixtures,
        \Doctrine\ORM\EntityManagerInterface $em
    ) {
        parent::__construct($request);

        $this->fixtures = $fixtures;
        $this->matcher = (new SimpleFactory())->createMatcher();
        $this->em = $em;
    }

    /**
     * @BeforeScenario @createSchema
     */
    public function createSchema(){
        // .....
    }
}
@GrzegorzMatuszakTSH
Copy link

GrzegorzMatuszakTSH commented Mar 11, 2020

I have the same problem.
As a hotfix I added in my services_test.yaml manual configuration:

    behatch.http_call.request:
        class: Behatch\HttpCall\Request
        arguments:
            - '@behat.mink'
        public: false

Original path with configuration: behatch/contexts/src/Resources/services/http_call.yml

@CharloMez
Copy link

I have the same issue.
The problem is that behatch and symfony-extension have two way to inject dependencies.

You can inject Behatch dependencies through behat.yml like this:

                - App\Behat\Context\JsonExtendedContext:
                    httpCallResultPool: 'behatch:behatch.http_call.result_pool'
                    request: 'behatch:behatch.http_call.request'

Because Behatch provide a resolver to behat HttpCallResultPoolResolver

But symfony-extension only provide dependency injection for context as service... so:
in behat.yaml this doesn't work (because symfony don't provide resolver to behat)

                - App\Behat\Context\JsonExtendedContext:
                    httpCallResultPool: 'behatch:behatch.http_call.result_pool'
                    request: 'behatch:behatch.http_call.request'
                    kernel: "@kernel"

in service_test.yaml this doesn't work (because behatch service are private and can only be injected through behat Resolver

    App\Behat\Context\JsonExtendedContext:
        $httpCallResultPool: "@behatch.http_call.result_pool"
        $kernel: "@kernel"

@GrzegorzMatuszakTSH I'm not sure your solution is the best, because you provide a new reference of this object, I'm not sure that internally behatch will use the same instance. So between your context and behatch context, informations will be differents.

This is a real issue.

I think there is two way to handle this:

  • Provide a behat Resolver to inject symfony objects through behat.yaml
  • In symfony-extension extension class trying to resolve arguments with every resolver that implement Behat\Behat\Context\Argument\ArgumentResolver (I think this solution is the best, it will allow full autowiring)

@GrzegorzMatuszakTSH
Copy link

@CharloMez Yes, I agree with you.
As I wrote my "solution" was a hotfix and we need a change in the library to fix it in the right way.
Your ideas are very good :)

@pamil
Copy link
Member

pamil commented May 5, 2020

@CharloMez would you be willing to contribute the second solution?

@CharloMez
Copy link

CharloMez commented May 6, 2020

@pamil I'm trying, but I don't find how to get all ArgumentResolver...
when I try in compiler pass

use Behat\Behat\Context\ServiceContainer\ContextExtension;
.....

$container->findTaggedServiceIds(ContextExtension::ARGUMENT_RESOLVER_TAG);

I got nothing, but behat find them in it's extension here
https://github.com/Behat/Behat/blob/98cfd077dcb68a6f1e20f3faa94b31e63b0dd182/src/Behat/Behat/Context/ServiceContainer/ContextExtension.php#L279

I think I miss something in symfony process. It is probably not the same container which is injected in behat extension, but I don't know how to access to the same container from SymfonyExtension.
any idea how to get these services ?

@ymarillet
Copy link

ymarillet commented Jul 1, 2020

I tried many other solutions (extending JsonContext, calling the behatch internal container to get the JsonContext, ...) but only one worked (that's dirty though): Reflection

<?php

namespace App\Tests\Behat;

use Behat\Behat\Context\Context;
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use Behatch\Context\JsonContext;
use Behatch\HttpCall\HttpCallResultPool;
use Behatch\Json\JsonInspector;

class JsonExtendedContext implements Context
{
    private HttpCallResultPool $httpCallResultPool;

    private JsonInspector $inspector;

    /**
     * @BeforeScenario
     */
    public function beforeScenario(BeforeScenarioScope $scope)
    {
        $jsonContext = $scope->getEnvironment()->getContext(JsonContext::class);
        $refl = new \ReflectionClass(JsonContext::class);

        $httpCallResultPoolProperty = $refl->getProperty('httpCallResultPool');
        $inspectorProperty = $refl->getProperty('inspector');

        $httpCallResultPoolProperty->setAccessible(true);
        $inspectorProperty->setAccessible(true);

        $this->httpCallResultPool = $httpCallResultPoolProperty->getValue($jsonContext);
        $this->inspector = $inspectorProperty->getValue($jsonContext);
    }

    // your steps here ...

@aleksbrgt
Copy link

Given the example from the original @masoud91 comment, it seems you are only using the Request to forward it to the parent __constructor , you can simply avoid to extend the RestContext and only implement Behat\Behat\Context\Context.

However this is not resolving the issue of getting the Request for ourselves.

@gonzalovilaseca
Copy link

@pamil I'm happy to contribute the second solution if this is still needed, I implemented an extension on top of the original sf2 extension and it doesn't work with this one, so if you give me some guidance I can contribute.

@nathansalter
Copy link

nathansalter commented Jan 7, 2021

I managed to wrangle a working version by doing this:

services_test.yaml:

services:
  defaults:
    autowire: true
    autoconfigure: true
    bind:
      $behatContainer: '@test.service_container'

  App\Tests\Context\:
    resource: '../tests/Context/*'
    public: true

JsonContext.php:

class JsonContext extends BaseContext
{
    private ContainerInterface $behatContainer;

    public function __construct(ContainerInterface $behatContainer, string $evaluationMode = 'javascript')
    {
        $this->behatContainer = $behatContainer;
    }

    /** @BeforeScenario */
    public function gatherContexts(BeforeScenarioScope $scope): void
    {
        $container = $this->behatContainer->get('behat.service_container');
        $this->httpCallResultPool = $container->get('behatch.http_call.result_pool');
    }
}

However, using this method I couldn't get a working version to override RestContext. I think this is because the request isn't actually put into the container, so there's no method to get the current Behat request. Definitely requires more work.

For other services, here's the list of available services that I found in the container:

{
    "cli.input": "Symfony\\Component\\Console\\Input\\ArgvInput",
    "cli.output": "Symfony\\Component\\Console\\Output\\ConsoleOutput",
    "translator": "Behat\\Behat\\Definition\\Translator\\Translator",
    "fob_symfony.kernel": "App\\Kernel",
    "fob_symfony.mink": "FriendsOfBehat\\SymfonyExtension\\Mink\\Mink",
    "fob_symfony.driver_kernel": "App\\Kernel",
    "behatch.http_call.result_pool": "Behatch\\HttpCall\\HttpCallResultPool",
    "definition.pattern_transformer": "Behat\\Behat\\Definition\\Pattern\\PatternTransformer",
    "environment.manager": "Behat\\Testwork\\Environment\\EnvironmentManager",
    "argument.mixed_organiser": "Behat\\Testwork\\Argument\\MixedArgumentOrganiser",
    "call.center": "Behat\\Testwork\\Call\\CallCenter",
    "cli.command": "Behat\\Testwork\\Cli\\Command"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants