Hello world ! :)
I am still exploring the huge potential of Behat 3 and got a new question about contexts.
On Behat 2, I was used to have a main FeatureContext which used many SubContexts. Then I was able to access/change class (context) methods/properties from other classes with :
$this->getMainContext()->getSubcontext('subcontext_alias')->some_method();
From now, on Behat 3, the new doc says :
Basically, all contexts under contexts section of your behat.yml are the same for Behat. It will find and use methods in them same way it does in default FeatureContext.
So if I have :
# behat.yml
contexts:
- HelloContext
- WorldContext
# HelloContext.php
<?php
use Behat\Behat\Context\SnippetAcceptingContext;
class HelloContext implements SnippetAcceptingContext
{
public $greetings = "Hello";
}
What should I do to be able to access and modify $greetings from WorldContext ?
# WorldContext.php
<?php
use Behat\Behat\Context\Context;
class WorldContext implements Context
{
public function changeGreetings(){
// On Behat 2, I was doing
// $this->getMainContext()->getSubContext("HelloContext")->greetings .= " World !";
}
}
Thanks !
It seems that such system is not possible anymore (or if yes, please inform us in that topic !).
A workaround is to create a singleton class which have static fields and methods that could be callable from other context. It works well for a kind of MemoryClass which holds data you need in other contexts.
Also the Behat Page Extension seems very promising in regrouping functions into Page objects that could be reuse in code. Check it out here : http://extensions.behat.org/page-object/
Thanks to @norzechowicz for all the ideas and help !
As I told you, this singleton is a "hack" and you use it on your own risk. IMO you should not use one context in another because things might have different meaning for them. Its very easy to make a mess this way in your test suite.
Anyway PageObjectExtension should solve your problems :beer:
Indeed, the PageObjectExtension looks promising.
As for the singleton hack, for know it is a necessary hack as we need some data to be shared across all contexts during our tests. It's still better than a non-working app !
I would second the ability to have inter-context communications.
The usecase is the following:
At the moment the codebase resorts to making most methods in helper contexts static methods, and putting a huge amount of current-state information in a singleton class.
But that feels bad.
Instead of making every context a singleton on its own, I was thinking of binding them to a context-pool via creation of an extension and letting the helper contexts expose an Interface, say
interface shareableContext
public function shareMe($callable)
{
$callable($this);
}
This might be in the end just a more convoluted way of doing what we do already with all our static methods...
Apropos PageObject: I am so far not convinced of its benefits. It seems overkill most of the time. Plus it does not directly address my needs.
The long story:
a) The tests I have seen written end up in feature steps which read _given I test that the functionality X works_, which removes imho all the advantages bdd has over say unit tests, as only the coder knows what is going on, and the product manager can not read nor write features
b) the way the pageObject class itself works is a bit counterintuitive vs. the http navigation flow (dev can create a pageObject without navigating to it and viceversa)
c) most tests end up split in 3 parts: the feature file, the context and the pageObject. This makes it hard to write and understand them
Have you guys find out how to use access data between contexts.
I am in the middle of upgrading to behat 3 and this is a big problem for us.
Steps like: i_click_on() are used in mostly all context. If I use trait, then it fails with duplicate step error.
Appreciate any help here :)
@rajeshtaneja I will try to post a gist of the work I have done
I have an idea about how to build this. I will try to build an extension for this during the weekend (maybe earlier if I have time for it)
Thanks Christophe and Gaetano ,
It will be very helpful, if I can get some clue on how to re-arrange my contexts. I looked at pageObject and I think that is an overkill. We have all basic functions like i_login_as(), i_have_following_users() etc. and they need to be part of mostly every context. The list is too big and it comes from different part of code. In behat 2.x it was used as sub-context, so that was not a problem, but not context being isolated is making me think what is the best way to re-arrange them.
I can create a new context object in my current context and set mink to call steps from diffent context, but saying so, this is messy way and (To be frank) I am not sure if that is the right way.
Cheers.
@stof tell me if you need any help!
Here's the gist https://gist.github.com/gggeek/f7a27006b9861ec841b9
Sorry if it is not fully usable as-is (you have to make a behat extension out of it, plus it does not contain examples of contexts sharing each other), but it should be understandable to people who grok behat
Thanks Gaetano,
This is a good way to share context, just wondering how step definition list be populated. Anyway will try apply this design to see if I can get anywhere.
While working on my idea yesterday evening, I discovered that there is a much better way to do this, without any extra Behat extension: https://gist.github.com/stof/930e968829cd66751a3a
I will submit a PR to the doc with this
@stof I had found out that possibility, but did not go that way because I did not want to litter my behat.yml with a lot of contexts declared in every suite (in fact the tests I was given had many such 'supporting' contexts in each suite, and I tried to remove as many as possible).
But I might have missed something. Is it f.e. possible to declare some contexts only once in a way that they apply to each suite anyway?
@gggeek This issue is about having a way to communicate between contexts, so I don't understand your comment saying you don't want multiple contexts. If you don't have multiple contexts, you are simply not concerned about the issue of communicating between them.
@RynnHeldeD I suggest keeping this closed in favor of the solution I suggested above (and for which I sent a documentation PR)
Alright, as there was some discussion, I thought it would be pertinent to reopen, sorry.
@stof you are right. My comment was not meant as a NACK, rather as an explanation of the rationale behind the different approach I had taken, so fine with me with the docs approach.
For the record, the contexts I wanted to eliminate from behat.yml were context with purely 'support' functionality - I agree that for the common case you'd want communication to happen between contexts which are declared as part of a suite because they do fully 'belong' there.
This should solve the issue right? http://stackoverflow.com/questions/29674685/how-to-communicate-between-contexts-in-behat-3
Most helpful comment
While working on my idea yesterday evening, I discovered that there is a much better way to do this, without any extra Behat extension: https://gist.github.com/stof/930e968829cd66751a3a
I will submit a PR to the doc with this