Last active
May 24, 2017 12:03
-
-
Save rosstuck/0b6ba370645f6b2f5cb1 to your computer and use it in GitHub Desktop.
Behat / ES Helper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Assert\Assertion; | |
use Behat\Behat\Tester\Exception\PendingException; | |
use Behat\Behat\Context\Context; | |
use Behat\Behat\Context\SnippetAcceptingContext; | |
use Behat\Gherkin\Node\PyStringNode; | |
use Behat\Gherkin\Node\TableNode; | |
/** | |
* Defines application features from the specific context. | |
*/ | |
class FeatureContext implements Context, SnippetAcceptingContext | |
{ | |
/** | |
* @var EventTimeline | |
*/ | |
private $timeline; | |
public function __construct() | |
{ | |
$this->timeline = new EventTimeline(CookieJar::class); | |
} | |
/** | |
* @Given I put a :flavor cookie in the jar | |
*/ | |
public function iPutARaisinCookieInTheJar($flavor) | |
{ | |
$this->timeline->given(new CookiePlacedInJar($flavor)); | |
} | |
/** | |
* @When I eat a cookie | |
*/ | |
public function iEatACookie() | |
{ | |
$this->timeline->whenI()->eatCookie(); | |
} | |
/** | |
* @Then I should have eaten a :flavor cookie | |
*/ | |
public function iShouldHaveEatenACookie($flavor) | |
{ | |
assertEquals( | |
new CookieEaten($flavor), | |
$this->timeline->next() | |
); | |
} | |
/** | |
* @Then I should have eaten at least one :flavor cookie | |
*/ | |
public function iShouldHaveEatenAtLeastOneCookie($flavor) | |
{ | |
assertContains( | |
new CookieEaten($flavor), | |
$this->timeline->getNewEvents(), | |
'', true, false //phpunit, yo | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Written for a Broadway style agregate | |
class EventTimeline | |
{ | |
/** | |
* @var string | |
*/ | |
private $aggregateClassName; | |
/** | |
* @var object|null | |
*/ | |
private $aggregate; | |
/** | |
* @var object[] | |
*/ | |
private $past = []; | |
/** | |
* @var object[] | |
*/ | |
private $future = []; | |
/** | |
* @var object[] | |
*/ | |
private $runningEvents = []; | |
/** | |
* @param string $aggregateClassName | |
*/ | |
public function __construct($aggregateClassName) | |
{ | |
$this->aggregateClassName = $aggregateClassName; | |
} | |
public function given($event) | |
{ | |
$this->past[] = $event; | |
} | |
public function whenI() | |
{ | |
if ($this->aggregate !== null) { | |
return $this->aggregate; | |
} | |
$this->aggregate = $this->aggregateClassName::reconstituteForHydration(); | |
array_map([$this->aggregate, 'handleEvent'], $this->past); | |
return $this->aggregate; | |
} | |
public function next() | |
{ | |
$this->captureNewEvents(); | |
$nextEvent = array_shift($this->runningEvents); | |
if ($nextEvent === null) { | |
throw new \RuntimeException('No more events'); | |
} | |
return $nextEvent; | |
} | |
public function getNewEvents() | |
{ | |
$this->captureNewEvents(); | |
return $this->future; | |
} | |
private function captureNewEvents() | |
{ | |
$newEvents = $this->whenI()->getUncommittedEvents(); | |
$this->future = array_merge($this->future, $newEvents); | |
$this->runningEvents = array_merge($this->runningEvents, $newEvents); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class CookieJar extends AggregateRoot | |
{ | |
private $cookies = []; | |
public function restockCookie($flavor) | |
{ | |
$this->apply(new CookiePlacedInJar($flavor)); | |
} | |
public function eatCookie() | |
{ | |
if (empty($this->cookies)) { | |
throw new \LogicException('Cookies all gone'); | |
} | |
$this->apply(new CookieEaten(end($this->cookies))); | |
} | |
protected function applyCookiePlacedInJar(CookiePlacedInJar $event) | |
{ | |
$this->cookies[] = $event->getFlavor(); | |
} | |
protected function applyCookieEaten(CookieEaten $event) | |
{ | |
if (empty($this->cookies)) { | |
throw new \LogicException('That...probably wasn\'t a cookie'); | |
} | |
$key = array_pop($this->cookies); | |
unset($this->cookies[$key]); | |
} | |
} | |
abstract class AggregateRoot | |
{ | |
private $pendingEvents = []; | |
public function handleEvent($event) | |
{ | |
$classParts = explode('\\', get_class($event)); | |
$methodName = 'apply' . end($classParts); | |
if (method_exists($this, $methodName)) { | |
$this->$methodName($event); | |
} | |
} | |
protected function apply($event) | |
{ | |
$this->handleEvent($event); | |
$this->pendingEvents[] = $event; | |
} | |
public function getUncommittedEvents() | |
{ | |
$events = $this->pendingEvents; | |
$this->pendingEvents = []; | |
return $events; | |
} | |
public static function reconstituteForHydration() | |
{ | |
return new static(); | |
} | |
} | |
class CookiePlacedInJar | |
{ | |
/** | |
* @var string | |
*/ | |
private $flavor; | |
/** | |
* @param string $flavor | |
*/ | |
public function __construct($flavor) | |
{ | |
$this->flavor = $flavor; | |
} | |
/** | |
* @return string | |
*/ | |
public function getFlavor() | |
{ | |
return $this->flavor; | |
} | |
} | |
class CookieEaten | |
{ | |
/** | |
* @var string | |
*/ | |
private $flavor; | |
/** | |
* @param string $flavor | |
*/ | |
public function __construct($flavor) | |
{ | |
$this->flavor = $flavor; | |
} | |
/** | |
* @return string | |
*/ | |
public function getFlavor() | |
{ | |
return $this->flavor; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment