diff --git a/README.md b/README.md index 23de4e8..2ccaa0e 100644 --- a/README.md +++ b/README.md @@ -50,3 +50,21 @@ $ composer serve ``` You can then browse to http://localhost:8080. + +## Skeleton Development + +This section applies only if you cloned this repo with ``git clone``, not when you installed expressive with +``composer create-project ...``. + +If you want to run tests against the installer, you need to clone this repo and setup all dependencies with composer. +Make sure you **prevent composer running scripts** with ``--no-scripts``, otherwise it will remove the installer and +all tests. + +```bash +$ composer install --no-scripts +$ vendor/bin/phpunit +``` + +Please note that the installer tests remove installed config files and templates before and after running the tests. + +Before contributing read [this](CONTRIBUTING.md). diff --git a/composer.json b/composer.json index 3d49be9..93f9d41 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "authors": [ { "name": "Geert Eltink", - "homepage": "https://xtreamwayz.github.io/" + "homepage": "https://xtreamwayz.com/" } ], "extra": { @@ -23,9 +23,20 @@ "zendframework/zend-stdlib": "~2.7" }, "require-dev": { - "composer/composer": ">=1.0.0-alpha10", "phpunit/phpunit": "^4.8", - "squizlabs/php_codesniffer": "^2.3" + "squizlabs/php_codesniffer": "^2.3", + "filp/whoops": "^1.1", + "composer/composer": ">=1.0.0-alpha11", + "zendframework/zend-expressive-aurarouter": "^1.0", + "zendframework/zend-expressive-fastroute": "^1.0", + "zendframework/zend-expressive-zendrouter": "^1.0", + "zendframework/zend-expressive-platesrenderer": "^1.0", + "zendframework/zend-expressive-twigrenderer": "^1.0", + "zendframework/zend-expressive-zendviewrenderer": "^1.0", + "zendframework/zend-servicemanager": "^2.5", + "ocramius/proxy-manager": "^1.0", + "aura/di": "3.0.*@beta", + "mouf/pimple-interop": "^1.0" }, "autoload": { "psr-4": { @@ -35,7 +46,8 @@ }, "autoload-dev": { "psr-4": { - "AppTest\\": "test/AppTest/" + "AppTest\\": "test/AppTest/", + "ExpressiveInstallerTest\\": "test/ExpressiveInstallerTest/" } }, "scripts": { diff --git a/src/ExpressiveInstaller/OptionalPackages.php b/src/ExpressiveInstaller/OptionalPackages.php index b7da1e3..0bff610 100644 --- a/src/ExpressiveInstaller/OptionalPackages.php +++ b/src/ExpressiveInstaller/OptionalPackages.php @@ -42,27 +42,27 @@ class OptionalPackages /** * @var array */ - private static $config; + public static $config; /** * @var array */ - private static $composerDefinition; + public static $composerDefinition; /** * @var string[] */ - private static $composerRequires; + public static $composerRequires; /** * @var string[] */ - private static $composerDevRequires; + public static $composerDevRequires; /** * @var string[] */ - private static $stabilityFlags; + public static $stabilityFlags; /** * Install command: choose packages and provide configuration. @@ -162,8 +162,19 @@ public static function install(Event $event) // House keeping $io->write("Remove installer"); - // Remove composer source + // Remove test dependencies unset(self::$composerDefinition['require-dev']['composer/composer']); + unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-aurarouter']); + unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-fastroute']); + unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-zendrouter']); + unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-platesrenderer']); + unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-twigrenderer']); + unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-zendviewrenderer']); + unset(self::$composerDefinition['require-dev']['zendframework/zend-servicemanager']); + unset(self::$composerDefinition['require-dev']['ocramius/proxy-manager']); + unset(self::$composerDefinition['require-dev']['aura/di']); + unset(self::$composerDefinition['require-dev']['mouf/pimple-interop']); + unset(self::$composerDefinition['autoload-dev']['psr-4']['ExpressiveInstallerTest\\']); // Remove installer data unset(self::$composerDefinition['extra']['optional-packages']); @@ -189,7 +200,7 @@ public static function install(Event $event) self::removeDefaultMiddleware($io, $projectRoot); } - self::cleanUp($io); + self::cleanUp($io, $projectRoot); } /** @@ -199,11 +210,13 @@ public static function install(Event $event) * this one) and assets (including configuration and templates). * * @param IOInterface $io + * @param string $projectRoot */ - private static function cleanUp(IOInterface $io) + private static function cleanUp(IOInterface $io, $projectRoot) { - $io->write("Removing Expressive installer classes and configuration"); + $io->write("Removing Expressive installer classes, configuration, and tests"); self::recursiveRmdir(__DIR__); + self::recursiveRmdir($projectRoot . '/test/ExpressiveInstallerTest'); } /** @@ -288,7 +301,7 @@ private static function askQuestion(Composer $composer, IOInterface $io, $questi * @param $packageName * @param $packageVersion */ - private static function addPackage(IOInterface $io, $packageName, $packageVersion) + public static function addPackage(IOInterface $io, $packageName, $packageVersion) { $io->write(sprintf( " - Adding package %s (%s)", @@ -340,7 +353,7 @@ private static function addPackage(IOInterface $io, $packageName, $packageVersio * @param string $target Destination. * @param bool $force whether or not to copy over an existing file. */ - private static function copyFile(IOInterface $io, $projectRoot, $source, $target, $force = false) + public static function copyFile(IOInterface $io, $projectRoot, $source, $target, $force = false) { // Copy file if ($force === false && is_file($projectRoot . $target)) { diff --git a/test/ExpressiveInstallerTest/ContainersTest.php b/test/ExpressiveInstallerTest/ContainersTest.php new file mode 100644 index 0000000..20a7bd8 --- /dev/null +++ b/test/ExpressiveInstallerTest/ContainersTest.php @@ -0,0 +1,65 @@ +installPackage( + OptionalPackages::$config['questions']['container']['options'][$containerOption], + $copyFilesKey + ); + $this->installPackage( + OptionalPackages::$config['questions']['router']['options'][$routerOption], + $copyFilesKey + ); + + // Test container + $container = $this->getContainer(); + $this->assertInstanceOf(ContainerInterface::class, $container); + $this->assertInstanceOf($expectedContainer, $container); + $this->assertTrue($container->has(Expressive\Helper\UrlHelper::class)); + $this->assertTrue($container->has(Expressive\Helper\ServerUrlHelper::class)); + $this->assertTrue($container->has(Expressive\Application::class)); + $this->assertTrue($container->has(Expressive\Router\RouterInterface::class)); + + // Test home page + $response = $this->getAppResponse(); + $this->assertEquals($expectedResponseStatusCode, $response->getStatusCode()); + } + + public function containerProvider() + { + // $containerOption, $routerOption, $copyFilesKey, $expectedResponseStatusCode, $expectedContainer + return [ + 'aura-minimal' => [1, 2, 'minimal-files', 404, AuraContainer::class], + 'aura-full' => [1, 2, 'copy-files', 200, AuraContainer::class], + 'pimple-minimal' => [2, 2, 'minimal-files', 404, PimpleInteropContainer::class], + 'pimple-full' => [2, 2, 'copy-files', 200, PimpleInteropContainer::class], + 'zend-sm-minimal' => [3, 2, 'minimal-files', 404, ZendServiceManagerContainer::class], + 'zend-sm-full' => [3, 2, 'copy-files', 200, ZendServiceManagerContainer::class], + ]; + } +} diff --git a/test/ExpressiveInstallerTest/InstallerTestCase.php b/test/ExpressiveInstallerTest/InstallerTestCase.php new file mode 100644 index 0000000..582c963 --- /dev/null +++ b/test/ExpressiveInstallerTest/InstallerTestCase.php @@ -0,0 +1,109 @@ +response = null; + + $this->cleanup(); + + $this->io = $this->prophesize('Composer\IO\IOInterface'); + + // Get composer.json + $composerFile = Factory::getComposerFile(); + $json = new JsonFile($composerFile); + OptionalPackages::$composerDefinition = $json->read(); + + $this->projectRoot = realpath(dirname($composerFile)); + + OptionalPackages::$config = require 'src/ExpressiveInstaller/config.php'; + } + + public function tearDown() + { + parent::tearDown(); + + $this->cleanup(); + } + + public function installPackage($config, $copyFilesKey) + { + /* TODO: First we need to set $composerDefinition, $composerRequires, $composerDevRequires and $stabilityFlags; + // Add packages to install + if (isset($config['packages'])) { + foreach ($config['packages'] as $packageName) { + OptionalPackages::addPackage($this->io, $packageName, $this->config['packages'][$packageName]); + } + }*/ + + // Copy files + if (isset($config[$copyFilesKey])) { + foreach ($config[$copyFilesKey] as $source => $target) { + OptionalPackages::copyFile($this->io->reveal(), $this->projectRoot, $source, $target); + } + } + } + + public function cleanup() + { + foreach ($this->teardownFiles as $file) { + if (is_file($this->projectRoot.$file)) { + unlink($this->projectRoot.$file); + } + } + } + + public function getContainer() + { + if (!$this->container) { + /** @var ContainerInterface $container */ + $this->container = require 'config/container.php'; + } + + return $this->container; + } + + public function getAppResponse($path = '/') + { + $container = $this->getContainer(); + + /** @var Application $app */ + $app = $container->get('Zend\Expressive\Application'); + $request = new ServerRequest([], [], 'https://example.com'.$path, 'GET'); + + /** @var ResponseInterface $response */ + $response = $app($request, new Response()); + + return $response; + } +} diff --git a/test/ExpressiveInstallerTest/RoutersTest.php b/test/ExpressiveInstallerTest/RoutersTest.php new file mode 100644 index 0000000..dc1018f --- /dev/null +++ b/test/ExpressiveInstallerTest/RoutersTest.php @@ -0,0 +1,82 @@ + 'home', + 'path' => '/', + 'middleware' => HomePageAction::class, + 'allowed_methods' => ['GET'], + ], + [ + 'name' => 'api.ping', + 'path' => '/api/ping', + 'middleware' => PingAction::class, + 'allowed_methods' => ['GET'], + ], + ]; + + /** + * @dataProvider routerProvider + */ + public function testRouter( + $containerOption, + $routerOption, + $copyFilesKey, + $expectedResponseStatusCode, + $expectedRoutes, + $expectedRouter + ) { + // Install packages + $this->installPackage( + OptionalPackages::$config['questions']['container']['options'][$containerOption], + $copyFilesKey + ); + $this->installPackage( + OptionalPackages::$config['questions']['router']['options'][$routerOption], + $copyFilesKey + ); + + // Test container + $container = $this->getContainer(); + $this->assertTrue($container->has(Router\RouterInterface::class)); + + // Test config + $config = $container->get('config'); + $this->assertEquals( + $expectedRouter, + $config['dependencies']['invokables'][Router\RouterInterface::class] + ); + $this->assertEquals($expectedRoutes, $config['routes']); + + // Test home page + $response = $this->getAppResponse(); + $this->assertEquals($expectedResponseStatusCode, $response->getStatusCode()); + } + + public function routerProvider() + { + // $containerOption, $routerOption, $copyFilesKey, $expectedResponseStatusCode, $expectedRoutes, $expectedRouter + return [ + 'aura-minimal' => [3, 1, 'minimal-files', 404, [], Router\AuraRouter::class], + 'aura-full' => [3, 1, 'copy-files', 200, $this->expectedRoutes, Router\AuraRouter::class], + 'fastroute-minimal' => [3, 2, 'minimal-files', 404, [], Router\FastRouteRouter::class], + 'fastroute-full' => [3, 2, 'copy-files', 200, $this->expectedRoutes, Router\FastRouteRouter::class], + 'zend-router-minimal' => [3, 3, 'minimal-files', 404, [], Router\ZendRouter::class], + 'zend-router-full' => [3, 3, 'copy-files', 200, $this->expectedRoutes, Router\ZendRouter::class], + ]; + } +} diff --git a/test/ExpressiveInstallerTest/TemplateRenderersTest.php b/test/ExpressiveInstallerTest/TemplateRenderersTest.php new file mode 100644 index 0000000..f91c836 --- /dev/null +++ b/test/ExpressiveInstallerTest/TemplateRenderersTest.php @@ -0,0 +1,88 @@ +installPackage( + OptionalPackages::$config['questions']['container']['options'][$containerOption], + $copyFilesKey + ); + $this->installPackage( + OptionalPackages::$config['questions']['router']['options'][$routerOption], + $copyFilesKey + ); + $this->installPackage( + OptionalPackages::$config['questions']['template-engine']['options'][$templateRendererOption], + $copyFilesKey + ); + + // Test container + $container = $this->getContainer(); + $this->assertTrue($container->has(Expressive\Application::class)); + $this->assertTrue($container->has('Zend\Expressive\FinalHandler')); + + // Test config + $config = $container->get('config'); + $this->assertEquals( + Expressive\Container\TemplatedErrorHandlerFactory::class, + $config['dependencies']['factories']['Zend\Expressive\FinalHandler'] + ); + + // Test template renderer + $templateRenderer = $container->get(Expressive\Template\TemplateRendererInterface::class); + $this->assertInstanceOf(Expressive\Template\TemplateRendererInterface::class, $templateRenderer); + $this->assertInstanceOf($expectedTemplateRenderer, $templateRenderer); + + if ($copyFilesKey == 'copy-files') { + // Test home page for full install only, otherwise you get invalid template name errors + $response = $this->getAppResponse(); + $this->assertEquals($expectedResponseStatusCode, $response->getStatusCode()); + } + } + + public function templateRendererProvider() + { + // $containerOption, $routerOption, $templateRendererOption, $copyFilesKey, $expectedResponseStatusCode, + // $expectedTemplateRenderer + return [ + // Full tests first so all the template paths are created before the minimal tests start + 'plates-full' => [3, 2, 1, 'copy-files', 200, Expressive\Plates\PlatesRenderer::class], + 'twig-full' => [3, 2, 2, 'copy-files', 200, Expressive\Twig\TwigRenderer::class], + 'zend-view-full' => [3, 2, 3, 'copy-files', 200, Expressive\ZendView\ZendViewRenderer::class], + // Minimal tests must be after the full tests !!! + 'plates-minimal' => [3, 2, 1, 'minimal-files', 404, Expressive\Plates\PlatesRenderer::class], + 'twig-minimal' => [3, 2, 2, 'minimal-files', 404, Expressive\Twig\TwigRenderer::class], + 'zend-view-minimal' => [3, 2, 3, 'minimal-files', 404, Expressive\ZendView\ZendViewRenderer::class], + ]; + } +}