Skip to content

Commit 15de08c

Browse files
committed
[make:security:form-login] add ability to generate tests
1 parent e7ea13d commit 15de08c

File tree

3 files changed

+133
-2
lines changed

3 files changed

+133
-2
lines changed

src/Maker/Security/MakeFormLogin.php

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@
1212
namespace Symfony\Bundle\MakerBundle\Maker\Security;
1313

1414
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
15+
use Doctrine\ORM\EntityManager;
1516
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
17+
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
1618
use Symfony\Bundle\MakerBundle\ConsoleStyle;
1719
use Symfony\Bundle\MakerBundle\DependencyBuilder;
1820
use Symfony\Bundle\MakerBundle\Exception\RuntimeCommandException;
1921
use Symfony\Bundle\MakerBundle\FileManager;
2022
use Symfony\Bundle\MakerBundle\Generator;
2123
use Symfony\Bundle\MakerBundle\InputConfiguration;
2224
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
25+
use Symfony\Bundle\MakerBundle\Maker\Common\CanGenerateTestsTrait;
2326
use Symfony\Bundle\MakerBundle\Security\InteractiveSecurityHelper;
2427
use Symfony\Bundle\MakerBundle\Security\SecurityConfigUpdater;
2528
use Symfony\Bundle\MakerBundle\Security\SecurityControllerBuilder;
@@ -33,6 +36,7 @@
3336
use Symfony\Component\Console\Command\Command;
3437
use Symfony\Component\Console\Input\InputInterface;
3538
use Symfony\Component\HttpFoundation\Response;
39+
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
3640
use Symfony\Component\Routing\Attribute\Route;
3741
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
3842
use Symfony\Component\Yaml\Yaml;
@@ -48,10 +52,13 @@
4852
*/
4953
final class MakeFormLogin extends AbstractMaker
5054
{
55+
use CanGenerateTestsTrait;
56+
5157
private const SECURITY_CONFIG_PATH = 'config/packages/security.yaml';
5258
private YamlSourceManipulator $ysm;
5359
private string $controllerName;
5460
private string $firewallToUpdate;
61+
private string $userClass;
5562
private string $userNameField;
5663
private bool $willLogout;
5764

@@ -70,6 +77,8 @@ public static function getCommandName(): string
7077
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
7178
{
7279
$command->setHelp(file_get_contents(\dirname(__DIR__, 2).'/Resources/help/security/MakeFormLogin.txt'));
80+
81+
$this->configureCommandWithTestsOption($command);
7382
}
7483

7584
public static function getCommandDescription(): string
@@ -116,9 +125,11 @@ public function interact(InputInterface $input, ConsoleStyle $io, Command $comma
116125

117126
$securityHelper = new InteractiveSecurityHelper();
118127
$this->firewallToUpdate = $securityHelper->guessFirewallName($io, $securityData);
119-
$userClass = $securityHelper->guessUserClass($io, $securityData['security']['providers']);
120-
$this->userNameField = $securityHelper->guessUserNameField($io, $userClass, $securityData['security']['providers']);
128+
$this->userClass = $securityHelper->guessUserClass($io, $securityData['security']['providers']);
129+
$this->userNameField = $securityHelper->guessUserNameField($io, $this->userClass, $securityData['security']['providers']);
121130
$this->willLogout = $io->confirm('Do you want to generate a \'/logout\' URL?');
131+
132+
$this->interactSetGenerateTests($input, $io);
122133
}
123134

124135
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
@@ -167,6 +178,39 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
167178
$securityData = $this->securityConfigUpdater->updateForLogout($securityData, $this->firewallToUpdate);
168179
}
169180

181+
if ($this->shouldGenerateTests()) {
182+
$testClassDetails = $generator->createClassNameDetails(
183+
'LoginControllerTest',
184+
'Test\\',
185+
);
186+
187+
$useStatements = new UseStatementGenerator([
188+
sprintf('\%s', $this->userClass),
189+
// $userClassNameDetails->getFullName(),
190+
// $userRepositoryDetails->getFullName(),
191+
EntityManager::class,
192+
WebTestCase::class,
193+
UserPasswordHasherInterface::class,
194+
]);
195+
196+
$generator->generateFile(
197+
targetPath: sprintf('tests/%s.php', $testClassDetails->getShortName()),
198+
templateName: 'security/formLogin/Test.LoginController.tpl.php',
199+
variables: [
200+
'use_statements' => $useStatements,
201+
'user_class' => $this->userClass,
202+
// 'user_short_name' => $userClassNameDetails->getShortName(),
203+
// 'user_repo_short_name' => $userRepositoryDetails->getShortName(),
204+
// 'success_route_path' => null !== $this->controllerResetSuccessRoute ? $this->controllerResetSuccessRoute->getPath() : '/',
205+
// 'from_email' => $this->fromEmailAddress,
206+
],
207+
);
208+
209+
if (!class_exists(WebTestCase::class)) {
210+
$io->caution('You\'ll need to install the `symfony/test-pack` to execute the tests for your new controller.');
211+
}
212+
}
213+
170214
$generator->dumpFile(self::SECURITY_CONFIG_PATH, $securityData);
171215

172216
$generator->writeChanges();
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?= "<?php\n" ?>
2+
namespace App\Tests;
3+
4+
<?= $use_statements ?>
5+
6+
class LoginControllerTest extends WebTestCase
7+
{
8+
public function testRegister(): void
9+
{
10+
$client = static::createClient();
11+
$client->disableReboot();
12+
$container = static::getContainer();
13+
$em = $container->get('doctrine.orm.entity_manager');
14+
$userRepository = $em->getRepository(\<?= $user_class ?>::class);
15+
16+
foreach ($userRepository->findAll() as $user) {
17+
$em->remove($user);
18+
}
19+
20+
$em->flush();
21+
22+
self::assertCount(0, $userRepository->findAll());
23+
24+
// Ensure login with invalid credentials shows error message
25+
$client->request('GET', '/login');
26+
self::assertResponseIsSuccessful();
27+
28+
$client->submitForm('Sign in', [
29+
'_username' => '[email protected]',
30+
'_password' => 'password',
31+
]);
32+
33+
self::assertResponseRedirects('/login');
34+
35+
$client->followRedirect();
36+
37+
self::assertSelectorTextContains('.alert-danger', 'Invalid credentials.');
38+
39+
// Ensure login with valid credentials
40+
/** @var UserPasswordHasherInterface $passwordHasher */
41+
$passwordHasher = (static::getContainer())->get('security.user_password_hasher');
42+
43+
$user = (new User())->setEmail('[email protected]');
44+
$user->setPassword($passwordHasher->hashPassword($user, 'password'));
45+
46+
$em->persist($user);
47+
$em->flush();
48+
49+
$client->submitForm('Sign in', [
50+
'_username' => '[email protected]',
51+
'_password' => 'password',
52+
]);
53+
54+
self::assertResponseRedirects('/');
55+
$client->followRedirect();
56+
self::assertSelectorNotExists('.alert-danger');
57+
self::assertResponseIsSuccessful();
58+
}
59+
}

tests/Maker/Security/MakeFormLoginTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,34 @@ public function getTestDetails(): \Generator
9999
$this->assertSame('app_logout', $securityConfig['security']['firewalls']['main']['logout']['path']);
100100
}),
101101
];
102+
103+
yield 'generates_form_login_using_defaults_with_test' => [$this->createMakerTest()
104+
->run(function (MakerTestRunner $runner) {
105+
$this->makeUser($runner);
106+
107+
$output = $runner->runMaker([
108+
'SecurityController', // Controller Name
109+
'y', // Generate Logout,
110+
'y', // Generate tests
111+
]);
112+
113+
$this->assertStringContainsString('Success', $output);
114+
$fixturePath = \dirname(__DIR__, 2).'/fixtures/security/make-form-login/expected';
115+
116+
$this->assertFileEquals($fixturePath.'/SecurityController.php', $runner->getPath('src/Controller/SecurityController.php'));
117+
$this->assertFileEquals($fixturePath.'/login.html.twig', $runner->getPath('templates/security/login.html.twig'));
118+
119+
$securityConfig = $runner->readYaml('config/packages/security.yaml');
120+
121+
$this->assertSame('app_login', $securityConfig['security']['firewalls']['main']['form_login']['login_path']);
122+
$this->assertSame('app_login', $securityConfig['security']['firewalls']['main']['form_login']['check_path']);
123+
$this->assertTrue($securityConfig['security']['firewalls']['main']['form_login']['enable_csrf']);
124+
$this->assertSame('app_logout', $securityConfig['security']['firewalls']['main']['logout']['path']);
125+
126+
$runner->configureDatabase();
127+
$runner->runTests();
128+
}),
129+
];
102130
}
103131

104132
private function runLoginTest(MakerTestRunner $runner): void

0 commit comments

Comments
 (0)