Compare commits

..

28 commits

Author SHA1 Message Date
Simon Vieille
6c248452df
ci(conf): add chrome
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-01-10 10:36:01 +01:00
Simon Vieille
bbe14360d9
ci(conf): add chrome
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-01-10 10:30:03 +01:00
Simon Vieille
7769e25c75
ci(conf): add chrome driver
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-01-10 10:23:14 +01:00
Simon Vieille
56be2ebec7
ci(conf): add chrome driver
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-01-10 10:10:29 +01:00
Simon Vieille
8aa1b2f8c3
ci(conf): dbrekelmans/bdi
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-01-10 10:00:38 +01:00
Simon Vieille
f8094c45f8
ci(conf): webserver is now run as daemon
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-01-09 23:11:56 +01:00
Simon Vieille
f55605bea0
ci(conf): rollback images
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-01-09 22:52:24 +01:00
Simon Vieille
b1bf3a42a1
ci(conf): use deblan php images
Some checks are pending
ci/woodpecker/push/woodpecker Pipeline is pending
2023-01-09 22:51:39 +01:00
Simon Vieille
c16e4652cb
feat(tests): update default env
Some checks are pending
ci/woodpecker/push/woodpecker Pipeline is pending
2023-01-09 22:28:57 +01:00
Simon Vieille
2ed04163b4
feat(tests): add phpunit conf 2023-01-09 22:28:25 +01:00
Simon Vieille
496cd46db7
ci(tests): add web server start 2023-01-09 22:26:12 +01:00
Simon Vieille
dd3630237c
test(backoffice): add base functional tests
test creation of a navigation
test creation of a menu
test creation of a page
2023-01-09 22:25:39 +01:00
Simon Vieille
5dbcc51309
ci(test): update commands
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-01-09 10:20:19 +01:00
Simon Vieille
4b1fdb8652
ci(test): configure test database
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-01-09 10:09:05 +01:00
Simon Vieille
2aab5310d2
feat(test): remove doctrine prefix on test 2023-01-09 10:06:59 +01:00
Simon Vieille
3df5aba320
ci(test): add test database
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-01-09 09:59:21 +01:00
Simon Vieille
85e04205cd
feat(test): add dependencies
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-01-09 09:49:30 +01:00
Simon Vieille
40633fa567
ci(conf): use mariadb for tests
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-01-08 23:14:16 +01:00
Simon Vieille
8535ef9082
refactor(test): apply php-cs-fixer
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
add select user by email
2023-01-08 23:10:57 +01:00
Simon Vieille
f6c932314b
feat(test): configure phpunit
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-01-08 22:51:53 +01:00
Simon Vieille
80af94a95e
refactor(test): rename LoginTest 2023-01-08 22:51:27 +01:00
Simon Vieille
a22725ad6d
ci(command): add for murph:user:create 2023-01-08 22:51:01 +01:00
Simon Vieille
49b90f6e6c
fix(ci): create directory public/js in CI
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-01-08 21:58:23 +01:00
Simon Vieille
919edfe664
test(auth): add test of admin page access
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-01-08 21:49:34 +01:00
Simon Vieille
518c98710e
feat(ci): add base of CI 2023-01-08 21:48:56 +01:00
Simon Vieille
9937160ae0
feat(test): update murph/murph-core version 2023-01-08 21:48:34 +01:00
Simon Vieille
d4eabf1937
feat(db): add APP_ENV in doctrine-migrate script 2023-01-08 21:47:59 +01:00
Simon Vieille
fdc6c423ff
feat(tests): configure tests 2023-01-08 21:47:33 +01:00
27 changed files with 13792 additions and 3008 deletions

View file

@ -2,6 +2,5 @@
KERNEL_CLASS='App\Kernel' KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st' APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999 SYMFONY_DEPRECATIONS_HELPER=999999
PANTHER_APP_ENV=panther PANTHER_APP_ENV=test
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
DATABASE_URL="sqlite:///%kernel.project_dir%/var/data_tests.db"

3
.gitignore vendored
View file

@ -33,3 +33,6 @@ yarn-error.log
/phpunit.xml /phpunit.xml
.phpunit.result.cache .phpunit.result.cache
###< phpunit/phpunit ### ###< phpunit/phpunit ###
# Tests
/drivers/

View file

@ -1,6 +1,6 @@
matrix: matrix:
PHP_VERSION: PHP_VERSION:
- 8.0 # - 8.0
- 8.1 - 8.1
services: services:
@ -9,23 +9,25 @@ services:
environment: environment:
- MARIADB_ROOT_PASSWORD=root - MARIADB_ROOT_PASSWORD=root
steps: pipeline:
db_wait: wait_db:
image: gitnet.fr/deblan/timeout:latest image: gitnet.fr/deblan/timeout:latest
commands: commands:
- /bin/timeout -t 30 -v -c 'while true; do nc -z -v db 3306 2>&1 | grep succeeded && exit 0; sleep 0.5; done' - /bin/timeout -t 30 -v -c 'while true; do nc -z -v db 3306 2>&1 | grep succeeded && exit 0; sleep 0.5; done'
db_create: create_db:
image: mariadb:10.3 image: mariadb:10.3
commands: commands:
- mysql -hdb -uroot -proot -e "CREATE DATABASE app" - mysql -hdb -uroot -proot -e "CREATE DATABASE app"
- mysql -hdb -uroot -proot -e "CREATE DATABASE app_test"
config: config:
image: deblan/php:${PHP_VERSION} image: deblan/php:8.1
commands: commands:
- echo APP_ENV=prod >> .env.local - echo APP_ENV=prod >> .env.local
- echo APP_SECRET=$(openssl rand -hex 32) >> .env.local - echo APP_SECRET=$(openssl rand -hex 32) >> .env.local
- echo DATABASE_URL=mysql://root:root@db/app >> .env.local - echo DATABASE_URL=mysql://root:root@db/app >> .env.local
- echo DATABASE_URL=mysql://root:root@db/app_test >> .env.test.local
composer: composer:
image: deblan/php:${PHP_VERSION} image: deblan/php:${PHP_VERSION}
@ -33,7 +35,7 @@ steps:
- apt-get update && apt-get -y install git - apt-get update && apt-get -y install git
- composer install --no-scripts - composer install --no-scripts
db_migrate: migrate:
image: deblan/php:${PHP_VERSION} image: deblan/php:${PHP_VERSION}
environment: environment:
- PHP=php - PHP=php
@ -47,3 +49,14 @@ steps:
- test -d public/js || mkdir public/js - test -d public/js || mkdir public/js
- test -f public/js/fos_js_routes.json || echo "{}" > public/js/fos_js_routes.json - test -f public/js/fos_js_routes.json || echo "{}" > public/js/fos_js_routes.json
- npm run build - npm run build
tests:
image: deblan/php:${PHP_VERSION}
commands:
- apt-get update && apt-get install -y unzip
- composer install --no-scripts --dev
- curl -o chromedriver_linux64.zip https://chromedriver.storage.googleapis.com/108.0.5359.71/chromedriver_linux64.zip && unzip -d drivers chromedriver_linux64.zip
- curl -o /tmp/chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && apt install -y /tmp/chrome.deb
- vendor/bin/bdi detect drivers
- symfony server:start --port=9080 --no-tls -d
- php bin/phpunit

View file

@ -1,75 +1,6 @@
## [Unreleased] ## [Unreleased]
## [v1.26.0] - 2025-03-17 ## [1.17.0] 2022-11-19
### Changed
* upgrade murph/murph-core
## [v1.25.1] - 2024-05-13
### Fixed
* fix murph-npm version
## [v1.25.0] - 2024-05-12
### Changed
* upgrade murph/murph-core
## [v1.23.0] - 2023-09-28
### Changed
* upgrade murph/murph-core
## [v1.22.0] - 2023-09-28
### Added
* update woodpecker ci base file
### Fixed
* fix #1: add UniqueEntity constraint in the User entity
### Changed
* upgrade murph/murph-core
## [1.21.0] - 2023-08-11
### Changed
* upgrade murph/murph-core
## [1.20.0] - 2023-07-27
### Fixed
* fix collection widget: allow_add/allow_delete and prototype
### Added
* add user admin controller and simples views in default files
* add chdir in the console entrypoint
### Changed
* upgrade murph/murph-core
## [1.19.0] - 2023-04-15
### Changed
* upgrade murph/murph-core
## [1.18.0] - 2023-01-13
### Added
* feat(dep): update dependencies
* feat(update): apply new recipe for phpunit
* feat(update): apply recipes:update doctrine/doctrine-bundle
* feat(update): apply recipes:update doctrine/doctrine-migrations-bundle
* feat(update): apply recipes:update liip/imagine-bundle
* feat(update): apply recipes:update stof/doctrine-extensions-bundle
* feat(update): apply recipes:update symfony/apache-pack
* feat(update): apply recipes:update symfony/console
* feat(update): apply recipes:update symfony/debug-bundle
* feat(update): apply recipes:update symfony/flex
* feat(update): apply recipes:update symfony/mailer
* feat(update): apply recipes:update symfony/framework-bundle
* feat(update): apply recipes:update symfony/monolog-bundle
* feat(update): apply recipes:update symfony/routing
* feat(update): apply recipes:update symfony/security-bundle
* feat(update): apply recipes:update symfony/translation
* feat(update): apply recipes:update symfony/twig-bundle
* feat(update): apply recipes:update symfony/validator
* feat(update): apply recipes:update symfony/web-profiler-bundle
* feat(update): apply recipes:update symfony/webpack-encore-bundle
* feat(update): apply recipes:update scheb/2fa-bundle
### Fixed
* fix(config): fix typo in 2fa conf
* fix(config): fix firewall config
## [1.17.0] - 2022-11-19
### Changed ### Changed
* upgrade murph/murph-core * upgrade murph/murph-core
* replace annotation with attributes * replace annotation with attributes

View file

@ -24,3 +24,6 @@ doctrine-migration:
PHP=$(PHP_BIN) ./bin/doctrine-migrate PHP=$(PHP_BIN) ./bin/doctrine-migrate
build: clean js-routing asset build: clean js-routing asset
run-tests:
$(PHP_BIN) bin/phpunit tests/

View file

@ -10,8 +10,6 @@ if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
chdir(__DIR__.'/../');
return function (array $context) { return function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); $kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);

View file

@ -1,7 +1,9 @@
#!/bin/sh #!/bin/sh
CLASS_NAME="$(echo "yes" | "$PHP" ./bin/console doctrine:migration:diff -e dev | grep -o "Version[0-9]*" | tail -n 1)" APP_ENV="${APP_ENV:-dev}"
CLASS_NAME="$(echo "yes" | "$PHP" ./bin/console doctrine:migration:diff -e "$APP_ENV" | grep -o "Version[0-9]*" | tail -n 1)"
if [ -n "$CLASS_NAME" ]; then if [ -n "$CLASS_NAME" ]; then
echo "yes" | "$PHP" ./bin/console doctrine:migration:exec --up "DoctrineMigrations\\$CLASS_NAME" -e dev echo "yes" | "$PHP" ./bin/console doctrine:migration:exec --up "DoctrineMigrations\\$CLASS_NAME" -e "$APP_ENV"
fi fi

View file

@ -7,13 +7,15 @@
"prefer-stable": true, "prefer-stable": true,
"require": { "require": {
"php": ">=8.0.0", "php": ">=8.0.0",
"murph/murph-core": "^1.26" "murph/murph-core": "dev-master"
}, },
"require-dev": { "require-dev": {
"dbrekelmans/bdi": "^1.0",
"symfony/browser-kit": "^5.4", "symfony/browser-kit": "^5.4",
"symfony/css-selector": "^5.4", "symfony/css-selector": "^5.4",
"symfony/debug-bundle": "^5.4", "symfony/debug-bundle": "^5.4",
"symfony/maker-bundle": "^1.0", "symfony/maker-bundle": "^1.0",
"symfony/panther": "^2.0",
"symfony/phpunit-bridge": "^6.2", "symfony/phpunit-bridge": "^6.2",
"symfony/stopwatch": "^5.4", "symfony/stopwatch": "^5.4",
"symfony/var-dumper": "^5.4", "symfony/var-dumper": "^5.4",

View file

@ -18,7 +18,6 @@ core:
# - image/png # - image/png
# - image/jpg # - image/jpg
# - image/jpeg # - image/jpeg
# - image/webp
# - image/gif # - image/gif
# - image/svg+xml # - image/svg+xml
# - video/mp4 # - video/mp4

View file

@ -29,11 +29,11 @@ doctrine:
alias: GedmoTree # (optional) it will default to the name set for the mapping alias: GedmoTree # (optional) it will default to the name set for the mapping
is_bundle: false is_bundle: false
when@test: # when@test:
doctrine: # doctrine:
dbal: # dbal:
# "TEST_TOKEN" is typically set by ParaTest # # "TEST_TOKEN" is typically set by ParaTest
dbname_suffix: '_test%env(default::TEST_TOKEN)%' # dbname_suffix: '_test%env(default::TEST_TOKEN)%'
when@prod: when@prod:
doctrine: doctrine:

View file

@ -3,10 +3,6 @@ security:
App\Entity\User: App\Entity\User:
algorithm: auto algorithm: auto
access_decision_manager:
strategy: consensus
allow_if_all_abstain: false
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
enable_authenticator_manager: true enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords

11023
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -13,13 +13,22 @@
<ini name="error_reporting" value="-1" /> <ini name="error_reporting" value="-1" />
<server name="APP_ENV" value="test" force="true" /> <server name="APP_ENV" value="test" force="true" />
<server name="SHELL_VERBOSITY" value="-1" /> <server name="SHELL_VERBOSITY" value="-1" />
<server name="SYMFONY_DEPRECATIONS_HELPER" value="weak" />
<server name="SYMFONY_PHPUNIT_REMOVE" value="" /> <server name="SYMFONY_PHPUNIT_REMOVE" value="" />
<server name="SYMFONY_PHPUNIT_VERSION" value="9.5" /> <server name="SYMFONY_PHPUNIT_VERSION" value="9.5" />
</php> </php>
<testsuites> <testsuites>
<testsuite name="Project Test Suite"> <testsuite name="CLI">
<directory>tests</directory> <file>tests/Core/Command/CreateUserTest.php</file>
</testsuite>
<testsuite name="Login">
<file>tests/Core/Auth/LoginTest.php</file>
</testsuite>
<testsuite name="Site">
<file>tests/Core/Site/NavigationTest.php</file>
<file>tests/Core/Site/TreeTest.php</file>
<file>tests/Core/Site/PageTest.php</file>
</testsuite> </testsuite>
</testsuites> </testsuites>
@ -33,10 +42,7 @@
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" /> <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
</listeners> </listeners>
<!-- Run `composer require symfony/panther` before enabling this extension -->
<!--
<extensions> <extensions>
<extension class="Symfony\Component\Panther\ServerExtension" /> <extension class="Symfony\Component\Panther\ServerExtension" />
</extensions> </extensions>
-->
</phpunit> </phpunit>

View file

@ -1,79 +0,0 @@
<?php
namespace App\Controller;
use App\Core\Controller\User\UserAdminController as BaseUserAdminController;
use App\Core\Crud\CrudConfiguration;
use App\Core\Factory\UserFactory as Factory;
use App\Core\Manager\EntityManager;
use App\Core\Security\TokenGenerator;
use App\Entity\User as Entity;
use App\Repository\UserRepositoryQuery as RepositoryQuery;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Routing\Annotation\Route;
class UserAdminController extends BaseUserAdminController
{
#[Route(path: '/admin/user/{page}', name: 'admin_user_index', methods: ['GET'], requirements: ['page' => '\d+'])]
public function index(RepositoryQuery $query, Request $request, Session $session, int $page = 1): Response
{
return parent::index($query, $request, $session, $page);
}
#[Route(path: '/admin/user/new', name: 'admin_user_new', methods: ['GET', 'POST'])]
public function new(Factory $factory, EntityManager $entityManager, Request $request, TokenGenerator $tokenGenerator): Response
{
return parent::new($factory, $entityManager, $request, $tokenGenerator);
}
#[Route(path: '/admin/user/show/{entity}', name: 'admin_user_show', methods: ['GET'])]
public function show(Entity $entity): Response
{
return parent::show($entity);
}
#[Route(path: '/admin/user/filter', name: 'admin_user_filter', methods: ['GET'])]
public function filter(Session $session): Response
{
return parent::filter($session);
}
#[Route(path: '/admin/user/edit/{entity}', name: 'admin_user_edit', methods: ['GET', 'POST'])]
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
{
return parent::edit($entity, $entityManager, $request);
}
#[Route(path: '/admin/user/inline_edit/{entity}/{context}/{label}', name: 'admin_user_inline_edit', methods: ['GET', 'POST'])]
public function inlineEdit(string $context, string $label, Entity $entity, EntityManager $entityManager, Request $request): Response
{
return parent::inlineEdit($context, $label, $entity, $entityManager, $request);
}
#[Route(path: '/admin/user/delete/{entity}', name: 'admin_user_delete', methods: ['DELETE', 'POST'])]
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
{
return parent::delete($entity, $entityManager, $request);
}
#[Route(path: '/admin/user/resetting_request/{entity}', name: 'admin_user_resetting_request', methods: ['POST'])]
public function requestResetting(Entity $entity, EventDispatcherInterface $eventDispatcher, Request $request): Response
{
return parent::requestResetting($entity, $eventDispatcher, $request);
}
protected function getConfiguration(): CrudConfiguration
{
if ($this->configuration) {
return $this->configuration;
}
return parent::getConfiguration()
->setView('form', 'admin/user_admin/_form.html.twig')
->setView('show_entity', 'admin/user_admin/_show.html.twig')
;
}
}

View file

@ -9,11 +9,9 @@ use Doctrine\ORM\Mapping as ORM;
use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface; use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
#[ORM\Entity(repositoryClass: UserRepository::class)] #[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\HasLifecycleCallbacks] #[ORM\HasLifecycleCallbacks]
#[UniqueEntity('email')]
class User implements PasswordAuthenticatedUserInterface, UserInterface, TwoFactorInterface, EntityInterface class User implements PasswordAuthenticatedUserInterface, UserInterface, TwoFactorInterface, EntityInterface
{ {
use Timestampable; use Timestampable;

View file

@ -2,17 +2,10 @@
namespace App; namespace App;
use App\Core\DependencyInjection\Compiler\BuilderBlockPass;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class Kernel extends BaseKernel class Kernel extends BaseKernel
{ {
use MicroKernelTrait; use MicroKernelTrait;
protected function build(ContainerBuilder $container): void
{
$container->addCompilerPass(new BuilderBlockPass());
}
} }

View file

@ -1,51 +0,0 @@
<?php
namespace App\Security\Voter;
use App\Core\Entity\EntityInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;
class EntityVoter extends Voter
{
public const EDIT = 'edit';
public const VIEW = 'show';
public const DELETE = 'delete';
protected function supports(string $attribute, mixed $subject): bool
{
// replace with your own logic
// https://symfony.com/doc/current/security/voters.html
return in_array($attribute, [self::EDIT, self::VIEW, self::DELETE])
&& $subject instanceof EntityInterface;
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof UserInterface) {
return false;
}
switch ($attribute) {
case self::EDIT:
return true;
break;
case self::VIEW:
return true;
break;
case self::DELETE:
return true;
break;
}
return false;
}
}

View file

@ -1 +0,0 @@
{{ include('@Core/user/user_admin/_form.html.twig') }}

View file

@ -1 +0,0 @@
{{ include('@Core/user/user_admin/_show.html.twig') }}

View file

@ -0,0 +1,40 @@
<?php
namespace App\Tests\Core\Auth;
use App\Repository\UserRepositoryQuery;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
/**
* @internal
* @coversNothing
*/
class LoginTest extends WebTestCase
{
protected UserRepositoryQuery $query;
protected KernelBrowser $client;
protected function setUp(): void
{
$this->client = static::createClient();
$this->query = self::$container->get(UserRepositoryQuery::class);
}
public function testLoginRedirect(): void
{
$crawler = $this->client->request('GET', '/admin');
$this->assertResponseStatusCodeSame(302);
$this->client->followRedirect();
$this->assertResponseIsSuccessful();
}
public function testLoginUser(): void
{
$user = $this->query->create()->andWhere('.email=\'admin@localhost\'')->findOne();
$this->client->loginUser($user);
$this->client->request('GET', '/admin/account/');
$this->assertResponseStatusCodeSame(200);
}
}

View file

@ -0,0 +1,68 @@
<?php
namespace App\Tests\Core\Command;
use App\Repository\UserRepositoryQuery;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Tester\CommandTester;
/**
* @internal
* @coversNothing
*/
class CreateUserTest extends KernelTestCase
{
protected UserRepositoryQuery $query;
protected function setUp(): void
{
self::bootKernel();
$this->query = self::$container->get(UserRepositoryQuery::class);
}
public function testCommandExecute(): void
{
$kernel = static::createKernel();
$application = new Application($kernel);
$command = $application->find('murph:user:create');
$commandTester = new CommandTester($command);
$commandTester->setInputs([
'admin@localhost',
'admin_password',
'y',
'n',
]);
$commandTester->execute(['command' => $command->getName()]);
$output = $commandTester->getDisplay();
$this->assertStringContainsString('User created!', $output);
$commandTester->setInputs([
'writer@localhost',
'writer_password',
'n',
'y',
]);
$commandTester->execute(['command' => $command->getName()]);
$output = $commandTester->getDisplay();
$this->assertStringContainsString('User created!', $output);
}
public function testCreatedUsers(): void
{
$users = $this->query->create()->find();
$this->assertEquals(2, count($users));
$this->assertEquals('admin@localhost', $users[0]->getEmail());
$this->assertEquals('admin@localhost', $users[0]->getUsername());
$this->assertEquals('writer@localhost', $users[1]->getEmail());
$this->assertEquals('writer@localhost', $users[1]->getUsername());
$this->assertEquals(true, $users[0]->getIsAdmin());
$this->assertEquals(false, $users[0]->getIsWriter());
$this->assertEquals(false, $users[1]->getIsAdmin());
$this->assertEquals(true, $users[1]->getIsWriter());
}
}

View file

@ -0,0 +1,50 @@
<?php
namespace App\Tests\Core;
use App\Repository\UserRepositoryQuery;
use Symfony\Component\Panther\Client as PantherClient;
use Symfony\Component\Panther\PantherTestCase as BasePantherTestCase;
abstract class PantherTestCase extends BasePantherTestCase
{
protected UserRepositoryQuery $query;
protected PantherClient $client;
protected function container()
{
if (null === self::$container) {
static::bootKernel();
}
return self::$container;
}
protected function setUp(): void
{
$this->client = static::createPantherClient([
'external_base_uri' => 'http://localhost:9080'
]);
$this->query = $this->container()->get(UserRepositoryQuery::class);
}
protected function authenticateAdmin(): void
{
$this->client->request('GET', '/login');
$this->client->submitForm('Login', [
'_username' => 'admin@localhost',
'_password' => 'admin_password',
]);
$this->client->waitFor('.nav-item-label');
}
protected function authenticateWriter(): void
{
$this->client->request('GET', '/login');
$this->client->submitForm('Login', [
'_username' => 'writer@localhost',
'_password' => 'writer_password',
]);
$this->client->waitFor('.nav-item-label');
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace App\Tests\Core\Site;
use App\Tests\Core\PantherTestCase;
/**
* @internal
* @coversNothing
*/
class NavigationTest extends PantherTestCase
{
public function testCreateNavigation(): void
{
$this->authenticateAdmin();
$this->client->request('GET', '/admin/site/tree');
$this->client->waitFor('.toast-body.text-text-warning');
$this->assertSelectorTextContains('.toast-body.text-text-warning', 'You must add a navigation.');
$this->client->request('GET', '/admin/site/navigation');
$this->assertSelectorTextContains('h1', 'Navigations');
$this->client->request('GET', '/admin/site/navigation/new');
$this->assertSelectorTextContains('h1', 'New navigation');
$this->client->submitForm('Save', [
'navigation[label]' => 'Test navigation',
'navigation[locale]' => 'en',
'navigation[code]' => 'nav',
'navigation[domain]' => 'localhost',
]);
$this->client->waitFor('.toast-body.text-text-success');
$this->assertSelectorTextContains('.toast-body.text-text-success', 'The data has been saved.');
$this->client->request('GET', '/admin/site/navigation');
$this->assertSelectorTextContains('.table tbody tr td', 'Test navigation');
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace App\Tests\Core\Site;
use App\Tests\Core\PantherTestCase;
/**
* @internal
* @coversNothing
*/
class PageTest extends PantherTestCase
{
public function testCreatePage(): void
{
$this->client->request('GET', '/admin/site/tree');
$this->client->executeScript("document.querySelector('#node-2 .float-right button[data-modal]').click()");
$this->client->waitFor('#form-node-edit');
$this->client->executeScript("document.querySelector('#node-page-action .card-header label').click()");
$this->client->executeScript("document.querySelector('a[href=\"#form-node-edit-routing\"]').click()");
$this->client->executeScript("document.querySelector('#node_url').value='/foo'");
$this->client->executeScript("document.querySelector('#node_code').value='/foo'");
$this->client->executeScript("document.querySelector('.modal.show .modal-footer button[type=\"submit\"]').click()");
$this->client->waitFor('.toast-body.text-text-success');
$this->assertSelectorTextContains('.toast-body.text-text-success', 'The data has been saved.');
$this->assertSelectorTextContains('#node-2 .float-right a', 'Page');
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace App\Tests\Core\Site;
use App\Tests\Core\PantherTestCase;
/**
* @internal
* @coversNothing
*/
class TreeTest extends PantherTestCase
{
public function testCreateTree(): void
{
$this->client->request('GET', '/admin/site/tree');
$this->assertSelectorTextContains('button[data-toggle="modal"]', 'Add a menu');
$this->client->executeScript("document.querySelector('button[data-toggle=\"modal\"]').click()");
$this->client->waitFor('#form-menu-new');
$this->client->submitForm('Save', [
'menu[label]' => 'Test menu',
'menu[code]' => 'menu',
]);
$this->client->waitFor('.toast-body.text-text-success');
$this->assertSelectorTextContains('.toast-body.text-text-success', 'The data has been saved.');
$this->client->request('GET', '/admin/site/tree');
$this->assertSelectorTextContains('.h4', 'Test menu');
$this->assertSelectorTextContains('#node-2 .col-6', 'First element');
}
}

View file

@ -13,3 +13,9 @@ if (file_exists(dirname(__DIR__).'/config/bootstrap.php')) {
if ($_SERVER['APP_DEBUG']) { if ($_SERVER['APP_DEBUG']) {
umask(0000); umask(0000);
} }
passthru(sprintf(
'APP_ENV=test PHP=%s "%s/../bin/doctrine-migrate"',
$_ENV['PHP_BIN'] ?? $_ENV['PHP'] ?? 'php',
__DIR__
));

5129
yarn.lock

File diff suppressed because it is too large Load diff