diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..5ace4600a1
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 606986b374..4d923fd215 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -2,7 +2,8 @@ on:
pull_request:
branches-ignore: gh-pages
push:
- branches-ignore: gh-pages
+ branches:
+ - main
name: build
@@ -20,7 +21,7 @@ jobs:
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
- php-version: '8.1'
+ php-version: '8.2'
ini-values: memory_limit=-1, date.timezone='UTC'
tools: phpcs
@@ -45,13 +46,15 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
- php: ['8.0', '8.1', '8.2']
+ php: ['8.1', '8.2', '8.3', '8.4']
mode: ['stable', 'experimental']
exclude:
- - php: '8.1'
- mode: 'experimental'
- php: '8.2'
mode: 'experimental'
+ - php: '8.3'
+ mode: 'experimental'
+ - php: '8.4'
+ mode: 'experimental'
steps:
- name: Checkout
@@ -87,15 +90,15 @@ jobs:
if: matrix.mode == 'stable'
run: composer update --no-interaction --no-progress --optimize-autoloader --ansi
- - name: Composer install lowest versions of dependencies on PHP 8.0 in experimental mode
- if: matrix.php == '8.0' && matrix.mode == 'experimental'
+ - name: Composer install lowest versions of dependencies on PHP 8.1 in experimental mode
+ if: matrix.php == '8.1' && matrix.mode == 'experimental'
run: composer update --prefer-lowest --no-interaction --no-progress --optimize-autoloader --ansi
- name: Test that failing test really fails
run: if php codecept run -c tests/data/claypit/ scenario FailedCept -vvv; then echo "Test hasn't failed"; false; fi;
-# - name: Run tests without code coverage on PHP 8.0
-# if: matrix.php == '8.0'
+# - name: Run tests without code coverage on PHP 8.1
+# if: matrix.php == '8.1'
# run: |
# php -S 127.0.0.1:8008 -t tests/data/app >/dev/null 2>&1 &
# php codecept build
@@ -137,7 +140,7 @@ jobs:
fail-fast: false
matrix:
os: [windows-latest]
- php: ['8.0', '8.1', '8.2']
+ php: ['8.1', '8.2', '8.3', '8.4']
steps:
- name: Checkout
@@ -172,7 +175,7 @@ jobs:
run: composer install --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
- name: Run tests cli
- if: matrix.php != '8.1'
+ if: matrix.php != '8.2'
run: php codecept run cli --skip-group coverage
- name: Run tests unit
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index cec660bde1..0a04cbfc63 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -12,5 +12,6 @@
'array_syntax' => ['syntax' => 'short'],
'braces' => ['allow_single_line_closure' => true,],
'no_spaces_after_function_name' => true,
+ 'nullable_type_declaration_for_default_null_value' => true,
'single_blank_line_at_eof' => true,
])->setFinder($finder);
diff --git a/CHANGELOG-5.x.md b/CHANGELOG-5.x.md
index ba2aa54d13..745631fbc6 100644
--- a/CHANGELOG-5.x.md
+++ b/CHANGELOG-5.x.md
@@ -1,3 +1,19 @@
+#### 5.2.0
+
+* Fix FAIL message color highlighting by @antonvolokha in #6754
+* Update the codebase to PHP 8.1 by @TavoNiievez in #6747
+* generate:cest: Adding `declare(strict_types=1);` and return type `void` to generated files by @ThomasLandauer in #6736
+* Declare nullable parameter types explicitly by @W0rma in #6774 , #6775
+* chore: Included githubactions in the dependabot config (#6471) by @SamMousa in #6783
+* Added new option --disable-coverage-php to skip coverage.serialized report by @adrenalinkin in #6761
+* chore: add branch alias for main to fix composer install with dev deps by @SamMousa in #6787
+* chore(ci): prevent test CI running twice on PR branches by @SamMousa in #6788
+* Simplify classes by @TavoNiievez in #6767 , #6750 , #6764
+* PHP 8.4: `E_STRICT` deprecation by @W0rma in #6802
+* Fix PHP 8.4 deprecation. by @kagg-design in #6811
+* Fix test suite names in bootstrap command by @W0rma in #6813
+* Docs (minor) by @ThomasLandauer in #6804 , #6805 , #6806 , 6807 , #6792 , #6810 , #6751 , #6744
+
#### 5.1.2
* Prevent unrelated error from being displayed if a scenario step has failed by @craig-mcmahon in #6743
diff --git a/composer.json b/composer.json
index 31b219bf16..d462bd24c0 100644
--- a/composer.json
+++ b/composer.json
@@ -15,7 +15,7 @@
"minimum-stability": "RC",
"require": {
- "php": "^8.0",
+ "php": "^8.1",
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
@@ -28,12 +28,12 @@
"phpunit/php-timer": "^5.0.3 || ^6.0 || ^7.0",
"sebastian/comparator": "^4.0.5 || ^5.0 || ^6.0",
"sebastian/diff": "^4.0.3 || ^5.0 || ^6.0",
- "symfony/console": ">=4.4.24 <8.0",
- "symfony/css-selector": ">=4.4.24 <8.0",
- "symfony/event-dispatcher": ">=4.4.24 <8.0",
- "symfony/finder": ">=4.4.24 <8.0",
- "symfony/yaml": ">=4.4.24 <8.0",
- "symfony/var-dumper": ">=4.4.24 <8.0",
+ "symfony/console": ">=5.4.24 <8.0",
+ "symfony/css-selector": ">=5.4.24 <8.0",
+ "symfony/event-dispatcher": ">=5.4.24 <8.0",
+ "symfony/finder": ">=5.4.24 <8.0",
+ "symfony/yaml": ">=5.4.24 <8.0",
+ "symfony/var-dumper": ">=5.4.24 <8.0",
"psy/psysh": "^0.11.2 || ^0.12"
},
"require-dev": {
@@ -46,8 +46,8 @@
"codeception/module-filesystem": "*@dev",
"codeception/module-phpbrowser": "*@dev",
"codeception/util-universalframework": "*@dev",
- "symfony/process": ">=4.4.24 <8.0",
- "symfony/dotenv": ">=4.4.24 <8.0",
+ "symfony/process": ">=5.4.24 <8.0",
+ "symfony/dotenv": ">=5.4.24 <8.0",
"vlucas/phpdotenv": "^5.1",
"jetbrains/phpstorm-attributes": "^1.0"
},
@@ -68,7 +68,11 @@
"replace": {
"codeception/phpunit-wrapper": "*"
},
-
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.2.x-dev"
+ }
+ },
"autoload": {
"classmap": [
"src/PHPUnit/TestCase.php"
@@ -112,6 +116,7 @@
"codeception/module-db": "source",
"codeception/module-filesystem": "source",
"codeception/module-phpbrowser": "source",
+ "codeception/lib-innerbrowser": "source",
"*": "dist"
}
}
diff --git a/ext/DotReporter.php b/ext/DotReporter.php
index f048ae49af..53d9ac3518 100644
--- a/ext/DotReporter.php
+++ b/ext/DotReporter.php
@@ -13,7 +13,7 @@
/**
* DotReporter provides less verbose output for test execution.
- * Like PHPUnit printer it prints dots "." for successful testes and "F" for failures.
+ * Like PHPUnit printer it prints dots "." for successful tests and "F" for failures.
*
* 
*
diff --git a/ext/Recorder.php b/ext/Recorder.php
index d8641dd967..0ddbd1533f 100644
--- a/ext/Recorder.php
+++ b/ext/Recorder.php
@@ -10,6 +10,7 @@
use Codeception\Exception\ExtensionException;
use Codeception\Extension;
use Codeception\Lib\Interfaces\ScreenshotSaver;
+use Codeception\Module;
use Codeception\Module\WebDriver;
use Codeception\Step;
use Codeception\Step\Comment as CommentStep;
@@ -48,14 +49,14 @@
use function uniqid;
/**
- * Saves a screenshot of each step in acceptance tests and shows them as a slideshow on one HTML page (here's an [example](https://codeception.com/images/recorder.gif))
- * Activated only for suites with WebDriver module enabled.
+ * Saves a screenshot of each step in acceptance tests and shows them as a slideshow on one HTML page (here's an [example](https://codeception.com/images/recorder.gif)).
+ * Works only for suites with WebDriver module enabled.
*
* The screenshots are saved to `tests/_output/record_*` directories, open `index.html` to see them as a slideshow.
*
* #### Installation
*
- * Add this to the list of enabled extensions in `codeception.yml` or `acceptance.suite.yml`:
+ * Add this to the list of enabled extensions in `codeception.yml` or `Acceptance.suite.yml`:
*
* ``` yaml
* extensions:
@@ -86,7 +87,7 @@
* ```
* #### Skipping recording of steps with annotations
*
- * It is also possible to skip recording of steps for specified tests by using the @skipRecording annotation.
+ * It is also possible to skip recording of steps for specified tests by using the `@skipRecording` annotation.
*
* ```php
* /**
@@ -99,7 +100,6 @@
* $I->amOnUrl('https://codeception.com');
* }
* ```
- *
*/
class Recorder extends Extension
{
@@ -283,7 +283,7 @@ class Recorder extends Extension
Events::STEP_AFTER => 'afterStep',
];
- protected ?\Codeception\Module $webDriverModule = null;
+ protected ?Module $webDriverModule = null;
protected ?string $dir = null;
@@ -345,12 +345,12 @@ public function beforeSuite(): void
public function afterSuite(): void
{
- if (!$this->webDriverModule) {
+ if (!$this->webDriverModule instanceof Module) {
return;
}
$links = '';
- if (!empty($this->slides)) {
+ if ($this->slides !== []) {
foreach ($this->recordedTests as $suiteName => $suite) {
$links .= "
- {$suiteName}
";
foreach ($suite as $fileName => $tests) {
@@ -391,7 +391,7 @@ public function afterSuite(): void
public function before(TestEvent $event): void
{
- if (!$this->webDriverModule) {
+ if (!$this->webDriverModule instanceof Module) {
return;
}
$this->dir = null;
@@ -435,7 +435,7 @@ public function cleanup(TestEvent $event): void
}
}
- if (!$this->webDriverModule || !$this->dir) {
+ if (!$this->webDriverModule instanceof Module || !$this->dir) {
return;
}
if (!$this->config['delete_successful']) {
@@ -450,7 +450,7 @@ public function cleanup(TestEvent $event): void
public function persist(TestEvent $event): void
{
- if (!$this->webDriverModule) {
+ if (!$this->webDriverModule instanceof Module) {
return;
}
$indicatorHtml = '';
@@ -466,7 +466,7 @@ public function persist(TestEvent $event): void
try {
!is_dir($dir) && !mkdir($dir) && !is_dir($dir);
$this->dir = $dir;
- } catch (Exception $exception) {
+ } catch (Exception) {
$this->skipRecording[] = $testPath;
$this->appendErrorMessage(
$testPath,
@@ -486,7 +486,7 @@ public function persist(TestEvent $event): void
}
$this->webDriverModule->webDriver->takeScreenshot($this->dir . DIRECTORY_SEPARATOR . $filename);
- } catch (Exception $exception) {
+ } catch (Exception) {
$this->appendErrorMessage(
$testPath,
"⏺ Unable to capture a screenshot for {$testPath}/before"
@@ -503,13 +503,13 @@ public function persist(TestEvent $event): void
$indicatorHtml .= (new Template($this->indicatorTemplate))
->place('step', (int)$i)
- ->place('isActive', (int)$i ? '' : 'active')
+ ->place('isActive', (int)$i !== 0 ? '' : 'active')
->produce();
$slideHtml .= (new Template($this->slidesTemplate))
->place('image', $i)
->place('caption', $step->getHtml('#3498db'))
- ->place('isActive', (int)$i ? '' : 'active')
+ ->place('isActive', (int)$i !== 0 ? '' : 'active')
->place('isError', $status === 'success' ? '' : 'error')
->place('timeStamp', $this->timeStamps[$i])
->produce();
@@ -518,7 +518,7 @@ public function persist(TestEvent $event): void
$html = (new Template($this->template))
->place('indicators', $indicatorHtml)
->place('slides', $slideHtml)
- ->place('feature', ucfirst($event->getTest()->getFeature()))
+ ->place('feature', ucfirst((string) $event->getTest()->getFeature()))
->place('test', Descriptor::getTestSignature($event->getTest()))
->place('carousel_class', $this->config['animate_slides'] ? ' slide' : '')
->produce();
@@ -550,7 +550,7 @@ public function persist(TestEvent $event): void
public function afterStep(StepEvent $event): void
{
- if ($this->webDriverModule === null || $this->dir === null) {
+ if (!$this->webDriverModule instanceof Module || $this->dir === null) {
return;
}
@@ -571,7 +571,7 @@ public function afterStep(StepEvent $event): void
}
$this->webDriverModule->webDriver->takeScreenshot($this->dir . DIRECTORY_SEPARATOR . $filename);
- } catch (Exception $exception) {
+ } catch (Exception) {
$testPath = codecept_relative_path(Descriptor::getTestFullName($event->getTest()));
$this->appendErrorMessage(
$testPath,
@@ -589,6 +589,7 @@ protected function isStepIgnored(StepEvent $event): bool
$configIgnoredSteps = $this->config['ignore_steps'];
$annotationIgnoredSteps = $event->getTest()->getMetadata()->getParam('skipRecording');
+ /** @var string[] $ignoredSteps */
$ignoredSteps = array_unique(
array_merge(
$configIgnoredSteps,
diff --git a/ext/RunBefore.php b/ext/RunBefore.php
index cd18b8da20..3ad4bc954e 100644
--- a/ext/RunBefore.php
+++ b/ext/RunBefore.php
@@ -111,7 +111,7 @@ private function removeProcessFromMonitoring(int $index): void
private function processMonitoring(): void
{
- while (count($this->processes) !== 0) {
+ while ($this->processes !== []) {
$this->checkProcesses();
sleep(1);
}
diff --git a/ext/RunFailed.php b/ext/RunFailed.php
index e244edcaaf..bf7765b7ac 100644
--- a/ext/RunFailed.php
+++ b/ext/RunFailed.php
@@ -20,7 +20,7 @@
use function unlink;
/**
- * Saves failed tests into tests/_output/failed in order to rerun failed tests.
+ * Saves failed tests into `tests/_output/failed` in order to rerun failed tests.
*
* To rerun failed tests just run the `failed` group:
*
@@ -32,9 +32,9 @@
* ```
* --override "extensions: config: Codeception\Extension\RunFailed: fail-group: another_group1"
* ```
- * Remember: if you run tests and they generated custom-named fail group, to run this group, you should add override too
+ * Remember: If you run tests and they generated custom-named fail group, to run this group, you should add override too
*
- * Starting from Codeception 2.1 **this extension is enabled by default**.
+ * **This extension is enabled by default.**
*
* ``` yaml
* extensions:
@@ -88,7 +88,7 @@ public function saveFailed(PrintResultEvent $event): void
protected function localizePath(string $path): string
{
$root = realpath($this->getRootDir()) . DIRECTORY_SEPARATOR;
- if (substr($path, 0, strlen($root)) === $root) {
+ if (str_starts_with($path, $root)) {
return substr($path, strlen($root));
}
return $path;
diff --git a/ext/RunProcess.php b/ext/RunProcess.php
index 6389e4dd40..b6ba20061f 100644
--- a/ext/RunProcess.php
+++ b/ext/RunProcess.php
@@ -4,6 +4,7 @@
namespace Codeception\Extension;
+use BadMethodCallException;
use Codeception\Events;
use Codeception\Exception\ExtensionException;
use Codeception\Extension;
@@ -16,12 +17,13 @@
/**
* Extension to start and stop processes per suite.
- * Can be used to start/stop selenium server, chromedriver, mailcatcher, etc.
+ * Can be used to start/stop selenium server, chromedriver, [MailCatcher](https://mailcatcher.me/), etc.
+ * Each command is executed only once, at the beginning of the test suite. To execute a command before each test, see [Before/After Attributes](https://codeception.com/docs/AdvancedUsage#BeforeAfter-Attributes).
*
- * Can be configured in suite config:
+ * Can be enabled in suite config:
*
* ```yaml
- * # acceptance.suite.yml
+ * # Acceptance.suite.yml
* extensions:
* enabled:
* - Codeception\Extension\RunProcess:
@@ -31,8 +33,7 @@
* Multiple parameters can be passed as array:
*
* ```yaml
- * # acceptance.suite.yml
- *
+ * # Acceptance.suite.yml
* extensions:
* enabled:
* - Codeception\Extension\RunProcess:
@@ -42,8 +43,7 @@
*
* In the end of a suite all launched processes will be stopped.
*
- * To wait for the process to be launched use `sleep` option.
- * In this case you need configuration to be specified as object:
+ * To wait for the process to be launched use `sleep` option. In this case you need configuration to be specified as object:
*
* ```yaml
* extensions:
@@ -54,7 +54,7 @@
* sleep: 5 # wait 5 seconds for processes to boot
* ```
*
- * HINT: you can use different configurations per environment.
+ * HINT: You can use different configurations per environment.
*/
class RunProcess extends Extension
{
@@ -127,7 +127,7 @@ public function stopProcess(): void
*/
public function __sleep()
{
- throw new \BadMethodCallException('Cannot serialize ' . __CLASS__);
+ throw new BadMethodCallException('Cannot serialize ' . self::class);
}
/**
@@ -138,6 +138,6 @@ public function __sleep()
*/
public function __wakeup()
{
- throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
+ throw new BadMethodCallException('Cannot unserialize ' . self::class);
}
}
diff --git a/src/Codeception/Actor.php b/src/Codeception/Actor.php
index 0e29025065..e01f0ae62a 100644
--- a/src/Codeception/Actor.php
+++ b/src/Codeception/Actor.php
@@ -42,7 +42,7 @@ public function wantToTest(string $text): void
public function __call(string $method, array $arguments)
{
- $class = $this::class;
+ $class = static::class;
throw new RuntimeException("Call to undefined method {$class}::{$method}");
}
diff --git a/src/Codeception/Application.php b/src/Codeception/Application.php
index 44cab365f6..3244c44bfe 100644
--- a/src/Codeception/Application.php
+++ b/src/Codeception/Application.php
@@ -99,9 +99,9 @@ protected function getCustomCommandName(string $commandClass): string
*
* @inheritDoc
*/
- public function run(InputInterface $input = null, OutputInterface $output = null): int
+ public function run(?InputInterface $input = null, ?OutputInterface $output = null): int
{
- if ($input === null) {
+ if (!$input instanceof InputInterface) {
$input = $this->getCoreArguments();
}
@@ -135,7 +135,7 @@ protected function getDefaultInputDefinition(): InputDefinition
*/
protected function getCoreArguments(): SymfonyArgvInput
{
- if ($this->coreArguments !== null) {
+ if ($this->coreArguments instanceof SymfonyArgvInput) {
return $this->coreArguments;
}
diff --git a/src/Codeception/Codecept.php b/src/Codeception/Codecept.php
index 1018716693..1410893291 100644
--- a/src/Codeception/Codecept.php
+++ b/src/Codeception/Codecept.php
@@ -36,7 +36,7 @@ class Codecept
/**
* @var string
*/
- public const VERSION = '5.1.2';
+ public const VERSION = '5.2.0';
protected ResultAggregator $resultAggregator;
@@ -45,40 +45,41 @@ class Codecept
protected ExtensionLoader $extensionLoader;
protected array $options = [
- 'silent' => false,
- 'debug' => false,
- 'steps' => false,
- 'html' => false,
- 'xml' => false,
- 'phpunit-xml' => false,
- 'no-redirect' => true,
- 'report' => false,
- 'colors' => false,
- 'coverage' => false,
- 'coverage-xml' => false,
- 'coverage-html' => false,
- 'coverage-text' => false,
- 'coverage-crap4j' => false,
- 'coverage-cobertura' => false,
- 'coverage-phpunit' => false,
- 'groups' => null,
- 'excludeGroups' => null,
- 'filter' => null,
- 'shard' => null,
- 'env' => null,
- 'fail-fast' => 0,
- 'ansi' => true,
- 'verbosity' => 1,
- 'interactive' => true,
- 'no-rebuild' => false,
- 'quiet' => false,
+ 'silent' => false,
+ 'debug' => false,
+ 'steps' => false,
+ 'html' => false,
+ 'xml' => false,
+ 'phpunit-xml' => false,
+ 'no-redirect' => true,
+ 'report' => false,
+ 'colors' => false,
+ 'coverage' => false,
+ 'coverage-xml' => false,
+ 'coverage-html' => false,
+ 'coverage-text' => false,
+ 'coverage-crap4j' => false,
+ 'coverage-cobertura' => false,
+ 'coverage-phpunit' => false,
+ 'disable-coverage-php' => false,
+ 'groups' => null,
+ 'excludeGroups' => null,
+ 'filter' => null,
+ 'shard' => null,
+ 'env' => null,
+ 'fail-fast' => 0,
+ 'ansi' => true,
+ 'verbosity' => 1,
+ 'interactive' => true,
+ 'no-rebuild' => false,
+ 'quiet' => false,
];
protected array $config = [];
protected array $extensions = [];
- private Output $output;
+ private readonly Output $output;
public function __construct(array $options = [])
{
@@ -154,7 +155,7 @@ public function registerSubscribers(): void
private function isConsolePrinterSubscribed(): bool
{
- foreach ($this->dispatcher->getListeners() as $event => $listeners) {
+ foreach ($this->dispatcher->getListeners() as $listeners) {
foreach ($listeners as $listener) {
if ($listener instanceof ConsolePrinter) {
return true;
@@ -192,15 +193,7 @@ private function registerReporters(): void
}
}
- private function absolutePath(string $path): string
- {
- if ((str_starts_with($path, '/')) or (strpos($path, ':') === 1)) { // absolute path
- return $path;
- }
- return Configuration::outputDir() . $path;
- }
-
- public function run(string $suite, string $test = null, array $config = null): void
+ public function run(string $suite, ?string $test = null, ?array $config = null): void
{
ini_set(
'memory_limit',
@@ -219,7 +212,7 @@ public function run(string $suite, string $test = null, array $config = null): v
// Iterate over all unique environment sets and runs the given suite with each of the merged configurations.
foreach (array_unique($selectedEnvironments) as $envList) {
- $envSet = explode(',', $envList);
+ $envSet = explode(',', (string) $envList);
$suiteEnvConfig = $config;
// contains a list of the environments used in this suite configuration env set.
@@ -249,14 +242,14 @@ public function run(string $suite, string $test = null, array $config = null): v
}
}
- public function runSuite(array $settings, string $suite, string $test = null): void
+ public function runSuite(array $settings, string $suite, ?string $test = null): void
{
$settings['shard'] = $this->options['shard'];
$suiteManager = new SuiteManager($this->dispatcher, $suite, $settings, $this->options);
$suiteManager->initialize();
- srand($this->options['seed']);
+ mt_srand($this->options['seed']);
$suiteManager->loadTests($test);
- srand();
+ mt_srand();
$suiteManager->run($this->resultAggregator);
}
diff --git a/src/Codeception/Command/Bootstrap.php b/src/Codeception/Command/Bootstrap.php
index 510bb00568..5e208c0c13 100644
--- a/src/Codeception/Command/Bootstrap.php
+++ b/src/Codeception/Command/Bootstrap.php
@@ -15,7 +15,7 @@
* 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**.
+ * 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
@@ -28,33 +28,21 @@ class Bootstrap extends Command
{
protected function configure(): void
{
- $this->setDefinition(
- [
- new InputArgument('path', InputArgument::OPTIONAL, 'custom installation dir', null),
- new InputOption(
- 'namespace',
- 's',
- 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")
- ]
- );
+ $this->setDescription('Creates default test suites and generates all required files')
+ ->addArgument('path', InputArgument::OPTIONAL, 'custom installation dir')
+ ->addOption('namespace', 's', InputOption::VALUE_OPTIONAL, 'Namespace to add for actor classes and helpers')
+ ->addOption('actor', 'a', InputOption::VALUE_OPTIONAL, 'Custom actor instead of Tester')
+ ->addOption('empty', 'e', InputOption::VALUE_NONE, "Don't create standard suites");
}
- public function getDescription(): string
- {
- return "Creates default test suites and generates all required files";
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$bootstrap = new BootstrapTemplate($input, $output);
- if ($input->getArgument('path')) {
- $bootstrap->initDir($input->getArgument('path'));
+ if ($path = $input->getArgument('path')) {
+ $bootstrap->initDir($path);
}
+
$bootstrap->setup();
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/Build.php b/src/Codeception/Command/Build.php
index c4fb231d39..c8721f8d92 100644
--- a/src/Codeception/Command/Build.php
+++ b/src/Codeception/Command/Build.php
@@ -39,7 +39,7 @@ protected function execute(InputInterface $input, SymfonyOutputInterface $output
{
$this->output = $output;
$this->buildActorsForConfig();
- return 0;
+ return Command::SUCCESS;
}
private function buildActor(array $settings): bool
@@ -65,7 +65,7 @@ private function buildActions(array $settings): bool
$actionsGenerator = new ActionsGenerator($settings);
$content = $actionsGenerator->produce();
$this->output->writeln(
- " -> {$settings['actor']}Actions.php generated successfully. "
+ sprintf(' -> %sActions.php generated successfully. ', $settings['actor'])
. $actionsGenerator->getNumMethods() . " methods added"
);
@@ -77,7 +77,7 @@ private function buildActions(array $settings): bool
private function buildSuiteActors(): void
{
$suites = $this->getSuites();
- if (!empty($suites)) {
+ if ($suites !== []) {
$this->output->writeln("Building Actor classes for suites: " . implode(', ', $suites) . '');
}
foreach ($suites as $suite) {
@@ -89,12 +89,12 @@ private function buildSuiteActors(): void
$actorBuilt = $this->buildActor($settings);
if ($actorBuilt) {
- $this->output->writeln("{$settings['actor']}.php created.");
+ $this->output->writeln($settings['actor'] . '.php created.');
}
}
}
- protected function buildActorsForConfig($configFile = null): void
+ protected function buildActorsForConfig(?string $configFile = null): void
{
$config = $this->getGlobalConfig($configFile);
diff --git a/src/Codeception/Command/Clean.php b/src/Codeception/Command/Clean.php
index 10758057fa..c77872b397 100644
--- a/src/Codeception/Command/Clean.php
+++ b/src/Codeception/Command/Clean.php
@@ -20,30 +20,28 @@ class Clean extends Command
{
use Shared\ConfigTrait;
- public function getDescription(): string
+ protected function configure(): void
{
- return 'Recursively cleans log and generated code';
+ $this->setDescription('Recursively cleans log and generated code');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
- $projectDir = Configuration::projectDir();
- $this->cleanProjectsRecursively($output, $projectDir);
+ $this->cleanProjectsRecursively($output, Configuration::projectDir());
$output->writeln("Done");
- return 0;
+ return Command::SUCCESS;
}
private function cleanProjectsRecursively(OutputInterface $output, string $projectDir): void
{
$config = Configuration::config($projectDir);
$logDir = Configuration::outputDir();
- $output->writeln("Cleaning up output " . $logDir . "...");
+ $output->writeln(sprintf('Cleaning up output %s...', $logDir));
FileSystem::doEmptyDir($logDir);
$subProjects = $config['include'];
foreach ($subProjects as $subProject) {
- $subProjectDir = $projectDir . $subProject;
- $this->cleanProjectsRecursively($output, $subProjectDir);
+ $this->cleanProjectsRecursively($output, $projectDir . $subProject);
}
}
}
diff --git a/src/Codeception/Command/Completion.php b/src/Codeception/Command/Completion.php
index dd71e0cf55..26b13b2a4a 100644
--- a/src/Codeception/Command/Completion.php
+++ b/src/Codeception/Command/Completion.php
@@ -10,6 +10,7 @@
use Stecman\Component\Symfony\Console\BashCompletion\Completion\ShellPathCompletion;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionCommand;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionHandler;
+use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputDefinition as SymfonyInputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -72,7 +73,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
parent::execute($input, $output);
- return 0;
+ return Command::SUCCESS;
}
protected function createDefinition(): SymfonyInputDefinition
diff --git a/src/Codeception/Command/CompletionFallback.php b/src/Codeception/Command/CompletionFallback.php
index b45a8604a6..9f76dd971b 100644
--- a/src/Codeception/Command/CompletionFallback.php
+++ b/src/Codeception/Command/CompletionFallback.php
@@ -31,6 +31,6 @@ protected function configure(): void
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln("Install optional stecman/symfony-console-completion");
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/ConfigValidate.php b/src/Codeception/Command/ConfigValidate.php
index 84e7e06d30..6719d1d63f 100644
--- a/src/Codeception/Command/ConfigValidate.php
+++ b/src/Codeception/Command/ConfigValidate.php
@@ -46,22 +46,13 @@ class ConfigValidate extends Command
protected function configure(): void
{
- $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();
+ $this->setDescription('Validates and prints config to screen')
+ ->addArgument('suite', InputArgument::OPTIONAL, 'To show suite configuration')
+ ->addOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config')
+ ->addOption('override', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Override config values');
}
- public function getDescription(): string
- {
- return 'Validates and prints config to screen';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->addStyles($output);
@@ -72,8 +63,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
$output->writeln("------------------------------\n");
$output->writeln("{$suite} Suite Config:\n");
$output->writeln($this->formatOutput($config));
-
- return 0;
+ return Command::SUCCESS;
}
$output->write("Validating global config... ");
@@ -82,8 +72,9 @@ public function execute(InputInterface $input, OutputInterface $output): int
if (!empty($input->getOption('override'))) {
$config = $this->overrideConfig($input->getOption('override'));
}
- $suites = Configuration::suites();
+
$output->writeln("Ok");
+ $suites = Configuration::suites();
$output->writeln("------------------------------\n");
$output->writeln("Codeception Config:\n");
@@ -104,7 +95,8 @@ public function execute(InputInterface $input, OutputInterface $output): int
}
$output->writeln("Execute codecept config:validate [] to see config for a suite");
- return 0;
+
+ return Command::SUCCESS;
}
protected function formatOutput($config): ?string
diff --git a/src/Codeception/Command/Console.php b/src/Codeception/Command/Console.php
index a3fe75855c..cebea00dbd 100644
--- a/src/Codeception/Command/Console.php
+++ b/src/Codeception/Command/Console.php
@@ -49,20 +49,12 @@ class Console extends Command
protected function configure(): void
{
- $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(): string
- {
- return 'Launches interactive test console';
+ $this->setDescription('Launches interactive test console')
+ ->addArgument('suite', InputArgument::REQUIRED, 'suite to be executed')
+ ->addOption('colors', '', InputOption::VALUE_NONE, 'Use colors in output');
}
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$suiteName = $input->getArgument('suite');
$this->output = $output;
@@ -103,6 +95,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
if (isset($config['namespace']) && $config['namespace'] !== '') {
$settings['actor'] = $config['namespace'] . '\\Support\\' . $settings['actor'];
}
+
$actor = $settings['actor'];
$I = new $actor($scenario);
@@ -126,7 +119,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
$eventDispatcher->dispatch(new SuiteEvent($this->suite), Events::SUITE_AFTER);
$output->writeln("Bye-bye!");
- return 0;
+ return Command::SUCCESS;
}
protected function listenToSignals(): void
diff --git a/src/Codeception/Command/DryRun.php b/src/Codeception/Command/DryRun.php
index a1c448c36c..73d8b4a8d3 100644
--- a/src/Codeception/Command/DryRun.php
+++ b/src/Codeception/Command/DryRun.php
@@ -18,6 +18,7 @@
use Codeception\Test\Test;
use Exception;
use InvalidArgumentException;
+use ReflectionClass;
use ReflectionIntersectionType;
use ReflectionMethod;
use ReflectionNamedType;
@@ -33,7 +34,7 @@
use function str_replace;
/**
- * Shows step by step execution process for scenario driven tests without actually running them.
+ * Shows step-by-step execution process for scenario driven tests without actually running them.
*
* * `codecept dry-run acceptance`
* * `codecept dry-run acceptance MyCest`
@@ -62,10 +63,10 @@ public function getDescription(): string
return 'Prints step-by-step scenario-driven test or a feature';
}
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->addStyles($output);
- $suite = $input->getArgument('suite');
+ $suite = (string)$input->getArgument('suite');
$test = $input->getArgument('test');
$config = $this->getGlobalConfig();
@@ -106,7 +107,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
return 0;
}
- protected function matchTestFromFilename($filename, $testsPath)
+ protected function matchTestFromFilename($filename, $testsPath): array
{
$filename = str_replace(['//', '\/', '\\'], '/', $filename);
$res = preg_match("#^{$testsPath}/(.*?)/(.*)$#", $filename, $matches);
@@ -143,7 +144,7 @@ protected function dryRunTest(OutputInterface $output, EventDispatcher $eventDis
private function mockModule(string $moduleName, ModuleContainer $moduleContainer): void
{
$module = $moduleContainer->getModule($moduleName);
- $class = new \ReflectionClass($module);
+ $class = new ReflectionClass($module);
$methodResults = [];
foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
if ($method->isConstructor()) {
@@ -155,7 +156,7 @@ private function mockModule(string $moduleName, ModuleContainer $moduleContainer
$moduleContainer->mock($moduleName, Stub::makeEmpty($module, $methodResults));
}
- private function getDefaultResultForMethod(\ReflectionClass $class, ReflectionMethod $method): mixed
+ private function getDefaultResultForMethod(ReflectionClass $class, ReflectionMethod $method): mixed
{
$returnType = $method->getReturnType();
@@ -219,7 +220,7 @@ private function returnDefaultValueForIntersectionType(ReflectionIntersectionTyp
if ($extends !== null) {
$code .= " extends \\$extends";
}
- if (count($implements) > 0) {
+ if ($implements !== []) {
$code .= ' implements ' . implode(', ', $implements);
}
$code .= ' {}';
diff --git a/src/Codeception/Command/GenerateCest.php b/src/Codeception/Command/GenerateCest.php
index 6ddac7902f..aff87c6aae 100644
--- a/src/Codeception/Command/GenerateCest.php
+++ b/src/Codeception/Command/GenerateCest.php
@@ -28,18 +28,12 @@ class GenerateCest extends Command
protected function configure(): void
{
- $this->setDefinition([
- new InputArgument('suite', InputArgument::REQUIRED, 'suite where tests will be put'),
- new InputArgument('class', InputArgument::REQUIRED, 'test name'),
- ]);
+ $this->setDescription('Generates empty Cest file in suite')
+ ->addArgument('suite', InputArgument::REQUIRED, 'suite where tests will be put')
+ ->addArgument('class', InputArgument::REQUIRED, 'test name');
}
- public function getDescription(): string
- {
- return 'Generates empty Cest file in suite';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$suite = $input->getArgument('suite');
$class = $input->getArgument('class');
@@ -53,16 +47,16 @@ public function execute(InputInterface $input, OutputInterface $output): int
if (file_exists($filename)) {
$output->writeln("Test {$filename} already exists");
- return 1;
+ return Command::FAILURE;
}
$cest = new CestGenerator($class, $config);
$res = $this->createFile($filename, $cest->produce());
if (!$res) {
$output->writeln("Test {$filename} already exists");
- return 1;
+ return Command::FAILURE;
}
$output->writeln("Test was created in {$filename}");
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/GenerateEnvironment.php b/src/Codeception/Command/GenerateEnvironment.php
index fe5c648d75..024974099c 100644
--- a/src/Codeception/Command/GenerateEnvironment.php
+++ b/src/Codeception/Command/GenerateEnvironment.php
@@ -25,17 +25,11 @@ class GenerateEnvironment extends Command
protected function configure(): void
{
- $this->setDefinition([
- new InputArgument('env', InputArgument::REQUIRED, 'Environment name'),
- ]);
+ $this->setDescription('Generates empty environment config')
+ ->addArgument('env', InputArgument::REQUIRED, 'Environment name');
}
- public function getDescription(): string
- {
- return 'Generates empty environment config';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$config = $this->getGlobalConfig();
if (Configuration::envsDir() === '') {
@@ -45,19 +39,20 @@ public function execute(InputInterface $input, OutputInterface $output): int
. "envs: tests/_envs"
);
}
+
$relativePath = $config['paths']['envs'];
$env = $input->getArgument('env');
- $file = "{$env}.yml";
+ $file = $env . '.yml';
$path = $this->createDirectoryFor($relativePath, $file);
- $saved = $this->createFile($path . $file, "# `{$env}` environment config goes here");
+ $saved = $this->createFile($path . $file, sprintf('# `%s` environment config goes here', $env));
if ($saved) {
- $output->writeln("{$env} config was created in {$relativePath}/{$file}");
- return 0;
- } else {
- $output->writeln("File {$relativePath}/{$file} already exists");
- return 1;
+ $output->writeln(sprintf('%s config was created in %s/%s', $env, $relativePath, $file));
+ return Command::SUCCESS;
}
+
+ $output->writeln(sprintf('File %s/%s already exists', $relativePath, $file));
+ return Command::FAILURE;
}
}
diff --git a/src/Codeception/Command/GenerateFeature.php b/src/Codeception/Command/GenerateFeature.php
index 8fd6f83b7d..18356bb43a 100644
--- a/src/Codeception/Command/GenerateFeature.php
+++ b/src/Codeception/Command/GenerateFeature.php
@@ -30,22 +30,16 @@ class GenerateFeature extends Command
protected function configure(): void
{
- $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'),
- ]);
+ $this->setDescription('Generates empty feature file in suite')
+ ->addArgument('suite', InputArgument::REQUIRED, 'suite to be tested')
+ ->addArgument('feature', InputArgument::REQUIRED, 'feature to be generated')
+ ->addOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config');
}
- public function getDescription(): string
- {
- return 'Generates empty feature file in suite';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$suite = $input->getArgument('suite');
- $filename = $input->getArgument('feature');
+ $filename = (string)$input->getArgument('feature');
$config = $this->getSuiteConfig($suite);
$this->createDirectoryFor($config['path'], $filename);
@@ -54,13 +48,13 @@ public function execute(InputInterface $input, OutputInterface $output): int
if (!preg_match('#\.feature$#', $filename)) {
$filename .= '.feature';
}
- $fullPath = rtrim($config['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename;
+ $fullPath = rtrim((string) $config['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename;
$res = $this->createFile($fullPath, $feature->produce());
if (!$res) {
$output->writeln("Feature {$filename} already exists");
- return 1;
+ return Command::FAILURE;
}
$output->writeln("Feature was created in {$fullPath}");
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/GenerateGroup.php b/src/Codeception/Command/GenerateGroup.php
index 7c7ef1310d..0456264411 100644
--- a/src/Codeception/Command/GenerateGroup.php
+++ b/src/Codeception/Command/GenerateGroup.php
@@ -25,17 +25,11 @@ class GenerateGroup extends Command
protected function configure(): void
{
- $this->setDefinition([
- new InputArgument('group', InputArgument::REQUIRED, 'Group class name'),
- ]);
+ $this->setDescription('Generates Group subscriber')
+ ->addArgument('group', InputArgument::REQUIRED, 'Group class name');
}
- public function getDescription(): string
- {
- return 'Generates Group subscriber';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$config = $this->getGlobalConfig();
$groupInputArgument = (string)$input->getArgument('group');
@@ -50,13 +44,13 @@ public function execute(InputInterface $input, OutputInterface $output): int
if (!$res) {
$output->writeln("Group {$filename} already exists");
- return 1;
+ return Command::FAILURE;
}
$output->writeln("Group extension was created in {$filename}");
$output->writeln(
'To use this group extension, include it to "extensions" option of global Codeception config.'
);
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/GenerateHelper.php b/src/Codeception/Command/GenerateHelper.php
index f265b4890d..cc45e893cb 100644
--- a/src/Codeception/Command/GenerateHelper.php
+++ b/src/Codeception/Command/GenerateHelper.php
@@ -27,17 +27,11 @@ class GenerateHelper extends Command
protected function configure(): void
{
- $this->setDefinition([
- new InputArgument('name', InputArgument::REQUIRED, 'helper name'),
- ]);
+ $this->setDescription('Generates a new helper')
+ ->addArgument('name', InputArgument::REQUIRED, 'Helper name');
}
- public function getDescription(): string
- {
- return 'Generates new helper';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = ucfirst((string)$input->getArgument('name'));
$config = $this->getGlobalConfig();
@@ -48,10 +42,10 @@ public function execute(InputInterface $input, OutputInterface $output): int
$res = $this->createFile($filename, (new Helper($config, $name))->produce());
if ($res) {
$output->writeln("Helper {$filename} created");
- return 0;
- } else {
- $output->writeln("Error creating helper {$filename}");
- return 1;
+ return Command::SUCCESS;
}
+
+ $output->writeln(sprintf('Error creating helper %s', $filename));
+ return Command::FAILURE;
}
}
diff --git a/src/Codeception/Command/GeneratePageObject.php b/src/Codeception/Command/GeneratePageObject.php
index 053880cb32..6e067aacd3 100644
--- a/src/Codeception/Command/GeneratePageObject.php
+++ b/src/Codeception/Command/GeneratePageObject.php
@@ -28,19 +28,12 @@ class GeneratePageObject extends Command
protected function configure(): void
{
- $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();
+ $this->setDescription('Generates empty PageObject class')
+ ->addArgument('suite', InputArgument::REQUIRED, 'Either suite name or page object name')
+ ->addArgument('page', InputArgument::OPTIONAL, 'Page name of pageobject to represent');
}
- public function getDescription(): string
- {
- return 'Generates empty PageObject class';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$suite = (string)$input->getArgument('suite');
$class = $input->getArgument('page');
@@ -69,9 +62,9 @@ public function execute(InputInterface $input, OutputInterface $output): int
if (!$res) {
$output->writeln("PageObject {$filename} already exists");
- return 1;
+ return Command::FAILURE;
}
$output->writeln("PageObject was created in {$filename}");
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/GenerateScenarios.php b/src/Codeception/Command/GenerateScenarios.php
index d31767dbc5..452e392ffd 100644
--- a/src/Codeception/Command/GenerateScenarios.php
+++ b/src/Codeception/Command/GenerateScenarios.php
@@ -37,18 +37,11 @@ class GenerateScenarios extends Command
protected function configure(): void
{
- $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(): string
- {
- return 'Generates text representation for all scenarios';
+ $this->setDescription('Generates text representation for all scenarios')
+ ->addArgument('suite', InputArgument::REQUIRED, 'suite from which texts should be generated')
+ ->addOption('path', 'p', InputOption::VALUE_REQUIRED, 'Use specified path as destination instead of default')
+ ->addOption('single-file', '', InputOption::VALUE_NONE, 'Render all scenarios to only one file')
+ ->addOption('format', 'f', InputOption::VALUE_REQUIRED, 'Specify output format: html or text (default)', 'text');
}
protected function execute(InputInterface $input, OutputInterface $output): int
@@ -57,13 +50,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$suiteConf = $this->getSuiteConfig($suite);
- $path = $input->getOption('path')
- ? $input->getOption('path')
- : Configuration::dataDir() . 'scenarios';
+ $path = $input->getOption('path') ?: Configuration::dataDir() . 'scenarios';
$format = $input->getOption('format');
- @mkdir($path);
+ @mkdir($path, 0777, true);
if (!is_writable($path)) {
throw new ConfigurationException(
@@ -71,7 +62,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
);
}
- $path = $path . DIRECTORY_SEPARATOR . $suite;
+ $path .= DIRECTORY_SEPARATOR . $suite;
if (!$input->getOption('single-file')) {
@mkdir($path);
}
@@ -83,7 +74,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
$tests = $this->getTests($suiteManager);
- $scenarios = "";
+ $scenarios = '';
+
+ $output->writeln('This command is deprecated and will be removed in the next major version of Codeception.');
foreach ($tests as $test) {
if (!$test instanceof ScenarioDriven || !$test instanceof Descriptive) {
@@ -111,13 +104,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if ($input->getOption('single-file')) {
$this->createFile($path . $this->formatExtension($format), $this->decorate($scenarios, $format), true);
}
- return 0;
+
+ return Command::SUCCESS;
}
protected function decorate(string $text, string $format): string
{
if ($format === 'html') {
- return "$text";
+ return "{$text}";
}
return $text;
}
@@ -130,10 +124,7 @@ protected function getTests($suiteManager)
protected function formatExtension(string $format): string
{
- if ($format === 'html') {
- return '.html';
- }
- return '.txt';
+ return '.' . ($format === 'html' ? 'html' : 'txt');
}
private function underscore(string $name): string
diff --git a/src/Codeception/Command/GenerateSnapshot.php b/src/Codeception/Command/GenerateSnapshot.php
index 171c957201..ad91a001a2 100644
--- a/src/Codeception/Command/GenerateSnapshot.php
+++ b/src/Codeception/Command/GenerateSnapshot.php
@@ -29,19 +29,12 @@ class GenerateSnapshot extends Command
protected function configure(): void
{
- $this->setDefinition([
- new InputArgument('suite', InputArgument::REQUIRED, 'Suite name or snapshot name)'),
- new InputArgument('snapshot', InputArgument::OPTIONAL, 'Name of snapshot'),
- ]);
- parent::configure();
+ $this->setDescription('Generates empty Snapshot class')
+ ->addArgument('suite', InputArgument::REQUIRED, 'Suite name or snapshot name)')
+ ->addArgument('snapshot', InputArgument::OPTIONAL, 'Name of snapshot');
}
- public function getDescription(): string
- {
- return 'Generates empty Snapshot class';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$suite = (string)$input->getArgument('suite');
$class = $input->getArgument('snapshot');
@@ -70,9 +63,9 @@ public function execute(InputInterface $input, OutputInterface $output): int
if (!$res) {
$output->writeln("Snapshot {$filename} already exists");
- return 1;
+ return Command::FAILURE;
}
$output->writeln("Snapshot was created in {$filename}");
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/GenerateStepObject.php b/src/Codeception/Command/GenerateStepObject.php
index 848e411db5..d790bb01a6 100644
--- a/src/Codeception/Command/GenerateStepObject.php
+++ b/src/Codeception/Command/GenerateStepObject.php
@@ -30,37 +30,23 @@ class GenerateStepObject extends Command
protected function configure(): void
{
- $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'),
- ]);
+ $this->setDescription('Generates empty StepObject class')
+ ->addArgument('suite', InputArgument::REQUIRED, 'Suite for StepObject')
+ ->addArgument('step', InputArgument::REQUIRED, 'StepObject name')
+ ->addOption('silent', '', InputOption::VALUE_NONE, 'Skip verification question');
}
- public function getDescription(): string
- {
- return 'Generates empty StepObject class';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$suite = (string)$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);
- /**
- * @var QuestionHelper
- */
- $dialog = $this->getHelperSet()->get('question');
+ /** @var QuestionHelper $dialog */
+ $dialog = $this->getHelper('question');
$filename = $path . $class . '.php';
-
- $helper = $this->getHelper('question');
- $question = new Question("Add action to StepObject class (ENTER to exit): ");
-
$stepObject = new StepObjectGenerator($config, ucfirst($suite) . '\\' . $step);
if (!$input->getOption('silent')) {
@@ -77,9 +63,9 @@ public function execute(InputInterface $input, OutputInterface $output): int
if (!$res) {
$output->writeln("StepObject {$filename} already exists");
- return 1;
+ return Command::FAILURE;
}
$output->writeln("StepObject was created in {$filename}");
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/GenerateSuite.php b/src/Codeception/Command/GenerateSuite.php
index ea82c217fe..606a039448 100644
--- a/src/Codeception/Command/GenerateSuite.php
+++ b/src/Codeception/Command/GenerateSuite.php
@@ -35,31 +35,21 @@ class GenerateSuite extends Command
protected function configure(): void
{
- $this->setDefinition([
- new InputArgument('suite', InputArgument::REQUIRED, 'suite to be generated'),
- new InputArgument('actor', InputArgument::OPTIONAL, 'name of new actor class'),
- ]);
+ $this->setDescription('Generates new test suite')
+ ->addArgument('suite', InputArgument::REQUIRED, 'suite to be generated')
+ ->addArgument('actor', InputArgument::OPTIONAL, 'name of new actor class');
}
- public function getDescription(): string
- {
- return 'Generates new test suite';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->addStyles($output);
$suite = ucfirst((string)$input->getArgument('suite'));
- $actor = $input->getArgument('actor');
+ $config = $this->getGlobalConfig();
+ $actor = $input->getArgument('actor') ?: $suite . $config['actor_suffix'];
if ($this->containsInvalidCharacters($suite)) {
$output->writeln("Suite name '{$suite}' contains invalid characters. ([A-Za-z0-9_]).");
- return 1;
- }
-
- $config = $this->getGlobalConfig();
- if (!$actor) {
- $actor = $suite . $config['actor_suffix'];
+ return Command::FAILURE;
}
$dir = Configuration::testsDir();
@@ -85,26 +75,16 @@ public function execute(InputInterface $input, OutputInterface $output): int
# enable helpers as array
enabled: []
EOF;
-
- $this->createFile(
- $dir . $suite . '.suite.yml',
- $yamlSuiteConfig = (new Template($yamlSuiteConfigTemplate))
- ->place('actor', $actor)
- ->place('suite_namespace', $config['namespace'] . '\\' . $suite)
- ->produce()
- );
-
+ $yamlSuiteConfig = (new Template($yamlSuiteConfigTemplate))
+ ->place('actor', $actor)
+ ->place('suite_namespace', $config['namespace'] . '\\' . $suite)
+ ->produce();
+ $this->createFile($dir . $suite . '.suite.yml', $yamlSuiteConfig);
Configuration::append(Yaml::parse($yamlSuiteConfig));
$actorGenerator = new ActorGenerator(Configuration::config());
$content = $actorGenerator->produce();
-
- $file = $this->createDirectoryFor(
- Configuration::supportDir(),
- $actor
- ) . $this->getShortClassName($actor);
- $file .= '.php';
-
+ $file = $this->createDirectoryFor(Configuration::supportDir(), $actor) . $this->getShortClassName($actor) . '.php';
$this->createFile($file, $content);
$output->writeln("Actor " . $actor . " was created in {$file}");
@@ -117,7 +97,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
$output->writeln("3. Run tests of this suite with codecept run {$suite} command");
$output->writeln("Suite {$suite} generated");
- return 0;
+ return Command::SUCCESS;
}
private function containsInvalidCharacters(string $suite): bool
diff --git a/src/Codeception/Command/GenerateTest.php b/src/Codeception/Command/GenerateTest.php
index 1e9aa61f77..5d1e5a7e05 100644
--- a/src/Codeception/Command/GenerateTest.php
+++ b/src/Codeception/Command/GenerateTest.php
@@ -23,21 +23,12 @@ class GenerateTest extends Command
protected function configure(): void
{
- $this->setDefinition(
- [
- new InputArgument('suite', InputArgument::REQUIRED, 'suite where tests will be put'),
- new InputArgument('class', InputArgument::REQUIRED, 'class name'),
- ]
- );
- parent::configure();
+ $this->setDescription('Generates empty unit test file in suite')
+ ->addArgument('suite', InputArgument::REQUIRED, 'Suite where tests will be put')
+ ->addArgument('class', InputArgument::REQUIRED, 'Class name');
}
- public function getDescription(): string
- {
- return 'Generates empty unit test file in suite';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$suite = $input->getArgument('suite');
$class = $input->getArgument('class');
@@ -46,19 +37,16 @@ public function execute(InputInterface $input, OutputInterface $output): int
$className = $this->getShortClassName($class);
$path = $this->createDirectoryFor($config['path'], $class);
-
- $filename = $this->completeSuffix($className, 'Test');
- $filename = $path . $filename;
+ $filename = $path . $this->completeSuffix($className, 'Test');
$test = new TestGenerator($config, $class);
$res = $this->createFile($filename, $test->produce());
-
if (!$res) {
$output->writeln("Test {$filename} already exists");
- return 1;
+ return Command::FAILURE;
}
$output->writeln("Test was created in {$filename}");
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/GherkinSnippets.php b/src/Codeception/Command/GherkinSnippets.php
index a90112f6c1..3a1657e42e 100644
--- a/src/Codeception/Command/GherkinSnippets.php
+++ b/src/Codeception/Command/GherkinSnippets.php
@@ -31,22 +31,13 @@ class GherkinSnippets extends Command
protected function configure(): void
{
- $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();
+ $this->setDescription('Fetches empty steps from feature files of suite and prints code snippets for them')
+ ->addArgument('suite', InputArgument::REQUIRED, 'Suite to scan for feature files')
+ ->addArgument('test', InputArgument::OPTIONAL, 'Test to be scanned')
+ ->addOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config');
}
- public function getDescription(): string
- {
- return 'Fetches empty steps from feature files of suite and prints code snippets for them';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->addStyles($output);
$suite = $input->getArgument('suite');
@@ -54,16 +45,14 @@ public function execute(InputInterface $input, OutputInterface $output): int
$config = $this->getSuiteConfig($suite);
$generator = new GherkinSnippetsGenerator($config, $test);
-
$snippets = $generator->getSnippets();
- if (empty($snippets)) {
+ if ($snippets === []) {
$output->writeln(" All Gherkin steps are defined. Exiting... ");
- return 0;
+ return Command::SUCCESS;
}
$output->writeln(" Snippets found in: ");
- $features = $generator->getFeatures();
- foreach ($features as $feature) {
+ foreach ($generator->getFeatures() as $feature) {
$output->writeln(" - {$feature} ");
}
$output->writeln(" Generated Snippets: ");
@@ -74,6 +63,6 @@ public function execute(InputInterface $input, OutputInterface $output): int
$output->writeln(" ----------------------------------------- ");
$output->writeln(sprintf(' %d snippets proposed', count($snippets)));
$output->writeln(" Copy generated snippets to {$config['actor']} or a specific Gherkin context ");
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/GherkinSteps.php b/src/Codeception/Command/GherkinSteps.php
index 042592ac83..96a77ff56d 100644
--- a/src/Codeception/Command/GherkinSteps.php
+++ b/src/Codeception/Command/GherkinSteps.php
@@ -29,21 +29,12 @@ class GherkinSteps extends Command
protected function configure(): void
{
- $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();
+ $this->setDescription('Prints all defined feature steps')
+ ->addArgument('suite', InputArgument::REQUIRED, 'suite to scan for feature files')
+ ->addOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config');
}
- public function getDescription(): string
- {
- return 'Prints all defined feature steps';
- }
-
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->addStyles($output);
$suite = $input->getArgument('suite');
@@ -59,11 +50,10 @@ public function execute(InputInterface $input, OutputInterface $output): int
$output->writeln("Steps from {$name} context:");
foreach ($context as $step => $callable) {
- if (count($callable) < 2) {
- continue;
+ if (count($callable) >= 2) {
+ $method = $callable[0] . '::' . $callable[1];
+ $table->addRow([$step, $method]);
}
- $method = $callable[0] . '::' . $callable[1];
- $table->addRow([$step, $method]);
}
$table->render();
}
@@ -71,6 +61,6 @@ public function execute(InputInterface $input, OutputInterface $output): int
if (!isset($table)) {
$output->writeln("No steps are defined, start creating them by running gherkin:snippets");
}
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/Init.php b/src/Codeception/Command/Init.php
index ead5326d2c..841ffb14e2 100644
--- a/src/Codeception/Command/Init.php
+++ b/src/Codeception/Command/Init.php
@@ -19,43 +19,28 @@ class Init extends Command
{
protected function configure(): void
{
- $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(): string
- {
- return "Creates test suites by a template";
+ $this->setDescription("Creates test suites by a template")
+ ->addArgument('template', InputArgument::REQUIRED, 'Init template for the setup')
+ ->addOption('path', null, InputOption::VALUE_REQUIRED, 'Change current directory')
+ ->addOption('namespace', null, InputOption::VALUE_OPTIONAL, 'Namespace to add for actor classes and helpers');
}
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
- $template = (string)$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");
- }
+ $template = (string) $input->getArgument('template');
+ $className = class_exists($template) ? $template : '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");
+ throw new Exception($className . ' is not a valid template');
}
if ($path = $input->getOption('path')) {
$initProcess->initDir($path);
}
$initProcess->setup();
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/Run.php b/src/Codeception/Command/Run.php
index aa815f4f21..ac326b4b70 100644
--- a/src/Codeception/Command/Run.php
+++ b/src/Codeception/Command/Run.php
@@ -89,39 +89,40 @@
*
* 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")
- * --phpunit-xml Generate PhpUnit XML Log (default: "phpunit-report.xml")
- * --no-redirect Do not redirect to Composer-installed version in vendor/codeception
- * --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. Almost the same as `--quiet`
- * --steps Show steps in output
- * --debug (-d) Alias for `-vv`
- * --bootstrap Execute bootstrap script before the test
- * --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")
- * --coverage-cobertura Generate CodeCoverage Cobertura report in file (default: "coverage-cobertura")
- * --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 nth failure (defaults to 1)
- * --no-rebuild Do not rebuild actor classes on start
- * --help (-h) Display this help message.
- * --quiet (-q) Do not output any message. Almost the same as `--silent`
- * --verbose (-v|vv|vvv) Increase the verbosity of messages: `v` for normal output, `vv` for steps and debug, `vvv` for Codeception-internal 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.
- * --seed Use the given seed for shuffling tests
+ * --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")
+ * --phpunit-xml Generate PhpUnit XML Log (default: "phpunit-report.xml")
+ * --no-redirect Do not redirect to Composer-installed version in vendor/codeception
+ * --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. Almost the same as `--quiet`
+ * --steps Show steps in output
+ * --debug (-d) Alias for `-vv`
+ * --bootstrap Execute bootstrap script before the test
+ * --coverage Run with code coverage (default: "coverage.serialized")
+ * --disable-coverage-php Don't generate CodeCoverage report in raw PHP serialized format
+ * --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")
+ * --coverage-cobertura Generate CodeCoverage Cobertura report in file (default: "coverage-cobertura")
+ * --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 nth failure (defaults to 1)
+ * --no-rebuild Do not rebuild actor classes on start
+ * --help (-h) Display this help message.
+ * --quiet (-q) Do not output any message. Almost the same as `--silent`
+ * --verbose (-v|vv|vvv) Increase the verbosity of messages: `v` for normal output, `vv` for steps and debug, `vvv` for Codeception-internal 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.
+ * --seed Use the given seed for shuffling tests
* ```
*
*/
@@ -147,114 +148,42 @@ class Run extends Command
*/
protected function configure(): void
{
- $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('phpunit-xml', '', InputOption::VALUE_OPTIONAL, 'Generate PhpUnit XML Log', 'phpunit-report.xml'),
- 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('shard', '', InputOption::VALUE_REQUIRED, 'Execute subset of tests to run tests on different machine. To split tests on 3 machines to run with shards: 1/3, 2/3, 3/3'),
- new InputOption('filter', '', InputOption::VALUE_REQUIRED, 'Filter tests by name'),
- new InputOption('grep', '', InputOption::VALUE_REQUIRED, 'Filter tests by name (alias to --filter)'),
- new InputOption('bootstrap', '', InputOption::VALUE_OPTIONAL, 'Execute custom PHP script before running tests. Path can be absolute or relative to current working directory', false),
- new InputOption('no-redirect', '', InputOption::VALUE_NONE, 'Do not redirect to Composer-installed version in vendor/codeception'),
- 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-cobertura',
- '',
- InputOption::VALUE_OPTIONAL,
- 'Generate CodeCoverage report in Cobertura 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_OPTIONAL, 'Stop after nth failure'),
- new InputOption('no-rebuild', '', InputOption::VALUE_NONE, 'Do not rebuild actor classes on start'),
- new InputOption(
- 'seed',
- '',
- InputOption::VALUE_REQUIRED,
- 'Define random seed for shuffle setting'
- ),
- new InputOption('no-artifacts', '', InputOption::VALUE_NONE, "Don't report about artifacts"),
- ]);
-
- parent::configure();
- }
-
- public function getDescription(): string
- {
- return 'Runs the test suites';
+ $this->setDescription('Runs the test suites')
+ ->addArgument('suite', InputArgument::OPTIONAL, 'suite to be tested')
+ ->addArgument('test', InputArgument::OPTIONAL, 'test to be run')
+ ->addOption('override', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Override config values')
+ ->addOption('ext', 'e', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Run with extension enabled')
+ ->addOption('report', '', InputOption::VALUE_NONE, 'Show output in compact style')
+ ->addOption('html', '', InputOption::VALUE_OPTIONAL, 'Generate html with results', 'report.html')
+ ->addOption('xml', '', InputOption::VALUE_OPTIONAL, 'Generate JUnit XML Log', 'report.xml')
+ ->addOption('phpunit-xml', '', InputOption::VALUE_OPTIONAL, 'Generate PhpUnit XML Log', 'phpunit-report.xml')
+ ->addOption('colors', '', InputOption::VALUE_NONE, 'Use colors in output')
+ ->addOption('no-colors', '', InputOption::VALUE_NONE, 'Force no colors in output (useful to override config file)')
+ ->addOption('silent', '', InputOption::VALUE_NONE, 'Only outputs suite names and final results')
+ ->addOption('steps', '', InputOption::VALUE_NONE, 'Show steps in output')
+ ->addOption('debug', 'd', InputOption::VALUE_NONE, 'Show debug and scenario output')
+ ->addOption('shard', '', InputOption::VALUE_REQUIRED, 'Execute subset of tests to run tests on different machine. To split tests on 3 machines to run with shards: 1/3, 2/3, 3/3')
+ ->addOption('filter', '', InputOption::VALUE_REQUIRED, 'Filter tests by name')
+ ->addOption('grep', '', InputOption::VALUE_REQUIRED, 'Filter tests by name (alias to --filter)')
+ ->addOption('bootstrap', '', InputOption::VALUE_OPTIONAL, 'Execute custom PHP script before running tests. Path can be absolute or relative to current working directory', false)
+ ->addOption('no-redirect', '', InputOption::VALUE_NONE, 'Do not redirect to Composer-installed version in vendor/codeception')
+ ->addOption('coverage', '', InputOption::VALUE_OPTIONAL, 'Run with code coverage')
+ ->addOption('coverage-html', '', InputOption::VALUE_OPTIONAL, 'Generate CodeCoverage HTML report in path')
+ ->addOption('coverage-xml', '', InputOption::VALUE_OPTIONAL, 'Generate CodeCoverage XML report in file')
+ ->addOption('coverage-text', '', InputOption::VALUE_OPTIONAL, 'Generate CodeCoverage text report in file')
+ ->addOption('coverage-crap4j', '', InputOption::VALUE_OPTIONAL, 'Generate CodeCoverage report in Crap4J XML format')
+ ->addOption('coverage-cobertura', '', InputOption::VALUE_OPTIONAL, 'Generate CodeCoverage report in Cobertura XML format')
+ ->addOption('coverage-phpunit', '', InputOption::VALUE_OPTIONAL, 'Generate CodeCoverage PHPUnit report in path')
+ ->addOption('disable-coverage-php', '', InputOption::VALUE_NONE, "Don't generate CodeCoverage report in raw PHP serialized format")
+ ->addOption('no-exit', '', InputOption::VALUE_NONE, "Don't finish with exit code")
+ ->addOption('group', 'g', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Groups of tests to be executed')
+ ->addOption('skip', 's', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Skip selected suites')
+ ->addOption('skip-group', 'x', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Skip selected groups')
+ ->addOption('env', '', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Run tests in selected environments.')
+ ->addOption('fail-fast', 'f', InputOption::VALUE_OPTIONAL, 'Stop after nth failure')
+ ->addOption('no-rebuild', '', InputOption::VALUE_NONE, 'Do not rebuild actor classes on start')
+ ->addOption('seed', '', InputOption::VALUE_REQUIRED, 'Define random seed for shuffle setting')
+ ->addOption('no-artifacts', '', InputOption::VALUE_NONE, "Don't report about artifacts");
}
/**
@@ -262,7 +191,7 @@ public function getDescription(): string
*
* @throws ConfigurationException|ParseException
*/
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->ensurePhpExtIsAvailable('CURL');
$this->ensurePhpExtIsAvailable('mbstring');
@@ -313,6 +242,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
$userOptions['verbosity'] = $this->output->getVerbosity();
$userOptions['interactive'] = !$input->hasParameterOption(['--no-interaction', '-n']);
$userOptions['ansi'] = (!$input->hasParameterOption('--no-ansi') xor $input->hasParameterOption('ansi'));
+ $userOptions['disable-coverage-php'] = (bool) $this->options['disable-coverage-php'];
$userOptions['seed'] = $this->options['seed'] ? (int)$this->options['seed'] : rand();
if ($this->options['no-colors'] || !$userOptions['ansi']) {
@@ -335,7 +265,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
$userOptions['fail-fast'] = (int)$this->options['fail-fast'] ?: 1;
}
- $suite = $input->getArgument('suite');
+ $suite = (string)$input->getArgument('suite');
$test = $input->getArgument('test');
if ($this->options['group']) {
@@ -469,7 +399,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
if (!empty($wildcardSuites) && ! empty($appSpecificSuites)) {
$this->output->writeLn('Wildcard options can not be combined with specific suites of included apps.');
- return 2;
+ return Command::INVALID;
}
if (
@@ -510,10 +440,10 @@ public function execute(InputInterface $input, OutputInterface $output): int
exit(1);
}
- return 0;
+ return Command::SUCCESS;
}
- protected function matchSingleTest($suite, $config): ?array
+ protected function matchSingleTest(string $suite, array $config): ?array
{
// Workaround when codeception.yml is inside tests directory and tests path is set to "."
// @see https://github.com/Codeception/Codeception/issues/4432
@@ -580,7 +510,7 @@ protected function runIncludedSuites(
string $parentDir,
array $filterAppSuites = [],
array $filterSuitesByWildcard = [],
- ) {
+ ): void {
$defaultConfig = Configuration::config();
$absolutePath = Configuration::projectDir();
@@ -589,13 +519,13 @@ protected function runIncludedSuites(
$config = Configuration::config($currentDir);
if (!empty($defaultConfig['groups'])) {
- $groups = array_map(fn ($g) => $absolutePath . $g, $defaultConfig['groups']);
+ $groups = array_map(fn ($g): string => $absolutePath . $g, $defaultConfig['groups']);
Configuration::append(['groups' => $groups]);
}
$suites = Configuration::suites();
- if (!empty($filterSuitesByWildcard)) {
+ if ($filterSuitesByWildcard !== []) {
$suites = array_intersect($suites, $filterSuitesByWildcard);
}
@@ -701,7 +631,7 @@ private function matchFilteredTestName(string &$path): ?string
// phpunit --filter matches against the fully qualified method name, so tests actually begin with :
$caratPos = strpos($filter, '^');
if ($caratPos !== false) {
- $filter = substr_replace($filter, ':', $caratPos, 1);
+ return substr_replace($filter, ':', $caratPos, 1);
}
return $filter;
}
@@ -789,7 +719,7 @@ private function addRuntimeOptionsToCurrentConfig(array $config): array
}
// enable extensions
if ($this->options['ext']) {
- $config = $this->enableExtensions($this->options['ext']);
+ return $this->enableExtensions($this->options['ext']);
}
return $config;
diff --git a/src/Codeception/Command/SelfUpdate.php b/src/Codeception/Command/SelfUpdate.php
index c31923358a..1f0a82de9b 100644
--- a/src/Codeception/Command/SelfUpdate.php
+++ b/src/Codeception/Command/SelfUpdate.php
@@ -27,10 +27,12 @@ class SelfUpdate extends Command
* @var string
*/
public const NAME = 'Codeception';
+
/**
* @var string
*/
public const GITHUB_REPO = 'Codeception/Codeception';
+
/**
* @var string
*/
@@ -41,21 +43,12 @@ class SelfUpdate extends Command
*/
protected string $filename;
- /**
- * {@inheritdoc}
- */
protected function configure(): void
{
$this->filename = $_SERVER['argv'][0] ?? Phar::running(false);
$this
->setAliases(['selfupdate'])
- ->setDescription(
- sprintf(
- 'Upgrade %s to the latest version',
- $this->filename
- )
- );
- parent::configure();
+ ->setDescription(sprintf('Upgrade %s to the latest version', $this->filename));
}
protected function getCurrentVersion(): string
@@ -63,48 +56,30 @@ protected function getCurrentVersion(): string
return Codecept::VERSION;
}
- /**
- * {@inheritdoc}
- */
- public function execute(InputInterface $input, OutputInterface $output): int
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
- $currentVersion = $this->getCurrentVersion();
-
$output->writeln(
- sprintf(
- '%s version %s',
- self::NAME,
- $currentVersion
- )
+ sprintf('%s version %s', self::NAME, $this->getCurrentVersion())
);
- $url = self::PHAR_URL;
-
$updater = new Updater(null, false);
- $updater->getStrategy()->setPharUrl($url . 'codecept.phar');
- $updater->getStrategy()->setVersionUrl($url . 'codecept.version');
+ $updater->getStrategy()->setPharUrl(self::PHAR_URL . 'codecept.phar');
+ $updater->getStrategy()->setVersionUrl(self::PHAR_URL . 'codecept.version');
try {
if ($updater->hasUpdate()) {
$output->writeln("\nUpdating...");
$updater->update();
- $output->writeln(
- sprintf("\n%s has been updated.\n", $this->filename)
- );
+ $output->writeln("\n{$this->filename} has been updated.\n");
} else {
$output->writeln('You are already using the latest version.');
}
- } catch (Exception $e) {
- $output->writeln(
- sprintf(
- "\n%s\n",
- $e->getMessage()
- )
- );
- return 1;
+ } catch (Exception $exception) {
+ $output->writeln("\n{$exception->getMessage()}\n");
+ return Command::FAILURE;
}
- return 0;
+ return Command::SUCCESS;
}
}
diff --git a/src/Codeception/Command/Shared/ActorTrait.php b/src/Codeception/Command/Shared/ActorTrait.php
index e46a7fdaf9..f6f25b604a 100644
--- a/src/Codeception/Command/Shared/ActorTrait.php
+++ b/src/Codeception/Command/Shared/ActorTrait.php
@@ -29,7 +29,7 @@ protected function getActorClassName(): ?string
return $namespace . $this->settings['actor'];
}
- private function getActor($test)
+ private function getActor($test): ?object
{
$actorClass = $this->getActorClassName();
diff --git a/src/Codeception/Command/Shared/ConfigTrait.php b/src/Codeception/Command/Shared/ConfigTrait.php
index fb8f14e82f..2eed6c8823 100644
--- a/src/Codeception/Command/Shared/ConfigTrait.php
+++ b/src/Codeception/Command/Shared/ConfigTrait.php
@@ -26,7 +26,7 @@ protected function getSuiteConfig(string $suite): array
return Configuration::suiteSettings($suite, $this->getGlobalConfig());
}
- protected function getGlobalConfig(string $conf = null): array
+ protected function getGlobalConfig(?string $conf = null): array
{
return Configuration::config($conf);
}
@@ -34,7 +34,7 @@ protected function getGlobalConfig(string $conf = null): array
/**
* @return string[]
*/
- protected function getSuites($conf = null): array
+ protected function getSuites(): array
{
return Configuration::suites();
}
diff --git a/src/Codeception/Configuration.php b/src/Codeception/Configuration.php
index d123d62cfb..49ecfed6a5 100644
--- a/src/Codeception/Configuration.php
+++ b/src/Codeception/Configuration.php
@@ -132,7 +132,7 @@ class Configuration
'enabled' => [],
'config' => [],
],
- 'error_level' => 'E_ALL & ~E_STRICT & ~E_DEPRECATED',
+ 'error_level' => 'E_ALL & ~E_DEPRECATED',
'convert_deprecations_to_exceptions' => false,
];
@@ -148,7 +148,7 @@ class Configuration
* @return array
* @throws ConfigurationException
*/
- public static function config(string $configFile = null): array
+ public static function config(?string $configFile = null): array
{
if (!$configFile && self::$config) {
return self::$config;
@@ -212,7 +212,7 @@ public static function config(string $configFile = null): array
$config = self::mergeConfigs($config, self::getConfFromContents($configContents, $configFile));
}
- if ($config == self::$defaultConfig) {
+ if ($config === self::$defaultConfig) {
throw new ConfigurationException("Configuration file is invalid");
}
@@ -361,7 +361,7 @@ public static function suiteSettings(string $suite, array $config): array
$settings['path'] = $suite;
}
- $config['paths']['tests'] = str_replace('/', DIRECTORY_SEPARATOR, $config['paths']['tests']);
+ $config['paths']['tests'] = str_replace('/', DIRECTORY_SEPARATOR, (string) $config['paths']['tests']);
$settings['path'] = self::$dir . DIRECTORY_SEPARATOR . $config['paths']['tests']
. DIRECTORY_SEPARATOR . $settings['path'] . DIRECTORY_SEPARATOR;
@@ -495,7 +495,7 @@ public static function modules(array $settings): array
{
return array_filter(
array_map(
- fn ($m) => is_array($m) ? key($m) : $m,
+ fn ($m): mixed => is_array($m) ? key($m) : $m,
$settings['modules']['enabled'],
array_keys($settings['modules']['enabled'])
),
@@ -723,7 +723,7 @@ protected static function loadSuiteConfig(string $suite, string $path, array $se
*/
protected static function expandWildcardedIncludes(array $includes): array
{
- if (empty($includes)) {
+ if ($includes === []) {
return $includes;
}
$expandedIncludes = [];
diff --git a/src/Codeception/Coverage/Filter.php b/src/Codeception/Coverage/Filter.php
index f572936ad0..00e87f9892 100644
--- a/src/Codeception/Coverage/Filter.php
+++ b/src/Codeception/Coverage/Filter.php
@@ -61,40 +61,31 @@ public function whiteList(array $config): self
return $this->newWhiteList($coverage['whitelist']);
}
- if (isset($coverage['whitelist']['include'])) {
- if (!is_array($coverage['whitelist']['include'])) {
- throw new ConfigurationException('Error parsing yaml. Config `whitelist: include:` should be an array');
- }
- foreach ($coverage['whitelist']['include'] as $fileOrDir) {
- $finder = !str_contains($fileOrDir, '*')
- ? [Configuration::projectDir() . DIRECTORY_SEPARATOR . $fileOrDir]
- : $this->matchWildcardPattern($fileOrDir);
-
- foreach ($finder as $file) {
- $filter->includeFile((string)$file);
- }
+ foreach (['include', 'exclude'] as $type) {
+ if (!isset($coverage['whitelist'][$type])) {
+ continue;
}
- }
- if (isset($coverage['whitelist']['exclude'])) {
- if (!is_array($coverage['whitelist']['exclude'])) {
- throw new ConfigurationException('Error parsing yaml. Config `whitelist: exclude:` should be an array');
+ if (!is_array($coverage['whitelist'][$type])) {
+ throw new ConfigurationException("Error parsing yaml. Config `whitelist: {$type}:` should be an array");
}
- foreach ($coverage['whitelist']['exclude'] as $fileOrDir) {
+ foreach ($coverage['whitelist'][$type] as $fileOrDir) {
try {
- $finder = !str_contains($fileOrDir, '*')
- ? [Configuration::projectDir() . DIRECTORY_SEPARATOR . $fileOrDir]
- : $this->matchWildcardPattern($fileOrDir);
+ $finder = str_contains($fileOrDir, '*')
+ ? $this->matchWildcardPattern($fileOrDir)
+ : [Configuration::projectDir() . DIRECTORY_SEPARATOR . $fileOrDir];
foreach ($finder as $file) {
- $filter->excludeFile((string)$file);
+ $file = (string) $file;
+ $type === 'include' ? $filter->includeFile($file) : $filter->excludeFile($file);
}
} catch (DirectoryNotFoundException) {
continue;
}
}
}
+
return $this;
}
@@ -110,45 +101,45 @@ private function newWhiteList(array $whitelist): self
throw new ConfigurationException('Error parsing yaml. Config `whitelist: exclude:` should be an array');
}
- if (count($exclude) === 0 && count($include) === 0) {
+ if ($exclude === [] && $include === []) {
return $this;
}
- if (count($include) === 0) {
+ if ($include === []) {
$include = [
Configuration::projectDir() . DIRECTORY_SEPARATOR . '*'
];
}
- $allIncludedFiles = [];
- foreach ($include as $fileOrDir) {
- $finder = !str_contains($fileOrDir, '*')
- ? $this->matchFileOrDirectory($fileOrDir)
- : $this->matchWildcardPattern($fileOrDir);
+ $allIncludedFiles = $this->matchFiles($include);
+ $allExcludedFiles = $this->matchFiles($exclude);
- $allIncludedFiles += iterator_to_array($finder->getIterator());
+ $coveredFiles = array_diff($allIncludedFiles, $allExcludedFiles);
+
+ foreach ($coveredFiles as $coveredFile) {
+ $this->phpUnitFilter->includeFile((string) $coveredFile);
}
- $allExcludedFiles = [];
- foreach ($exclude as $fileOrDir) {
+ return $this;
+ }
+
+ private function matchFiles(array $files): array
+ {
+ $matchedFiles = [];
+
+ foreach ($files as $fileOrDir) {
try {
- $finder = !str_contains($fileOrDir, '*')
- ? $this->matchFileOrDirectory($fileOrDir)
- : $this->matchWildcardPattern($fileOrDir);
+ $finder = str_contains($fileOrDir, '*')
+ ? $this->matchWildcardPattern($fileOrDir)
+ : $this->matchFileOrDirectory($fileOrDir);
- $allExcludedFiles += iterator_to_array($finder->getIterator());
+ $matchedFiles += iterator_to_array($finder->getIterator());
} catch (DirectoryNotFoundException) {
continue;
}
}
- $coveredFiles = array_diff($allIncludedFiles, $allExcludedFiles);
-
- foreach ($coveredFiles as $coveredFile) {
- $this->phpUnitFilter->includeFile((string)$coveredFile);
- }
-
- return $this;
+ return $matchedFiles;
}
/**
@@ -190,11 +181,8 @@ protected function matchWildcardPattern(string $pattern): Finder
$finder->name($file);
if ($parts !== []) {
$lastPath = array_pop($parts);
- if ($lastPath === '*') {
- $finder->in(Configuration::projectDir() . implode('/', $parts));
- } else {
- $finder->in(Configuration::projectDir() . implode('/', [...$parts, $lastPath]));
- }
+ $path = implode('/', ($lastPath === '*' ? $parts : [...$parts, $lastPath]));
+ $finder->in(Configuration::projectDir() . $path);
}
$finder->ignoreVCS(true)->files();
return $finder;
diff --git a/src/Codeception/Coverage/PhpCodeCoverageFactory.php b/src/Codeception/Coverage/PhpCodeCoverageFactory.php
index 182af7b39d..bac262a308 100644
--- a/src/Codeception/Coverage/PhpCodeCoverageFactory.php
+++ b/src/Codeception/Coverage/PhpCodeCoverageFactory.php
@@ -15,22 +15,18 @@ class PhpCodeCoverageFactory
public static function build(): CodeCoverage
{
- if (self::$instance !== null) {
+ if (self::$instance instanceof CodeCoverage) {
return self::$instance;
}
- $coverageConfiguration = Configuration::config()['coverage'];
- $pathCoverage = $coverageConfiguration['path_coverage'] ?? false;
+ $coverageConfig = Configuration::config()['coverage'];
+ $pathCoverage = $coverageConfig['path_coverage'] ?? false;
$filter = new CodeCoverageFilter();
- if ($pathCoverage) {
- $driver = (new Selector())->forLineAndPathCoverage($filter);
- } else {
- $driver = (new Selector())->forLineCoverage($filter);
- }
- self::$instance = new CodeCoverage($driver, $filter);
+ $selector = new Selector();
+ $driver = $pathCoverage ? $selector->forLineAndPathCoverage($filter) : $selector->forLineCoverage($filter);
- return self::$instance;
+ return self::$instance = new CodeCoverage($driver, $filter);
}
public static function clear(): void
diff --git a/src/Codeception/Coverage/Subscriber/Local.php b/src/Codeception/Coverage/Subscriber/Local.php
index 0de32083a3..441f0a3aea 100644
--- a/src/Codeception/Coverage/Subscriber/Local.php
+++ b/src/Codeception/Coverage/Subscriber/Local.php
@@ -12,12 +12,7 @@
use Codeception\Exception\ConfigurationException;
use Codeception\Exception\ModuleException;
use Codeception\Lib\Interfaces\Remote;
-use Codeception\Stub;
use Exception;
-use PHPUnit\Runner\CodeCoverage as PHPUnitCodeCoverage;
-use PHPUnit\Runner\Version as PHPUnitVersion;
-use SebastianBergmann\CodeCoverage\CodeCoverage;
-use SebastianBergmann\CodeCoverage\Filter as CodeCoverageFilter;
/**
* Collects code coverage from unit and functional tests.
diff --git a/src/Codeception/Coverage/Subscriber/LocalServer.php b/src/Codeception/Coverage/Subscriber/LocalServer.php
index f2c971436a..2b45b912a7 100644
--- a/src/Codeception/Coverage/Subscriber/LocalServer.php
+++ b/src/Codeception/Coverage/Subscriber/LocalServer.php
@@ -20,16 +20,12 @@
use SebastianBergmann\CodeCoverage\CodeCoverage;
use function array_filter;
-use function array_key_exists;
use function array_replace_recursive;
-use function codecept_debug;
use function file_exists;
use function file_get_contents;
-use function is_array;
use function json_encode;
use function parse_url;
use function preg_match;
-use function rtrim;
use function str_replace;
use function stream_context_create;
use function unserialize;
@@ -79,7 +75,7 @@ class LocalServer extends SuiteSubscriber
protected array $c3Access = [
'http' => [
- 'method' => "GET",
+ 'method' => 'GET',
'header' => ''
]
];
@@ -113,8 +109,7 @@ public function beforeSuite(SuiteEvent $event): void
if ($this->settings['remote_config']) {
$this->addC3AccessHeader(self::COVERAGE_HEADER_CONFIG, $this->settings['remote_config']);
- $knock = $this->c3Request('clear');
- if ($knock === false) {
+ if ($this->c3Request('clear') === false) {
throw new RemoteException(
'
CodeCoverage Error.
@@ -149,44 +144,23 @@ public function afterSuite(SuiteEvent $event): void
return;
}
- // wait for all running tests to finish
- $blockfilename = Configuration::outputDir() . 'c3tmp/block_report';
- if (file_exists($blockfilename) && filesize($blockfilename) !== 0) {
- $retries = 120; // 30 sec total
- while (file_get_contents($blockfilename) !== '0' && --$retries >= 0) {
- usleep(250_000); // 0.25 sec
- }
- if (file_get_contents($blockfilename) !== '0' && $retries === -1) {
- Notification::warning(
- 'Timeout: Some coverage data is not included in the coverage report.',
- '',
- );
- }
- }
+ $outputDir = Configuration::outputDir() . 'c3tmp/';
+ $blockFile = $outputDir . 'block_report';
+ $coverageFile = $outputDir . 'codecoverage.serialized';
+ $errorFile = $outputDir . 'error.txt';
- $coverageFile = Configuration::outputDir() . 'c3tmp/codecoverage.serialized';
- $retries = 5;
- while (!file_exists($coverageFile) && --$retries >= 0) {
- $seconds = (int)(0.5 * 1_000_000); // 0.5 sec
- usleep($seconds);
- }
+ $this->waitForFile($blockFile, 120, 250_000);
+ $this->waitForFile($coverageFile, 5, 500_000);
if (!file_exists($coverageFile)) {
- if (file_exists(Configuration::outputDir() . 'c3tmp/error.txt')) {
- throw new RuntimeException(file_get_contents(Configuration::outputDir() . 'c3tmp/error.txt'));
- }
-
- throw new RuntimeException('Code coverage file ' . $coverageFile . ' does not exist');
+ throw new RuntimeException(
+ file_exists($errorFile) ? file_get_contents($errorFile) : "Code coverage file {$coverageFile} does not exist"
+ );
}
- $contents = file_get_contents($coverageFile);
- $coverage = @unserialize($contents);
- if ($coverage === false) {
- return;
+ if ($coverage = @unserialize(file_get_contents($coverageFile))) {
+ $this->preProcessCoverage($coverage)->mergeToPrint($coverage);
}
-
- $this->preProcessCoverage($coverage)
- ->mergeToPrint($coverage);
}
/**
@@ -194,25 +168,21 @@ public function afterSuite(SuiteEvent $event): void
*/
protected function preProcessCoverage(CodeCoverage $coverage): self
{
- //Only Process If Work Directory Set
- if ($this->settings['work_dir'] === null) {
+ if (!$this->settings['work_dir']) {
return $this;
}
- $workDir = rtrim($this->settings['work_dir'], '/\\') . DIRECTORY_SEPARATOR;
+ $workDir = rtrim((string) $this->settings['work_dir'], '/\\') . DIRECTORY_SEPARATOR;
$projectDir = Configuration::projectDir();
- $coverageData = $coverage->getData(true); //We only want covered files, not all whitelisted ones.
+ $coverageData = $coverage->getData(true); // We only want covered files, not all whitelisted ones.
codecept_debug("Replacing all instances of {$workDir} with {$projectDir}");
foreach ($coverageData as $path => $datum) {
unset($coverageData[$path]);
-
- $path = str_replace($workDir, $projectDir, $path);
-
+ $path = str_replace($workDir, $projectDir, (string) $path);
$coverageData[$path] = $datum;
}
-
$coverage->setData($coverageData);
return $this;
@@ -222,14 +192,14 @@ protected function c3Request(string $action): string|false
{
$this->addC3AccessHeader(self::COVERAGE_HEADER, 'remote-access');
$context = stream_context_create($this->c3Access);
- $c3Url = $this->settings['c3_url'] ?: $this->module->_getUrl();
- $contents = file_get_contents($c3Url . '/c3/report/' . $action, false, $context);
+ $c3Url = $this->settings['c3_url'] ?? $this->module->_getUrl();
+ $contents = file_get_contents("{$c3Url}/c3/report/{$action}", false, $context);
$okHeaders = array_filter(
$http_response_header,
fn ($h) => preg_match('#^HTTP(.*?)\s200#', $h)
);
- if (empty($okHeaders)) {
+ if ($okHeaders === []) {
throw new RemoteException("Request was not successful. See response header: " . $http_response_header[0]);
}
if ($contents === false) {
@@ -238,60 +208,52 @@ protected function c3Request(string $action): string|false
return $contents;
}
- protected function startCoverageCollection($testName): void
+ protected function startCoverageCollection(string $testName): void
{
- $value = [
+ $coverageDataJson = json_encode([
'CodeCoverage' => $testName,
'CodeCoverage_Suite' => $this->suiteName,
'CodeCoverage_Config' => $this->settings['remote_config']
- ];
- $value = json_encode($value, JSON_THROW_ON_ERROR);
+ ], JSON_THROW_ON_ERROR);
if ($this->module instanceof WebDriverModule) {
$this->module->amOnPage('/');
}
- $cookieDomain = $this->settings['cookie_domain'] ?? null;
+ $cookieDomain = $this->settings['cookie_domain'] ??
+ parse_url($this->settings['c3_url'] ?? $this->module->_getUrl(), PHP_URL_HOST) ??
+ 'localhost';
if (!$cookieDomain) {
- $c3Url = parse_url($this->settings['c3_url'] ?: $this->module->_getUrl());
-
// we need to separate coverage cookies by host; we can't separate cookies by port.
- $cookieDomain = $c3Url['host'] ?? 'localhost';
- }
-
- $cookieParams = [];
- if ($cookieDomain !== 'localhost') {
- $cookieParams['domain'] = $cookieDomain;
+ $cookieDomain = 'localhost';
}
- $this->module->setCookie(self::COVERAGE_COOKIE, $value, $cookieParams);
+ $cookieParams = $cookieDomain !== 'localhost' ? ['domain' => $cookieDomain] : [];
+ $this->module->setCookie(self::COVERAGE_COOKIE, $coverageDataJson, $cookieParams);
// putting in configuration ensures the cookie is used for all sessions of a MultiSession test
$cookies = $this->module->_getConfig('cookies');
- if (!$cookies || !is_array($cookies)) {
+ if (!is_array($cookies)) {
$cookies = [];
}
- $found = false;
+ $cookieUpdated = false;
foreach ($cookies as &$cookie) {
- if (!is_array($cookie) || !array_key_exists('Name', $cookie) || !array_key_exists('Value', $cookie)) {
- // \Codeception\Lib\InnerBrowser will complain about this
- continue;
- }
- if ($cookie['Name'] === self::COVERAGE_COOKIE) {
- $found = true;
- $cookie['Value'] = $value;
+ if (isset($cookie['Name'], $cookie['Value']) && $cookie['Name'] === self::COVERAGE_COOKIE) {
+ $cookie['Value'] = $coverageDataJson;
+ $cookieUpdated = true;
break;
}
+ // \Codeception\Lib\InnerBrowser will complain about this
}
unset($cookie);
- if (!$found) {
+ if (!$cookieUpdated) {
$cookies[] = [
'Name' => self::COVERAGE_COOKIE,
- 'Value' => $value
+ 'Value' => $coverageDataJson
];
}
@@ -304,8 +266,7 @@ protected function fetchErrors(): void
// @see https://github.com/Codeception/Codeception/issues/1485
if ($this->module instanceof WebDriverModule) {
try {
- $alert = $this->module->webDriver->switchTo()->alert();
- $alert->getText();
+ $this->module->webDriver->switchTo()->alert()->getText();
// If this succeeds an alert is present, abort
return;
} catch (NoSuchAlertException) {
@@ -318,7 +279,7 @@ protected function fetchErrors(): void
} catch (ModuleException) {
// when a new session is started we can't get cookies because there is no
// current page, but there can be no code coverage error either
- $error = null;
+ return;
}
if (!empty($error)) {
$this->module->resetCookie(self::COVERAGE_COOKIE_ERROR);
@@ -326,6 +287,7 @@ protected function fetchErrors(): void
}
}
+ /** @param string[] $headers */
protected function getRemoteError(array $headers): void
{
foreach ($headers as $header) {
@@ -338,7 +300,7 @@ protected function getRemoteError(array $headers): void
protected function addC3AccessHeader(string $header, string $value): void
{
$headerString = "{$header}: {$value}\r\n";
- if (!str_contains($this->c3Access['http']['header'], $headerString)) {
+ if (!str_contains((string) $this->c3Access['http']['header'], $headerString)) {
$this->c3Access['http']['header'] .= $headerString;
}
}
@@ -350,4 +312,17 @@ protected function applySettings(array $settings): void
$this->c3Access = array_replace_recursive($this->c3Access, $settings['coverage']['remote_context_options']);
}
}
+
+ private function waitForFile(string $file, int $maxRetries, int $sleepTime): void
+ {
+ $retries = $maxRetries;
+ while ($retries > 0 && (!file_exists($file) || file_get_contents($file) !== '0')) {
+ usleep($sleepTime);
+ $retries--;
+ }
+
+ if (!file_exists($file) || file_get_contents($file) !== '0') {
+ Notification::warning('Timeout: Some coverage data is not included in the coverage report.', '');
+ }
+ }
}
diff --git a/src/Codeception/Coverage/Subscriber/Printer.php b/src/Codeception/Coverage/Subscriber/Printer.php
index 1f627fd58c..718d46476b 100644
--- a/src/Codeception/Coverage/Subscriber/Printer.php
+++ b/src/Codeception/Coverage/Subscriber/Printer.php
@@ -9,7 +9,6 @@
use Codeception\Coverage\PhpCodeCoverageFactory;
use Codeception\Event\PrintResultEvent;
use Codeception\Events;
-use Codeception\Exception\ConfigurationException;
use Codeception\Lib\Console\Output;
use Codeception\Subscriber\Shared\StaticEventsTrait;
use PHPUnit\Runner\Version as PHPUnitVersion;
@@ -25,9 +24,8 @@
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use function array_merge;
-use function class_exists;
use function file_put_contents;
-use function sprintf;
+use function str_starts_with;
use function strpos;
class Printer implements EventSubscriberInterface
@@ -53,7 +51,7 @@ class Printer implements EventSubscriberInterface
protected string $logDir;
- public function __construct(protected array $options, private Output $output)
+ public function __construct(protected array $options, private readonly Output $output)
{
$this->logDir = Configuration::outputDir();
$this->settings = array_merge($this->settings, Configuration::config()['coverage']);
@@ -68,7 +66,7 @@ public function __construct(protected array $options, private Output $output)
protected function absolutePath(string $path): string
{
- if ((str_starts_with($path, '/')) || (strpos($path, ':') === 1)) { // absolute path
+ if (str_starts_with($path, '/') || strpos($path, ':') === 1) { // absolute path
return $path;
}
return $this->logDir . $path;
@@ -85,78 +83,39 @@ public function printResult(PrintResultEvent $event): void
$this->printConsole();
}
$this->output->write("Remote CodeCoverage reports are not printed to console\n");
- $this->printPHP();
- $this->output->write("\n");
- if ($this->options['coverage-html']) {
- $this->printHtml();
- $this->output->write("HTML report generated in {$this->options['coverage-html']}\n");
- }
- if ($this->options['coverage-xml']) {
- $this->printXml();
- $this->output->write("XML report generated in {$this->options['coverage-xml']}\n");
- }
- if ($this->options['coverage-text']) {
- $this->printText();
- $this->output->write("Text report generated in {$this->options['coverage-text']}\n");
- }
- if ($this->options['coverage-crap4j']) {
- $this->printCrap4j();
- $this->output->write("Crap4j report generated in {$this->options['coverage-crap4j']}\n");
- }
- if ($this->options['coverage-cobertura']) {
- $this->printCobertura();
- $this->output->write("Cobertura report generated in {$this->options['coverage-cobertura']}\n");
+ if ($this->options['disable-coverage-php'] === true) {
+ $this->output->write("PHP serialized report was skipped\n");
+ } else {
+ $this->printPHP();
}
- if ($this->options['coverage-phpunit']) {
- $this->printPHPUnit();
- $this->output->write("PHPUnit report generated in {$this->options['coverage-phpunit']}\n");
+ $this->output->write("\n");
+
+ $reports = [
+ 'HTML' => ['name' => 'coverage-html', 'method' => 'printHTML'],
+ 'XML' => ['name' => 'coverage-xml', 'method' => 'printXML'],
+ 'Text' => ['name' => 'coverage-text', 'method' => 'printText'],
+ 'Crap4j' => ['name' => 'coverage-crap4j', 'method' => 'printCrap4j'],
+ 'Cobertura' => ['name' => 'coverage-cobertura', 'method' => 'printCobertura'],
+ 'PHPUnit' => ['name' => 'coverage-phpunit', 'method' => 'printPHPUnit'],
+ ];
+
+ foreach ($reports as $reportType => $reportData) {
+ if ($option = $this->options[$reportData['name']]) {
+ $this->{$reportData['method']}();
+ $this->output->write("{$reportType} report generated in {$option}\n");
+ }
}
}
protected function printConsole(): void
{
- if (PHPUnitVersion::series() < 10) {
- $writer = new TextReport(
- $this->settings['low_limit'],
- $this->settings['high_limit'],
- $this->settings['show_uncovered'],
- $this->settings['show_only_summary']
- );
- } else {
- $writer = new TextReport(
- Thresholds::from(
- $this->settings['low_limit'],
- $this->settings['high_limit'],
- ),
- $this->settings['show_uncovered'],
- $this->settings['show_only_summary']
- );
- }
+ $writer = $this->createTextWriter();
$this->output->write($writer->process(self::$coverage, $this->options['colors']));
}
protected function printHtml(): void
{
- if (PHPUnitVersion::series() < 10) {
- $writer = new HtmlFacadeReport(
- $this->settings['low_limit'],
- $this->settings['high_limit'],
- sprintf(
- ', Codeception and PHPUnit %s',
- PHPUnitVersion::id()
- )
- );
- } else {
- $writer = new HtmlFacadeReport(
- sprintf(
- ', Codeception and PHPUnit %s',
- PHPUnitVersion::id()
- ),
- null,
- Thresholds::from($this->settings['low_limit'], $this->settings['high_limit']),
- );
- }
-
+ $writer = $this->createHtmlFacadeWriter();
$writer->process(self::$coverage, $this->absolutePath($this->options['coverage-html']));
}
@@ -174,27 +133,10 @@ protected function printPHP(): void
protected function printText(): void
{
- if (PHPUnitVersion::series() < 10) {
- $writer = new TextReport(
- $this->settings['low_limit'],
- $this->settings['high_limit'],
- $this->settings['show_uncovered'],
- $this->settings['show_only_summary']
- );
- } else {
- $writer = new TextReport(
- Thresholds::from(
- $this->settings['low_limit'],
- $this->settings['high_limit'],
- ),
- $this->settings['show_uncovered'],
- $this->settings['show_only_summary']
- );
- }
-
+ $writer = $this->createTextWriter();
file_put_contents(
$this->absolutePath($this->options['coverage-text']),
- $writer->process(self::$coverage, false)
+ $writer->process(self::$coverage)
);
}
@@ -215,4 +157,19 @@ protected function printPHPUnit(): void
$writer = new XmlFacadeReport(PHPUnitVersion::id());
$writer->process(self::$coverage, $this->absolutePath($this->options['coverage-phpunit']));
}
+
+ private function createHtmlFacadeWriter(): HtmlFacadeReport
+ {
+ $generator = ', Codeception and PHPUnit {PHPUnitVersion::id()}';
+ return PHPUnitVersion::series() < 10 ?
+ new HtmlFacadeReport($this->settings['low_limit'], $this->settings['high_limit'], $generator) :
+ new HtmlFacadeReport($generator, null, Thresholds::from($this->settings['low_limit'], $this->settings['high_limit']));
+ }
+
+ private function createTextWriter(): TextReport
+ {
+ return PHPUnitVersion::series() < 10 ?
+ new TextReport($this->settings['low_limit'], $this->settings['high_limit'], $this->settings['show_uncovered'], $this->settings['show_only_summary']) :
+ new TextReport(Thresholds::from($this->settings['low_limit'], $this->settings['high_limit']), $this->settings['show_uncovered'], $this->settings['show_only_summary']);
+ }
}
diff --git a/src/Codeception/Coverage/Subscriber/RemoteServer.php b/src/Codeception/Coverage/Subscriber/RemoteServer.php
index 98bcb9e92d..0a8cf446e6 100644
--- a/src/Codeception/Coverage/Subscriber/RemoteServer.php
+++ b/src/Codeception/Coverage/Subscriber/RemoteServer.php
@@ -36,67 +36,37 @@ public function afterSuite(SuiteEvent $event): void
if (!$this->isEnabled()) {
return;
}
-
$suite = strtr($event->getSuite()->getName(), ['\\' => '.']);
+
if ($this->options['coverage-xml']) {
- $this->retrieveAndPrintXml($suite);
+ $this->retrieveAndPrint('clover', $suite, '.remote.coverage.xml');
}
if ($this->options['coverage-html']) {
- $this->retrieveAndPrintHtml($suite);
+ $this->retrieveToTempFileAndPrint('html', $suite, '.remote.coverage');
}
if ($this->options['coverage-crap4j']) {
- $this->retrieveAndPrintCrap4j($suite);
+ $this->retrieveAndPrint('crap4j', $suite, '.remote.crap4j.xml');
}
if ($this->options['coverage-cobertura']) {
- $this->retrieveAndPrintCobertura($suite);
+ $this->retrieveAndPrint('cobertura', $suite, '.remote.cobertura.xml');
}
if ($this->options['coverage-phpunit']) {
- $this->retrieveAndPrintPHPUnit($suite);
- }
- }
-
- protected function retrieveAndPrintHtml(string $suite): void
- {
- $tempFile = tempnam(sys_get_temp_dir(), 'C3') . '.tar';
- file_put_contents($tempFile, $this->c3Request('html'));
-
- $destDir = Configuration::outputDir() . $suite . '.remote.coverage';
- if (is_dir($destDir)) {
- FileSystem::doEmptyDir($destDir);
- } else {
- mkdir($destDir, 0777, true);
+ $this->retrieveToTempFileAndPrint('phpunit', $suite, '.remote.coverage-phpunit');
}
-
- $pharData = new PharData($tempFile);
- $pharData->extractTo($destDir);
-
- unlink($tempFile);
- }
-
- protected function retrieveAndPrintXml(string $suite): void
- {
- $destFile = Configuration::outputDir() . $suite . '.remote.coverage.xml';
- file_put_contents($destFile, $this->c3Request('clover'));
- }
-
- protected function retrieveAndPrintCrap4j(string $suite): void
- {
- $destFile = Configuration::outputDir() . $suite . '.remote.crap4j.xml';
- file_put_contents($destFile, $this->c3Request('crap4j'));
}
- protected function retrieveAndPrintCobertura(string $suite): void
+ protected function retrieveAndPrint(string $type, string $suite, string $extension): void
{
- $destFile = Configuration::outputDir() . $suite . '.remote.cobertura.xml';
- file_put_contents($destFile, $this->c3Request('cobertura'));
+ $destFile = Configuration::outputDir() . $suite . $extension;
+ file_put_contents($destFile, $this->c3Request($type));
}
- protected function retrieveAndPrintPHPUnit(string $suite): void
+ protected function retrieveToTempFileAndPrint(string $type, string $suite, string $extension): void
{
$tempFile = tempnam(sys_get_temp_dir(), 'C3') . '.tar';
- file_put_contents($tempFile, $this->c3Request('phpunit'));
+ file_put_contents($tempFile, $this->c3Request($type));
- $destDir = Configuration::outputDir() . $suite . '.remote.coverage-phpunit';
+ $destDir = Configuration::outputDir() . $suite . $extension;
if (is_dir($destDir)) {
FileSystem::doEmptyDir($destDir);
} else {
diff --git a/src/Codeception/Coverage/SuiteSubscriber.php b/src/Codeception/Coverage/SuiteSubscriber.php
index 1316450147..647ae44ccc 100644
--- a/src/Codeception/Coverage/SuiteSubscriber.php
+++ b/src/Codeception/Coverage/SuiteSubscriber.php
@@ -84,6 +84,11 @@ protected function applySettings(array $settings): void
}
}
+ $this->configureCoverage();
+ }
+
+ protected function configureCoverage(): void
+ {
if ($this->settings['strict_covers_annotation']) {
$this->coverage->enableCheckForUnintentionallyCoveredCode();
}
diff --git a/src/Codeception/Exception/Error.php b/src/Codeception/Exception/Error.php
index bf7b58948a..8e226fc105 100644
--- a/src/Codeception/Exception/Error.php
+++ b/src/Codeception/Exception/Error.php
@@ -8,7 +8,7 @@
class Error extends Exception
{
- public function __construct(string $message, int $code, string $file, int $line, \Exception $previous = null)
+ public function __construct(string $message, int $code, string $file, int $line, ?\Exception $previous = null)
{
parent::__construct($message, $code, $previous);
diff --git a/src/Codeception/Exception/ExtensionException.php b/src/Codeception/Exception/ExtensionException.php
index c8adace7c6..ddd98112e6 100644
--- a/src/Codeception/Exception/ExtensionException.php
+++ b/src/Codeception/Exception/ExtensionException.php
@@ -15,7 +15,7 @@ class ExtensionException extends Exception
*
* @param object|string $extension
*/
- public function __construct($extension, string $message, Exception $previous = null)
+ public function __construct($extension, string $message, ?Exception $previous = null)
{
parent::__construct($message, 0, $previous);
if (is_object($extension)) {
diff --git a/src/Codeception/Exception/ModuleConfigException.php b/src/Codeception/Exception/ModuleConfigException.php
index 315cdf8f11..5a7a4ae1fb 100644
--- a/src/Codeception/Exception/ModuleConfigException.php
+++ b/src/Codeception/Exception/ModuleConfigException.php
@@ -17,7 +17,7 @@ class ModuleConfigException extends Exception
*
* @param object|string $module
*/
- public function __construct($module, string $message, Exception $previous = null)
+ public function __construct($module, string $message, ?Exception $previous = null)
{
if (is_object($module)) {
$module = $module::class;
diff --git a/src/Codeception/Exception/TestParseException.php b/src/Codeception/Exception/TestParseException.php
index 4e2df4cb13..04ae1a775b 100644
--- a/src/Codeception/Exception/TestParseException.php
+++ b/src/Codeception/Exception/TestParseException.php
@@ -8,7 +8,7 @@
class TestParseException extends Exception
{
- public function __construct(string $fileName, string $errors = null, int $line = null)
+ public function __construct(string $fileName, ?string $errors = null, ?int $line = null)
{
$this->message = "Couldn't parse test '{$fileName}'";
if ($line !== null) {
diff --git a/src/Codeception/InitTemplate.php b/src/Codeception/InitTemplate.php
index 797a42f6e9..f9e50135f6 100644
--- a/src/Codeception/InitTemplate.php
+++ b/src/Codeception/InitTemplate.php
@@ -97,7 +97,7 @@ abstract public function setup();
*
* @return mixed|string
*/
- protected function ask(string $question, string|bool|array $answer = null): mixed
+ protected function ask(string $question, string|bool|array|null $answer = null): mixed
{
$question = "? {$question}";
$dialog = new QuestionHelper();
diff --git a/src/Codeception/Lib/Actor/Shared/Comment.php b/src/Codeception/Lib/Actor/Shared/Comment.php
index fe9a8a6108..44e20d68ed 100644
--- a/src/Codeception/Lib/Actor/Shared/Comment.php
+++ b/src/Codeception/Lib/Actor/Shared/Comment.php
@@ -29,7 +29,7 @@ public function am(string $role): self
{
$role = trim($role);
- if (stripos('aeiou', (string)$role[0]) !== false) {
+ if (stripos('aeiou', $role[0]) !== false) {
return $this->comment('As an ' . $role);
}
diff --git a/src/Codeception/Lib/Actor/Shared/Friend.php b/src/Codeception/Lib/Actor/Shared/Friend.php
index 7961f14d20..50f90ffd1d 100644
--- a/src/Codeception/Lib/Actor/Shared/Friend.php
+++ b/src/Codeception/Lib/Actor/Shared/Friend.php
@@ -13,7 +13,7 @@ trait Friend
abstract protected function getScenario(): Scenario;
- public function haveFriend(string $name, string $actorClass = null): LibFriend
+ public function haveFriend(string $name, ?string $actorClass = null): LibFriend
{
if (!isset($this->friends[$name])) {
$actor = $actorClass === null ? $this : new $actorClass($this->getScenario());
diff --git a/src/Codeception/Lib/Actor/Shared/Pause.php b/src/Codeception/Lib/Actor/Shared/Pause.php
index 0816d10202..a8d5574ef4 100644
--- a/src/Codeception/Lib/Actor/Shared/Pause.php
+++ b/src/Codeception/Lib/Actor/Shared/Pause.php
@@ -7,8 +7,6 @@
use Codeception\Command\Console;
use Codeception\Lib\PauseShell;
use Codeception\Util\Debug;
-use Psy\Shell;
-use Psy\Configuration;
trait Pause
{
diff --git a/src/Codeception/Lib/Connector/Shared/PhpSuperGlobalsConverter.php b/src/Codeception/Lib/Connector/Shared/PhpSuperGlobalsConverter.php
index 41d57c5cbb..ca4296605e 100644
--- a/src/Codeception/Lib/Connector/Shared/PhpSuperGlobalsConverter.php
+++ b/src/Codeception/Lib/Connector/Shared/PhpSuperGlobalsConverter.php
@@ -8,101 +8,72 @@
* Converts BrowserKit\Request's request parameters and files into PHP-compatible structure
*
* @see https://bugs.php.net/bug.php?id=25589
- * @see https://bugs.php.net/bug.php?id=25589
+ * @see https://bugs.php.net/bug.php?id=40000
*
* @package Codeception\Lib\Connector
*/
trait PhpSuperGlobalsConverter
{
/**
- * Rearrange files array to be compatible with PHP $_FILES superglobal structure
- * @see https://bugs.php.net/bug.php?id=25589
+ * Rearrange files array to match PHP $_FILES structure.
+ * Handles nested arrays within files, ensuring compatibility with PHP's $_FILES superglobal.
*/
protected function remapFiles(array $requestFiles): array
{
- $files = $this->rearrangeFiles($requestFiles);
-
- return $this->replaceSpaces($files);
+ $normalizedFiles = $this->normalizeFilesArray($requestFiles);
+ return $this->normalizeQueryParameters($normalizedFiles);
}
/**
- * Escape high-level variable name with dots, underscores and other "special" chars
- * to be compatible with PHP "bug"
- * @see https://bugs.php.net/bug.php?id=40000
+ * Normalize request parameters by replacing spaces and special characters.
+ * Ensures compatibility with PHP's handling of query parameters.
*/
protected function remapRequestParameters(array $parameters): array
{
- return $this->replaceSpaces($parameters);
+ return $this->normalizeQueryParameters($parameters);
}
- private function rearrangeFiles(array $requestFiles): array
+ private function normalizeFilesArray(array $requestFiles): array
{
- $files = [];
- foreach ($requestFiles as $name => $info) {
- if (!is_array($info)) {
+ $normalizedFiles = [];
+ foreach ($requestFiles as $fieldName => $fileInfo) {
+ if (!is_array($fileInfo)) {
continue;
}
- /**
- * If we have a form with fields like
- * ```
- *
- *
- * ```
- * then only array variable will be used while simple variable will be ignored in php $_FILES
- * (eg $_FILES = [
- * foo => [
- * tmp_name => [
- * 'bar' => 'asdf'
- * ],
- * //...
- * ]
- * ]
- * )
- * (notice there is no entry for file "foo", only for file "foo[bar]"
- * this will check if current element contains inner arrays within it's keys
- * so we can ignore element itself and only process inner files
- */
- $hasInnerArrays = count(array_filter($info, 'is_array'));
+ // Check if the current file info has nested arrays within its keys
+ $containsNestedArrays = count(array_filter($fileInfo, 'is_array'));
- if ($hasInnerArrays || !isset($info['tmp_name'])) {
- $inner = $this->remapFiles($info);
- foreach ($inner as $innerName => $innerInfo) {
- /**
- * Convert from ['a' => ['tmp_name' => '/tmp/test.txt'] ]
- * to ['tmp_name' => ['a' => '/tmp/test.txt'] ]
- */
- $innerInfo = array_map(
- fn ($v) => [$innerName => $v],
- $innerInfo
+ if ($containsNestedArrays || !isset($fileInfo['tmp_name'])) {
+ $nestedFiles = $this->remapFiles($fileInfo);
+ // Convert from ['a' => ['tmp_name' => '/tmp/test.txt'] ]
+ // to ['tmp_name' => ['a' => '/tmp/test.txt'] ]
+ foreach ($nestedFiles as $nestedFieldName => $nestedFileInfo) {
+ $nestedFileInfo = array_map(
+ fn($value): array => [$nestedFieldName => $value],
+ $nestedFileInfo
);
- if (empty($files[$name])) {
- $files[$name] = [];
- }
-
- $files[$name] = array_replace_recursive($files[$name], $innerInfo);
+ $normalizedFiles[$fieldName] = array_replace_recursive(
+ $normalizedFiles[$fieldName] ?? [],
+ $nestedFileInfo
+ );
}
} else {
- $files[$name] = $info;
+ $normalizedFiles[$fieldName] = $fileInfo;
}
}
- return $files;
+ return $normalizedFiles;
}
/**
- * Replace spaces and dots and other chars in high-level query parameters for
- * compatibility with PHP bug (or not a bug)
- * @see https://bugs.php.net/bug.php?id=40000
- *
- * @param array $parameters Array of request parameters to be converted
+ * Normalize query parameters by replacing spaces and special characters.
+ * Ensures compatibility with PHP's handling of query strings.
*/
- private function replaceSpaces(array $parameters): array
+ private function normalizeQueryParameters(array $parameters): array
{
- $qs = http_build_query($parameters);
- parse_str($qs, $output);
-
- return $output;
+ parse_str(http_build_query($parameters), $normalizedParameters);
+ return $normalizedParameters;
}
}
diff --git a/src/Codeception/Lib/Console/Colorizer.php b/src/Codeception/Lib/Console/Colorizer.php
index 59a09134ec..1f69432d24 100644
--- a/src/Codeception/Lib/Console/Colorizer.php
+++ b/src/Codeception/Lib/Console/Colorizer.php
@@ -10,13 +10,11 @@ class Colorizer
{
public function colorize(string $string = ''): string
{
- $fp = fopen('php://memory', 'r+');
- fwrite($fp, $string);
- rewind($fp);
-
+ $lines = explode("\n", $string);
$colorizedMessage = '';
- while ($line = fgets($fp)) {
- $char = $line[0];
+
+ foreach ($lines as $line) {
+ $char = $line[0] ?? '';
$line = OutputFormatter::escape(trim($line));
switch ($char) {
diff --git a/src/Codeception/Lib/Console/DiffFactory.php b/src/Codeception/Lib/Console/DiffFactory.php
index 7160079890..25da4d4566 100644
--- a/src/Codeception/Lib/Console/DiffFactory.php
+++ b/src/Codeception/Lib/Console/DiffFactory.php
@@ -17,12 +17,7 @@ public function createDiff(ComparisonFailure $failure): string
private function getDiff(string $expected = '', string $actual = ''): string
{
- if (!$actual && !$expected) {
- return '';
- }
-
$differ = new Differ(new UnifiedDiffOutputBuilder(''));
-
- return $differ->diff($expected, $actual);
+ return ($expected || $actual) ? $differ->diff($expected, $actual) : '';
}
}
diff --git a/src/Codeception/Lib/Console/Message.php b/src/Codeception/Lib/Console/Message.php
index e4ae493e65..0d54d93296 100644
--- a/src/Codeception/Lib/Console/Message.php
+++ b/src/Codeception/Lib/Console/Message.php
@@ -13,10 +13,9 @@ public function __construct(protected string $message, protected ?Output $output
{
}
- public function with($param): self
+ public function with(...$params): self
{
- $args = array_merge([$this->message], func_get_args());
- $this->message = sprintf(...$args);
+ $this->message = sprintf($this->message, ...$params);
return $this;
}
@@ -29,7 +28,6 @@ public function style(string $name): self
public function width(int $length, string $char = ' '): self
{
$messageLength = $this->getLength();
-
if ($messageLength < $length) {
$this->message .= str_repeat($char, $length - $messageLength);
}
@@ -44,42 +42,33 @@ public function cut(int $length): self
public function write(int $verbose = OutputInterface::VERBOSITY_NORMAL): void
{
- if ($verbose > $this->output->getVerbosity()) {
- return;
+ if ($verbose <= $this->output->getVerbosity()) {
+ $this->output->write($this->message);
}
- $this->output->write($this->message);
}
public function writeln(int $verbose = OutputInterface::VERBOSITY_NORMAL): void
{
- if ($verbose > $this->output->getVerbosity()) {
- return;
+ if ($verbose <= $this->output->getVerbosity()) {
+ $this->output->writeln($this->message);
}
- $this->output->writeln($this->message);
}
public function prepend(Message|string $string): self
{
- if ($string instanceof Message) {
- $string = $string->getMessage();
- }
- $this->message = $string . $this->message;
+ $this->message = ($string instanceof Message ? $string->getMessage() : $string) . $this->message;
return $this;
}
public function append(Message|string $string): self
{
- if ($string instanceof Message) {
- $string = $string->getMessage();
- }
- $this->message .= $string;
-
+ $this->message .= $string instanceof Message ? $string->getMessage() : $string;
return $this;
}
public function apply(callable $func): self
{
- $this->message = call_user_func($func, $this->message);
+ $this->message = $func($this->message);
return $this;
}
@@ -97,7 +86,6 @@ public function getMessage(): string
public function block(string $style): self
{
$this->message = $this->output->formatHelper->formatBlock($this->message, $style, true);
-
return $this;
}
diff --git a/src/Codeception/Lib/Console/Output.php b/src/Codeception/Lib/Console/Output.php
index 3740bc434a..dc8a259d1e 100644
--- a/src/Codeception/Lib/Console/Output.php
+++ b/src/Codeception/Lib/Console/Output.php
@@ -31,13 +31,20 @@ public function __construct(array $config)
{
$this->config = array_merge($this->config, $config);
- // enable interactive output mode for CLI
$this->isInteractive = $this->config['interactive']
&& isset($_SERVER['TERM'])
- && PHP_SAPI == 'cli'
+ && PHP_SAPI === 'cli'
&& $_SERVER['TERM'] != 'linux';
$formatter = new OutputFormatter($this->config['colors']);
+ $this->configureStyles($formatter);
+
+ $this->formatHelper = new SymfonyFormatterHelper();
+ parent::__construct($this->config['verbosity'], $this->config['colors'], $formatter);
+ }
+
+ protected function configureStyles(OutputFormatter $formatter): void
+ {
$formatter->setStyle('default', new OutputFormatterStyle());
$formatter->setStyle('bold', new OutputFormatterStyle(null, null, ['bold']));
$formatter->setStyle('focus', new OutputFormatterStyle('magenta', null, ['bold']));
@@ -48,21 +55,16 @@ public function __construct(array $config)
$formatter->setStyle('debug', new OutputFormatterStyle('cyan'));
$formatter->setStyle('comment', new OutputFormatterStyle('yellow'));
$formatter->setStyle('info', new OutputFormatterStyle('green'));
-
- $this->formatHelper = new SymfonyFormatterHelper();
-
- parent::__construct($this->config['verbosity'], $this->config['colors'], $formatter);
}
- public function isInteractive(): bool
+ protected function clean(string $message): string
{
- return $this->isInteractive;
+ return str_replace('\/', '/', $message);
}
- protected function clean(string $message): string
+ public function isInteractive(): bool
{
- // clear json serialization
- return str_replace('\/', '/', $message);
+ return $this->isInteractive;
}
public function debug(mixed $message): void
@@ -91,7 +93,6 @@ public function message($message): Message
public function exception(Exception $exception): void
{
$class = $exception::class;
-
$this->writeln("");
$this->writeln(sprintf('(![ %s ]!)', $class));
$this->writeln($exception->getMessage());
diff --git a/src/Codeception/Lib/Console/ReplHistory.php b/src/Codeception/Lib/Console/ReplHistory.php
index cdb9f0e975..be1ce097e1 100644
--- a/src/Codeception/Lib/Console/ReplHistory.php
+++ b/src/Codeception/Lib/Console/ReplHistory.php
@@ -23,7 +23,7 @@ private function __construct()
public static function getInstance(): ReplHistory
{
- if (static::$instance == null) {
+ if (static::$instance === null) {
static::$instance = new self();
}
@@ -47,14 +47,12 @@ public function clear(): void
public function save(): void
{
- if (empty($this->stashedCommands)) {
+ if ($this->stashedCommands === []) {
return;
}
file_put_contents($this->outputFile, implode("\n", $this->stashedCommands) . "\n", FILE_APPEND);
-
codecept_debug("Stashed commands have been saved to {$this->outputFile}");
-
$this->clear();
}
}
diff --git a/src/Codeception/Lib/Di.php b/src/Codeception/Lib/Di.php
index 5a6f6e370d..8fbbac379c 100644
--- a/src/Codeception/Lib/Di.php
+++ b/src/Codeception/Lib/Di.php
@@ -11,6 +11,7 @@
use ReflectionException;
use ReflectionMethod;
use ReflectionObject;
+use Throwable;
class Di
{
@@ -26,14 +27,13 @@ class Di
protected ?Di $fallback = null;
- public function __construct(Di $fallback = null)
+ public function __construct(?Di $fallback = null)
{
$this->fallback = $fallback;
}
public function get(string $className): ?object
{
- // normalize namespace
$className = ltrim($className, '\\');
return $this->container[$className] ?? null;
}
@@ -50,52 +50,45 @@ public function set(object $class): void
*/
public function instantiate(
string $className,
- array $constructorArgs = null,
+ ?array $constructorArgs = null,
string $injectMethodName = self::DEFAULT_INJECT_METHOD_NAME
): ?object {
- // normalize namespace
$className = ltrim($className, '\\');
- // get class from container
if (isset($this->container[$className])) {
if ($this->container[$className] instanceof $className) {
return $this->container[$className];
}
-
throw new InjectionException("Failed to resolve cyclic dependencies for class '{$className}'");
}
- // get class from parent container
- if ($this->fallback && ($class = $this->fallback->get($className))) {
+ if ($this->fallback instanceof Di && ($class = $this->fallback->get($className))) {
return $class;
}
- $this->container[$className] = false; // flag that object is being instantiated
+ $this->container[$className] = false;
+
+ try {
+ $reflectedClass = new ReflectionClass($className);
+ } catch (ReflectionException $e) {
+ throw new InjectionException("Failed to create instance of '{$className}'. " . $e->getMessage());
+ }
- $reflectedClass = new ReflectionClass($className);
if (!$reflectedClass->isInstantiable()) {
return null;
}
- $reflectedConstructor = $reflectedClass->getConstructor();
- if (is_null($reflectedConstructor)) {
- $object = new $className();
- } else {
- try {
- if (!$constructorArgs) {
- $constructorArgs = $this->prepareArgs($reflectedConstructor);
- }
- } catch (Exception $e) {
- throw new InjectionException("Failed to create instance of '{$className}'. " . $e->getMessage());
- }
- $object = $reflectedClass->newInstanceArgs($constructorArgs);
- }
+ $constructorArgs = $constructorArgs ?? $this->prepareArgs($reflectedClass->getConstructor());
- if ($injectMethodName !== '') {
- $this->injectDependencies($object, $injectMethodName);
+ try {
+ $object = $reflectedClass->newInstanceArgs($constructorArgs ?? []);
+ } catch (ReflectionException $e) {
+ throw new InjectionException("Failed to create instance of '{$className}'. " . $e->getMessage());
}
+ $this->injectDependencies($object, $injectMethodName);
$this->container[$className] = $object;
+
return $object;
}
@@ -106,59 +99,60 @@ public function instantiate(
public function injectDependencies(object $object, string $injectMethodName = self::DEFAULT_INJECT_METHOD_NAME, array $defaults = []): void
{
$reflectedObject = new ReflectionObject($object);
- $reflectionObjectHasMethod = $reflectedObject->hasMethod($injectMethodName);
- if (!$reflectionObjectHasMethod) {
- return;
- }
- $reflectedMethod = $reflectedObject->getMethod($injectMethodName);
- try {
- $args = $this->prepareArgs($reflectedMethod, $defaults);
- } catch (Exception $e) {
- $msg = $e->getMessage();
- if ($e->getPrevious() !== null) { // injection failed because PHP code is invalid. See #3869
- $msg .= '; ' . $e->getPrevious();
+ if ($reflectedObject->hasMethod($injectMethodName)) {
+ $reflectedMethod = $reflectedObject->getMethod($injectMethodName);
+
+ try {
+ $args = $this->prepareArgs($reflectedMethod, $defaults);
+ } catch (Exception $e) {
+ $msg = $e->getMessage();
+ if ($e->getPrevious() instanceof Throwable) {
+ $msg .= '; ' . $e->getPrevious();
+ }
+ throw new InjectionException(
+ "Failed to inject dependencies in instance of '{$reflectedObject->name}'. {$msg}"
+ );
}
- throw new InjectionException(
- "Failed to inject dependencies in instance of '{$reflectedObject->name}'. {$msg}"
- );
- }
- if (!$reflectedMethod->isPublic()) {
$reflectedMethod->setAccessible(true);
+ $reflectedMethod->invokeArgs($object, $args);
}
- $reflectedMethod->invokeArgs($object, $args);
}
- protected function prepareArgs(ReflectionMethod $method, array $defaults = []): array
+ protected function prepareArgs(?ReflectionMethod $method = null, array $defaults = []): array
{
$args = [];
- $parameters = $method->getParameters();
- foreach ($parameters as $k => $parameter) {
- $dependency = ReflectionHelper::getClassFromParameter($parameter);
- if (is_null($dependency)) {
- if ($parameter->isVariadic()) {
- continue;
- }
- if (!$parameter->isOptional()) {
- if (!isset($defaults[$k])) {
- throw new InjectionException("Parameter '{$parameter->name}' must have default value.");
- }
- $args[] = $defaults[$k];
- continue;
- }
- $args[] = $parameter->getDefaultValue();
- } else {
- $arg = $this->instantiate($dependency);
- if (is_null($arg)) {
+
+ if ($method !== null) {
+ foreach ($method->getParameters() as $k => $parameter) {
+ $dependency = ReflectionHelper::getClassFromParameter($parameter);
+
+ if (is_null($dependency)) {
if ($parameter->isVariadic()) {
continue;
}
- throw new InjectionException("Failed to resolve dependency '{$dependency}'.");
+
+ if (!$parameter->isOptional()) {
+ $args[] = $defaults[$k] ?? throw new InjectionException("Parameter '{$parameter->name}' must have default value.");
+ } else {
+ $args[] = $parameter->getDefaultValue();
+ }
+ } else {
+ try {
+ $arg = $this->instantiate($dependency);
+ } catch (ReflectionException $e) {
+ throw new InjectionException("Failed to resolve dependency '{$dependency}'. " . $e->getMessage());
+ }
+
+ if (is_null($arg) && !$parameter->isVariadic()) {
+ throw new InjectionException("Failed to resolve dependency '{$dependency}'.");
+ }
+ $args[] = $arg;
}
- $args[] = $arg;
}
}
+
return $args;
}
}
diff --git a/src/Codeception/Lib/Friend.php b/src/Codeception/Lib/Friend.php
index 99ee0a17c8..b73200398b 100644
--- a/src/Codeception/Lib/Friend.php
+++ b/src/Codeception/Lib/Friend.php
@@ -16,14 +16,14 @@ class Friend
public function __construct(protected string $name, protected Actor $actor, array $modules = [])
{
- $this->multiSessionModules = array_filter($modules, fn ($m): bool => $m instanceof MultiSession);
+ $this->multiSessionModules = array_filter($modules, fn($m): bool => $m instanceof MultiSession);
- if (empty($this->multiSessionModules)) {
+ if ($this->multiSessionModules === []) {
throw new TestRuntimeException("No multisession modules used. Can't instantiate friend");
}
}
- public function does($closure)
+ public function does(callable $closure)
{
$currentUserData = [];
@@ -39,7 +39,7 @@ public function does($closure)
}
$this->actor->comment(strtoupper("{$this->name} does ---"));
- $ret = $closure($this->actor);
+ $result = $closure($this->actor);
$this->actor->comment(strtoupper("--- {$this->name} finished"));
foreach ($this->multiSessionModules as $module) {
@@ -47,7 +47,8 @@ public function does($closure)
$this->data[$name] = $module->_backupSession();
$module->_loadSession($currentUserData[$name]);
}
- return $ret;
+
+ return $result;
}
public function isGoingTo(string $argumentation): void
@@ -68,8 +69,9 @@ public function expectsTo(string $prediction): void
public function leave(): void
{
foreach ($this->multiSessionModules as $module) {
- if (isset($this->data[$module->_getName()])) {
- $module->_closeSession($this->data[$module->_getName()]);
+ $name = $module->_getName();
+ if (isset($this->data[$name])) {
+ $module->_closeSession($this->data[$name]);
}
}
}
diff --git a/src/Codeception/Lib/Generator/Actions.php b/src/Codeception/Lib/Generator/Actions.php
index 4de4d09c6b..7e164dc2e3 100644
--- a/src/Codeception/Lib/Generator/Actions.php
+++ b/src/Codeception/Lib/Generator/Actions.php
@@ -87,15 +87,18 @@ public function __construct(array $settings)
$this->name = $settings['actor'];
$this->settings = $settings;
$this->di = new Di();
- $modules = Configuration::modules($this->settings);
$this->moduleContainer = new ModuleContainer($this->di, $settings);
- foreach ($modules as $moduleName) {
+ $this->initializeModules();
+ }
+
+ protected function initializeModules()
+ {
+ foreach (Configuration::modules($this->settings) as $moduleName) {
$this->moduleContainer->create($moduleName);
}
$this->modules = $this->moduleContainer->all();
$this->actions = $this->moduleContainer->getActions();
-
- $this->generatedSteps = (array)$settings['step_decorators'];
+ $this->generatedSteps = (array)$this->settings['step_decorators'];
}
public function produce(): string
@@ -105,14 +108,13 @@ public function produce(): string
$methods = [];
$code = [];
foreach ($this->actions as $action => $moduleName) {
- if (in_array($action, $methods)) {
- continue;
+ if (!in_array($action, $methods)) {
+ $class = new ReflectionClass($this->modules[$moduleName]);
+ $method = $class->getMethod($action);
+ $code[] = $this->addMethod($method);
+ $methods[] = $action;
+ ++$this->numMethods;
}
- $class = new ReflectionClass($this->modules[$moduleName]);
- $method = $class->getMethod($action);
- $code[] = $this->addMethod($method);
- $methods[] = $action;
- ++$this->numMethods;
}
return (new Template($this->template))
@@ -251,11 +253,6 @@ public static function genHash(array $modules, array $settings): string
return md5(Codecept::VERSION . serialize($actions) . serialize($settings['modules']) . implode(',', (array)$settings['step_decorators']));
}
- public function getNumMethods(): int
- {
- return $this->numMethods;
- }
-
private function createReturnTypeHint(ReflectionMethod $refMethod): string
{
$returnType = $refMethod->getReturnType();
@@ -322,10 +319,14 @@ private function stringifyAttribute(ReflectionAttribute $attribute): string
// If we can't get the class then just return what we've been given.
$name = $attribute->getName();
}
- $arguments = $attribute->getArguments();
// Strip the wrapping array brackets so parameters aren't converted to arrays.
- $args = substr(ReflectionHelper::phpEncodeValue($arguments), 1, -1);
+ $args = substr(ReflectionHelper::phpEncodeValue($attribute->getArguments()), 1, -1);
return '#[' . $name . '(' . $args . ')]';
}
+
+ public function getNumMethods(): int
+ {
+ return $this->numMethods;
+ }
}
diff --git a/src/Codeception/Lib/Generator/Cest.php b/src/Codeception/Lib/Generator/Cest.php
index f27924fc8f..f3f52008f6 100644
--- a/src/Codeception/Lib/Generator/Cest.php
+++ b/src/Codeception/Lib/Generator/Cest.php
@@ -17,17 +17,20 @@ class Cest
protected string $template = <<getNamespaceHeader($this->settings['namespace'] . '\\' . ucfirst($this->settings['suite']) . '\\' . $this->name);
+ $namespaceHeader = $this->getNamespaceHeader($this->settings['namespace'] . '\\' . ucfirst((string)$this->settings['suite']) . '\\' . $this->name);
if ($namespaceHeader) {
$namespaceHeader .= "\nuse " . $this->supportNamespace() . $actor . ";";
diff --git a/src/Codeception/Lib/Generator/GherkinSnippets.php b/src/Codeception/Lib/Generator/GherkinSnippets.php
index 0c8e0cc8f9..ee31dbcc0e 100644
--- a/src/Codeception/Lib/Generator/GherkinSnippets.php
+++ b/src/Codeception/Lib/Generator/GherkinSnippets.php
@@ -40,10 +40,10 @@ public function {{methodName}}({{params}})
public function __construct(array $settings, $test = null)
{
$loader = new Gherkin($settings);
- $pattern = $loader->getPattern();
$path = $settings['path'];
- if (!empty($test)) {
- $path = $settings['path'] . '/' . $test;
+ $pattern = $loader->getPattern();
+ if ($test) {
+ $path = "$path/$test";
if (preg_match($pattern, $test)) {
$path = dirname($path);
$pattern = basename($test);
@@ -58,8 +58,7 @@ public function __construct(array $settings, $test = null)
->name($pattern);
foreach ($finder as $file) {
- $pathname = str_replace("//", "/", $file->getPathname());
- $loader->loadTests($pathname);
+ $loader->loadTests($file->getPathname());
}
$availableSteps = $loader->getSteps();
$allSteps = [];
@@ -101,41 +100,34 @@ public function addSnippet(StepNode $step): void
$pattern = $step->getText();
// match numbers (not in quotes)
- if (preg_match_all('#([\d.])(?=([^"]*"[^"]*")*[^"]*$)#', $pattern, $matches)) {
- foreach ($matches[1] as $num => $param) {
- ++$num;
- $args[] = '$num' . $num;
- $pattern = str_replace($param, ":num{$num}", $pattern);
- }
- }
-
- // match quoted string
- if (preg_match_all('#"(.*?)"#', $pattern, $matches)) {
- foreach ($matches[1] as $num => $param) {
- ++$num;
- $args[] = '$arg' . $num;
- $pattern = str_replace('"' . $param . '"', ":arg{$num}", $pattern);
- }
- }
- // Has multiline argument at the end of step?
+ $pattern = preg_replace_callback('#([\d.])(?=([^"]*"[^"]*")*[^"]*$)#', function () use (&$args) {
+ $args[] = '$num' . (count($args) + 1);
+ return ":num" . count($args);
+ }, $pattern);
+
+ // match quoted strings
+ $pattern = preg_replace_callback('#"(.*?)"#', function () use (&$args) {
+ $args[] = '$arg' . (count($args) + 1);
+ return ":arg" . count($args);
+ }, $pattern);
+
+ // add multiline argument if present
if (self::stepHasPyStringArgument($step)) {
- $num = count($args) + 1;
- $pattern .= " :arg{$num}";
- $args[] = '$arg' . $num;
+ $args[] = '$arg' . (count($args) + 1);
+ $pattern .= " :arg" . count($args);
}
+
if (in_array($pattern, $this->processed)) {
return;
}
$methodName = preg_replace('#(\s+?|\'|\"|\W)#', '', ucwords(preg_replace('#"(.*?)"|\d+#', '', $step->getText())));
- if (empty($methodName)) {
- $methodName = 'step_' . substr(sha1($pattern), 0, 9);
- }
+ $methodName = empty($methodName) ? 'step_' . substr(sha1($pattern), 0, 9) : lcfirst($methodName);
$this->snippets[] = (new Template($this->template))
->place('type', $step->getKeywordType())
->place('text', $pattern)
- ->place('methodName', lcfirst($methodName))
+ ->place('methodName', $methodName)
->place('params', implode(', ', $args))
->produce();
@@ -162,9 +154,7 @@ public static function stepHasPyStringArgument(StepNode $step): bool
{
if ($step->hasArguments()) {
$stepArgs = $step->getArguments();
- if ($stepArgs[count($stepArgs) - 1]->getNodeType() == "PyString") {
- return true;
- }
+ return end($stepArgs)->getNodeType() === 'PyString';
}
return false;
}
diff --git a/src/Codeception/Lib/Generator/Group.php b/src/Codeception/Lib/Generator/Group.php
index 0ea6056825..b23dcfa915 100644
--- a/src/Codeception/Lib/Generator/Group.php
+++ b/src/Codeception/Lib/Generator/Group.php
@@ -50,8 +50,6 @@ public function _after(TestEvent \$e)
public function __construct(protected array $settings, protected string $name)
{
- $this->settings = $settings;
- $this->name = $name;
$this->namespace = $this->getNamespaceString($this->supportNamespace() . '\\Group\\' . $name);
}
diff --git a/src/Codeception/Lib/Generator/Test.php b/src/Codeception/Lib/Generator/Test.php
index 7298a952b1..88cd2ff8e1 100644
--- a/src/Codeception/Lib/Generator/Test.php
+++ b/src/Codeception/Lib/Generator/Test.php
@@ -51,19 +51,18 @@ public function __construct(protected array $settings, string $name)
public function produce(): string
{
$actor = $this->settings['actor'];
-
- $ns = $this->getNamespaceHeader($this->settings['namespace'] . '\\' . ucfirst($this->settings['suite']) . '\\' . $this->name);
+ $namespacePath = $this->settings['namespace'] . '\\' . ucfirst((string)$this->settings['suite']) . '\\' . $this->name;
+ $ns = $this->getNamespaceHeader($namespacePath);
if ($ns) {
$ns .= "\nuse " . $this->supportNamespace() . $actor . ";";
}
-
$tester = '';
- if ($this->settings['actor']) {
+ if ($actor) {
$tester = (new Template($this->testerTemplate))
->place('actorClass', $actor)
- ->place('actor', lcfirst(Configuration::config()['actor_suffix']))
+ ->place('actor', lcfirst((string)Configuration::config()['actor_suffix']))
->produce();
}
diff --git a/src/Codeception/Lib/GroupManager.php b/src/Codeception/Lib/GroupManager.php
index 91464a911c..3f29920a63 100644
--- a/src/Codeception/Lib/GroupManager.php
+++ b/src/Codeception/Lib/GroupManager.php
@@ -10,7 +10,6 @@
use Codeception\Test\Test;
use Codeception\Util\PathResolver;
use Symfony\Component\Finder\Finder;
-use Symfony\Component\Finder\SplFileInfo;
use function realpath;
@@ -23,6 +22,7 @@ class GroupManager
protected string $rootDir;
+ /** @param string[] $configuredGroups */
public function __construct(protected array $configuredGroups)
{
$this->rootDir = Configuration::baseDir();
@@ -47,10 +47,8 @@ protected function loadGroupsByPattern(): void
if (!str_contains($group, '*')) {
continue;
}
- $path = dirname($pattern);
- if (!PathResolver::isPathAbsolute($pattern)) {
- $path = $this->rootDir . $path;
- }
+
+ $path = PathResolver::isPathAbsolute($pattern) ? dirname($pattern) : $this->rootDir . dirname($pattern);
$files = Finder::create()->files()
->name(basename($pattern))
@@ -58,11 +56,9 @@ protected function loadGroupsByPattern(): void
->in($path);
foreach ($files as $file) {
- /** @var SplFileInfo $file * */
$prefix = str_replace('*', '', $group);
$pathPrefix = str_replace('*', '', basename($pattern));
$groupName = $prefix . str_replace($pathPrefix, '', $file->getRelativePathname());
-
$this->configuredGroups[$groupName] = dirname($pattern) . DIRECTORY_SEPARATOR . $file->getRelativePathname();
}
@@ -74,49 +70,50 @@ protected function loadConfiguredGroupSettings(): void
{
foreach ($this->configuredGroups as $group => $tests) {
$this->testsInGroups[$group] = [];
- if (is_array($tests)) {
- foreach ($tests as $test) {
- $file = str_replace(['/', '\\'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $test);
- $this->testsInGroups[$group][] = $this->normalizeFilePath($file, $group);
- }
- continue;
- }
+ $testsArray = is_array($tests) ? $tests : $this->getTestsFromFile($tests);
- $path = $tests;
- if (!codecept_is_path_absolute($tests)) {
- $path = $this->rootDir . $tests;
+ foreach ($testsArray as $test) {
+ $file = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $test);
+ $this->testsInGroups[$group][] = $this->normalizeFilePath($file, $group);
}
+ }
+ }
- if (is_file($path)) {
- $handle = @fopen($path, "r");
- if ($handle) {
- while (($test = fgets($handle, 4096)) !== false) {
- // if the current line is blank then we need to move to the next line
- // otherwise the current codeception directory becomes part of the group
- // which causes every single test to run
- if (trim($test) === '') {
- continue;
- }
-
- $file = str_replace(['/', '\\'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], trim($test));
- $this->testsInGroups[$group][] = $this->normalizeFilePath($file, $group);
- }
- fclose($handle);
+ private function getTestsFromFile(string $tests): array
+ {
+ $path = codecept_is_path_absolute($tests) ? $tests : $this->rootDir . $tests;
+ if (!is_file($path)) {
+ return [];
+ }
+
+ $testsArray = [];
+ $handle = fopen($path, 'r');
+ if ($handle) {
+ while (($test = fgets($handle, 4096)) !== false) {
+ // if the current line is blank then we need to move to the next line
+ // otherwise the current codeception directory becomes part of the group
+ // which causes every single test to run
+ if (trim($test) !== '') {
+ $testsArray[] = trim($test);
}
}
+ fclose($handle);
}
+ return $testsArray;
}
private function normalizeFilePath(string $file, string $group): string
{
$pathParts = explode(':', $file);
- if (codecept_is_path_absolute($file)) {
+ $isAbsolute = codecept_is_path_absolute($file);
+
+ if ($isAbsolute) {
if ($file[0] === '/' && count($pathParts) > 1) {
- //take segment before first :
+ // Take segment before first :
$this->checkIfFileExists($pathParts[0], $group);
return sprintf('%s:%s', realpath($pathParts[0]), $pathParts[1]);
} elseif (count($pathParts) > 2) {
- //on Windows take segment before second :
+ // On Windows take segment before second :
$fullPath = $pathParts[0] . ':' . $pathParts[1];
$this->checkIfFileExists($fullPath, $group);
return sprintf('%s:%s', realpath($fullPath), $pathParts[2]);
@@ -149,12 +146,9 @@ public function groupsForTest(Test $test): array
$groups = $test->getMetadata()->getGroups();
foreach ($this->testsInGroups as $group => $tests) {
+ /** @var string[] $tests */
foreach ($tests as $testPattern) {
- if ($filename == $testPattern) {
- $groups[] = $group;
- }
-
- if (str_starts_with($filename . ':' . $testName, (string)$testPattern)) {
+ if ($filename == $testPattern || str_starts_with($filename . ':' . $testName, $testPattern)) {
$groups[] = $group;
}
if (
@@ -165,6 +159,7 @@ public function groupsForTest(Test $test): array
}
}
}
+
return array_unique($groups);
}
}
diff --git a/src/Codeception/Lib/ModuleContainer.php b/src/Codeception/Lib/ModuleContainer.php
index 9dd2bb1eec..1fa713640f 100644
--- a/src/Codeception/Lib/ModuleContainer.php
+++ b/src/Codeception/Lib/ModuleContainer.php
@@ -75,7 +75,7 @@ class ModuleContainer
private array $actions = [];
- public function __construct(private Di $di, private array $config)
+ public function __construct(private readonly Di $di, private array $config)
{
$this->di->set($this);
}
@@ -97,14 +97,14 @@ public function create(string $moduleName, bool $active = true): ?object
if (!class_exists($moduleClass)) {
if (isset(self::$packages[$moduleName])) {
$package = self::$packages[$moduleName];
- throw new ConfigurationException("Module {$moduleName} is not installed.\nUse Composer to install corresponding package:\n\ncomposer require {$package} --dev");
+ throw new ConfigurationException("Codeception's module {$moduleName} not found. Install it with:\n\ncomposer require {$package} --dev");
}
throw new ConfigurationException("Module {$moduleName} could not be found and loaded");
}
$config = $this->getModuleConfig($moduleName);
- if (empty($config) && !$active) {
+ if ($config === [] && !$active) {
// For modules that are a dependency of other modules we want to skip the validation of the config.
// This config validation is performed in \Codeception\Module::__construct().
// Explicitly setting $config to null skips this validation.
@@ -171,7 +171,7 @@ private function getActionsForModule(Module $module, array $config): array
/**
* Should a method be included as an action?
*/
- private function includeMethodAsAction(Module $module, ReflectionMethod $method, array $configuredParts = null): bool
+ private function includeMethodAsAction(Module $module, ReflectionMethod $method, ?array $configuredParts = null): bool
{
// Filter out excluded actions
if ($module::$excludeActions && in_array($method->name, $module::$excludeActions)) {
@@ -202,7 +202,7 @@ private function includeMethodAsAction(Module $module, ReflectionMethod $method,
// If a part is configured for the module, only include actions from that part
if ($configuredParts) {
$moduleParts = Annotation::forMethod($module, $method->name)->fetchAll('part');
- if (!array_uintersect($moduleParts, $configuredParts, 'strcasecmp')) {
+ if (array_uintersect($moduleParts, $configuredParts, 'strcasecmp') === []) {
return false;
}
}
@@ -246,7 +246,7 @@ public function hasModule(string $moduleName): bool
public function getModule(string $moduleName): Module
{
if (!$this->hasModule($moduleName)) {
- $this->throwMissingModuleExceptionWithSuggestion(__CLASS__, $moduleName);
+ $this->throwMissingModuleExceptionWithSuggestion(self::class, $moduleName);
}
return $this->modules[$moduleName];
@@ -333,7 +333,7 @@ private function injectModuleDependencies(string $moduleName, DependsOnModule $m
throw new ModuleException($module, 'Module requires method _inject to be defined to accept dependencies');
}
- $dependencies = array_map(fn ($dependency): ?object => $this->create($dependency, false), $this->getConfiguredDependencies($moduleName));
+ $dependencies = array_map(fn($dependency): ?object => $this->create($dependency, false), $this->getConfiguredDependencies($moduleName));
call_user_func_array([$module, '_inject'], $dependencies);
}
@@ -343,7 +343,7 @@ private function injectModuleDependencies(string $moduleName, DependsOnModule $m
*
* @throws ModuleException|ModuleRequireException
*/
- private function checkForMissingDependencies(string $moduleName, $module): void
+ private function checkForMissingDependencies(string $moduleName, DependsOnModule $module): void
{
$dependencies = $this->getModuleDependencies($module);
$configuredDependenciesCount = count($this->getConfiguredDependencies($moduleName));
@@ -370,7 +370,7 @@ private function getModuleDependencies(DependsOnModule $module): array
{
$depends = $module->_depends();
- if (!$depends) {
+ if ($depends === []) {
return [];
}
@@ -493,7 +493,7 @@ private function validateConflict(Module $module, Module $otherModule): void
*
* @return class-string|Module|string
*/
- private function normalizeConflictSpecification(string $conflicts)
+ private function normalizeConflictSpecification(string $conflicts): string|Module
{
if (interface_exists($conflicts) || class_exists($conflicts)) {
return $conflicts;
diff --git a/src/Codeception/Lib/ParamsLoader.php b/src/Codeception/Lib/ParamsLoader.php
index b417787e37..b238186ffd 100644
--- a/src/Codeception/Lib/ParamsLoader.php
+++ b/src/Codeception/Lib/ParamsLoader.php
@@ -12,21 +12,17 @@
use Symfony\Component\Dotenv\Dotenv as SymfonyDotenv;
use Symfony\Component\Yaml\Yaml;
-use function class_exists;
use function codecept_absolute_path;
use function codecept_relative_path;
-use function extension_loaded;
use function file_exists;
use function file_get_contents;
-use function method_exists;
use function parse_ini_file;
use function preg_match;
+use function simplexml_load_file;
class ParamsLoader
{
/**
- * @param array|string $paramStorage
- * @return array
* @throws ConfigurationException
*/
public static function load(array|string $paramStorage): array
@@ -35,8 +31,8 @@ public static function load(array|string $paramStorage): array
return $paramStorage;
}
- if ($paramStorage === 'env' || $paramStorage === 'environment') {
- return self::loadEnvironmentVars();
+ if (in_array($paramStorage, ['env', 'environment'])) {
+ return $_SERVER;
}
$paramsFile = codecept_absolute_path($paramStorage);
@@ -44,35 +40,28 @@ public static function load(array|string $paramStorage): array
throw new ConfigurationException("Params file {$paramsFile} not found");
}
- try {
- if (preg_match('#\.ya?ml$#', $paramStorage)) {
- return self::loadYamlFile($paramsFile);
+ $loaderMappings = [
+ 'loadYamlFile' => '#\.ya?ml$#',
+ 'loadIniFile' => '#\.ini$#',
+ 'loadPhpFile' => '#\.php$#',
+ 'loadDotEnvFile' => '#(\.env(\.|$))#',
+ 'loadXmlFile' => '#\.xml$#',
+ ];
+
+ foreach ($loaderMappings as $method => $pattern) {
+ if (preg_match($pattern, $paramStorage)) {
+ try {
+ return self::$method($paramStorage);
+ } catch (Exception $e) {
+ throw new ConfigurationException("Failed loading params from {$paramStorage}\n" . $e->getMessage());
+ }
}
-
- if (preg_match('#\.ini$#', $paramStorage)) {
- return self::loadIniFile($paramsFile);
- }
-
- if (preg_match('#\.php$#', $paramStorage)) {
- return self::loadPhpFile($paramsFile);
- }
-
- if (preg_match('#(\.env(\.|$))#', $paramStorage)) {
- return self::loadDotEnvFile($paramsFile);
- }
-
- if (preg_match('#\.xml$#', $paramStorage)) {
- return self::loadXmlFile($paramsFile);
- }
- } catch (Exception $e) {
- throw new ConfigurationException("Failed loading params from {$paramStorage}\n" . $e->getMessage());
}
throw new ConfigurationException("Params can't be loaded from `{$paramStorage}`.");
}
/**
- * @return array
* @throws ConfigurationException
*/
private static function loadIniFile(string $file): array
@@ -82,7 +71,6 @@ private static function loadIniFile(string $file): array
}
/**
- * @return array
* @throws ConfigurationException
*/
private static function loadPhpFile(string $file): array
@@ -92,23 +80,15 @@ private static function loadPhpFile(string $file): array
}
/**
- * @return array
* @throws ConfigurationException
*/
private static function loadYamlFile(string $file): array
{
$params = Yaml::parse(self::getFileContents($file));
- $params = self::validateParams($params, $file);
-
- if (isset($params['parameters'])) { // Symfony style
- $params = self::validateParams($params['parameters'], $file);
- ;
- }
- return self::validateParams($params, $file);
+ return self::validateParams($params['parameters'] ?? $params, $file);
}
/**
- * @return array
* @throws ConfigurationException
*/
private static function loadXmlFile(string $file): array
@@ -127,10 +107,9 @@ private static function loadXmlFile(string $file): array
'bool', 'boolean', 'int', 'integer', 'float', 'double' => settype($value, $type),
'constant' => constant($value),
'collection' => $paramsToArray($param),
- default => (string) $param,
+ default => (string)$param,
};
}
-
return $a;
};
@@ -138,29 +117,25 @@ private static function loadXmlFile(string $file): array
if ($simpleXMLElement === false) {
throw new ConfigurationException("Params can't be loaded from `{$file}`.");
}
- $params = $paramsToArray($simpleXMLElement);
+ $params = $paramsToArray($simpleXMLElement);
return self::validateParams($params, $file);
}
/**
- * @return array
* @throws ConfigurationException
*/
private static function loadDotEnvFile(string $file): array
{
- // vlucas/phpdotenv
if (
- class_exists(PhpDotenv::class)
- && class_exists(RepositoryBuilder::class)
- && method_exists(RepositoryBuilder::class, 'createWithDefaultAdapters')
+ class_exists(PhpDotenv::class) &&
+ class_exists(RepositoryBuilder::class) &&
+ method_exists(RepositoryBuilder::class, 'createWithDefaultAdapters')
) {
$repository = RepositoryBuilder::createWithDefaultAdapters()->make();
$dotenv = PhpDotenv::create($repository, codecept_root_dir(), codecept_relative_path($file));
-
return $dotenv->load();
}
- // symfony/dotenv
if (class_exists(SymfonyDotenv::class)) {
$symfonyDotEnv = new SymfonyDotenv();
$values = $symfonyDotEnv->parse(self::getFileContents($file), $file);
@@ -174,14 +149,6 @@ class_exists(PhpDotenv::class)
);
}
- /**
- * @return array
- */
- private static function loadEnvironmentVars(): array
- {
- return $_SERVER;
- }
-
/**
* @throws ConfigurationException
*/
@@ -195,7 +162,6 @@ private static function getFileContents(string $file): string
}
/**
- * @return array
* @throws ConfigurationException
*/
private static function validateParams(mixed $params, string $file): array
diff --git a/src/Codeception/Lib/Parser.php b/src/Codeception/Lib/Parser.php
index 4c91a59d7f..6e47f99369 100644
--- a/src/Codeception/Lib/Parser.php
+++ b/src/Codeception/Lib/Parser.php
@@ -28,16 +28,10 @@ public function prepareToRun(string $code): void
public function parseFeature(string $code): void
{
- $matches = [];
$code = $this->stripComments($code);
- $res = preg_match("#\\\$I->wantTo\\(\\s*?['\"](.*?)['\"]\\s*?\\);#", $code, $matches);
- if ($res) {
- $this->scenario->setFeature($matches[1]);
- return;
- }
- $res = preg_match("#\\\$I->wantToTest\\(['\"](.*?)['\"]\\);#", $code, $matches);
- if ($res) {
- $this->scenario->setFeature("test " . $matches[1]);
+ if (preg_match("#\\\$I->(wantTo|wantToTest)\\(\\s*?['\"](.*?)['\"]\\s*?\\);#", $code, $matches)) {
+ $feature = $matches[1] === 'wantToTest' ? "test {$matches[2]}" : $matches[2];
+ $this->scenario->setFeature($feature);
}
}
@@ -48,17 +42,15 @@ public function parseScenarioOptions(string $code): void
public function parseSteps(string $code): void
{
- // parse per line
$friends = [];
$lines = explode("\n", $code);
$isFriend = false;
+
foreach ($lines as $line) {
- // friends
- if (preg_match("#\\\$I->haveFriend\\((.*?)\\);#", $line, $matches)) {
+ if (preg_match("#\\\$I->haveFriend\\((.*?)\\);#", $line, $matches)) { // Friends
$friends[] = trim($matches[1], '\'"');
}
- // friend's section start
- if (preg_match("#\\\$(.*?)->does\\(#", $line, $matches)) {
+ if (preg_match("#\\\$(.*?)->does\\(#", $line, $matches)) { // Friends section start
$friend = $matches[1];
if (!in_array($friend, $friends)) {
continue;
@@ -67,14 +59,10 @@ public function parseSteps(string $code): void
$this->addCommentStep("\n----- {$friend} does -----");
continue;
}
-
- // actions
- if (preg_match("#\\\$I->(.*)\\((.*?)\\);#", $line, $matches)) {
+ if (preg_match("#\\\$I->(.*)\\((.*?)\\);#", $line, $matches)) { // Actions
$this->addStep($matches);
}
-
- // friend's section ends
- if ($isFriend && str_contains($line, '}')) {
+ if ($isFriend && str_contains($line, '}')) { // Friends section ends
$this->addCommentStep("-------- back to me\n");
$isFriend = false;
}
@@ -84,10 +72,9 @@ public function parseSteps(string $code): void
protected function addStep(array $matches): void
{
[$m, $action, $params] = $matches;
- if (in_array($action, ['wantTo', 'wantToTest'])) {
- return;
+ if (!in_array($action, ['wantTo', 'wantToTest'])) {
+ $this->scenario->addStep(new Action($action, explode(',', $params)));
}
- $this->scenario->addStep(new Action($action, explode(',', $params)));
}
protected function addCommentStep(string $comment): void
@@ -111,62 +98,69 @@ public static function load(string $file): void
*/
public static function getClassesFromFile(string $file): array
{
- $sourceCode = file_get_contents($file);
- $classes = [];
- $tokens = token_get_all($sourceCode, TOKEN_PARSE);
-
- $tokenCount = count($tokens);
+ $sourceCodeTokens = token_get_all(file_get_contents($file), TOKEN_PARSE);
+ $classes = [];
$namespace = '';
- for ($i = 0; $i < $tokenCount; ++$i) {
- if ($tokens[$i][0] === T_NAMESPACE) {
- $namespace = '';
- for ($j = $i + 1; $j < $tokenCount; ++$j) {
- if ($tokens[$j] === '{' || $tokens[$j] === ';') {
- break;
- }
- if ($tokens[$j][0] === T_STRING || $tokens[$j][0] === T_NAME_QUALIFIED) {
- $namespace .= $tokens[$j][1] . '\\';
- }
- }
+ foreach ($sourceCodeTokens as $i => $token) {
+ if ($token[0] === T_NAMESPACE) {
+ $namespace = self::extractNamespace($sourceCodeTokens, $i);
}
-
- if ($tokens[$i][0] === T_CLASS) {
- // class at the beginning of file
- if (!isset($tokens[$i - 2])) {
- $classes[] = $namespace . $tokens[$i + 2][1];
- continue;
- }
- // new class
- if ($tokens[$i - 2][0] === T_NEW) {
- continue;
+ if ($token[0] === T_CLASS) {
+ $class = self::extractClass($sourceCodeTokens, $i);
+ if ($class) {
+ $classes[] = $namespace . $class;
}
- // :: class
- if ($tokens[$i - 1][0] === T_WHITESPACE && $tokens[$i - 2][0] === T_DOUBLE_COLON) {
- continue;
- }
- // ::class
- if ($tokens[$i - 1][0] === T_DOUBLE_COLON) {
- continue;
- }
- // class{
- if (isset($tokens[$i + 1]) && ($tokens[$i + 1] === '{')) {
- continue;
- }
- // class {
- if (isset($tokens[$i + 2]) && $tokens[$i + 1][0] === T_WHITESPACE && $tokens[$i + 2] === '{') {
- continue;
- }
- $classes[] = $namespace . $tokens[$i + 2][1];
}
}
- $tokens = null;
gc_mem_caches();
-
return $classes;
}
+ private static function extractNamespace(array $tokens, int $index): string
+ {
+ $namespace = '';
+ for ($j = $index + 1; $j < count($tokens); ++$j) {
+ if ($tokens[$j] === '{' || $tokens[$j] === ';') {
+ break;
+ }
+ if ($tokens[$j][0] === T_STRING || $tokens[$j][0] === T_NAME_QUALIFIED) {
+ $namespace .= $tokens[$j][1] . '\\';
+ }
+ }
+ return $namespace;
+ }
+
+ private static function extractClass(array $tokens, int $index): ?string
+ {
+ // class at the beginning of file
+ if (!isset($tokens[$index - 2])) {
+ return $tokens[$index + 2][1] ?? null;
+ }
+ // new class
+ if (isset($tokens[$index - 2]) && $tokens[$index - 2][0] === T_NEW) {
+ return null;
+ }
+ // :: class
+ if (isset($tokens[$index - 1]) && $tokens[$index - 1][0] === T_WHITESPACE && isset($tokens[$index - 2]) && $tokens[$index - 2][0] === T_DOUBLE_COLON) {
+ return null;
+ }
+ // ::class
+ if (isset($tokens[$index - 1]) && $tokens[$index - 1][0] === T_DOUBLE_COLON) {
+ return null;
+ }
+ // class{
+ if (isset($tokens[$index + 1]) && $tokens[$index + 1] === '{') {
+ return null;
+ }
+ // class {
+ if (isset($tokens[$index + 2]) && $tokens[$index + 1][0] === T_WHITESPACE && $tokens[$index + 2] === '{') {
+ return null;
+ }
+ return $tokens[$index + 2][1] ?? null;
+ }
+
/*
* Include in different scope to prevent included file from affecting $file variable
*/
@@ -177,24 +171,16 @@ private static function includeFile(string $file): void
protected function stripComments(string $code): string
{
- $code = preg_replace('#//.*?$#m', '', $code); // remove inline comments
- return preg_replace('#/*\*.*?\*/#ms', '', $code); // remove block comment
+ return preg_replace(['#//.*?$#m', '#/*\*.*?\*/#ms'], '', $code); // inline & block comments
}
protected function matchComments(string $code): string
{
- $matches = [];
- $comments = '';
- $hasLineComment = preg_match_all('#//(.*?)$#m', $code, $matches);
- if ($hasLineComment) {
- foreach ($matches[1] as $line) {
- $comments .= $line . "\n";
- }
- }
- $hasBlockComment = preg_match('#/*\*(.*?)\*/#ms', $code, $matches);
- if ($hasBlockComment) {
- $comments .= $matches[1] . "\n";
- }
- return $comments;
+ preg_match_all('#//(.*?)$#m', $code, $lineMatches);
+ preg_match('#/\*(.*?)\*/#ms', $code, $blockMatch);
+ $lineComments = implode("\n", $lineMatches[1] ?? []);
+ $blockComments = $blockMatch[1] ?? '';
+
+ return $lineComments . "\n" . $blockComments . "\n";
}
}
diff --git a/src/Codeception/Lib/PauseShell.php b/src/Codeception/Lib/PauseShell.php
index 3bd5afd567..6e5f750efa 100644
--- a/src/Codeception/Lib/PauseShell.php
+++ b/src/Codeception/Lib/PauseShell.php
@@ -1,9 +1,11 @@
psyConf = new Configuration([
'prompt' => '>> ',
- 'startupMessage' => "Execution PAUSED All commands will be saved to $relativeLogFilePath"
+ 'startupMessage' => "Execution PAUSED All commands will be saved to $relativeLogFilePath",
+ 'historyFile' => codecept_output_dir(self::LOG_FILE),
+ 'historySize' => 1000,
]);
- $this->psyConf->setHistoryFile(codecept_output_dir(self::LOG_FILE));
- $this->psyConf->setHistorySize(1000);
}
public function addMessage(string $message): self
diff --git a/src/Codeception/Module.php b/src/Codeception/Module.php
index ebf1db81ab..559011074f 100644
--- a/src/Codeception/Module.php
+++ b/src/Codeception/Module.php
@@ -134,7 +134,7 @@ protected function validateConfig(): void
$fields = array_keys($this->config);
if (array_intersect($this->requiredFields, $fields) !== $this->requiredFields) {
throw new ModuleConfigException(
- $this::class,
+ static::class,
"\nOptions: " . implode(', ', $this->requiredFields) . " are required\n" .
"Please, update the configuration and set all the required fields\n\n"
);
@@ -158,7 +158,7 @@ protected function validateConfig(): void
*/
public function _getName(): string
{
- $moduleName = '\\' . $this::class;
+ $moduleName = '\\' . static::class;
if (str_starts_with($moduleName, ModuleContainer::MODULE_NAMESPACE)) {
return substr($moduleName, strlen(ModuleContainer::MODULE_NAMESPACE));
@@ -172,7 +172,7 @@ public function _getName(): string
*/
public function _hasRequiredFields(): bool
{
- return !empty($this->requiredFields);
+ return $this->requiredFields !== [];
}
/**
@@ -287,7 +287,7 @@ protected function getModules(): array
protected function getModule(string $name): Module
{
if (!$this->hasModule($name)) {
- $this->moduleContainer->throwMissingModuleExceptionWithSuggestion(__CLASS__, $name);
+ $this->moduleContainer->throwMissingModuleExceptionWithSuggestion(self::class, $name);
}
return $this->moduleContainer->getModule($name);
}
@@ -298,15 +298,12 @@ protected function getModule(string $name): Module
* @param string|null $key
* @return mixed the config item's value or null if it doesn't exist
*/
- public function _getConfig(string $key = null): mixed
+ public function _getConfig(?string $key = null): mixed
{
if (!$key) {
return $this->config;
}
- if (isset($this->config[$key])) {
- return $this->config[$key];
- }
- return null;
+ return $this->config[$key] ?? null;
}
protected function scalarizeArray(array $array): array
diff --git a/src/Codeception/Reporter/HtmlReporter.php b/src/Codeception/Reporter/HtmlReporter.php
index ba00c7227d..7bfb98ad3e 100644
--- a/src/Codeception/Reporter/HtmlReporter.php
+++ b/src/Codeception/Reporter/HtmlReporter.php
@@ -14,7 +14,6 @@
use Codeception\Test\Descriptor;
use Codeception\Test\Interfaces\ScenarioDriven;
use Codeception\Test\Test;
-use Codeception\TestInterface;
use Codeception\Util\PathResolver;
use SebastianBergmann\Template\Template;
use SebastianBergmann\Timer\Timer;
@@ -167,16 +166,14 @@ public function printTestEvent(TestEvent $event, string $scenarioStatus): void
$png = '';
$html = '';
- if ($test instanceof TestInterface) {
- $reports = $test->getMetadata()->getReports();
- if (isset($reports['png'])) {
- $localPath = PathResolver::getRelativeDir($reports['png'], codecept_output_dir());
- $png = " |
";
- }
- if (isset($reports['html'])) {
- $localPath = PathResolver::getRelativeDir($reports['html'], codecept_output_dir());
- $html = "| See HTML snapshot of a failed page |
";
- }
+ $reports = $test->getMetadata()->getReports();
+ if (isset($reports['png'])) {
+ $localPath = PathResolver::getRelativeDir($reports['png'], codecept_output_dir());
+ $png = " |
";
+ }
+ if (isset($reports['html'])) {
+ $localPath = PathResolver::getRelativeDir($reports['html'], codecept_output_dir());
+ $html = "| See HTML snapshot of a failed page |
";
}
$toggle = $stepsBuffer ? '+' : '';
@@ -249,16 +246,14 @@ public function printTestResult(Test $test, float $time, string $scenarioStatus)
$png = '';
$html = '';
- if ($test instanceof TestInterface) {
- $reports = $test->getMetadata()->getReports();
- if (isset($reports['png'])) {
- $localPath = PathResolver::getRelativeDir($reports['png'], codecept_output_dir());
- $png = " |
";
- }
- if (isset($reports['html'])) {
- $localPath = PathResolver::getRelativeDir($reports['html'], codecept_output_dir());
- $html = "| See HTML snapshot of a failed page |
";
- }
+ $reports = $test->getMetadata()->getReports();
+ if (isset($reports['png'])) {
+ $localPath = PathResolver::getRelativeDir($reports['png'], codecept_output_dir());
+ $png = " |
";
+ }
+ if (isset($reports['html'])) {
+ $localPath = PathResolver::getRelativeDir($reports['html'], codecept_output_dir());
+ $html = "| See HTML snapshot of a failed page |
";
}
$toggle = $stepsBuffer ? '+' : '';
diff --git a/src/Codeception/Reporter/JUnitReporter.php b/src/Codeception/Reporter/JUnitReporter.php
index 21b8f95473..74112969bc 100644
--- a/src/Codeception/Reporter/JUnitReporter.php
+++ b/src/Codeception/Reporter/JUnitReporter.php
@@ -218,7 +218,7 @@ public function startTest(TestEvent $event): void
$this->currentTestCase = $this->document->createElement('testcase');
foreach ($test->getReportFields() as $attr => $value) {
- if ($this->isStrict and !in_array($attr, $this->strictAttributes)) {
+ if ($this->isStrict && !in_array($attr, $this->strictAttributes)) {
continue;
}
$this->currentTestCase->setAttribute($attr, $value);
@@ -313,7 +313,7 @@ public function testFailure(FailEvent $event): void
public function testSkipped(FailEvent $event): void
{
- if ($this->currentTestCase === null) {
+ if (!$this->currentTestCase instanceof DOMElement) {
return;
}
@@ -325,7 +325,7 @@ public function testSkipped(FailEvent $event): void
public function testUseless(FailEvent $event): void
{
- if ($this->currentTestCase === null) {
+ if (!$this->currentTestCase instanceof DOMElement) {
return;
}
@@ -343,7 +343,7 @@ public function testUseless(FailEvent $event): void
*/
private function doAddFault(Test $test, Throwable $t, string $type): void
{
- if ($this->currentTestCase === null) {
+ if (!$this->currentTestCase instanceof DOMElement) {
return;
}
diff --git a/src/Codeception/Reporter/ReportPrinter.php b/src/Codeception/Reporter/ReportPrinter.php
index 580c698494..9042c29cbf 100644
--- a/src/Codeception/Reporter/ReportPrinter.php
+++ b/src/Codeception/Reporter/ReportPrinter.php
@@ -64,7 +64,7 @@ public function testError(FailEvent $event): void
public function testFailure(FailEvent $event): void
{
- $this->printTestResult($event->getTest(), "\033[41;37mFAIL\033[0m");
+ $this->printTestResult($event->getTest(), "FAIL");
$this->failureCount++;
}
diff --git a/src/Codeception/Snapshot.php b/src/Codeception/Snapshot.php
index b1eeb640d9..ac21122613 100644
--- a/src/Codeception/Snapshot.php
+++ b/src/Codeception/Snapshot.php
@@ -78,7 +78,7 @@ protected function save(): void
protected function getFileName(): string
{
if (!$this->fileName) {
- $this->fileName = preg_replace('#\W#', '.', $this::class) . '.' . $this->extension;
+ $this->fileName = preg_replace('#\W#', '.', static::class) . '.' . $this->extension;
}
return codecept_data_dir() . $this->fileName;
}
@@ -168,6 +168,6 @@ public function setSnapshotFileExtension(string $fileExtension = 'json'): void
private function printDebug(string $message): void
{
- Debug::debug($this::class . ': ' . $message);
+ Debug::debug(static::class . ': ' . $message);
}
}
diff --git a/src/Codeception/Step.php b/src/Codeception/Step.php
index fa28ceb09d..ce032a701d 100644
--- a/src/Codeception/Step.php
+++ b/src/Codeception/Step.php
@@ -41,6 +41,7 @@ abstract class Step implements Stringable
protected bool $isTry = false;
+ /** @param string[] $arguments */
public function __construct(protected string $action, protected array $arguments = [])
{
}
@@ -64,14 +65,14 @@ public function saveTrace(): void
$this->addMetaStep($traceLine, $stack);
}
- private function isTestFile(string $file)
+ private function isTestFile(string $file): int|false
{
return preg_match('#[^\\' . DIRECTORY_SEPARATOR . '](Cest|Cept|Test).php$#', $file);
}
public function getName(): string
{
- $class = explode('\\', __CLASS__);
+ $class = explode('\\', self::class);
return end($class);
}
@@ -124,10 +125,7 @@ public function getArgumentsAsString(int $maxLength = self::DEFAULT_MAX_LENGTH):
uasort($arguments, function ($arg1, $arg2): int {
$length1 = mb_strlen($arg1, 'utf-8');
$length2 = mb_strlen($arg2, 'utf-8');
- if ($length1 === $length2) {
- return 0;
- }
- return ($length1 < $length2) ? -1 : 1;
+ return $length1 <=> $length2;
});
$allowedLength = floor(($maxLength - $argumentCount + 1) / $argumentCount);
@@ -243,7 +241,7 @@ public function toString(int $maxLength): string
public function getHtml(string $highlightColor = '#732E81'): string
{
- if (empty($this->arguments)) {
+ if ($this->arguments === []) {
return sprintf('%s %s', ucfirst($this->prefix), $this->humanize($this->getAction()));
}
@@ -276,10 +274,10 @@ protected function humanize(string $text): string
/**
* @return mixed
*/
- public function run(ModuleContainer $container = null)
+ public function run(?ModuleContainer $container = null)
{
$this->executed = true;
- if ($container === null) {
+ if (!$container instanceof ModuleContainer) {
return null;
}
$activeModule = $container->moduleForAction($this->action);
diff --git a/src/Codeception/Step/Comment.php b/src/Codeception/Step/Comment.php
index 8162eb1d03..ef5943a5c2 100644
--- a/src/Codeception/Step/Comment.php
+++ b/src/Codeception/Step/Comment.php
@@ -31,7 +31,7 @@ public function getPhpCode(int $maxLength): string
return '// ' . $this->getAction();
}
- public function run(ModuleContainer $container = null): void
+ public function run(?ModuleContainer $container = null): void
{
// don't do anything, let's rest
}
diff --git a/src/Codeception/Step/ConditionalAssertion.php b/src/Codeception/Step/ConditionalAssertion.php
index d7141bdd25..015b48b19b 100644
--- a/src/Codeception/Step/ConditionalAssertion.php
+++ b/src/Codeception/Step/ConditionalAssertion.php
@@ -15,7 +15,7 @@
class ConditionalAssertion extends Assertion implements GeneratedStep
{
- public function run(ModuleContainer $container = null): void
+ public function run(?ModuleContainer $container = null): void
{
try {
parent::run($container);
diff --git a/src/Codeception/Step/Executor.php b/src/Codeception/Step/Executor.php
index 122e70ff53..51427a032d 100644
--- a/src/Codeception/Step/Executor.php
+++ b/src/Codeception/Step/Executor.php
@@ -10,16 +10,12 @@
class Executor extends CodeceptionStep
{
- protected Closure $callable;
-
- public function __construct(Closure $callable, array $arguments = [])
+ public function __construct(protected Closure $callable, array $arguments = [])
{
parent::__construct('execute callable function', []);
-
- $this->callable = $callable;
}
- public function run(ModuleContainer $container = null)
+ public function run(?ModuleContainer $container = null)
{
$callable = $this->callable;
diff --git a/src/Codeception/Step/Incomplete.php b/src/Codeception/Step/Incomplete.php
index 1ee849b2e8..022579c47f 100644
--- a/src/Codeception/Step/Incomplete.php
+++ b/src/Codeception/Step/Incomplete.php
@@ -10,7 +10,7 @@
class Incomplete extends CodeceptionStep
{
- public function run(ModuleContainer $container = null): void
+ public function run(?ModuleContainer $container = null): void
{
throw new IncompleteTestError($this->getAction());
}
diff --git a/src/Codeception/Step/Meta.php b/src/Codeception/Step/Meta.php
index 3711754864..f3eb9baa1a 100644
--- a/src/Codeception/Step/Meta.php
+++ b/src/Codeception/Step/Meta.php
@@ -14,7 +14,7 @@
class Meta extends CodeceptionStep
{
- public function run(ModuleContainer $container = null): void
+ public function run(?ModuleContainer $container = null): void
{
}
diff --git a/src/Codeception/Step/Retry.php b/src/Codeception/Step/Retry.php
index 1198f3b6fe..e39fb98377 100644
--- a/src/Codeception/Step/Retry.php
+++ b/src/Codeception/Step/Retry.php
@@ -38,7 +38,7 @@ public function __construct($action, array $arguments, private int $retryNum, pr
$this->arguments = $arguments;
}
- public function run(ModuleContainer $container = null)
+ public function run(?ModuleContainer $container = null)
{
$retry = 0;
$interval = $this->retryInterval;
diff --git a/src/Codeception/Step/Skip.php b/src/Codeception/Step/Skip.php
index 064ea004f7..5333abd575 100644
--- a/src/Codeception/Step/Skip.php
+++ b/src/Codeception/Step/Skip.php
@@ -12,7 +12,7 @@
class Skip extends CodeceptionStep
{
- public function run(ModuleContainer $container = null): void
+ public function run(?ModuleContainer $container = null): void
{
$skipMessage = $this->getAction();
diff --git a/src/Codeception/Step/TryTo.php b/src/Codeception/Step/TryTo.php
index cca9eea2b2..a90635724e 100644
--- a/src/Codeception/Step/TryTo.php
+++ b/src/Codeception/Step/TryTo.php
@@ -13,7 +13,7 @@
class TryTo extends Assertion implements GeneratedStep
{
- public function run(ModuleContainer $container = null): bool
+ public function run(?ModuleContainer $container = null): bool
{
$this->isTry = true;
try {
diff --git a/src/Codeception/Subscriber/Console.php b/src/Codeception/Subscriber/Console.php
index 5d229ed206..1364418573 100644
--- a/src/Codeception/Subscriber/Console.php
+++ b/src/Codeception/Subscriber/Console.php
@@ -31,6 +31,7 @@
use PHPUnit\Framework\IncompleteTestError;
use PHPUnit\Framework\SelfDescribing;
use PHPUnit\Framework\SkippedTest;
+use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Timer\Duration;
use SebastianBergmann\Timer\ResourceUsageFormatter;
use SebastianBergmann\Timer\Timer;
@@ -42,7 +43,6 @@
use function array_map;
use function array_merge;
use function array_reverse;
-use function array_shift;
use function codecept_relative_path;
use function count;
use function exec;
@@ -172,7 +172,7 @@ public function beforeSuite(SuiteEvent $event): void
implode(
', ',
array_map(
- fn ($module) => $module->_getName(),
+ fn ($module): string => $module->_getName(),
$event->getSuite()->getModules()
)
)
@@ -255,7 +255,6 @@ private function printResourceUsage(Duration $duration): void
/**
* @param FailEvent[] $defects
- * @param string $type
*/
private function printDefects(array $defects, string $type): void
{
@@ -319,11 +318,11 @@ protected function printFooter(PrintResultEvent $event): void
if ($result->wasSuccessful()) {
$style = 'warning';
$this->message('OK, but incomplete, skipped, or useless tests!')->style($style)->writeln();
- } elseif ($result->errorCount()) {
+ } elseif ($result->errorCount() !== 0) {
$this->message('ERRORS!')->style($style)->writeln();
- } elseif ($result->failureCount()) {
+ } elseif ($result->failureCount() !== 0) {
$this->message('FAILURES!')->style($style)->writeln();
- } elseif ($result->warningCount()) {
+ } elseif ($result->warningCount() !== 0) {
$style = 'warning';
$this->message('WARNINGS!')->style($style)->writeln();
}
@@ -442,7 +441,7 @@ public function beforeStep(StepEvent $event): void
}
$metaStep = $event->getStep()->getMetaStep();
- if ($metaStep && $this->metaStep != $metaStep) {
+ if ($metaStep instanceof Meta && $this->metaStep != $metaStep) {
$this->message(' ' . $metaStep->getPrefix())
->style('bold')
->append($metaStep->__toString())
@@ -459,17 +458,17 @@ private function printStep(Step $step): void
return; // don't print empty comments
}
$msg = $this->message(' ');
- if ($this->metaStep) {
+ if ($this->metaStep instanceof Meta) {
$msg->append(' ');
}
$msg->append($step->getPrefix());
$prefixLength = $msg->getLength();
- if (!$this->metaStep) {
+ if (!$this->metaStep instanceof Meta) {
$msg->style('bold');
}
$maxLength = $this->width - $prefixLength;
$msg->append(OutputFormatter::escape($step->toString($maxLength)));
- if ($this->metaStep) {
+ if ($this->metaStep instanceof Meta) {
$msg->style('info');
}
$msg->writeln();
@@ -531,7 +530,7 @@ public function printReports(TestInterface $failedTest): void
return;
}
$reports = $failedTest->getMetadata()->getReports();
- if (!empty($reports)) {
+ if ($reports !== []) {
$this->output->writeln('Artifacts:');
$this->output->writeln('');
}
@@ -542,7 +541,7 @@ public function printReports(TestInterface $failedTest): void
}
}
- public function printException($exception, string $cause = null): void
+ public function printException($exception, ?string $cause = null): void
{
if ($exception instanceof SkippedTest || $exception instanceof IncompleteTestError) {
if ($exception->getMessage() !== '') {
@@ -563,7 +562,7 @@ public function printException($exception, string $cause = null): void
if ($exception instanceof ExpectationFailedException) {
$comparisonFailure = $exception->getComparisonFailure();
- if ($comparisonFailure !== null) {
+ if ($comparisonFailure instanceof ComparisonFailure) {
$message->append($this->messageFactory->prepareComparisonFailureMessage($comparisonFailure));
}
}
@@ -779,9 +778,7 @@ protected function writelnFinishedTest(TestEvent $event, Message $result): void
$numFails = count(
array_filter(
$test->getScenario()?->getSteps() ?? [],
- function (Step $step) {
- return $step->hasFailed() && $step instanceof ConditionalAssertion;
- }
+ fn(Step $step): bool => $step->hasFailed() && $step instanceof ConditionalAssertion
)
);
@@ -811,7 +808,7 @@ protected function writeTimeInformation(TestEvent $event): void
if ($time !== 0.0) {
$this
->message(number_format(round($time, 2), 2))
- ->prepend('(')
+ ->prepend(' (')
->append('s)')
->style('info')
->write();
diff --git a/src/Codeception/Subscriber/Deprecation.php b/src/Codeception/Subscriber/Deprecation.php
index c08c9253e9..4e60ec2c6a 100644
--- a/src/Codeception/Subscriber/Deprecation.php
+++ b/src/Codeception/Subscriber/Deprecation.php
@@ -35,7 +35,7 @@ public function __construct(array $options)
public function afterSuite(SuiteEvent $event): void
{
$messages = Notification::all();
- if (count($messages) === 0) {
+ if ($messages === []) {
return;
}
diff --git a/src/Codeception/Subscriber/ErrorHandler.php b/src/Codeception/Subscriber/ErrorHandler.php
index 7cad330b4f..5b13d5d141 100644
--- a/src/Codeception/Subscriber/ErrorHandler.php
+++ b/src/Codeception/Subscriber/ErrorHandler.php
@@ -4,12 +4,12 @@
namespace Codeception\Subscriber;
+use Codeception\Event\SuiteEvent;
+use Codeception\Events;
use Codeception\Exception\Deprecation;
use Codeception\Exception\Error;
use Codeception\Exception\Notice;
use Codeception\Exception\Warning;
-use Codeception\Event\SuiteEvent;
-use Codeception\Events;
use Codeception\Lib\Notification;
use PHPUnit\Framework\Error\Deprecated as PHPUnit9Deprecation;
use PHPUnit\Framework\Error\Error as PHPUnit9Error;
@@ -21,7 +21,6 @@
use function call_user_func;
use function class_exists;
-use function count;
use function error_get_last;
use function error_reporting;
use function getenv;
@@ -72,7 +71,12 @@ class ErrorHandler implements EventSubscriberInterface
public function __construct()
{
- $this->errorLevel = E_ALL & ~E_STRICT & ~E_DEPRECATED;
+ // E_STRICT is deprecated in PHP 8.4
+ if (\PHP_VERSION_ID < 80400) {
+ $this->errorLevel = E_ALL & ~E_STRICT & ~E_DEPRECATED;
+ } else {
+ $this->errorLevel = E_ALL & ~E_DEPRECATED;
+ }
}
public function onFinish(SuiteEvent $event): void
@@ -99,7 +103,7 @@ public function handle(SuiteEvent $event): void
// and silence DeprecationErrorHandler yelling about 'THE ERROR HANDLER HAS CHANGED!'
register_shutdown_function([$this, 'shutdownHandler']);
$this->registerDeprecationErrorHandler();
- $this->oldHandler = set_error_handler([$this, 'errorHandler']);
+ $this->oldHandler = set_error_handler($this->errorHandler(...));
$this->initialized = true;
}
@@ -122,7 +126,7 @@ public function errorHandler(int $errNum, string $errMsg, string $errFile, int $
if (PHPUnitVersion::series() < 10) {
throw match ($errNum) {
E_DEPRECATED, E_USER_DEPRECATED => new PHPUnit9Deprecation($errMsg, $errNum, $errFile, $errLine),
- E_NOTICE, E_STRICT, E_USER_NOTICE => new PHPUnit9Notice($errMsg, $errNum, $errFile, $errLine),
+ E_NOTICE, E_USER_NOTICE => new PHPUnit9Notice($errMsg, $errNum, $errFile, $errLine),
E_WARNING, E_USER_WARNING => new PHPUnit9Warning($errMsg, $errNum, $errFile, $errLine),
default => new PHPUnit9Error($errMsg, $errNum, $errFile, $errLine),
};
@@ -130,7 +134,7 @@ public function errorHandler(int $errNum, string $errMsg, string $errFile, int $
$errMsg .= ' at ' . $errFile . ':' . $errLine;
throw match ($errNum) {
E_DEPRECATED, E_USER_DEPRECATED => new Deprecation($errMsg, $errNum, $errFile, $errLine),
- E_NOTICE, E_STRICT, E_USER_NOTICE => new Notice($errMsg, $errNum, $errFile, $errLine),
+ E_NOTICE, E_USER_NOTICE => new Notice($errMsg, $errNum, $errFile, $errLine),
E_WARNING, E_USER_WARNING => new Warning($errMsg, $errNum, $errFile, $errLine),
default => new Error($errMsg, $errNum, $errFile, $errLine),
};
@@ -184,7 +188,7 @@ private function registerDeprecationErrorHandler(): void
if (
$old
&& is_array($old)
- && count($old) > 0
+ && $old !== []
&& $old[0] instanceof \Symfony\Component\Debug\ErrorHandler
) {
restore_error_handler();
diff --git a/src/Codeception/Subscriber/PrepareTest.php b/src/Codeception/Subscriber/PrepareTest.php
index 002fedbc32..1e853526b9 100644
--- a/src/Codeception/Subscriber/PrepareTest.php
+++ b/src/Codeception/Subscriber/PrepareTest.php
@@ -9,7 +9,6 @@
use Codeception\Lib\Di;
use Codeception\Test\Cest;
use Codeception\Test\Unit;
-use Codeception\TestInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class PrepareTest implements EventSubscriberInterface
@@ -29,10 +28,6 @@ public function prepare(TestEvent $event): void
{
$test = $event->getTest();
- if (!$test instanceof TestInterface) {
- return;
- }
-
$prepareMethods = $test->getMetadata()->getParam('prepare');
if (!$prepareMethods) {
diff --git a/src/Codeception/Suite.php b/src/Codeception/Suite.php
index 5d30c5fa62..e71a80e58a 100644
--- a/src/Codeception/Suite.php
+++ b/src/Codeception/Suite.php
@@ -15,7 +15,9 @@
use PHPUnit\Framework\SkippedTestError;
use PHPUnit\Framework\SkippedWithMessageException;
use PHPUnit\Runner\Version;
+use PHPUnit\TextUI\CliArguments\Builder;
use PHPUnit\TextUI\Configuration\Registry;
+use PHPUnit\TextUI\XmlConfiguration\DefaultConfiguration;
use Symfony\Component\EventDispatcher\EventDispatcher;
use function count;
@@ -40,7 +42,7 @@ class Suite
*/
private array $tests = [];
- public function __construct(private EventDispatcher $dispatcher, private string $name = '')
+ public function __construct(private readonly EventDispatcher $dispatcher, private readonly string $name = '')
{
}
@@ -76,7 +78,7 @@ public function collectCodeCoverage(bool $enabled): void
public function run(ResultAggregator $result): void
{
- if (count($this->tests) === 0) {
+ if ($this->tests === []) {
return;
}
@@ -88,32 +90,28 @@ public function run(ResultAggregator $result): void
}
$this->dispatcher->dispatch(new TestEvent($test), Events::TEST_START);
- if ($test instanceof TestInterface) {
- if ($test->getMetadata()->isBlocked()) {
- $result->addTest($test);
-
- $skip = $test->getMetadata()->getSkip();
- if ($skip !== null) {
- if (class_exists(SkippedWithMessageException::class)) {
- $exception = new SkippedWithMessageException($skip);
- } else {
- $exception = new SkippedTestError($skip);
- }
- $failEvent = new FailEvent($test, $exception, 0);
- $result->addSkipped($failEvent);
- $this->dispatcher->dispatch($failEvent, Events::TEST_SKIPPED);
+ if ($test instanceof TestInterface && $test->getMetadata()->isBlocked()) {
+ $result->addTest($test);
+ $skip = $test->getMetadata()->getSkip();
+ if ($skip !== null) {
+ if (class_exists(SkippedWithMessageException::class)) {
+ $exception = new SkippedWithMessageException($skip);
+ } else {
+ $exception = new SkippedTestError($skip);
}
- $incomplete = $test->getMetadata()->getIncomplete();
- if ($incomplete !== null) {
- $exception = new IncompleteTestError($incomplete);
- $failEvent = new FailEvent($test, $exception, 0);
- $result->addIncomplete($failEvent);
- $this->dispatcher->dispatch($failEvent, Events::TEST_INCOMPLETE);
- }
-
- $this->dispatcher->dispatch(new TestEvent($test, 0), Events::TEST_END);
- continue;
+ $failEvent = new FailEvent($test, $exception, 0);
+ $result->addSkipped($failEvent);
+ $this->dispatcher->dispatch($failEvent, Events::TEST_SKIPPED);
+ }
+ $incomplete = $test->getMetadata()->getIncomplete();
+ if ($incomplete !== null) {
+ $exception = new IncompleteTestError($incomplete);
+ $failEvent = new FailEvent($test, $exception, 0);
+ $result->addIncomplete($failEvent);
+ $this->dispatcher->dispatch($failEvent, Events::TEST_INCOMPLETE);
}
+ $this->dispatcher->dispatch(new TestEvent($test, 0), Events::TEST_END);
+ continue;
}
if ($test instanceof TestCaseWrapper) {
@@ -158,7 +156,7 @@ protected function getDependencies(Test $test): array
$tests = [];
foreach ($test->fetchDependencies() as $requiredTestName) {
$required = $this->findMatchedTest($requiredTestName);
- if ($required === null) {
+ if (!$required instanceof Test) {
continue;
}
$tests = array_merge($tests, $this->getDependencies($required));
@@ -208,10 +206,8 @@ public function setBaseName(string $baseName): void
protected function fire(string $eventType, TestEvent $event): void
{
$test = $event->getTest();
- if ($test instanceof TestInterface) {
- foreach ($test->getMetadata()->getGroups() as $group) {
- $this->dispatcher->dispatch($event, $eventType . '.' . $group);
- }
+ foreach ($test->getMetadata()->getGroups() as $group) {
+ $this->dispatcher->dispatch($event, $eventType . '.' . $group);
}
$this->dispatcher->dispatch($event, $eventType);
}
@@ -247,8 +243,8 @@ public function initPHPUnitConfiguration(): void
$cliParameters [] = '--disallow-test-output';
}
- $cliConfiguration = (new \PHPUnit\TextUI\CliArguments\Builder())->fromParameters($cliParameters, []);
- $xmlConfiguration = \PHPUnit\TextUI\XmlConfiguration\DefaultConfiguration::create();
+ $cliConfiguration = (new Builder())->fromParameters($cliParameters);
+ $xmlConfiguration = DefaultConfiguration::create();
Registry::init($cliConfiguration, $xmlConfiguration);
}
}
diff --git a/src/Codeception/SuiteManager.php b/src/Codeception/SuiteManager.php
index ae229a81bb..b57667c23e 100644
--- a/src/Codeception/SuiteManager.php
+++ b/src/Codeception/SuiteManager.php
@@ -25,8 +25,6 @@ class SuiteManager
protected ?Suite $suite = null;
- protected ?EventDispatcher $dispatcher = null;
-
protected GroupManager $groupManager;
protected ModuleContainer $moduleContainer;
@@ -39,10 +37,9 @@ class SuiteManager
private Filter $testFilter;
- public function __construct(EventDispatcher $dispatcher, string $name, array $settings, array $options)
+ public function __construct(protected ?EventDispatcher $dispatcher, string $name, array $settings, array $options)
{
$this->settings = $settings;
- $this->dispatcher = $dispatcher;
$this->di = new Di();
$this->groupManager = new GroupManager($settings['groups']);
$this->moduleContainer = new ModuleContainer($this->di, $settings);
@@ -81,7 +78,7 @@ public function initialize(): void
ini_set('xdebug.show_exception_trace', '0'); // Issue https://github.com/symfony/symfony/issues/7646
}
- public function loadTests(string $path = null): void
+ public function loadTests(?string $path = null): void
{
$testLoader = new Loader($this->settings);
$testLoader->loadTests($path);
@@ -116,10 +113,10 @@ protected function addToSuite(Test $test): void
}
$this->suite->addTest($test);
-
- if (!empty($groups) && $test instanceof TestInterface) {
- $test->getMetadata()->setGroups($groups);
+ if ($groups === []) {
+ return;
}
+ $test->getMetadata()->setGroups($groups);
}
protected function createSuite(string $name): Suite
@@ -166,7 +163,7 @@ public function getModuleContainer(): ModuleContainer
protected function checkEnvironmentExists(TestInterface $test): void
{
$envs = $test->getMetadata()->getEnv();
- if (empty($envs)) {
+ if ($envs === []) {
return;
}
if (!isset($this->settings['env'])) {
@@ -184,13 +181,13 @@ protected function checkEnvironmentExists(TestInterface $test): void
protected function isExecutedInCurrentEnvironment(TestInterface $test): bool
{
$envs = $test->getMetadata()->getEnv();
- if (empty($envs)) {
+ if ($envs === []) {
return true;
}
$currentEnvironments = explode(',', $this->env);
foreach ($envs as $envList) {
$envList = explode(',', $envList);
- if (count($envList) == count(array_intersect($currentEnvironments, $envList))) {
+ if (count($envList) === count(array_intersect($currentEnvironments, $envList))) {
return true;
}
}
diff --git a/src/Codeception/Template/Bootstrap.php b/src/Codeception/Template/Bootstrap.php
index 6672ca35c8..c5d4a7b151 100644
--- a/src/Codeception/Template/Bootstrap.php
+++ b/src/Codeception/Template/Bootstrap.php
@@ -33,7 +33,7 @@ public function setup(): void
$input = $this->input;
if ($input->getOption('namespace')) {
- $this->namespace = trim($input->getOption('namespace'), '\\');
+ $this->namespace = trim((string) $input->getOption('namespace'), '\\');
}
if ($input->hasOption('actor') && $input->getOption('actor')) {
@@ -67,10 +67,10 @@ public function setup(): void
$this->say();
$this->say("Next steps:");
- $this->say('1. Edit tests/acceptance.suite.yml to set url of your application. Change PhpBrowser to WebDriver to enable browser testing');
- $this->say("2. Edit tests/functional.suite.yml to enable a framework module. Remove this file if you don't use a framework");
- $this->say("3. Create your first acceptance tests using codecept g:cest acceptance First");
- $this->say("4. Write first test in tests/acceptance/FirstCest.php");
+ $this->say('1. Edit tests/Acceptance.suite.yml to set url of your application. Change PhpBrowser to WebDriver to enable browser testing');
+ $this->say("2. Edit tests/Functional.suite.yml to enable a framework module. Remove this file if you don't use a framework");
+ $this->say("3. Create your first acceptance tests using codecept g:cest Acceptance First");
+ $this->say("4. Write first test in tests/Acceptance/FirstCest.php");
$this->say("5. Run tests using: codecept run");
}
diff --git a/src/Codeception/Template/Dependencies.php b/src/Codeception/Template/Dependencies.php
index 79368cad59..1bb1972cc8 100644
--- a/src/Codeception/Template/Dependencies.php
+++ b/src/Codeception/Template/Dependencies.php
@@ -27,7 +27,7 @@ public function setup(): void
$config = Configuration::config();
$modules = [];
$suites = Configuration::suites();
- if (empty($suites)) {
+ if ($suites === []) {
$this->sayError("No suites found in current config.");
$this->sayWarning('If you use sub-configs with `include` option, run this script on subconfigs:');
$this->sayWarning('Example: php vendor/bin/codecept init dependencies -c backend/');
diff --git a/src/Codeception/Test/DataProvider.php b/src/Codeception/Test/DataProvider.php
index 157583f59f..827279777f 100644
--- a/src/Codeception/Test/DataProvider.php
+++ b/src/Codeception/Test/DataProvider.php
@@ -45,7 +45,7 @@ public static function getDataForMethod(ReflectionMethod $method, ?ReflectionCla
// dataProvider annotation
$dataProviderAnnotations = Annotation::forMethod($testClassName, $methodName)->fetchAll('dataProvider');
// lowercase for back compatible
- if (empty($dataProviderAnnotations)) {
+ if ($dataProviderAnnotations === []) {
$dataProviderAnnotations = Annotation::forMethod($testClassName, $methodName)->fetchAll('dataprovider');
}
@@ -136,8 +136,8 @@ private static function getTestClass(ReflectionMethod $dataProviderMethod, ?Refl
{
$dataProviderDeclaringClass = $dataProviderMethod->getDeclaringClass();
// data provider in abstract class?
- if ($dataProviderDeclaringClass->isAbstract() && null !== $testClass && $dataProviderDeclaringClass->name !== $testClass->name) {
- $dataProviderDeclaringClass = $testClass;
+ if ($dataProviderDeclaringClass->isAbstract() && $testClass instanceof ReflectionClass && $dataProviderDeclaringClass->name !== $testClass->name) {
+ return $testClass;
}
return $dataProviderDeclaringClass;
}
diff --git a/src/Codeception/Test/Feature/ScenarioLoader.php b/src/Codeception/Test/Feature/ScenarioLoader.php
index c9e94fb80f..62eda58147 100644
--- a/src/Codeception/Test/Feature/ScenarioLoader.php
+++ b/src/Codeception/Test/Feature/ScenarioLoader.php
@@ -34,7 +34,7 @@ public function getScenarioText(string $format = 'text'): string
$code = $this->getSourceCode();
$this->getParser()->parseFeature($code);
$this->getParser()->parseSteps($code);
- if ($format == 'html') {
+ if ($format === 'html') {
return $this->getScenario()->getHtml();
}
return $this->getScenario()->getText();
diff --git a/src/Codeception/Test/Filter.php b/src/Codeception/Test/Filter.php
index a7400e318a..ac00bf7c3d 100644
--- a/src/Codeception/Test/Filter.php
+++ b/src/Codeception/Test/Filter.php
@@ -4,6 +4,8 @@
namespace Codeception\Test;
+use function array_intersect;
+
class Filter
{
private ?string $namePattern = null;
@@ -13,11 +15,11 @@ class Filter
/**
* @param string[] $includeGroups
* @param string[] $excludeGroups
- * @param string $namePattern
+ * @param string|null $namePattern
*/
public function __construct(
- private ?array $includeGroups,
- private ?array $excludeGroups,
+ private readonly ?array $includeGroups,
+ private readonly ?array $excludeGroups,
?string $namePattern
) {
if ($namePattern === null) {
@@ -25,7 +27,7 @@ public function __construct(
}
// Validates regexp without E_WARNING
- set_error_handler(function () {
+ set_error_handler(function (): void {
}, E_WARNING);
$isRegularExpression = preg_match($namePattern, '') !== false;
restore_error_handler();
@@ -95,10 +97,10 @@ public function isNameAccepted(Test $test): bool
public function isGroupAccepted(Test $test, array $groups): bool
{
- if ($this->includeGroups !== null && $this->includeGroups !== [] && count(\array_intersect($groups, $this->includeGroups)) === 0) {
+ if ($this->includeGroups !== null && $this->includeGroups !== [] && array_intersect($groups, $this->includeGroups) === []) {
return false;
}
- if ($this->excludeGroups !== null && $this->excludeGroups !== [] && count(\array_intersect($groups, $this->excludeGroups)) > 0) {
+ if ($this->excludeGroups !== null && $this->excludeGroups !== [] && count(array_intersect($groups, $this->excludeGroups)) > 0) {
return false;
}
diff --git a/src/Codeception/Test/Gherkin.php b/src/Codeception/Test/Gherkin.php
index 785ddef917..fb2639fc05 100644
--- a/src/Codeception/Test/Gherkin.php
+++ b/src/Codeception/Test/Gherkin.php
@@ -33,24 +33,15 @@
class Gherkin extends Test implements ScenarioDriven, Reported
{
- protected array $steps = [];
-
- protected FeatureNode $featureNode;
-
- protected ScenarioInterface $scenarioNode;
-
protected Scenario $scenario;
- public function __construct(FeatureNode $featureNode, ScenarioInterface $scenarioNode, array $steps = [])
+ public function __construct(protected FeatureNode $featureNode, protected ScenarioInterface $scenarioNode, protected array $steps = [])
{
- $this->featureNode = $featureNode;
- $this->scenarioNode = $scenarioNode;
- $this->steps = $steps;
$this->setMetadata(new Metadata());
$this->scenario = new Scenario($this);
- $this->getMetadata()->setName($scenarioNode->getTitle());
- $this->getMetadata()->setFeature((string)$featureNode->getTitle());
- $this->getMetadata()->setFilename($featureNode->getFile());
+ $this->getMetadata()->setName($this->scenarioNode->getTitle());
+ $this->getMetadata()->setFeature((string)$this->featureNode->getTitle());
+ $this->getMetadata()->setFilename($this->featureNode->getFile());
}
public function __clone(): void
diff --git a/src/Codeception/Test/Loader.php b/src/Codeception/Test/Loader.php
index 9391d2e3f5..88f38acb09 100644
--- a/src/Codeception/Test/Loader.php
+++ b/src/Codeception/Test/Loader.php
@@ -106,10 +106,10 @@ public function getTests(): array
private function splitTestsIntoChunks(int $chunks): array
{
- if (empty($this->tests)) {
+ if ($this->tests === []) {
return [];
}
- return array_chunk($this->tests, intval(ceil(sizeof($this->tests) / $chunks)));
+ return array_chunk($this->tests, (int) ceil(count($this->tests) / $chunks));
}
protected function relativeName(string $file): string
@@ -170,7 +170,7 @@ public function loadTest(string $path): void
throw new Exception('Test format not supported. Please, check you use the right suffix. Available filetypes: Cept, Cest, Test');
}
- public function loadTests(string $fileName = null): void
+ public function loadTests(?string $fileName = null): void
{
if ($fileName) {
$this->loadTest($fileName);
diff --git a/src/Codeception/Test/Loader/Gherkin.php b/src/Codeception/Test/Loader/Gherkin.php
index d079dd6af8..1c0a9bc65b 100644
--- a/src/Codeception/Test/Loader/Gherkin.php
+++ b/src/Codeception/Test/Loader/Gherkin.php
@@ -10,7 +10,6 @@
use Behat\Gherkin\Node\ExampleNode;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\OutlineNode;
-use Behat\Gherkin\Node\ScenarioInterface;
use Behat\Gherkin\Node\ScenarioNode;
use Behat\Gherkin\Parser as GherkinParser;
use Codeception\Configuration;
@@ -93,7 +92,7 @@ protected function fetchGherkinSteps(): void
$this->addSteps($roleContexts, "role:{$role}");
}
- if (empty($this->steps) && empty($contexts['default']) && $this->settings['actor']) { // if no context is set, actor to be a context
+ if ($this->steps === [] && empty($contexts['default']) && $this->settings['actor']) { // if no context is set, actor to be a context
$actorContext = $this->supportNamespace() . $this->settings['actor'];
if ($actorContext) {
$contexts['default'][] = $actorContext;
@@ -197,7 +196,6 @@ public function loadTests(string $filename): void
}
foreach ($featureNode->getScenarios() as $scenarioNode) {
- /** @var ScenarioInterface $scenarioNode */
$steps = $this->steps['default']; // load default context
foreach (array_merge($scenarioNode->getTags(), $featureNode->getTags()) as $tag) { // load tag contexts
diff --git a/src/Codeception/Test/Loader/Unit.php b/src/Codeception/Test/Loader/Unit.php
index 2c674ab882..8717bf8802 100644
--- a/src/Codeception/Test/Loader/Unit.php
+++ b/src/Codeception/Test/Loader/Unit.php
@@ -111,8 +111,6 @@ protected function enhancePhpunitTest(
array $afterClassMethods,
): TestCaseWrapper {
- $test = new TestCaseWrapper($testCase, $beforeClassMethods, $afterClassMethods);
-
- return $test;
+ return new TestCaseWrapper($testCase, $beforeClassMethods, $afterClassMethods);
}
}
diff --git a/src/Codeception/Test/Metadata.php b/src/Codeception/Test/Metadata.php
index ef4e2961be..9e588ad4c3 100644
--- a/src/Codeception/Test/Metadata.php
+++ b/src/Codeception/Test/Metadata.php
@@ -131,6 +131,7 @@ public function setFilename(string $filename): void
$this->filename = $filename;
}
+ /** @return string[] */
public function getDependencies(): array
{
return $this->params['depends'];
@@ -138,7 +139,10 @@ public function getDependencies(): array
public function isBlocked(): bool
{
- return $this->getSkip() !== null || $this->getIncomplete() !== null;
+ if ($this->getSkip() !== null) {
+ return true;
+ }
+ return $this->getIncomplete() !== null;
}
public function getFeature(): string
@@ -181,7 +185,7 @@ public function addReport(string $type, $report): void
* Returns test params like: env, group, skip, incomplete, etc.
* Can return by annotation or return all if no key passed
*/
- public function getParam(string $key = null): mixed
+ public function getParam(?string $key = null): mixed
{
if ($key) {
if (isset($this->params[$key])) {
@@ -214,7 +218,7 @@ public function setParamsFromAttributes($attributes): void
{
$params = [];
foreach ($attributes as $attribute) {
- $name = lcfirst(str_replace('Codeception\\Attribute\\', '', $attribute->getName()));
+ $name = lcfirst(str_replace('Codeception\\Attribute\\', '', (string) $attribute->getName()));
if ($attribute->isRepeated()) {
$params[$name] ??= [];
$params[$name][] = $attribute->getArguments();
@@ -233,7 +237,7 @@ public function setParamsFromAttributes($attributes): void
continue;
};
- $this->params[$single] = array_map(fn($a) => is_array($a) ? $a : [$a], $this->params[$single]);
+ $this->params[$single] = array_map(fn($a): array => is_array($a) ? $a : [$a], $this->params[$single]);
$this->params[$single] = array_merge(...$this->params[$single]);
}
diff --git a/src/Codeception/Test/Test.php b/src/Codeception/Test/Test.php
index fbfa1a1385..dd26585eab 100644
--- a/src/Codeception/Test/Test.php
+++ b/src/Codeception/Test/Test.php
@@ -10,8 +10,8 @@
use Codeception\Exception\UselessTestException;
use Codeception\PHPUnit\Wrapper\Test as TestWrapper;
use Codeception\ResultAggregator;
-use Codeception\Test\Interfaces\ScenarioDriven;
use Codeception\TestInterface;
+use LogicException;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Exception;
@@ -186,11 +186,7 @@ final public function realRun(ResultAggregator $result): void
$result->addFailure(new FailEvent($this, $e, $time));
$status = self::STATUS_FAIL;
$eventType = Events::TEST_FAIL;
- } catch (Exception $e) {
- $result->addError(new FailEvent($this, $e, $time));
- $status = self::STATUS_ERROR;
- $eventType = Events::TEST_ERROR;
- } catch (Throwable $e) {
+ } catch (Exception | Throwable $e) {
$result->addError(new FailEvent($this, $e, $time));
$status = self::STATUS_ERROR;
$eventType = Events::TEST_ERROR;
@@ -240,8 +236,8 @@ protected function doesNotPerformAssertions(): bool
public function getResultAggregator(): ResultAggregator
{
- if ($this->resultAggregator === null) {
- throw new \LogicException('ResultAggregator is not set');
+ if (!$this->resultAggregator instanceof ResultAggregator) {
+ throw new LogicException('ResultAggregator is not set');
}
return $this->resultAggregator;
}
@@ -270,14 +266,12 @@ public function numberOfAssertionsPerformed(): int
protected function fire(string $eventType, TestEvent $event): void
{
- if ($this->eventDispatcher === null) {
+ if (!$this->eventDispatcher instanceof EventDispatcher) {
throw new RuntimeException('EventDispatcher must be injected before running test');
}
$test = $event->getTest();
- if ($test instanceof TestInterface) {
- foreach ($test->getMetadata()->getGroups() as $group) {
- $this->eventDispatcher->dispatch($event, $eventType . '.' . $group);
- }
+ foreach ($test->getMetadata()->getGroups() as $group) {
+ $this->eventDispatcher->dispatch($event, $eventType . '.' . $group);
}
$this->eventDispatcher->dispatch($event, $eventType);
}
@@ -301,7 +295,7 @@ private function checkConditionalAsserts(ResultAggregator $result): void
}
$lastFailure = $result->getLastFailure();
- if ($lastFailure === null) {
+ if (!$lastFailure instanceof FailEvent) {
return;
}
diff --git a/src/Codeception/Test/TestCaseWrapper.php b/src/Codeception/Test/TestCaseWrapper.php
index dad82a972c..e10b5984d8 100644
--- a/src/Codeception/Test/TestCaseWrapper.php
+++ b/src/Codeception/Test/TestCaseWrapper.php
@@ -25,7 +25,7 @@
*/
class TestCaseWrapper extends Test implements Reported, Dependent, StrictCoverage, TestInterface, Descriptive
{
- private Metadata $metadata;
+ private readonly Metadata $metadata;
/**
* @var array
@@ -44,11 +44,7 @@ public function __construct(
$this->metadata = new Metadata();
$metadata = $this->metadata;
- if (PHPUnitVersion::series() < 10) {
- $methodName = $testCase->getName(false);
- } else {
- $methodName = $testCase->name();
- }
+ $methodName = PHPUnitVersion::series() < 10 ? $testCase->getName(false) : $testCase->name();
$metadata->setName($methodName);
$metadata->setFilename((new ReflectionClass($testCase))->getFileName());
@@ -156,18 +152,15 @@ public function test(): void
}
$numberOfAssertionsPerformed = $this->getNumAssertions();
- if (
- $this->reportUselessTests &&
- $numberOfAssertionsPerformed > 0 &&
- $this->testCase->doesNotPerformAssertions()
- ) {
- throw new UselessTestException(
- sprintf(
- 'This test indicates it does not perform assertions but %d assertions were performed',
- $numberOfAssertionsPerformed
- )
- );
+ if (!$this->reportUselessTests || $numberOfAssertionsPerformed <= 0 || !$this->testCase->doesNotPerformAssertions()) {
+ return;
}
+ throw new UselessTestException(
+ sprintf(
+ 'This test indicates it does not perform assertions but %d assertions were performed',
+ $numberOfAssertionsPerformed
+ )
+ );
}
/**
diff --git a/src/Codeception/Test/Unit.php b/src/Codeception/Test/Unit.php
index c4fc0066b1..072dacddcc 100644
--- a/src/Codeception/Test/Unit.php
+++ b/src/Codeception/Test/Unit.php
@@ -16,8 +16,8 @@
use Codeception\Test\Feature\Stub;
use Codeception\TestInterface;
use Codeception\Util\Debug;
+use LogicException;
-use function get_class;
use function lcfirst;
use function method_exists;
@@ -38,14 +38,14 @@ class Unit extends TestCase implements
public function __clone(): void
{
- if ($this->scenario !== null) {
+ if ($this->scenario instanceof Scenario) {
$this->scenario = clone $this->scenario;
}
}
public function getMetadata(): Metadata
{
- if (!$this->metadata) {
+ if (!$this->metadata instanceof Metadata) {
$this->metadata = new Metadata();
}
return $this->metadata;
@@ -63,7 +63,7 @@ public function setMetadata(?Metadata $metadata): void
public function getResultAggregator(): ResultAggregator
{
- throw new \LogicException('This method should not be called, TestCaseWrapper class must be used instead');
+ throw new LogicException('This method should not be called, TestCaseWrapper class must be used instead');
}
protected function _setUp()
@@ -81,7 +81,7 @@ protected function _setUp()
/** @var Di $di */
$di = $this->getMetadata()->getService('di');
// auto-inject $tester property
- if (($this->getMetadata()->getCurrent('actor')) && ($property = lcfirst(Configuration::config()['actor_suffix']))) {
+ if (($this->getMetadata()->getCurrent('actor')) && ($property = lcfirst((string) Configuration::config()['actor_suffix']))) {
$this->$property = $di->instantiate($this->getMetadata()->getCurrent('actor'));
}
@@ -124,7 +124,6 @@ public function getModule(string $module): Module
* Starts interactive pause in this test
*
* @param array $vars
- * @return void
*/
public function pause(array $vars = []): void
{
@@ -149,7 +148,7 @@ public function getReportFields(): array
{
return [
'name' => $this->getName(false),
- 'class' => get_class($this),
+ 'class' => static::class,
'file' => $this->getMetadata()->getFilename()
];
}
@@ -158,8 +157,8 @@ public function fetchDependencies(): array
{
$names = [];
foreach ($this->getMetadata()->getDependencies() as $required) {
- if (!str_contains($required, ':') && method_exists($this, $required)) {
- $required = get_class($this) . ":{$required}";
+ if (!str_contains((string) $required, ':') && method_exists($this, $required)) {
+ $required = static::class . ":{$required}";
}
$names[] = $required;
}
diff --git a/src/Codeception/Util/ActionSequence.php b/src/Codeception/Util/ActionSequence.php
index df341382dc..f6efadacd6 100644
--- a/src/Codeception/Util/ActionSequence.php
+++ b/src/Codeception/Util/ActionSequence.php
@@ -7,10 +7,10 @@
use Closure;
use Codeception\Step\Action;
use Exception;
+use Stringable;
use function call_user_func_array;
use function codecept_debug;
-use function get_class;
use function implode;
use function is_array;
use function str_replace;
@@ -53,7 +53,7 @@
* @method $this seeOptionIsSelected($selector, $optionText)
* @method $this dontSeeOptionIsSelected($selector, $optionText)
*/
-class ActionSequence
+class ActionSequence implements Stringable
{
/**
* @var Action[]
@@ -114,7 +114,7 @@ public function run(object $context): void
try {
call_user_func_array([$context, $step->getAction()], $step->getArguments());
} catch (Exception $exception) {
- $class = get_class($exception); // rethrow exception for a specific action
+ $class = $exception::class; // rethrow exception for a specific action
throw new $class($exception->getMessage() . "\nat {$step}");
}
}
diff --git a/src/Codeception/Util/Annotation.php b/src/Codeception/Util/Annotation.php
index c4975ad799..b9b7474700 100644
--- a/src/Codeception/Util/Annotation.php
+++ b/src/Codeception/Util/Annotation.php
@@ -4,11 +4,11 @@
namespace Codeception\Util;
+use ReflectionAttribute;
use ReflectionClass;
use ReflectionMethod;
use Reflector;
-use function get_class;
use function in_array;
use function is_object;
use function json_decode;
@@ -52,7 +52,7 @@ class Annotation
public static function forClass(object|string $class): self
{
if (is_object($class)) {
- $class = get_class($class);
+ $class = $class::class;
}
if (!isset(static::$reflectedClasses[$class])) {
@@ -111,9 +111,9 @@ public function method(string $method): self
public function fetch(string $annotation): ?string
{
$attr = $this->attribute($annotation);
- if ($attr) {
+ if ($attr instanceof ReflectionAttribute) {
$arguments = $attr->getArguments();
- if (count($arguments) === 0) {
+ if ($arguments === []) {
return '';
}
return $arguments[0];
@@ -128,7 +128,7 @@ public function fetch(string $annotation): ?string
public function fetchAll(string $annotation): array
{
$attr = $this->attribute($annotation);
- if ($attr) {
+ if ($attr instanceof ReflectionAttribute) {
if (!$attr->isRepeated()) {
return $attr->getArguments();
}
@@ -137,11 +137,11 @@ public function fetchAll(string $annotation): array
$annotation = 'examples'; // we renamed this annotation
}
$name = ucfirst($annotation);
- $attrs = array_filter($attrs, fn ($a) => $a->getName() === "Codeception\\Attribute\\$name");
+ $attrs = array_filter($attrs, fn ($a): bool => $a->getName() === "Codeception\\Attribute\\$name");
if ($annotation === 'examples') {
- return array_map(fn (\ReflectionAttribute $a) => $a->getArguments(), $attrs);
+ return array_map(fn (ReflectionAttribute $a): array => $a->getArguments(), $attrs);
}
- return array_merge(...array_map(fn (\ReflectionAttribute $a) => $a->getArguments(), $attrs));
+ return array_merge(...array_map(fn (ReflectionAttribute $a): array => $a->getArguments(), $attrs));
}
$docBlock = (string)$this->currentReflectedItem->getDocComment();
if (preg_match_all(sprintf(self::$regex, $annotation), $docBlock, $matched)) {
@@ -154,19 +154,18 @@ public function attributes(): array
{
$attrs = $this->currentReflectedItem->getAttributes();
$attrs = array_filter($attrs);
- $attrs = array_filter($attrs, fn (\ReflectionAttribute $a) => str_starts_with($a->getName(), 'Codeception\\Attribute\\'));
- return $attrs;
+ return array_filter($attrs, fn (ReflectionAttribute $a): bool => str_starts_with($a->getName(), 'Codeception\\Attribute\\'));
}
- public function attribute($name): ?\ReflectionAttribute
+ public function attribute(string $name): ?ReflectionAttribute
{
$attrs = $this->attributes();
if ($name === 'example') {
$name = 'examples'; // we renamed this annotation
}
$name = ucfirst($name);
- $attrs = array_filter($attrs, fn ($a) => $a->getName() === "Codeception\\Attribute\\$name");
- if (empty($attrs)) {
+ $attrs = array_filter($attrs, fn ($a): bool => $a->getName() === "Codeception\\Attribute\\$name");
+ if ($attrs === []) {
return null;
}
return reset($attrs);
diff --git a/src/Codeception/Util/Autoload.php b/src/Codeception/Util/Autoload.php
index 834c0f32b7..e04b96c6a0 100644
--- a/src/Codeception/Util/Autoload.php
+++ b/src/Codeception/Util/Autoload.php
@@ -53,7 +53,7 @@ private function __construct()
public static function addNamespace(string $prefix, string $baseDir, bool $prepend = false): void
{
if (!self::$registered) {
- spl_autoload_register([__CLASS__, 'load']);
+ spl_autoload_register(fn(string $class): string|false => self::load($class));
self::$registered = true;
}
@@ -101,7 +101,7 @@ public static function load(string $class): string|false
}
// fix for empty prefix
- if (isset(self::$map['\\']) && ($class[0] != '\\')) {
+ if (isset(self::$map['\\']) && ($class[0] !== '\\')) {
return self::load('\\' . $class);
}
diff --git a/src/Codeception/Util/Debug.php b/src/Codeception/Util/Debug.php
index cf2d3ab616..b2e54753d2 100644
--- a/src/Codeception/Util/Debug.php
+++ b/src/Codeception/Util/Debug.php
@@ -4,7 +4,6 @@
namespace Codeception\Util;
-use Codeception\Command\Console;
use Codeception\Lib\Console\Output;
use Codeception\Lib\PauseShell;
use Symfony\Component\Console\Helper\QuestionHelper;
@@ -29,7 +28,7 @@ public static function setOutput(Output $output): void
*/
public static function debug(mixed $message): void
{
- if (!self::$output) {
+ if (!self::$output instanceof Output) {
return;
}
self::$output->debug($message);
@@ -71,7 +70,7 @@ public static function pause(array $vars = []): void
public static function confirm($question)
{
- if (!self::$output) {
+ if (!self::$output instanceof Output) {
return;
}
diff --git a/src/Codeception/Util/FileSystem.php b/src/Codeception/Util/FileSystem.php
index 39c7b51daa..e5fe135d46 100644
--- a/src/Codeception/Util/FileSystem.php
+++ b/src/Codeception/Util/FileSystem.php
@@ -60,9 +60,7 @@ public static function deleteDir(string $dir): bool
if (!self::deleteDir($dir . DIRECTORY_SEPARATOR . $item)) {
chmod($dir . DIRECTORY_SEPARATOR . $item, 0777);
- if (!self::deleteDir($dir . DIRECTORY_SEPARATOR . $item)) {
- return false;
- }
+ return false;
}
}
@@ -74,7 +72,7 @@ public static function copyDir(string $src, string $dst): void
$dir = opendir($src);
@mkdir($dst);
while (false !== ($file = readdir($dir))) {
- if (($file != '.') && ($file != '..')) {
+ if (($file !== '.') && ($file !== '..')) {
if (is_dir($src . DIRECTORY_SEPARATOR . $file)) {
self::copyDir($src . DIRECTORY_SEPARATOR . $file, $dst . DIRECTORY_SEPARATOR . $file);
} else {
diff --git a/src/Codeception/Util/PathResolver.php b/src/Codeception/Util/PathResolver.php
index 389ad572cf..9e41e0f1b4 100644
--- a/src/Codeception/Util/PathResolver.php
+++ b/src/Codeception/Util/PathResolver.php
@@ -128,7 +128,7 @@ private static function getPathAbsolutenessPrefix(string $path, string $dirSep =
*/
private static function isWindows(string $dirSep = DIRECTORY_SEPARATOR): bool
{
- return ($dirSep == '\\');
+ return ($dirSep === '\\');
}
public static function isPathAbsolute(string $path): bool
diff --git a/src/Codeception/Util/ReflectionHelper.php b/src/Codeception/Util/ReflectionHelper.php
index 501fbd4917..54f405cd08 100644
--- a/src/Codeception/Util/ReflectionHelper.php
+++ b/src/Codeception/Util/ReflectionHelper.php
@@ -16,7 +16,6 @@
use function array_pop;
use function count;
use function explode;
-use function get_class;
use function implode;
use function in_array;
use function is_array;
@@ -37,7 +36,7 @@ class ReflectionHelper
*
* @throws ReflectionException
*/
- public static function readPrivateProperty(object $object, string $property, string $class = null): mixed
+ public static function readPrivateProperty(object $object, string $property, ?string $class = null): mixed
{
if (is_null($class)) {
$class = $object;
@@ -54,7 +53,7 @@ public static function readPrivateProperty(object $object, string $property, str
*
* @throws ReflectionException
*/
- public static function setPrivateProperty(object $object, string $property, $value, string $class = null): void
+ public static function setPrivateProperty(object $object, string $property, $value, ?string $class = null): void
{
if (is_null($class)) {
$class = $object;
@@ -71,7 +70,7 @@ public static function setPrivateProperty(object $object, string $property, $val
*
* @throws ReflectionException
*/
- public static function invokePrivateMethod(?object $object, string $method, array $args = [], string $class = null): mixed
+ public static function invokePrivateMethod(?object $object, string $method, array $args = [], ?string $class = null): mixed
{
if (is_null($class)) {
$class = $object;
@@ -90,7 +89,7 @@ public static function invokePrivateMethod(?object $object, string $method, arra
*/
public static function getClassShortName(object $object): string
{
- $path = explode('\\', get_class($object));
+ $path = explode('\\', $object::class);
return array_pop($path);
}
@@ -119,7 +118,7 @@ public static function getDefaultValue(ReflectionParameter $parameter): string
{
if ($parameter->isDefaultValueAvailable()) {
if (method_exists($parameter, 'isDefaultValueConstant') && $parameter->isDefaultValueConstant()) {
- $constName = $parameter->getDefaultValueConstantName();
+ $constName = (string)$parameter->getDefaultValueConstantName();
if (str_contains($constName, '::')) {
[$class, $const] = explode('::', $constName);
if (in_array($class, ['self', 'static'])) {
@@ -176,7 +175,7 @@ public static function phpEncodeArray(array $array): string
);
if ($isPlainArray($array)) {
- return '[' . implode(', ', array_map([self::class, 'phpEncodeValue'], $array)) . ']';
+ return '[' . implode(', ', array_map(fn($value): string => self::phpEncodeValue($value), $array)) . ']';
}
$values = array_map(
diff --git a/src/Codeception/Util/StackTraceFilter.php b/src/Codeception/Util/StackTraceFilter.php
index 801e771326..e607e86c1b 100644
--- a/src/Codeception/Util/StackTraceFilter.php
+++ b/src/Codeception/Util/StackTraceFilter.php
@@ -18,7 +18,7 @@ public static function getFilteredStackTrace(Throwable $e, bool $asString = true
{
$stackTrace = $asString ? '' : [];
- $trace = $e->getPrevious() ? $e->getPrevious()->getTrace() : $e->getTrace();
+ $trace = $e->getPrevious() instanceof Throwable ? $e->getPrevious()->getTrace() : $e->getTrace();
$eFile = $e->getFile();
$eLine = $e->getLine();
@@ -31,10 +31,10 @@ public static function getFilteredStackTrace(Throwable $e, bool $asString = true
}
foreach ($trace as $step) {
- if (self::classIsFiltered($step) and $filter) {
+ if (self::classIsFiltered($step) && $filter) {
continue;
}
- if (self::fileIsFiltered($step) and $filter) {
+ if (self::fileIsFiltered($step) && $filter) {
continue;
}
@@ -60,13 +60,14 @@ protected static function classIsFiltered(array $step): bool
$className = $step['class'];
foreach (self::$filteredClassesPattern as $filteredClassName) {
- if (str_starts_with($className, $filteredClassName)) {
+ if (str_starts_with((string) $className, (string) $filteredClassName)) {
return true;
}
}
return false;
}
+ /** @param string[] $step */
protected static function fileIsFiltered(array $step): bool
{
if (!isset($step['file'])) {
@@ -89,12 +90,7 @@ protected static function fileIsFiltered(array $step): bool
if (str_contains($step['file'], $modulePath)) {
return false; // don`t filter modules
}
-
- if (str_contains($step['file'], 'src' . DIRECTORY_SEPARATOR . 'Codeception' . DIRECTORY_SEPARATOR)) {
- return true;
- }
-
- return false;
+ return str_contains($step['file'], 'src' . DIRECTORY_SEPARATOR . 'Codeception' . DIRECTORY_SEPARATOR);
}
private static function frameExists(array $trace, string $file, int $line): bool
diff --git a/src/Codeception/Util/Template.php b/src/Codeception/Util/Template.php
index ab450a39e2..dd2c536984 100644
--- a/src/Codeception/Util/Template.php
+++ b/src/Codeception/Util/Template.php
@@ -20,9 +20,9 @@ class Template
public function __construct(
private string $template,
- private string $placeholderStart = '{{',
- private string $placeholderEnd = '}}',
- private ?string $encoderFunction = null,
+ private readonly string $placeholderStart = '{{',
+ private readonly string $placeholderEnd = '}}',
+ private readonly ?string $encoderFunction = null,
) {
}
@@ -45,10 +45,7 @@ public function setVars(array $vars): void
public function getVar(string $name)
{
- if (isset($this->vars[$name])) {
- return $this->vars[$name];
- }
- return null;
+ return $this->vars[$name] ?? null;
}
/**
diff --git a/tests/cli/BuildCest.php b/tests/cli/BuildCest.php
index caf67ae1d5..757e76b1ca 100644
--- a/tests/cli/BuildCest.php
+++ b/tests/cli/BuildCest.php
@@ -8,7 +8,6 @@
#[Group('core')]
final class BuildCest
{
- /** @var string */
private string $originalCliHelperContents;
public function _before()
@@ -21,7 +20,7 @@ public function _after()
file_put_contents(codecept_root_dir('tests/support/CliHelper.php'), $this->originalCliHelperContents);
}
- public function buildsActionsForAClass(CliGuy $I): void
+ public function buildsActionsForAClass(CliGuy $I)
{
$I->wantToTest('build command');
$I->runShellCommand('php codecept build');
@@ -36,7 +35,7 @@ public function buildsActionsForAClass(CliGuy $I): void
$I->seeInThisFile('public function assertSame($expected, $actual, string $message = "") {');
}
- public function usesLiteralTypes(CliGuy $I, Scenario $scenario): void
+ public function usesLiteralTypes(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('generate typehints with generated actions');
@@ -55,7 +54,7 @@ public function usesLiteralTypes(CliGuy $I, Scenario $scenario): void
$I->seeInThisFile('public function grabFromOutput(string $regex): string');
}
- public function generatedUnionReturnType(CliGuy $I, Scenario $scenario): void
+ public function generatedUnionReturnType(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('generate action with union return type');
@@ -72,12 +71,8 @@ public function generatedUnionReturnType(CliGuy $I, Scenario $scenario): void
$I->seeInThisFile('public function grabFromOutput(array|string $param): string|int');
}
- public function generatedIntersectReturnTypeOnPhp81(CliGuy $I, Scenario $scenario): void
+ public function generatedIntersectReturnTypeOnPhp81(CliGuy $I, Scenario $scenario)
{
- if (PHP_VERSION_ID < 80100) {
- $scenario->skip('Does not work in PHP < 8.1');
- }
-
$I->wantToTest('generate action with intersect return type');
$cliHelperContents = file_get_contents(codecept_root_dir('tests/support/CliHelper.php'));
@@ -93,7 +88,7 @@ public function generatedIntersectReturnTypeOnPhp81(CliGuy $I, Scenario $scenari
$I->seeInThisFile('public function grabFromOutput(\Codeception\Module\CliHelper&\ArrayObject $param): \Codeception\Module\CliHelper&\ArrayObject');
}
- public function noReturnForVoidType(CliGuy $I, Scenario $scenario): void
+ public function noReturnForVoidType(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('no return keyword generated for void typehint');
@@ -112,7 +107,7 @@ public function noReturnForVoidType(CliGuy $I, Scenario $scenario): void
$I->dontSeeInThisFile('return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion(\'seeDirFound\', func_get_args()));');
}
- public function generateNullableParameters(CliGuy $I, Scenario $scenario): void
+ public function generateNullableParameters(CliGuy $I, Scenario $scenario)
{
$cliHelperContents = file_get_contents(codecept_root_dir('tests/support/CliHelper.php'));
$cliHelperContents = str_replace('public function seeDirFound($dir)', 'public function seeDirFound(\Directory $dir = null): ?bool', $cliHelperContents);
@@ -127,7 +122,7 @@ public function generateNullableParameters(CliGuy $I, Scenario $scenario): void
$I->seeInThisFile('public function seeDirFound(?\Directory $dir = NULL): ?bool');
}
- public function generateMixedParameters(CliGuy $I, Scenario $scenario): void
+ public function generateMixedParameters(CliGuy $I, Scenario $scenario)
{
$cliHelperContents = file_get_contents(codecept_root_dir('tests/support/CliHelper.php'));
$cliHelperContents = str_replace('public function seeDirFound($dir)', 'public function seeDirFound(mixed $dir = null): mixed', $cliHelperContents);
@@ -142,7 +137,7 @@ public function generateMixedParameters(CliGuy $I, Scenario $scenario): void
$I->seeInThisFile('public function seeDirFound(mixed $dir = NULL): mixed');
}
- public function generateCorrectTypeWhenSelfTypeIsUsed(CliGuy $I, Scenario $scenario): void
+ public function generateCorrectTypeWhenSelfTypeIsUsed(CliGuy $I, Scenario $scenario)
{
if (PHP_MAJOR_VERSION < 7) {
$scenario->skip('Does not work in PHP < 7');
@@ -160,7 +155,7 @@ public function generateCorrectTypeWhenSelfTypeIsUsed(CliGuy $I, Scenario $scena
$I->seeInThisFile('public function seeDirFound(\Codeception\Module\CliHelper $dir): \Codeception\Module\CliHelper');
}
- public function generateCorrectTypeWhenParentTypeIsUsed(CliGuy $I, Scenario $scenario): void
+ public function generateCorrectTypeWhenParentTypeIsUsed(CliGuy $I, Scenario $scenario)
{
if (PHP_MAJOR_VERSION < 7) {
$scenario->skip('Does not work in PHP < 7');
@@ -178,12 +173,8 @@ public function generateCorrectTypeWhenParentTypeIsUsed(CliGuy $I, Scenario $sce
$I->seeInThisFile('public function seeDirFound(\Codeception\Module $dir): \Codeception\Module');
}
- public function noReturnForNeverType(CliGuy $I, Scenario $scenario): void
+ public function noReturnForNeverType(CliGuy $I, Scenario $scenario)
{
- if (PHP_VERSION_ID < 80100) {
- $scenario->skip('Does not work in PHP < 8.1');
- }
-
$I->wantToTest('no return keyword generated for never typehint');
$cliHelperContents = file_get_contents(codecept_root_dir('tests/support/CliHelper.php'));
@@ -201,7 +192,7 @@ public function noReturnForNeverType(CliGuy $I, Scenario $scenario): void
$I->dontSeeInThisFile('return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion(\'seeDirFound\', func_get_args()));');
}
- public function generateAttributeForMethodAttributeWithNoParametersAndNoBrackets(CliGuy $I, Scenario $scenario): void
+ public function generateAttributeForMethodAttributeWithNoParametersAndNoBrackets(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('attribute generation for method attribute with no parameters and no brackets');
@@ -219,7 +210,7 @@ public function generateAttributeForMethodAttributeWithNoParametersAndNoBrackets
$I->seeInThisFile("*/\n #[\Codeception\Attribute\Examples()]\n public function canSeeDirFound(\$dir) {");
}
- public function generateAttributeForMethodAttributeWithNoParametersAndEmptyBrackets(CliGuy $I, Scenario $scenario): void
+ public function generateAttributeForMethodAttributeWithNoParametersAndEmptyBrackets(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('attribute generation for method attribute with no parameters and empty brackets');
@@ -237,7 +228,7 @@ public function generateAttributeForMethodAttributeWithNoParametersAndEmptyBrack
$I->seeInThisFile("*/\n #[\Codeception\Attribute\Examples()]\n public function canSeeDirFound(\$dir) {");
}
- public function generateAttributeForMethodAttributeWithASingleParameter(CliGuy $I, Scenario $scenario): void
+ public function generateAttributeForMethodAttributeWithASingleParameter(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('attribute generation for method attribute with a single parameter');
@@ -255,7 +246,7 @@ public function generateAttributeForMethodAttributeWithASingleParameter(CliGuy $
$I->seeInThisFile("*/\n #[\Codeception\Attribute\Examples(\"magic\")]\n public function canSeeDirFound(\$dir) {");
}
- public function generateAttributeForMethodAttributeWithMultipleParameters(CliGuy $I, Scenario $scenario): void
+ public function generateAttributeForMethodAttributeWithMultipleParameters(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('attribute generation for method attribute with multiple parameters');
@@ -273,7 +264,7 @@ public function generateAttributeForMethodAttributeWithMultipleParameters(CliGuy
$I->seeInThisFile("*/\n #[\Codeception\Attribute\Examples(\"magic\", \"dark\")]\n public function canSeeDirFound(\$dir) {");
}
- public function generateAttributeForMethodAttributeWithMultipleParametersOverMultipleLines(CliGuy $I, Scenario $scenario): void
+ public function generateAttributeForMethodAttributeWithMultipleParametersOverMultipleLines(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('attribute generation for method attribute with multiple parameters over multiple lines');
@@ -291,7 +282,7 @@ public function generateAttributeForMethodAttributeWithMultipleParametersOverMul
$I->seeInThisFile("*/\n #[\Codeception\Attribute\Examples(\"magic\", \"dark\")]\n public function canSeeDirFound(\$dir) {");
}
- public function generateAttributesForMultipleMethodAttributeDeclarations(CliGuy $I, Scenario $scenario): void
+ public function generateAttributesForMultipleMethodAttributeDeclarations(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('attribute generation for multiple method attribute declarations');
@@ -309,7 +300,7 @@ public function generateAttributesForMultipleMethodAttributeDeclarations(CliGuy
$I->seeInThisFile("*/\n #[\Codeception\Attribute\Examples()]\n #[\Codeception\Attribute\Before(\"doX\")]\n public function canSeeDirFound(\$dir) {");
}
- public function generateAttributeForParameterAttributeWithNoParametersAndNoBrackets(CliGuy $I, Scenario $scenario): void
+ public function generateAttributeForParameterAttributeWithNoParametersAndNoBrackets(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('attribute generation for parameter attribute with no parameters and no brackets');
@@ -327,7 +318,7 @@ public function generateAttributeForParameterAttributeWithNoParametersAndNoBrack
$I->seeInThisFile("*/\n public function canSeeDirFound(#[\JetBrains\PhpStorm\Deprecated()] \$dir) {");
}
- public function generateAttributeForParameterAttributeWithMultipleParameters(CliGuy $I, Scenario $scenario): void
+ public function generateAttributeForParameterAttributeWithMultipleParameters(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('attribute generation for parameter attribute with multiple parameters');
@@ -345,7 +336,7 @@ public function generateAttributeForParameterAttributeWithMultipleParameters(Cli
$I->seeInThisFile("*/\n public function canSeeDirFound(#[\JetBrains\PhpStorm\Deprecated(\"it's old\", \"see a better method\")] \$dir) {");
}
- public function generateAttributesForParameterAttributesWithMultipleAttributeDeclarations(CliGuy $I, Scenario $scenario): void
+ public function generateAttributesForParameterAttributesWithMultipleAttributeDeclarations(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('attribute generation for parameter attribute with multiple attribute declarations');
@@ -363,7 +354,7 @@ public function generateAttributesForParameterAttributesWithMultipleAttributeDec
$I->seeInThisFile("*/\n public function canSeeDirFound(#[\JetBrains\PhpStorm\Deprecated(\"it's old\")]#[\JetBrains\PhpStorm\ExpectedValues([1, 2])] \$dir) {");
}
- public function generateAttributesForParameterAttributesWithMultipleAttributesInASingleDeclaration(CliGuy $I, Scenario $scenario): void
+ public function generateAttributesForParameterAttributesWithMultipleAttributesInASingleDeclaration(CliGuy $I, Scenario $scenario)
{
$I->wantToTest('attribute generation for parameter attribute with multiple attributes in a single declaration');
diff --git a/tests/cli/DryRunCest.php b/tests/cli/DryRunCest.php
index a7d6294aae..1e700b33cb 100644
--- a/tests/cli/DryRunCest.php
+++ b/tests/cli/DryRunCest.php
@@ -30,11 +30,7 @@ public function runFeature(CliGuy $I)
public function runTestsWithTypedHelper(CliGuy $I)
{
- if (PHP_VERSION_ID < 80100) {
- $I->markTestSkipped('Requires PHP 8.1');
- }
-
- $I->amInPath(\codecept_data_dir('typed_helper'));
+ $I->amInPath(codecept_data_dir('typed_helper'));
$I->executeCommand('build');
$I->executeCommand('dry-run unit --no-ansi');
$I->seeInShellOutput('print comment');
diff --git a/tests/cli/IncludedCest.php b/tests/cli/IncludedCest.php
index 9af16eb9c5..0feaf51559 100644
--- a/tests/cli/IncludedCest.php
+++ b/tests/cli/IncludedCest.php
@@ -125,10 +125,11 @@ public function runIncludedWithHtmlOutput(CliGuy $I)
#[Before('moveToIncluded')]
#[Group('coverage')]
- public function runIncludedWithCoverage(CliGuy $I)
+ public function runIncludedWithCoverage(CliGuy $I): void
{
$I->executeCommand('run --coverage-xml');
$I->amInPath('_log');
+ $I->seeFileFound('coverage.serialized');
$I->seeFileFound('coverage.xml');
//these assertions shrank over the years to be compatible with many versions of php-code-coverage library
$I->seeInThisFile('BillEvans" namespace="');
@@ -136,14 +137,24 @@ public function runIncludedWithCoverage(CliGuy $I)
$I->seeInThisFile('Hobbit" namespace="');
}
+ #[Before('moveToIncluded')]
+ #[Group('coverage')]
+ public function runIncludedWithoutPhpReport(CliGuy $I): void
+ {
+ $I->executeCommand('run --coverage-text --disable-coverage-php');
+ $I->amInPath('_log');
+ $I->seeFileFound('coverage.txt');
+ $I->cantSeeFileFound('coverage.serialized');
+ }
+
#[Before('moveToIncluded')]
public function buildIncluded(CliGuy $I)
{
$I->executeCommand('build');
$I->seeInShellOutput('generated successfully');
- $I->seeInShellOutput('Jazz\\TestGuy');
- $I->seeInShellOutput('Jazz\\Pianist\\TestGuy');
- $I->seeInShellOutput('Shire\\TestGuy');
+ $I->seeInShellOutput(\Jazz\TestGuy::class);
+ $I->seeInShellOutput(\Jazz\Pianist\TestGuy::class);
+ $I->seeInShellOutput(\Shire\TestGuy::class);
}
#[Before('moveToIncluded')]
diff --git a/tests/cli/RunCest.php b/tests/cli/RunCest.php
index a52bffdf32..0448d19ac5 100755
--- a/tests/cli/RunCest.php
+++ b/tests/cli/RunCest.php
@@ -417,9 +417,6 @@ public function runTestsWithSteps(CliGuy $I)
);
}
- /**
- * @param CliGuy $I
- */
public function runTestWithFailedScenario(CliGuy $I, $scenario)
{
if (!extension_loaded('xdebug')) {
@@ -984,16 +981,10 @@ public function addTest(TestHtmlReportRegexBuilder $testBuilder): self
class TestHtmlReportRegexBuilder
{
- private string $testClass;
-
- private string $testCase;
-
private $stepsRegex;
- public function __construct(string $testClass, string $testCase)
+ public function __construct(private readonly string $testClass, private readonly string $testCase)
{
- $this->testClass = $testClass;
- $this->testCase = $testCase;
}
public function getTestClass(): string
diff --git a/tests/cli/RunSkippedCest.php b/tests/cli/RunSkippedCest.php
index e3a5f4250e..7462262ed9 100644
--- a/tests/cli/RunSkippedCest.php
+++ b/tests/cli/RunSkippedCest.php
@@ -2,7 +2,7 @@
class RunSkippedCest
{
- public function classLevelSkipAnnotationWithMessage(CliGuy $I): void
+ public function classLevelSkipAnnotationWithMessage(CliGuy $I)
{
$I->amInPath('tests/data/skip');
$I->executeCommand('run -v --no-ansi unit ClassLevelSkipAnnotationWithMessageCest.php');
@@ -12,7 +12,7 @@ public function classLevelSkipAnnotationWithMessage(CliGuy $I): void
$I->seeInShellOutput('OK, but incomplete, skipped, or useless tests!');
}
- public function classLevelSkipAnnotationWithoutMessage(CliGuy $I): void
+ public function classLevelSkipAnnotationWithoutMessage(CliGuy $I)
{
$I->amInPath('tests/data/skip');
$I->executeCommand('run -v --no-ansi unit ClassLevelSkipAnnotationWithoutMessageCest.php');
@@ -21,7 +21,7 @@ public function classLevelSkipAnnotationWithoutMessage(CliGuy $I): void
$I->seeInShellOutput('OK, but incomplete, skipped, or useless tests!');
}
- public function classLevelSkipAttributeWithMessage(CliGuy $I): void
+ public function classLevelSkipAttributeWithMessage(CliGuy $I)
{
$I->amInPath('tests/data/skip');
$I->executeCommand('run -v --no-ansi unit ClassLevelSkipAttributeWithMessageCest.php');
@@ -31,7 +31,7 @@ public function classLevelSkipAttributeWithMessage(CliGuy $I): void
$I->seeInShellOutput('OK, but incomplete, skipped, or useless tests!');
}
- public function classLevelSkipAttributeWithoutMessage(CliGuy $I): void
+ public function classLevelSkipAttributeWithoutMessage(CliGuy $I)
{
$I->amInPath('tests/data/skip');
$I->executeCommand('run -v --no-ansi unit ClassLevelSkipAttributeWithoutMessageCest.php');
@@ -40,7 +40,7 @@ public function classLevelSkipAttributeWithoutMessage(CliGuy $I): void
$I->seeInShellOutput('OK, but incomplete, skipped, or useless tests!');
}
- public function methodLevelSkipAnnotationWithMessage(CliGuy $I): void
+ public function methodLevelSkipAnnotationWithMessage(CliGuy $I)
{
$I->amInPath('tests/data/skip');
$I->executeCommand('run -v --no-ansi unit MethodLevelSkipAnnotationWithMessageCest.php');
@@ -50,7 +50,7 @@ public function methodLevelSkipAnnotationWithMessage(CliGuy $I): void
$I->seeInShellOutput('OK, but incomplete, skipped, or useless tests!');
}
- public function methodLevelSkipAnnotationWithoutMessage(CliGuy $I): void
+ public function methodLevelSkipAnnotationWithoutMessage(CliGuy $I)
{
$I->amInPath('tests/data/skip');
$I->executeCommand('run -v --no-ansi unit MethodLevelSkipAnnotationWithoutMessageCest.php');
@@ -59,7 +59,7 @@ public function methodLevelSkipAnnotationWithoutMessage(CliGuy $I): void
$I->seeInShellOutput('OK, but incomplete, skipped, or useless tests!');
}
- public function methodLevelSkipAttributeWithMessage(CliGuy $I): void
+ public function methodLevelSkipAttributeWithMessage(CliGuy $I)
{
$I->amInPath('tests/data/skip');
$I->executeCommand('run -v --no-ansi unit MethodLevelSkipAttributeWithMessageCest.php');
@@ -69,7 +69,7 @@ public function methodLevelSkipAttributeWithMessage(CliGuy $I): void
$I->seeInShellOutput('OK, but incomplete, skipped, or useless tests!');
}
- public function methodLevelSkipAttributeWithoutMessage(CliGuy $I): void
+ public function methodLevelSkipAttributeWithoutMessage(CliGuy $I)
{
$I->amInPath('tests/data/skip');
$I->executeCommand('run -v --no-ansi unit MethodLevelSkipAttributeWithoutMessageCest.php');
diff --git a/tests/cli/RunUselessTestsCest.php b/tests/cli/RunUselessTestsCest.php
index 266e706337..9793dc575e 100644
--- a/tests/cli/RunUselessTestsCest.php
+++ b/tests/cli/RunUselessTestsCest.php
@@ -2,7 +2,7 @@
class RunUselessTestsCest
{
- public function checkOutput(CliGuy $I): void
+ public function checkOutput(CliGuy $I)
{
$I->amInPath('tests/data/useless');
$I->executeCommand('run');
@@ -82,7 +82,7 @@ public function checkOutput(CliGuy $I): void
);
}
- public function checkReports(CliGuy $I): void
+ public function checkReports(CliGuy $I)
{
$I->amInPath('tests/data/useless');
$I->executeCommand('run --report --xml --phpunit-xml --html');
diff --git a/tests/cli/WantToCest.php b/tests/cli/WantToCest.php
index d30747ac66..d587e40ffe 100644
--- a/tests/cli/WantToCest.php
+++ b/tests/cli/WantToCest.php
@@ -2,14 +2,14 @@
class WantToCest
{
- public function iWantToSetsFeatureInCeptFormat(CliGuy $I): void
+ public function iWantToSetsFeatureInCeptFormat(CliGuy $I)
{
$I->amInPath('tests/data/want_to');
$I->executeCommand('run --no-ansi unit WantToCept.php');
$I->seeInShellOutput('+ WantToCept: Check if wantTo works');
}
- public function iWantToSetsFeatureInCestFormat(CliGuy $I): void
+ public function iWantToSetsFeatureInCestFormat(CliGuy $I)
{
$I->amInPath('tests/data/want_to');
$I->executeCommand('run --no-ansi unit WantToCest.php:^IWantTo');
@@ -19,14 +19,14 @@ public function iWantToSetsFeatureInCestFormat(CliGuy $I): void
/**
* Tests https://github.com/Codeception/Codeception/issues/4123
*/
- public function testerWantDoesntSetFeatureInCestFormat(CliGuy $I): void
+ public function testerWantDoesntSetFeatureInCestFormat(CliGuy $I)
{
$I->amInPath('tests/data/want_to');
$I->executeCommand('run --no-ansi unit WantToCest.php:^TesterWantTo');
$I->seeInShellOutput('+ WantToCest: Tester want to');
}
- public function iWantToWithVariableIsIgnored(CliGuy $I): void
+ public function iWantToWithVariableIsIgnored(CliGuy $I)
{
$I->amInPath('tests/data/want_to');
$I->executeCommand('run --no-ansi unit WantToCest.php:Variable');
@@ -36,7 +36,7 @@ public function iWantToWithVariableIsIgnored(CliGuy $I): void
/**
* Tests https://github.com/Codeception/Codeception/issues/4124
*/
- public function iWantToDoesntOverrideDataproviderData(CliGuy $I): void
+ public function iWantToDoesntOverrideDataproviderData(CliGuy $I)
{
$I->amInPath('tests/data/want_to');
$I->executeCommand('run --no-ansi unit WantToCest.php:DataProviderIWantTo');
@@ -44,7 +44,7 @@ public function iWantToDoesntOverrideDataproviderData(CliGuy $I): void
$I->seeInShellOutput('+ WantToCest: Check if I->wantTo doesn\\\'t override data provider data | "bbb"');
}
- public function testerWantToDoesntOverrideDataproviderData(CliGuy $I): void
+ public function testerWantToDoesntOverrideDataproviderData(CliGuy $I)
{
$I->amInPath('tests/data/want_to');
$I->executeCommand('run --no-ansi unit WantToCest.php:DataProviderTesterWantTo');
@@ -52,7 +52,7 @@ public function testerWantToDoesntOverrideDataproviderData(CliGuy $I): void
$I->seeInShellOutput('+ WantToCest: Data provider tester want to | "bbb"');
}
- public function wantToTextIsUsedInXmlReport(CliGuy $I): void
+ public function wantToTextIsUsedInXmlReport(CliGuy $I)
{
$I->amInPath('tests/data/want_to');
$I->executeCommand('run unit --xml');
diff --git a/tests/data/included/jazz/pianist/tests/functional/TestGuy.php b/tests/data/included/jazz/pianist/tests/functional/TestGuy.php
index df9747de77..00d80e8180 100644
--- a/tests/data/included/jazz/pianist/tests/functional/TestGuy.php
+++ b/tests/data/included/jazz/pianist/tests/functional/TestGuy.php
@@ -291,7 +291,7 @@ public function deleteThisFile()
* Conditional Assertion: Test won't be stopped on fail
* @see \Codeception\Module\Filesystem::seeFileFound()
*/
- public function canSeeFileFound($filename, string $path = null)
+ public function canSeeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeFileFound', func_get_args()));
}
@@ -312,7 +312,7 @@ public function canSeeFileFound($filename, string $path = null)
* @param string|null $path
* @see \Codeception\Module\Filesystem::seeFileFound()
*/
- public function seeFileFound($filename, string $path = null)
+ public function seeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\Assertion('seeFileFound', func_get_args()));
}
@@ -328,7 +328,7 @@ public function seeFileFound($filename, string $path = null)
* Conditional Assertion: Test won't be stopped on fail
* @see \Codeception\Module\Filesystem::dontSeeFileFound()
*/
- public function cantSeeFileFound($filename, string $path = null)
+ public function cantSeeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeFileFound', func_get_args()));
}
@@ -342,7 +342,7 @@ public function cantSeeFileFound($filename, string $path = null)
* @param string|null $path
* @see \Codeception\Module\Filesystem::dontSeeFileFound()
*/
- public function dontSeeFileFound($filename, string $path = null)
+ public function dontSeeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeFileFound', func_get_args()));
}
diff --git a/tests/data/included/jazz/tests/functional/TestGuy.php b/tests/data/included/jazz/tests/functional/TestGuy.php
index 5f67138bf4..c2663c4879 100644
--- a/tests/data/included/jazz/tests/functional/TestGuy.php
+++ b/tests/data/included/jazz/tests/functional/TestGuy.php
@@ -291,7 +291,7 @@ public function deleteThisFile()
* Conditional Assertion: Test won't be stopped on fail
* @see \Codeception\Module\Filesystem::seeFileFound()
*/
- public function canSeeFileFound($filename, string $path = null)
+ public function canSeeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeFileFound', func_get_args()));
}
@@ -312,7 +312,7 @@ public function canSeeFileFound($filename, string $path = null)
* @param string|null $path
* @see \Codeception\Module\Filesystem::seeFileFound()
*/
- public function seeFileFound($filename, string $path = null)
+ public function seeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\Assertion('seeFileFound', func_get_args()));
}
@@ -328,7 +328,7 @@ public function seeFileFound($filename, string $path = null)
* Conditional Assertion: Test won't be stopped on fail
* @see \Codeception\Module\Filesystem::dontSeeFileFound()
*/
- public function cantSeeFileFound($filename, string $path = null)
+ public function cantSeeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeFileFound', func_get_args()));
}
@@ -342,7 +342,7 @@ public function cantSeeFileFound($filename, string $path = null)
* @param string|null $path
* @see \Codeception\Module\Filesystem::dontSeeFileFound()
*/
- public function dontSeeFileFound($filename, string $path = null)
+ public function dontSeeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeFileFound', func_get_args()));
}
diff --git a/tests/data/included/shire/tests/functional/TestGuy.php b/tests/data/included/shire/tests/functional/TestGuy.php
index 92bb2c9084..23458114b2 100644
--- a/tests/data/included/shire/tests/functional/TestGuy.php
+++ b/tests/data/included/shire/tests/functional/TestGuy.php
@@ -291,7 +291,7 @@ public function deleteThisFile()
* Conditional Assertion: Test won't be stopped on fail
* @see \Codeception\Module\Filesystem::seeFileFound()
*/
- public function canSeeFileFound($filename, string $path = null)
+ public function canSeeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeFileFound', func_get_args()));
}
@@ -312,7 +312,7 @@ public function canSeeFileFound($filename, string $path = null)
* @param string|null $path
* @see \Codeception\Module\Filesystem::seeFileFound()
*/
- public function seeFileFound($filename, string $path = null)
+ public function seeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\Assertion('seeFileFound', func_get_args()));
}
@@ -328,7 +328,7 @@ public function seeFileFound($filename, string $path = null)
* Conditional Assertion: Test won't be stopped on fail
* @see \Codeception\Module\Filesystem::dontSeeFileFound()
*/
- public function cantSeeFileFound($filename, string $path = null)
+ public function cantSeeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeFileFound', func_get_args()));
}
@@ -342,7 +342,7 @@ public function cantSeeFileFound($filename, string $path = null)
* @param string|null $path
* @see \Codeception\Module\Filesystem::dontSeeFileFound()
*/
- public function dontSeeFileFound($filename, string $path = null)
+ public function dontSeeFileFound($filename, ?string $path = null)
{
return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeFileFound', func_get_args()));
}
diff --git a/tests/unit.suite.yml b/tests/unit.suite.yml
index 85e49456e7..36561b2fff 100644
--- a/tests/unit.suite.yml
+++ b/tests/unit.suite.yml
@@ -1,7 +1,7 @@
# Codeception Test Suite Configuration
# suite for unit (internal) tests.
-error_level: "E_ALL | E_STRICT"
+error_level: "E_ALL"
actor: CodeGuy
bootstrap: _bootstrap.php
modules:
diff --git a/tests/unit/Codeception/ApplicationTest.php b/tests/unit/Codeception/ApplicationTest.php
index fd3263a788..6f6b0b98b3 100644
--- a/tests/unit/Codeception/ApplicationTest.php
+++ b/tests/unit/Codeception/ApplicationTest.php
@@ -12,7 +12,7 @@ public function testRegisterCustomCommand()
{
\Codeception\Configuration::append(['extensions' => [
'commands' => [
- 'Project\Command\MyCustomCommand']]]);
+ \Project\Command\MyCustomCommand::class]]]);
$application = new Application();
$application->registerCustomCommands();
diff --git a/tests/unit/Codeception/Command/BaseCommandRunner.php b/tests/unit/Codeception/Command/BaseCommandRunner.php
index 6bf27e83fb..6633792130 100644
--- a/tests/unit/Codeception/Command/BaseCommandRunner.php
+++ b/tests/unit/Codeception/Command/BaseCommandRunner.php
@@ -46,7 +46,7 @@ protected function execute(array $args = [], $isSuite = true)
protected function makeCommand($className, $saved = true, $extraMethods = [])
{
- if (!$this->config) {
+ if ($this->config === []) {
$this->config = [];
}
diff --git a/tests/unit/Codeception/Command/BuildTest.php b/tests/unit/Codeception/Command/BuildTest.php
index 3416bdf2c6..89b3b45145 100644
--- a/tests/unit/Codeception/Command/BuildTest.php
+++ b/tests/unit/Codeception/Command/BuildTest.php
@@ -4,9 +4,6 @@
class BuildTest extends BaseCommandRunner
{
- /**
- * @var array
- */
public array $log = [];
protected function _setUp()
diff --git a/tests/unit/Codeception/Command/GenerateGroupTest.php b/tests/unit/Codeception/Command/GenerateGroupTest.php
index c44a8c2f28..93ec205c8c 100644
--- a/tests/unit/Codeception/Command/GenerateGroupTest.php
+++ b/tests/unit/Codeception/Command/GenerateGroupTest.php
@@ -4,9 +4,6 @@
class GenerateGroupTest extends BaseCommandRunner
{
- /**
- * @var array
- */
public array $log = [];
protected function _setUp()
diff --git a/tests/unit/Codeception/Command/GenerateScenarioTest.php b/tests/unit/Codeception/Command/GenerateScenarioTest.php
index 4078f352c0..b3f81c1eb0 100644
--- a/tests/unit/Codeception/Command/GenerateScenarioTest.php
+++ b/tests/unit/Codeception/Command/GenerateScenarioTest.php
@@ -7,19 +7,10 @@
class GenerateScenarioTest extends BaseCommandRunner
{
- /**
- * @var array
- */
public array $modules = [];
- /**
- * @var array
- */
public array $actions = [];
- /**
- * @var ModuleContainer
- */
protected ModuleContainer $moduleContainer;
protected function _setUp()
diff --git a/tests/unit/Codeception/Command/GenerateStepObjectTest.php b/tests/unit/Codeception/Command/GenerateStepObjectTest.php
index 684841cded..cd98a5a91f 100644
--- a/tests/unit/Codeception/Command/GenerateStepObjectTest.php
+++ b/tests/unit/Codeception/Command/GenerateStepObjectTest.php
@@ -4,9 +4,6 @@
class GenerateStepObjectTest extends BaseCommandRunner
{
- /**
- * @var array
- */
public array $log = [];
protected function _setUp()
diff --git a/tests/unit/Codeception/Command/GenerateSuiteTest.php b/tests/unit/Codeception/Command/GenerateSuiteTest.php
index e241285a09..5e0f098a6f 100644
--- a/tests/unit/Codeception/Command/GenerateSuiteTest.php
+++ b/tests/unit/Codeception/Command/GenerateSuiteTest.php
@@ -4,9 +4,6 @@
class GenerateSuiteTest extends BaseCommandRunner
{
- /**
- * @var array
- */
public array $log = [];
/**
diff --git a/tests/unit/Codeception/Command/GenerateTestTest.php b/tests/unit/Codeception/Command/GenerateTestTest.php
index fb3dc5586c..48a667bd1e 100644
--- a/tests/unit/Codeception/Command/GenerateTestTest.php
+++ b/tests/unit/Codeception/Command/GenerateTestTest.php
@@ -52,7 +52,7 @@ public function testGenerateWithSupportNamespaced()
$this->config['namespace'] = 'MiddleEarth';
$this->config['support_namespace'] = 'Gondor';
$this->execute(['suite' => 'shire', 'class' => 'HallUnderTheHill']);
- $this->assertEquals($this->filename, 'tests/shire/HallUnderTheHillTest.php');
+ $this->assertSame($this->filename, 'tests/shire/HallUnderTheHillTest.php');
$this->assertStringContainsString('namespace MiddleEarth\Unit;', $this->content);
$this->assertStringContainsString('use MiddleEarth\\Gondor\\HobbitGuy;', $this->content);
$this->assertIsValidPhp($this->content);
diff --git a/tests/unit/Codeception/Coverage/FilterTest.php b/tests/unit/Codeception/Coverage/FilterTest.php
index 7f5031d182..3af8514bd1 100644
--- a/tests/unit/Codeception/Coverage/FilterTest.php
+++ b/tests/unit/Codeception/Coverage/FilterTest.php
@@ -39,13 +39,12 @@ public function testWhitelistFilterApplied()
];
$this->filter->whiteList($config);
$fileFilter = $this->filter->getFilter();
- $filterMethod = $this->getFilterMethod();
- $this->assertFalse($fileFilter->$filterMethod(codecept_root_dir('tests/unit/C3Test.php')));
- $this->assertFalse($fileFilter->$filterMethod(codecept_root_dir('src/Codeception/Codecept.php')));
- $this->assertTrue($fileFilter->$filterMethod(codecept_root_dir('vendor/guzzlehttp/guzzle/src/Client.php')));
- $this->assertTrue($fileFilter->$filterMethod(codecept_root_dir('tests/support/CodeGuy.php')));
+ $this->assertFalse($fileFilter->isExcluded(codecept_root_dir('tests/unit/C3Test.php')));
+ $this->assertFalse($fileFilter->isExcluded(codecept_root_dir('src/Codeception/Codecept.php')));
+ $this->assertTrue($fileFilter->isExcluded(codecept_root_dir('vendor/guzzlehttp/guzzle/src/Client.php')));
+ $this->assertTrue($fileFilter->isExcluded(codecept_root_dir('tests/support/CodeGuy.php')));
$this->assertTrue(
- $fileFilter->$filterMethod(
+ $fileFilter->isExcluded(
codecept_root_dir('tests/unit.suite.yml')
),
'tests/unit.suite.yml appears in file list'
@@ -60,9 +59,8 @@ public function testShortcutFilter()
]];
$this->filter->whiteList($config);
$fileFilter = $this->filter->getFilter();
- $filterMethod = $this->getFilterMethod();
- $this->assertFalse($fileFilter->$filterMethod(codecept_root_dir('tests/unit/C3Test.php')));
- $this->assertTrue($fileFilter->$filterMethod(codecept_root_dir('tests/support/CodeGuy.php')));
+ $this->assertFalse($fileFilter->isExcluded(codecept_root_dir('tests/unit/C3Test.php')));
+ $this->assertTrue($fileFilter->isExcluded(codecept_root_dir('tests/support/CodeGuy.php')));
}
public function testWhitelistIncludeFilterApplied()
@@ -80,27 +78,15 @@ public function testWhitelistIncludeFilterApplied()
];
$this->filter->whiteList($config);
$fileFilter = $this->filter->getFilter();
- $filterMethod = $this->getFilterMethod();
- $this->assertFalse($fileFilter->$filterMethod(codecept_root_dir('tests/unit/C3Test.php')));
- $this->assertFalse($fileFilter->$filterMethod(codecept_root_dir('src/Codeception/Codecept.php')));
- $this->assertFalse($fileFilter->$filterMethod(codecept_root_dir('tests/support/CodeGuy.php')));
- $this->assertTrue($fileFilter->$filterMethod(codecept_root_dir('vendor/guzzlehttp/guzzle/src/Client.php')));
+ $this->assertFalse($fileFilter->isExcluded(codecept_root_dir('tests/unit/C3Test.php')));
+ $this->assertFalse($fileFilter->isExcluded(codecept_root_dir('src/Codeception/Codecept.php')));
+ $this->assertFalse($fileFilter->isExcluded(codecept_root_dir('tests/support/CodeGuy.php')));
+ $this->assertTrue($fileFilter->isExcluded(codecept_root_dir('vendor/guzzlehttp/guzzle/src/Client.php')));
$this->assertTrue(
- $fileFilter->$filterMethod(
+ $fileFilter->isExcluded(
codecept_root_dir('tests/unit.suite.yml')
),
'tests/unit.suite.yml appears in file list'
);
}
-
- private function getFilterMethod(): string
- {
- $filterMethod = 'isFiltered';
- if (method_exists($this->filter->getFilter(), 'isExcluded')) {
- //php-code-coverage 9+
- $filterMethod = 'isExcluded';
- }
-
- return $filterMethod;
- }
}
diff --git a/tests/unit/Codeception/Lib/Console/DiffFactoryTest.php b/tests/unit/Codeception/Lib/Console/DiffFactoryTest.php
index 445f033929..2d26c621b2 100644
--- a/tests/unit/Codeception/Lib/Console/DiffFactoryTest.php
+++ b/tests/unit/Codeception/Lib/Console/DiffFactoryTest.php
@@ -11,9 +11,6 @@
**/
class DiffFactoryTest extends \Codeception\Test\Unit
{
- /**
- * @var DiffFactory
- */
protected DiffFactory $diffFactory;
protected function _setUp()
diff --git a/tests/unit/Codeception/Lib/DiTest.php b/tests/unit/Codeception/Lib/DiTest.php
index 0ad1722a64..7084e2f693 100644
--- a/tests/unit/Codeception/Lib/DiTest.php
+++ b/tests/unit/Codeception/Lib/DiTest.php
@@ -8,9 +8,6 @@
class DiTest extends \Codeception\Test\Unit
{
- /**
- * @var Di
- */
protected Di $di;
protected function _setUp()
@@ -31,13 +28,13 @@ public function testFailDependenciesCyclic()
$this->injectionShouldFail(
'Failed to resolve cyclic dependencies for class \'FailDependenciesCyclic\IncorrectDependenciesClass\''
);
- $this->di->instantiate('FailDependenciesCyclic\IncorrectDependenciesClass');
+ $this->di->instantiate(\FailDependenciesCyclic\IncorrectDependenciesClass::class);
}
public function testFailDependenciesInChain()
{
$this->injectionShouldFail('Failed to resolve dependency \'FailDependenciesInChain\AnotherClass\'');
- $this->di->instantiate('FailDependenciesInChain\IncorrectDependenciesClass');
+ $this->di->instantiate(\FailDependenciesInChain\IncorrectDependenciesClass::class);
}
public function testFailDependenciesNonExistent()
@@ -45,12 +42,12 @@ public function testFailDependenciesNonExistent()
$expectedExceptionMessage = 'Class "FailDependenciesNonExistent\NonExistentClass" does not exist';
$this->injectionShouldFail($expectedExceptionMessage);
- $this->di->instantiate('FailDependenciesNonExistent\IncorrectDependenciesClass');
+ $this->di->instantiate(\FailDependenciesNonExistent\IncorrectDependenciesClass::class);
}
public function testFailDependenciesPrimitiveParam()
{
$this->injectionShouldFail("Parameter 'required' must have default value");
- $this->di->instantiate('FailDependenciesPrimitiveParam\IncorrectDependenciesClass');
+ $this->di->instantiate(\FailDependenciesPrimitiveParam\IncorrectDependenciesClass::class);
}
}
diff --git a/tests/unit/Codeception/Lib/ModuleContainerTest.php b/tests/unit/Codeception/Lib/ModuleContainerTest.php
index 22f79abbaa..67954398b0 100644
--- a/tests/unit/Codeception/Lib/ModuleContainerTest.php
+++ b/tests/unit/Codeception/Lib/ModuleContainerTest.php
@@ -35,14 +35,14 @@ protected function _tearDown()
public function testCreateModule()
{
$module = $this->moduleContainer->create('EmulateModuleHelper');
- $this->assertInstanceOf('Codeception\Module\EmulateModuleHelper', $module);
+ $this->assertInstanceOf(\Codeception\Module\EmulateModuleHelper::class, $module);
- $module = $this->moduleContainer->create('Codeception\Module\EmulateModuleHelper');
- $this->assertInstanceOf('Codeception\Module\EmulateModuleHelper', $module);
+ $module = $this->moduleContainer->create(\Codeception\Module\EmulateModuleHelper::class);
+ $this->assertInstanceOf(\Codeception\Module\EmulateModuleHelper::class, $module);
$this->assertTrue($this->moduleContainer->hasModule('EmulateModuleHelper'));
$this->assertInstanceOf(
- 'Codeception\Module\EmulateModuleHelper',
+ \Codeception\Module\EmulateModuleHelper::class,
$this->moduleContainer->getModule('EmulateModuleHelper')
);
}
@@ -104,7 +104,7 @@ public function testActionsExplicitlySetForNotInheritedModule()
public function testCreateModuleWithoutRequiredFields()
{
$this->expectException(\Codeception\Exception\ModuleConfigException::class);
- $this->moduleContainer->create('Codeception\Lib\StubModule');
+ $this->moduleContainer->create(\Codeception\Lib\StubModule::class);
}
#[Group('core')]
@@ -113,7 +113,7 @@ public function testCreateModuleWithCorrectConfig()
$config = [
'modules' => [
'config' => [
- 'Codeception\Lib\StubModule' => [
+ \Codeception\Lib\StubModule::class => [
'firstField' => 'firstValue',
'secondField' => 'secondValue',
]
@@ -122,7 +122,7 @@ public function testCreateModuleWithCorrectConfig()
];
$this->moduleContainer = new ModuleContainer(Stub::make(\Codeception\Lib\Di::class), $config);
- $module = $this->moduleContainer->create('Codeception\Lib\StubModule');
+ $module = $this->moduleContainer->create(\Codeception\Lib\StubModule::class);
$this->assertSame('firstValue', $module->_getFirstField());
$this->assertSame('secondValue', $module->_getSecondField());
@@ -134,7 +134,7 @@ public function testReconfigureModule()
$config = [
'modules' => [
'config' => [
- 'Codeception\Lib\StubModule' => [
+ \Codeception\Lib\StubModule::class => [
'firstField' => 'firstValue',
'secondField' => 'secondValue',
]
@@ -142,7 +142,7 @@ public function testReconfigureModule()
]
];
$this->moduleContainer = new ModuleContainer(Stub::make(\Codeception\Lib\Di::class), $config);
- $module = $this->moduleContainer->create('Codeception\Lib\StubModule');
+ $module = $this->moduleContainer->create(\Codeception\Lib\StubModule::class);
$module->_reconfigure(['firstField' => '1st', 'secondField' => '2nd']);
$this->assertSame('1st', $module->_getFirstField());
$this->assertSame('2nd', $module->_getSecondField());
@@ -154,7 +154,7 @@ public function testReconfigureModule()
public function testConflictsByModuleName()
{
$this->expectException(\Codeception\Exception\ModuleConflictException::class);
- $this->moduleContainer->create('Codeception\Lib\ConflictedModule');
+ $this->moduleContainer->create(\Codeception\Lib\ConflictedModule::class);
$this->moduleContainer->create('Cli');
$this->moduleContainer->validateConflicts();
}
@@ -163,7 +163,7 @@ public function testConflictsByModuleName()
public function testConflictsByClass()
{
$this->expectException(\Codeception\Exception\ModuleConflictException::class);
- $this->moduleContainer->create('Codeception\Lib\ConflictedModule2');
+ $this->moduleContainer->create(\Codeception\Lib\ConflictedModule2::class);
$this->moduleContainer->create('Cli');
$this->moduleContainer->validateConflicts();
}
@@ -171,7 +171,7 @@ public function testConflictsByClass()
public function testModuleDependenciesFail()
{
$this->expectException(\Codeception\Exception\ModuleRequireException::class);
- $this->moduleContainer->create('Codeception\Lib\DependencyModule');
+ $this->moduleContainer->create(\Codeception\Lib\DependencyModule::class);
}
public function testModuleDependencies()
@@ -192,16 +192,16 @@ public function testModuleDependencies()
public function testModuleParts1()
{
$config = ['modules' => [
- 'enabled' => ['\Codeception\Lib\PartedModule'],
+ 'enabled' => [\Codeception\Lib\PartedModule::class],
'config' => [
- '\Codeception\Lib\PartedModule' => [
+ \Codeception\Lib\PartedModule::class => [
'part' => 'one'
]
]
]
];
$this->moduleContainer = new ModuleContainer(Stub::make(\Codeception\Lib\Di::class), $config);
- $this->moduleContainer->create('\Codeception\Lib\PartedModule');
+ $this->moduleContainer->create(\Codeception\Lib\PartedModule::class);
$actions = $this->moduleContainer->getActions();
$this->assertArrayHasKey('partOne', $actions);
@@ -211,15 +211,15 @@ public function testModuleParts1()
public function testModuleParts2()
{
$config = ['modules' => [
- 'enabled' => ['\Codeception\Lib\PartedModule'],
- 'config' => ['\Codeception\Lib\PartedModule' => [
+ 'enabled' => [\Codeception\Lib\PartedModule::class],
+ 'config' => [\Codeception\Lib\PartedModule::class => [
'part' => ['Two']
]
]
]
];
$this->moduleContainer = new ModuleContainer(Stub::make(\Codeception\Lib\Di::class), $config);
- $this->moduleContainer->create('\Codeception\Lib\PartedModule');
+ $this->moduleContainer->create(\Codeception\Lib\PartedModule::class);
$actions = $this->moduleContainer->getActions();
$this->assertArrayHasKey('partTwo', $actions);
@@ -232,7 +232,7 @@ public function testShortConfigParts()
'modules' => [
'enabled' => [
[
- '\Codeception\Lib\PartedModule' => [
+ \Codeception\Lib\PartedModule::class => [
'part' => 'one'
],
],
@@ -240,7 +240,7 @@ public function testShortConfigParts()
],
];
$this->moduleContainer = new ModuleContainer(Stub::make(\Codeception\Lib\Di::class), $config);
- $this->moduleContainer->create('\Codeception\Lib\PartedModule');
+ $this->moduleContainer->create(\Codeception\Lib\PartedModule::class);
$actions = $this->moduleContainer->getActions();
$this->assertArrayHasKey('partOne', $actions);
@@ -252,7 +252,7 @@ public function testShortConfigFormat()
$config = [
'modules' =>
['enabled' => [
- ['Codeception\Lib\StubModule' => [
+ [\Codeception\Lib\StubModule::class => [
'firstField' => 'firstValue',
'secondField' => 'secondValue',
]
@@ -262,7 +262,7 @@ public function testShortConfigFormat()
];
$this->moduleContainer = new ModuleContainer(Stub::make(\Codeception\Lib\Di::class), $config);
- $module = $this->moduleContainer->create('Codeception\Lib\StubModule');
+ $module = $this->moduleContainer->create(\Codeception\Lib\StubModule::class);
$this->assertSame('firstValue', $module->_getFirstField());
$this->assertSame('secondValue', $module->_getSecondField());
@@ -283,23 +283,23 @@ public function testShortConfigDependencies()
public function testInjectModuleIntoHelper()
{
$config = ['modules' => [
- 'enabled' => ['Codeception\Lib\HelperModule'],
+ 'enabled' => [\Codeception\Lib\HelperModule::class],
]];
$this->moduleContainer = new ModuleContainer(Stub::make(\Codeception\Lib\Di::class), $config);
- $this->moduleContainer->create('Codeception\Lib\HelperModule');
- $this->assertTrue($this->moduleContainer->hasModule('Codeception\Lib\HelperModule'));
+ $this->moduleContainer->create(\Codeception\Lib\HelperModule::class);
+ $this->assertTrue($this->moduleContainer->hasModule(\Codeception\Lib\HelperModule::class));
}
public function testSuggestMissingModule()
{
- $correctModule = 'Codeception\Lib\HelperModule';
+ $correctModule = \Codeception\Lib\HelperModule::class;
$wrongModule = 'Codeception\Lib\Helpamodule';
$config = ['modules' => [
'enabled' => [$correctModule],
]];
$this->moduleContainer = new ModuleContainer(Stub::make(\Codeception\Lib\Di::class), $config);
- $this->moduleContainer->create('Codeception\Lib\HelperModule');
+ $this->moduleContainer->create(\Codeception\Lib\HelperModule::class);
$message = "Codeception\Lib\ModuleContainer: Module {$wrongModule} couldn't be connected (did you mean '{$correctModule}'?)";
$this->expectException(\Codeception\Exception\ModuleException::class);
@@ -366,7 +366,7 @@ class DependencyModule extends Module implements DependsOnModule
{
public function _depends(): array
{
- return ['Codeception\Lib\ConflictedModule' => 'Error message'];
+ return [\Codeception\Lib\ConflictedModule::class => 'Error message'];
}
public function _inject()
diff --git a/tests/unit/Codeception/Lib/ParserTest.php b/tests/unit/Codeception/Lib/ParserTest.php
index 4e86a9a6f5..242a6de998 100644
--- a/tests/unit/Codeception/Lib/ParserTest.php
+++ b/tests/unit/Codeception/Lib/ParserTest.php
@@ -167,13 +167,13 @@ public function testClassesFromFile()
public function testNamedParameterNamedClassIsNotClass()
{
$classes = Parser::getClassesFromFile(codecept_data_dir('namedParameter.php'));
- $this->assertEquals([], $classes);
+ $this->assertSame([], $classes);
}
#[Group('core')]
public function testParseTestContainingAnnonymousClassWithAttribute()
{
$classes = Parser::getClassesFromFile(codecept_data_dir('AnonymousClassWithAttributeCest.php'));
- $this->assertEquals(['Tests\Unit\AnonymousClassWithAttributeCest'], $classes);
+ $this->assertSame([\Tests\Unit\AnonymousClassWithAttributeCest::class], $classes);
}
}
diff --git a/tests/unit/Codeception/ScenarioTest.php b/tests/unit/Codeception/ScenarioTest.php
index d6ac401816..c9324bcfe1 100644
--- a/tests/unit/Codeception/ScenarioTest.php
+++ b/tests/unit/Codeception/ScenarioTest.php
@@ -6,7 +6,7 @@ class ScenarioTest extends \PHPUnit\Framework\TestCase
{
public function testGetHtml()
{
- $step1 = $this->getMockBuilder('\Codeception\Step')
+ $step1 = $this->getMockBuilder(\Codeception\Step::class)
->setConstructorArgs([
'Do some testing',
[
@@ -16,7 +16,7 @@ public function testGetHtml()
])
->onlyMethods([])
->getMock();
- $step2 = $this->getMockBuilder('\Codeception\Step')
+ $step2 = $this->getMockBuilder(\Codeception\Step::class)
->setConstructorArgs([
'Do even more testing without args',
[]
diff --git a/tests/unit/Codeception/Step/RetryTest.php b/tests/unit/Codeception/Step/RetryTest.php
index 276a3d5379..b3dbf30cc1 100644
--- a/tests/unit/Codeception/Step/RetryTest.php
+++ b/tests/unit/Codeception/Step/RetryTest.php
@@ -9,9 +9,6 @@
class RetryTest extends \PHPUnit\Framework\TestCase
{
- /**
- * @var bool
- */
protected bool $shouldFail = true;
public function testRetryStepShouldNotFailStep()
diff --git a/tests/unit/Codeception/Step/TryToTest.php b/tests/unit/Codeception/Step/TryToTest.php
index 1aff183747..66be6b8d12 100644
--- a/tests/unit/Codeception/Step/TryToTest.php
+++ b/tests/unit/Codeception/Step/TryToTest.php
@@ -9,9 +9,6 @@
class TryToTest extends \PHPUnit\Framework\TestCase
{
- /**
- * @var bool
- */
protected bool $shouldFail = true;
public function testTryToShouldReturnSuccess()
@@ -39,7 +36,7 @@ public function testTryStepShouldNotFailStep()
$this->assertFalse($tryTo->hasFailed(), 'successful retry still marks test as failed');
}
- public function _executeFailedCode()
+ public function _executeFailedCode(): never
{
throw new \Exception('Error');
}
diff --git a/tests/unit/Codeception/StepTest.php b/tests/unit/Codeception/StepTest.php
index 76fdb5914f..904cdb8f24 100644
--- a/tests/unit/Codeception/StepTest.php
+++ b/tests/unit/Codeception/StepTest.php
@@ -13,7 +13,7 @@ class StepTest extends TestCase
{
protected function getStep(array $args): Step
{
- return $this->getMockBuilder('\Codeception\Step')
+ return $this->getMockBuilder(\Codeception\Step::class)
->setConstructorArgs($args)
->onlyMethods([])
->getMock();
@@ -141,7 +141,7 @@ public function testFormattedOutput()
$this->assertSame('argument "some formatted output"', $output);
}
- public function testConstraintOutput(): void
+ public function testConstraintOutput()
{
$argument = Stub::makeEmpty(Constraint::class);
$argument->method('toString')->willReturn('is a constraint');
diff --git a/tests/unit/Codeception/Test/DataProviderTest.php b/tests/unit/Codeception/Test/DataProviderTest.php
index a7b289e24b..661df89b92 100644
--- a/tests/unit/Codeception/Test/DataProviderTest.php
+++ b/tests/unit/Codeception/Test/DataProviderTest.php
@@ -11,38 +11,38 @@ class DataProviderTest extends Unit
{
protected \CodeGuy $tester;
- public function testParsesAnnotationContainingMethodNameOnly(): void
+ public function testParsesAnnotationContainingMethodNameOnly()
{
$result = DataProvider::parseDataProviderAnnotation('getData', 'UnitTest', 'testMethod');
- self::assertSame(['UnitTest', 'getData'], $result);
+ $this->assertSame(['UnitTest', 'getData'], $result);
}
- public function testParsesAnnotationContainingClassNameAndMethodName(): void
+ public function testParsesAnnotationContainingClassNameAndMethodName()
{
$result = DataProvider::parseDataProviderAnnotation('AnotherClass::getData', 'UnitTest', 'testMethod');
- self::assertSame(['AnotherClass', 'getData'], $result);
+ $this->assertSame(['AnotherClass', 'getData'], $result);
}
- public function testParsesAnnotationContainingNamespacedClassNameAndMethodName(): void
+ public function testParsesAnnotationContainingNamespacedClassNameAndMethodName()
{
$result = DataProvider::parseDataProviderAnnotation('Namespace\AnotherClass::getData', 'UnitTest', 'testMethod');
- self::assertSame(['Namespace\AnotherClass', 'getData'], $result);
+ $this->assertSame(['Namespace\AnotherClass', 'getData'], $result);
}
- public function testParseAnnotationThrowsExceptionIfAnnotationContainsTooManyDoubleColons(): void
+ public function testParseAnnotationThrowsExceptionIfAnnotationContainsTooManyDoubleColons()
{
$this->expectException(InvalidTestException::class);
$this->expectExceptionMessage('Data provider "AnotherClass::bug::getData" specified for UnitTest::testMethod is invalid');
- $result = DataProvider::parseDataProviderAnnotation('AnotherClass::bug::getData', 'UnitTest', 'testMethod');
+ DataProvider::parseDataProviderAnnotation('AnotherClass::bug::getData', 'UnitTest', 'testMethod');
}
- public function testReturnsNullIfMethodHasNoDataProvider(): void
+ public function testReturnsNullIfMethodHasNoDataProvider()
{
$method = new ReflectionMethod($this, __FUNCTION__);
- self::assertNull(DataProvider::getDataForMethod($method));
+ $this->assertNull(DataProvider::getDataForMethod($method));
}
- public function testExecutesPublicStaticDataProviderInTheSameClass(): void
+ public function testExecutesPublicStaticDataProviderInTheSameClass()
{
require_once codecept_data_dir('data_provider/PublicStaticDataProviderTest.php');
$method = new ReflectionMethod(PublicStaticDataProviderTest::class, 'testDataProvider');
@@ -54,10 +54,10 @@ public function testExecutesPublicStaticDataProviderInTheSameClass(): void
'not baz' => ['baz', 5],
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
- public function testExecutesPublicDataProviderInTheSameClass(): void
+ public function testExecutesPublicDataProviderInTheSameClass()
{
require_once codecept_data_dir('data_provider/PublicDataProviderTest.php');
$method = new ReflectionMethod(PublicDataProviderTest::class, 'testDataProvider');
@@ -69,10 +69,10 @@ public function testExecutesPublicDataProviderInTheSameClass(): void
'not baz' => ['baz', 7],
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
- public function testExecutesPrivateDataProviderInTheSameClass(): void
+ public function testExecutesPrivateDataProviderInTheSameClass()
{
require_once codecept_data_dir('data_provider/PrivateDataProviderTest.php');
$method = new ReflectionMethod(PrivateDataProviderTest::class, 'testDataProvider');
@@ -84,10 +84,10 @@ public function testExecutesPrivateDataProviderInTheSameClass(): void
['baz', 7],
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
- public function testExecutesDataProviderSpecifiedUsingAttribute(): void
+ public function testExecutesDataProviderSpecifiedUsingAttribute()
{
require_once codecept_data_dir('data_provider/AttributeDataProviderTest.php');
$method = new ReflectionMethod(AttributeDataProviderTest::class, 'testDataProvider');
@@ -99,12 +99,12 @@ public function testExecutesDataProviderSpecifiedUsingAttribute(): void
'not baz' => ['baz', 7],
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
- public function testExecutesPrivateDataProviderInAnotherClass(): void
+ public function testExecutesPrivateDataProviderInAnotherClass()
{
require_once codecept_data_dir('data_provider/DataProviderInAnotherClassTest.php');
$method = new ReflectionMethod(DataProviderInAnotherClassTest::class, 'testDataProvider');
@@ -116,10 +116,10 @@ public function testExecutesPrivateDataProviderInAnotherClass(): void
'not baz' => ['baz', 7],
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
- public function testExecutesMultipleDataProviders(): void
+ public function testExecutesMultipleDataProviders()
{
require_once codecept_data_dir('data_provider/MultipleDataProviderTest.php');
$method = new ReflectionMethod(MultipleDataProviderTest::class, 'testDataProvider');
@@ -133,10 +133,10 @@ public function testExecutesMultipleDataProviders(): void
'def' => ['def', 9],
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
- public function testSupportsExampleAnnotations(): void
+ public function testSupportsExampleAnnotations()
{
require_once codecept_data_dir('data_provider/ExampleAnnotationTest.php');
$method = new ReflectionMethod(ExampleAnnotationTest::class, 'testExample');
@@ -147,10 +147,10 @@ public function testSupportsExampleAnnotations(): void
['bar', 6],
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
- public function testSupportsExamplesAttribute(): void
+ public function testSupportsExamplesAttribute()
{
require_once codecept_data_dir('data_provider/ExamplesAttributeTest.php');
$method = new ReflectionMethod(ExamplesAttributeTest::class, 'testExample');
@@ -161,10 +161,10 @@ public function testSupportsExamplesAttribute(): void
['bar', 8],
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
- public function testCombinesExampleAndDataProviderAnnotations(): void
+ public function testCombinesExampleAndDataProviderAnnotations()
{
require_once codecept_data_dir('data_provider/CombinedAnnotationDataProviderTest.php');
$method = new ReflectionMethod(CombinedAnnotationDataProviderTest::class, 'testCombined');
@@ -177,10 +177,10 @@ public function testCombinesExampleAndDataProviderAnnotations(): void
'def' => ['def', 9],
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
- public function testCombinesExampleAndDataProviderAttributes(): void
+ public function testCombinesExampleAndDataProviderAttributes()
{
require_once codecept_data_dir('data_provider/CombinedAttributeDataProviderTest.php');
$method = new ReflectionMethod(CombinedAttributeDataProviderTest::class, 'testCombined');
@@ -194,10 +194,10 @@ public function testCombinesExampleAndDataProviderAttributes(): void
'not baz' => ['baz', 7],
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
- public function testExecutesPublicDataProviderInAnotherAbstractClass(): void
+ public function testExecutesPublicDataProviderInAnotherAbstractClass()
{
require_once codecept_data_dir('data_provider/AbstractDataProviderTest.php');
$method = new ReflectionMethod(AbstractDataProviderTest::class, 'testDataProvider');
@@ -207,10 +207,10 @@ public function testExecutesPublicDataProviderInAnotherAbstractClass(): void
'foo' => ['foo'],
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
- public function testDataProviderReceivesActor(): void
+ public function testDataProviderReceivesActor()
{
require_once codecept_data_dir('data_provider/DataProviderReceivesActorTest.php');
$method = new ReflectionMethod(DataProviderReceivesActorTest::class, 'testDataProvider');
@@ -220,6 +220,6 @@ public function testDataProviderReceivesActor(): void
'codeGuyMethod() exists'
];
- self::assertSame($expectedResult, $result);
+ $this->assertSame($expectedResult, $result);
}
}
diff --git a/tests/unit/Codeception/Util/MockAutoload.php b/tests/unit/Codeception/Util/MockAutoload.php
index 62416d8ce2..cbb0ad65f4 100644
--- a/tests/unit/Codeception/Util/MockAutoload.php
+++ b/tests/unit/Codeception/Util/MockAutoload.php
@@ -6,9 +6,6 @@
class MockAutoload extends Autoload
{
- /**
- * @var array
- */
protected static array $files = [];
/**
diff --git a/tests/unit/Codeception/Util/ReflectionHelperTest.php b/tests/unit/Codeception/Util/ReflectionHelperTest.php
index 47940fd93d..b293e7cdca 100644
--- a/tests/unit/Codeception/Util/ReflectionHelperTest.php
+++ b/tests/unit/Codeception/Util/ReflectionHelperTest.php
@@ -79,19 +79,19 @@ public function testGetClassFromParameter()
$this->assertSame(
\Codeception\Util\Debug::class,
- ReflectionHelper::getClassFromParameter(new ReflectionParameter([$object, 'setDebug'], 0))
+ ReflectionHelper::getClassFromParameter(new ReflectionParameter($object->setDebug(...), 0))
);
$this->assertNull(
- ReflectionHelper::getClassFromParameter(new ReflectionParameter([$object, 'setDebug'], 1))
+ ReflectionHelper::getClassFromParameter(new ReflectionParameter($object->setDebug(...), 1))
);
$this->assertNull(
- ReflectionHelper::getClassFromParameter(new ReflectionParameter([$object, 'setDebug'], 'flavor'))
+ ReflectionHelper::getClassFromParameter(new ReflectionParameter($object->setDebug(...), 'flavor'))
);
$this->assertNull(
- ReflectionHelper::getClassFromParameter(new ReflectionParameter([$object, 'setInt'], 'i'))
+ ReflectionHelper::getClassFromParameter(new ReflectionParameter($object->setInt(...), 'i'))
);
}
@@ -102,37 +102,37 @@ public function testGetDefaultValue()
$this->assertSame(
'null',
- ReflectionHelper::getDefaultValue(new ReflectionParameter([$object, 'setDebug'], 0))
+ ReflectionHelper::getDefaultValue(new ReflectionParameter($object->setDebug(...), 0))
);
$this->assertSame(
'\Codeception\Util\ReflectionTestClass::FOO',
- ReflectionHelper::getDefaultValue(new ReflectionParameter([$object, 'setDebug'], 1))
+ ReflectionHelper::getDefaultValue(new ReflectionParameter($object->setDebug(...), 1))
);
$this->assertSame(
'\Codeception\Util\ReflectionTestClass::FOO',
- ReflectionHelper::getDefaultValue(new ReflectionParameter([$object, 'setDebug'], 'flavor'))
+ ReflectionHelper::getDefaultValue(new ReflectionParameter($object->setDebug(...), 'flavor'))
);
$this->assertSame(
'\Codeception\Codecept::VERSION',
- ReflectionHelper::getDefaultValue(new ReflectionParameter([$object, 'setFlavorImportedDefault'], 'flavor'))
+ ReflectionHelper::getDefaultValue(new ReflectionParameter($object->setFlavorImportedDefault(...), 'flavor'))
);
$this->assertSame(
"''",
- ReflectionHelper::getDefaultValue(new ReflectionParameter([$object, 'setValue'], 0))
+ ReflectionHelper::getDefaultValue(new ReflectionParameter($object->setValue(...), 0))
);
$this->assertSame(
'0',
- ReflectionHelper::getDefaultValue(new ReflectionParameter([$object, 'setInt'], 0))
+ ReflectionHelper::getDefaultValue(new ReflectionParameter($object->setInt(...), 0))
);
$this->assertSame(
'null',
- ReflectionHelper::getDefaultValue(new ReflectionParameter([$object, 'setMixed'], 0))
+ ReflectionHelper::getDefaultValue(new ReflectionParameter($object->setMixed(...), 0))
);
}