Created
April 14, 2015 09:08
A possible method of E2E testing Aye Aye Api
This file contains 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 | |
namespace AyeAye\Tests\Behat; | |
use Behat\Behat\Context\Context; | |
use Behat\Behat\Context\SnippetAcceptingContext; | |
use Behat\Behat\Tester\Exception\PendingException; | |
use Behat\Gherkin\Node\PyStringNode; | |
use Behat\Gherkin\Node\TableNode; | |
use Guzzle\Http\Client; | |
use GuzzleHttp\Message\Request; | |
use GuzzleHttp\Message\Response; | |
/** | |
* Defines application features from the specific context. | |
*/ | |
class FeatureContext implements Context, SnippetAcceptingContext | |
{ | |
/** | |
* @var array | |
*/ | |
protected $config = []; | |
/** | |
* @var Client | |
*/ | |
protected $client; | |
/** | |
* @var Request | |
*/ | |
protected $request; | |
/** | |
* @var Response | |
*/ | |
protected $response; | |
/** | |
* @var [] | |
*/ | |
protected $parameters; | |
/** | |
* Initializes context. | |
* | |
* Every scenario gets its own context instance. | |
* You can also pass arbitrary arguments to the | |
* context constructor through behat.yml. | |
* | |
* @param array $parameters | |
*/ | |
public function __construct(array $parameters = []) | |
{ | |
$this->config = $parameters; | |
$this->client = new Client($this->getConfig('base_url'), $this->getConfig('guzzle')); | |
$this->request = $this->client->createRequest(); | |
} | |
/** | |
* Look up a parameter | |
* @param string $name | |
* @param mixed $default | |
* @return mixed | |
*/ | |
protected function getConfig($name, $default = null) | |
{ | |
if (array_key_exists($name, $this->config)) { | |
return $this->config[$name]; | |
} | |
return $default; | |
} | |
/** | |
* @Given I create a new request | |
*/ | |
public function createNewRequest() | |
{ | |
$this->request = $this->client->createRequest(); | |
return $this; | |
} | |
/** | |
* @Given I create a new :method request | |
* @param string $method | |
* @return $this | |
*/ | |
public function iCreateANewRequest($method = 'GET') | |
{ | |
$this->request = $this->client->createRequest(strtoupper($method)); | |
$this->parameters = []; | |
return $this; | |
} | |
/** | |
* @When I set the :header header to :value | |
* @param $header | |
* @param $value | |
* @return $this | |
*/ | |
public function iSetTheHeaderTo($header, $value) | |
{ | |
$this->request->setHeader($header, $value); | |
return $this; | |
} | |
/** | |
* @When I set :variable to :value | |
* @param string $variable | |
* @param mixed $value | |
* @return $this | |
*/ | |
public function iSetVariableToValue($variable, $value) | |
{ | |
$this->parameters[$variable] = $value; | |
return $this; | |
} | |
/** | |
* @When I send the request to :url | |
* @param string $url | |
* @return $this | |
*/ | |
public function iSendTheRequestTo($url) | |
{ | |
// Add FQDN if required | |
if(!preg_match('/^\w+\:/', $url)) { | |
if($url[0] != '/') { | |
$url = "/$url"; | |
} | |
$url = $this->getConfig('base_url').$url; | |
} | |
$this->request->setUrl($url); | |
// Add parameters | |
switch($this->request->getMethod()) { | |
case 'GET': | |
$this->request->setUrl( | |
$this->request->getUrl(true)->setQuery($this->parameters) | |
); | |
break; | |
} | |
// Send the request | |
$this->response = $this->client->send($this->request); | |
return $this; | |
} | |
/** | |
* @Then the content-type of the request will be :contentType | |
* @param string $contentType | |
* @return $this | |
*/ | |
public function theContentTypeOfTheRequestWillBe($contentType) | |
{ | |
$this->request->setHeader('Content-type', $contentType); | |
return $this; | |
} | |
/** | |
* @Then I expect the content to to be :contentType | |
* @param $expectedContentType | |
* @throws \Exception | |
* @return $this | |
*/ | |
public function iExpectTheResponseContentTypeToBe($expectedContentType) | |
{ | |
$actualContentType = $this->response->getHeader('Content-Type'); | |
if($actualContentType != $expectedContentType) { | |
throw new \Exception("Expected Content-Type '$expectedContentType', received '$actualContentType'"); | |
} | |
return $this; | |
} | |
/** | |
* @Then I expect the status code to be :code | |
* @param $expectedCode | |
* @throws \Exception | |
* @return $this | |
*/ | |
public function iExpectTheStatusCodeToBe($expectedCode) | |
{ | |
$actualCode = $this->response->getStatusCode(); | |
if($actualCode != $expectedCode) { | |
throw new \Exception("Expected status code '$expectedCode', received '$actualCode'"); | |
} | |
return $this; | |
} | |
/** | |
* @Then I expect :property to equal :value | |
* @param $property | |
* @param $value | |
* @throws \Exception | |
* @returns $this | |
*/ | |
public function iExpectPropertyToBeEqualTo($property, $value) | |
{ | |
$response = $this->stringToObject($this->response->getBody(true)); | |
$testValue = $this->getNestedValue($response, $property); | |
if($testValue != $value) { | |
throw new \Exception("Expected to '$property' to equal '$value' but it was '$testValue'"); | |
} | |
return $this; | |
} | |
/** | |
* @Then I expect :property to contain :size value(s) | |
* @param $property | |
* @param $size | |
* @throws \Exception | |
* @returns $this | |
*/ | |
public function iExpectPropertyToBeOfSize($property, $size) | |
{ | |
$response = $this->stringToObject($this->response->getBody(true)); | |
$testArray = (array)$this->getNestedValue($response, $property); | |
$count = count($testArray); | |
if($count != $size) { | |
throw new \Exception("Expected to find '$size' items in '$property' but found '$count'"); | |
} | |
return $this; | |
} | |
/** | |
* @Then I expect :property to contain :value | |
* @param $property | |
* @param $value | |
* @throws \Exception | |
* @returns $this | |
*/ | |
public function iExpectPropertyToContain($property, $value) | |
{ | |
$exception = new \Exception("Expected to find '$value' in '$property' but could not"); | |
$response = $this->stringToObject($this->response->getBody(true)); | |
$testValue = $this->getNestedValue($response, $property); | |
if(is_scalar($testValue)) { | |
if(strpos($testValue, $value) === false) { | |
throw $exception; | |
} | |
return $this; | |
} | |
$testValue = (array)$testValue; | |
if(!in_array($value, $testValue) && !array_key_exists($value, $testValue)) { | |
throw $exception; | |
} | |
return $this; | |
} | |
/** | |
* @Then I expect :property not to contain :value | |
* @param $property | |
* @param $value | |
* @throws \Exception | |
* @returns $this | |
*/ | |
public function iExpectPropertyNotToContain($property, $value) | |
{ | |
$response = $this->stringToObject($this->response->getBody(true)); | |
$testArray = (array)$this->getNestedValue($response, $property); | |
if(in_array($value, $testArray) || array_key_exists($value, $testArray)) { | |
throw new \Exception("Did not expected to find '$value' in '$property' but did"); | |
} | |
return $this; | |
} | |
/** | |
* Hacky, should be replaced | |
* @param $string | |
* @return \stdClass | |
*/ | |
protected function stringToObject($string) { | |
$request = new \AyeAye\Api\Request(); | |
return $request->stringToObject($string); | |
} | |
/** | |
* Find the value of a nested property in an object or array | |
* @param $objectOrArray | |
* @param $propertyChain | |
* @return object | |
* @throws \Exception | |
*/ | |
protected function getNestedValue($objectOrArray, $propertyChain) { | |
if(!$propertyChain) { | |
return $objectOrArray; | |
} | |
if(!is_object($objectOrArray)) { | |
// A straight cast here doesn't seem to work for numeric keys | |
// $objectOrArray = (object)$objectOrArray | |
$object = new \stdClass(); | |
foreach($objectOrArray as $k => $v) { | |
$object->$k = $v; | |
} | |
$objectOrArray = $object; | |
} | |
if(is_string($propertyChain)) { | |
$propertyChain = explode('.', $propertyChain); | |
} | |
if(!$propertyChain) { | |
throw new \Exception("Property missing"); | |
} | |
$nextProperty = array_shift($propertyChain); | |
if(!property_exists($objectOrArray, $nextProperty)) { | |
throw new \Exception("Property '$nextProperty' does not exist"); | |
} | |
return $this->getNestedValue($objectOrArray->$nextProperty, $propertyChain); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment