Not entirely sure what's causing the issue, especially since I've followed the official documentation. I've also read countless Google Group discussions and questions here but to no avail.
So I've been building my app on top of Fabien Potencier's Silex Skeleton, but my unit test fails on a page that has a form on it using the FormServiceProvider.
PHPUnit 3.6.12 by Sebastian Bergmann.
Configuration read from /Users/Adam/Sites/AppEngine/phpunit.xml
..E
Time: 0 seconds, Memory: 10.00Mb
There was 1 error:
1) Acme\AppEngineTest::testAppControllerForm
session_start(): Cannot send session cookie - headers already sent by (output started at /usr/local/php5-20120823-092307/lib/php/PHPUnit/Util/Printer.php:173)
I have only one test class at the moment
namespace Acme;
use Silex\WebTestCase;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
class AppEngineTest extends WebTestCase
{
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
if (! defined('BASEPATH')) {
define('BASEPATH', __DIR__.'/../..');
}
}
public function createApplication()
{
$app = require BASEPATH.'/src/app.php';
$app['debug'] = true;
$app['exception_handler']->disable();
$app['session.storage'] = $app->share(function() {
return new MockArraySessionStorage();
});
$app['session.test'] = true;
require BASEPATH.'/config/prod.php';
require BASEPATH.'/src/controllers.php';
return $app;
}
public function testIndex()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/');
$this->assertTrue($client->getResponse()->isOk());
}
public function testAppControllerIndex()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/app/');
$this->assertEquals($client->getResponse()->isOk());
$this->assertCount(1, $crawler->filter('p:contains("Please choose an app from the following")'));
}
// This test fails
public function testAppControllerForm()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/app/form');
$this->assertTrue($client->getResponse()->isOk());
}
}
PHPUnit configuration
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true"
bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<testsuites>
<testsuite name="Test Suite">
<directory>tests/Acme</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
<php>
<server name="HTTP_USER_AGENT" value="PHPUnit"/>
</php>
</phpunit>
In controllers.php, I have mounted a controller containing the form
use Acme\Controller\FacebookAppControllerProvider;
$app->mount('/app/', new FacebookAppControllerProvider());
Which looks like this
<?php
namespace Acme\Controller;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Silex\Provider\FacebookServiceProvider;
use SlotMachine\Page as PageContainer;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Yaml\Yaml;
class FacebookAppControllerProvider implements ControllerProviderInterface
{
public function connect(Application $app)
{
if (! $app['twig']->hasExtension('silex_asset_path')) {
throw new \OutOfBoundsException(
'The `silex_asset_path` Twig extension provided by this library has not been registered.'
);
}
// creates a new controller based on the default route
$controllers = $app['controllers_factory'];
$app->register(new FacebookServiceProvider(), [
'facebook.config' => [
'appId' => '1',
'secret' => '2',
'sharedSession' => true,
'trustForwarded' => true,
'fileUpload' => false
],
'facebook.permissions' => [ 'email' ],
]);
$app['facebook_app.widget_data'] = [
'foo' => [
'name' => 'Foo'
],
'bar' => [
'name' => 'Bar'
]
];
$controllers->match('/', function (Application $app) {
return $app->render("facebook_app/index.html.twig", $app['facebook_app.widget_data']);
})->method('POST|GET');
$controllers->match('/app/{widget}/{tp}', function (Request $request, Application $app, $widget, $tp) {
$slots = new PageContainer(Yaml::parse(BASEPATH.'/src/Acme/Resources/config/'.$widget.'.slots.yml'));
// some default data for when the form is displayed the first time
$formData = [
'forename' => 'First-Name',
'surname' => 'Last-Name',
'telephone' => 'Telephone',
];
$form = $app->form($formData)
->add('forename', 'text', [ 'label' => 'Name' ])
->add('surname', 'text', [ 'label' => false ])
->add('telephone')
->getForm()
; //end
if ('POST' == $request->getMethod()) {
$form->bind($request);
if ($form->isValid()) {
$data = $form->getData();
// do something with the data
// redirect somewhere
return $app->redirect('/');
}
}
$pageData = [
'slot' => $slots->all(),
'template_number' => $tp,
'widget' => [
'slug' => $widget,
'name' => $app['facebook_app.widget_data'][$widget]['name']
],
'form' => $form->createView(),
];
foreach ($pageData['slot'] as $slot => &$card) {
$card = PageContainer::interpolate($card, [
'widget_name' => $pageData['widget']['name']
]);
}
$app['page_data'] = $pageData;
return $app->render(sprintf('templates/%s/template_%d.html.twig', $widget, $tp), $app['page_data']);
})
->method('POST|GET')
->assert('tp', '\d+')
->value('tp', 1)
; // end /app/{publication}/{tp} Controller
return $controllers;
}
}
In app.php, the FormServiceProvider is registered immediately after instantiating a new Silex Application and also before adding a Twig extension.
$app['twig'] = $app->share($app->extend('twig', function($twig, $app) {
// add custom globals, filters, tags, ...
$twig->addExtension(new Acme\Twig\SilexAssetPathExtension($app));
return $twig;
}));
There is a better approach, Symfony allows you to enable a testing session mode that doesnt use the 'session_*' functionality. I am not sure exactly how to enable this in Silex, but you have to enable the mock file storage in Symfony.
storage_id: session.storage.mock_file
Documentation for Silex is here: http://silex.sensiolabs.org/doc/providers/session.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With