Skip to content

Commit

Permalink
refactor http actions
Browse files Browse the repository at this point in the history
  • Loading branch information
kbond committed Dec 2, 2020
1 parent 53d979f commit c28e0c7
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 32 deletions.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,46 @@ $browser
;

// http request actions (NOTE: these are not available for PantherBrowser)
use Zenstruck\Browser\HttpOptions;

$browser
->get('/api/endpoint')
->put('/api/endpoint')
->post('/api/endpoint')
->delete('/api/endpoint')

// second parameter can be an array of request options
->post('/api/endpoint', [
// request headers
'headers' => ['X-Token' => 'my-token'],

// request body
'body' => 'request body',
])
->post('/api/endpoint', [
// json_encode request body and set Content-Type/Accept headers to application/json
'json' => ['request' => 'body'],

// simulates an AJAX request (sets the X-Requested-With to XMLHttpRequest)
'ajax' => true,
])

// optionally use the provided Zenstruck\Browser\HttpOptions object
->post('/api/endpoint',
HttpOptions::create()->withHeader('X-Token', 'my-token')->withBody('request body')
)

// sets the Content-Type/Accept headers to application/json
->post('/api/endpoint', HttpOptions::json())

// json encodes value and sets as body
->post('/api/endpoint', HttpOptions::json(['request' => 'body']))

// simulates an AJAX request (sets the X-Requested-With to XMLHttpRequest)
->post('/api/endpoint', HttpOptions::ajax())

// simulates a JSON AJAX request
->post('/api/endpoint', HttpOptions::jsonAjax())
;

// convenience methods
Expand Down
42 changes: 29 additions & 13 deletions src/Browser/Actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,48 @@ final public function visit(string $uri): self
return $this;
}

final public function get(string $url, array $parameters = [], array $files = [], array $server = []): self
/**
* @param HttpOptions|array $options @see HttpOptions::DEFAULT_OPTIONS
*/
final public function request(string $method, string $url, $options = []): self
{
$this->inner()->request('GET', $url, $parameters, $files, $server);
$options = HttpOptions::create($options);

$this->inner()->request($method, $url, $options->parameters(), $options->files(), $options->server(), $options->body());

return $this;
}

final public function post(string $url, array $parameters = [], array $files = [], array $server = []): self
/**
* @see request()
*/
final public function get(string $url, $options = []): self
{
$this->inner()->request('POST', $url, $parameters, $files, $server);

return $this;
return $this->request('GET', $url, $options);
}

final public function put(string $url, array $parameters = [], array $files = [], array $server = []): self
/**
* @see request()
*/
final public function post(string $url, $options = []): self
{
$this->inner()->request('PUT', $url, $parameters, $files, $server);

return $this;
return $this->request('POST', $url, $options);
}

final public function delete(string $url, array $parameters = []): self
/**
* @see request()
*/
final public function put(string $url, $options = []): self
{
$this->inner()->request('DELETE', $url, $parameters);
return $this->request('PUT', $url, $options);
}

return $this;
/**
* @see request()
*/
final public function delete(string $url, $options = []): self
{
return $this->request('DELETE', $url, $options);
}

final public function follow(string $link): self
Expand Down
162 changes: 162 additions & 0 deletions src/Browser/HttpOptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<?php

namespace Zenstruck\Browser;

/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
class HttpOptions
{
private const DEFAULT_OPTIONS = [
'headers' => [],
'parameters' => [],
'files' => [],
'server' => [],
'body' => null,
'json' => null,
'ajax' => false,
];

private array $options;

final public function __construct(array $options = [])
{
$this->options = \array_merge(self::DEFAULT_OPTIONS, $options);

if ($this->options['json']) {
$this->asJson($this->options['json']);
}

if ($this->options['ajax']) {
$this->asAjax();
}
}

/**
* @param self|array $value
*/
final public static function create($value = []): self
{
if ($value instanceof self) {
return $value;
}

return new self($value);
}

final public static function json($body = null): self
{
return self::create()->asJson($body);
}

final public static function ajax(): self
{
return self::create()->asAjax();
}

final public static function jsonAjax($body = null): self
{
return self::json($body)->asAjax();
}

final public function withHeader(string $header, string $value): self
{
$this->options['headers'][$header] = $value;

return $this;
}

final public function withHeaders(array $headers): self
{
$this->options['headers'] = $headers;

return $this;
}

final public function withParameters(array $parameters): self
{
$this->options['parameters'] = $parameters;

return $this;
}

final public function withServer(array $server): self
{
$this->options['server'] = $server;

return $this;
}

final public function withFiles(array $files): self
{
$this->options['files'] = $files;

return $this;
}

final public function withBody(?string $body): self
{
$this->options['body'] = $body;

return $this;
}

final public function asJson($body = null): self
{
return $this->withBody(null !== $body ? \json_encode($body, \JSON_THROW_ON_ERROR) : null)
->withHeader('Content-Type', 'application/json')
->withHeader('Accept', 'application/json')
;
}

final public function asAjax(): self
{
return $this->withHeader('X-Requested-With', 'XMLHttpRequest');
}

/**
* @internal
*/
final public function parameters(): array
{
return $this->options['parameters'];
}

/**
* @internal
*/
final public function files(): array
{
return $this->options['files'];
}

/**
* @author Kévin Dunglas <dunglas@gmail.com>
*
* @internal
*/
final public function server(): array
{
$server = $this->options['server'];

foreach ($this->options['headers'] as $header => $value) {
$header = \mb_strtoupper(\str_replace('-', '_', $header));

if ('CONTENT_TYPE' !== $header) {
$header = "HTTP_{$header}";
}

$server[$header] = $value;
}

return $server;
}

/**
* @internal
*/
final public function body(): ?string
{
return $this->options['body'];
}
}
26 changes: 22 additions & 4 deletions tests/BrowserTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
namespace Zenstruck\Browser\Tests;

use Zenstruck\Browser;
use Zenstruck\Browser\HttpOptions;

/**
* @author Kevin Bond <kevinbond@gmail.com>
*
* @method Browser browser()
*/
trait BrowserTests
{
Expand Down Expand Up @@ -171,16 +174,31 @@ public function http_method_actions(): void
$this->browser()
->get('/http-method')
->assertSuccessful()
->assertResponseContains('method: GET')
->assertResponseContains('"method":"GET"')
->post('/http-method')
->assertSuccessful()
->assertResponseContains('method: POST')
->assertResponseContains('"method":"POST"')
->delete('/http-method')
->assertSuccessful()
->assertResponseContains('method: DELETE')
->assertResponseContains('"method":"DELETE"')
->put('/http-method')
->assertSuccessful()
->assertResponseContains('method: PUT')
->assertResponseContains('"method":"PUT"')
->assertResponseContains('"ajax":false')
->post('/http-method', [
'json' => ['foo' => 'bar'],
'headers' => ['X-Foo' => 'Bar'],
'ajax' => true,
])
->assertResponseContains('"content-type":["application\/json"]')
->assertResponseContains('"x-foo":["Bar"]')
->assertResponseContains('"content":"{\u0022foo\u0022:\u0022bar\u0022}"')
->assertResponseContains('"ajax":true')
->post('/http-method', HttpOptions::jsonAjax(['foo' => 'bar'])->withHeader('X-Foo', 'Bar'))
->assertResponseContains('"content-type":["application\/json"]')
->assertResponseContains('"x-foo":["Bar"]')
->assertResponseContains('"content":"{\u0022foo\u0022:\u0022bar\u0022}"')
->assertResponseContains('"ajax":true')
;
}

Expand Down
14 changes: 0 additions & 14 deletions tests/Fixture/EmailBrowser.php

This file was deleted.

12 changes: 11 additions & 1 deletion tests/Fixture/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,17 @@ public function submitForm(Request $request): JsonResponse

public function httpMethod(Request $request): Response
{
return new Response("method: {$request->getMethod()}");
return new JsonResponse([
'method' => $request->getMethod(),
'headers' => $request->headers->all(),
'query' => $request->query->all(),
'attributes' => $request->attributes->all(),
'files' => $request->files->all(),
'server' => $request->server->all(),
'request' => $request->query->all(),
'content' => $request->getContent(),
'ajax' => $request->isXmlHttpRequest(),
]);
}

public function exception(): void
Expand Down

0 comments on commit c28e0c7

Please sign in to comment.