From a3d69ba38282b7a0a4cf53d7de44fceb909704cd Mon Sep 17 00:00:00 2001 From: KJunker Date: Tue, 13 Jul 2021 22:35:51 +0200 Subject: [PATCH 01/12] Create php.yml --- .github/workflows/php.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/php.yml diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..ee68550 --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,36 @@ +name: PHP Composer + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v2 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" + # Docs: https://getcomposer.org/doc/articles/scripts.md + + - name: Run test suite + run: composer -v exec phpunit -- tests --bootstrap tests/bootstrap.php --exclude-group example --stderr -v --debug From 447243ae51ab3157000d4a1f0fdb19a9d7df72d0 Mon Sep 17 00:00:00 2001 From: KJunker Date: Fri, 6 Aug 2021 09:59:12 +0200 Subject: [PATCH 02/12] Bugfix/fix extension failed tests writer (#75) * Create php.yml * Add a unique suffix for failed tests report files * add a new merger to merge the created report files from the FailedTestsMergerTask into one file * updated the FailedTestSplitterTask * Fixed issue in FailedTestSplitterTask * Updated README.md for usage of FailedTests Reports * Created new abtract class for the mergers * Created new abtract class for the mergers --- README.md | 17 +- src/Extension/FailedTestsReporter.php | 21 +- src/Merger/AbstractMerger.php | 35 ++++ src/Merger/FailedTestsMergerTask.php | 122 +++++++++++ src/Merger/HtmlReportMerger.php | 8 +- src/Merger/ReportMerger.php | 5 + src/Merger/XmlReportMergerTask.php | 7 +- src/Splitter/FailedTestSplitterTask.php | 22 +- tests/Extension/FailedTestsReporterTest.php | 31 ++- tests/Merger/FailedTestsMergerTaskTest.php | 196 ++++++++++++++++++ tests/Splitter/FailedTestSplitterTaskTest.php | 6 +- 11 files changed, 427 insertions(+), 43 deletions(-) create mode 100644 src/Merger/AbstractMerger.php create mode 100644 src/Merger/FailedTestsMergerTask.php create mode 100644 tests/Merger/FailedTestsMergerTaskTest.php diff --git a/README.md b/README.md index 1e0f9b8..d466607 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,8 @@ this command need run all tests with `Codeception\Task\TimeReporter` for collect ### SplitFailedTests -Enable extension for collect failed tests if you use taskSplitFailedTests +Enable extension for collect failed tests if you use taskSplitFailedTests +The extension saves the report files into \Codeception\Configuration::outputDir() ``` extensions: @@ -89,15 +90,23 @@ extensions: - Codeception\Task\Extension\FailedTestsReporter ``` +Merge the created report files from the FailedTestsReporter into single file +```php +$this->taskMergeFailedTestsReports() + ->fromPathWithPattern(\Codeception\Configuration::outputDir(), '/failedTests_\w+\.txt$/') + ->into(\Codeception\Configuration::outputDir() . 'failedTests.txt') // absolute path with Filename + ->run(); +``` + Load the failed Tests from a reportfile into the groups: -- Default report path is: `Configuration::outputDir() . 'failedTests.txt'` ```php $this ->taskSplitFailedTests(5) - ->setReportPath('tests/_output/' . FailedTestsReporter::REPORT_NAME) - ->groupsTo('tests/_data/group_') + ->setReportPath(\Codeception\Configuration::outputDir() . 'failedTests.txt') // absoulute Path to Reportfile + ->groupsTo(\Codeception\Configuration::outputDir() . 'group_') ->run(); ``` + ### MergeXmlReports Mergex several XML reports: diff --git a/src/Extension/FailedTestsReporter.php b/src/Extension/FailedTestsReporter.php index 7044caa..af13077 100644 --- a/src/Extension/FailedTestsReporter.php +++ b/src/Extension/FailedTestsReporter.php @@ -11,7 +11,11 @@ use Codeception\Test\Descriptor; /** - * Class FailedTestsReporter - reports the failed tests to a reportfile + * Class FailedTestsReporter - reports the failed tests to a reportfile with + * a unique name for parallel execution. + * + * Pattern is '/failedTests_\w+\.\w+\.txt/' + * * Modify the codeception.yml to enable this extension: * extensions: * enabled: @@ -20,10 +24,7 @@ class FailedTestsReporter extends Extension { /** @var string */ - public const REPORT_NAME = 'failedTests.txt'; - - /** @var string $reportFile */ - private $reportFile = self::REPORT_NAME; + public const REPORT_NAME = 'failedTests'; /** @var array $failedTests */ private $failedTests = []; @@ -54,7 +55,7 @@ public function endRun(): void return; } - $file = $this->getLogDir() . $this->reportFile; + $file = $this->getLogDir() . $this->getUniqReportFile(); if (is_file($file)) { unlink($file); // remove old reportFile } @@ -72,4 +73,12 @@ public function getTestname(TestEvent $e): string return substr(str_replace($this->getRootDir(), '', $name), 1); } + + /** + * @return string + */ + public function getUniqReportFile(): string + { + return self::REPORT_NAME . '_' . uniqid('', true) . '.txt'; + } } diff --git a/src/Merger/AbstractMerger.php b/src/Merger/AbstractMerger.php new file mode 100644 index 0000000..7bd060d --- /dev/null +++ b/src/Merger/AbstractMerger.php @@ -0,0 +1,35 @@ +src = $src; + } + + /** + * @inheritDoc + */ + abstract public function from($fileName); + + /** + * @inheritDoc + */ + abstract public function into(string $fileName); + + /** + * @inheritDoc + */ + abstract public function run(); +} diff --git a/src/Merger/FailedTestsMergerTask.php b/src/Merger/FailedTestsMergerTask.php new file mode 100644 index 0000000..c360897 --- /dev/null +++ b/src/Merger/FailedTestsMergerTask.php @@ -0,0 +1,122 @@ +taskMergeFailedTestsReports() + * ->from(__DIR__ . 'tests/_data/Acme/failedTests_123.txt') + * ->from(__DIR__ . 'tests/_data/failedTests_foo.txt') + * ->from([__DIR__ . 'tests/_data/Acme/failedTests_bar.txt', __DIR__ . 'tests/_data/Acme/failedTests_baz.txt',]) + * ->fromPathWithPattern(__DIR__ . 'tests/_data/failed_1/', '/failedTests_\w+\.txt$/') + * ->fromPathWithPattern(__DIR__ . 'tests/_data/failed_2/', '/failedTests_\w+\.txt$/') + * ->into(__DIR__ . '/failedTests.txt') // absolute path with Filename + * ->run(); + * ?> + * ``` + */ +class FailedTestsMergerTask extends AbstractMerger +{ + public const DEFAULT_PATTERN = '/^failedTests_\w+\.\w+\.txt$/'; + + public $pathPatterns = []; + + /** + * @var string + */ + private $dest; + + /** @var string[] */ + protected $src = []; + + /** + * @param string[]|string $fileName + * @return FailedTestsMergerTask|void + */ + public function from($fileName): self + { + if (!(is_array($fileName) || is_string($fileName) || !empty($fileName))) { + throw new InvalidArgumentException( + 'The argument must be an array or string and could not be empty.' + ); + } + + $this->src = array_merge($this->src, (is_string($fileName) ? [$fileName] : $fileName)); + + return $this; + } + + /** + * Search all report files in path with default pattern or the given pattern + * @param string $path - The path where the report files exists + * @param string|null $pattern - The regex pattern for the files (optional) + * @return $this + */ + public function fromPathWithPattern(string $path, ?string $pattern = null): self + { + $this->pathPatterns[$path] = $pattern ?? self::DEFAULT_PATTERN; + + return $this; + } + + public function into(string $fileName): self + { + $this->dest = $fileName; + + return $this; + } + + public function run() + { + $content = []; + $files = array_merge($this->src, $this->searchFilesByPattern()); + foreach ($files as $file) { + if (!is_file($file)) { + continue; + } + $tmpContent = file_get_contents($file); + if (!$tmpContent) { + throw new RuntimeException( + 'Could not read content of reportfile: ' . $file + ); + } + $content[] = $tmpContent; + } + + if (!empty($content)) { + file_put_contents($this->dest, implode(PHP_EOL, $content)); + } + } + + /** + * Search the files by the given path and pattern + * @return array + */ + private function searchFilesByPattern(): array + { + $results = []; + foreach ($this->pathPatterns as $path => $pattern) { + $files = Finder::create() + ->files() + ->in($path) + ->name($pattern ?? self::DEFAULT_PATTERN); + foreach ($files->getIterator() as $splFileInfo) { + $results[] = $splFileInfo->getPathname(); + } + } + + return $results; + } +} diff --git a/src/Merger/HtmlReportMerger.php b/src/Merger/HtmlReportMerger.php index a5254bc..1ca2f53 100644 --- a/src/Merger/HtmlReportMerger.php +++ b/src/Merger/HtmlReportMerger.php @@ -15,8 +15,9 @@ * Class MergeHTMLReportsTask * @author Kerimov Asif */ -class HtmlReportMerger extends BaseTask implements ReportMergerTaskInterface +class HtmlReportMerger extends AbstractMerger { + /** @var string[] */ protected $src = []; protected $dst; protected $countSuccess = 0; @@ -25,11 +26,6 @@ class HtmlReportMerger extends BaseTask implements ReportMergerTaskInterface protected $countIncomplete = 0; protected $previousLibXmlUseErrors; - public function __construct($src = []) - { - $this->src = $src; - } - public function from($fileName) { if (is_array($fileName)) { diff --git a/src/Merger/ReportMerger.php b/src/Merger/ReportMerger.php index 44c9fd5..b45da16 100644 --- a/src/Merger/ReportMerger.php +++ b/src/Merger/ReportMerger.php @@ -15,4 +15,9 @@ protected function taskMergeHTMLReports($src = []) { return $this->task(HtmlReportMerger::class, $src); } + + protected function taskMergeFailedTestsReports($src = []) + { + return $this->task(FailedTestsMergerTask::class, $src); + } } diff --git a/src/Merger/XmlReportMergerTask.php b/src/Merger/XmlReportMergerTask.php index ae7caf9..6515406 100644 --- a/src/Merger/XmlReportMergerTask.php +++ b/src/Merger/XmlReportMergerTask.php @@ -11,7 +11,7 @@ use Robo\Exception\TaskException; use Robo\Task\BaseTask; -class XmlReportMergerTask extends BaseTask implements ReportMergerTaskInterface +class XmlReportMergerTask extends AbstractMerger { /** * @var array|mixed @@ -32,11 +32,6 @@ class XmlReportMergerTask extends BaseTask implements ReportMergerTaskInterface /** @var DOMElement[][] */ protected $suites = []; - public function __construct(array $src = []) - { - $this->src = $src; - } - public function sumTime(): void { $this->summarizeTime = true; diff --git a/src/Splitter/FailedTestSplitterTask.php b/src/Splitter/FailedTestSplitterTask.php index dc2cf2d..74fe796 100644 --- a/src/Splitter/FailedTestSplitterTask.php +++ b/src/Splitter/FailedTestSplitterTask.php @@ -4,8 +4,7 @@ namespace Codeception\Task\Splitter; -use Codeception\Configuration; -use Codeception\Task\Extension\FailedTestsReporter; +use InvalidArgumentException; use RuntimeException; class FailedTestSplitterTask extends TestsSplitter @@ -14,12 +13,11 @@ class FailedTestSplitterTask extends TestsSplitter private $reportPath = null; /** - * @return string - * @throws \Codeception\Exception\ConfigurationException + * @return string - the absolute path to the report file with the failed tests */ public function getReportPath(): string { - return $this->reportPath ?? (Configuration::logDir() . FailedTestsReporter::REPORT_NAME); + return $this->reportPath; } /** @@ -30,9 +28,9 @@ public function run() $this->claimCodeceptionLoaded(); $reportPath = $this->getReportPath(); - if (!@file_exists($reportPath)) { + if (!@file_exists($reportPath) || !is_file($reportPath)) { throw new RuntimeException( - 'The reportfile "failedTests.txt" did not exists.' + 'The reportfile did not exists or is not a regular file.' ); } @@ -47,16 +45,16 @@ public function run() } /** - * @param string $reportPath + * @param string $reportFilePath * @return FailedTestSplitterTask */ - public function setReportPath(string $reportPath): FailedTestSplitterTask + public function setReportPath(string $reportFilePath): FailedTestSplitterTask { - if (empty($reportPath)) { - throw new \InvalidArgumentException('The reportPath could not be empty!'); + if (empty($reportFilePath)) { + throw new InvalidArgumentException('The reportPath could not be empty!'); } - $this->reportPath = $reportPath; + $this->reportPath = $reportFilePath; return $this; } diff --git a/tests/Extension/FailedTestsReporterTest.php b/tests/Extension/FailedTestsReporterTest.php index 2daf101..c7e6571 100644 --- a/tests/Extension/FailedTestsReporterTest.php +++ b/tests/Extension/FailedTestsReporterTest.php @@ -3,9 +3,10 @@ namespace Tests\Codeception\Task\Extension; use Codeception\Event\FailEvent; -use Codeception\Event\TestEvent; use Codeception\Task\Extension\FailedTestsReporter; use PHPUnit\Framework\TestCase; +use SplFileInfo; +use Symfony\Component\Finder\Finder; /** * Class FailedTestsReporterTest @@ -67,15 +68,35 @@ static function (FailEvent $event): array { } $reporter->endRun(); - $file = TEST_PATH . '/result/failedTests.txt'; - $this->assertFileExists($file); - $content = explode(PHP_EOL, file_get_contents($file)); + $files = Finder::create() + ->followLinks() + ->files() + ->in(TEST_PATH) + ->path('result') + ->name('/^failedTests_\w+\.\w+\.txt$/'); + + $iterator = $files->getIterator(); + $this->assertCount(1, $iterator); + $iterator->rewind(); + /** @var SplFileInfo $file */ + $file = $iterator->current(); + $this->assertTrue($file->isFile()); + $content = explode(PHP_EOL, file_get_contents($file->getPathname())); $this->assertCount(8, $content); } protected function tearDown(): void { parent::tearDown(); // TODO: Change the autogenerated stub - unlink(TEST_PATH . '/result/failedTests.txt'); + $files = Finder::create() + ->followLinks() + ->files() + ->in(TEST_PATH) + ->path('result') + ->name('/^failedTests_\w+\.\w+\.txt$/'); + + foreach ($files->getIterator() as $file) { + unlink($file->getPathname()); + } } } diff --git a/tests/Merger/FailedTestsMergerTaskTest.php b/tests/Merger/FailedTestsMergerTaskTest.php new file mode 100644 index 0000000..f3d25ef --- /dev/null +++ b/tests/Merger/FailedTestsMergerTaskTest.php @@ -0,0 +1,196 @@ + '/foo_\w+\.txt/', + 'bar' => '/bar_\w+\.txt/', + 'baz' => '/baz_\w+\.txt/', + ]; + + private static $testContent = [ + 'tests/acceptance/%s/baz.php:testA', + 'tests/acceptance/%s/baz.php:testB', + 'tests/acceptance/%s/baz.php:testC', + 'tests/acceptance/%s/baz.php:testD', + 'tests/acceptance/%s/baz.php:testE', + 'tests/acceptance/%s/baz.php:testF', + 'tests/acceptance/%s/baz.php:testG', + 'tests/acceptance/%s/baz.php:testH', + ]; + + private static $testFiles = []; + + /** + * Prepare the test files and directories + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + $tmpDir = sys_get_temp_dir(); + foreach (self::$tmpDirsPattern as $dir => $pattern) { + $tempDir = $tmpDir . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR; + if (!is_dir($tempDir)) { + mkdir($tempDir); + } + $i = 1; + while ($i <= self::TEST_FILES_PER_DIR) { + $tempfile = $tempDir . $dir . '_unit' . $i++ . '.txt'; + file_put_contents( + $tempfile, + implode( + PHP_EOL, + array_map( + static function (string $filename) use ($dir): string { + return sprintf($filename, $dir); + }, + self::$testContent + ) + ) + ); + self::$testFiles[] = $tempfile; + } + } + } + + /** + * @covers ::run + */ + public function testRunSingleFile(): void + { + $tmpDir = sys_get_temp_dir() . '/foz/'; + $testFile = $tmpDir . 'foz_123456.txt'; + + if (!is_dir($tmpDir)) { + mkdir($tmpDir); + } + + $this->putContents($testFile); + $task = new FailedTestsMergerTask(); + $task->setLogger(new Logger(new NullOutput())); + $task + ->from($testFile) + ->into(self::EXPECTED_TEST_MERGED_FILE) + ->run(); + + $this->assertFileExists(self::EXPECTED_TEST_MERGED_FILE); + $content = explode(PHP_EOL, file_get_contents(self::EXPECTED_TEST_MERGED_FILE)); + $this->assertCount( + count(self::$testContent), + $content + ); + } + + public function testRunWithPathAndFilePatterns(): void + { + $task = new FailedTestsMergerTask(); + $task->setLogger(new Logger(new NullOutput())); + + foreach (self::$tmpDirsPattern as $path => $pattern) { + $task->fromPathWithPattern( + sys_get_temp_dir() . DIRECTORY_SEPARATOR . $path, + $pattern + ); + } + + $task + ->into(self::EXPECTED_TEST_MERGED_FILE) + ->run(); + + $this->assertFileExists(self::EXPECTED_TEST_MERGED_FILE); + $this->assertCount( + (count(self::$testContent) * count(self::$testFiles)), + explode(PHP_EOL, file_get_contents(self::EXPECTED_TEST_MERGED_FILE)) + ); + } + + public function testRunWithFileAndArrayAndPathWithPatterns(): void + { + $tmpDir = sys_get_temp_dir() . '/foz/'; + $testFile = $tmpDir . 'foz_123456.txt'; + + if (!is_dir($tmpDir)) { + mkdir($tmpDir); + } + $this->putContents($testFile); + + $fileData = []; + $i = 0; + while ($i < self::TEST_FILES_PER_DIR) { + $testFile = $tmpDir . 'foz_' . (123456 + ++$i) . '.txt'; + $this->putContents($testFile); + $fileData[] = $testFile; + } + + $task = new FailedTestsMergerTask(); + $task->setLogger(new Logger(new NullOutput())); + $task->from($testFile); + $task->from($fileData); + foreach (self::$tmpDirsPattern as $path => $pattern) { + $task->fromPathWithPattern( + sys_get_temp_dir() . DIRECTORY_SEPARATOR . $path, + $pattern + ); + } + + $task + ->into(self::EXPECTED_TEST_MERGED_FILE) + ->run(); + + $this->assertFileExists(self::EXPECTED_TEST_MERGED_FILE); + $this->assertCount( + ( + count(self::$testContent) * ( + count(self::$testFiles) + + count($fileData) + + count([$testFile]) + ) + ), + explode(PHP_EOL, file_get_contents(self::EXPECTED_TEST_MERGED_FILE)) + ); + } + + public function tearDown(): void + { + parent::tearDown(); // TODO: Change the autogenerated stub + unlink(self::EXPECTED_TEST_MERGED_FILE); + } + + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); // TODO: Change the autogenerated stub + foreach (self::$testFiles as $file) { + unlink($file); + } + } + + /** + * @param string $testFile + */ + protected function putContents(string $testFile): void + { + file_put_contents( + $testFile, + implode( + PHP_EOL, + array_map( + static function (string $filename): string { + return sprintf($filename, 'foz'); + }, + self::$testContent + ) + ) + ); + } +} diff --git a/tests/Splitter/FailedTestSplitterTaskTest.php b/tests/Splitter/FailedTestSplitterTaskTest.php index 969f7a1..1b77658 100644 --- a/tests/Splitter/FailedTestSplitterTaskTest.php +++ b/tests/Splitter/FailedTestSplitterTaskTest.php @@ -2,13 +2,11 @@ namespace Tests\Codeception\Task\Splitter; -use Codeception\Task\Extension\FailedTestsReporter; use Codeception\Task\Splitter\FailedTestSplitterTask; use Codeception\Task\Splitter\TestsSplitter; use Consolidation\Log\Logger; use InvalidArgumentException; use PHPUnit\Framework\TestCase; -use Robo\Exception\TaskException; use RuntimeException; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Finder\Finder; @@ -19,7 +17,7 @@ public function testRunWillFailIfReportFileDoesNotExists(): void { $task = new FailedTestSplitterTask(5); $task->setLogger(new Logger(new NullOutput())); - $task->setReportPath('tests/_output/') + $task->setReportPath('tests/_output/failedTests.txt') ->groupsTo(TEST_PATH . '/result/group_'); $this->expectException(RuntimeException::class); @@ -36,7 +34,7 @@ public function testRun(): void $task->setLogger(new Logger(new NullOutput())); $groupTo = TEST_PATH . '/result/group_'; $task - ->setReportPath(TEST_PATH . '/fixtures/' . FailedTestsReporter::REPORT_NAME) + ->setReportPath(TEST_PATH . '/fixtures/failedTests.txt') ->groupsTo($groupTo) ->run(); From 66cf5400832a6929e6718a68a8a1c3eaa856c10a Mon Sep 17 00:00:00 2001 From: KJunker Date: Fri, 6 Aug 2021 10:00:42 +0200 Subject: [PATCH 03/12] Bugfix/merge html correction execution time (#74) * Create php.yml * Building Test for HTMLMerger, find error by summary of Test Execution Time * Sum the execution Time for the merged Reports * Codestyle fixing Co-authored-by: Michael Bodnarchuk --- src/Exception/KeyNotFoundException.php | 12 + src/Exception/XPathExpressionException.php | 15 + src/Merger/HtmlReportMerger.php | 147 ++++- tests/Merger/HtmlReportMergerTest.php | 61 ++ .../reports/html/expected_report.html | 528 ++++++++++++++++++ tests/fixtures/reports/html/report_1.html | 317 +++++++++++ tests/fixtures/reports/html/report_2.html | 292 ++++++++++ tests/fixtures/reports/html/report_3.html | 319 +++++++++++ 8 files changed, 1675 insertions(+), 16 deletions(-) create mode 100644 src/Exception/KeyNotFoundException.php create mode 100644 src/Exception/XPathExpressionException.php create mode 100644 tests/Merger/HtmlReportMergerTest.php create mode 100644 tests/fixtures/reports/html/expected_report.html create mode 100644 tests/fixtures/reports/html/report_1.html create mode 100644 tests/fixtures/reports/html/report_2.html create mode 100644 tests/fixtures/reports/html/report_3.html diff --git a/src/Exception/KeyNotFoundException.php b/src/Exception/KeyNotFoundException.php new file mode 100644 index 0000000..2e1a000 --- /dev/null +++ b/src/Exception/KeyNotFoundException.php @@ -0,0 +1,12 @@ +src = $src; + } + + /** + * @param string[]|string $fileName - a single report file or array of report files + * @return $this|HtmlReportMerger + */ + public function from($fileName): self { if (is_array($fileName)) { $this->src = array_merge($fileName, $this->src); @@ -36,7 +65,11 @@ public function from($fileName) return $this; } - public function into($fileName) + /** + * @param string $fileName + * @return $this|HtmlReportMerger + */ + public function into(string $fileName): self { $this->dst = $fileName; return $this; @@ -57,18 +90,34 @@ public function run() //read first source file as main $dstHTML = new DOMDocument(); $dstHTML->loadHTMLFile($this->src[0], LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); - + $this->countExecutionTime($dstHTML); //main node for all table rows - $table = (new \DOMXPath($dstHTML))->query("//table")->item(0); - + $nodeList = (new DOMXPath($dstHTML))->query("//table"); + if (!$nodeList) { + throw XPathExpressionException::malformedXPath("//table"); + } + $index = 0; + /** @var DOMNode $table */ + $table = $nodeList->item($index); + if (null === $table) { + throw new KeyNotFoundException('Could not find table item at pos: ' . $index); + } //prepare reference nodes for envs - $refnodes = (new DOMXPath($dstHTML))->query("//div[@class='layout']/table/tr[not(@class)]"); - + $xpathExprRefNodes = "//div[@class='layout']/table/tr[not(@class)]"; + $refnodes = (new DOMXPath($dstHTML))->query($xpathExprRefNodes); + if (!$refnodes) { + throw XPathExpressionException::malformedXPath($xpathExprRefNodes); + } for ($k = 1, $kMax = count($this->src); $k < $kMax; $k++) { $srcHTML = new DOMDocument(); $src = $this->src[$k]; $srcHTML->loadHTMLFile($src, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); - $suiteNodes = (new DOMXPath($srcHTML))->query("//div[@class='layout']/table/tr"); + $this->countExecutionTime($srcHTML); + $xpathExprSuiteNodes = "//div[@class='layout']/table/tr"; + $suiteNodes = (new DOMXPath($srcHTML))->query($xpathExprSuiteNodes); + if (!$suiteNodes) { + throw XPathExpressionException::malformedXPath($xpathExprSuiteNodes); + } $j = 0; foreach ($suiteNodes as $suiteNode) { if ($suiteNode->getAttribute('class') == '') { @@ -86,13 +135,14 @@ public function run() } /** - * The next 5 functions correct our almost finished final report + * The next 6 functions correct our almost finished final report */ $this->countSummary($dstHTML); $this->moveSummaryTable($dstHTML, $table); $this->updateSummaryTable($dstHTML); $this->updateToolbarTable($dstHTML); $this->updateButtons($dstHTML); + $this->updateHeaderLine($dstHTML); //save final report file_put_contents($this->dst, $dstHTML->saveHTML()); @@ -102,12 +152,72 @@ public function run() } /** - * This function counts all types of tests' scenarios and writes in class members - * @param $dstFile DOMDocument - destination file + * This function sums all execution time of each report + * @param DOMDocument $dstFile + * @throws XPathExpressionException */ - private function countSummary($dstFile) + private function countExecutionTime(DOMDocument $dstFile): void { - $tests = (new \DOMXPath($dstFile))->query("//table/tr[contains(@class,'scenarioRow')]"); + $xpathHeadline = "//h1[text() = 'Codeception Results ']"; + $nodeList = (new DOMXPath($dstFile)) + ->query($xpathHeadline); + if (!$nodeList) { + throw XPathExpressionException::malformedXPath($xpathHeadline); + } + $pregResult = preg_match( + '/^Codeception Results .* \((?\d+\.\d+)s\)$/', + $nodeList[0]->nodeValue, + $matches + ); + + if (false === $pregResult) { + throw new RuntimeException('Regexpression is malformed'); + } + + if (0 === $pregResult) { + return; + } + + $this->executionTimeSum += (float)$matches['timesum']; + } + + /** + * @param DOMDocument $dstFile + * @throws XPathExpressionException + */ + private function updateHeaderLine(DOMDocument $dstFile): void + { + $xpathHeadline = "//h1[text() = 'Codeception Results ']"; + $nodeList = (new DOMXPath($dstFile)) + ->query($xpathHeadline); + if (!$nodeList) { + throw XPathExpressionException::malformedXPath($xpathHeadline); + } + /** @var DOMNode $executionTimeNode */ + $executionTimeNode = $nodeList[0]->childNodes[1]->childNodes[1]; + /** @var DOMAttr $statusAttr */ + $statusNode = $nodeList[0]->childNodes[1]->childNodes[0]; + $statusAttr = $statusNode->attributes[0]; + if (0 !== ($this->countFailed + $this->countIncomplete + $this->countSkipped)) { + $statusNode->nodeValue = 'NOT OK'; + $statusAttr->value = 'color: red'; + } + $executionTimeNode->nodeValue = " ({$this->executionTimeSum}s)"; + } + + /** + * This function counts all types of tests' scenarios and writes in class members + * @param DOMDocument $dstFile - destination file + * @throws XPathExpressionException + */ + private function countSummary(DOMDocument $dstFile): void + { + $xpathExprTests = "//table/tr[contains(@class,'scenarioRow')]"; + /** @var DOMNodeList $tests */ + $tests = (new DOMXPath($dstFile))->query($xpathExprTests); + if (!$tests) { + throw XPathExpressionException::malformedXPath($xpathExprTests); + } foreach ($tests as $test) { $class = str_replace('scenarioRow ', '', $test->getAttribute('class')); switch ($class) { @@ -150,7 +260,7 @@ private function updateSummaryTable(DOMDocument $dstFile) */ private function moveSummaryTable(DOMDocument $dstFile, DOMNode $node) { - $summaryTable = (new \DOMXPath($dstFile))->query("//div[@id='stepContainerSummary']") + $summaryTable = (new DOMXPath($dstFile))->query("//div[@id='stepContainerSummary']") ->item(0)->parentNode->parentNode; $node->appendChild($dstFile->importNode($summaryTable, true)); } @@ -162,7 +272,7 @@ private function moveSummaryTable(DOMDocument $dstFile, DOMNode $node) */ private function updateToolbarTable(DOMDocument $dstFile) { - $dstFile = new \DOMXPath($dstFile); + $dstFile = new DOMXPath($dstFile); $pathFor = static function (string $type): string { return "//ul[@id='toolbar-filter']//a[@title='$type']"; }; @@ -175,10 +285,15 @@ private function updateToolbarTable(DOMDocument $dstFile) /** * This function updates "+" and "-" button for viewing test steps in final report * @param $dstFile DOMDocument - destination file + * @throws XPathExpressionException */ private function updateButtons(DOMDocument $dstFile) { - $nodes = (new \DOMXPath($dstFile))->query("//div[@class='layout']/table/tr[contains(@class, 'scenarioRow')]"); + $xpathExprNodes = "//div[@class='layout']/table/tr[contains(@class, 'scenarioRow')]"; + $nodes = (new DOMXPath($dstFile))->query($xpathExprNodes); + if (!$nodes) { + throw XPathExpressionException::malformedXPath($xpathExprNodes); + } for ($i = 2; $i < $nodes->length; $i += 2) { $n = $i / 2 + 1; $p = $nodes->item($i)->childNodes->item(1)->childNodes->item(1); diff --git a/tests/Merger/HtmlReportMergerTest.php b/tests/Merger/HtmlReportMergerTest.php new file mode 100644 index 0000000..129a563 --- /dev/null +++ b/tests/Merger/HtmlReportMergerTest.php @@ -0,0 +1,61 @@ +setLogger(new Logger(new NullOutput())); + $resultReport = TEST_PATH . '/result/report.html'; + $task + ->from( + [ + $reportPath . 'report_1.html', + $reportPath . 'report_2.html', + $reportPath . 'report_3.html', + ] + ) + ->into($resultReport) + ->run(); + + $this->assertFileExists($resultReport); + + //read first source file as main + $dstHTML = new DOMDocument(); + $dstHTML->loadHTMLFile($resultReport, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); + /** @var DOMNodeList $values */ + $values = (new DOMXPath($dstHTML)) + ->query("//*[contains(@class,'scenarioSuccessValue')]"); + + $this->assertCount(1, $values); + $this->assertSame($expectedSuccess, (int)$values[0]->nodeValue); + + $values = (new DOMXPath($dstHTML)) + ->query("//h1[text() = 'Codeception Results ']"); + preg_match( + '/^Codeception Results .* \((?\d+\.\d+)s\)$/', + $values[0]->nodeValue, + $matches + ); + + $this->assertSame($expectedTimeInSeconds, (float)$matches['timesum']); + } +} diff --git a/tests/fixtures/reports/html/expected_report.html b/tests/fixtures/reports/html/expected_report.html new file mode 100644 index 0000000..0c496f3 --- /dev/null +++ b/tests/fixtures/reports/html/expected_report.html @@ -0,0 +1,528 @@ + + + Test results + + + + + + + + + + +
+

Codeception Results OK (234.98s)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Acceptance (cloud-stage) Tests

+
+

+ + ExpleogroupCest » Student apply expleogroup and + choose interest 103.29s

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ I acting as "Vincenzo" +

+ +

+ I set locale "fr"

+ +

+ I visit "Page\Applications\ApplicationFormPage","","appsource=expleogroup" +

+ +

+ Page\Applications\ApplicationFormPage: start + application {"title":"La première étape de votre candidature","button":"Commencer"} +

+ +

+ Page\Applications\ApplicationFormPage: fill + personal details {"title":"Votre profil","birthdate":"Votre date de naissance","address":"Votre adresse","gender":"Votre genre"},{"gender":"Masculin","address":"7 cité paradis PARIS"} +

+ +

+ Page\Applications\ApplicationFormPage: fill + education {"title":"Vos études","education":"","diploma":"Quel est votre niveau de diplôme le plus élevé ?","frenchLevel":"","englishLevel":"Quel est votre niveau d’anglais ?"},{"diploma":"Bac+2","englishLevel":"Intermédiaire (B1-B2)"} +

+ +

+ Page\Applications\ApplicationFormPage: fill + learning resources {"title":"La formation en ligne et vous","followedCourses":"Avez-vous déjà suivi des cours en ligne ?","followedCoursesSubject":"Sur quels sujets et sur quels sites ?","resources":"Pour cette formation, vous aurez accès à :"},{"followedCourses":"Oui","followedCoursesSubject":"Coursera","resources":["Un endroit calme","Un ordinateur","Un micro"]} +

+ +

+ Page\Applications\ApplicationFormPage: fill + motivation {"title":"Votre nouvelle carrière","professionalProject":"Détaillez votre projet professionnel (à court, moyen et long-terme)","cv":"Ajoutez votre CV","linkedin":"","foundEmployer":"","desiredStartDate":"","nextButton":"Envoyer la candidature"},{"cv":"cv.pdf"} +

+ +

+ Page\Applications\ApplicationFormPage: see + application end {"title":"Merci de votre intérêt pour nos formations !","button":"RETOUR À L’ACCUEIL"} +

+ +
+
+

Api (cloud-stage) Tests

+
+

+ + AnalyticsCest » Get analytics with paths code + 2.44s

+
+ + + + + + + + + + + + + +

+ I acting as "Business\Users\BotAdmin" +

+ +

+ I get analytics "PATHS",[],"0-1000" +

+ +

+ I see analytics "PATHS" +

+ +
+ + +
+

Bdd (cloud-stage) Tests

+
+

+ + Course » Member can follow a course and pass a + quiz 129.25s

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    As a member +
    I want to follow a + course and pass a quiz
    In order to make + progress on the platform

+ Given i am "member"

+ +

+ When i choose a course

+ +

+ And i follow a course

+ +

+ And i pass a quiz

+ +

+ Then i see that i have followed the course

+ +

+ And i see that i have passed the quiz

+ +
+ + +
+

Summary

+
+ + + + + + + + + + + + + + + + + +
Successful scenarios:3
Failed scenarios:0
Skipped scenarios:0
Incomplete scenarios:0
+
+
+
+ + diff --git a/tests/fixtures/reports/html/report_1.html b/tests/fixtures/reports/html/report_1.html new file mode 100644 index 0000000..d91f6fd --- /dev/null +++ b/tests/fixtures/reports/html/report_1.html @@ -0,0 +1,317 @@ + + + Test results + + + + + + + + + + +
+

Codeception Results OK (103.29s)

+ + + + + + + + + + + + + + + +
+

Acceptance (cloud-stage) Tests

+
+

+ + ExpleogroupCest » Student apply expleogroup and choose interest 103.29s

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ I acting as "Vincenzo"

+ +

+ I set locale "fr"

+ +

+ I visit "Page\Applications\ApplicationFormPage","","appsource=expleogroup"

+ +

+ Page\Applications\ApplicationFormPage: start application {"title":"La première étape de votre candidature","button":"Commencer"}

+ +

+ Page\Applications\ApplicationFormPage: fill personal details {"title":"Votre profil","birthdate":"Votre date de naissance","address":"Votre adresse","gender":"Votre genre"},{"gender":"Masculin","address":"7 cité paradis PARIS"}

+ +

+ Page\Applications\ApplicationFormPage: fill education {"title":"Vos études","education":"","diploma":"Quel est votre niveau de diplôme le plus élevé ?","frenchLevel":"","englishLevel":"Quel est votre niveau d’anglais ?"},{"diploma":"Bac+2","englishLevel":"Intermédiaire (B1-B2)"}

+ +

+ Page\Applications\ApplicationFormPage: fill learning resources {"title":"La formation en ligne et vous","followedCourses":"Avez-vous déjà suivi des cours en ligne ?","followedCoursesSubject":"Sur quels sujets et sur quels sites ?","resources":"Pour cette formation, vous aurez accès à :"},{"followedCourses":"Oui","followedCoursesSubject":"Coursera","resources":["Un endroit calme","Un ordinateur","Un micro"]}

+ +

+ Page\Applications\ApplicationFormPage: fill motivation {"title":"Votre nouvelle carrière","professionalProject":"Détaillez votre projet professionnel (à court, moyen et long-terme)","cv":"Ajoutez votre CV","linkedin":"","foundEmployer":"","desiredStartDate":"","nextButton":"Envoyer la candidature"},{"cv":"cv.pdf"}

+ +

+ Page\Applications\ApplicationFormPage: see application end {"title":"Merci de votre intérêt pour nos formations !","button":"RETOUR À L’ACCUEIL"}

+ +
+
+

Summary

+
+ + + + + + + + + + + + + + + + + +
Successful scenarios:1
Failed scenarios:0
Skipped scenarios:0
Incomplete scenarios:0
+
+
+
+ + diff --git a/tests/fixtures/reports/html/report_2.html b/tests/fixtures/reports/html/report_2.html new file mode 100644 index 0000000..5e9d9dd --- /dev/null +++ b/tests/fixtures/reports/html/report_2.html @@ -0,0 +1,292 @@ + + + Test results + + + + + + + + + + +
+

Codeception Results OK (2.44s)

+ + + + + + + + + + + + + + + + + + + + +
+

Api (cloud-stage) Tests

+
+

+ + AnalyticsCest » Get analytics with paths code 2.44s

+
+ + + + + + + + + + + + + +

+ I acting as "Business\Users\BotAdmin"

+ +

+ I get analytics "PATHS",[],"0-1000"

+ +

+ I see analytics "PATHS"

+ +
+ + +
+

Summary

+
+ + + + + + + + + + + + + + + + + +
Successful scenarios:1
Failed scenarios:0
Skipped scenarios:0
Incomplete scenarios:0
+
+
+
+ + diff --git a/tests/fixtures/reports/html/report_3.html b/tests/fixtures/reports/html/report_3.html new file mode 100644 index 0000000..db1be8e --- /dev/null +++ b/tests/fixtures/reports/html/report_3.html @@ -0,0 +1,319 @@ + + + Test results + + + + + + + + + + +
+

Codeception Results OK (129.25s)

+ + + + + + + + + + + + + + + + + + + + + +
+

Bdd (cloud-stage) Tests

+
+

+ + Course » Member can follow a course and pass a quiz 129.25s

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    As a member
    I want to follow a course and pass a quiz
    In order to make progress on the platform

+ Given i am "member"

+ +

+ When i choose a course

+ +

+ And i follow a course

+ +

+ And i pass a quiz

+ +

+ Then i see that i have followed the course

+ +

+ And i see that i have passed the quiz

+ +
+ + +
+

Summary

+
+ + + + + + + + + + + + + + + + + +
Successful scenarios:1
Failed scenarios:0
Skipped scenarios:0
Incomplete scenarios:0
+
+
+
+ + From 57f0f50618d10eb5bee096c2486eb93c5c1d8359 Mon Sep 17 00:00:00 2001 From: Caroline BUZENET Date: Fri, 6 Aug 2021 10:01:12 +0200 Subject: [PATCH 04/12] testsFrom() method allow string or array (#73) --- src/Splitter/TestsSplitter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Splitter/TestsSplitter.php b/src/Splitter/TestsSplitter.php index 2cd1a14..2259e60 100644 --- a/src/Splitter/TestsSplitter.php +++ b/src/Splitter/TestsSplitter.php @@ -16,7 +16,7 @@ abstract class TestsSplitter extends BaseTask protected $numGroups; /** @var string */ protected $projectRoot = '.'; - /** @var string */ + /** @var string|array */ protected $testsFrom = 'tests'; /** @var string */ protected $saveTo = 'tests/_data/paracept_'; @@ -59,7 +59,7 @@ public function projectRoot(string $path): TestsSplitter return $this; } - public function testsFrom(string $path): TestsSplitter + public function testsFrom(string|array $path): TestsSplitter { $this->testsFrom = $path; From 97df7e9d86c30b0252a02ad5256467b1f1dc01b2 Mon Sep 17 00:00:00 2001 From: Michael Bodnarchuk Date: Fri, 6 Aug 2021 11:05:10 +0300 Subject: [PATCH 05/12] Revert "testsFrom() method allow string or array (#73)" (#77) This reverts commit 7fa164016db5894bf0363c898984e20a8173d2de. --- src/Splitter/TestsSplitter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Splitter/TestsSplitter.php b/src/Splitter/TestsSplitter.php index 2259e60..2cd1a14 100644 --- a/src/Splitter/TestsSplitter.php +++ b/src/Splitter/TestsSplitter.php @@ -16,7 +16,7 @@ abstract class TestsSplitter extends BaseTask protected $numGroups; /** @var string */ protected $projectRoot = '.'; - /** @var string|array */ + /** @var string */ protected $testsFrom = 'tests'; /** @var string */ protected $saveTo = 'tests/_data/paracept_'; @@ -59,7 +59,7 @@ public function projectRoot(string $path): TestsSplitter return $this; } - public function testsFrom(string|array $path): TestsSplitter + public function testsFrom(string $path): TestsSplitter { $this->testsFrom = $path; From cef4bd70ed43c29d28ecd2200c1a86bbe4b35558 Mon Sep 17 00:00:00 2001 From: Caroline BUZENET Date: Fri, 6 Aug 2021 10:21:35 +0200 Subject: [PATCH 06/12] Feat tests from allow string or array (#78) * testsFrom() method allow string or array * testsFrom() method allow string or array --- src/Splitter/TestsSplitter.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Splitter/TestsSplitter.php b/src/Splitter/TestsSplitter.php index 2cd1a14..28b0471 100644 --- a/src/Splitter/TestsSplitter.php +++ b/src/Splitter/TestsSplitter.php @@ -16,7 +16,7 @@ abstract class TestsSplitter extends BaseTask protected $numGroups; /** @var string */ protected $projectRoot = '.'; - /** @var string */ + /** @var string[]|string */ protected $testsFrom = 'tests'; /** @var string */ protected $saveTo = 'tests/_data/paracept_'; @@ -59,7 +59,11 @@ public function projectRoot(string $path): TestsSplitter return $this; } - public function testsFrom(string $path): TestsSplitter + /** + * @param string[]|string $path - a single path or array of paths + * @return $this|TestsSplitter + */ + public function testsFrom($path): TestsSplitter { $this->testsFrom = $path; From cb1c350c8e22d343bb1561e5a7ecef8964cd1ea5 Mon Sep 17 00:00:00 2001 From: Ihor Sychevskyi Date: Tue, 10 Aug 2021 00:36:47 +0300 Subject: [PATCH 07/12] add changelog (#80) --- CHANGELOG.md | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ed059d4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,81 @@ +## [1.2.0](1.2.0) + +- Bugfix for extension FailedTestsReporter and new FailedTestsMergerTask [#75](https://github.com/Codeception/robo-paracept/pull/75) + - generated Files will not be overwriten anymore + - each generated File has now a uniqid-suffix (PHP Function uniqid('', true)) + - merge generated report files from FailedTestsReporter into single file + - posibility to merge also another files into a single file + + +- Bugfix src/Splitter/TestsSplitter.php::testsFrom [#78](https://github.com/Codeception/robo-paracept/pull/78) @ccsuperstar + - revert string type hint and allow array or string again + +## [1.1.1](https://github.com/Codeception/robo-paracept/releases/tag/1.1.1) Bugfix + +* Fixed return type declaraton [#68](https://github.com/Codeception/robo-paracept/pull/68) + +## [1.1.0](https://github.com/Codeception/robo-paracept/releases/tag/1.1.0) Robo-Paracept 1.1 + +* SplitFailedTests task added to split by groups failed tests only [#65](https://github.com/Codeception/robo-paracept/pull/65) +* Fixed return type in taskSplitTestFilesByGroups [#62](https://github.com/Codeception/robo-paracept/pull/62) + +## [1.0.0](https://github.com/Codeception/robo-paracept/releases/tag/1.0.0) Robo-Paracept 1.0 + +Big day for Robo-Paracept. The first stable version is released! ✈️ + +### Changes + +* **Support for modern PHP 7.3, 7.4, 8.0** +* Added support for the latest [Robo task runner](https://robo.li) +* Added **Filters** to select tests before splitting them +* Added **SplitByTime** task to use time statistics of previous runs to balance groups of tests. Thanks to @ivan1986 + +## [0.4.2](https://github.com/Codeception/robo-paracept/releases/tag/0.4.2) Resolve dependencies when splitting tests + +[#46](https://github.com/Codeception/robo-paracept/pull/46) + +## [0.4.1](https://github.com/Codeception/robo-paracept/releases/tag/0.4.1) Release with new PHPUnit support + +* PHPUnit 6.x support in split [#45](https://github.com/Codeception/robo-paracept/pull/45) +* follow symlinks while scanning for tests [#44](https://github.com/Codeception/robo-paracept/pull/44) + +## [0.4.0](https://github.com/Codeception/robo-paracept/releases/tag/0.4.0) Minor improvements + +* [#37](https://github.com/Codeception/robo-paracept/pull/37) Added `excluePath` option to `SplitTestsByGroups` task. By @thejanasatan +* [#36](https://github.com/Codeception/robo-paracept/pull/36) Added mergeRewrite to merge reports by @maxgorovenko +* [#30](https://github.com/Codeception/robo-paracept/pull/30) Fixed execute test name from data provider by @ivan1986 + +Also PHPUnit 6 compatibility can be achieved by including Codeception's autoloader: + +```php +require 'vendor/codeception/codeception/autoload.php' +``` + +See https://github.com/Codeception/robo-paracept/issues/35#issuecomment-311605115 + +## [0.3.1](https://github.com/Codeception/robo-paracept/releases/tag/0.3.1) 0.3.1: Merge pull request #27 from dhiva/master + +Improved HTML report merge [#27](https://github.com/Codeception/robo-paracept/pull/27) + +## [0.3.0](https://github.com/Codeception/robo-paracept/releases/tag/0.3.0) Robo 1.0 compatibility + +* Robo 1.0 compatibility (Merged [#19](https://github.com/Codeception/robo-paracept/issues/19) , Fixed [#16](https://github.com/Codeception/robo-paracept/issues/16) [#17](https://github.com/Codeception/robo-paracept/pull/17)) +* Support for `.feature` files in `SplitGroups`. Merged [#23](https://github.com/Codeception/robo-paracept/pull/23) + +## [0.2.0](https://github.com/Codeception/robo-paracept/releases/tag/0.2.0) Support for Robo 0.7-1.0 + +Fixed using with Robo >= 0.7 + +* [#12](https://github.com/Codeception/robo-paracept/pull/12) +* [#15](https://github.com/Codeception/robo-paracept/pull/15) +* Fixed [#14](https://github.com/Codeception/robo-paracept/issues/14) + +## [0.1.1](https://github.com/Codeception/robo-paracept/releases/tag/0.1.1) Codeception v2.2 and Robo 0.7 compat + +Reference + +https://codeception.com/docs/12-ParallelExecution#Robo + +## [0.1.0](https://github.com/Codeception/robo-paracept/releases/tag/0.1.0) + +To be compatible with codeception 2.2.2 \ No newline at end of file From a0b2aa1c5be81a52877d8ddc2c993130a42b72c1 Mon Sep 17 00:00:00 2001 From: Ihor Sychevskyi Date: Fri, 13 Aug 2021 02:22:38 +0300 Subject: [PATCH 08/12] update changelog (#83) --- CHANGELOG.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed059d4..f694e92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,22 @@ -## [1.2.0](1.2.0) +## [1.2.1](https://github.com/Codeception/robo-paracept/releases/tag/1.2.1) Bugfix + +Pull Request: [#82](https://github.com/Codeception/robo-paracept/pull/82) + +Calculation number of tests in groups in class TestsSplitterTask did not work as expected. +If you have a high number of Tests it was possible that the last group received a huge number of tests while all others had a stable small number of tests. + +- Fixing calculation number of tests in Groups +- Using PHP Built In round() instead of floor() + +## [1.2.0](https://github.com/Codeception/robo-paracept/releases/tag/1.2.0) - Bugfix for extension FailedTestsReporter and new FailedTestsMergerTask [#75](https://github.com/Codeception/robo-paracept/pull/75) - generated Files will not be overwriten anymore - each generated File has now a uniqid-suffix (PHP Function uniqid('', true)) - merge generated report files from FailedTestsReporter into single file - posibility to merge also another files into a single file - - -- Bugfix src/Splitter/TestsSplitter.php::testsFrom [#78](https://github.com/Codeception/robo-paracept/pull/78) @ccsuperstar + +- Bugfix src/Splitter/TestsSplitter.php::testsFrom [#78](https://github.com/Codeception/robo-paracept/pull/78) [@ccsuperstar](https://github.com/ccsuperstar) - revert string type hint and allow array or string again ## [1.1.1](https://github.com/Codeception/robo-paracept/releases/tag/1.1.1) Bugfix @@ -28,7 +37,7 @@ Big day for Robo-Paracept. The first stable version is released! ✈️ * **Support for modern PHP 7.3, 7.4, 8.0** * Added support for the latest [Robo task runner](https://robo.li) * Added **Filters** to select tests before splitting them -* Added **SplitByTime** task to use time statistics of previous runs to balance groups of tests. Thanks to @ivan1986 +* Added **SplitByTime** task to use time statistics of previous runs to balance groups of tests. Thanks to [@ivan1986](https://github.com/ivan1986) ## [0.4.2](https://github.com/Codeception/robo-paracept/releases/tag/0.4.2) Resolve dependencies when splitting tests @@ -41,9 +50,9 @@ Big day for Robo-Paracept. The first stable version is released! ✈️ ## [0.4.0](https://github.com/Codeception/robo-paracept/releases/tag/0.4.0) Minor improvements -* [#37](https://github.com/Codeception/robo-paracept/pull/37) Added `excluePath` option to `SplitTestsByGroups` task. By @thejanasatan -* [#36](https://github.com/Codeception/robo-paracept/pull/36) Added mergeRewrite to merge reports by @maxgorovenko -* [#30](https://github.com/Codeception/robo-paracept/pull/30) Fixed execute test name from data provider by @ivan1986 +* [#37](https://github.com/Codeception/robo-paracept/pull/37) Added `excluePath` option to `SplitTestsByGroups` task. By [@thejanasatan](https://github.com/thejanasatan) +* [#36](https://github.com/Codeception/robo-paracept/pull/36) Added mergeRewrite to merge reports by [@maxgorovenko](https://github.com/maxgorovenko) +* [#30](https://github.com/Codeception/robo-paracept/pull/30) Fixed execute test name from data provider by [@ivan1986](https://github.com/ivan1986) Also PHPUnit 6 compatibility can be achieved by including Codeception's autoloader: @@ -51,7 +60,7 @@ Also PHPUnit 6 compatibility can be achieved by including Codeception's autoload require 'vendor/codeception/codeception/autoload.php' ``` -See https://github.com/Codeception/robo-paracept/issues/35#issuecomment-311605115 +See [#35 (comment)](https://github.com/Codeception/robo-paracept/issues/35#issuecomment-311605115) ## [0.3.1](https://github.com/Codeception/robo-paracept/releases/tag/0.3.1) 0.3.1: Merge pull request #27 from dhiva/master From b4627eec712142d122f41d7eda85030d8ec51a28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Sep 2021 21:52:24 +0200 Subject: [PATCH 09/12] Bump codeception/codeception from 4.1.21 to 4.1.22 (#84) Bumps [codeception/codeception](https://github.com/Codeception/Codeception) from 4.1.21 to 4.1.22. - [Release notes](https://github.com/Codeception/Codeception/releases) - [Changelog](https://github.com/Codeception/Codeception/blob/4.1/CHANGELOG-4.x.md) - [Commits](https://github.com/Codeception/Codeception/compare/4.1.21...4.1.22) --- updated-dependencies: - dependency-name: codeception/codeception dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 543 ++++++++++++++------------------------------------ 1 file changed, 149 insertions(+), 394 deletions(-) diff --git a/composer.lock b/composer.lock index 6842fe1..7c109f5 100644 --- a/composer.lock +++ b/composer.lock @@ -55,10 +55,6 @@ } ], "description": "Initialize Symfony Console commands from annotated command class methods.", - "support": { - "issues": "https://github.com/consolidation/annotated-command/issues", - "source": "https://github.com/consolidation/annotated-command/tree/4.2.4" - }, "time": "2020-12-10T16:56:39+00:00" }, { @@ -115,10 +111,6 @@ } ], "description": "Provide configuration services for a commandline tool.", - "support": { - "issues": "https://github.com/consolidation/config/issues", - "source": "https://github.com/consolidation/config/tree/2.0.1" - }, "time": "2020-12-06T00:03:30+00:00" }, { @@ -167,10 +159,6 @@ } ], "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", - "support": { - "issues": "https://github.com/consolidation/log/issues", - "source": "https://github.com/consolidation/log/tree/2.0.2" - }, "time": "2020-12-10T16:26:23+00:00" }, { @@ -226,10 +214,6 @@ } ], "description": "Format text by applying transformations provided by plug-in formatters.", - "support": { - "issues": "https://github.com/consolidation/output-formatters/issues", - "source": "https://github.com/consolidation/output-formatters/tree/4.1.2" - }, "time": "2020-12-12T19:04:59+00:00" }, { @@ -325,10 +309,6 @@ } ], "description": "Modern task runner", - "support": { - "issues": "https://github.com/consolidation/Robo/issues", - "source": "https://github.com/consolidation/Robo/tree/3.0.3" - }, "time": "2021-02-21T19:19:43+00:00" }, { @@ -379,10 +359,6 @@ } ], "description": "Provides a self:update command for Symfony Console applications.", - "support": { - "issues": "https://github.com/consolidation/self-update/issues", - "source": "https://github.com/consolidation/self-update/tree/1.2.0" - }, "time": "2020-04-13T02:49:20+00:00" }, { @@ -442,10 +418,6 @@ "dot", "notation" ], - "support": { - "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", - "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/master" - }, "time": "2017-01-20T21:14:22+00:00" }, { @@ -493,10 +465,6 @@ } ], "description": "Expands internal property references in PHP arrays file.", - "support": { - "issues": "https://github.com/grasmash/expander/issues", - "source": "https://github.com/grasmash/expander/tree/master" - }, "time": "2017-12-21T22:14:55+00:00" }, { @@ -566,10 +534,6 @@ "provider", "service" ], - "support": { - "issues": "https://github.com/thephpleague/container/issues", - "source": "https://github.com/thephpleague/container/tree/3.4.1" - }, "funding": [ { "url": "https://github.com/philipobenito", @@ -620,10 +584,6 @@ "container-interop", "psr" ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.1" - }, "time": "2021-03-05T17:36:06+00:00" }, { @@ -670,10 +630,6 @@ "psr", "psr-14" ], - "support": { - "issues": "https://github.com/php-fig/event-dispatcher/issues", - "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" - }, "time": "2019-01-08T18:20:26+00:00" }, { @@ -721,9 +677,6 @@ "psr", "psr-3" ], - "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" - }, "time": "2021-05-03T11:20:27+00:00" }, { @@ -798,9 +751,6 @@ ], "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/console/tree/v5.1.11" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -865,9 +815,6 @@ ], "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -886,23 +833,23 @@ }, { "name": "symfony/event-dispatcher", - "version": "v5.3.0", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "67a5f354afa8e2f231081b3fa11a5912f933c3ce" + "reference": "ce7b20d69c66a20939d8952b617506a44d102130" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/67a5f354afa8e2f231081b3fa11a5912f933c3ce", - "reference": "67a5f354afa8e2f231081b3fa11a5912f933c3ce", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ce7b20d69c66a20939d8952b617506a44d102130", + "reference": "ce7b20d69c66a20939d8952b617506a44d102130", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1", "symfony/event-dispatcher-contracts": "^2", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "symfony/dependency-injection": "<4.4" @@ -912,7 +859,7 @@ "symfony/event-dispatcher-implementation": "2.0" }, "require-dev": { - "psr/log": "~1.0", + "psr/log": "^1|^2|^3", "symfony/config": "^4.4|^5.0", "symfony/dependency-injection": "^4.4|^5.0", "symfony/error-handler": "^4.4|^5.0", @@ -950,9 +897,6 @@ ], "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.3.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -967,7 +911,7 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2021-08-04T21:20:46+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -1029,9 +973,6 @@ "interoperability", "standards" ], - "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.4.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1091,9 +1032,6 @@ ], "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.3.3" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1152,9 +1090,6 @@ ], "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/finder/tree/v5.3.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1231,9 +1166,6 @@ "polyfill", "portable" ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1252,16 +1184,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.23.0", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "24b72c6baa32c746a4d0840147c9715e42bb68ab" + "reference": "16880ba9c5ebe3642d1995ab866db29270b36535" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/24b72c6baa32c746a4d0840147c9715e42bb68ab", - "reference": "24b72c6baa32c746a4d0840147c9715e42bb68ab", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/16880ba9c5ebe3642d1995ab866db29270b36535", + "reference": "16880ba9c5ebe3642d1995ab866db29270b36535", "shasum": "" }, "require": { @@ -1312,9 +1244,6 @@ "portable", "shim" ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1329,7 +1258,7 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" + "time": "2021-05-27T12:26:48+00:00" }, { "name": "symfony/polyfill-intl-normalizer", @@ -1396,9 +1325,6 @@ "portable", "shim" ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1417,16 +1343,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.23.0", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", "shasum": "" }, "require": { @@ -1476,9 +1402,6 @@ "portable", "shim" ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1493,7 +1416,7 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2021-05-27T12:26:48+00:00" }, { "name": "symfony/polyfill-php73", @@ -1555,9 +1478,6 @@ "portable", "shim" ], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1576,16 +1496,16 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.23.0", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be", + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be", "shasum": "" }, "require": { @@ -1638,9 +1558,6 @@ "portable", "shim" ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1655,7 +1572,7 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-07-28T13:41:28+00:00" }, { "name": "symfony/process", @@ -1700,9 +1617,6 @@ ], "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/process/tree/v5.3.2" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1779,9 +1693,6 @@ "interoperability", "standards" ], - "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.4.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1800,16 +1711,16 @@ }, { "name": "symfony/string", - "version": "v5.3.3", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1" + "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1", - "reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1", + "url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5", + "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5", "shasum": "" }, "require": { @@ -1862,9 +1773,6 @@ "utf-8", "utf8" ], - "support": { - "source": "https://github.com/symfony/string/tree/v5.3.3" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1879,20 +1787,20 @@ "type": "tidelift" } ], - "time": "2021-06-27T11:44:38+00:00" + "time": "2021-08-26T08:00:08+00:00" }, { "name": "symfony/yaml", - "version": "v5.3.3", + "version": "v5.3.6", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "485c83a2fb5893e2ff21bf4bfc7fdf48b4967229" + "reference": "4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/485c83a2fb5893e2ff21bf4bfc7fdf48b4967229", - "reference": "485c83a2fb5893e2ff21bf4bfc7fdf48b4967229", + "url": "https://api.github.com/repos/symfony/yaml/zipball/4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7", + "reference": "4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7", "shasum": "" }, "require": { @@ -1937,9 +1845,6 @@ ], "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/yaml/tree/v5.3.3" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1954,7 +1859,7 @@ "type": "tidelift" } ], - "time": "2021-06-24T08:13:00+00:00" + "time": "2021-07-29T06:20:01+00:00" } ], "packages-dev": [ @@ -2016,24 +1921,20 @@ "gherkin", "parser" ], - "support": { - "issues": "https://github.com/Behat/Gherkin/issues", - "source": "https://github.com/Behat/Gherkin/tree/v4.8.0" - }, "time": "2021-02-04T12:44:21+00:00" }, { "name": "codeception/codeception", - "version": "4.1.21", + "version": "4.1.22", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "c25f20d842a7e3fa0a8e6abf0828f102c914d419" + "reference": "9777ec3690ceedc4bce2ed13af7af4ca4ee3088f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/c25f20d842a7e3fa0a8e6abf0828f102c914d419", - "reference": "c25f20d842a7e3fa0a8e6abf0828f102c914d419", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/9777ec3690ceedc4bce2ed13af7af4ca4ee3088f", + "reference": "9777ec3690ceedc4bce2ed13af7af4ca4ee3088f", "shasum": "" }, "require": { @@ -2044,7 +1945,7 @@ "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*", - "guzzlehttp/psr7": "~1.4", + "guzzlehttp/psr7": "^1.4 | ^2.0", "php": ">=5.6.0 <9.0", "symfony/console": ">=2.7 <6.0", "symfony/css-selector": ">=2.7 <6.0", @@ -2105,17 +2006,13 @@ "functional testing", "unit testing" ], - "support": { - "issues": "https://github.com/Codeception/Codeception/issues", - "source": "https://github.com/Codeception/Codeception/tree/4.1.21" - }, "funding": [ { "url": "https://opencollective.com/codeception", "type": "open_collective" } ], - "time": "2021-05-28T17:43:39+00:00" + "time": "2021-08-06T17:15:34+00:00" }, { "name": "codeception/lib-asserts", @@ -2165,10 +2062,6 @@ "keywords": [ "codeception" ], - "support": { - "issues": "https://github.com/Codeception/lib-asserts/issues", - "source": "https://github.com/Codeception/lib-asserts/tree/1.13.2" - }, "time": "2020-10-21T16:26:20+00:00" }, { @@ -2214,10 +2107,6 @@ } ], "description": "PHPUnit classes used by Codeception", - "support": { - "issues": "https://github.com/Codeception/phpunit-wrapper/issues", - "source": "https://github.com/Codeception/phpunit-wrapper/tree/9.0.6" - }, "time": "2020-12-28T13:59:47+00:00" }, { @@ -2248,10 +2137,6 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", - "support": { - "issues": "https://github.com/Codeception/Stub/issues", - "source": "https://github.com/Codeception/Stub/tree/3.7.0" - }, "time": "2020-07-03T15:54:43+00:00" }, { @@ -2314,11 +2199,6 @@ "validation", "versioning" ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.5" - }, "funding": [ { "url": "https://packagist.com", @@ -2378,11 +2258,6 @@ "Xdebug", "performance" ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/2.0.1" - }, "funding": [ { "url": "https://packagist.com", @@ -2465,10 +2340,6 @@ "docblock", "parser" ], - "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.13.1" - }, "time": "2021-05-16T18:07:53+00:00" }, { @@ -2520,10 +2391,6 @@ "constructor", "instantiate" ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.0" - }, "funding": [ { "url": "https://www.doctrine-project.org/sponsorship.html", @@ -2600,10 +2467,6 @@ "parser", "php" ], - "support": { - "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.1" - }, "funding": [ { "url": "https://www.doctrine-project.org/sponsorship.html", @@ -2696,10 +2559,6 @@ } ], "description": "A tool to automatically fix PHP code style", - "support": { - "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", - "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.0.0" - }, "funding": [ { "url": "https://github.com/keradus", @@ -2710,29 +2569,32 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.8.2", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91" + "reference": "1dc8d9cba3897165e16d12bb13d813afb1eb3fe7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/1dc8d9cba3897165e16d12bb13d813afb1eb3fe7", + "reference": "1dc8d9cba3897165e16d12bb13d813afb1eb3fe7", "shasum": "" }, "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" }, "provide": { + "psr/http-factory-implementation": "1.0", "psr/http-message-implementation": "1.0" }, "require-dev": { - "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + "bamarni/composer-bin-plugin": "^1.4.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.8 || ^9.3.10" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -2740,16 +2602,13 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "2.0-dev" } }, "autoload": { "psr-4": { "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2764,6 +2623,11 @@ { "name": "Tobias Schultze", "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" } ], "description": "PSR-7 message implementation that also provides common utility methods", @@ -2777,11 +2641,7 @@ "uri", "url" ], - "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.8.2" - }, - "time": "2021-04-26T09:17:50+00:00" + "time": "2021-06-30T20:03:07+00:00" }, { "name": "myclabs/deep-copy", @@ -2829,10 +2689,6 @@ "object", "object graph" ], - "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" - }, "funding": [ { "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", @@ -2875,10 +2731,6 @@ } ], "description": "JUnit XML Document generation library", - "support": { - "issues": "https://github.com/cmuench/junit-xml/issues", - "source": "https://github.com/cmuench/junit-xml/tree/1.1.0" - }, "time": "2020-12-25T09:08:58+00:00" }, { @@ -2931,10 +2783,6 @@ "parser", "php" ], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.11.0" - }, "time": "2021-07-03T13:36:55+00:00" }, { @@ -3001,10 +2849,6 @@ "phplint", "syntax" ], - "support": { - "issues": "https://github.com/overtrue/phplint/issues", - "source": "https://github.com/overtrue/phplint/tree/3.0.0" - }, "time": "2021-06-02T13:27:41+00:00" }, { @@ -3061,10 +2905,6 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/master" - }, "time": "2020-06-27T14:33:11+00:00" }, { @@ -3112,10 +2952,6 @@ } ], "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.1.0" - }, "time": "2021-02-23T14:00:09+00:00" }, { @@ -3164,10 +3000,6 @@ "keywords": [ "diff" ], - "support": { - "issues": "https://github.com/PHP-CS-Fixer/diff/issues", - "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" - }, "time": "2020-10-14T08:32:19+00:00" }, { @@ -3217,10 +3049,6 @@ "reflection", "static analysis" ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, "time": "2020-06-27T09:03:43+00:00" }, { @@ -3273,10 +3101,6 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" - }, "time": "2020-09-03T19:13:55+00:00" }, { @@ -3322,10 +3146,6 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" - }, "time": "2020-09-17T18:55:26+00:00" }, { @@ -3389,10 +3209,6 @@ "spy", "stub" ], - "support": { - "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.13.0" - }, "time": "2021-03-17T13:42:18+00:00" }, { @@ -3460,10 +3276,6 @@ "testing", "xunit" ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -3520,10 +3332,6 @@ "filesystem", "iterator" ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -3583,10 +3391,6 @@ "keywords": [ "process" ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -3642,10 +3446,6 @@ "keywords": [ "template" ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -3701,10 +3501,6 @@ "keywords": [ "timer" ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -3800,10 +3596,6 @@ "testing", "xunit" ], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.6" - }, "funding": [ { "url": "https://phpunit.de/donate.html", @@ -3860,11 +3652,60 @@ "psr", "psr-6" ], - "support": { - "source": "https://github.com/php-fig/cache/tree/master" - }, "time": "2016-08-06T20:24:11+00:00" }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "time": "2019-04-30T12:38:16+00:00" + }, { "name": "psr/http-message", "version": "1.0.1", @@ -3913,9 +3754,6 @@ "request", "response" ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/master" - }, "time": "2016-08-06T14:39:51+00:00" }, { @@ -3956,10 +3794,6 @@ } ], "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" - }, "time": "2019-03-08T08:55:37+00:00" }, { @@ -3968,12 +3802,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "fc5e5d772af47d035df8178172391259b6e30566" + "reference": "94cca8d2520d4626036c799109c278548572bdbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/fc5e5d772af47d035df8178172391259b6e30566", - "reference": "fc5e5d772af47d035df8178172391259b6e30566", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/94cca8d2520d4626036c799109c278548572bdbe", + "reference": "94cca8d2520d4626036c799109c278548572bdbe", "shasum": "" }, "conflict": { @@ -3990,13 +3824,14 @@ "bagisto/bagisto": "<0.1.5", "barrelstrength/sprout-base-email": "<1.2.7", "barrelstrength/sprout-forms": "<3.9", - "baserproject/basercms": "<4.4.5", + "baserproject/basercms": "<=4.5", "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", "bolt/bolt": "<3.7.2", "bolt/core": "<4.1.13", "brightlocal/phpwhois": "<=4.2.5", "buddypress/buddypress": "<5.1.2", "bugsnag/bugsnag-laravel": ">=2,<2.0.2", + "cachethq/cachet": "<2.5.1", "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", @@ -4006,7 +3841,7 @@ "composer/composer": "<1.10.22|>=2-alpha.1,<2.0.13", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/core": ">=2,<3.5.39", - "contao/core-bundle": ">=4,<4.4.52|>=4.5,<4.9.16|>=4.10,<4.11.5|= 4.10.0", + "contao/core-bundle": ">=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|= 4.10.0", "contao/listing-bundle": ">=4,<4.4.8", "craftcms/cms": "<3.6.7", "croogo/croogo": "<3.0.7", @@ -4023,10 +3858,10 @@ "doctrine/mongodb-odm": ">=1,<1.0.2", "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", - "dolibarr/dolibarr": "<11.0.4", + "dolibarr/dolibarr": "<14", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.80|>=8,<8.9.14|>=9,<9.0.12|>=9.1,<9.1.7", - "drupal/drupal": ">=7,<7.80|>=8,<8.9.14|>=9,<9.0.12|>=9.1,<9.1.7", + "drupal/core": ">=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", + "drupal/drupal": ">=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", "dweeves/magmi": "<=0.7.24", "endroid/qr-code-bundle": "<3.4.2", "enshrined/svg-sanitize": "<0.13.1", @@ -4049,6 +3884,7 @@ "ezyang/htmlpurifier": "<4.1.1", "facade/ignition": "<1.16.14|>=2,<2.4.2|>=2.5,<2.5.2", "feehi/cms": "<=2.1.1", + "feehi/feehicms": "<=0.1.3", "firebase/php-jwt": "<2", "flarum/core": ">=1,<=1.0.1", "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", @@ -4062,6 +3898,7 @@ "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", + "froala/wysiwyg-editor": "<3.2.7", "fuel/core": "<1.8.1", "getgrav/grav": "<=1.7.10", "getkirby/cms": "<=3.5.6", @@ -4069,7 +3906,9 @@ "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", "gree/jose": "<=2.2", "gregwar/rst": "<1.0.3", + "grumpydictator/firefly-iii": "<5.6", "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", + "helloxz/imgurl": "<=2.31", "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", "illuminate/database": "<6.20.26|>=7,<8.40", @@ -4090,18 +3929,21 @@ "laminas/laminas-http": "<2.14.2", "laravel/framework": "<6.20.26|>=7,<8.40", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", + "lavalite/cms": "<=5.8", "league/commonmark": "<0.18.3", "league/flysystem": "<1.1.4|>=2,<2.1.1", "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", "librenms/librenms": "<21.1", "livewire/livewire": ">2.2.4,<2.2.6", + "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", "magento/magento1ce": "<1.9.4.3", "magento/magento1ee": ">=1,<1.14.4.3", "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", "marcwillmann/turn": "<0.3.3", - "mautic/core": "<3.3.2|= 2.13.1", + "mautic/core": "<4|= 2.13.1", "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", + "miniorange/miniorange-saml": "<1.4.3", "mittwald/typo3_forum": "<1.2.1", "monolog/monolog": ">=1.8,<1.12", "moodle/moodle": "<3.5.17|>=3.7,<3.7.9|>=3.8,<3.8.8|>=3.9,<3.9.5|>=3.10,<3.10.2", @@ -4112,6 +3954,7 @@ "neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", + "nilsteampassnet/teampass": "<=2.1.27.36", "nukeviet/nukeviet": "<4.3.4", "nystudio107/craft-seomatic": "<3.3", "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", @@ -4119,11 +3962,12 @@ "october/cms": "= 1.1.1|= 1.0.471|= 1.0.469|>=1.0.319,<1.0.469", "october/october": ">=1.0.319,<1.0.466", "october/rain": "<1.0.472|>=1.1,<1.1.2", + "october/system": "<1.0.472|>=1.1.1,<1.1.5", "onelogin/php-saml": "<2.10.4", "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", "opencart/opencart": "<=3.0.3.2", "openid/php-openid": "<2.3", - "openmage/magento-lts": "<=19.4.12|>=20,<=20.0.8", + "openmage/magento-lts": "<19.4.15|>=20,<20.0.13", "orchid/platform": ">=9,<9.4.4", "oro/crm": ">=1.7,<1.7.4", "oro/platform": ">=1.7,<1.7.4", @@ -4133,10 +3977,10 @@ "paragonie/random_compat": "<2", "passbolt/passbolt_api": "<2.11", "paypal/merchant-sdk-php": "<3.12", - "pear/archive_tar": "<1.4.12", + "pear/archive_tar": "<1.4.14", "personnummer/personnummer": "<3.0.2", "phanan/koel": "<5.1.4", - "phpfastcache/phpfastcache": ">=5,<5.0.13", + "phpfastcache/phpfastcache": "<6.1.5|>=7,<7.1.2|>=8,<8.0.7", "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", "phpmyadmin/phpmyadmin": "<4.9.6|>=5,<5.0.3", @@ -4146,7 +3990,7 @@ "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", - "pimcore/pimcore": "<10.0.7", + "pimcore/pimcore": "<10.1.1", "pocketmine/pocketmine-mp": "<3.15.4", "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", @@ -4169,8 +4013,8 @@ "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", - "shopware/core": "<=6.4.1", - "shopware/platform": "<=6.4.1", + "shopware/core": "<=6.4.3", + "shopware/platform": "<=6.4.3", "shopware/production": "<=6.3.5.2", "shopware/shopware": "<=5.6.9", "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", @@ -4244,12 +4088,13 @@ "thelia/thelia": ">=2.1-beta.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "titon/framework": ">=0,<9.9.99", + "topthink/think": "<=6.0.9", "tribalsystems/zenario": "<8.8.53370", "truckersmp/phpwhois": "<=4.3.1", "twig/twig": "<1.38|>=2,<2.7", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.25|>=10,<10.4.14|>=11,<11.1.1", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.19|>=11,<11.3.2", "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", - "typo3/cms-core": ">=6.2,<=6.2.56|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.25|>=10,<10.4.14|>=11,<11.1.1", + "typo3/cms-core": ">=6.2,<=6.2.56|>=7,<=7.6.52|>=8,<=8.7.41|>=9,<9.5.29|>=10,<10.4.19|>=11,<11.3.2", "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", @@ -4258,9 +4103,11 @@ "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", "ua-parser/uap-php": "<3.8", "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", + "vanilla/safecurl": "<0.9.2", "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", "vrana/adminer": "<4.7.9", "wallabag/tcpdf": "<6.2.22", + "webcoast/deferred-image-processing": "<1.0.2", "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", "wp-cli/wp-cli": "<2.5", @@ -4275,7 +4122,7 @@ "yiisoft/yii2-jui": "<2.0.4", "yiisoft/yii2-redis": "<2.0.8", "yoast-seo-for-typo3/yoast_seo": "<7.2.1", - "yourls/yourls": "<1.7.4", + "yourls/yourls": "<=1.8.1", "zendesk/zendesk_api_client_php": "<2.2.11", "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", @@ -4322,10 +4169,6 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "support": { - "issues": "https://github.com/Roave/SecurityAdvisories/issues", - "source": "https://github.com/Roave/SecurityAdvisories/tree/latest" - }, "funding": [ { "url": "https://github.com/Ocramius", @@ -4336,7 +4179,7 @@ "type": "tidelift" } ], - "time": "2021-07-13T18:03:10+00:00" + "time": "2021-09-01T09:02:34+00:00" }, { "name": "sebastian/cli-parser", @@ -4382,10 +4225,6 @@ ], "description": "Library for parsing CLI options", "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -4438,10 +4277,6 @@ ], "description": "Collection of value objects that represent the PHP code units", "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -4493,10 +4328,6 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -4567,10 +4398,6 @@ "compare", "equality" ], - "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -4624,10 +4451,6 @@ ], "description": "Library for calculating the complexity of PHP code units", "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -4690,10 +4513,6 @@ "unidiff", "unified diff" ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -4753,10 +4572,6 @@ "environment", "hhvm" ], - "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -4830,10 +4645,6 @@ "export", "exporter" ], - "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -4894,10 +4705,6 @@ "keywords": [ "global state" ], - "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -4951,10 +4758,6 @@ ], "description": "Library for counting the lines of code in PHP source code", "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -5008,10 +4811,6 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -5063,10 +4862,6 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -5126,10 +4921,6 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -5181,10 +4972,6 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -5237,10 +5024,6 @@ ], "description": "Collection of value objects that represent the types of the PHP type system", "homepage": "https://github.com/sebastianbergmann/type", - "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.4" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -5290,10 +5073,6 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" - }, "funding": [ { "url": "https://github.com/sebastianbergmann", @@ -5351,29 +5130,25 @@ "phpcs", "standards" ], - "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" - }, "time": "2021-04-09T00:54:41+00:00" }, { "name": "symfony/css-selector", - "version": "v5.3.0", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "fcd0b29a7a0b1bb5bfbedc6231583d77fea04814" + "reference": "7fb120adc7f600a59027775b224c13a33530dd90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/fcd0b29a7a0b1bb5bfbedc6231583d77fea04814", - "reference": "fcd0b29a7a0b1bb5bfbedc6231583d77fea04814", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/7fb120adc7f600a59027775b224c13a33530dd90", + "reference": "7fb120adc7f600a59027775b224c13a33530dd90", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -5404,9 +5179,6 @@ ], "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.3.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -5421,7 +5193,7 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:40:38+00:00" + "time": "2021-07-21T12:38:00+00:00" }, { "name": "symfony/options-resolver", @@ -5473,9 +5245,6 @@ "configuration", "options" ], - "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.3.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -5549,9 +5318,6 @@ "portable", "shim" ], - "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -5611,9 +5377,6 @@ ], "description": "Provides a way to profile code", "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.3.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -5668,10 +5431,6 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "support": { - "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/master" - }, "funding": [ { "url": "https://github.com/theseer", @@ -5732,10 +5491,6 @@ "check", "validate" ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" - }, "time": "2021-03-09T10:59:23+00:00" } ], From e35b32fbc49264d02a139a5a793a6fd3567ef61a Mon Sep 17 00:00:00 2001 From: Caroline BUZENET Date: Tue, 15 Nov 2022 16:11:27 +0100 Subject: [PATCH 10/12] Remove not allowed addFilter method on taskSplitTestFilesByGroups example --- src/Splitter/TestFileSplitterTask.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Splitter/TestFileSplitterTask.php b/src/Splitter/TestFileSplitterTask.php index d1d4b0e..c0b318b 100644 --- a/src/Splitter/TestFileSplitterTask.php +++ b/src/Splitter/TestFileSplitterTask.php @@ -20,8 +20,6 @@ * ->testsFrom('tests/unit/Acme') * ->codeceptionRoot('projects/tested') * ->groupsTo('tests/_log/paratest_') - * ->addFilter(new Filter1()) - * ->addFilter(new Filter2()) * ->run(); * ``` * From 626c2da39172de9cfb44306f773171cda08d581c Mon Sep 17 00:00:00 2001 From: vansari Date: Sat, 17 Dec 2022 20:18:31 +0100 Subject: [PATCH 11/12] Using Makefile and Docker for a better Test Feeling --- Makefile | 31 +++++++++++++++++++++++++++++++ docker/Dockerfile | 13 +++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 Makefile create mode 100644 docker/Dockerfile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6efb163 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +.DEFAULT_GOAL := help + +mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) +current_dir := $(dir $(mkfile_path)) + +help: + @echo "Use this makefile to execute your tests in correct php version" + @echo "\tr.php-7.4\t\trun Tests with PHP 7.4" + @echo "\tr.php-8.0\t\trun Tests with PHP 8.0" + @echo "\tr.php-8.1\t\trun Tests with PHP 8.1" + @echo "\tr.php-8.2\t\trun Tests with PHP 8.2" + +r.php-7.4: + docker build -t robo:php-7.4 --target PHP74 --build-arg PHP_VERSION=7.4 docker + docker run --rm -v $(current_dir):/app -w /app robo:php-7.4 composer install + docker run --rm -v $(current_dir):/app -w /app robo:php-7.4 composer test + +r.php-8.0: + docker build -t robo:php-8.0 --target PHP8 --build-arg PHP_VERSION=8.0 docker + docker run --rm -v $(current_dir):/app -w /app robo:php-8.0 composer install + docker run --rm -v $(current_dir):/app -w /app robo:php-8.0 composer test + +r.php-8.1: + docker build -t robo:php-8.1 --target PHP8 --build-arg PHP_VERSION=8.1 docker + docker run --rm -v $(current_dir):/app -w /app robo:php-8.1 composer install + docker run --rm -v $(current_dir):/app -w /app robo:php-8.1 composer test + +r.php-8.2: + docker build -t robo:php-8.2 --target PHP8 --build-arg PHP_VERSION=8.2 docker + docker run --rm -v $(current_dir):/app -w /app robo:php-8.2 composer install + docker run --rm -v $(current_dir):/app -w /app robo:php-8.2 composer test \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..073ad7b --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,13 @@ +ARG PHP_VERSION=7.4 +FROM php:${PHP_VERSION}-cli as base +COPY --from=composer /usr/bin/composer /usr/bin/composer + +RUN apt update \ + && apt upgrade -y \ + && apt install -y apt-utils libxml2-dev libzip-dev + +FROM base as PHP74 +RUN docker-php-ext-install dom json xml zip + +FROM base as PHP8 +RUN docker-php-ext-install dom xml zip \ No newline at end of file From d91d2bf55da2a05bb6373bb7e728d2f2716e8c52 Mon Sep 17 00:00:00 2001 From: Caroline BUZENET Date: Tue, 15 Nov 2022 16:15:53 +0100 Subject: [PATCH 12/12] Max execution time for suite in final report xml and max execution time of all html reports for report.html --- src/Merger/HtmlReportMerger.php | 83 ++- src/Merger/XmlReportMergerTask.php | 22 +- tests/Merger/HtmlReportMergerTest.php | 152 +++++ tests/Merger/XmlReportMergerTaskTest.php | 26 +- .../html/expected_report_codeception5.html | 528 ++++++++++++++++++ .../reports/html/report_1_codeception5.html | 317 +++++++++++ .../reports/html/report_2_codeception5.html | 292 ++++++++++ .../reports/html/report_3_codeception5.html | 319 +++++++++++ 8 files changed, 1728 insertions(+), 11 deletions(-) create mode 100644 tests/fixtures/reports/html/expected_report_codeception5.html create mode 100644 tests/fixtures/reports/html/report_1_codeception5.html create mode 100644 tests/fixtures/reports/html/report_2_codeception5.html create mode 100644 tests/fixtures/reports/html/report_3_codeception5.html diff --git a/src/Merger/HtmlReportMerger.php b/src/Merger/HtmlReportMerger.php index 88f198d..a2c0066 100644 --- a/src/Merger/HtmlReportMerger.php +++ b/src/Merger/HtmlReportMerger.php @@ -50,7 +50,20 @@ class HtmlReportMerger extends AbstractMerger protected bool $previousLibXmlUseErrors = false; - private float $executionTimeSum = 0; + protected bool $maxTime = false; + + protected array $executionTime = []; + + /** + * @var string|float + */ + private $executionTimeSum = 0; + + + public function maxTime(): void + { + $this->maxTime = true; + } /** * HtmlReportMerger constructor. @@ -198,9 +211,10 @@ private function countExecutionTime(DOMDocument $dstFile): void if (!$nodeList) { throw XPathExpressionException::malformedXPath($xpathHeadline); } - + $hoursMinutesSeconds = '(([0-1]?\d|2[0-3])(?::([0-5]?\d))?(?::([0-5]?\d))\.\d+)'; + $seconds = '\d+\.\d+s'; $pregResult = preg_match( - '#^Codeception Results .* \((?\d+\.\d+)s\)$#', + "#^Codeception Results .* \((?$hoursMinutesSeconds|$seconds)\)$#", $nodeList[0]->nodeValue, $matches ); @@ -213,7 +227,18 @@ private function countExecutionTime(DOMDocument $dstFile): void return; } - $this->executionTimeSum += (float)$matches['timesum']; + if (str_contains($matches['timesum'], 's')) { + $matches['timesum'] = str_replace('s', '', $matches['timesum']); + } + if (!$this->maxTime) { + if (str_contains($matches['timesum'], ':')) { + $this->executionTimeSum = $this->sumTime(strval($this->executionTimeSum), (string)$matches['timesum']); + } else { + $this->executionTimeSum += (float)$matches['timesum']; + } + } else { + $this->executionTime[] = (string)$matches['timesum']; + } } /** @@ -238,8 +263,20 @@ private function updateHeaderLine(DOMDocument $dstFile): void $statusNode->nodeValue = 'FAILED'; $statusAttr->value = 'color: red'; } - - $executionTimeNode->nodeValue = sprintf(' (%ss)', $this->executionTimeSum); + if (!$this->maxTime) { + $executionTime = (string)$this->executionTimeSum; + } else { + usort($this->executionTime, function ($a, $b) { + return strcmp($a, $b); + }); + $executionTime = max($this->executionTime); + } + $executionTimeNode->nodeValue = sprintf( + (preg_match('#([0-1]?\d|2[0-3])(?::([0-5]?\d))?(?::([0-5]?\d))\.\d+#', $executionTime)) + ? ' (%s)' + : ' (%ss)', + $executionTime + ); } /** @@ -342,4 +379,38 @@ private function updateButtons(DOMDocument $dstFile): void $table->setAttribute('id', "stepContainer" . $n); } } + + private function sumTime(string $time1, string $time2): string + { + $times = [$time1, $time2]; + $seconds = 0; + $milliseconds = 0; + $isHour = false; + foreach ($times as $time) { + if ($time !== '0') { + $output = explode(':', $time); + if (count($output) > 2) { + $isHour = true; + [$hour, $minute, $second] = $output; + $seconds += $hour * 3600; + } else { + [$minute, $second] = $output; + } + $seconds += $minute * 60; + [$second, $millisecond] = explode('.', $second); + $seconds += $second; + $milliseconds += $millisecond; + } + } + if ($isHour) { + $hours = floor($seconds / 3600); + $seconds -= $hours * 3600; + } + $minutes = floor($seconds / 60); + $seconds -= $minutes * 60; + + return $isHour + ? sprintf('%02d:%02d:%02d.%02d', $hours, $minutes, $seconds, $milliseconds) + : sprintf('%02d:%02d.%02d', $minutes, $seconds, $milliseconds); + } } diff --git a/src/Merger/XmlReportMergerTask.php b/src/Merger/XmlReportMergerTask.php index d8d88e6..fcbc5b1 100644 --- a/src/Merger/XmlReportMergerTask.php +++ b/src/Merger/XmlReportMergerTask.php @@ -18,8 +18,10 @@ class XmlReportMergerTask extends AbstractMerger protected array $src = []; protected string $dst = ''; + protected array $suiteDuration = []; protected bool $summarizeTime = true; + protected bool $maxSuiteTime = false; protected bool $mergeRewrite = false; @@ -36,6 +38,12 @@ public function maxTime(): void $this->summarizeTime = false; } + public function maxSuiteTime(): void + { + $this->summarizeTime = false; + $this->maxSuiteTime = true; + } + public function mergeRewrite(): self { $this->mergeRewrite = true; @@ -111,6 +119,7 @@ public function run(): void protected function loadSuites(DOMElement $current): void { + $this->suiteDuration[$current->getAttribute('name')][] = (float) $current->getAttribute('time'); /** @var DOMNode $node */ foreach ($current->childNodes as $node) { if ($node instanceof DOMElement) { @@ -136,13 +145,20 @@ protected function mergeSuites(DOMDocument $dstXml): void 'errors' => 0, 'time' => 0, ]; + foreach ($tests as $test) { $resultNode->appendChild($test); $data['assertions'] += (int)$test->getAttribute('assertions'); - $data['time'] = $this->summarizeTime - ? ((float)$test->getAttribute('time') + $data['time']) - : max($test->getAttribute('time'), $data['time']); + if ($this->summarizeTime) { + $data['time'] = ((float)$test->getAttribute('time') + $data['time']); + } else { + if ($this->maxSuiteTime) { + $data['time'] = max($this->suiteDuration[$suiteName]); + } else { + $data['time'] = max($test->getAttribute('time'), $data['time']); + } + } $data['failures'] += $test->getElementsByTagName('failure')->length; $data['errors'] += $test->getElementsByTagName('error')->length; diff --git a/tests/Merger/HtmlReportMergerTest.php b/tests/Merger/HtmlReportMergerTest.php index d3df126..f5be1f5 100644 --- a/tests/Merger/HtmlReportMergerTest.php +++ b/tests/Merger/HtmlReportMergerTest.php @@ -62,4 +62,156 @@ public function testRun(): void $this->assertSame($expectedTimeInSeconds, (float)$matches['timesum']); } + + /** + * @covers ::run + */ + public function testRunWithCodeception5Reports(): void + { + $expectedTimeInSeconds = '03:34.98'; + $expectedSuccess= 3; + + $reportPath = TEST_PATH . '/fixtures/reports/html/'; + $task = new HtmlReportMerger(); + $task->setLogger(new Logger(new NullOutput())); + + $resultReport = TEST_PATH . '/result/report_codeception5.html'; + $task + ->from( + [ + $reportPath . 'report_0_codeception5.html', // this file did not exists and it should not fail + $reportPath . 'report_1_codeception5.html', + $reportPath . 'report_2_codeception5.html', + $reportPath . 'report_3_codeception5.html', + ] + ) + ->into($resultReport) + ->run(); + + $this->assertFileExists($resultReport); + + //read first source file as main + $dstHTML = new DOMDocument(); + $dstHTML->loadHTMLFile($resultReport, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); + /** @var DOMNodeList $values */ + $values = (new DOMXPath($dstHTML)) + ->query("//*[contains(@class,'scenarioSuccessValue')]"); + + $this->assertCount(1, $values); + $this->assertSame($expectedSuccess, (int)$values[0]->nodeValue); + + $values = (new DOMXPath($dstHTML)) + ->query("//h1[text() = 'Codeception Results ']"); + preg_match( + '#^Codeception Results .* \((?(([0-1]?\d|2[0-3])(?::([0-5]?\d))?(?::([0-5]?\d))\.\d+))\)$#', + $values[0]->nodeValue, + $matches + ); + + $this->assertSame($expectedTimeInSeconds, (string)$matches['timesum']); + } + + /** + * @covers ::run + */ + public function testRunMaxTimeReports(): void + { + $expectedTime = '129.25'; + $expectedSuccess= 3; + + $reportPath = TEST_PATH . '/fixtures/reports/html/'; + $task = new HtmlReportMerger(); + $task->setLogger(new Logger(new NullOutput())); + + $resultReport = TEST_PATH . '/result/report_max_time.html'; + $task->maxTime(); + $task + ->from( + [ + $reportPath . 'report_0.html', // this file did not exists and it should not fail + $reportPath . 'report_1.html', + $reportPath . 'report_2.html', + $reportPath . 'report_3.html', + ] + ) + ->into($resultReport) + ->run(); + + $this->assertFileExists($resultReport); + + //read first source file as main + $dstHTML = new DOMDocument(); + $dstHTML->loadHTMLFile($resultReport, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); + /** @var DOMNodeList $values */ + $values = (new DOMXPath($dstHTML)) + ->query("//*[contains(@class,'scenarioSuccessValue')]"); + + $this->assertCount(1, $values); + $this->assertSame($expectedSuccess, (int)$values[0]->nodeValue); + + $values = (new DOMXPath($dstHTML)) + ->query("//h1[text() = 'Codeception Results ']"); + preg_match( + '#^Codeception Results .* \((?\d+\.\d+)s\)$#', + $values[0]->nodeValue, + $matches + ); + $executionTime[] = (string)$matches['timesum']; + usort($executionTime, function ($a, $b) { + return strcmp($a, $b); + }); + $this->assertSame($expectedTime, max($executionTime)); + } + + /** + * @covers ::run + */ + public function testRunMaxTimeWithCodeception5Reports(): void + { + $expectedTime = '02:09.25'; + $expectedSuccess= 3; + + $reportPath = TEST_PATH . '/fixtures/reports/html/'; + $task = new HtmlReportMerger(); + $task->setLogger(new Logger(new NullOutput())); + + $resultReport = TEST_PATH . '/result/report_codeception5_max_time.html'; + $task->maxTime(); + $task + ->from( + [ + $reportPath . 'report_0_codeception5.html', // this file did not exists and it should not fail + $reportPath . 'report_1_codeception5.html', + $reportPath . 'report_2_codeception5.html', + $reportPath . 'report_3_codeception5.html', + ] + ) + ->into($resultReport) + ->run(); + + $this->assertFileExists($resultReport); + + //read first source file as main + $dstHTML = new DOMDocument(); + $dstHTML->loadHTMLFile($resultReport, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); + /** @var DOMNodeList $values */ + $values = (new DOMXPath($dstHTML)) + ->query("//*[contains(@class,'scenarioSuccessValue')]"); + + $this->assertCount(1, $values); + $this->assertSame($expectedSuccess, (int)$values[0]->nodeValue); + + $values = (new DOMXPath($dstHTML)) + ->query("//h1[text() = 'Codeception Results ']"); + preg_match( + '#^Codeception Results .* \((?(([0-1]?\d|2[0-3])(?::([0-5]?\d))?(?::([0-5]?\d))\.\d+))\)$#', + $values[0]->nodeValue, + $matches + ); + $executionTime[] = (string)$matches['timesum']; + usort($executionTime, function ($a, $b) { + return strcmp($a, $b); + }); + $this->assertSame($expectedTime, max($executionTime)); + } } diff --git a/tests/Merger/XmlReportMergerTaskTest.php b/tests/Merger/XmlReportMergerTaskTest.php index 9cf40cd..22416bc 100644 --- a/tests/Merger/XmlReportMergerTaskTest.php +++ b/tests/Merger/XmlReportMergerTaskTest.php @@ -26,11 +26,11 @@ public function testMergeReports(): void $this->assertFileExists(TEST_PATH . '/result/merged.xml'); $xml = file_get_contents(TEST_PATH . '/result/merged.xml'); $this->assertStringContainsString( - '', $xml ); $this->assertStringContainsString( - '', $xml ); $this->assertStringContainsString( @@ -45,6 +45,28 @@ public function testMergeReports(): void ); } + public function testMergeReportsMaxSuiteTime(): void + { + $task = new XmlReportMergerTask(); + $task->setLogger(new Logger(new NullOutput())); + $task->maxSuiteTime(); + $task->from(TEST_PATH . '/fixtures/result1.xml') + ->from(TEST_PATH . '/fixtures/result2.xml') + ->into(TEST_PATH . '/result/merged.xml') + ->run(); + + $this->assertFileExists(TEST_PATH . '/result/merged.xml'); + $xml = file_get_contents(TEST_PATH . '/result/merged.xml'); + $this->assertStringContainsString( + '', + $xml + ); + $this->assertStringContainsString( + '', + $xml + ); + } + public function testMergeRewriteReports(): void { $task = new XmlReportMergerTask(); diff --git a/tests/fixtures/reports/html/expected_report_codeception5.html b/tests/fixtures/reports/html/expected_report_codeception5.html new file mode 100644 index 0000000..0c496f3 --- /dev/null +++ b/tests/fixtures/reports/html/expected_report_codeception5.html @@ -0,0 +1,528 @@ + + + Test results + + + + + + + + + + +
+

Codeception Results OK (234.98s)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Acceptance (cloud-stage) Tests

+
+

+ + ExpleogroupCest » Student apply expleogroup and + choose interest 103.29s

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ I acting as "Vincenzo" +

+ +

+ I set locale "fr"

+ +

+ I visit "Page\Applications\ApplicationFormPage","","appsource=expleogroup" +

+ +

+ Page\Applications\ApplicationFormPage: start + application {"title":"La première étape de votre candidature","button":"Commencer"} +

+ +

+ Page\Applications\ApplicationFormPage: fill + personal details {"title":"Votre profil","birthdate":"Votre date de naissance","address":"Votre adresse","gender":"Votre genre"},{"gender":"Masculin","address":"7 cité paradis PARIS"} +

+ +

+ Page\Applications\ApplicationFormPage: fill + education {"title":"Vos études","education":"","diploma":"Quel est votre niveau de diplôme le plus élevé ?","frenchLevel":"","englishLevel":"Quel est votre niveau d’anglais ?"},{"diploma":"Bac+2","englishLevel":"Intermédiaire (B1-B2)"} +

+ +

+ Page\Applications\ApplicationFormPage: fill + learning resources {"title":"La formation en ligne et vous","followedCourses":"Avez-vous déjà suivi des cours en ligne ?","followedCoursesSubject":"Sur quels sujets et sur quels sites ?","resources":"Pour cette formation, vous aurez accès à :"},{"followedCourses":"Oui","followedCoursesSubject":"Coursera","resources":["Un endroit calme","Un ordinateur","Un micro"]} +

+ +

+ Page\Applications\ApplicationFormPage: fill + motivation {"title":"Votre nouvelle carrière","professionalProject":"Détaillez votre projet professionnel (à court, moyen et long-terme)","cv":"Ajoutez votre CV","linkedin":"","foundEmployer":"","desiredStartDate":"","nextButton":"Envoyer la candidature"},{"cv":"cv.pdf"} +

+ +

+ Page\Applications\ApplicationFormPage: see + application end {"title":"Merci de votre intérêt pour nos formations !","button":"RETOUR À L’ACCUEIL"} +

+ +
+
+

Api (cloud-stage) Tests

+
+

+ + AnalyticsCest » Get analytics with paths code + 2.44s

+
+ + + + + + + + + + + + + +

+ I acting as "Business\Users\BotAdmin" +

+ +

+ I get analytics "PATHS",[],"0-1000" +

+ +

+ I see analytics "PATHS" +

+ +
+ + +
+

Bdd (cloud-stage) Tests

+
+

+ + Course » Member can follow a course and pass a + quiz 129.25s

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    As a member +
    I want to follow a + course and pass a quiz
    In order to make + progress on the platform

+ Given i am "member"

+ +

+ When i choose a course

+ +

+ And i follow a course

+ +

+ And i pass a quiz

+ +

+ Then i see that i have followed the course

+ +

+ And i see that i have passed the quiz

+ +
+ + +
+

Summary

+
+ + + + + + + + + + + + + + + + + +
Successful scenarios:3
Failed scenarios:0
Skipped scenarios:0
Incomplete scenarios:0
+
+
+
+ + diff --git a/tests/fixtures/reports/html/report_1_codeception5.html b/tests/fixtures/reports/html/report_1_codeception5.html new file mode 100644 index 0000000..3073123 --- /dev/null +++ b/tests/fixtures/reports/html/report_1_codeception5.html @@ -0,0 +1,317 @@ + + + Test results + + + + + + + + + + +
+

Codeception Results OK (01:23.29)

+ + + + + + + + + + + + + + + +
+

Acceptance (cloud-stage) Tests

+
+

+ + ExpleogroupCest » Student apply expleogroup and choose interest 103.29s

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ I acting as "Vincenzo"

+ +

+ I set locale "fr"

+ +

+ I visit "Page\Applications\ApplicationFormPage","","appsource=expleogroup"

+ +

+ Page\Applications\ApplicationFormPage: start application {"title":"La première étape de votre candidature","button":"Commencer"}

+ +

+ Page\Applications\ApplicationFormPage: fill personal details {"title":"Votre profil","birthdate":"Votre date de naissance","address":"Votre adresse","gender":"Votre genre"},{"gender":"Masculin","address":"7 cité paradis PARIS"}

+ +

+ Page\Applications\ApplicationFormPage: fill education {"title":"Vos études","education":"","diploma":"Quel est votre niveau de diplôme le plus élevé ?","frenchLevel":"","englishLevel":"Quel est votre niveau d’anglais ?"},{"diploma":"Bac+2","englishLevel":"Intermédiaire (B1-B2)"}

+ +

+ Page\Applications\ApplicationFormPage: fill learning resources {"title":"La formation en ligne et vous","followedCourses":"Avez-vous déjà suivi des cours en ligne ?","followedCoursesSubject":"Sur quels sujets et sur quels sites ?","resources":"Pour cette formation, vous aurez accès à :"},{"followedCourses":"Oui","followedCoursesSubject":"Coursera","resources":["Un endroit calme","Un ordinateur","Un micro"]}

+ +

+ Page\Applications\ApplicationFormPage: fill motivation {"title":"Votre nouvelle carrière","professionalProject":"Détaillez votre projet professionnel (à court, moyen et long-terme)","cv":"Ajoutez votre CV","linkedin":"","foundEmployer":"","desiredStartDate":"","nextButton":"Envoyer la candidature"},{"cv":"cv.pdf"}

+ +

+ Page\Applications\ApplicationFormPage: see application end {"title":"Merci de votre intérêt pour nos formations !","button":"RETOUR À L’ACCUEIL"}

+ +
+
+

Summary

+
+ + + + + + + + + + + + + + + + + +
Successful scenarios:1
Failed scenarios:0
Skipped scenarios:0
Incomplete scenarios:0
+
+
+
+ + diff --git a/tests/fixtures/reports/html/report_2_codeception5.html b/tests/fixtures/reports/html/report_2_codeception5.html new file mode 100644 index 0000000..8bb50e2 --- /dev/null +++ b/tests/fixtures/reports/html/report_2_codeception5.html @@ -0,0 +1,292 @@ + + + Test results + + + + + + + + + + +
+

Codeception Results OK (00:02.44)

+ + + + + + + + + + + + + + + + + + + + +
+

Api (cloud-stage) Tests

+
+

+ + AnalyticsCest » Get analytics with paths code 2.44s

+
+ + + + + + + + + + + + + +

+ I acting as "Business\Users\BotAdmin"

+ +

+ I get analytics "PATHS",[],"0-1000"

+ +

+ I see analytics "PATHS"

+ +
+ + +
+

Summary

+
+ + + + + + + + + + + + + + + + + +
Successful scenarios:1
Failed scenarios:0
Skipped scenarios:0
Incomplete scenarios:0
+
+
+
+ + diff --git a/tests/fixtures/reports/html/report_3_codeception5.html b/tests/fixtures/reports/html/report_3_codeception5.html new file mode 100644 index 0000000..bffa76b --- /dev/null +++ b/tests/fixtures/reports/html/report_3_codeception5.html @@ -0,0 +1,319 @@ + + + Test results + + + + + + + + + + +
+

Codeception Results OK (02:09.25)

+ + + + + + + + + + + + + + + + + + + + + +
+

Bdd (cloud-stage) Tests

+
+

+ + Course » Member can follow a course and pass a quiz 129.25s

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    As a member
    I want to follow a course and pass a quiz
    In order to make progress on the platform

+ Given i am "member"

+ +

+ When i choose a course

+ +

+ And i follow a course

+ +

+ And i pass a quiz

+ +

+ Then i see that i have followed the course

+ +

+ And i see that i have passed the quiz

+ +
+ + +
+

Summary

+
+ + + + + + + + + + + + + + + + + +
Successful scenarios:1
Failed scenarios:0
Skipped scenarios:0
Incomplete scenarios:0
+
+
+
+ +