init
This commit is contained in:
57
vendor/codeception/base/src/Codeception/Command/Bootstrap.php
vendored
Normal file
57
vendor/codeception/base/src/Codeception/Command/Bootstrap.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Template\Bootstrap as BootstrapTemplate;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Creates default config, tests directory and sample suites for current project.
|
||||
* Use this command to start building a test suite.
|
||||
*
|
||||
* By default it will create 3 suites **acceptance**, **functional**, and **unit**.
|
||||
*
|
||||
* * `codecept bootstrap` - creates `tests` dir and `codeception.yml` in current dir.
|
||||
* * `codecept bootstrap --empty` - creates `tests` dir without suites
|
||||
* * `codecept bootstrap --namespace Frontend` - creates tests, and use `Frontend` namespace for actor classes and helpers.
|
||||
* * `codecept bootstrap --actor Wizard` - sets actor as Wizard, to have `TestWizard` actor in tests.
|
||||
* * `codecept bootstrap path/to/the/project` - provide different path to a project, where tests should be placed
|
||||
*
|
||||
*/
|
||||
class Bootstrap extends Command
|
||||
{
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition(
|
||||
[
|
||||
new InputArgument('path', InputArgument::OPTIONAL, 'custom installation dir', null),
|
||||
new InputOption(
|
||||
'namespace',
|
||||
'ns',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Namespace to add for actor classes and helpers'
|
||||
),
|
||||
new InputOption('actor', 'a', InputOption::VALUE_OPTIONAL, 'Custom actor instead of Tester'),
|
||||
new InputOption('empty', 'e', InputOption::VALUE_NONE, 'Don\'t create standard suites')
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return "Creates default test suites and generates all required files";
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$bootstrap = new BootstrapTemplate($input, $output);
|
||||
if ($input->getArgument('path')) {
|
||||
$bootstrap->initDir($input->getArgument('path'));
|
||||
}
|
||||
$bootstrap->setup();
|
||||
}
|
||||
}
|
||||
108
vendor/codeception/base/src/Codeception/Command/Build.php
vendored
Normal file
108
vendor/codeception/base/src/Codeception/Command/Build.php
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Generator\Actions as ActionsGenerator;
|
||||
use Codeception\Lib\Generator\Actor as ActorGenerator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Generates Actor classes (initially Guy classes) from suite configs.
|
||||
* Starting from Codeception 2.0 actor classes are auto-generated. Use this command to generate them manually.
|
||||
*
|
||||
* * `codecept build`
|
||||
* * `codecept build path/to/project`
|
||||
*
|
||||
*/
|
||||
class Build extends Command
|
||||
{
|
||||
use Shared\Config;
|
||||
use Shared\FileSystem;
|
||||
|
||||
protected $inheritedMethodTemplate = ' * @method void %s(%s)';
|
||||
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates base classes for all suites';
|
||||
}
|
||||
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
$this->buildActorsForConfig();
|
||||
}
|
||||
|
||||
private function buildActor(array $settings)
|
||||
{
|
||||
$actorGenerator = new ActorGenerator($settings);
|
||||
$this->output->writeln(
|
||||
'<info>' . Configuration::config()['namespace'] . '\\' . $actorGenerator->getActorName()
|
||||
. "</info> includes modules: " . implode(', ', $actorGenerator->getModules())
|
||||
);
|
||||
|
||||
$content = $actorGenerator->produce();
|
||||
|
||||
$file = $this->createDirectoryFor(
|
||||
Configuration::supportDir(),
|
||||
$settings['actor']
|
||||
) . $this->getShortClassName($settings['actor']);
|
||||
$file .= '.php';
|
||||
return $this->createFile($file, $content);
|
||||
}
|
||||
|
||||
private function buildActions(array $settings)
|
||||
{
|
||||
$actionsGenerator = new ActionsGenerator($settings);
|
||||
$this->output->writeln(
|
||||
" -> {$settings['actor']}Actions.php generated successfully. "
|
||||
. $actionsGenerator->getNumMethods() . " methods added"
|
||||
);
|
||||
|
||||
$content = $actionsGenerator->produce();
|
||||
|
||||
$file = $this->createDirectoryFor(Configuration::supportDir() . '_generated', $settings['actor']);
|
||||
$file .= $this->getShortClassName($settings['actor']) . 'Actions.php';
|
||||
return $this->createFile($file, $content, true);
|
||||
}
|
||||
|
||||
private function buildSuiteActors()
|
||||
{
|
||||
$suites = $this->getSuites();
|
||||
if (!empty($suites)) {
|
||||
$this->output->writeln("<info>Building Actor classes for suites: " . implode(', ', $suites) . '</info>');
|
||||
}
|
||||
foreach ($suites as $suite) {
|
||||
$settings = $this->getSuiteConfig($suite);
|
||||
if (!$settings['actor']) {
|
||||
continue; // no actor
|
||||
}
|
||||
$this->buildActions($settings);
|
||||
$actorBuilt = $this->buildActor($settings);
|
||||
|
||||
if ($actorBuilt) {
|
||||
$this->output->writeln("{$settings['actor']}.php created.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function buildActorsForConfig($configFile = null)
|
||||
{
|
||||
$config = $this->getGlobalConfig($configFile);
|
||||
|
||||
$dir = Configuration::projectDir();
|
||||
$this->buildSuiteActors();
|
||||
|
||||
foreach ($config['include'] as $subConfig) {
|
||||
$this->output->writeln("\n<comment>Included Configuration: $subConfig</comment>");
|
||||
$this->buildActorsForConfig($dir . DIRECTORY_SEPARATOR . $subConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
vendor/codeception/base/src/Codeception/Command/Clean.php
vendored
Normal file
45
vendor/codeception/base/src/Codeception/Command/Clean.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Util\FileSystem;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Recursively cleans `output` directory and generated code.
|
||||
*
|
||||
* * `codecept clean`
|
||||
*
|
||||
*/
|
||||
class Clean extends Command
|
||||
{
|
||||
use Shared\Config;
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Recursively cleans log and generated code';
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$projectDir = Configuration::projectDir();
|
||||
$this->cleanProjectsRecursively($output, $projectDir);
|
||||
$output->writeln("Done");
|
||||
}
|
||||
|
||||
private function cleanProjectsRecursively(OutputInterface $output, $projectDir)
|
||||
{
|
||||
$logDir = Configuration::logDir();
|
||||
$output->writeln("<info>Cleaning up output " . $logDir . "...</info>");
|
||||
FileSystem::doEmptyDir($logDir);
|
||||
|
||||
$config = Configuration::config($projectDir);
|
||||
$subProjects = $config['include'];
|
||||
foreach ($subProjects as $subProject) {
|
||||
$subProjectDir = $projectDir . $subProject;
|
||||
$this->cleanProjectsRecursively($output, $subProjectDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
84
vendor/codeception/base/src/Codeception/Command/Completion.php
vendored
Normal file
84
vendor/codeception/base/src/Codeception/Command/Completion.php
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
if (!class_exists('Stecman\Component\Symfony\Console\BashCompletion\Completion')) {
|
||||
echo "Please install `stecman/symfony-console-completion\n` to enable auto completion";
|
||||
return;
|
||||
}
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Stecman\Component\Symfony\Console\BashCompletion\Completion as ConsoleCompletion;
|
||||
use Stecman\Component\Symfony\Console\BashCompletion\CompletionCommand;
|
||||
use Stecman\Component\Symfony\Console\BashCompletion\CompletionHandler;
|
||||
use Stecman\Component\Symfony\Console\BashCompletion\Completion\ShellPathCompletion as ShellPathCompletion;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Completion extends CompletionCommand
|
||||
{
|
||||
protected function configureCompletion(CompletionHandler $handler)
|
||||
{
|
||||
// Can't set for all commands, because it wouldn't work well with generate:suite
|
||||
$suiteCommands = [
|
||||
'run',
|
||||
'config:validate',
|
||||
'console',
|
||||
'dry-run',
|
||||
'generate:cept',
|
||||
'generate:cest',
|
||||
'generate:feature',
|
||||
'generate:phpunit',
|
||||
'generate:scenarios',
|
||||
'generate:stepobject',
|
||||
'generate:test',
|
||||
'gherkin:snippets',
|
||||
'gherkin:steps'
|
||||
];
|
||||
|
||||
foreach ($suiteCommands as $suiteCommand) {
|
||||
$handler->addHandler(new ConsoleCompletion(
|
||||
$suiteCommand,
|
||||
'suite',
|
||||
ConsoleCompletion::TYPE_ARGUMENT,
|
||||
Configuration::suites()
|
||||
));
|
||||
}
|
||||
|
||||
$handler->addHandlers([
|
||||
new ShellPathCompletion(
|
||||
ConsoleCompletion::ALL_COMMANDS,
|
||||
'path',
|
||||
ConsoleCompletion::TYPE_ARGUMENT
|
||||
),
|
||||
new ShellPathCompletion(
|
||||
ConsoleCompletion::ALL_COMMANDS,
|
||||
'test',
|
||||
ConsoleCompletion::TYPE_ARGUMENT
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($input->getOption('generate-hook') && $input->getOption('use-vendor-bin')) {
|
||||
global $argv;
|
||||
$argv[0] = 'vendor/bin/' . basename($argv[0]);
|
||||
}
|
||||
|
||||
parent::execute($input, $output);
|
||||
}
|
||||
|
||||
protected function createDefinition()
|
||||
{
|
||||
$definition = parent::createDefinition();
|
||||
$definition->addOption(new InputOption(
|
||||
'use-vendor-bin',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'Use the vendor bin for autocompletion.'
|
||||
));
|
||||
|
||||
return $definition;
|
||||
}
|
||||
}
|
||||
40
vendor/codeception/base/src/Codeception/Command/CompletionFallback.php
vendored
Normal file
40
vendor/codeception/base/src/Codeception/Command/CompletionFallback.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Stecman\Component\Symfony\Console\BashCompletion\Completion as ConsoleCompletion;
|
||||
use Stecman\Component\Symfony\Console\BashCompletion\CompletionCommand;
|
||||
use Stecman\Component\Symfony\Console\BashCompletion\CompletionHandler;
|
||||
use Stecman\Component\Symfony\Console\BashCompletion\Completion\ShellPathCompletion as ShellPathCompletion;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class CompletionFallback extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('_completion')
|
||||
->setDescription('BASH completion hook.')
|
||||
->setHelp(<<<END
|
||||
To enable BASH completion, install optional stecman/symfony-console-completion first:
|
||||
|
||||
<comment>composer require stecman/symfony-console-completion</comment>
|
||||
|
||||
END
|
||||
);
|
||||
|
||||
// Hide this command from listing if supported
|
||||
// Command::setHidden() was not available before Symfony 3.2.0
|
||||
if (method_exists($this, 'setHidden')) {
|
||||
$this->setHidden(true);
|
||||
}
|
||||
}
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln("Install optional <comment>stecman/symfony-console-completion</comment>");
|
||||
}
|
||||
}
|
||||
105
vendor/codeception/base/src/Codeception/Command/ConfigValidate.php
vendored
Normal file
105
vendor/codeception/base/src/Codeception/Command/ConfigValidate.php
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Validates and prints Codeception config.
|
||||
* Use it do debug Yaml configs
|
||||
*
|
||||
* Check config:
|
||||
*
|
||||
* * `codecept config`: check global config
|
||||
* * `codecept config unit`: check suite config
|
||||
*
|
||||
* Load config:
|
||||
*
|
||||
* * `codecept config:validate -c path/to/another/config`: from another dir
|
||||
* * `codecept config:validate -c another_config.yml`: from another config file
|
||||
*
|
||||
* Check overriding config values (like in `run` command)
|
||||
*
|
||||
* * `codecept config:validate -o "settings: shuffle: true"`: enable shuffle
|
||||
* * `codecept config:validate -o "settings: lint: false"`: disable linting
|
||||
* * `codecept config:validate -o "reporters: report: \Custom\Reporter" --report`: use custom reporter
|
||||
*
|
||||
*/
|
||||
class ConfigValidate extends Command
|
||||
{
|
||||
use Shared\Config;
|
||||
use Shared\Style;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition(
|
||||
[
|
||||
new InputArgument('suite', InputArgument::OPTIONAL, 'to show suite configuration'),
|
||||
new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
|
||||
new InputOption('override', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Override config values'),
|
||||
]
|
||||
);
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Validates and prints config to screen';
|
||||
}
|
||||
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->addStyles($output);
|
||||
|
||||
if ($suite = $input->getArgument('suite')) {
|
||||
$output->write("Validating <bold>$suite</bold> config... ");
|
||||
$config = $this->getSuiteConfig($suite, $input->getOption('config'));
|
||||
$output->writeln("Ok");
|
||||
$output->writeln("------------------------------\n");
|
||||
$output->writeln("<info>$suite Suite Config</info>:\n");
|
||||
$output->writeln($this->formatOutput($config));
|
||||
return;
|
||||
}
|
||||
|
||||
$output->write("Validating global config... ");
|
||||
$config = $this->getGlobalConfig();
|
||||
$output->writeln($input->getOption('override'));
|
||||
if (count($input->getOption('override'))) {
|
||||
$config = $this->overrideConfig($input->getOption('override'));
|
||||
}
|
||||
$suites = Configuration::suites();
|
||||
$output->writeln("Ok");
|
||||
|
||||
$output->writeln("------------------------------\n");
|
||||
$output->writeln("<info>Codeception Config</info>:\n");
|
||||
$output->writeln($this->formatOutput($config));
|
||||
|
||||
$output->writeln('<info>Directories</info>:');
|
||||
$output->writeln("<comment>codecept_root_dir()</comment> " . codecept_root_dir());
|
||||
$output->writeln("<comment>codecept_output_dir()</comment> " . codecept_output_dir());
|
||||
$output->writeln("<comment>codecept_data_dir()</comment> " . codecept_data_dir());
|
||||
$output->writeln('');
|
||||
|
||||
$output->writeln("<info>Available suites</info>: " . implode(', ', $suites));
|
||||
|
||||
foreach ($suites as $suite) {
|
||||
$output->write("Validating suite <bold>$suite</bold>... ");
|
||||
$this->getSuiteConfig($suite);
|
||||
$output->writeln('Ok');
|
||||
}
|
||||
|
||||
|
||||
$output->writeln("Execute <info>codecept config:validate [<suite>]</info> to see config for a suite");
|
||||
}
|
||||
|
||||
protected function formatOutput($config)
|
||||
{
|
||||
$output = print_r($config, true);
|
||||
return preg_replace('~\[(.*?)\] =>~', "<fg=yellow>$1</fg=yellow> =>", $output);
|
||||
}
|
||||
}
|
||||
159
vendor/codeception/base/src/Codeception/Command/Console.php
vendored
Normal file
159
vendor/codeception/base/src/Codeception/Command/Console.php
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Codecept;
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Event\SuiteEvent;
|
||||
use Codeception\Event\TestEvent;
|
||||
use Codeception\Events;
|
||||
use Codeception\Exception\ConfigurationException;
|
||||
use Codeception\Lib\Console\Output;
|
||||
use Codeception\Scenario;
|
||||
use Codeception\SuiteManager;
|
||||
use Codeception\Test\Cept;
|
||||
use Codeception\Util\Debug;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
|
||||
/**
|
||||
* Try to execute test commands in run-time. You may try commands before writing the test.
|
||||
*
|
||||
* * `codecept console acceptance` - starts acceptance suite environment. If you use WebDriver you can manipulate browser with Codeception commands.
|
||||
*/
|
||||
class Console extends Command
|
||||
{
|
||||
protected $test;
|
||||
protected $codecept;
|
||||
protected $suite;
|
||||
protected $output;
|
||||
protected $actions = [];
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'suite to be executed'),
|
||||
new InputOption('colors', '', InputOption::VALUE_NONE, 'Use colors in output'),
|
||||
]);
|
||||
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Launches interactive test console';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$suiteName = $input->getArgument('suite');
|
||||
$this->output = $output;
|
||||
|
||||
$config = Configuration::config();
|
||||
$settings = Configuration::suiteSettings($suiteName, $config);
|
||||
|
||||
$options = $input->getOptions();
|
||||
$options['debug'] = true;
|
||||
$options['silent'] = true;
|
||||
$options['interactive'] = false;
|
||||
$options['colors'] = true;
|
||||
|
||||
Debug::setOutput(new Output($options));
|
||||
|
||||
$this->codecept = new Codecept($options);
|
||||
$dispatcher = $this->codecept->getDispatcher();
|
||||
|
||||
$suiteManager = new SuiteManager($dispatcher, $suiteName, $settings);
|
||||
$suiteManager->initialize();
|
||||
$this->suite = $suiteManager->getSuite();
|
||||
$moduleContainer = $suiteManager->getModuleContainer();
|
||||
|
||||
$this->actions = array_keys($moduleContainer->getActions());
|
||||
|
||||
$this->test = new Cept(null, null);
|
||||
$this->test->getMetadata()->setServices([
|
||||
'dispatcher' => $dispatcher,
|
||||
'modules' => $moduleContainer
|
||||
]);
|
||||
|
||||
$scenario = new Scenario($this->test);
|
||||
if (!$settings['actor']) {
|
||||
throw new ConfigurationException("Interactive shell can't be started without an actor");
|
||||
}
|
||||
if (isset($config["namespace"])) {
|
||||
$settings['actor'] = $config["namespace"] .'\\' . $settings['actor'];
|
||||
}
|
||||
$actor = $settings['actor'];
|
||||
$I = new $actor($scenario);
|
||||
|
||||
$this->listenToSignals();
|
||||
|
||||
$output->writeln("<info>Interactive console started for suite $suiteName</info>");
|
||||
$output->writeln("<info>Try Codeception commands without writing a test</info>");
|
||||
$output->writeln("<info>type 'exit' to leave console</info>");
|
||||
$output->writeln("<info>type 'actions' to see all available actions for this suite</info>");
|
||||
|
||||
$suiteEvent = new SuiteEvent($this->suite, $this->codecept->getResult(), $settings);
|
||||
$dispatcher->dispatch(Events::SUITE_BEFORE, $suiteEvent);
|
||||
|
||||
$dispatcher->dispatch(Events::TEST_PARSED, new TestEvent($this->test));
|
||||
$dispatcher->dispatch(Events::TEST_BEFORE, new TestEvent($this->test));
|
||||
|
||||
$output->writeln("\n\n<comment>\$I</comment> = new {$settings['actor']}(\$scenario);");
|
||||
$this->executeCommands($input, $output, $I, $settings['bootstrap']);
|
||||
|
||||
$dispatcher->dispatch(Events::TEST_AFTER, new TestEvent($this->test));
|
||||
$dispatcher->dispatch(Events::SUITE_AFTER, new SuiteEvent($this->suite));
|
||||
|
||||
$output->writeln("<info>Bye-bye!</info>");
|
||||
}
|
||||
|
||||
protected function executeCommands(InputInterface $input, OutputInterface $output, $I, $bootstrap)
|
||||
{
|
||||
$dialog = new QuestionHelper();
|
||||
|
||||
if (file_exists($bootstrap)) {
|
||||
require $bootstrap;
|
||||
}
|
||||
|
||||
do {
|
||||
$question = new Question("<comment>\$I-></comment>");
|
||||
$question->setAutocompleterValues($this->actions);
|
||||
|
||||
$command = $dialog->ask($input, $output, $question);
|
||||
if ($command == 'actions') {
|
||||
$output->writeln("<info>" . implode(' ', $this->actions));
|
||||
continue;
|
||||
}
|
||||
if ($command == 'exit') {
|
||||
return;
|
||||
}
|
||||
if ($command == '') {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$value = eval("return \$I->$command;");
|
||||
if ($value && !is_object($value)) {
|
||||
codecept_debug($value);
|
||||
}
|
||||
} catch (\PHPUnit\Framework\AssertionFailedError $fail) {
|
||||
$output->writeln("<error>fail</error> " . $fail->getMessage());
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>error</error> " . $e->getMessage());
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
protected function listenToSignals()
|
||||
{
|
||||
if (function_exists('pcntl_signal')) {
|
||||
declare (ticks = 1);
|
||||
pcntl_signal(SIGINT, SIG_IGN);
|
||||
pcntl_signal(SIGTERM, SIG_IGN);
|
||||
}
|
||||
}
|
||||
}
|
||||
134
vendor/codeception/base/src/Codeception/Command/DryRun.php
vendored
Normal file
134
vendor/codeception/base/src/Codeception/Command/DryRun.php
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Event\SuiteEvent;
|
||||
use Codeception\Event\TestEvent;
|
||||
use Codeception\Events;
|
||||
use Codeception\Subscriber\Bootstrap as BootstrapLoader;
|
||||
use Codeception\Subscriber\Console as ConsolePrinter;
|
||||
use Codeception\SuiteManager;
|
||||
use Codeception\Test\Interfaces\ScenarioDriven;
|
||||
use Codeception\Test\Test;
|
||||
use Codeception\Util\Maybe;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
|
||||
/**
|
||||
* Shows step by step execution process for scenario driven tests without actually running them.
|
||||
*
|
||||
* * `codecept dry-run acceptance`
|
||||
* * `codecept dry-run acceptance MyCest`
|
||||
* * `codecept dry-run acceptance checkout.feature`
|
||||
* * `codecept dry-run tests/acceptance/MyCest.php`
|
||||
*
|
||||
*/
|
||||
class DryRun extends Command
|
||||
{
|
||||
use Shared\Config;
|
||||
use Shared\Style;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition(
|
||||
[
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'suite to scan for feature files'),
|
||||
new InputArgument('test', InputArgument::OPTIONAL, 'tests to be loaded'),
|
||||
]
|
||||
);
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Prints step-by-step scenario-driven test or a feature';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->addStyles($output);
|
||||
$suite = $input->getArgument('suite');
|
||||
$test = $input->getArgument('test');
|
||||
|
||||
$config = $this->getGlobalConfig();
|
||||
if (! Configuration::isEmpty() && ! $test && strpos($suite, $config['paths']['tests']) === 0) {
|
||||
list(, $suite, $test) = $this->matchTestFromFilename($suite, $config['paths']['tests']);
|
||||
}
|
||||
$settings = $this->getSuiteConfig($suite);
|
||||
|
||||
$dispatcher = new EventDispatcher();
|
||||
$dispatcher->addSubscriber(new ConsolePrinter([
|
||||
'colors' => !$input->getOption('no-ansi'),
|
||||
'steps' => true,
|
||||
'verbosity' => OutputInterface::VERBOSITY_VERBOSE,
|
||||
]));
|
||||
$dispatcher->addSubscriber(new BootstrapLoader());
|
||||
|
||||
$suiteManager = new SuiteManager($dispatcher, $suite, $settings);
|
||||
$moduleContainer = $suiteManager->getModuleContainer();
|
||||
foreach (Configuration::modules($settings) as $module) {
|
||||
$moduleContainer->mock($module, new Maybe());
|
||||
}
|
||||
$suiteManager->loadTests($test);
|
||||
$tests = $suiteManager->getSuite()->tests();
|
||||
|
||||
$dispatcher->dispatch(Events::SUITE_INIT, new SuiteEvent($suiteManager->getSuite(), null, $settings));
|
||||
$dispatcher->dispatch(Events::SUITE_BEFORE, new SuiteEvent($suiteManager->getSuite(), null, $settings));
|
||||
foreach ($tests as $test) {
|
||||
if ($test instanceof \PHPUnit\Framework\TestSuite\DataProvider) {
|
||||
foreach ($test as $t) {
|
||||
if ($t instanceof Test) {
|
||||
$this->dryRunTest($output, $dispatcher, $t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($test instanceof Test and $test instanceof ScenarioDriven) {
|
||||
$this->dryRunTest($output, $dispatcher, $test);
|
||||
}
|
||||
}
|
||||
$dispatcher->dispatch(Events::SUITE_AFTER, new SuiteEvent($suiteManager->getSuite()));
|
||||
}
|
||||
|
||||
|
||||
protected function matchTestFromFilename($filename, $tests_path)
|
||||
{
|
||||
$filename = str_replace(['//', '\/', '\\'], '/', $filename);
|
||||
$res = preg_match("~^$tests_path/(.*?)/(.*)$~", $filename, $matches);
|
||||
if (!$res) {
|
||||
throw new \InvalidArgumentException("Test file can't be matched");
|
||||
}
|
||||
|
||||
return $matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputInterface $output
|
||||
* @param $dispatcher
|
||||
* @param $test
|
||||
*/
|
||||
protected function dryRunTest(OutputInterface $output, EventDispatcher $dispatcher, Test $test)
|
||||
{
|
||||
$dispatcher->dispatch(Events::TEST_START, new TestEvent($test));
|
||||
$dispatcher->dispatch(Events::TEST_BEFORE, new TestEvent($test));
|
||||
try {
|
||||
$test->test();
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
$dispatcher->dispatch(Events::TEST_AFTER, new TestEvent($test));
|
||||
$dispatcher->dispatch(Events::TEST_END, new TestEvent($test));
|
||||
if ($test->getMetadata()->isBlocked()) {
|
||||
$output->writeln('');
|
||||
if ($skip = $test->getMetadata()->getSkip()) {
|
||||
$output->writeln("<warning> SKIPPED </warning>" . $skip);
|
||||
}
|
||||
if ($incomplete = $test->getMetadata()->getIncomplete()) {
|
||||
$output->writeln("<warning> INCOMPLETE </warning>" . $incomplete);
|
||||
}
|
||||
}
|
||||
$output->writeln('');
|
||||
}
|
||||
}
|
||||
55
vendor/codeception/base/src/Codeception/Command/GenerateCept.php
vendored
Normal file
55
vendor/codeception/base/src/Codeception/Command/GenerateCept.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Lib\Generator\Cept;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Generates Cept (scenario-driven test) file:
|
||||
*
|
||||
* * `codecept generate:cept suite Login`
|
||||
* * `codecept g:cept suite subdir/subdir/testnameCept.php`
|
||||
* * `codecept g:cept suite LoginCept -c path/to/project`
|
||||
*
|
||||
*/
|
||||
class GenerateCept extends Command
|
||||
{
|
||||
use Shared\FileSystem;
|
||||
use Shared\Config;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'suite to be tested'),
|
||||
new InputArgument('test', InputArgument::REQUIRED, 'test to be run'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates empty Cept file in suite';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$suite = $input->getArgument('suite');
|
||||
$filename = $input->getArgument('test');
|
||||
|
||||
$config = $this->getSuiteConfig($suite);
|
||||
$this->createDirectoryFor($config['path'], $filename);
|
||||
|
||||
$filename = $this->completeSuffix($filename, 'Cept');
|
||||
$gen = new Cept($config);
|
||||
|
||||
$full_path = rtrim($config['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename;
|
||||
$res = $this->createFile($full_path, $gen->produce());
|
||||
if (!$res) {
|
||||
$output->writeln("<error>Test $filename already exists</error>");
|
||||
return;
|
||||
}
|
||||
$output->writeln("<info>Test was created in $full_path</info>");
|
||||
}
|
||||
}
|
||||
62
vendor/codeception/base/src/Codeception/Command/GenerateCest.php
vendored
Normal file
62
vendor/codeception/base/src/Codeception/Command/GenerateCest.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Lib\Generator\Cest as CestGenerator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Generates Cest (scenario-driven object-oriented test) file:
|
||||
*
|
||||
* * `codecept generate:cest suite Login`
|
||||
* * `codecept g:cest suite subdir/subdir/testnameCest.php`
|
||||
* * `codecept g:cest suite LoginCest -c path/to/project`
|
||||
* * `codecept g:cest "App\Login"`
|
||||
*
|
||||
*/
|
||||
class GenerateCest extends Command
|
||||
{
|
||||
use Shared\FileSystem;
|
||||
use Shared\Config;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'suite where tests will be put'),
|
||||
new InputArgument('class', InputArgument::REQUIRED, 'test name'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates empty Cest file in suite';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$suite = $input->getArgument('suite');
|
||||
$class = $input->getArgument('class');
|
||||
|
||||
$config = $this->getSuiteConfig($suite);
|
||||
$className = $this->getShortClassName($class);
|
||||
$path = $this->createDirectoryFor($config['path'], $class);
|
||||
|
||||
$filename = $this->completeSuffix($className, 'Cest');
|
||||
$filename = $path . $filename;
|
||||
|
||||
if (file_exists($filename)) {
|
||||
$output->writeln("<error>Test $filename already exists</error>");
|
||||
return;
|
||||
}
|
||||
$gen = new CestGenerator($class, $config);
|
||||
$res = $this->createFile($filename, $gen->produce());
|
||||
if (!$res) {
|
||||
$output->writeln("<error>Test $filename already exists</error>");
|
||||
return;
|
||||
}
|
||||
|
||||
$output->writeln("<info>Test was created in $filename</info>");
|
||||
}
|
||||
}
|
||||
58
vendor/codeception/base/src/Codeception/Command/GenerateEnvironment.php
vendored
Normal file
58
vendor/codeception/base/src/Codeception/Command/GenerateEnvironment.php
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Exception\ConfigurationException;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Generates empty environment configuration file into envs dir:
|
||||
*
|
||||
* * `codecept g:env firefox`
|
||||
*
|
||||
* Required to have `envs` path to be specified in `codeception.yml`
|
||||
*/
|
||||
class GenerateEnvironment extends Command
|
||||
{
|
||||
use Shared\FileSystem;
|
||||
use Shared\Config;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('env', InputArgument::REQUIRED, 'Environment name'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates empty environment config';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$conf = $this->getGlobalConfig();
|
||||
if (!Configuration::envsDir()) {
|
||||
throw new ConfigurationException(
|
||||
"Path for environments configuration is not set.\n"
|
||||
. "Please specify envs path in your `codeception.yml`\n \n"
|
||||
. "envs: tests/_envs"
|
||||
);
|
||||
}
|
||||
$relativePath = $conf['paths']['envs'];
|
||||
$env = $input->getArgument('env');
|
||||
$file = "$env.yml";
|
||||
|
||||
$path = $this->createDirectoryFor($relativePath, $file);
|
||||
$saved = $this->createFile($path . $file, "# `$env` environment config goes here");
|
||||
|
||||
if ($saved) {
|
||||
$output->writeln("<info>$env config was created in $relativePath/$file</info>");
|
||||
} else {
|
||||
$output->writeln("<error>File $relativePath/$file already exists</error>");
|
||||
}
|
||||
}
|
||||
}
|
||||
58
vendor/codeception/base/src/Codeception/Command/GenerateFeature.php
vendored
Normal file
58
vendor/codeception/base/src/Codeception/Command/GenerateFeature.php
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Lib\Generator\Feature;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Generates Feature file (in Gherkin):
|
||||
*
|
||||
* * `codecept generate:feature suite Login`
|
||||
* * `codecept g:feature suite subdir/subdir/login.feature`
|
||||
* * `codecept g:feature suite login.feature -c path/to/project`
|
||||
*
|
||||
*/
|
||||
class GenerateFeature extends Command
|
||||
{
|
||||
use Shared\FileSystem;
|
||||
use Shared\Config;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'suite to be tested'),
|
||||
new InputArgument('feature', InputArgument::REQUIRED, 'feature to be generated'),
|
||||
new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates empty feature file in suite';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$suite = $input->getArgument('suite');
|
||||
$filename = $input->getArgument('feature');
|
||||
|
||||
$config = $this->getSuiteConfig($suite);
|
||||
$this->createDirectoryFor($config['path'], $filename);
|
||||
|
||||
$gen = new Feature(basename($filename));
|
||||
if (!preg_match('~\.feature$~', $filename)) {
|
||||
$filename .= '.feature';
|
||||
}
|
||||
$full_path = rtrim($config['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename;
|
||||
$res = $this->createFile($full_path, $gen->produce());
|
||||
if (!$res) {
|
||||
$output->writeln("<error>Feature $filename already exists</error>");
|
||||
return;
|
||||
}
|
||||
$output->writeln("<info>Feature was created in $full_path</info>");
|
||||
}
|
||||
}
|
||||
56
vendor/codeception/base/src/Codeception/Command/GenerateGroup.php
vendored
Normal file
56
vendor/codeception/base/src/Codeception/Command/GenerateGroup.php
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Generator\Group as GroupGenerator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Creates empty GroupObject - extension which handles all group events.
|
||||
*
|
||||
* * `codecept g:group Admin`
|
||||
*/
|
||||
class GenerateGroup extends Command
|
||||
{
|
||||
use Shared\FileSystem;
|
||||
use Shared\Config;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('group', InputArgument::REQUIRED, 'Group class name'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates Group subscriber';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$config = $this->getGlobalConfig();
|
||||
$group = $input->getArgument('group');
|
||||
|
||||
$class = ucfirst($group);
|
||||
$path = $this->createDirectoryFor(Configuration::supportDir() . 'Group' . DIRECTORY_SEPARATOR, $class);
|
||||
|
||||
$filename = $path . $class . '.php';
|
||||
|
||||
$gen = new GroupGenerator($config, $group);
|
||||
$res = $this->createFile($filename, $gen->produce());
|
||||
|
||||
if (!$res) {
|
||||
$output->writeln("<error>Group $filename already exists</error>");
|
||||
return;
|
||||
}
|
||||
|
||||
$output->writeln("<info>Group extension was created in $filename</info>");
|
||||
$output->writeln(
|
||||
'To use this group extension, include it to "extensions" option of global Codeception config.'
|
||||
);
|
||||
}
|
||||
}
|
||||
50
vendor/codeception/base/src/Codeception/Command/GenerateHelper.php
vendored
Normal file
50
vendor/codeception/base/src/Codeception/Command/GenerateHelper.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Generator\Helper;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Creates empty Helper class.
|
||||
*
|
||||
* * `codecept g:helper MyHelper`
|
||||
* * `codecept g:helper "My\Helper"`
|
||||
*
|
||||
*/
|
||||
class GenerateHelper extends Command
|
||||
{
|
||||
use Shared\FileSystem;
|
||||
use Shared\Config;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('name', InputArgument::REQUIRED, 'helper name'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates new helper';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$name = ucfirst($input->getArgument('name'));
|
||||
$config = $this->getGlobalConfig();
|
||||
|
||||
$path = $this->createDirectoryFor(Configuration::supportDir() . 'Helper', $name);
|
||||
$filename = $path . $this->getShortClassName($name) . '.php';
|
||||
|
||||
$res = $this->createFile($filename, (new Helper($name, $config['namespace']))->produce());
|
||||
if ($res) {
|
||||
$output->writeln("<info>Helper $filename created</info>");
|
||||
} else {
|
||||
$output->writeln("<error>Error creating helper $filename</error>");
|
||||
}
|
||||
}
|
||||
}
|
||||
75
vendor/codeception/base/src/Codeception/Command/GeneratePageObject.php
vendored
Normal file
75
vendor/codeception/base/src/Codeception/Command/GeneratePageObject.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Generator\PageObject as PageObjectGenerator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Generates PageObject. Can be generated either globally, or just for one suite.
|
||||
* If PageObject is generated globally it will act as UIMap, without any logic in it.
|
||||
*
|
||||
* * `codecept g:page Login`
|
||||
* * `codecept g:page Registration`
|
||||
* * `codecept g:page acceptance Login`
|
||||
*/
|
||||
class GeneratePageObject extends Command
|
||||
{
|
||||
use Shared\FileSystem;
|
||||
use Shared\Config;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'Either suite name or page object name)'),
|
||||
new InputArgument('page', InputArgument::OPTIONAL, 'Page name of pageobject to represent'),
|
||||
]);
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates empty PageObject class';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$suite = $input->getArgument('suite');
|
||||
$class = $input->getArgument('page');
|
||||
|
||||
if (!$class) {
|
||||
$class = $suite;
|
||||
$suite = null;
|
||||
}
|
||||
|
||||
$conf = $suite
|
||||
? $this->getSuiteConfig($suite)
|
||||
: $this->getGlobalConfig();
|
||||
|
||||
if ($suite) {
|
||||
$suite = DIRECTORY_SEPARATOR . ucfirst($suite);
|
||||
}
|
||||
|
||||
$path = $this->createDirectoryFor(Configuration::supportDir() . 'Page' . $suite, $class);
|
||||
|
||||
$filename = $path . $this->getShortClassName($class) . '.php';
|
||||
|
||||
$output->writeln($filename);
|
||||
|
||||
$gen = new PageObjectGenerator($conf, ucfirst($suite) . '\\' . $class);
|
||||
$res = $this->createFile($filename, $gen->produce());
|
||||
|
||||
if (!$res) {
|
||||
$output->writeln("<error>PageObject $filename already exists</error>");
|
||||
exit;
|
||||
}
|
||||
$output->writeln("<info>PageObject was created in $filename</info>");
|
||||
}
|
||||
|
||||
protected function pathToPageObject($class, $suite)
|
||||
{
|
||||
}
|
||||
}
|
||||
142
vendor/codeception/base/src/Codeception/Command/GenerateScenarios.php
vendored
Normal file
142
vendor/codeception/base/src/Codeception/Command/GenerateScenarios.php
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Exception\ConfigurationException as ConfigurationException;
|
||||
use Codeception\Test\Cest;
|
||||
use Codeception\Test\Interfaces\ScenarioDriven;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
|
||||
/**
|
||||
* Generates user-friendly text scenarios from scenario-driven tests (Cest, Cept).
|
||||
*
|
||||
* * `codecept g:scenarios acceptance` - for all acceptance tests
|
||||
* * `codecept g:scenarios acceptance --format html` - in html format
|
||||
* * `codecept g:scenarios acceptance --path doc` - generate scenarios to `doc` dir
|
||||
*/
|
||||
class GenerateScenarios extends Command
|
||||
{
|
||||
use Shared\FileSystem;
|
||||
use Shared\Config;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'suite from which texts should be generated'),
|
||||
new InputOption('path', 'p', InputOption::VALUE_REQUIRED, 'Use specified path as destination instead of default'),
|
||||
new InputOption('single-file', '', InputOption::VALUE_NONE, 'Render all scenarios to only one file'),
|
||||
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Specify output format: html or text (default)', 'text'),
|
||||
]);
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates text representation for all scenarios';
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$suite = $input->getArgument('suite');
|
||||
|
||||
$suiteConf = $this->getSuiteConfig($suite);
|
||||
|
||||
$path = $input->getOption('path')
|
||||
? $input->getOption('path')
|
||||
: Configuration::dataDir() . 'scenarios';
|
||||
|
||||
$format = $input->getOption('format');
|
||||
|
||||
@mkdir($path);
|
||||
|
||||
if (!is_writable($path)) {
|
||||
throw new ConfigurationException(
|
||||
"Path $path is not writable. Please, set valid permissions for folder to store scenarios."
|
||||
);
|
||||
}
|
||||
|
||||
$path = $path . DIRECTORY_SEPARATOR . $suite;
|
||||
if (!$input->getOption('single-file')) {
|
||||
@mkdir($path);
|
||||
}
|
||||
|
||||
$suiteManager = new \Codeception\SuiteManager(new EventDispatcher(), $suite, $suiteConf);
|
||||
|
||||
if ($suiteConf['bootstrap']) {
|
||||
if (file_exists($suiteConf['path'] . $suiteConf['bootstrap'])) {
|
||||
require_once $suiteConf['path'] . $suiteConf['bootstrap'];
|
||||
}
|
||||
}
|
||||
|
||||
$tests = $this->getTests($suiteManager);
|
||||
$scenarios = "";
|
||||
|
||||
foreach ($tests as $test) {
|
||||
if (!($test instanceof ScenarioDriven)) {
|
||||
continue;
|
||||
}
|
||||
$feature = $test->getScenarioText($format);
|
||||
|
||||
$name = $this->underscore(basename($test->getFileName(), '.php'));
|
||||
|
||||
// create separate file for each test in Cest
|
||||
if ($test instanceof Cest && !$input->getOption('single-file')) {
|
||||
$name .= '.' . $this->underscore($test->getTestMethod());
|
||||
}
|
||||
|
||||
if ($input->getOption('single-file')) {
|
||||
$scenarios .= $feature;
|
||||
$output->writeln("* $name rendered");
|
||||
} else {
|
||||
$feature = $this->decorate($feature, $format);
|
||||
$this->createFile($path . DIRECTORY_SEPARATOR . $name . $this->formatExtension($format), $feature, true);
|
||||
$output->writeln("* $name generated");
|
||||
}
|
||||
}
|
||||
|
||||
if ($input->getOption('single-file')) {
|
||||
$this->createFile($path . $this->formatExtension($format), $this->decorate($scenarios, $format), true);
|
||||
}
|
||||
}
|
||||
|
||||
protected function decorate($text, $format)
|
||||
{
|
||||
switch ($format) {
|
||||
case 'text':
|
||||
return $text;
|
||||
case 'html':
|
||||
return "<html><body>$text</body></html>";
|
||||
}
|
||||
}
|
||||
|
||||
protected function getTests($suiteManager)
|
||||
{
|
||||
$suiteManager->loadTests();
|
||||
return $suiteManager->getSuite()->tests();
|
||||
}
|
||||
|
||||
protected function formatExtension($format)
|
||||
{
|
||||
switch ($format) {
|
||||
case 'text':
|
||||
return '.txt';
|
||||
case 'html':
|
||||
return '.html';
|
||||
}
|
||||
}
|
||||
|
||||
private function underscore($name)
|
||||
{
|
||||
$name = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\\1_\\2', $name);
|
||||
$name = preg_replace('/([a-z\d])([A-Z])/', '\\1_\\2', $name);
|
||||
$name = str_replace(['/', '\\'], ['.', '.'], $name);
|
||||
$name = preg_replace('/_Cept$/', '', $name);
|
||||
$name = preg_replace('/_Cest$/', '', $name);
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
75
vendor/codeception/base/src/Codeception/Command/GenerateStepObject.php
vendored
Normal file
75
vendor/codeception/base/src/Codeception/Command/GenerateStepObject.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Generator\StepObject as StepObjectGenerator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
|
||||
/**
|
||||
* Generates StepObject class. You will be asked for steps you want to implement.
|
||||
*
|
||||
* * `codecept g:stepobject acceptance AdminSteps`
|
||||
* * `codecept g:stepobject acceptance UserSteps --silent` - skip action questions
|
||||
*
|
||||
*/
|
||||
class GenerateStepObject extends Command
|
||||
{
|
||||
use Shared\FileSystem;
|
||||
use Shared\Config;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'Suite for StepObject'),
|
||||
new InputArgument('step', InputArgument::REQUIRED, 'StepObject name'),
|
||||
new InputOption('silent', '', InputOption::VALUE_NONE, 'skip verification question'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates empty StepObject class';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$suite = $input->getArgument('suite');
|
||||
$step = $input->getArgument('step');
|
||||
$config = $this->getSuiteConfig($suite);
|
||||
|
||||
$class = $this->getShortClassName($step);
|
||||
|
||||
$path = $this->createDirectoryFor(Configuration::supportDir() . 'Step' . DIRECTORY_SEPARATOR . ucfirst($suite), $step);
|
||||
|
||||
$dialog = $this->getHelperSet()->get('question');
|
||||
$filename = $path . $class . '.php';
|
||||
|
||||
$helper = $this->getHelper('question');
|
||||
$question = new Question("Add action to StepObject class (ENTER to exit): ");
|
||||
|
||||
$gen = new StepObjectGenerator($config, ucfirst($suite) . '\\' . $step);
|
||||
|
||||
if (!$input->getOption('silent')) {
|
||||
do {
|
||||
$question = new Question('Add action to StepObject class (ENTER to exit): ', null);
|
||||
$action = $dialog->ask($input, $output, $question);
|
||||
if ($action) {
|
||||
$gen->createAction($action);
|
||||
}
|
||||
} while ($action);
|
||||
}
|
||||
|
||||
$res = $this->createFile($filename, $gen->produce());
|
||||
|
||||
if (!$res) {
|
||||
$output->writeln("<error>StepObject $filename already exists</error>");
|
||||
exit;
|
||||
}
|
||||
$output->writeln("<info>StepObject was created in $filename</info>");
|
||||
}
|
||||
}
|
||||
134
vendor/codeception/base/src/Codeception/Command/GenerateSuite.php
vendored
Normal file
134
vendor/codeception/base/src/Codeception/Command/GenerateSuite.php
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Generator\Helper;
|
||||
use Codeception\Util\Template;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Codeception\Lib\Generator\Actor as ActorGenerator;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* Create new test suite. Requires suite name and actor name
|
||||
*
|
||||
* * ``
|
||||
* * `codecept g:suite api` -> api + ApiTester
|
||||
* * `codecept g:suite integration Code` -> integration + CodeTester
|
||||
* * `codecept g:suite frontend Front` -> frontend + FrontTester
|
||||
*
|
||||
*/
|
||||
class GenerateSuite extends Command
|
||||
{
|
||||
use Shared\FileSystem;
|
||||
use Shared\Config;
|
||||
use Shared\Style;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'suite to be generated'),
|
||||
new InputArgument('actor', InputArgument::OPTIONAL, 'name of new actor class'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates new test suite';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->addStyles($output);
|
||||
$suite = $input->getArgument('suite');
|
||||
$actor = $input->getArgument('actor');
|
||||
|
||||
if ($this->containsInvalidCharacters($suite)) {
|
||||
$output->writeln("<error>Suite name '$suite' contains invalid characters. ([A-Za-z0-9_]).</error>");
|
||||
return;
|
||||
}
|
||||
|
||||
$config = $this->getGlobalConfig();
|
||||
if (!$actor) {
|
||||
$actor = ucfirst($suite) . $config['actor_suffix'];
|
||||
}
|
||||
|
||||
$dir = Configuration::testsDir();
|
||||
if (file_exists($dir . $suite . '.suite.yml')) {
|
||||
throw new \Exception("Suite configuration file '$suite.suite.yml' already exists.");
|
||||
}
|
||||
|
||||
$this->createDirectoryFor($dir . $suite);
|
||||
|
||||
if ($config['settings']['bootstrap']) {
|
||||
// generate bootstrap file
|
||||
$this->createFile(
|
||||
$dir . $suite . DIRECTORY_SEPARATOR . $config['settings']['bootstrap'],
|
||||
"<?php\n",
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
$helperName = ucfirst($suite);
|
||||
|
||||
$file = $this->createDirectoryFor(
|
||||
Configuration::supportDir() . "Helper",
|
||||
"$helperName.php"
|
||||
) . "$helperName.php";
|
||||
|
||||
$gen = new Helper($helperName, $config['namespace']);
|
||||
// generate helper
|
||||
$this->createFile(
|
||||
$file,
|
||||
$gen->produce()
|
||||
);
|
||||
|
||||
$output->writeln("Helper <info>" . $gen->getHelperName() . "</info> was created in $file");
|
||||
|
||||
$yamlSuiteConfigTemplate = <<<EOF
|
||||
actor: {{actor}}
|
||||
modules:
|
||||
enabled:
|
||||
- {{helper}}
|
||||
EOF;
|
||||
|
||||
$this->createFile(
|
||||
$dir . $suite . '.suite.yml',
|
||||
$yamlSuiteConfig = (new Template($yamlSuiteConfigTemplate))
|
||||
->place('actor', $actor)
|
||||
->place('helper', $gen->getHelperName())
|
||||
->produce()
|
||||
);
|
||||
|
||||
Configuration::append(Yaml::parse($yamlSuiteConfig));
|
||||
$actorGenerator = new ActorGenerator(Configuration::config());
|
||||
|
||||
$content = $actorGenerator->produce();
|
||||
|
||||
$file = $this->createDirectoryFor(
|
||||
Configuration::supportDir(),
|
||||
$actor
|
||||
) . $this->getShortClassName($actor);
|
||||
$file .= '.php';
|
||||
|
||||
$this->createFile($file, $content);
|
||||
|
||||
$output->writeln("Actor <info>" . $actor . "</info> was created in $file");
|
||||
|
||||
$output->writeln("Suite config <info>$suite.suite.yml</info> was created.");
|
||||
$output->writeln(' ');
|
||||
$output->writeln("Next steps:");
|
||||
$output->writeln("1. Edit <bold>$suite.suite.yml</bold> to enable modules for this suite");
|
||||
$output->writeln("2. Create first test with <bold>generate:cest testName</bold> ( or test|cept) command");
|
||||
$output->writeln("3. Run tests of this suite with <bold>codecept run $suite</bold> command");
|
||||
|
||||
$output->writeln("<info>Suite $suite generated</info>");
|
||||
}
|
||||
|
||||
private function containsInvalidCharacters($suite)
|
||||
{
|
||||
return preg_match('#[^A-Za-z0-9_]#', $suite) ? true : false;
|
||||
}
|
||||
}
|
||||
60
vendor/codeception/base/src/Codeception/Command/GenerateTest.php
vendored
Normal file
60
vendor/codeception/base/src/Codeception/Command/GenerateTest.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Lib\Generator\Test as TestGenerator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Generates skeleton for Unit Test that extends `Codeception\TestCase\Test`.
|
||||
*
|
||||
* * `codecept g:test unit User`
|
||||
* * `codecept g:test unit "App\User"`
|
||||
*/
|
||||
class GenerateTest extends Command
|
||||
{
|
||||
use Shared\FileSystem;
|
||||
use Shared\Config;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition(
|
||||
[
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'suite where tests will be put'),
|
||||
new InputArgument('class', InputArgument::REQUIRED, 'class name'),
|
||||
]
|
||||
);
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Generates empty unit test file in suite';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$suite = $input->getArgument('suite');
|
||||
$class = $input->getArgument('class');
|
||||
|
||||
$config = $this->getSuiteConfig($suite);
|
||||
|
||||
$className = $this->getShortClassName($class);
|
||||
$path = $this->createDirectoryFor($config['path'], $class);
|
||||
|
||||
$filename = $this->completeSuffix($className, 'Test');
|
||||
$filename = $path . $filename;
|
||||
|
||||
$gen = new TestGenerator($config, $class);
|
||||
|
||||
$res = $this->createFile($filename, $gen->produce());
|
||||
|
||||
if (!$res) {
|
||||
$output->writeln("<error>Test $filename already exists</error>");
|
||||
return;
|
||||
}
|
||||
$output->writeln("<info>Test was created in $filename</info>");
|
||||
}
|
||||
}
|
||||
72
vendor/codeception/base/src/Codeception/Command/GherkinSnippets.php
vendored
Normal file
72
vendor/codeception/base/src/Codeception/Command/GherkinSnippets.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Lib\Generator\GherkinSnippets as SnippetsGenerator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Generates code snippets for matched feature files in a suite.
|
||||
* Code snippets are expected to be implemented in Actor or PageObjects
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* * `codecept gherkin:snippets acceptance` - snippets from all feature of acceptance tests
|
||||
* * `codecept gherkin:snippets acceptance/feature/users` - snippets from `feature/users` dir of acceptance tests
|
||||
* * `codecept gherkin:snippets acceptance user_account.feature` - snippets from a single feature file
|
||||
* * `codecept gherkin:snippets acceptance/feature/users/user_accout.feature` - snippets from feature file in a dir
|
||||
*/
|
||||
class GherkinSnippets extends Command
|
||||
{
|
||||
use Shared\Config;
|
||||
use Shared\Style;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition(
|
||||
[
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'suite to scan for feature files'),
|
||||
new InputArgument('test', InputArgument::OPTIONAL, 'test to be scanned'),
|
||||
new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
|
||||
]
|
||||
);
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Fetches empty steps from feature files of suite and prints code snippets for them';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->addStyles($output);
|
||||
$suite = $input->getArgument('suite');
|
||||
$test = $input->getArgument('test');
|
||||
$config = $this->getSuiteConfig($suite);
|
||||
|
||||
$generator = new SnippetsGenerator($config, $test);
|
||||
$snippets = $generator->getSnippets();
|
||||
$features = $generator->getFeatures();
|
||||
|
||||
if (empty($snippets)) {
|
||||
$output->writeln("<notice> All Gherkin steps are defined. Exiting... </notice>");
|
||||
return;
|
||||
}
|
||||
$output->writeln("<comment> Snippets found in: </comment>");
|
||||
foreach ($features as $feature) {
|
||||
$output->writeln("<info> - {$feature} </info>");
|
||||
}
|
||||
$output->writeln("<comment> Generated Snippets: </comment>");
|
||||
$output->writeln("<info> ----------------------------------------- </info>");
|
||||
foreach ($snippets as $snippet) {
|
||||
$output->writeln($snippet);
|
||||
}
|
||||
$output->writeln("<info> ----------------------------------------- </info>");
|
||||
$output->writeln(sprintf(' <bold>%d</bold> snippets proposed', count($snippets)));
|
||||
$output->writeln("<notice> Copy generated snippets to {$config['actor']} or a specific Gherkin context </notice>");
|
||||
}
|
||||
}
|
||||
71
vendor/codeception/base/src/Codeception/Command/GherkinSteps.php
vendored
Normal file
71
vendor/codeception/base/src/Codeception/Command/GherkinSteps.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Test\Loader\Gherkin;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Prints all steps from all Gherkin contexts for a specific suite
|
||||
*
|
||||
* ```
|
||||
* codecept gherkin:steps acceptance
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
class GherkinSteps extends Command
|
||||
{
|
||||
use Shared\Config;
|
||||
use Shared\Style;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition(
|
||||
[
|
||||
new InputArgument('suite', InputArgument::REQUIRED, 'suite to scan for feature files'),
|
||||
new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
|
||||
]
|
||||
);
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Prints all defined feature steps';
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->addStyles($output);
|
||||
$suite = $input->getArgument('suite');
|
||||
$config = $this->getSuiteConfig($suite);
|
||||
$config['describe_steps'] = true;
|
||||
|
||||
$loader = new Gherkin($config);
|
||||
$steps = $loader->getSteps();
|
||||
|
||||
foreach ($steps as $name => $context) {
|
||||
/** @var $table Table **/
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Step', 'Implementation']);
|
||||
$output->writeln("Steps from <bold>$name</bold> context:");
|
||||
|
||||
foreach ($context as $step => $callable) {
|
||||
if (count($callable) < 2) {
|
||||
continue;
|
||||
}
|
||||
$method = $callable[0] . '::' . $callable[1];
|
||||
$table->addRow([$step, $method]);
|
||||
}
|
||||
$table->render();
|
||||
}
|
||||
|
||||
if (!isset($table)) {
|
||||
$output->writeln("No steps are defined, start creating them by running <bold>gherkin:snippets</bold>");
|
||||
}
|
||||
}
|
||||
}
|
||||
55
vendor/codeception/base/src/Codeception/Command/Init.php
vendored
Normal file
55
vendor/codeception/base/src/Codeception/Command/Init.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\InitTemplate;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Init extends Command
|
||||
{
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition(
|
||||
[
|
||||
new InputArgument('template', InputArgument::REQUIRED, 'Init template for the setup'),
|
||||
new InputOption('path', null, InputOption::VALUE_REQUIRED, 'Change current directory', null),
|
||||
new InputOption('namespace', null, InputOption::VALUE_OPTIONAL, 'Namespace to add for actor classes and helpers\'', null),
|
||||
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return "Creates test suites by a template";
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$template = $input->getArgument('template');
|
||||
|
||||
if (class_exists($template)) {
|
||||
$className = $template;
|
||||
} else {
|
||||
$className = 'Codeception\Template\\' . ucfirst($template);
|
||||
|
||||
if (!class_exists($className)) {
|
||||
throw new \Exception("Template from a $className can't be loaded; Init can't be executed");
|
||||
}
|
||||
}
|
||||
|
||||
$initProcess = new $className($input, $output);
|
||||
if (!$initProcess instanceof InitTemplate) {
|
||||
throw new \Exception("$className is not a valid template");
|
||||
}
|
||||
if ($input->getOption('path')) {
|
||||
$initProcess->initDir($input->getOption('path'));
|
||||
}
|
||||
$initProcess->setup();
|
||||
}
|
||||
}
|
||||
558
vendor/codeception/base/src/Codeception/Command/Run.php
vendored
Normal file
558
vendor/codeception/base/src/Codeception/Command/Run.php
vendored
Normal file
@@ -0,0 +1,558 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Codeception\Codecept;
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Util\PathResolver;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Executes tests.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* * `codecept run acceptance`: run all acceptance tests
|
||||
* * `codecept run tests/acceptance/MyCept.php`: run only MyCept
|
||||
* * `codecept run acceptance MyCept`: same as above
|
||||
* * `codecept run acceptance MyCest:myTestInIt`: run one test from a Cest
|
||||
* * `codecept run acceptance checkout.feature`: run feature-file
|
||||
* * `codecept run acceptance -g slow`: run tests from *slow* group
|
||||
* * `codecept run unit,functional`: run only unit and functional suites
|
||||
*
|
||||
* Verbosity modes:
|
||||
*
|
||||
* * `codecept run -v`:
|
||||
* * `codecept run --steps`: print step-by-step execution
|
||||
* * `codecept run -vv`:
|
||||
* * `codecept run --debug`: print steps and debug information
|
||||
* * `codecept run -vvv`: print internal debug information
|
||||
*
|
||||
* Load config:
|
||||
*
|
||||
* * `codecept run -c path/to/another/config`: from another dir
|
||||
* * `codecept run -c another_config.yml`: from another config file
|
||||
*
|
||||
* Override config values:
|
||||
*
|
||||
* * `codecept run -o "settings: shuffle: true"`: enable shuffle
|
||||
* * `codecept run -o "settings: lint: false"`: disable linting
|
||||
* * `codecept run -o "reporters: report: \Custom\Reporter" --report`: use custom reporter
|
||||
*
|
||||
* Run with specific extension
|
||||
*
|
||||
* * `codecept run --ext Recorder` run with Recorder extension enabled
|
||||
* * `codecept run --ext DotReporter` run with DotReporter printer
|
||||
* * `codecept run --ext "My\Custom\Extension"` run with an extension loaded by class name
|
||||
*
|
||||
* Full reference:
|
||||
* ```
|
||||
* Arguments:
|
||||
* suite suite to be tested
|
||||
* test test to be run
|
||||
*
|
||||
* Options:
|
||||
* -o, --override=OVERRIDE Override config values (multiple values allowed)
|
||||
* --config (-c) Use custom path for config
|
||||
* --report Show output in compact style
|
||||
* --html Generate html with results (default: "report.html")
|
||||
* --xml Generate JUnit XML Log (default: "report.xml")
|
||||
* --tap Generate Tap Log (default: "report.tap.log")
|
||||
* --json Generate Json Log (default: "report.json")
|
||||
* --colors Use colors in output
|
||||
* --no-colors Force no colors in output (useful to override config file)
|
||||
* --silent Only outputs suite names and final results
|
||||
* --steps Show steps in output
|
||||
* --debug (-d) Show debug and scenario output
|
||||
* --coverage Run with code coverage (default: "coverage.serialized")
|
||||
* --coverage-html Generate CodeCoverage HTML report in path (default: "coverage")
|
||||
* --coverage-xml Generate CodeCoverage XML report in file (default: "coverage.xml")
|
||||
* --coverage-text Generate CodeCoverage text report in file (default: "coverage.txt")
|
||||
* --coverage-phpunit Generate CodeCoverage PHPUnit report in file (default: "coverage-phpunit")
|
||||
* --no-exit Don't finish with exit code
|
||||
* --group (-g) Groups of tests to be executed (multiple values allowed)
|
||||
* --skip (-s) Skip selected suites (multiple values allowed)
|
||||
* --skip-group (-x) Skip selected groups (multiple values allowed)
|
||||
* --env Run tests in selected environments. (multiple values allowed, environments can be merged with ',')
|
||||
* --fail-fast (-f) Stop after first failure
|
||||
* --help (-h) Display this help message.
|
||||
* --quiet (-q) Do not output any message.
|
||||
* --verbose (-v|vv|vvv) Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
|
||||
* --version (-V) Display this application version.
|
||||
* --ansi Force ANSI output.
|
||||
* --no-ansi Disable ANSI output.
|
||||
* --no-interaction (-n) Do not ask any interactive question.
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
class Run extends Command
|
||||
{
|
||||
use Shared\Config;
|
||||
/**
|
||||
* @var Codecept
|
||||
*/
|
||||
protected $codecept;
|
||||
|
||||
/**
|
||||
* @var integer of executed suites
|
||||
*/
|
||||
protected $executed = 0;
|
||||
|
||||
/**
|
||||
* @var array of options (command run)
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
|
||||
/**
|
||||
* Sets Run arguments
|
||||
* @throws \Symfony\Component\Console\Exception\InvalidArgumentException
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument('suite', InputArgument::OPTIONAL, 'suite to be tested'),
|
||||
new InputArgument('test', InputArgument::OPTIONAL, 'test to be run'),
|
||||
new InputOption('override', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Override config values'),
|
||||
new InputOption('ext', 'e', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Run with extension enabled'),
|
||||
new InputOption('report', '', InputOption::VALUE_NONE, 'Show output in compact style'),
|
||||
new InputOption('html', '', InputOption::VALUE_OPTIONAL, 'Generate html with results', 'report.html'),
|
||||
new InputOption('xml', '', InputOption::VALUE_OPTIONAL, 'Generate JUnit XML Log', 'report.xml'),
|
||||
new InputOption('tap', '', InputOption::VALUE_OPTIONAL, 'Generate Tap Log', 'report.tap.log'),
|
||||
new InputOption('json', '', InputOption::VALUE_OPTIONAL, 'Generate Json Log', 'report.json'),
|
||||
new InputOption('colors', '', InputOption::VALUE_NONE, 'Use colors in output'),
|
||||
new InputOption(
|
||||
'no-colors',
|
||||
'',
|
||||
InputOption::VALUE_NONE,
|
||||
'Force no colors in output (useful to override config file)'
|
||||
),
|
||||
new InputOption('silent', '', InputOption::VALUE_NONE, 'Only outputs suite names and final results'),
|
||||
new InputOption('steps', '', InputOption::VALUE_NONE, 'Show steps in output'),
|
||||
new InputOption('debug', 'd', InputOption::VALUE_NONE, 'Show debug and scenario output'),
|
||||
new InputOption(
|
||||
'coverage',
|
||||
'',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Run with code coverage'
|
||||
),
|
||||
new InputOption(
|
||||
'coverage-html',
|
||||
'',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Generate CodeCoverage HTML report in path'
|
||||
),
|
||||
new InputOption(
|
||||
'coverage-xml',
|
||||
'',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Generate CodeCoverage XML report in file'
|
||||
),
|
||||
new InputOption(
|
||||
'coverage-text',
|
||||
'',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Generate CodeCoverage text report in file'
|
||||
),
|
||||
new InputOption(
|
||||
'coverage-crap4j',
|
||||
'',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Generate CodeCoverage report in Crap4J XML format'
|
||||
),
|
||||
new InputOption(
|
||||
'coverage-phpunit',
|
||||
'',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Generate CodeCoverage PHPUnit report in path'
|
||||
),
|
||||
new InputOption('no-exit', '', InputOption::VALUE_NONE, 'Don\'t finish with exit code'),
|
||||
new InputOption(
|
||||
'group',
|
||||
'g',
|
||||
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
|
||||
'Groups of tests to be executed'
|
||||
),
|
||||
new InputOption(
|
||||
'skip',
|
||||
's',
|
||||
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
|
||||
'Skip selected suites'
|
||||
),
|
||||
new InputOption(
|
||||
'skip-group',
|
||||
'x',
|
||||
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
|
||||
'Skip selected groups'
|
||||
),
|
||||
new InputOption(
|
||||
'env',
|
||||
'',
|
||||
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
|
||||
'Run tests in selected environments.'
|
||||
),
|
||||
new InputOption('fail-fast', 'f', InputOption::VALUE_NONE, 'Stop after first failure'),
|
||||
new InputOption('no-rebuild', '', InputOption::VALUE_NONE, 'Do not rebuild actor classes on start'),
|
||||
]);
|
||||
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Runs the test suites';
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes Run
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @return int|null|void
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->ensureCurlIsAvailable();
|
||||
$this->options = $input->getOptions();
|
||||
$this->output = $output;
|
||||
|
||||
// load config
|
||||
$config = $this->getGlobalConfig();
|
||||
|
||||
// update config from options
|
||||
if (count($this->options['override'])) {
|
||||
$config = $this->overrideConfig($this->options['override']);
|
||||
}
|
||||
if ($this->options['ext']) {
|
||||
$config = $this->enableExtensions($this->options['ext']);
|
||||
}
|
||||
|
||||
if (!$this->options['colors']) {
|
||||
$this->options['colors'] = $config['settings']['colors'];
|
||||
}
|
||||
if (!$this->options['silent']) {
|
||||
$this->output->writeln(
|
||||
Codecept::versionString() . "\nPowered by " . \PHPUnit\Runner\Version::getVersionString()
|
||||
);
|
||||
}
|
||||
if ($this->options['debug']) {
|
||||
$this->output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
|
||||
}
|
||||
|
||||
$userOptions = array_intersect_key($this->options, array_flip($this->passedOptionKeys($input)));
|
||||
$userOptions = array_merge(
|
||||
$userOptions,
|
||||
$this->booleanOptions($input, [
|
||||
'xml' => 'report.xml',
|
||||
'html' => 'report.html',
|
||||
'json' => 'report.json',
|
||||
'tap' => 'report.tap.log',
|
||||
'coverage' => 'coverage.serialized',
|
||||
'coverage-xml' => 'coverage.xml',
|
||||
'coverage-html' => 'coverage',
|
||||
'coverage-text' => 'coverage.txt',
|
||||
'coverage-crap4j' => 'crap4j.xml',
|
||||
'coverage-phpunit' => 'coverage-phpunit'])
|
||||
);
|
||||
$userOptions['verbosity'] = $this->output->getVerbosity();
|
||||
$userOptions['interactive'] = !$input->hasParameterOption(['--no-interaction', '-n']);
|
||||
$userOptions['ansi'] = (!$input->hasParameterOption('--no-ansi') xor $input->hasParameterOption('ansi'));
|
||||
|
||||
if ($this->options['no-colors'] || !$userOptions['ansi']) {
|
||||
$userOptions['colors'] = false;
|
||||
}
|
||||
if ($this->options['group']) {
|
||||
$userOptions['groups'] = $this->options['group'];
|
||||
}
|
||||
if ($this->options['skip-group']) {
|
||||
$userOptions['excludeGroups'] = $this->options['skip-group'];
|
||||
}
|
||||
if ($this->options['report']) {
|
||||
$userOptions['silent'] = true;
|
||||
}
|
||||
if ($this->options['coverage-xml'] or $this->options['coverage-html'] or $this->options['coverage-text'] or $this->options['coverage-crap4j'] or $this->options['coverage-phpunit']) {
|
||||
$this->options['coverage'] = true;
|
||||
}
|
||||
if (!$userOptions['ansi'] && $input->getOption('colors')) {
|
||||
$userOptions['colors'] = true; // turn on colors even in non-ansi mode if strictly passed
|
||||
}
|
||||
|
||||
$suite = $input->getArgument('suite');
|
||||
$test = $input->getArgument('test');
|
||||
|
||||
if ($this->options['group']) {
|
||||
$this->output->writeln(sprintf("[Groups] <info>%s</info> ", implode(', ', $this->options['group'])));
|
||||
}
|
||||
if ($input->getArgument('test')) {
|
||||
$this->options['steps'] = true;
|
||||
}
|
||||
|
||||
if (!$test) {
|
||||
// Check if suite is given and is in an included path
|
||||
if (!empty($suite) && !empty($config['include'])) {
|
||||
$isIncludeTest = false;
|
||||
// Remember original projectDir
|
||||
$projectDir = Configuration::projectDir();
|
||||
|
||||
foreach ($config['include'] as $include) {
|
||||
// Find if the suite begins with an include path
|
||||
if (strpos($suite, $include) === 0) {
|
||||
// Use include config
|
||||
$config = Configuration::config($projectDir.$include);
|
||||
|
||||
if (!isset($config['paths']['tests'])) {
|
||||
throw new \RuntimeException(
|
||||
sprintf("Included '%s' has no tests path configured", $include)
|
||||
);
|
||||
}
|
||||
|
||||
$testsPath = $include . DIRECTORY_SEPARATOR. $config['paths']['tests'];
|
||||
|
||||
try {
|
||||
list(, $suite, $test) = $this->matchTestFromFilename($suite, $testsPath);
|
||||
$isIncludeTest = true;
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// Incorrect include match, continue trying to find one
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$result = $this->matchSingleTest($suite, $config);
|
||||
if ($result) {
|
||||
list(, $suite, $test) = $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore main config
|
||||
if (!$isIncludeTest) {
|
||||
$config = Configuration::config($projectDir);
|
||||
}
|
||||
} elseif (!empty($suite)) {
|
||||
$result = $this->matchSingleTest($suite, $config);
|
||||
if ($result) {
|
||||
list(, $suite, $test) = $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($test) {
|
||||
$filter = $this->matchFilteredTestName($test);
|
||||
$userOptions['filter'] = $filter;
|
||||
}
|
||||
|
||||
$this->codecept = new Codecept($userOptions);
|
||||
|
||||
if ($suite and $test) {
|
||||
$this->codecept->run($suite, $test, $config);
|
||||
}
|
||||
|
||||
// Run all tests of given suite or all suites
|
||||
if (!$test) {
|
||||
$suites = $suite ? explode(',', $suite) : Configuration::suites();
|
||||
$this->executed = $this->runSuites($suites, $this->options['skip']);
|
||||
|
||||
if (!empty($config['include']) and !$suite) {
|
||||
$current_dir = Configuration::projectDir();
|
||||
$suites += $config['include'];
|
||||
$this->runIncludedSuites($config['include'], $current_dir);
|
||||
}
|
||||
|
||||
if ($this->executed === 0) {
|
||||
throw new \RuntimeException(
|
||||
sprintf("Suite '%s' could not be found", implode(', ', $suites))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->codecept->printResult();
|
||||
|
||||
if (!$input->getOption('no-exit')) {
|
||||
if (!$this->codecept->getResult()->wasSuccessful()) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function matchSingleTest($suite, $config)
|
||||
{
|
||||
// Workaround when codeception.yml is inside tests directory and tests path is set to "."
|
||||
// @see https://github.com/Codeception/Codeception/issues/4432
|
||||
if (isset($config['paths']['tests']) && $config['paths']['tests'] === '.' && !preg_match('~^\.[/\\\]~', $suite)) {
|
||||
$suite = './' . $suite;
|
||||
}
|
||||
|
||||
// running a single test when suite has a configured path
|
||||
if (isset($config['suites'])) {
|
||||
foreach ($config['suites'] as $s => $suiteConfig) {
|
||||
if (!isset($suiteConfig['path'])) {
|
||||
continue;
|
||||
}
|
||||
$testsPath = $config['paths']['tests'] . DIRECTORY_SEPARATOR . $suiteConfig['path'];
|
||||
if ($suiteConfig['path'] === '.') {
|
||||
$testsPath = $config['paths']['tests'];
|
||||
}
|
||||
if (preg_match("~^$testsPath/(.*?)$~", $suite, $matches)) {
|
||||
$matches[2] = $matches[1];
|
||||
$matches[1] = $s;
|
||||
return $matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run single test without included tests
|
||||
if (! Configuration::isEmpty() && strpos($suite, $config['paths']['tests']) === 0) {
|
||||
return $this->matchTestFromFilename($suite, $config['paths']['tests']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs included suites recursively
|
||||
*
|
||||
* @param array $suites
|
||||
* @param string $parent_dir
|
||||
*/
|
||||
protected function runIncludedSuites($suites, $parent_dir)
|
||||
{
|
||||
foreach ($suites as $relativePath) {
|
||||
$current_dir = rtrim($parent_dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $relativePath;
|
||||
$config = Configuration::config($current_dir);
|
||||
$suites = Configuration::suites();
|
||||
|
||||
$namespace = $this->currentNamespace();
|
||||
$this->output->writeln(
|
||||
"\n<fg=white;bg=magenta>\n[$namespace]: tests from $current_dir\n</fg=white;bg=magenta>"
|
||||
);
|
||||
|
||||
$this->executed += $this->runSuites($suites, $this->options['skip']);
|
||||
if (!empty($config['include'])) {
|
||||
$this->runIncludedSuites($config['include'], $current_dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function currentNamespace()
|
||||
{
|
||||
$config = Configuration::config();
|
||||
if (!$config['namespace']) {
|
||||
throw new \RuntimeException(
|
||||
"Can't include into runner suite without a namespace;\n"
|
||||
. "Please add `namespace` section into included codeception.yml file"
|
||||
);
|
||||
}
|
||||
|
||||
return $config['namespace'];
|
||||
}
|
||||
|
||||
protected function runSuites($suites, $skippedSuites = [])
|
||||
{
|
||||
$executed = 0;
|
||||
foreach ($suites as $suite) {
|
||||
if (in_array($suite, $skippedSuites)) {
|
||||
continue;
|
||||
}
|
||||
if (!in_array($suite, Configuration::suites())) {
|
||||
continue;
|
||||
}
|
||||
$this->codecept->run($suite);
|
||||
$executed++;
|
||||
}
|
||||
|
||||
return $executed;
|
||||
}
|
||||
|
||||
protected function matchTestFromFilename($filename, $testsPath)
|
||||
{
|
||||
$testsPath = str_replace(['//', '\/', '\\'], '/', $testsPath);
|
||||
$filename = str_replace(['//', '\/', '\\'], '/', $filename);
|
||||
$res = preg_match("~^$testsPath/(.*?)(?>/(.*))?$~", $filename, $matches);
|
||||
|
||||
if (!$res) {
|
||||
throw new \InvalidArgumentException("Test file can't be matched");
|
||||
}
|
||||
if (!isset($matches[2])) {
|
||||
$matches[2] = null;
|
||||
}
|
||||
|
||||
return $matches;
|
||||
}
|
||||
|
||||
private function matchFilteredTestName(&$path)
|
||||
{
|
||||
$test_parts = explode(':', $path, 2);
|
||||
if (count($test_parts) > 1) {
|
||||
list($path, $filter) = $test_parts;
|
||||
// use carat to signify start of string like in normal regex
|
||||
// phpunit --filter matches against the fully qualified method name, so tests actually begin with :
|
||||
$carat_pos = strpos($filter, '^');
|
||||
if ($carat_pos !== false) {
|
||||
$filter = substr_replace($filter, ':', $carat_pos, 1);
|
||||
}
|
||||
return $filter;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function passedOptionKeys(InputInterface $input)
|
||||
{
|
||||
$options = [];
|
||||
$request = (string)$input;
|
||||
$tokens = explode(' ', $request);
|
||||
foreach ($tokens as $token) {
|
||||
$token = preg_replace('~=.*~', '', $token); // strip = from options
|
||||
|
||||
if (empty($token)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($token == '--') {
|
||||
break; // there should be no options after ' -- ', only arguments
|
||||
}
|
||||
|
||||
if (substr($token, 0, 2) === '--') {
|
||||
$options[] = substr($token, 2);
|
||||
} elseif ($token[0] === '-') {
|
||||
$shortOption = substr($token, 1);
|
||||
$options[] = $this->getDefinition()->getOptionForShortcut($shortOption)->getName();
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
protected function booleanOptions(InputInterface $input, $options = [])
|
||||
{
|
||||
$values = [];
|
||||
$request = (string)$input;
|
||||
foreach ($options as $option => $defaultValue) {
|
||||
if (strpos($request, "--$option")) {
|
||||
$values[$option] = $input->getOption($option) ? $input->getOption($option) : $defaultValue;
|
||||
} else {
|
||||
$values[$option] = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
private function ensureCurlIsAvailable()
|
||||
{
|
||||
if (!extension_loaded('curl')) {
|
||||
throw new \Exception(
|
||||
"Codeception requires CURL extension installed to make tests run\n"
|
||||
. "If you are not sure, how to install CURL, please refer to StackOverflow\n\n"
|
||||
. "Notice: PHP for Apache/Nginx and CLI can have different php.ini files.\n"
|
||||
. "Please make sure that your PHP you run from console has CURL enabled."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
311
vendor/codeception/base/src/Codeception/Command/SelfUpdate.php
vendored
Normal file
311
vendor/codeception/base/src/Codeception/Command/SelfUpdate.php
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
<?php
|
||||
namespace Codeception\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Codeception\Codecept;
|
||||
|
||||
/**
|
||||
* Auto-updates phar archive from official site: 'http://codeception.com/codecept.phar' .
|
||||
*
|
||||
* * `php codecept.phar self-update`
|
||||
*
|
||||
* @author Franck Cassedanne <franck@cassedanne.com>
|
||||
*/
|
||||
class SelfUpdate extends Command
|
||||
{
|
||||
/**
|
||||
* Class constants
|
||||
*/
|
||||
const NAME = 'Codeception';
|
||||
const GITHUB_REPO = 'Codeception/Codeception';
|
||||
const PHAR_URL = 'http://codeception.com/releases/%s/codecept.phar';
|
||||
const PHAR_URL_PHP54 = 'http://codeception.com/releases/%s/php54/codecept.phar';
|
||||
|
||||
/**
|
||||
* Holds the current script filename.
|
||||
* @var string
|
||||
*/
|
||||
protected $filename;
|
||||
|
||||
/**
|
||||
* Holds the live version string.
|
||||
* @var string
|
||||
*/
|
||||
protected $liveVersion;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
if (isset($_SERVER['argv'], $_SERVER['argv'][0])) {
|
||||
$this->filename = $_SERVER['argv'][0];
|
||||
} else {
|
||||
$this->filename = \Phar::running(false);
|
||||
}
|
||||
|
||||
$this
|
||||
// ->setAliases(array('selfupdate'))
|
||||
->setDescription(
|
||||
sprintf(
|
||||
'Upgrade <comment>%s</comment> to the latest version',
|
||||
$this->filename
|
||||
)
|
||||
);
|
||||
|
||||
parent::configure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getCurrentVersion()
|
||||
{
|
||||
return Codecept::VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$version = $this->getCurrentVersion();
|
||||
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
'<info>%s</info> version <comment>%s</comment>',
|
||||
self::NAME,
|
||||
$version
|
||||
)
|
||||
);
|
||||
|
||||
$output->writeln("\n<info>Checking for a new version...</info>\n");
|
||||
try {
|
||||
$latestVersion = $this->getLatestStableVersion();
|
||||
if ($this->isOutOfDate($version, $latestVersion)) {
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
'A newer version is available: <comment>%s</comment>',
|
||||
$latestVersion
|
||||
)
|
||||
);
|
||||
if (!$input->getOption('no-interaction')) {
|
||||
$dialog = $this->getHelperSet()->get('question');
|
||||
$question = new ConfirmationQuestion("\n<question>Do you want to update?</question> ", false);
|
||||
if (!$dialog->ask($input, $output, $question)) {
|
||||
$output->writeln("\n<info>Bye-bye!</info>\n");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
$output->writeln("\n<info>Updating...</info>");
|
||||
|
||||
$this->retrievePharFile($latestVersion, $output);
|
||||
} else {
|
||||
$output->writeln('You are already using the latest version.');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
"<error>\n%s\n</error>",
|
||||
$e->getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the provided version is current.
|
||||
*
|
||||
* @param string $version The version number to check.
|
||||
* @param string $latestVersion Latest stable version
|
||||
* @return boolean Returns True if a new version is available.
|
||||
*/
|
||||
private function isOutOfDate($version, $latestVersion)
|
||||
{
|
||||
return -1 != version_compare($version, $latestVersion, '>=');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getLatestStableVersion()
|
||||
{
|
||||
$stableVersions = $this->filterStableVersions(
|
||||
$this->getGithubTags(self::GITHUB_REPO)
|
||||
);
|
||||
|
||||
return array_reduce(
|
||||
$stableVersions,
|
||||
function ($a, $b) {
|
||||
return version_compare($a, $b, '>') ? $a : $b;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $tags
|
||||
* @return array
|
||||
*/
|
||||
private function filterStableVersions($tags)
|
||||
{
|
||||
return array_filter($tags, function ($tag) {
|
||||
return preg_match('/^[0-9]+\.[0-9]+\.[0-9]+$/', $tag);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of tags from a github repo.
|
||||
*
|
||||
* @param string $repo The repository name to check upon.
|
||||
* @return array
|
||||
*/
|
||||
protected function getGithubTags($repo)
|
||||
{
|
||||
$jsonTags = $this->retrieveContentFromUrl(
|
||||
'https://api.github.com/repos/' . $repo . '/tags'
|
||||
);
|
||||
|
||||
return array_map(
|
||||
function ($tag) {
|
||||
return $tag['name'];
|
||||
},
|
||||
json_decode($jsonTags, true)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the body-content from the provided URL.
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
* @throws \Exception if status code is above 300
|
||||
*/
|
||||
private function retrieveContentFromUrl($url)
|
||||
{
|
||||
$ctx = $this->prepareContext($url);
|
||||
|
||||
$body = file_get_contents($url, 0, $ctx);
|
||||
|
||||
if (isset($http_response_header)) {
|
||||
$code = substr($http_response_header[0], 9, 3);
|
||||
if (floor($code / 100) > 3) {
|
||||
throw new \Exception($http_response_header[0]);
|
||||
}
|
||||
} else {
|
||||
throw new \Exception('Request failed.');
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add proxy support to context if environment variable was set up
|
||||
*
|
||||
* @param array $opt context options
|
||||
* @param string $url
|
||||
*/
|
||||
private function prepareProxy(&$opt, $url)
|
||||
{
|
||||
$scheme = parse_url($url)['scheme'];
|
||||
if ($scheme === 'http' && (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy']))) {
|
||||
$proxy = !empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY'];
|
||||
}
|
||||
|
||||
if ($scheme === 'https' && (!empty($_SERVER['HTTPS_PROXY']) || !empty($_SERVER['https_proxy']))) {
|
||||
$proxy = !empty($_SERVER['https_proxy']) ? $_SERVER['https_proxy'] : $_SERVER['HTTPS_PROXY'];
|
||||
}
|
||||
|
||||
if (!empty($proxy)) {
|
||||
$proxy = str_replace(['http://', 'https://'], ['tcp://', 'ssl://'], $proxy);
|
||||
$opt['http']['proxy'] = $proxy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preparing context for request
|
||||
* @param $url
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
private function prepareContext($url)
|
||||
{
|
||||
$opts = [
|
||||
'http' => [
|
||||
'follow_location' => 1,
|
||||
'max_redirects' => 20,
|
||||
'timeout' => 10,
|
||||
'user_agent' => self::NAME
|
||||
]
|
||||
];
|
||||
$this->prepareProxy($opts, $url);
|
||||
return stream_context_create($opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the latest phar file.
|
||||
*
|
||||
* @param string $version
|
||||
* @param OutputInterface $output
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function retrievePharFile($version, OutputInterface $output)
|
||||
{
|
||||
$temp = basename($this->filename, '.phar') . '-temp.phar';
|
||||
|
||||
try {
|
||||
$sourceUrl = $this->getPharUrl($version);
|
||||
if (@copy($sourceUrl, $temp)) {
|
||||
chmod($temp, 0777 & ~umask());
|
||||
|
||||
// test the phar validity
|
||||
$phar = new \Phar($temp);
|
||||
// free the variable to unlock the file
|
||||
unset($phar);
|
||||
rename($temp, $this->filename);
|
||||
} else {
|
||||
throw new \Exception('Request failed.');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
if (!$e instanceof \UnexpectedValueException
|
||||
&& !$e instanceof \PharException
|
||||
) {
|
||||
throw $e;
|
||||
}
|
||||
unlink($temp);
|
||||
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
"<error>\nSomething went wrong (%s).\nPlease re-run this again.</error>\n",
|
||||
$e->getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
"\n<comment>%s</comment> has been updated.\n",
|
||||
$this->filename
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Phar file URL for specified version
|
||||
*
|
||||
* @param string $version
|
||||
* @return string
|
||||
*/
|
||||
protected function getPharUrl($version)
|
||||
{
|
||||
$sourceUrl = self::PHAR_URL;
|
||||
if (version_compare(PHP_VERSION, '7.0.0', '<')) {
|
||||
$sourceUrl = self::PHAR_URL_PHP54;
|
||||
}
|
||||
|
||||
return sprintf($sourceUrl, $version);
|
||||
}
|
||||
}
|
||||
66
vendor/codeception/base/src/Codeception/Command/Shared/Config.php
vendored
Normal file
66
vendor/codeception/base/src/Codeception/Command/Shared/Config.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace Codeception\Command\Shared;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Symfony\Component\Console\Exception\InvalidOptionException;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
trait Config
|
||||
{
|
||||
protected function getSuiteConfig($suite)
|
||||
{
|
||||
return Configuration::suiteSettings($suite, $this->getGlobalConfig());
|
||||
}
|
||||
|
||||
protected function getGlobalConfig($conf = null)
|
||||
{
|
||||
return Configuration::config($conf);
|
||||
}
|
||||
|
||||
protected function getSuites($conf = null)
|
||||
{
|
||||
return Configuration::suites();
|
||||
}
|
||||
|
||||
protected function overrideConfig($configOptions)
|
||||
{
|
||||
$updatedConfig = [];
|
||||
foreach ($configOptions as $option) {
|
||||
$keys = explode(': ', $option);
|
||||
if (count($keys) < 2) {
|
||||
throw new \InvalidArgumentException('--config-option should have config passed as "key:value"');
|
||||
}
|
||||
$value = array_pop($keys);
|
||||
$yaml = '';
|
||||
for ($ind = 0; count($keys); $ind += 2) {
|
||||
$yaml .= "\n" . str_repeat(' ', $ind) . array_shift($keys) . ': ';
|
||||
}
|
||||
$yaml .= $value;
|
||||
try {
|
||||
$config = Yaml::parse($yaml);
|
||||
} catch (ParseException $e) {
|
||||
throw new \Codeception\Exception\ParseException("Overridden config can't be parsed: \n$yaml\n" . $e->getParsedLine());
|
||||
}
|
||||
$updatedConfig = array_merge_recursive($updatedConfig, $config);
|
||||
}
|
||||
return Configuration::append($updatedConfig);
|
||||
}
|
||||
|
||||
protected function enableExtensions($extensions)
|
||||
{
|
||||
$config = ['extensions' => ['enabled' => []]];
|
||||
foreach ($extensions as $name) {
|
||||
if (!class_exists($name)) {
|
||||
$className = 'Codeception\\Extension\\' . ucfirst($name);
|
||||
if (!class_exists($className)) {
|
||||
throw new InvalidOptionException("Extension $name can't be loaded (tried by $name and $className)");
|
||||
}
|
||||
$config['extensions']['enabled'][] = $className;
|
||||
continue;
|
||||
}
|
||||
$config['extensions']['enabled'][] = $name;
|
||||
}
|
||||
return Configuration::append($config);
|
||||
}
|
||||
}
|
||||
54
vendor/codeception/base/src/Codeception/Command/Shared/FileSystem.php
vendored
Normal file
54
vendor/codeception/base/src/Codeception/Command/Shared/FileSystem.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace Codeception\Command\Shared;
|
||||
|
||||
use Codeception\Util\Shared\Namespaces;
|
||||
|
||||
trait FileSystem
|
||||
{
|
||||
use Namespaces;
|
||||
|
||||
protected function createDirectoryFor($basePath, $className = '')
|
||||
{
|
||||
$basePath = rtrim($basePath, DIRECTORY_SEPARATOR);
|
||||
if ($className) {
|
||||
$className = str_replace(['/', '\\'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $className);
|
||||
$path = $basePath . DIRECTORY_SEPARATOR . $className;
|
||||
$basePath = pathinfo($path, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
if (!file_exists($basePath)) {
|
||||
// Second argument should be mode. Well, umask() doesn't seem to return any if not set. Config may fix this.
|
||||
mkdir($basePath, 0775, true); // Third parameter commands to create directories recursively
|
||||
}
|
||||
return $basePath;
|
||||
}
|
||||
|
||||
protected function completeSuffix($filename, $suffix)
|
||||
{
|
||||
if (strpos(strrev($filename), strrev($suffix)) === 0) {
|
||||
$filename .= '.php';
|
||||
}
|
||||
if (strpos(strrev($filename), strrev($suffix . '.php')) !== 0) {
|
||||
$filename .= $suffix . '.php';
|
||||
}
|
||||
if (strpos(strrev($filename), strrev('.php')) !== 0) {
|
||||
$filename .= '.php';
|
||||
}
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
protected function removeSuffix($classname, $suffix)
|
||||
{
|
||||
$classname = preg_replace('~\.php$~', '', $classname);
|
||||
return preg_replace("~$suffix$~", '', $classname);
|
||||
}
|
||||
|
||||
protected function createFile($filename, $contents, $force = false, $flags = null)
|
||||
{
|
||||
if (file_exists($filename) && !$force) {
|
||||
return false;
|
||||
}
|
||||
file_put_contents($filename, $contents, $flags);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
16
vendor/codeception/base/src/Codeception/Command/Shared/Style.php
vendored
Normal file
16
vendor/codeception/base/src/Codeception/Command/Shared/Style.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace Codeception\Command\Shared;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
trait Style
|
||||
{
|
||||
public function addStyles(OutputInterface $output)
|
||||
{
|
||||
$output->getFormatter()->setStyle('notice', new OutputFormatterStyle('white', 'green', ['bold']));
|
||||
$output->getFormatter()->setStyle('bold', new OutputFormatterStyle(null, null, ['bold']));
|
||||
$output->getFormatter()->setStyle('warning', new OutputFormatterStyle(null, 'yellow', ['bold']));
|
||||
$output->getFormatter()->setStyle('debug', new OutputFormatterStyle('cyan'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user