diff --git a/src/Symfony/Component/BrowserKit/CHANGELOG.md b/src/Symfony/Component/BrowserKit/CHANGELOG.md index 185071e6b2..b966974d8d 100644 --- a/src/Symfony/Component/BrowserKit/CHANGELOG.md +++ b/src/Symfony/Component/BrowserKit/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * Added `HttpBrowser`, an implementation of a browser with the HttpClient component * Renamed `Client` to `AbstractBrowser` * Marked `Response` final. * Deprecated `Response::buildHeader()` diff --git a/src/Symfony/Component/BrowserKit/HttpBrowser.php b/src/Symfony/Component/BrowserKit/HttpBrowser.php new file mode 100644 index 0000000000..cb13c738d3 --- /dev/null +++ b/src/Symfony/Component/BrowserKit/HttpBrowser.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\BrowserKit; + +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\Multipart\FormDataPart; +use Symfony\Component\Mime\Part\TextPart; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * An implementation of a browser using the HttpClient component + * to make real HTTP requests. + * + * @author Fabien Potencier + * + * @final + */ +class HttpBrowser extends AbstractBrowser +{ + private $client; + + public function __construct(HttpClientInterface $client = null, History $history = null, CookieJar $cookieJar = null) + { + if (!class_exists(HttpClient::class)) { + throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); + } + + $this->client = $client ?? HttpClient::create(); + + parent::__construct([], $history, $cookieJar); + } + + protected function doRequest($request) + { + $headers = $this->getHeaders($request); + $body = ''; + if (null !== $part = $this->getBody($request)) { + $headers = array_merge($headers, $part->getPreparedHeaders()->toArray()); + $body = $part->bodyToIterable(); + } + $response = $this->client->request($request->getMethod(), $request->getUri(), [ + 'headers' => $headers, + 'body' => $body, + 'max_redirects' => 0, + ]); + + return new Response($response->getContent(false), $response->getStatusCode(), $response->getHeaders(false)); + } + + private function getBody(Request $request): ?AbstractPart + { + if (\in_array($request->getMethod(), ['GET', 'HEAD'])) { + return null; + } + + if (!class_exists(AbstractPart::class)) { + throw new \LogicException('You cannot pass non-empty bodies as the Mime component is not installed. Try running "composer require symfony/mime".'); + } + + if (null !== $content = $request->getContent()) { + return new TextPart($content, 'utf-8', 'plain', '8bit'); + } + + $fields = $request->getParameters(); + foreach ($request->getFiles() as $name => $file) { + if (!isset($file['tmp_name'])) { + continue; + } + + $fields[$name] = DataPart::fromPath($file['tmp_name'], $file['name']); + } + + return new FormDataPart($fields); + } + + private function getHeaders(Request $request): array + { + $headers = []; + foreach ($request->getServer() as $key => $value) { + $key = strtolower(str_replace('_', '-', $key)); + $contentHeaders = ['content-length' => true, 'content-md5' => true, 'content-type' => true]; + if (0 === strpos($key, 'http-')) { + $headers[substr($key, 5)] = $value; + } elseif (isset($contentHeaders[$key])) { + // CONTENT_* are not prefixed with HTTP_ + $headers[$key] = $value; + } + } + $cookies = []; + foreach ($this->getCookieJar()->allRawValues($request->getUri()) as $name => $value) { + $cookies[] = $name.'='.$value; + } + if ($cookies) { + $headers['cookie'] = implode('; ', $cookies); + } + + return $headers; + } +} diff --git a/src/Symfony/Component/BrowserKit/README.md b/src/Symfony/Component/BrowserKit/README.md index a0083ac5bd..ef6d75b783 100644 --- a/src/Symfony/Component/BrowserKit/README.md +++ b/src/Symfony/Component/BrowserKit/README.md @@ -4,6 +4,9 @@ BrowserKit Component The BrowserKit component simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically. +The component comes with a concrete implementation that uses the HttpClient +component to make real HTTP requests. + Resources --------- diff --git a/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php b/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php index c51ea95e21..13bb2db105 100644 --- a/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php @@ -75,21 +75,26 @@ EOF; class AbstractBrowserTest extends TestCase { + public function getBrowser(array $server = [], History $history = null, CookieJar $cookieJar = null) + { + return new TestClient($server, $history, $cookieJar); + } + public function testGetHistory() { - $client = new TestClient([], $history = new History()); + $client = $this->getBrowser([], $history = new History()); $this->assertSame($history, $client->getHistory(), '->getHistory() returns the History'); } public function testGetCookieJar() { - $client = new TestClient([], null, $cookieJar = new CookieJar()); + $client = $this->getBrowser([], null, $cookieJar = new CookieJar()); $this->assertSame($cookieJar, $client->getCookieJar(), '->getCookieJar() returns the CookieJar'); } public function testGetRequest() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://example.com/'); $this->assertEquals('http://example.com/', $client->getRequest()->getUri(), '->getCrawler() returns the Request of the last request'); @@ -101,13 +106,13 @@ class AbstractBrowserTest extends TestCase */ public function testGetRequestNull() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertNull($client->getRequest()); } public function testXmlHttpRequest() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->xmlHttpRequest('GET', 'http://example.com/', [], [], [], null, true); $this->assertEquals($client->getRequest()->getServer()['HTTP_X_REQUESTED_WITH'], 'XMLHttpRequest'); $this->assertFalse($client->getServerParameter('HTTP_X_REQUESTED_WITH', false)); @@ -115,7 +120,7 @@ class AbstractBrowserTest extends TestCase public function testGetRequestWithIpAsHttpHost() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'https://example.com/foo', [], [], ['HTTP_HOST' => '127.0.0.1']); $this->assertEquals('https://example.com/foo', $client->getRequest()->getUri()); @@ -125,7 +130,7 @@ class AbstractBrowserTest extends TestCase public function testGetResponse() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo')); $client->request('GET', 'http://example.com/'); @@ -139,13 +144,13 @@ class AbstractBrowserTest extends TestCase */ public function testGetResponseNull() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertNull($client->getResponse()); } public function testGetInternalResponse() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new SpecialResponse('foo')); $client->request('GET', 'http://example.com/'); @@ -160,7 +165,7 @@ class AbstractBrowserTest extends TestCase */ public function testGetInternalResponseNull() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertNull($client->getInternalResponse()); } @@ -168,14 +173,14 @@ class AbstractBrowserTest extends TestCase { $json = '{"jsonrpc":"2.0","method":"echo","id":7,"params":["Hello World"]}'; - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('POST', 'http://example.com/jsonrpc', [], [], [], $json); $this->assertEquals($json, $client->getRequest()->getContent()); } public function testGetCrawler() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo')); $crawler = $client->request('GET', 'http://example.com/'); @@ -188,18 +193,18 @@ class AbstractBrowserTest extends TestCase */ public function testGetCrawlerNull() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertNull($client->getCrawler()); } public function testRequestHttpHeaders() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', '/'); $headers = $client->getRequest()->getServer(); $this->assertEquals('localhost', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com'); $headers = $client->getRequest()->getServer(); $this->assertEquals('www.example.com', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header'); @@ -208,7 +213,7 @@ class AbstractBrowserTest extends TestCase $headers = $client->getRequest()->getServer(); $this->assertTrue($headers['HTTPS'], '->request() sets the HTTPS header'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com:8080'); $headers = $client->getRequest()->getServer(); $this->assertEquals('www.example.com:8080', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header with port'); @@ -216,20 +221,20 @@ class AbstractBrowserTest extends TestCase public function testRequestURIConversion() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', '/foo'); $this->assertEquals('http://localhost/foo', $client->getRequest()->getUri(), '->request() converts the URI to an absolute one'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com'); $this->assertEquals('http://www.example.com', $client->getRequest()->getUri(), '->request() does not change absolute URIs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/'); $client->request('GET', '/foo'); $this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo'); $client->request('GET', '#'); $this->assertEquals('http://www.example.com/foo#', $client->getRequest()->getUri(), '->request() uses the previous request for #'); @@ -238,32 +243,32 @@ class AbstractBrowserTest extends TestCase $client->request('GET', '#foo'); $this->assertEquals('http://www.example.com/foo#foo', $client->getRequest()->getUri(), '->request() uses the previous request for #'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/'); $client->request('GET', 'bar'); $this->assertEquals('http://www.example.com/foo/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/foobar'); $client->request('GET', 'bar'); $this->assertEquals('http://www.example.com/foo/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/'); $client->request('GET', 'http'); $this->assertEquals('http://www.example.com/foo/http', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo'); $client->request('GET', 'http/bar'); $this->assertEquals('http://www.example.com/http/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/'); $client->request('GET', 'http'); $this->assertEquals('http://www.example.com/http', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo'); $client->request('GET', '?'); $this->assertEquals('http://www.example.com/foo?', $client->getRequest()->getUri(), '->request() uses the previous request for ?'); @@ -275,7 +280,7 @@ class AbstractBrowserTest extends TestCase public function testRequestReferer() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/foobar'); $client->request('GET', 'bar'); $server = $client->getRequest()->getServer(); @@ -284,7 +289,7 @@ class AbstractBrowserTest extends TestCase public function testRequestHistory() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/foobar'); $client->request('GET', 'bar'); @@ -294,7 +299,7 @@ class AbstractBrowserTest extends TestCase public function testRequestCookies() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo', 200, ['Set-Cookie' => 'foo=bar'])); $client->request('GET', 'http://www.example.com/foo/foobar'); $this->assertEquals(['foo' => 'bar'], $client->getCookieJar()->allValues('http://www.example.com/foo/foobar'), '->request() updates the CookieJar'); @@ -305,7 +310,7 @@ class AbstractBrowserTest extends TestCase public function testRequestSecureCookies() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo', 200, ['Set-Cookie' => 'foo=bar; path=/; secure'])); $client->request('GET', 'https://www.example.com/foo/foobar'); @@ -314,7 +319,7 @@ class AbstractBrowserTest extends TestCase public function testClick() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo')); $crawler = $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -325,7 +330,7 @@ class AbstractBrowserTest extends TestCase public function testClickLink() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo')); $client->request('GET', 'http://www.example.com/foo/foobar'); $client->clickLink('foo'); @@ -335,7 +340,7 @@ class AbstractBrowserTest extends TestCase public function testClickLinkNotFound() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foobar')); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -349,7 +354,7 @@ class AbstractBrowserTest extends TestCase public function testClickForm() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('
')); $crawler = $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -360,7 +365,7 @@ class AbstractBrowserTest extends TestCase public function testSubmit() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('
')); $crawler = $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -371,7 +376,7 @@ class AbstractBrowserTest extends TestCase public function testSubmitForm() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('
')); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -391,7 +396,7 @@ class AbstractBrowserTest extends TestCase public function testSubmitFormNotFound() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('
')); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -408,7 +413,7 @@ class AbstractBrowserTest extends TestCase public function testSubmitPreserveAuth() { - $client = new TestClient(['PHP_AUTH_USER' => 'foo', 'PHP_AUTH_PW' => 'bar']); + $client = $this->getBrowser(['PHP_AUTH_USER' => 'foo', 'PHP_AUTH_PW' => 'bar']); $client->setNextResponse(new Response('
')); $crawler = $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -431,7 +436,7 @@ class AbstractBrowserTest extends TestCase public function testSubmitPassthrewHeaders() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('
')); $crawler = $client->request('GET', 'http://www.example.com/foo/foobar'); $headers = ['Accept-Language' => 'de']; @@ -445,7 +450,7 @@ class AbstractBrowserTest extends TestCase public function testFollowRedirect() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->followRedirects(false); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -462,19 +467,19 @@ class AbstractBrowserTest extends TestCase $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => 'http://www.example.com/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() automatically follows redirects if followRedirects is true'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 201, ['Location' => 'http://www.example.com/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); $this->assertEquals('http://www.example.com/foo/foobar', $client->getRequest()->getUri(), '->followRedirect() does not follow redirect if HTTP Code is not 30x'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 201, ['Location' => 'http://www.example.com/redirected'])); $client->followRedirects(false); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -489,12 +494,12 @@ class AbstractBrowserTest extends TestCase public function testFollowRelativeRedirect() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => '/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => '/redirected:1234'])); $client->request('GET', 'http://www.example.com/foo/foobar'); $this->assertEquals('http://www.example.com/redirected:1234', $client->getRequest()->getUri(), '->followRedirect() follows relative urls'); @@ -502,7 +507,7 @@ class AbstractBrowserTest extends TestCase public function testFollowRedirectWithMaxRedirects() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setMaxRedirects(1); $client->setNextResponse(new Response('', 302, ['Location' => 'http://www.example.com/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -525,13 +530,13 @@ class AbstractBrowserTest extends TestCase $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => '//www.example.org/'])); $client->request('GET', 'https://www.example.com/'); $this->assertEquals('https://www.example.org/', $client->getRequest()->getUri(), '->followRedirect() follows protocol-relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => 'http://www.example.com/redirected'])); $client->request('POST', 'http://www.example.com/foo/foobar', ['name' => 'bar']); @@ -541,7 +546,7 @@ class AbstractBrowserTest extends TestCase public function testFollowRedirectWithCookies() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->followRedirects(false); $client->setNextResponse(new Response('', 302, [ 'Location' => 'http://www.example.com/redirected', @@ -562,7 +567,7 @@ class AbstractBrowserTest extends TestCase 'HTTPS' => false, ]; - $client = new TestClient(); + $client = $this->getBrowser(); $client->followRedirects(false); $client->setNextResponse(new Response('', 302, [ 'Location' => 'http://www.example.com/redirected', @@ -589,7 +594,7 @@ class AbstractBrowserTest extends TestCase 'HTTP_REFERER' => 'http://www.example.com:8080/', ]; - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, [ 'Location' => 'http://www.example.com:8080/redirected', ])); @@ -600,7 +605,7 @@ class AbstractBrowserTest extends TestCase public function testIsFollowingRedirects() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertTrue($client->isFollowingRedirects(), '->getFollowRedirects() returns default value'); $client->followRedirects(false); $this->assertFalse($client->isFollowingRedirects(), '->getFollowRedirects() returns assigned value'); @@ -608,7 +613,7 @@ class AbstractBrowserTest extends TestCase public function testGetMaxRedirects() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertEquals(-1, $client->getMaxRedirects(), '->getMaxRedirects() returns default value'); $client->setMaxRedirects(3); $this->assertEquals(3, $client->getMaxRedirects(), '->getMaxRedirects() returns assigned value'); @@ -621,7 +626,7 @@ class AbstractBrowserTest extends TestCase $server = ['X_TEST_FOO' => 'bazbar']; $content = 'foobarbaz'; - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 307, ['Location' => 'http://www.example.com/redirected'])); $client->request('POST', 'http://www.example.com/foo/foobar', $parameters, $files, $server, $content); @@ -641,7 +646,7 @@ class AbstractBrowserTest extends TestCase $server = ['X_TEST_FOO' => 'bazbar']; $content = 'foobarbaz'; - $client = new TestClient(); + $client = $this->getBrowser(); foreach ([301, 302, 303] as $code) { $client->setNextResponse(new Response('', $code, ['Location' => 'http://www.example.com/redirected'])); @@ -661,7 +666,7 @@ class AbstractBrowserTest extends TestCase */ public function testFollowMetaRefresh(string $content, string $expectedEndingUrl, bool $followMetaRefresh = true) { - $client = new TestClient(); + $client = $this->getBrowser(); $client->followMetaRefresh($followMetaRefresh); $client->setNextResponse(new Response($content)); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -691,7 +696,7 @@ class AbstractBrowserTest extends TestCase public function testBack() { - $client = new TestClient(); + $client = $this->getBrowser(); $parameters = ['foo' => 'bar']; $files = ['myfile.foo' => 'baz']; @@ -711,7 +716,7 @@ class AbstractBrowserTest extends TestCase public function testForward() { - $client = new TestClient(); + $client = $this->getBrowser(); $parameters = ['foo' => 'bar']; $files = ['myfile.foo' => 'baz']; @@ -732,7 +737,7 @@ class AbstractBrowserTest extends TestCase public function testBackAndFrowardWithRedirects() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo'); $client->setNextResponse(new Response('', 301, ['Location' => 'http://www.example.com/redirected'])); @@ -751,7 +756,7 @@ class AbstractBrowserTest extends TestCase public function testReload() { - $client = new TestClient(); + $client = $this->getBrowser(); $parameters = ['foo' => 'bar']; $files = ['myfile.foo' => 'baz']; @@ -770,7 +775,7 @@ class AbstractBrowserTest extends TestCase public function testRestart() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/foobar'); $client->restart(); @@ -780,7 +785,7 @@ class AbstractBrowserTest extends TestCase public function testInsulatedRequests() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->insulate(); $client->setNextScript("new Symfony\Component\BrowserKit\Response('foobar')"); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -799,7 +804,7 @@ class AbstractBrowserTest extends TestCase public function testGetServerParameter() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); $this->assertEquals('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); $this->assertEquals('testvalue', $client->getServerParameter('testkey', 'testvalue')); @@ -807,7 +812,7 @@ class AbstractBrowserTest extends TestCase public function testSetServerParameter() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); $this->assertEquals('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); @@ -821,7 +826,7 @@ class AbstractBrowserTest extends TestCase public function testSetServerParameterInRequest() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); $this->assertEquals('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); @@ -855,7 +860,7 @@ class AbstractBrowserTest extends TestCase public function testRequestWithRelativeUri() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', '/', [], [], [ 'HTTP_HOST' => 'testhost', @@ -872,7 +877,7 @@ class AbstractBrowserTest extends TestCase public function testInternalRequest() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'https://www.example.com/https/www.example.com', [], [], [ 'HTTP_HOST' => 'testhost', @@ -890,7 +895,7 @@ class AbstractBrowserTest extends TestCase */ public function testInternalRequestNull() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertNull($client->getInternalRequest()); } diff --git a/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php b/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php new file mode 100644 index 0000000000..be1996d171 --- /dev/null +++ b/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\BrowserKit\Tests; + +use Symfony\Component\BrowserKit\CookieJar; +use Symfony\Component\BrowserKit\History; +use Symfony\Component\BrowserKit\HttpBrowser; +use Symfony\Component\BrowserKit\Response; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; + +class SpecialHttpResponse extends Response +{ +} + +class TestHttpClient extends HttpBrowser +{ + protected $nextResponse = null; + protected $nextScript = null; + + public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null) + { + $client = new MockHttpClient(function (string $method, string $url, array $options) { + if (null === $this->nextResponse) { + return new MockResponse(); + } + + return new MockResponse($this->nextResponse->getContent(), [ + 'http_code' => $this->nextResponse->getStatusCode(), + 'raw_headers' => $this->nextResponse->getHeaders(), + ]); + }); + parent::__construct($client); + + $this->setServerParameters($server); + $this->history = $history ?? new History(); + $this->cookieJar = $cookieJar ?? new CookieJar(); + } + + public function setNextResponse(Response $response) + { + $this->nextResponse = $response; + } + + public function setNextScript($script) + { + $this->nextScript = $script; + } + + protected function filterResponse($response) + { + if ($response instanceof SpecialHttpResponse) { + return new Response($response->getContent(), $response->getStatusCode(), $response->getHeaders()); + } + + return $response; + } + + protected function doRequest($request) + { + $response = parent::doRequest($request); + + if (null === $this->nextResponse) { + return $response; + } + + $class = \get_class($this->nextResponse); + $response = new $class($response->getContent(), $response->getStatusCode(), $response->getHeaders()); + $this->nextResponse = null; + + return $response; + } + + protected function getScript($request) + { + $r = new \ReflectionClass('Symfony\Component\BrowserKit\Response'); + $path = $r->getFileName(); + + return <<nextScript); +EOF; + } +} + +class HttpBrowserTest extends AbstractBrowserTest +{ + public function getBrowser(array $server = [], History $history = null, CookieJar $cookieJar = null) + { + return new TestHttpClient($server, $history, $cookieJar); + } + + public function testGetInternalResponse() + { + $client = $this->getBrowser(); + $client->setNextResponse(new SpecialHttpResponse('foo')); + $client->request('GET', 'http://example.com/'); + + $this->assertInstanceOf('Symfony\Component\BrowserKit\Response', $client->getInternalResponse()); + $this->assertNotInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialHttpResponse', $client->getInternalResponse()); + $this->assertInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialHttpResponse', $client->getResponse()); + } +} diff --git a/src/Symfony/Component/BrowserKit/composer.json b/src/Symfony/Component/BrowserKit/composer.json index 4c0567b5da..b5efd066a0 100644 --- a/src/Symfony/Component/BrowserKit/composer.json +++ b/src/Symfony/Component/BrowserKit/composer.json @@ -20,8 +20,10 @@ "symfony/dom-crawler": "~3.4|~4.0" }, "require-dev": { - "symfony/process": "~3.4|~4.0", - "symfony/css-selector": "~3.4|~4.0" + "symfony/css-selector": "~3.4|~4.0", + "symfony/http-client": "^4.3", + "symfony/mime": "^4.3", + "symfony/process": "~3.4|~4.0" }, "suggest": { "symfony/process": "" diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index c6630b65bc..9c63f0052e 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -56,7 +56,7 @@ class MockResponse implements ResponseInterface } } - $info['raw_headers'] = $rawHeaders; + $this->info['raw_headers'] = $rawHeaders; } /**