diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 2d2bb5abd..4c74d70f1 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
- php: [8.0]
+ php: [8.2]
steps:
- name: Checkout code
@@ -20,24 +20,22 @@ jobs:
php-version: ${{ matrix.php }}
coverage: none
- - name: Checkout Mezzio Sample
- uses: actions/checkout@v2
- with:
- repository: Naktibalda/codeception-mezzio-tests
- path: framework-tests
- ref: '5.0'
- submodules: recursive
-
- name: Install Mezzio Sample
- run: composer update --no-dev --prefer-dist --no-interaction
- working-directory: framework-tests
+ run: composer create-project mezzio/mezzio-skeleton --prefer-dist --no-interaction framework-tests
+ - name: Copy The Tests/Site
+ run: cp -rf src-test/{src,templates,test,tests,codeception.yml} framework-tests/
- - name: Validate composer.json and composer.lock
- run: composer validate
+ - name: Copy The Config
+ run: cp -f src-test/config/routes.php framework-tests/config/
- - name: Install dependencies
- run: composer update --prefer-dist --no-progress --no-interaction --no-suggest
+ - name: Remove The Default
+ run: composer remove mezzio/mezzio-fastroute
+ working-directory: framework-tests
+
+ - name: Install The Dependencies
+ run: composer require -n mezzio/mezzio-laminasrouter mezzio/mezzio-laminasviewrenderer:^2 mezzio/mezzio-session-ext -n
+ working-directory: framework-tests
- name: Run test suite
- run: php vendor/bin/codecept run functional -c framework-tests
+ run: php -d register_argc_argv=On vendor/bin/codecept run functional -c framework-tests
diff --git a/composer.json b/composer.json
index a6929bc4a..bbed0568c 100644
--- a/composer.json
+++ b/composer.json
@@ -15,9 +15,9 @@
"php": "^8.0",
"codeception/lib-innerbrowser": "^3.0 | ^4.0",
"codeception/codeception": "^5.0.8",
- "container-interop/container-interop": "^1.2",
"laminas/laminas-diactoros": "^2.0 || ^3.0",
- "mezzio/mezzio": "^3.0"
+ "mezzio/mezzio": "^3.0",
+ "psr/container": "^1|^2"
},
"require-dev": {
"codeception/module-rest": "^3.3"
diff --git a/src-test/codeception.yml b/src-test/codeception.yml
new file mode 100644
index 000000000..7f49380ed
--- /dev/null
+++ b/src-test/codeception.yml
@@ -0,0 +1,19 @@
+actor: Tester
+bootstrap: _bootstrap.php
+paths:
+ tests: tests
+ log: tests/_output
+ data: tests/_data
+ support: tests/_support
+ envs: tests/_envs
+ output: tests/_output
+settings:
+ colors: true
+ memory_limit: 1024M
+modules:
+ config:
+ Db:
+ dsn: ''
+ user: ''
+ password: ''
+ dump: tests/_data/dump.sql
diff --git a/src-test/config/routes.php b/src-test/config/routes.php
new file mode 100644
index 000000000..ad7b48c1c
--- /dev/null
+++ b/src-test/config/routes.php
@@ -0,0 +1,44 @@
+get('/', App\Handler\HomePageHandler::class, 'home');
+ * $app->post('/album', App\Handler\AlbumCreateHandler::class, 'album.create');
+ * $app->put('/album/:id', App\Handler\AlbumUpdateHandler::class, 'album.put');
+ * $app->patch('/album/:id', App\Handler\AlbumUpdateHandler::class, 'album.patch');
+ * $app->delete('/album/:id', App\Handler\AlbumDeleteHandler::class, 'album.delete');
+ *
+ * Or with multiple request methods:
+ *
+ * $app->route('/contact', App\Handler\ContactHandler::class, ['GET', 'POST', ...], 'contact');
+ *
+ * Or handling all request methods:
+ *
+ * $app->route('/contact', App\Handler\ContactHandler::class)->setName('contact');
+ *
+ * or:
+ *
+ * $app->route(
+ * '/contact',
+ * App\Handler\ContactHandler::class,
+ * Mezzio\Router\Route::HTTP_METHOD_ANY,
+ * 'contact'
+ * );
+ */
+return function (Application $app, MiddlewareFactory $factory, ContainerInterface $container) : void {
+ $app->get('/', App\Handler\HomePageHandler::class, 'home');
+ $app->get('/api/ping', App\Handler\PingHandler::class, 'api.ping');
+ $app->route('/rest', App\Handler\RestHandler::class, ['GET', 'POST', 'PUT', 'DELETE'], 'rest');
+
+ $app->get('/session/:action', [
+ Mezzio\Session\SessionMiddleware::class,
+ App\Handler\SessionHandler::class,
+ ], 'session.test');
+};
diff --git a/src-test/src/App/ConfigProvider.php b/src-test/src/App/ConfigProvider.php
new file mode 100644
index 000000000..c648cef77
--- /dev/null
+++ b/src-test/src/App/ConfigProvider.php
@@ -0,0 +1,59 @@
+ $this->getDependencies(),
+ 'templates' => $this->getTemplates(),
+ ];
+ }
+
+ /**
+ * Returns the container dependencies
+ */
+ public function getDependencies() : array
+ {
+ return [
+ 'invokables' => [
+ Handler\PingHandler::class => Handler\PingHandler::class,
+ Handler\RestHandler::class => Handler\RestHandler::class,
+ Handler\SessionHandler::class => Handler\SessionHandler::class,
+ ],
+ 'factories' => [
+ Handler\HomePageHandler::class => Handler\HomePageHandlerFactory::class,
+ ],
+ ];
+ }
+
+ /**
+ * Returns the templates configuration
+ */
+ public function getTemplates() : array
+ {
+ return [
+ 'paths' => [
+ 'app' => ['templates/app'],
+ 'error' => ['templates/error'],
+ 'layout' => ['templates/layout'],
+ ],
+ ];
+ }
+}
diff --git a/src-test/src/App/Handler/HomePageHandler.php b/src-test/src/App/Handler/HomePageHandler.php
new file mode 100644
index 000000000..4d5551256
--- /dev/null
+++ b/src-test/src/App/Handler/HomePageHandler.php
@@ -0,0 +1,102 @@
+containerName = $containerName;
+ $this->router = $router;
+ $this->template = $template;
+ }
+
+ public function handle(ServerRequestInterface $request) : ResponseInterface
+ {
+ if ($this->template === null) {
+ return new JsonResponse([
+ 'welcome' => 'Congratulations! You have installed the mezzio skeleton application.',
+ 'docsUrl' => 'https://docs.mezzio.dev/mezzio/',
+ ]);
+ }
+
+ $data = [];
+
+ switch ($this->containerName) {
+ case 'Aura\Di\Container':
+ $data['containerName'] = 'Aura.Di';
+ $data['containerDocs'] = 'http://auraphp.com/packages/2.x/Di.html';
+ break;
+ case 'Pimple\Container':
+ $data['containerName'] = 'Pimple';
+ $data['containerDocs'] = 'https://pimple.symfony.com/';
+ break;
+ case 'Laminas\ServiceManager\ServiceManager':
+ $data['containerName'] = 'Laminas Servicemanager';
+ $data['containerDocs'] = 'https://docs.laminas.dev/laminas-servicemanager/';
+ break;
+ case 'Auryn\Injector':
+ $data['containerName'] = 'Auryn';
+ $data['containerDocs'] = 'https://github.com/rdlowrey/Auryn';
+ break;
+ case 'Symfony\Component\DependencyInjection\ContainerBuilder':
+ $data['containerName'] = 'Symfony DI Container';
+ $data['containerDocs'] = 'https://symfony.com/doc/current/service_container.html';
+ break;
+ case 'Zend\DI\Config\ContainerWrapper':
+ case 'DI\Container':
+ $data['containerName'] = 'PHP-DI';
+ $data['containerDocs'] = 'http://php-di.org';
+ break;
+ }
+
+ if ($this->router instanceof Router\AuraRouter) {
+ $data['routerName'] = 'Aura.Router';
+ $data['routerDocs'] = 'http://auraphp.com/packages/2.x/Router.html';
+ } elseif ($this->router instanceof Router\FastRouteRouter) {
+ $data['routerName'] = 'FastRoute';
+ $data['routerDocs'] = 'https://github.com/nikic/FastRoute';
+ } elseif ($this->router instanceof Router\LaminasRouter) {
+ $data['routerName'] = 'Laminas Router';
+ $data['routerDocs'] = 'https://docs.laminas.dev/laminas-router/';
+ }
+
+ if ($this->template instanceof PlatesRenderer) {
+ $data['templateName'] = 'Plates';
+ $data['templateDocs'] = 'http://platesphp.com/';
+ } elseif ($this->template instanceof TwigRenderer) {
+ $data['templateName'] = 'Twig';
+ $data['templateDocs'] = 'http://twig.sensiolabs.org/documentation';
+ } elseif ($this->template instanceof LaminasViewRenderer) {
+ $data['templateName'] = 'Laminas View';
+ $data['templateDocs'] = 'https://docs.laminas.dev/laminas-view/';
+ }
+
+ return new HtmlResponse($this->template->render('app::home-page', $data));
+ }
+}
diff --git a/src-test/src/App/Handler/HomePageHandlerFactory.php b/src-test/src/App/Handler/HomePageHandlerFactory.php
new file mode 100644
index 000000000..af9a98928
--- /dev/null
+++ b/src-test/src/App/Handler/HomePageHandlerFactory.php
@@ -0,0 +1,27 @@
+get(RouterInterface::class);
+ $template = $container->has(TemplateRendererInterface::class)
+ ? $container->get(TemplateRendererInterface::class)
+ : ($container->has(\Zend\Expressive\Template\TemplateRendererInterface::class)
+ ? $container->get(\Zend\Expressive\Template\TemplateRendererInterface::class)
+ : null);
+
+ return new HomePageHandler(get_class($container), $router, $template);
+ }
+}
diff --git a/src-test/src/App/Handler/PingHandler.php b/src-test/src/App/Handler/PingHandler.php
new file mode 100644
index 000000000..3fc16259d
--- /dev/null
+++ b/src-test/src/App/Handler/PingHandler.php
@@ -0,0 +1,20 @@
+ time()]);
+ }
+}
diff --git a/src-test/src/App/Handler/RestHandler.php b/src-test/src/App/Handler/RestHandler.php
new file mode 100644
index 000000000..b2471166c
--- /dev/null
+++ b/src-test/src/App/Handler/RestHandler.php
@@ -0,0 +1,58 @@
+getHeader('X-Auth-Token');
+ if (count($tokenHeader) > 0) {
+ $tokenHeaderValue = $tokenHeader[0];
+ } else {
+ $tokenHeaderValue = null;
+ }
+ $data = array(
+ 'requestMethod' => $request->getMethod(),
+ 'requestUri' => $request->getRequestTarget(),
+ 'queryParams' => $request->getQueryParams(),
+ 'formParams' => $request->getParsedBody(),
+ 'rawBody' => (string)$request->getBody(),
+ 'headers' => $request->getHeaders(),
+ 'X-Auth-Token' => $tokenHeaderValue,
+ 'files' => $this->filesToArray($request->getUploadedFiles()),
+ );
+ return new JsonResponse($data);
+ }
+
+ private function filesToArray(array $files)
+ {
+ $result = [];
+ foreach ($files as $fieldName => $uploadedFile) {
+ /**
+ * @var $uploadedFile UploadedFile|array
+ */
+ if (is_array($uploadedFile)) {
+ $result[$fieldName] = $this->filesToArray($uploadedFile);
+ } else {
+ $result[$fieldName] = [
+ 'name' => $uploadedFile->getClientFilename(),
+ 'tmp_name' => ReflectionHelper::readPrivateProperty($uploadedFile, 'file'),
+ 'size' => $uploadedFile->getSize(),
+ 'type' => $uploadedFile->getClientMediaType(),
+ 'error' => $uploadedFile->getError(),
+ ];
+ }
+ }
+ return $result;
+ }
+}
diff --git a/src-test/src/App/Handler/SessionHandler.php b/src-test/src/App/Handler/SessionHandler.php
new file mode 100644
index 000000000..5e861dfce
--- /dev/null
+++ b/src-test/src/App/Handler/SessionHandler.php
@@ -0,0 +1,37 @@
+getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
+
+ $action = $request->getAttribute('action');
+ if ('set' === $action) {
+ $session->set('name', 'Somebody');
+
+ return new TextResponse('Name set');
+ }
+
+ if ('get' === $action) {
+ $name = $session->get('name', 'Nobody');
+
+ return new TextResponse(sprintf('The name is: %s', $name));
+ }
+
+ return new EmptyResponse();
+ }
+}
diff --git a/src-test/templates/app/home-page.phtml b/src-test/templates/app/home-page.phtml
new file mode 100644
index 000000000..2d9a728ef
--- /dev/null
+++ b/src-test/templates/app/home-page.phtml
@@ -0,0 +1,116 @@
+headTitle('Home'); ?>
+
+
+
Welcome to mezzio
+
+ Congratulations! You have successfully installed the
+ mezzio skeleton application .
+ This skeleton can serve as a simple starting point for you to begin building your application.
+
+
+ Mezzio builds on laminas-stratigility to provide a minimalist PSR-7 middleware framework for PHP.
+
+
+
+
+
+
+
+ Mezzio is fast, small and perfect for rapid application development, prototyping and api's.
+ You decide how you extend it and choose the best packages from major framework or standalone projects.
+
+
+
+
+
+
+ HTTP messages are the foundation of web development. Web browsers and HTTP clients such as cURL create
+ HTTP request messages that are sent to a web server, which provides an HTTP response message.
+ Server-side code receives an HTTP request message, and returns an HTTP response message.
+
+
+
+
+
+
+ Middleware is code that exists between the request and response, and which can take the incoming
+ request, perform actions based on it, and either complete the response or pass delegation on to the
+ next middleware in the queue. Your application is easily extended with custom middleware created by
+ yourself or others .
+
+
+
+
+
+
+
+
+
+
+ One fundamental feature of mezzio is that it provides mechanisms for implementing dynamic
+ routing, a feature required in most modern web applications. Mezzio ships with multiple adapters.
+
+ routerName)) : ?>
+
+
+ Get started with = $this->routerName ?>.
+
+
+
+
+
+
+
+
+ By default, no middleware in Mezzio is templated. We do not even provide a default templating
+ engine, as the choice of templating engine is often very specific to the project and/or organization.
+ However, Mezzio does provide abstraction for templating, which allows you to write middleware that
+ is engine-agnostic.
+
+ templateName)) : ?>
+
+
+ Get started with = $this->templateName ?>.
+
+
+
+
+
diff --git a/src-test/templates/error/404.phtml b/src-test/templates/error/404.phtml
new file mode 100644
index 000000000..93a855780
--- /dev/null
+++ b/src-test/templates/error/404.phtml
@@ -0,0 +1,9 @@
+headTitle('404 Not Found'); ?>
+
+Oops!
+This is awkward.
+We encountered a 404 Not Found error.
+
+ You are looking for something that doesn't exist or may have moved. Check out one of the links on this page
+ or head back to Home .
+
diff --git a/src-test/templates/error/error.phtml b/src-test/templates/error/error.phtml
new file mode 100644
index 000000000..5f2995120
--- /dev/null
+++ b/src-test/templates/error/error.phtml
@@ -0,0 +1,11 @@
+headTitle(sprintf('%d %s', $this->status, $this->reason)); ?>
+
+Oops!
+This is awkward.
+We encountered a =$this->escapeHtml(sprintf('%d %s', $this->status, $this->reason))?> error.
+status == 404) : ?>
+
+ You are looking for something that doesn't exist or may have moved. Check out one of the links on this page
+ or head back to Home .
+
+
diff --git a/src-test/templates/layout/default.phtml b/src-test/templates/layout/default.phtml
new file mode 100644
index 000000000..a225b31b4
--- /dev/null
+++ b/src-test/templates/layout/default.phtml
@@ -0,0 +1,80 @@
+headLink()
+ ->prependStylesheet('https://use.fontawesome.com/releases/v5.0.6/css/all.css')
+ ->prependStylesheet('https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css');
+$this->inlineScript()
+ ->prependFile('https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js')
+ ->prependFile('https://code.jquery.com/jquery-3.3.1.min.js');
+?>
+
+
+
+
+
+
+
+ =$this->headTitle('mezzio')->setSeparator(' - ')->setAutoEscape(false)?>
+ =$this->headMeta()?>
+ =$this->headLink()?>
+
+
+
+
+
+
+
+ =$this->content?>
+
+
+
+
+
+ =$this->inlineScript()?>
+
+
diff --git a/src-test/test/AppTest/Handler/HomePageHandlerFactoryTest.php b/src-test/test/AppTest/Handler/HomePageHandlerFactoryTest.php
new file mode 100644
index 000000000..5e0cbd086
--- /dev/null
+++ b/src-test/test/AppTest/Handler/HomePageHandlerFactoryTest.php
@@ -0,0 +1,54 @@
+container = $this->prophesize(ContainerInterface::class);
+ $router = $this->prophesize(RouterInterface::class);
+
+ $this->container->get(RouterInterface::class)->willReturn($router);
+ }
+
+ public function testFactoryWithoutTemplate()
+ {
+ $factory = new HomePageHandlerFactory();
+ $this->container->has(TemplateRendererInterface::class)->willReturn(false);
+ $this->container->has(\Zend\Expressive\Template\TemplateRendererInterface::class)->willReturn(false);
+
+ $this->assertInstanceOf(HomePageHandlerFactory::class, $factory);
+
+ $homePage = $factory($this->container->reveal());
+
+ $this->assertInstanceOf(HomePageHandler::class, $homePage);
+ }
+
+ public function testFactoryWithTemplate()
+ {
+ $this->container->has(TemplateRendererInterface::class)->willReturn(true);
+ $this->container
+ ->get(TemplateRendererInterface::class)
+ ->willReturn($this->prophesize(TemplateRendererInterface::class));
+
+ $factory = new HomePageHandlerFactory();
+
+ $homePage = $factory($this->container->reveal());
+
+ $this->assertInstanceOf(HomePageHandler::class, $homePage);
+ }
+}
diff --git a/src-test/test/AppTest/Handler/HomePageHandlerTest.php b/src-test/test/AppTest/Handler/HomePageHandlerTest.php
new file mode 100644
index 000000000..27b0a2c6a
--- /dev/null
+++ b/src-test/test/AppTest/Handler/HomePageHandlerTest.php
@@ -0,0 +1,65 @@
+container = $this->prophesize(ContainerInterface::class);
+ $this->router = $this->prophesize(RouterInterface::class);
+ }
+
+ public function testReturnsJsonResponseWhenNoTemplateRendererProvided()
+ {
+ $homePage = new HomePageHandler(
+ get_class($this->container->reveal()),
+ $this->router->reveal(),
+ null
+ );
+ $response = $homePage->handle(
+ $this->prophesize(ServerRequestInterface::class)->reveal()
+ );
+
+ $this->assertInstanceOf(JsonResponse::class, $response);
+ }
+
+ public function testReturnsHtmlResponseWhenTemplateRendererProvided()
+ {
+ $renderer = $this->prophesize(TemplateRendererInterface::class);
+ $renderer
+ ->render('app::home-page', Argument::type('array'))
+ ->willReturn('');
+
+ $homePage = new HomePageHandler(
+ get_class($this->container->reveal()),
+ $this->router->reveal(),
+ $renderer->reveal()
+ );
+
+ $response = $homePage->handle(
+ $this->prophesize(ServerRequestInterface::class)->reveal()
+ );
+
+ $this->assertInstanceOf(HtmlResponse::class, $response);
+ }
+}
diff --git a/src-test/test/AppTest/Handler/PingHandlerTest.php b/src-test/test/AppTest/Handler/PingHandlerTest.php
new file mode 100644
index 000000000..83d3aae25
--- /dev/null
+++ b/src-test/test/AppTest/Handler/PingHandlerTest.php
@@ -0,0 +1,26 @@
+handle(
+ $this->prophesize(ServerRequestInterface::class)->reveal()
+ );
+
+ $json = json_decode((string) $response->getBody());
+
+ $this->assertInstanceOf(JsonResponse::class, $response);
+ $this->assertTrue(isset($json->ack));
+ }
+}
diff --git a/src-test/tests/_bootstrap.php b/src-test/tests/_bootstrap.php
new file mode 100644
index 000000000..b74d4c0df
--- /dev/null
+++ b/src-test/tests/_bootstrap.php
@@ -0,0 +1,4 @@
+wantTo('click a link and see a change in url');
+
+$I->amOnPage('/');
+$I->click('Ping Test');
+$I->seeCurrentUrlEquals('/api/ping');
+$I->see("ack");
diff --git a/src-test/tests/functional/FileUploadWithObjectCept.php b/src-test/tests/functional/FileUploadWithObjectCept.php
new file mode 100644
index 000000000..3770a6446
--- /dev/null
+++ b/src-test/tests/functional/FileUploadWithObjectCept.php
@@ -0,0 +1,14 @@
+wantTo('upload file');
+
+$I->sendPOST('/rest', [], [
+ 'dump' => new Laminas\Diactoros\UploadedFile(codecept_data_dir('dump.sql'), 57, 0, 'dump.sql', 'text/plain')
+]);
+$I->seeResponseIsJson();
+$I->seeResponseContainsJson(['files' => [
+ 'dump' => [
+ 'name' => 'dump.sql',
+ 'size' => 57,
+ ]
+]]);
diff --git a/src-test/tests/functional/SeeCept.php b/src-test/tests/functional/SeeCept.php
new file mode 100644
index 000000000..299144689
--- /dev/null
+++ b/src-test/tests/functional/SeeCept.php
@@ -0,0 +1,7 @@
+wantTo('perform request and match text in response');
+
+$I->amOnPage('/');
+$I->seeResponseCodeIs(200);
+$I->see('HTTP messages are the foundation of web development.');
diff --git a/src-test/tests/functional/SeeResponseCodeIsCept.php b/src-test/tests/functional/SeeResponseCodeIsCept.php
new file mode 100644
index 000000000..21b21620b
--- /dev/null
+++ b/src-test/tests/functional/SeeResponseCodeIsCept.php
@@ -0,0 +1,6 @@
+wantTo('see different response code');
+
+$I->amOnPage('/error');
+$I->seeResponseCodeIs(404);
diff --git a/src-test/tests/functional/SessionCest.php b/src-test/tests/functional/SessionCest.php
new file mode 100644
index 000000000..47d9a0522
--- /dev/null
+++ b/src-test/tests/functional/SessionCest.php
@@ -0,0 +1,22 @@
+amOnPage('/session/get');
+ $I->see('Nobody');
+
+ $I->amOnPage('/session/set');
+ $I->see('Name set');
+
+ $I->amOnPage('/session/get');
+ $I->see('Somebody');
+ }
+
+ public function secondTimeUsingSessionMustNotBeAffectedByFirstTime(FunctionalTester $I)
+ {
+ $I->amOnPage('/session/get');
+ $I->see('Nobody');
+ }
+}
diff --git a/src-test/tests/functional/_bootstrap.php b/src-test/tests/functional/_bootstrap.php
new file mode 100644
index 000000000..8a8855580
--- /dev/null
+++ b/src-test/tests/functional/_bootstrap.php
@@ -0,0 +1,2 @@
+wantTo('click a link and see a change in url');
+
+$I->amOnPage('/');
+$I->click('Ping Test');
+$I->seeCurrentUrlEquals('/api/ping');
+$I->see("ack");
diff --git a/tests/functional/FileUploadWithObjectCept.php b/tests/functional/FileUploadWithObjectCept.php
new file mode 100644
index 000000000..76854610c
--- /dev/null
+++ b/tests/functional/FileUploadWithObjectCept.php
@@ -0,0 +1,17 @@
+wantTo('upload file');
+
+$I->sendPOST('/rest', [], [
+ 'dump' => new Laminas\Diactoros\UploadedFile(codecept_data_dir('dump.sql'), 57, 0, 'dump.sql', 'text/plain')
+]);
+$I->seeResponseIsJson();
+$I->seeResponseContainsJson(['files' => [
+ 'dump' => [
+ 'name' => 'dump.sql',
+ 'size' => 57,
+ ]
+]]);
diff --git a/tests/functional/REST/DeleteMethodCept.php b/tests/functional/REST/DeleteMethodCept.php
new file mode 100644
index 000000000..bd297778b
--- /dev/null
+++ b/tests/functional/REST/DeleteMethodCept.php
@@ -0,0 +1,7 @@
+wantTo('make DELETE request');
+
+$I->sendDELETE('/rest');
+$I->seeResponseIsJson();
+$I->seeResponseContainsJson(array('requestMethod' => 'DELETE'));
diff --git a/tests/functional/REST/DeleteMethodWithQueryStringCept.php b/tests/functional/REST/DeleteMethodWithQueryStringCept.php
new file mode 100644
index 000000000..a2e6f570b
--- /dev/null
+++ b/tests/functional/REST/DeleteMethodWithQueryStringCept.php
@@ -0,0 +1,12 @@
+wantTo('make DELETE request with query string');
+$I->sendDELETE('/rest?param=value');
+
+$expectedResponse = array(
+ 'requestMethod' => 'DELETE',
+ 'queryParams' => array(
+ 'param' => 'value'
+ ),
+);
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/REST/GetMethodCept.php b/tests/functional/REST/GetMethodCept.php
new file mode 100644
index 000000000..6832b8885
--- /dev/null
+++ b/tests/functional/REST/GetMethodCept.php
@@ -0,0 +1,9 @@
+wantTo('make GET request');
+$I->sendGET('/rest');
+$I->seeResponseIsJson();
+$expectedResponse = array(
+ 'requestMethod' => 'GET',
+);
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/REST/GetMethodWithParamsCept.php b/tests/functional/REST/GetMethodWithParamsCept.php
new file mode 100644
index 000000000..a141e0273
--- /dev/null
+++ b/tests/functional/REST/GetMethodWithParamsCept.php
@@ -0,0 +1,13 @@
+wantTo('make GET request with parameters');
+$I->sendGET('/rest',['param' => 'value']);
+$I->seeResponseIsJson();
+
+$expectedResponse = array(
+ 'requestMethod' => 'GET',
+ 'queryParams' => array(
+ 'param' => 'value'
+ ),
+);
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/REST/GetMethodWithQueryStringAndParamsCept.php b/tests/functional/REST/GetMethodWithQueryStringAndParamsCept.php
new file mode 100644
index 000000000..122eebc77
--- /dev/null
+++ b/tests/functional/REST/GetMethodWithQueryStringAndParamsCept.php
@@ -0,0 +1,15 @@
+wantTo('make GET request with query string');
+$I->sendGET('/rest?param1=value1', ['param2' => 'value2']);
+$I->seeResponseIsJson();
+
+$expectedResponse = [
+ 'requestMethod' => 'GET',
+ 'requestUri' => '/rest?param1=value1¶m2=value2',
+ 'queryParams' => [
+ 'param1' => 'value1',
+ 'param2' => 'value2',
+ ],
+];
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/REST/GetMethodWithQueryStringCept.php b/tests/functional/REST/GetMethodWithQueryStringCept.php
new file mode 100644
index 000000000..2af31b898
--- /dev/null
+++ b/tests/functional/REST/GetMethodWithQueryStringCept.php
@@ -0,0 +1,13 @@
+wantTo('make GET request with query string');
+$I->sendGET('/rest?param=value');
+$I->seeResponseIsJson();
+
+$expectedResponse = array(
+ 'requestMethod' => 'GET',
+ 'queryParams' => array(
+ 'param' => 'value'
+ ),
+);
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/REST/GetMethodWithRequestHeaderCept.php b/tests/functional/REST/GetMethodWithRequestHeaderCept.php
new file mode 100644
index 000000000..4d6cd3645
--- /dev/null
+++ b/tests/functional/REST/GetMethodWithRequestHeaderCept.php
@@ -0,0 +1,12 @@
+wantTo('make GET request with custom request header');
+$I->haveHttpHeader('X-Auth-Token', 'verySecureToken');
+$I->sendGET('/rest');
+
+$expectedResponse = array(
+ 'requestMethod' => 'GET',
+ 'queryParams' => array(),
+ 'X-Auth-Token' => 'verySecureToken',
+);
+$I->seeResponseContainsJson($expectedResponse);
\ No newline at end of file
diff --git a/tests/functional/REST/PostMethodCept.php b/tests/functional/REST/PostMethodCept.php
new file mode 100644
index 000000000..7c4f0e8e0
--- /dev/null
+++ b/tests/functional/REST/PostMethodCept.php
@@ -0,0 +1,7 @@
+wantTo('make POST request');
+
+$I->sendPOST('/rest');
+$I->seeResponseIsJson();
+$I->seeResponseContainsJson(array('requestMethod' => 'POST'));
diff --git a/tests/functional/REST/PostMethodFileArrayUploadCept.php b/tests/functional/REST/PostMethodFileArrayUploadCept.php
new file mode 100644
index 000000000..6b27c002f
--- /dev/null
+++ b/tests/functional/REST/PostMethodFileArrayUploadCept.php
@@ -0,0 +1,34 @@
+wantTo('upload file');
+
+$I->sendPOST('/rest', [], ['dump' => [
+ [
+ 'name' => 'dump1.sql',
+ 'type' => 'text/plain',
+ 'size' => 57,
+ 'tmp_name' => codecept_data_dir('dump.sql'),
+ 'error' => 0,
+ ],
+ [
+ 'name' => 'dump2.sql',
+ 'type' => 'text/sql',
+ 'size' => 60,
+ 'tmp_name' => codecept_data_dir('dump.sql'),
+ 'error' => 0,
+ ],
+ ]
+]);
+$I->seeResponseIsJson();
+$I->seeResponseContainsJson(['files' => [
+ 'dump' => [
+ [
+ 'name' => 'dump1.sql',
+ 'size' => 57,
+ ],
+ [
+ 'name' => 'dump2.sql',
+ 'size' => 60,
+ ]
+ ]
+]]);
diff --git a/tests/functional/REST/PostMethodFileUploadCept.php b/tests/functional/REST/PostMethodFileUploadCept.php
new file mode 100644
index 000000000..e7c4ec51f
--- /dev/null
+++ b/tests/functional/REST/PostMethodFileUploadCept.php
@@ -0,0 +1,19 @@
+wantTo('upload file');
+
+$I->sendPOST('/rest', [], ['dump' => [
+ 'name' => 'dump.sql',
+ 'type' => 'text/plain',
+ 'size' => 57,
+ 'tmp_name' => codecept_data_dir('dump.sql'),
+ 'error' => 0,
+ ],
+]);
+$I->seeResponseIsJson();
+$I->seeResponseContainsJson(['files' => [
+ 'dump' => [
+ 'name' => 'dump.sql',
+ 'size' => 57,
+ ]
+]]);
diff --git a/tests/functional/REST/PostMethodFileUploadWithKeyValueArrayCept.php b/tests/functional/REST/PostMethodFileUploadWithKeyValueArrayCept.php
new file mode 100644
index 000000000..b5302069c
--- /dev/null
+++ b/tests/functional/REST/PostMethodFileUploadWithKeyValueArrayCept.php
@@ -0,0 +1,17 @@
+wantTo('upload file using simple key-value array');
+
+$uploadFile = codecept_data_dir('dump.sql');
+
+$I->sendPOST('/rest', [], ['dump' => $uploadFile]);
+$I->seeResponseIsJson();
+$I->seeResponseContainsJson(['files' => [
+ 'dump' => [
+ 'name' => 'dump.sql',
+ 'tmp_name' => $uploadFile,
+ 'type' => 'text/plain',
+ 'size' => 57,
+ 'error' => 0,
+ ]
+]]);
diff --git a/tests/functional/REST/PostMethodFileUploadWithKeyValueInNestedArrayCept.php b/tests/functional/REST/PostMethodFileUploadWithKeyValueInNestedArrayCept.php
new file mode 100644
index 000000000..be9213969
--- /dev/null
+++ b/tests/functional/REST/PostMethodFileUploadWithKeyValueInNestedArrayCept.php
@@ -0,0 +1,47 @@
+wantTo('upload file using simple key-value array');
+
+$uploadFile = codecept_data_dir('dump.sql');
+
+$I->sendPOST('/rest', [], [
+ 'dump1' => $uploadFile,
+ 'nested' => [
+ 'dump2' => $uploadFile,
+ ],
+ 'nested1' => [
+ 'nested2' => [
+ 'dump3' => $uploadFile,
+ ]
+ ],
+]);
+$I->seeResponseIsJson();
+$I->seeResponseContainsJson(['files' => [
+ 'dump1' => [
+ 'name' => 'dump.sql',
+ 'tmp_name' => $uploadFile,
+ 'type' => 'text/plain',
+ 'size' => 57,
+ 'error' => 0,
+ ],
+ 'nested' => [
+ 'dump2' => [
+ 'name' => 'dump.sql',
+ 'tmp_name' => $uploadFile,
+ 'type' => 'text/plain',
+ 'size' => 57,
+ 'error' => 0,
+ ],
+ ],
+ 'nested1' => [
+ 'nested2' => [
+ 'dump3' => [
+ 'name' => 'dump.sql',
+ 'tmp_name' => $uploadFile,
+ 'type' => 'text/plain',
+ 'size' => 57,
+ 'error' => 0,
+ ],
+ ],
+ ],
+]]);
diff --git a/tests/functional/REST/PostMethodWithFormDataCept.php b/tests/functional/REST/PostMethodWithFormDataCept.php
new file mode 100644
index 000000000..4c698a803
--- /dev/null
+++ b/tests/functional/REST/PostMethodWithFormDataCept.php
@@ -0,0 +1,12 @@
+wantTo('make POST request with form data');
+$I->sendPOST('/rest', array('foo' => 'bar'));
+
+$expectedResponse = array(
+ 'requestMethod' => 'POST',
+ 'formParams' => array(
+ 'foo' => 'bar'
+ ),
+);
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/REST/PostMethodWithQueryStringCept.php b/tests/functional/REST/PostMethodWithQueryStringCept.php
new file mode 100644
index 000000000..2012b996d
--- /dev/null
+++ b/tests/functional/REST/PostMethodWithQueryStringCept.php
@@ -0,0 +1,12 @@
+wantTo('make POST request with query string');
+$I->sendPOST('/rest?param=value');
+
+$expectedResponse = array(
+ 'requestMethod' => 'POST',
+ 'queryParams' => array(
+ 'param' => 'value'
+ ),
+);
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/REST/PostMethodWithRawBodyCept.php b/tests/functional/REST/PostMethodWithRawBodyCept.php
new file mode 100644
index 000000000..f5e7e535f
--- /dev/null
+++ b/tests/functional/REST/PostMethodWithRawBodyCept.php
@@ -0,0 +1,11 @@
+wantTo('make POST request with raw body');
+$I->sendPOST('/rest', 'raw request body');
+
+$expectedResponse = array(
+ 'requestMethod' => 'POST',
+ 'formParams' => array(),
+ 'rawBody' => 'raw request body',
+);
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/REST/PutMethodCept.php b/tests/functional/REST/PutMethodCept.php
new file mode 100644
index 000000000..c9ad65c3b
--- /dev/null
+++ b/tests/functional/REST/PutMethodCept.php
@@ -0,0 +1,7 @@
+wantTo('make PUT request');
+
+$I->sendPUT('/rest');
+$I->seeResponseIsJson();
+$I->seeResponseContainsJson(array('requestMethod' => 'PUT'));
diff --git a/tests/functional/REST/PutMethodWithQueryStringCept.php b/tests/functional/REST/PutMethodWithQueryStringCept.php
new file mode 100644
index 000000000..ec7a423fc
--- /dev/null
+++ b/tests/functional/REST/PutMethodWithQueryStringCept.php
@@ -0,0 +1,12 @@
+wantTo('make PUT request with query string');
+$I->sendPUT('/rest?param=value');
+
+$expectedResponse = array(
+ 'requestMethod' => 'PUT',
+ 'queryParams' => array(
+ 'param' => 'value'
+ ),
+);
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/REST/PutMethodWithRawBodyCept.php b/tests/functional/REST/PutMethodWithRawBodyCept.php
new file mode 100644
index 000000000..9446220e6
--- /dev/null
+++ b/tests/functional/REST/PutMethodWithRawBodyCept.php
@@ -0,0 +1,11 @@
+wantTo('make PUT request with raw body');
+$I->sendPUT('/rest', 'raw request body');
+
+$expectedResponse = array(
+ 'requestMethod' => 'PUT',
+ 'formParams' => array(),
+ 'rawBody' => 'raw request body',
+);
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/REST/RequestUriCept.php b/tests/functional/REST/RequestUriCept.php
new file mode 100644
index 000000000..42fe531ad
--- /dev/null
+++ b/tests/functional/REST/RequestUriCept.php
@@ -0,0 +1,9 @@
+wantTo('pass request uri');
+$I->sendGET('/rest?param=value¶m2=value2');
+$I->seeResponseIsJson();
+$expectedResponse = array(
+ 'requestUri' => '/rest?param=value¶m2=value2',
+);
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/REST/SecondRequestSeesNoLeftoversFromTheFirstRequestCept.php b/tests/functional/REST/SecondRequestSeesNoLeftoversFromTheFirstRequestCept.php
new file mode 100644
index 000000000..23a540bd5
--- /dev/null
+++ b/tests/functional/REST/SecondRequestSeesNoLeftoversFromTheFirstRequestCept.php
@@ -0,0 +1,30 @@
+wantTo('ensure that request object is reset between requests');
+
+//$I->haveHttpHeader('X-Auth-Token', 'verySecureToken');
+$I->sendPOST('/rest?queryParam=1', ['foo' => 'bar']);
+
+$expectedResponse = array(
+ 'requestMethod' => 'POST',
+ 'requestUri' => '/rest?queryParam=1',
+ 'queryParams' => ['queryParam' => '1'],
+ 'formParams' => ['foo' => 'bar'],
+// 'X-Auth-Token' => 'verySecureToken',
+
+);
+$I->seeResponseContainsJson($expectedResponse);
+
+//$I->haveHttpHeader('X-Auth-Token', null );
+$I->sendGET('/rest');
+$I->seeResponseIsJson();
+$expectedResponse = array(
+ 'requestMethod' => 'GET',
+ 'requestUri' => '/rest',
+ 'queryParams' => [],
+ 'formParams' => [],
+// 'X-Auth-Token' => null,
+
+);
+
+$I->seeResponseContainsJson($expectedResponse);
diff --git a/tests/functional/SeeCept.php b/tests/functional/SeeCept.php
new file mode 100644
index 000000000..13a6d957d
--- /dev/null
+++ b/tests/functional/SeeCept.php
@@ -0,0 +1,10 @@
+wantTo('perform request and match text in response');
+
+$I->amOnPage('/');
+$I->seeResponseCodeIs(200);
+$I->see('HTTP messages are the foundation of web development.');
diff --git a/tests/functional/SeeResponseCodeIsCept.php b/tests/functional/SeeResponseCodeIsCept.php
new file mode 100644
index 000000000..3dea43074
--- /dev/null
+++ b/tests/functional/SeeResponseCodeIsCept.php
@@ -0,0 +1,9 @@
+wantTo('see different response code');
+
+$I->amOnPage('/error');
+$I->seeResponseCodeIs(404);
diff --git a/tests/functional/_bootstrap.php b/tests/functional/_bootstrap.php
new file mode 100644
index 000000000..8a8855580
--- /dev/null
+++ b/tests/functional/_bootstrap.php
@@ -0,0 +1,2 @@
+