vendor/symfony/maker-bundle/src/Maker/MakeTest.php line 166

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the Symfony MakerBundle package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\MakerBundle\Maker;
  11. use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase as LegacyApiTestCase;
  12. use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
  13. use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
  14. use Symfony\Bundle\FrameworkBundle\Test\WebTestAssertionsTrait;
  15. use Symfony\Bundle\MakerBundle\ConsoleStyle;
  16. use Symfony\Bundle\MakerBundle\DependencyBuilder;
  17. use Symfony\Bundle\MakerBundle\Exception\RuntimeCommandException;
  18. use Symfony\Bundle\MakerBundle\Generator;
  19. use Symfony\Bundle\MakerBundle\InputAwareMakerInterface;
  20. use Symfony\Bundle\MakerBundle\InputConfiguration;
  21. use Symfony\Bundle\MakerBundle\Validator;
  22. use Symfony\Component\BrowserKit\History;
  23. use Symfony\Component\Console\Command\Command;
  24. use Symfony\Component\Console\Input\InputArgument;
  25. use Symfony\Component\Console\Input\InputInterface;
  26. use Symfony\Component\CssSelector\CssSelectorConverter;
  27. use Symfony\Component\Panther\PantherTestCaseTrait;
  28. /**
  29. * @author Kévin Dunglas <kevin@dunglas.fr>
  30. * @author Javier Eguiluz <javier.eguiluz@gmail.com>
  31. * @author Ryan Weaver <weaverryan@gmail.com>
  32. */
  33. final class MakeTest extends AbstractMaker implements InputAwareMakerInterface
  34. {
  35. private const DESCRIPTIONS = [
  36. 'TestCase' => 'basic PHPUnit tests',
  37. 'KernelTestCase' => 'basic tests that have access to Symfony services',
  38. 'WebTestCase' => 'to run browser-like scenarios, but that don\'t execute JavaScript code',
  39. 'ApiTestCase' => 'to run API-oriented scenarios',
  40. 'PantherTestCase' => 'to run e2e scenarios, using a real-browser or HTTP client and a real web server',
  41. ];
  42. private const DOCS = [
  43. 'TestCase' => 'https://symfony.com/doc/current/testing.html#unit-tests',
  44. 'KernelTestCase' => 'https://symfony.com/doc/current/testing/database.html#functional-testing-of-a-doctrine-repository',
  45. 'WebTestCase' => 'https://symfony.com/doc/current/testing.html#functional-tests',
  46. 'ApiTestCase' => 'https://api-platform.com/docs/distribution/testing/',
  47. 'PantherTestCase' => 'https://github.com/symfony/panther#testing-usage',
  48. ];
  49. public static function getCommandName(): string
  50. {
  51. return 'make:test';
  52. }
  53. /**
  54. * @deprecated remove this method when removing make:unit-test and make:functional-test
  55. */
  56. public static function getCommandAliases(): iterable
  57. {
  58. yield 'make:unit-test';
  59. yield 'make:functional-test';
  60. }
  61. public static function getCommandDescription(): string
  62. {
  63. return 'Creates a new test class';
  64. }
  65. public function configureCommand(Command $command, InputConfiguration $inputConfig): void
  66. {
  67. $typesDesc = [];
  68. $typesHelp = [];
  69. foreach (self::DESCRIPTIONS as $type => $desc) {
  70. $typesDesc[] = sprintf('<fg=yellow>%s</> (%s)', $type, $desc);
  71. $typesHelp[] = sprintf('* <info>%s</info>: %s', $type, $desc);
  72. }
  73. $command
  74. ->addArgument('type', InputArgument::OPTIONAL, 'The type of test: '.implode(', ', $typesDesc))
  75. ->addArgument('name', InputArgument::OPTIONAL, 'The name of the test class (e.g. <fg=yellow>BlogPostTest</>)')
  76. ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeTest.txt').implode("\n", $typesHelp));
  77. $inputConfig->setArgumentAsNonInteractive('name');
  78. $inputConfig->setArgumentAsNonInteractive('type');
  79. }
  80. public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
  81. {
  82. /* @deprecated remove the following block when removing make:unit-test and make:functional-test */
  83. $this->handleDeprecatedMakerCommands($input, $io);
  84. if (null !== $type = $input->getArgument('type')) {
  85. if (!isset(self::DESCRIPTIONS[$type])) {
  86. throw new RuntimeCommandException(sprintf('The test type must be one of "%s", "%s" given.', implode('", "', array_keys(self::DESCRIPTIONS)), $type));
  87. }
  88. } else {
  89. $input->setArgument(
  90. 'type',
  91. $io->choice('Which test type would you like?', self::DESCRIPTIONS)
  92. );
  93. }
  94. if ('ApiTestCase' === $input->getArgument('type') && !class_exists(ApiTestCase::class) && !class_exists(LegacyApiTestCase::class)) {
  95. $io->warning([
  96. 'API Platform is required for this test type. Install it with',
  97. 'composer require api',
  98. ]);
  99. }
  100. if ('PantherTestCase' === $input->getArgument('type') && !trait_exists(PantherTestCaseTrait::class)) {
  101. $io->warning([
  102. 'symfony/panther is required for this test type. Install it with',
  103. 'composer require symfony/panther --dev',
  104. ]);
  105. }
  106. if (null === $input->getArgument('name')) {
  107. $io->writeln([
  108. '',
  109. 'Choose a class name for your test, like:',
  110. ' * <fg=yellow>UtilTest</> (to create tests/UtilTest.php)',
  111. ' * <fg=yellow>Service\\UtilTest</> (to create tests/Service/UtilTest.php)',
  112. ' * <fg=yellow>\\App\Tests\\Service\\UtilTest</> (to create tests/Service/UtilTest.php)',
  113. ]);
  114. $nameArgument = $command->getDefinition()->getArgument('name');
  115. $value = $io->ask($nameArgument->getDescription(), $nameArgument->getDefault(), [Validator::class, 'notBlank']);
  116. $input->setArgument($nameArgument->getName(), $value);
  117. }
  118. }
  119. public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
  120. {
  121. $testClassNameDetails = $generator->createClassNameDetails(
  122. $input->getArgument('name'),
  123. 'Tests\\',
  124. 'Test'
  125. );
  126. $type = $input->getArgument('type');
  127. $generator->generateClass(
  128. $testClassNameDetails->getFullName(),
  129. "test/$type.tpl.php",
  130. [
  131. 'web_assertions_are_available' => trait_exists(WebTestAssertionsTrait::class),
  132. 'use_legacy_container_property' => $this->useLegacyContainerProperty(),
  133. 'api_test_case_fqcn' => !class_exists(ApiTestCase::class) ? LegacyApiTestCase::class : ApiTestCase::class,
  134. ]
  135. );
  136. $generator->writeChanges();
  137. $this->writeSuccessMessage($io);
  138. $io->text([
  139. 'Next: Open your new test class and start customizing it.',
  140. sprintf('Find the documentation at <fg=yellow>%s</>', self::DOCS[$type]),
  141. ]);
  142. }
  143. public function configureDependencies(DependencyBuilder $dependencies, InputInterface $input = null): void
  144. {
  145. if (null === $input) {
  146. return;
  147. }
  148. switch ($input->getArgument('type')) {
  149. case 'WebTestCase':
  150. $dependencies->addClassDependency(
  151. History::class,
  152. 'browser-kit',
  153. true,
  154. true
  155. );
  156. $dependencies->addClassDependency(
  157. CssSelectorConverter::class,
  158. 'css-selector',
  159. true,
  160. true
  161. );
  162. return;
  163. case 'ApiTestCase':
  164. $dependencies->addClassDependency(
  165. !class_exists(ApiTestCase::class) ? LegacyApiTestCase::class : ApiTestCase::class,
  166. 'api',
  167. true,
  168. false
  169. );
  170. return;
  171. case 'PantherTestCase':
  172. $dependencies->addClassDependency(
  173. PantherTestCaseTrait::class,
  174. 'panther',
  175. true,
  176. true
  177. );
  178. return;
  179. }
  180. }
  181. /**
  182. * @deprecated
  183. */
  184. private function handleDeprecatedMakerCommands(InputInterface $input, ConsoleStyle $io): void
  185. {
  186. $currentCommand = $input->getFirstArgument();
  187. switch ($currentCommand) {
  188. case 'make:unit-test':
  189. $input->setArgument('type', 'TestCase');
  190. $io->warning('The "make:unit-test" command is deprecated, use "make:test" instead.');
  191. break;
  192. case 'make:functional-test':
  193. $input->setArgument('type', trait_exists(PantherTestCaseTrait::class) ? 'WebTestCase' : 'PantherTestCase');
  194. $io->warning('The "make:functional-test" command is deprecated, use "make:test" instead.');
  195. break;
  196. }
  197. }
  198. private function useLegacyContainerProperty(): bool
  199. {
  200. // for 5.2 and lower
  201. return !method_exists(KernelTestCase::class, 'getContainer');
  202. }
  203. }