Skip to content

Commit

Permalink
Merge pull request #142 from snicco/fix/testing-bundle
Browse files Browse the repository at this point in the history
fix(testing-bundle): fix request generation of test browser
  • Loading branch information
calvinalkan committed May 28, 2022
2 parents 7ba8ade + 37806c2 commit 28520fe
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 22 deletions.
3 changes: 3 additions & 0 deletions src/Snicco/Bundle/testing/codeception.dist.yml
Expand Up @@ -15,6 +15,9 @@ settings:
log_incomplete_skipped: true
report_useless_tests: true

reporters:
report: "PhpStorm_Codeception_ReportPrinter"

coverage:
enabled: true
include:
Expand Down
2 changes: 1 addition & 1 deletion src/Snicco/Bundle/testing/composer.json
Expand Up @@ -23,6 +23,7 @@
"snicco/better-wp-mail-testing": "^1.2",
"snicco/http-routing-testing": "^1.2",
"snicco/http-routing-bundle": "^1.2",
"snicco/str-arr": "^1.2",
"snicco/pimple-bridge": "^1.2",
"symfony/browser-kit": "^5.4",
"symfony/dom-crawler": "^5.4.6",
Expand All @@ -31,7 +32,6 @@
},
"require-dev": {
"snicco/better-wpdb-bundle": "^1.2",
"snicco/str-arr": "^1.2",
"nyholm/psr7": "^1.0.0"
},
"autoload": {
Expand Down
117 changes: 99 additions & 18 deletions src/Snicco/Bundle/testing/src/Functional/Browser.php
Expand Up @@ -7,6 +7,7 @@
use BadMethodCallException;
use LogicException;
use Psr\Http\Message\ServerRequestFactoryInterface;
use Psr\Http\Message\ServerRequestInterface as Psr7Request;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\UploadedFileFactoryInterface;
use Snicco\Bundle\HttpRouting\HttpKernel;
Expand All @@ -17,14 +18,19 @@
use Snicco\Component\HttpRouting\Routing\Admin\AdminAreaPrefix;
use Snicco\Component\HttpRouting\Routing\UrlPath;
use Snicco\Component\HttpRouting\Testing\AssertableResponse;
use Snicco\Component\StrArr\Str;
use Symfony\Component\BrowserKit\AbstractBrowser;
use Symfony\Component\BrowserKit\CookieJar;
use Symfony\Component\BrowserKit\History;
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;
use Webmozart\Assert\Assert;

use function array_keys;
use function in_array;
use function is_array;
use function parse_str;
use function strpos;

use function strtolower;

use const UPLOAD_ERR_OK;

Expand Down Expand Up @@ -120,21 +126,109 @@ protected function filterResponse(object $response): \Symfony\Component\BrowserK
);
}

protected function filterRequest(\Symfony\Component\BrowserKit\Request $request): Request
protected function filterRequest(BrowserKitRequest $request): Request
{
$psr_server_request = $this->request_factory->createServerRequest(
$request->getMethod(),
$request->getUri(),
$request->getServer(),
);

$psr_server_request = $this->addHeadersFromServer($request, $psr_server_request);
$psr_server_request = $this->addCookies($request, $psr_server_request);
$psr_server_request = $this->addRequestBody($request, $psr_server_request);
$psr_server_request = $this->addFiles($request, $psr_server_request);

parse_str($psr_server_request->getUri()->getQuery(), $query);

$path = $psr_server_request->getUri()
->getPath();

$api_prefix = $this->api_prefix->asString();

if (Str::startsWith($path, $this->admin_area_prefix->asString())) {
$type = Request::TYPE_ADMIN_AREA;
} elseif ('/' !== $api_prefix && Str::startsWith($path, $api_prefix)) {
$type = Request::TYPE_API;
} else {
$type = Request::TYPE_FRONTEND;
}

return Request::fromPsr($psr_server_request->withQueryParams($query), $type);
}

private function addHeadersFromServer(BrowserKitRequest $browser_kit_request, Psr7Request $request): Psr7Request
{
foreach ($browser_kit_request->getServer() as $key => $value) {
Assert::stringNotEmpty($key);

$http_header = Str::startsWith($key, 'HTTP_');
$content_header = Str::startsWith($key, 'CONTENT_');

if (! $http_header && ! $content_header) {
continue;
}

if (is_array($value)) {
Assert::allStringNotEmpty($value);
} else {
Assert::stringNotEmpty($value);
}

if (Str::startsWith($key, 'HTTP_')) {
$header_name = Str::afterFirst($key, 'HTTP_');

$header_name = strtolower(Str::replaceAll($header_name, '_', '-'));

// These are already added by symfony.
if (in_array($header_name, ['host', 'referer'], true)) {
$request = $request->withHeader($header_name, $value);
} else {
$request = $request->withAddedHeader($header_name, $value);
}

continue;
}

if (Str::startsWith($key, 'CONTENT_')) {
$header_name = 'content-' . strtolower(Str::afterFirst($key, 'CONTENT_'));
$request = $request->withAddedHeader($header_name, $value);
}
}

return $request;
}

private function addCookies(BrowserKitRequest $request, Psr7Request $psr_server_request): Psr7Request
{
$cookies = $request->getCookies();
Assert::allString($cookies);
Assert::allString(array_keys($cookies));

$psr_server_request = $psr_server_request->withCookieParams($cookies);
$psr_server_request = $psr_server_request->withParsedBody($request->getParameters());
return $psr_server_request->withCookieParams($cookies);
}

private function addRequestBody(BrowserKitRequest $request, Psr7Request $psr_server_request): Psr7Request
{
$params = $request->getParameters();
$raw_body = $request->getContent();

if ($params && $raw_body) {
throw new LogicException('Its not possible to pass a raw request body and an array of parameters.');
}
if ([] !== $params) {
$psr_server_request = $psr_server_request->withParsedBody($request->getParameters());
} elseif (null !== $raw_body) {
$psr_server_request = $psr_server_request->withBody(
$this->stream_factory->createStream($raw_body)
);
}

return $psr_server_request;
}

private function addFiles(BrowserKitRequest $request, Psr7Request $psr_server_request): Psr7Request
{
$files = [];

foreach ($request->getFiles() as $name => $path) {
Expand All @@ -148,19 +242,6 @@ protected function filterRequest(\Symfony\Component\BrowserKit\Request $request)
);
}

$psr_server_request = $psr_server_request->withUploadedFiles($files);
$psr_server_request = $psr_server_request->withParsedBody($request->getParameters());

parse_str($psr_server_request->getUri()->getQuery(), $query);

if (0 === strpos($psr_server_request->getUri()->getPath(), $this->admin_area_prefix->asString())) {
$type = Request::TYPE_ADMIN_AREA;
} elseif (0 === strpos($psr_server_request->getUri()->getPath(), $this->api_prefix->asString())) {
$type = Request::TYPE_API;
} else {
$type = Request::TYPE_FRONTEND;
}

return Request::fromPsr($psr_server_request->withQueryParams($query), $type);
return $psr_server_request->withUploadedFiles($files);
}
}
107 changes: 105 additions & 2 deletions src/Snicco/Bundle/testing/tests/wordpress/Functional/BrowserTest.php
Expand Up @@ -7,6 +7,7 @@
use BadMethodCallException;
use Closure;
use Codeception\TestCase\WPTestCase;
use LogicException;
use Snicco\Bundle\HttpRouting\HttpKernel;
use Snicco\Bundle\HttpRouting\Psr17FactoryDiscovery;
use Snicco\Bundle\Testing\Functional\Browser;
Expand Down Expand Up @@ -234,6 +235,108 @@ public function test_api_requests_are_created_correctly(): void
->assertNotDelegated();
}

/**
* @test
*/
public function that_api_requests_are_not_created_if_the_api_prefix_is_empty(): void
{
$browser = $this->getBrowser([], null, '');

$browser->request('GET', '/api/test/check-api');

$browser->getResponse()
->assertSeeText('false')
->assertOk()
->assertNotDelegated();
}

/**
* @test
*/
public function that_http_and_content_server_params_are_converted_to_response_headers(): void
{
$browser = $this->getBrowser([
'HTTP_ACCEPT' => ['application/json', 'text/html'],
'CONTENT_TYPE' => 'application/json',
'HTTP_HOST' => 'snicco.test',
'HTTP_USER_AGENT' => 'snicco.test framework',
'HTTP_REFERER' => '/foo/bar',
]);

$browser->request('GET', '/headers-as-json');

$response = $browser->getResponse();
$response->assertStatus(200);
$response->assertNotDelegated()
->assertIsJson();

$body = (array) json_decode($response->body(), true, JSON_THROW_ON_ERROR, JSON_THROW_ON_ERROR);

$this->assertEquals([
'accept' => [
'application/json',
'text/html',
],
'content-type' => [
'application/json',
],
'host' => [
'snicco.test',
],
'user-agent' => [
'snicco.test framework',
],
'referer' => [
'/foo/bar',
],
], $body);
}

/**
* @test
*/
public function that_the_raw_content_can_not_be_used_together_with_params(): void
{
$browser = $this->getBrowser();

$this->expectException(LogicException::class);
$this->expectExceptionMessage('not possible');

$browser->request('POST', '/raw-body', [
'foo' => 'bar',
], [], [], 'foo_raw');
}

/**
* @test
*/
public function that_the_raw_content_is_transformed_and_used_in_the_psr7_request(): void
{
$browser = $this->getBrowser();

$browser->request('POST', '/raw-body', [], [], [], 'foo_raw');

$browser->getResponse()
->assertOk()
->assertSeeText('foo_raw')
->assertNotDelegated();
}

/**
* @test
*/
public function that_the_json_request_method_works(): void
{
$browser = $this->getBrowser();

$browser->jsonRequest('POST', '/raw-body', ['foo_raw']);

$browser->getResponse()
->assertOk()
->assertSeeText('foo_raw')
->assertNotDelegated();
}

/**
* @test
*/
Expand All @@ -251,7 +354,7 @@ public function test_assertable_dom(): void
/**
* @param array<string,mixed> $server
*/
private function getBrowser(array $server = [], CookieJar $cookies = null): Browser
private function getBrowser(array $server = [], CookieJar $cookies = null, string $api_prefix = '/api'): Browser
{
$kernel = ($this->boot_kernel_closure)(Environment::testing());
$kernel->afterRegister(function (Kernel $kernel): void {
Expand All @@ -266,7 +369,7 @@ private function getBrowser(array $server = [], CookieJar $cookies = null): Brow
$kernel->container()
->make(Psr17FactoryDiscovery::class),
AdminAreaPrefix::fromString('/wp-admin'),
UrlPath::fromString('/api'),
UrlPath::fromString($api_prefix),
$server,
null,
$cookies
Expand Down
Expand Up @@ -42,6 +42,12 @@ public function cookiesAsJson(Request $request): Response
->json($request->getCookieParams());
}

public function headersAsJson(Request $request): Response
{
return $this->respondWith()
->json($request->getHeaders());
}

public function bodyAsJson(Request $request): Response
{
return $this->respondWith()
Expand All @@ -66,6 +72,12 @@ public function filesAsJson(Request $request): Response
->json($info);
}

public function rawBody(Request $request): Response
{
return $this->respondWith()
->html((string) $request->getBody());
}

public function admin(): Response
{
return $this->respondWith()
Expand Down
Expand Up @@ -11,6 +11,7 @@
$router->get('foo', '/foo', WebTestCaseController::class);
$router->get('query-params-as-json', '/query-params-as-json', [WebTestCaseController::class, 'queryParams']);
$router->get('cookies-as-json', '/cookies-as-json', [WebTestCaseController::class, 'cookiesAsJson']);
$router->get('headers-as-json', '/headers-as-json', [WebTestCaseController::class, 'headersAsJson']);
$router->get('check-api-frontend', '/check-api', [WebTestCaseController::class, 'checkIfApi']);
$router->get('full', '/full-url', [WebTestCaseController::class, 'fullUrl']);
$router->get('custom-server', '/custom-server-vars', [WebTestCaseController::class, 'serverVars']);
Expand All @@ -23,7 +24,13 @@
$router->post('files-as-json', '/files-as-json', [WebTestCaseController::class, 'filesAsJson']);
$router->post('send-mail', '/send-mail', [WebTestCaseController::class, 'sendMail']);

$router->get('force-exception-middleware', '/force-exception-middleware', WebTestCaseController::class)->middleware(
$router->post('raw-body', '/raw-body', [WebTestCaseController::class, 'rawBody']);

$router->get(
'force-exception-middleware',
'/force-exception-middleware',
WebTestCaseController::class
)->middleware(
MiddlewareThatAlwaysThrowsException::class
);
};

0 comments on commit 28520fe

Please sign in to comment.