diff --git a/.travis.yml b/.travis.yml
index a1c5395d..4b799d5b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,6 +17,8 @@ env:
- DEPS=low PROFILE=default
- DEPS=high PROFILE=symfony2
- DEPS=low PROFILE=symfony2
+ - DEPS=high PROFILE=browserKit
+ - DEPS=low PROFILE=browserKit
php:
- 5.5
diff --git a/behat.yml.dist b/behat.yml.dist
index 140bf0a6..8fa5ab3d 100644
--- a/behat.yml.dist
+++ b/behat.yml.dist
@@ -2,6 +2,8 @@ default:
suites:
default:
paths: [ '%paths.base%/tests/features' ]
+ filters:
+ tags: '~@symfony'
contexts:
- Behat\MinkExtension\Context\MinkContext
- behatch:context:browser:
@@ -33,3 +35,21 @@ symfony2:
extensions:
Behat\MinkExtension:
default_session: symfony2
+
+browserKit:
+ suites:
+ default:
+ filters:
+ tags: '@symfony'
+ extensions:
+ Behat\Symfony2Extension:
+ kernel:
+ bootstrap: 'tests/features/bootstrap/Bootstrap.php'
+ class: App\Kernel
+ env: test
+ debug: false
+ Behat\MinkExtension:
+ default_session: browserKit
+ sessions:
+ browserKit:
+ symfony2: ~
diff --git a/composer.json b/composer.json
index 7e39dd21..19ca2287 100644
--- a/composer.json
+++ b/composer.json
@@ -16,6 +16,8 @@
},
"require-dev": {
+ "symfony/templating": "^2.3|^3.0|^4.0",
+ "behat/symfony2-extension": "^2.1",
"behat/mink-goutte-driver": "^1.1",
"guzzlehttp/guzzle": "^6.3",
"behat/mink-selenium2-driver": "^1.3",
@@ -25,7 +27,8 @@
"autoload": {
"psr-4": {
- "Behatch\\": "src/"
+ "Behatch\\": "src/",
+ "App\\": "tests/fixtures/www/app"
}
},
diff --git a/src/HttpCall/Request/BrowserKit.php b/src/HttpCall/Request/BrowserKit.php
index 959bf8ff..e2fcc854 100644
--- a/src/HttpCall/Request/BrowserKit.php
+++ b/src/HttpCall/Request/BrowserKit.php
@@ -59,19 +59,22 @@ public function getContent()
public function send($method, $url, $parameters = [], $files = [], $content = null, $headers = [])
{
- foreach ($files as $originalName => &$file) {
- if (is_string($file)) {
- $file = new UploadedFile($file, $originalName);
- }
- }
-
$client = $this->mink->getSession()->getDriver()->getClient();
+ $tmpFiles = [];
+ if (!$client instanceof GoutteClient) {
+ $tmpFiles = $this->convertFilesToSymfonyUploadedFiles($files);
+ }
+
$client->followRedirects(false);
$client->request($method, $url, $parameters, $files, $headers, $content);
$client->followRedirects(true);
$this->resetHttpHeaders();
+ foreach ($tmpFiles as $tmpName) {
+ @unlink($tmpName);
+ }
+
return $this->mink->getSession()->getPage();
}
@@ -141,4 +144,37 @@ protected function resetHttpHeaders()
$client->restart();
}
}
+
+ private function convertFilesToSymfonyUploadedFiles(& $files)
+ {
+ $tmpFiles = [];
+ foreach ($files as $key => &$file) {
+ $tmpName = false;
+ if (is_string($file)) {
+ $tmpName = tempnam(sys_get_temp_dir(), 'upload');
+ copy($file, $tmpName);
+ $tmpFiles[] = $tmpName;
+ $originalName = $file;
+ } elseif (is_array($file)) {
+ // This mirrors Goutte\Client::addPostFiles() called from Goutte\Client::doRequest()
+ // so that a Symfony\Component\HttpKernel\Client can have the same behaviour
+ if (isset($file['tmp_name'])) {
+ $tmpName = $file['tmp_name'];
+ if (isset($file['name'])) {
+ $originalName = $file['name'];
+ } else {
+ $originalName = $tmpName;
+ }
+ } else {
+ $subTmpFiles = $this->convertFilesToSymfonyUploadedFiles($file);
+ $tmpFiles = array_merge($tmpFiles, $subTmpFiles);
+ }
+ }
+ if ($tmpName) {
+ $file = new UploadedFile($tmpName, $originalName, null, null, true);
+ }
+ }
+
+ return $tmpFiles;
+ }
}
diff --git a/tests/features/bootstrap/Bootstrap.php b/tests/features/bootstrap/Bootstrap.php
index 31064234..ff54c3a1 100644
--- a/tests/features/bootstrap/Bootstrap.php
+++ b/tests/features/bootstrap/Bootstrap.php
@@ -1,3 +1,4 @@
files->all();
+ $displayFiles = [];
+ /** @var UploadedFile $file */
+ foreach ($files as $key => $file) {
+ $displayFiles[$key] = [
+ 'name' => $file->getClientOriginalName(),
+ 'error' => $file->getError(),
+ 'size' => $file->getSize(),
+ ];
+ $file->move('/tmp/moved');
+ }
+
+ $view = 'templates/rest.php';
+ $parameters = [
+ 'server' => $request->server->all(),
+ 'method' => $request->getMethod(),
+ 'request' => $request->request->all(),
+ 'files' => $displayFiles,
+ 'body' => $request->getContent(),
+ ];
+ $content = $this->container->get('templating')->render($view, $parameters);
+ return new Response($content);
+ }
+}
diff --git a/tests/fixtures/www/app/Kernel.php b/tests/fixtures/www/app/Kernel.php
new file mode 100644
index 00000000..cb8c64fa
--- /dev/null
+++ b/tests/fixtures/www/app/Kernel.php
@@ -0,0 +1,97 @@
+projectDir) {
+ $this->projectDir = realpath(__DIR__ . '/../framework');
+ }
+
+ return $this->projectDir;
+ }
+
+ public function getCacheDir()
+ {
+ return $this->getProjectDir().'/var/cache/'.$this->environment;
+ }
+
+ public function getLogDir()
+ {
+ return $this->getProjectDir().'/var/log';
+ }
+
+ public function registerContainerConfiguration(LoaderInterface $loader)
+ {
+ $loader->load(function (ContainerBuilder $container) use ($loader) {
+ $container->loadFromExtension('framework', [
+ 'router' => [
+ 'resource' => 'kernel::loadRoutes',
+ 'type' => 'service',
+ ],
+ ]);
+
+ if ($this instanceof EventSubscriberInterface) {
+ $container->register('kernel', static::class)
+ ->setSynthetic(true)
+ ->setPublic(true)
+ ->addTag('kernel.event_subscriber');
+ }
+
+ $this->configureContainer($container, $loader);
+
+ $container->addObjectResource($this);
+ });
+ }
+
+ public function loadRoutes(LoaderInterface $loader)
+ {
+ $routes = new RouteCollectionBuilder($loader);
+ $this->configureRoutes($routes);
+
+ return $routes->build();
+ }
+
+ public function registerBundles()
+ {
+ $contents = require $this->getProjectDir().'/config/bundles.php';
+ foreach ($contents as $class => $envs) {
+ if (isset($envs['all']) || isset($envs[$this->environment])) {
+ yield new $class();
+ }
+ }
+ }
+
+ protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
+ {
+ $container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php'));
+ // Feel free to remove the "container.autowiring.strict_mode" parameter
+ // if you are using symfony/dependency-injection 4.0+ as it's the default behavior
+ $container->setParameter('container.autowiring.strict_mode', true);
+ $container->setParameter('container.dumper.inline_class_loader', true);
+ $confDir = $this->getProjectDir().'/config';
+
+ $loader->load($confDir.'/packages/framework'. self::CONFIG_EXTS);
+ $loader->load($confDir.'/services'.self::CONFIG_EXTS);
+ }
+
+ protected function configureRoutes(RouteCollectionBuilder $routes)
+ {
+ $confDir = $this->getProjectDir().'/config';
+
+ $routes->import($confDir.'/routes'.self::CONFIG_EXTS, '/');
+ }
+}
diff --git a/tests/fixtures/www/app/templates/rest.php b/tests/fixtures/www/app/templates/rest.php
new file mode 100644
index 00000000..367f72c9
--- /dev/null
+++ b/tests/fixtures/www/app/templates/rest.php
@@ -0,0 +1,32 @@
+You have sent a request.
+
+ header(s) received.
+ $value): ?>
+
:
+
+
+
+
No parameter received.
+
+
parameter(s) received.
+ $value): ?>
+
:
+
+
+
+
+
No files received.
+
+
file(s) received.
+ $value): ?>
+
- name :
+
- error :
+
- size :
+
+
+
+
+
No body received.
+
+
Body :
+
diff --git a/tests/fixtures/www/framework/config/bundles.php b/tests/fixtures/www/framework/config/bundles.php
new file mode 100644
index 00000000..49d3fb6f
--- /dev/null
+++ b/tests/fixtures/www/framework/config/bundles.php
@@ -0,0 +1,5 @@
+ ['all' => true],
+];
diff --git a/tests/fixtures/www/framework/config/packages/framework.yaml b/tests/fixtures/www/framework/config/packages/framework.yaml
new file mode 100644
index 00000000..bea1ba1b
--- /dev/null
+++ b/tests/fixtures/www/framework/config/packages/framework.yaml
@@ -0,0 +1,9 @@
+framework:
+ test: true
+ secret: 'xx-top-secret-yy'
+
+ router:
+ strict_requirements: ~
+
+ templating:
+ engines: ['php']
diff --git a/tests/fixtures/www/framework/config/routes.yaml b/tests/fixtures/www/framework/config/routes.yaml
new file mode 100644
index 00000000..6fbc211e
--- /dev/null
+++ b/tests/fixtures/www/framework/config/routes.yaml
@@ -0,0 +1,3 @@
+rest:
+ path: /symfony/rest
+ controller: 'App\Controller\RestController:action'
diff --git a/tests/fixtures/www/framework/config/services.yaml b/tests/fixtures/www/framework/config/services.yaml
new file mode 100644
index 00000000..531448f3
--- /dev/null
+++ b/tests/fixtures/www/framework/config/services.yaml
@@ -0,0 +1,32 @@
+# This file is the entry point to configure your own services.
+# Files in the packages/ subdirectory configure your dependencies.
+
+# Put parameters here that don't need to change on each machine where the app is deployed
+# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
+parameters:
+ locale: 'en'
+
+services:
+ # default configuration for services in *this* file
+ _defaults:
+ autowire: true # Automatically injects dependencies in your services.
+ autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
+ public: false # Allows optimizing the container by removing unused services; this also means
+ # fetching services directly from the container via $container->get() won't work.
+ # The best practice is to be explicit about your dependencies anyway.
+
+ # makes classes in src/ available to be used as services
+ # this creates a service per class whose id is the fully-qualified class name
+# App\:
+# resource: '../../app/*'
+# exclude: '../../app/Kernel.php}'
+# public: true
+
+ # controllers are imported separately to make sure services can be injected
+ # as action arguments even if you don't extend any base controller class
+ App\Controller\:
+ resource: '../../app/Controller'
+ tags: ['controller.service_arguments']
+
+ # add more service definitions when explicit configuration is needed
+ # please note that last definitions always *replace* previous ones