diff --git a/.travis.yml b/.travis.yml index cab2d722..a3c99eb5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,16 +14,35 @@ cache: - $HOME/.composer/cache/files env: - matrix: - - TARGET="phpspec" - - TARGET="codestyle" + global: + - EZPLATFORM_REPO="https://github.com/ezsystems/ezplatform.git" + - SYMFONY_ENV=behat + - SYMFONY_DEBUG=1 + +matrix: + include: + - name: "Unit tests with PhpSpec" + env: + - TARGET="phpspec" + - name: "Code style" + env: + - TARGET="codestyle" + - name: "Behat" + env: + - TARGET="behat" + - COMPOSE_FILE="doc/docker/base-dev.yml" + - BEHAT_OPTS="--mode=behat --profile=graphql --suite=graphql" + +install: + - if [ $TARGET == "behat" ]; then ./.travis/prepare_ezplatform.sh ${INSTALL_EZ_INSTALL_TYPE}; fi before_script: - - COMPOSER_MEMORY_LIMIT=-1 composer install + - if [ "$TARGET" != "behat" ]; then COMPOSER_MEMORY_LIMIT=-1 composer install; fi script: - if [ "$TARGET" == "phpspec" ] ; then ./vendor/bin/phpspec run --format=pretty; fi - if [ "$TARGET" == "codestyle" ] ; then ./vendor/bin/php-cs-fixer fix --dry-run -v --show-progress=estimating; fi + - if [ "$TARGET" == "behat" ]; then cd "$HOME/build/ezplatform"; docker-compose exec --user www-data app sh -c "bin/ezbehat ${BEHAT_OPTS}" ; fi notification: email: false diff --git a/.travis/prepare_ezplatform.sh b/.travis/prepare_ezplatform.sh new file mode 100755 index 00000000..18c6bccb --- /dev/null +++ b/.travis/prepare_ezplatform.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +EZPLATFORM_BRANCH=`php -r 'echo json_decode(file_get_contents("./composer.json"))->extra->_ezplatform_branch_for_behat_tests;'` +EZPLATFORM_BRANCH="${EZPLATFORM_BRANCH:-master}" +PACKAGE_BUILD_DIR=$PWD +EZPLATFORM_BUILD_DIR=${HOME}/build/ezplatform + +echo "> Cloning ezsystems/ezplatform:${EZPLATFORM_BRANCH}" +git clone --depth 1 --single-branch --branch "${EZPLATFORM_BRANCH}" ${EZPLATFORM_REPO} ${EZPLATFORM_BUILD_DIR} +cd ${EZPLATFORM_BUILD_DIR} + +/bin/bash ./bin/.travis/trusty/setup_ezplatform.sh "${COMPOSE_FILE}" '' "${PACKAGE_BUILD_DIR}" diff --git a/behat_suites.yml b/behat_suites.yml new file mode 100644 index 00000000..dc020a64 --- /dev/null +++ b/behat_suites.yml @@ -0,0 +1,20 @@ +# This file is meant to be imported from ezplatform's behat.yml.dist. +# All path are relative to the root ezplatform directory. +default: + autoload: + - '%paths.base%/vendor/ezsystems/ezplatform-graphql/features/bootstrap/' + +graphql: + suites: + graphql: + autoload: + - '%paths.base%/vendor/ezsystems/ezplatform-graphql/features/bootstrap/' + paths: + - '%paths.base%/vendor/ezsystems/ezplatform-graphql/features/Generator.feature' + - '%paths.base%/vendor/ezsystems/ezplatform-graphql/features/Schema.feature' + contexts: + - GeneratorContext + - ConfigurationContext + - CacheContext + - SchemaContext + - EzSystems\BehatBundle\Context\Object\ContentTypeGroup diff --git a/composer.json b/composer.json index 1ba4ce67..21f5d5c1 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,8 @@ "overblog/graphiql-bundle": "^0.1", "phpspec/phpspec": "^5.1", "friendsofphp/php-cs-fixer": "~2.15.1", - "mikey179/vfsstream": "^1.6" + "mikey179/vfsstream": "^1.6", + "behat/behat": "^3.0" }, "autoload": { "psr-4": { @@ -37,8 +38,10 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" - } + "dev-master": "1.0.x-dev", + "dev-tmp_ci_branch": "1.0.x-dev" + }, + "_ezplatform_branch_for_behat_tests": "behat_graphql" }, "scripts": { "fix-cs": "@php ./vendor/bin/php-cs-fixer fix -v --show-progress=estimating" diff --git a/features/Generator.feature b/features/Generator.feature new file mode 100644 index 00000000..6133ca9a --- /dev/null +++ b/features/Generator.feature @@ -0,0 +1,11 @@ +Feature: Schema generation + In order to use GraphQL + As an application maintainer + I need to generate the schema + +Scenario: An application maintainer generates the schema + Given the schema has not been generated + When I run the command "ezplatform:graphql:generate-schema" + When I clear the cache + Then the schema files are generated in "app/config/graphql/ezplatform" + And the GraphQL extension is configured to use that schema diff --git a/features/Schema.feature b/features/Schema.feature new file mode 100644 index 00000000..9b3978df --- /dev/null +++ b/features/Schema.feature @@ -0,0 +1,22 @@ +Feature: Schema generation + In order to use my content over GraphQL + As an API consumer + I need to expose my content structure as a graph + +Scenario: Content type groups are exposed at the root of the schema + Given there is a Content Type Group with identifier content + And there is a Content Type Group with identifier media + When I query the schema + Then the query type is set to "Domain" + And "Domain" has the following fields: + | field | type | + | content | DomainGroupContent | + | media | DomainGroupMedia | + + + +#Scenario: Content types are exposed as leafs of their content type group +# Given there is a Content Type Group with identifier content +# And there is a Content Type "folder" in the Content Type Group "content" +# When I query the schema +# Then it has a diff --git a/features/bootstrap/CacheContext.php b/features/bootstrap/CacheContext.php new file mode 100644 index 00000000..1815723c --- /dev/null +++ b/features/bootstrap/CacheContext.php @@ -0,0 +1,48 @@ +kernel = $kernel; + } + + /** + * @Given /^I clear the cache$/ + */ + public function iClearTheCache() + { + $application = new \Symfony\Bundle\FrameworkBundle\Console\Application($this->kernel); + $application->setAutoExit(false); + + $input = new ArrayInput(['command' => 'cache:clear', '--env' => 'behat']); + + // You can use NullOutput() if you don't need the output + $output = new BufferedOutput(); + Assert::assertEquals(0, $application->run($input, $output)); + $content = $output->fetch(); + $this->kernel->shutdown(); + $this->kernel->boot(); + } +} \ No newline at end of file diff --git a/features/bootstrap/ConfigurationContext.php b/features/bootstrap/ConfigurationContext.php new file mode 100644 index 00000000..d225b2e1 --- /dev/null +++ b/features/bootstrap/ConfigurationContext.php @@ -0,0 +1,46 @@ +kernel = $kernel; + } + + /** + * @Given /^the GraphQL extension is configured to use that schema$/ + */ + public function theGraphQLExtensionIsConfiguredToUseThatSchema() + { + $container = $this->kernel->getContainer(); + $executor = $container->get('overblog_graphql.request_executor'); + $schema = $executor->getSchema('default'); + Assert::assertEquals('Domain', (string)$schema->getQueryType()); + Assert::assertEquals('DomainContentMutation', (string)$schema->getMutationType()); + } + +} \ No newline at end of file diff --git a/features/bootstrap/GeneratorContext.php b/features/bootstrap/GeneratorContext.php new file mode 100644 index 00000000..ea120b92 --- /dev/null +++ b/features/bootstrap/GeneratorContext.php @@ -0,0 +1,77 @@ +kernel); + $application->setAutoExit(false); + + $input = new ArrayInput(['command' => $command, '--env' => 'behat']); + + $output = new BufferedOutput(); + $application->run($input, $output); + + $content = $output->fetch(); + } + + /** + * @Then /^the schema files are generated in "([^"]*)"$/ + */ + public function theSchemaFilesAreGeneratedIn($directory) + { + $finder = new Finder(); + Assert::assertFileExists('app/config/graphql/ezplatform/Domain.types.yml'); + Assert::assertFileExists('app/config/graphql/ezplatform/DomainContentMutation.types.yml'); + } + + /** + * @Given /^the schema has not been generated$/ + */ + public function theSchemaHasNotBeenGenerated() + { + if (file_exists('app/config/graphql/ezplatform')) { + $finder = new Finder(); + $fs = new Filesystem(); + $fs->remove($finder->in('app/config/graphql/ezplatform')->files()); + } + } + + /** + * Sets Kernel instance. + * + * @param \Symfony\Component\HttpKernel\KernelInterface $kernel + */ + public function setKernel(KernelInterface $kernel) + { + $this->kernel = $kernel; + } +} \ No newline at end of file diff --git a/features/bootstrap/SchemaContext.php b/features/bootstrap/SchemaContext.php new file mode 100644 index 00000000..3e44e0d9 --- /dev/null +++ b/features/bootstrap/SchemaContext.php @@ -0,0 +1,116 @@ +kernel = $kernel; + } + + /** + * @When /^I query the schema$/ + */ + public function iQueryTheSchema() + { + $query = <<< GQL +query IntrospectionQuery { + __schema { + queryType { name } + types { + name + fields { + name + type { name } + } + } + } +} +GQL; + $request = Request::create('/graphql', 'POST', ['query' => $query]); + $response = $this->kernel->handle($request); + $this->schema = json_decode($response->getContent(), true)['data']['__schema']; + } + + /** + * @Then /^the query type is set to "([^"]*)"$/ + */ + public function theQueryTypeIsSetTo($queryTypeName) + { + Assert::assertEquals($queryTypeName, $this->schema['queryType']['name']); + } + + /** + * @Given /^"([^"]*)" has the following fields:$/ + */ + public function hasTheFollowingFields($queryType, TableNode $fieldsWithType) + { + $type = $this->getTypeFromSchema($queryType); + + foreach($fieldsWithType as $row) { + $this->assertTypeHasFieldWithType($type, $row['field'], $row['type']); + } + } + + private function assertTypeHasFieldWithType($type, $fieldName, $fieldType) + { + $hasField = false; + $hasType = false; + $foundType = null; + + foreach ($type['fields'] as $field) { + if ($field['name'] === $fieldName) { + $hasField = true; + if ($field['type']['name'] === $fieldType) { + $hasType = true; + break; + } else { + $foundType = $field['type']['name']; + } + } + } + + Assert::assertTrue($hasField, $type['name'] . " does not have a field named $fieldName"); + Assert::assertTrue($hasType, $type['name'] . ".$fieldType is not of type $fieldType (found " . $foundType . ")"); + } + + private function getTypeFromSchema($typeName) + { + $domainType = null; + foreach ($this->schema['types'] as $type) { + if ($type['name'] === $typeName) { + $domainType = $type; + } + } + + if (null === $domainType) { + throw new Exception("Type $type wasn't found in the schema"); + } + + return $domainType; + } +} \ No newline at end of file