Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions behat_ibexa_oss.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ default:

Liuggio\Fastest\Behat\ListFeaturesExtension\Extension: ~

suites: ~

regression:
suites:
setup-oss:
Expand Down
41 changes: 40 additions & 1 deletion src/lib/Browser/Context/DebuggingContext.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?php

Check warning on line 1 in src/lib/Browser/Context/DebuggingContext.php

View workflow job for this annotation

GitHub Actions / Run code style check (8.3)

Found violation(s) of type: blank_line_before_statement

Check warning on line 1 in src/lib/Browser/Context/DebuggingContext.php

View workflow job for this annotation

GitHub Actions / Run code style check (8.3)

Found violation(s) of type: no_extra_blank_lines

Check warning on line 1 in src/lib/Browser/Context/DebuggingContext.php

View workflow job for this annotation

GitHub Actions / Run code style check (8.3)

Found violation(s) of type: no_unused_imports

Check warning on line 1 in src/lib/Browser/Context/DebuggingContext.php

View workflow job for this annotation

GitHub Actions / Run code style check (8.3)

Found violation(s) of type: class_attributes_separation

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
Expand All @@ -18,6 +18,7 @@
use Ibexa\Behat\Core\Log\KnownIssuesRegistry;
use Ibexa\Behat\Core\Log\TestLogProvider;
use Psr\Log\LoggerInterface;
use function RectorPrefix202508\Symfony\Component\String\s;

class DebuggingContext extends RawMinkContext
{
Expand Down Expand Up @@ -77,30 +78,68 @@
$this->failedStepResult = $scope->getTestResult();
}



/** @AfterStep */
public function getLogsAfterFailedStep(AfterStepScope $scope)
{
if ($scope->getTestResult()->getResultCode() !== TestResult::FAILED) {
return;
}

$filename = $this->takeScreenshot($scope);
$testLogProvider = new TestLogProvider($this->getSession(), $this->logDir);
$applicationsLogs = $testLogProvider->getApplicationLogs();
$browserLogs = $testLogProvider->getBrowserLogs();

$failureData = new TestFailureData(
$this->failedStepResult,
$applicationsLogs,
$browserLogs
$browserLogs,
$filename
);

$failureAnalysisResult = $this->knownIssuesRegistry->isKnown($failureData);
if ($failureAnalysisResult->isKnownFailure()) {
$this->display(sprintf("Known failure detected! JIRA: %s\n\n", $failureAnalysisResult->getJiraReference()));
}


$this->display($this->formatForDisplay($browserLogs, 'JS Console errors:'));
$this->display($this->formatForDisplay($applicationsLogs, 'Application logs:'));
$this->display($this->formatForDisplay($filename ? [$filename] : [], 'Screenshot:'));
$this->display($this->formatForDisplay($filename ? ['file://' . realpath($filename)] : [], 'Screenshot:'));
}

private function takeScreenshot(AfterStepScope $scope): string
{
// Use GITHUB_WORKSPACE if available, fallback to /tmp
$workspace = getenv('GITHUB_WORKSPACE') ?: getcwd();
$screenshotDir = $workspace . '/build/project/behat-output';
$this->logger->error(sprintf('Screenshot dir should be: %s', $screenshotDir));

// Ensure screenshot directory exists
if (!is_dir($screenshotDir)) {
$this->logger->error(sprintf('Screenshot directory does not exist, creating: %s', $screenshotDir));
if (!mkdir($screenshotDir, 0777, true) && !is_dir($screenshotDir)) {
$this->logger->error(sprintf('Failed to create screenshot directory: %s', $screenshotDir));
return '';
}
$this->logger->error(sprintf('Screenshot directory created: %s', $screenshotDir));
} else {
$this->logger->error(sprintf('Screenshot directory already exists: %s', $screenshotDir));
}

$scenarioTitle = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $scope->getFeature()->getTitle() . '_' . $scope->getStep()->getText());
$filename = sprintf('%s/%s_%s.png', $screenshotDir, date('Ymd_His'), $scenarioTitle);

$result = file_put_contents($filename, $this->getSession()->getScreenshot());
if ($result === false) {
$this->logger->error(sprintf('Failed to save screenshot at: %s', $filename));
return '';
}
$this->logger->error(sprintf('Screenshot saved at: %s', realpath($filename)));
return $filename;
}

private function formatForDisplay(array $logEntries, string $sectionName)
Expand Down
10 changes: 9 additions & 1 deletion src/lib/Core/Log/Failure/TestFailureData.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?php

Check warning on line 1 in src/lib/Core/Log/Failure/TestFailureData.php

View workflow job for this annotation

GitHub Actions / Run code style check (8.3)

Found violation(s) of type: no_whitespace_in_blank_line

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
Expand All @@ -20,12 +20,15 @@

/** @var string[] */
private $browserLogs;

private $screenshotPath;

public function __construct(ExceptionResult $failedStepResult, array $applicationLogs, array $browserLogs)
public function __construct(ExceptionResult $failedStepResult, array $applicationLogs, array $browserLogs, $screenshotPath = null)
{
$this->failedStepResult = $failedStepResult;
$this->applicationLogs = $applicationLogs;
$this->browserLogs = $browserLogs;
$this->screenshotPath = $screenshotPath;
}

public function getFailedStepsResult(): ExceptionResult
Expand All @@ -49,6 +52,11 @@
return $this->browserLogs;
}

public function getScreenshotPath()
{
return $this->screenshotPath;
}

public function applicationLogContainsFragment($logFragment)
{
foreach ($this->getApplicationLogs() as $logEntry) {
Expand Down
48 changes: 48 additions & 0 deletions src/lib/Subscriber/ScreenshotListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Behat\Subscriber;

use Behat\Behat\EventDispatcher\Event\StepTested;
use Behat\Mink\Mink;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ScreenshotListener implements EventSubscriberInterface
{
private $mink;

public function __construct(Mink $mink)
{
$this->mink = $mink;
}

public static function getSubscribedEvents(): array
{
return [
StepTested::AFTER => ['takeScreenshotOnFailure', -10],
];
}

public function takeScreenshotOnFailure(StepTested $event): void
{
if ($event->getTestResult()->isPassed()) {
return;
}

$session = $this->mink->getSession('panther');
if ($session->isStarted()) {
$screenshot = $session->getScreenshot();
$dir = '/app/tests/_output';
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
}
$filename = $dir . '/screenshot_' . uniqid() . '.png';
file_put_contents($filename, $screenshot);
}
}
}
Loading