Skip to content

Instantly share code, notes, and snippets.

@gooh
Created November 23, 2017 13:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gooh/4e9b2cb5a30ce9a684580c1b419caf0e to your computer and use it in GitHub Desktop.
Save gooh/4e9b2cb5a30ce9a684580c1b419caf0e to your computer and use it in GitHub Desktop.
version of webtestcase with all the project info removed
<?php
namespace Acme\ApiBundle\Tests;
use Exception;
use Acme\CoreBundle\Tests\DatabaseTestCase;
use Symfony\Bundle\FrameworkBundle\Client;
use Acme\ApiBundle\Tests\Helper\IgnoreValue;
use Acme\FrameworkBundle\Tests\Exception\FixtureFileNotMatchingException;
use Symfony\Component\BrowserKit\Cookie;
abstract class ApiTestCase extends DatabaseTestCase
{
/**
* Belongs to User Id 156
*/
const DEFAULT_ACCESS_TOKEN_STRING = '****';
const ROLE_USER_ACCESS_TOKEN_STRING = 'role_user_token';
const COOKIE_TOKEN_KEY = 'x-token';
const HEADER_TOKEN_KEY = 'HTTP_X_TOKEN';
/**
* @var string
*/
protected $resultsDir = 'ExpectedResults/';
/**
* @var array
*/
protected static $validLoginData = [
"username" => "***@example.com",
"password" => "***"
];
public function setUp()
{
$this->setupTestToUseFullFixtureSet();
parent::setUp();
}
/**
* Returns the Symfony Client
*
* Usually you will not need this method. Use {@see getLastResponseBody} or
* {@see assertHttpStatusCode} or {@see doJsonRequest} to interact with the
* client instead.
*
* @return Client
*/
protected function getClient()
{
return $this->client;
}
/**
* @param string $method
* @param string $uri
* @param array $queryParams
* @param mixed $jsonBody
*/
protected function doJsonRequest($method, $uri, array $queryParams = [], $jsonBody = null)
{
$this->client->request(
$method,
empty($queryParams) ? $uri : $uri . '?'. http_build_query($queryParams),
[ /* no params */ ],
[ /* no files */ ],
['CONTENT_TYPE' => 'application/json'],
is_null($jsonBody) ? $jsonBody : json_encode($jsonBody)
);
}
/**
* Assert StatusCode in last fetched Response matches given StatusCode
*
* @param int $expectedStatusCode
*/
protected function assertHttpStatusCode($expectedStatusCode)
{
$this->assertEquals(
$expectedStatusCode,
$this->getLastResponseCode(),
$this->getLastResponseBody()
);
}
/**
* Returns the Response Body of the last Response
*
* This is a convenience method to allow direct access to the Response body
* of the current Response. You can also call this via the client, fetching
* the Response and then the Content. This one is shorter.
*
* @return string
*/
protected function getLastResponseBody()
{
return $this->client->getResponse()->getContent();
}
/**
* Returns the Http Status Code of the last Response
*
* This is not part of the API and hence private. You are not supposed to
* use this method in your derived Testcases. Use assertHttpStatusCode()
* to verify Http status codes.
*
* @return int
*/
private function getLastResponseCode()
{
return $this->getClient()->getResponse()->getStatusCode();
}
/**
* Asserts the last Response matches a given file from the fixtures folder
*
* @param null $variant Variant of the fixture file. Defaults to test method name.
* @throws \Acme\FrameworkBundle\Tests\Exception\FixtureFileNotMatchingException
*/
protected function assertLastResponseEqualsFixtureFile($variant = null)
{
/*
* @internal the output of assertJsonStringEqualsJsonString is better
* for debugging than it's counterparts that assert on Files. This is
* why we use it here and load the expected results file.
*/
try {
$this->assertJsonStringEqualsJsonString(
file_get_contents($this->getExpectedResultsFile($variant)),
$this->getLastResponseBody()
);
} catch (\PHPUnit_Framework_ExpectationFailedException $e) {
$newException = new FixtureFileNotMatchingException($e->getMessage(), $e->getComparisonFailure());
$newException->setFixtureFileName($this->getExpectedResultsFile($variant));
throw $newException;
}
}
/**
* Returns the file path based to a fixture file
*
* The convention is to store fixtures in the results dir in a subfolder
* named after the short class name of the Test class followed by the
* test method name, e.g.
*
* db/fixtures/ExpectedResults/SomeControllerTest/testSomething.json
*
* @param string $variant Variant of the test, omitting will use just the test name
* @param string $fileExtension Extension of the result file, default is json
* @return string
*/
protected function getExpectedResultsFile($variant = null, $fileExtension = "json")
{
$reflectionClass = new \ReflectionClass($this);
$resultsDir = $this->getFixturesDir() . $this->resultsDir;
if (strpos($variant, $this->getName(false)) !== false) {
$variant = str_replace($this->getName(false), '', $variant);
}
return sprintf(
"%s%s/%s%s.%s",
$resultsDir,
$reflectionClass->getShortName(),
$this->getName(false),
$variant,
$fileExtension
);
}
/**
* Adds an Access Token for authentication to Server Params
*
* Note that this has to be written as HTTP_X_TOKEN in order for Symfony
* to pick it up as x-token. The token has to exist in the database and
* reference a valid user in order to work.
*
* If no $accessTokenString is passed, the token used will be the one
* defined in the class constant DEFAULT_ACCESS_TOKEN_STRING.
*
* @link https://github.com/symfony/symfony/issues/5074
*
* @param string $accessTokenString
*
* @return void
*/
protected function enableAuthentication($accessTokenString = null)
{
$accessTokenString = $this->getAccessTokenString($accessTokenString);
$this->client->setServerParameter(static::HEADER_TOKEN_KEY, $accessTokenString);
}
/**
* enable authentification with cookie. Used for file downloads
*
* @param null $accessTokenString
*/
protected function enableCookieAuthentification($accessTokenString = null)
{
$accessTokenString = $this->getAccessTokenString($accessTokenString);
$cookie = new Cookie(static::COOKIE_TOKEN_KEY, $accessTokenString);
$this->client->getCookieJar()->set($cookie);
}
/**
* Returns the given accessTokenString or as default the one
* defined in the class constant DEFAULT_ACCESS_TOKEN_STRING.
*
* @param null $accessTokenString
* @return null|string
*/
protected function getAccessTokenString($accessTokenString = null)
{
$accessTokenString = is_null($accessTokenString)
? static::DEFAULT_ACCESS_TOKEN_STRING
: $accessTokenString;
return $accessTokenString;
}
/**
* @see IgnoreValue
* @param array $fieldList
* @param string $dataKey Default "data"
*/
protected function assertLastResponseBodyIsJsonAndContainsFields(array $fieldList, $dataKey = 'data')
{
$responseBody = $this->getLastResponseBody();
$this->assertJson($responseBody);
$decodedData = json_decode($responseBody)->$dataKey;
foreach ($fieldList as $fieldName => $value) {
$this->assertObjectHasAttribute(
$fieldName,
$decodedData,
"Field [$fieldName] not in object"
);
if (false === $value instanceof IgnoreValue) {
$this->assertEquals(
$value,
$decodedData->$fieldName,
"Expecting [$value] got: [{$decodedData->$fieldName}]"
);
}
}
}
/**
* Asserts the last Response contains an empty data property.
*
* @param string $message Message in case Assertions fails
*/
protected function assertEmptyData($message = '')
{
$this->assertJsonStringEqualsJsonString(
'{"data": []}',
$this->getLastResponseBody(),
$message
);
}
/**
* Asserts that the given paramter of a POST or PUT request, which was matched
* against a form, contains errors.
*
* @param $parameterName
*/
protected function assertRequestFormHasErrorForParameter($parameterName)
{
$responseObjAsArray = json_decode($this->getLastResponseBody(), true);
$this->assertArrayHasKey(
"errors",
$responseObjAsArray,
"Response does not contain any errors."
);
$this->assertArrayHasKey(
"children",
$responseObjAsArray["errors"],
"Response errors does not contain any children"
);
$this->assertArrayHasKey(
$parameterName,
$responseObjAsArray["errors"]["children"],
"Response errors does not contain the field $parameterName"
);
$this->assertArrayHasKey(
"errors",
$responseObjAsArray["errors"]["children"][$parameterName],
"Field $parameterName does not have any Errors"
);
}
/**
* Generates an expected fixture file
*
* This method will take the response returned by a test and write it to
* the expected fixture file. The filename and path used follows our
* convention for expected result files. The $fileNumber parameter can be
* passed for tests that use dataProviders to create numbered files.
*
* Calling this method will cause your test to raise a warning. Verify the
* fixture you generated, then remove this method from your test. It should
* never be kept in a test.
*
* @param string $variant
* @param string $extension
*/
protected function generateExpectedResultsFile($variant = null, $extension = 'json')
{
$fileName = $this->getExpectedResultsFile($variant, $extension);
$dirName = dirname($fileName);
if (false === is_dir($dirName)) {
mkdir($dirName);
}
file_put_contents($fileName, $this->getLastResponseBody());
trigger_error(__METHOD__ . ' should never be kept in a test', E_USER_WARNING);
}
/**
* This method is run after a test was not successful.
*
* If the Environment variable 'RECREATEFIXTURES' is set it will recreate
* fixtures for tests which have failed.
*
* @param Exception $e
* @throws Exception
*/
protected function onNotSuccessfulTest(Exception $e)
{
$recreateFixtureFiles = getenv('RECREATEFIXTURES');
if ($e instanceof FixtureFileNotMatchingException && $recreateFixtureFiles) {
file_put_contents($e->getFixtureFileName(), $this->getLastResponseBody());
}
parent::onNotSuccessfulTest($e);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment