refs #377. Creacion de test funcionales para API User
parent
1350735e5c
commit
c76d0e4c74
|
@ -0,0 +1,6 @@
|
|||
# define your env variables for the test env here
|
||||
KERNEL_CLASS='App\Kernel'
|
||||
APP_SECRET='$ecretf0rt3st'
|
||||
SYMFONY_DEPRECATIONS_HELPER=999999
|
||||
PANTHER_APP_ENV=panther
|
||||
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
|
|
@ -15,3 +15,13 @@
|
|||
###> lexik/jwt-authentication-bundle ###
|
||||
/config/jwt/*.pem
|
||||
###< lexik/jwt-authentication-bundle ###
|
||||
|
||||
###> symfony/phpunit-bridge ###
|
||||
.phpunit.result.cache
|
||||
/phpunit.xml
|
||||
###< symfony/phpunit-bridge ###
|
||||
|
||||
###> phpunit/phpunit ###
|
||||
/phpunit.xml
|
||||
.phpunit.result.cache
|
||||
###< phpunit/phpunit ###
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
if (!ini_get('date.timezone')) {
|
||||
ini_set('date.timezone', 'UTC');
|
||||
}
|
||||
|
||||
if (is_file(dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit')) {
|
||||
if (PHP_VERSION_ID >= 80000) {
|
||||
require dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit';
|
||||
} else {
|
||||
define('PHPUNIT_COMPOSER_INSTALL', dirname(__DIR__).'/vendor/autoload.php');
|
||||
require PHPUNIT_COMPOSER_INSTALL;
|
||||
PHPUnit\TextUI\Command::main();
|
||||
}
|
||||
} else {
|
||||
if (!is_file(dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php')) {
|
||||
echo "Unable to find the `simple-phpunit.php` script in `vendor/symfony/phpunit-bridge/bin/`.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php';
|
||||
}
|
|
@ -83,8 +83,14 @@
|
|||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"dama/doctrine-test-bundle": "^8.1",
|
||||
"doctrine/doctrine-fixtures-bundle": "^3.6",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"symfony/browser-kit": "6.4.*",
|
||||
"symfony/css-selector": "6.4.*",
|
||||
"symfony/http-client": "6.4.*",
|
||||
"symfony/maker-bundle": "^1.59",
|
||||
"symfony/phpunit-bridge": "^7.0",
|
||||
"symfony/web-profiler-bundle": "^6.4",
|
||||
"zenstruck/foundry": "^1.37"
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,7 +19,9 @@ resources:
|
|||
provider: App\State\Provider\UserProvider
|
||||
ApiPlatform\Metadata\Patch:
|
||||
provider: App\State\Provider\UserProvider
|
||||
ApiPlatform\Metadata\Post: ~
|
||||
ApiPlatform\Metadata\Post:
|
||||
validation_context:
|
||||
groups: [ 'default', 'user:post' ]
|
||||
ApiPlatform\Metadata\Delete: ~
|
||||
|
||||
properties:
|
||||
|
|
|
@ -15,4 +15,5 @@ return [
|
|||
Gesdinet\JWTRefreshTokenBundle\GesdinetJWTRefreshTokenBundle::class => ['all' => true],
|
||||
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
||||
Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true],
|
||||
DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
|
||||
];
|
||||
|
|
|
@ -11,6 +11,13 @@ api_platform:
|
|||
paths: ['%kernel.project_dir%/config/api_platform', '%kernel.project_dir%/src/Dto']
|
||||
defaults:
|
||||
pagination_client_items_per_page: true
|
||||
cache_headers:
|
||||
vary: [ 'Content-Type', 'Authorization', 'Origin' ]
|
||||
extra_properties:
|
||||
standard_put: true
|
||||
rfc_7807_compliant_errors: true
|
||||
event_listeners_backward_compatibility_layer: false
|
||||
keep_legacy_inflector: false
|
||||
docs_formats:
|
||||
jsonld: ['application/ld+json']
|
||||
jsonopenapi: ['application/vnd.openapi+json']
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
when@test:
|
||||
dama_doctrine_test:
|
||||
enable_static_connection: true
|
||||
enable_static_meta_data_cache: true
|
||||
enable_static_query_cache: true
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
backupGlobals="false"
|
||||
colors="true"
|
||||
bootstrap="tests/bootstrap.php"
|
||||
convertDeprecationsToExceptions="false"
|
||||
>
|
||||
<php>
|
||||
<ini name="display_errors" value="1" />
|
||||
<ini name="error_reporting" value="-1" />
|
||||
<server name="APP_ENV" value="test" force="true" />
|
||||
<server name="SHELL_VERBOSITY" value="-1" />
|
||||
<server name="SYMFONY_PHPUNIT_REMOVE" value="" />
|
||||
<server name="SYMFONY_PHPUNIT_VERSION" value="9.6" />
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Project Test Suite">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
|
||||
<listeners>
|
||||
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
|
||||
</listeners>
|
||||
|
||||
<extensions>
|
||||
<extension class="DAMA\DoctrineTestBundle\PHPUnit\PHPUnitExtension"/>
|
||||
</extensions>
|
||||
</phpunit>
|
|
@ -23,10 +23,10 @@ final class UserInput
|
|||
#[Groups(['user:write'])]
|
||||
public array $allowedOrganizationalUnits = [];
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\NotBlank(groups: ['user:create'])]
|
||||
#[Assert\Length(min: 8)]
|
||||
#[Groups(['user:write'])]
|
||||
public string $password;
|
||||
public ?string $password = null;
|
||||
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['user:write'])]
|
||||
|
@ -59,9 +59,13 @@ final class UserInput
|
|||
|
||||
$user->setUsername($this->username);
|
||||
$user->setRoles($this->roles);
|
||||
$user->setPassword($this->password);
|
||||
$user->setEnabled($this->enabled);
|
||||
$user->setUserGroups($this->userGroups);
|
||||
|
||||
if ($this->password !== null) {
|
||||
$user->setPassword($this->password);
|
||||
}
|
||||
|
||||
//$user->setAllowedOrganizationalUnits($this->allowedOrganizationalUnits);
|
||||
|
||||
return $user;
|
||||
|
|
|
@ -16,11 +16,6 @@ final class UserFactory extends ModelFactory
|
|||
{
|
||||
CONST PLAIN_PASSWORD = '12345678';
|
||||
|
||||
/**
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
|
||||
*
|
||||
* @todo inject services if required
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
|
|
@ -27,7 +27,7 @@ class UserProcessor implements ProcessorInterface
|
|||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = [])
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): UserOutput|null
|
||||
{
|
||||
switch ($operation){
|
||||
case $operation instanceof Post:
|
||||
|
@ -55,7 +55,9 @@ class UserProcessor implements ProcessorInterface
|
|||
|
||||
$user = $data->createOrUpdateEntity($entity);
|
||||
|
||||
$user->setPassword($this->userPasswordHasher->hashPassword($user, $data->password));
|
||||
if ($data->password !== null){
|
||||
$user->setPassword($this->userPasswordHasher->hashPassword($user, $data->password));
|
||||
}
|
||||
|
||||
$this->validator->validate($user);
|
||||
$this->userRepository->save($user);
|
||||
|
|
41
symfony.lock
41
symfony.lock
|
@ -13,6 +13,18 @@
|
|||
"src/ApiResource/.gitignore"
|
||||
]
|
||||
},
|
||||
"dama/doctrine-test-bundle": {
|
||||
"version": "8.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes-contrib",
|
||||
"branch": "main",
|
||||
"version": "7.2",
|
||||
"ref": "896306d79d4ee143af9eadf9b09fd34a8c391b70"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/dama_doctrine_test_bundle.yaml"
|
||||
]
|
||||
},
|
||||
"doctrine/doctrine-bundle": {
|
||||
"version": "2.12",
|
||||
"recipe": {
|
||||
|
@ -90,6 +102,20 @@
|
|||
"config/packages/nelmio_cors.yaml"
|
||||
]
|
||||
},
|
||||
"phpunit/phpunit": {
|
||||
"version": "9.6",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "9.6",
|
||||
"ref": "7364a21d87e658eb363c5020c072ecfdc12e2326"
|
||||
},
|
||||
"files": [
|
||||
".env.test",
|
||||
"phpunit.xml.dist",
|
||||
"tests/bootstrap.php"
|
||||
]
|
||||
},
|
||||
"ramsey/uuid-doctrine": {
|
||||
"version": "2.0",
|
||||
"recipe": {
|
||||
|
@ -166,6 +192,21 @@
|
|||
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
|
||||
}
|
||||
},
|
||||
"symfony/phpunit-bridge": {
|
||||
"version": "7.0",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "6.3",
|
||||
"ref": "a411a0480041243d97382cac7984f7dce7813c08"
|
||||
},
|
||||
"files": [
|
||||
".env.test",
|
||||
"bin/phpunit",
|
||||
"phpunit.xml.dist",
|
||||
"tests/bootstrap.php"
|
||||
]
|
||||
},
|
||||
"symfony/routing": {
|
||||
"version": "6.4",
|
||||
"recipe": {
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace Functional;
|
||||
|
||||
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
|
||||
use ApiPlatform\Symfony\Bundle\Test\Client;
|
||||
use App\Factory\UserFactory;
|
||||
use Faker\Factory;
|
||||
use Faker\Generator;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Zenstruck\Foundry\Test\Factories;
|
||||
use Zenstruck\Foundry\Test\ResetDatabase;
|
||||
|
||||
abstract class AbstractTest extends ApiTestCase
|
||||
{
|
||||
use ResetDatabase, Factories;
|
||||
|
||||
protected static Client $client;
|
||||
protected static Generator $faker;
|
||||
private ?string $token = null;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
self::bootKernel();
|
||||
|
||||
self::$client = static::createClient();
|
||||
self::$faker = Factory::create();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws DecodingExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
protected function getToken($body = []): string
|
||||
{
|
||||
if ($this->token) {
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
$response = static::createClient()->request('POST', '/auth/login', ['json' => $body ?: [
|
||||
'username' => 'ogadmin',
|
||||
'password' => '12345678',
|
||||
]]);
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
$data = $response->toArray();
|
||||
$this->token = $data['token'];
|
||||
|
||||
return $data['token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws DecodingExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
protected function createClientWithCredentials($token = null): Client
|
||||
{
|
||||
$token = $token ?: $this->getToken();
|
||||
|
||||
return static::createClient([], ['headers' => ['authorization' => 'Bearer '.$token]]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
namespace Functional;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Factory\UserFactory;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
|
||||
class UserTest extends AbstractTest
|
||||
{
|
||||
CONST USER_ADMIN = 'ogadmin';
|
||||
CONST USER_CREATE = 'test-create';
|
||||
CONST USER_UPDATE = 'test-update';
|
||||
CONST USER_DELETE = 'test-delete';
|
||||
|
||||
/**
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws DecodingExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
*/
|
||||
public function testGetCollection(): void
|
||||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN]);
|
||||
UserFactory::createMany(10);
|
||||
|
||||
$this->createClientWithCredentials()->request('GET', '/api/users');
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
|
||||
$this->assertJsonContains([
|
||||
'@context' => '/api/contexts/User',
|
||||
'@id' => '/api/users',
|
||||
'@type' => 'hydra:Collection',
|
||||
'hydra:totalItems' => 11,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws DecodingExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
*/
|
||||
public function testCreate(): void
|
||||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN]);
|
||||
$this->createClientWithCredentials()->request('POST', '/api/users',['json' => [
|
||||
'username' => self::USER_CREATE,
|
||||
'password' => '12345678',
|
||||
'enabled' => true,
|
||||
]]);
|
||||
|
||||
$this->assertResponseStatusCodeSame(201);
|
||||
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
|
||||
$this->assertJsonContains([
|
||||
'@context' => '/api/contexts/UserOutput',
|
||||
'@type' => 'User',
|
||||
'username' => self::USER_CREATE,
|
||||
'enabled' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws DecodingExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
*/
|
||||
public function testUpdateBook(): void
|
||||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN]);
|
||||
UserFactory::createOne(['username' => self::USER_UPDATE]);
|
||||
|
||||
$iri = $this->findIriBy(User::class, ['username' => self::USER_UPDATE]);
|
||||
|
||||
$this->createClientWithCredentials()->request('PATCH', $iri, ['json' => [
|
||||
'username' => self::USER_UPDATE,
|
||||
]]);
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertJsonContains([
|
||||
'@id' => $iri,
|
||||
'username' => self::USER_UPDATE,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws DecodingExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
public function testDeleteBook(): void
|
||||
{
|
||||
UserFactory::createOne(['username' => self::USER_ADMIN]);
|
||||
UserFactory::createOne(['username' => self::USER_DELETE]);
|
||||
|
||||
$iri = $this->findIriBy(User::class, ['username' => self::USER_DELETE]);
|
||||
|
||||
$this->createClientWithCredentials()->request('DELETE', $iri);
|
||||
$this->assertResponseStatusCodeSame(204);
|
||||
$this->assertNull(
|
||||
static::getContainer()->get('doctrine')->getRepository(User::class)->findOneBy(['username' => self::USER_DELETE])
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
use Symfony\Component\Dotenv\Dotenv;
|
||||
|
||||
require dirname(__DIR__).'/vendor/autoload.php';
|
||||
|
||||
if (method_exists(Dotenv::class, 'bootEnv')) {
|
||||
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
|
||||
}
|
||||
|
||||
if ($_SERVER['APP_DEBUG']) {
|
||||
umask(0000);
|
||||
}
|
Loading…
Reference in New Issue