Skip to content

Commit

Permalink
Refactored to have a consistent interface.
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexSkrypnyk committed Jan 19, 2025
1 parent 7846775 commit 328aee8
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,13 @@ public function __construct(
*/
public function initializeContext(Context $context): void {
if ($context instanceof ScreenshotAwareContextInterface) {
$dir = $this->resolveScreenshotDir();
$dir = getenv('BEHAT_SCREENSHOT_DIR') ?: $this->dir;

if ($this->shouldPurge() && $this->needsPurging) {
$this->purgeFilesInDir($dir);
if ((getenv('BEHAT_SCREENSHOT_PURGE') || $this->purge) && $this->needsPurging) {
$fs = new Filesystem();
if ($fs->exists($dir)) {
$fs->remove((new Finder())->files()->in($dir));
}
$this->needsPurging = FALSE;
}

Expand All @@ -74,43 +77,4 @@ public function initializeContext(Context $context): void {
}
}

/**
* Remove files in directory.
*
* @param string $dir
* Directory to purge files in.
*/
protected function purgeFilesInDir(string $dir): void {
$fs = new Filesystem();
$finder = new Finder();
if ($fs->exists($dir)) {
$fs->remove($finder->files()->in($dir));
}
}

/**
* Resolve directory using one of supported paths.
*
* @return string
* Path to the screenshots directory.
*/
protected function resolveScreenshotDir(): string {
$dir = getenv('BEHAT_SCREENSHOT_DIR');
if (!empty($dir)) {
return $dir;
}

return $this->dir;
}

/**
* Decide if 'purge' flag was set.
*
* @return bool
* TRUE if should purge, FALSE otherwise.
*/
protected function shouldPurge(): bool {
return getenv('BEHAT_SCREENSHOT_PURGE') || $this->purge;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,30 @@ interface ScreenshotAwareContextInterface extends Context {
*/
public function setScreenshotParameters(string $dir, bool $fail, string $fail_prefix, string $filename_pattern, string $filename_pattern_failed, array $info_types): static;

/**
* Save screenshot content into a file.
*
* @param array<string,mixed> $options
* Contextual options.
*/
public function iSaveScreenshot(array $options): void;

/**
* Adds information to context.
*
* @param string $label
* Debug information label.
* @param string $value
* Debug information value.
*/
public function appendInfo(string $label, string $value): void;

/**
* Render information.
*
* @return string
* Rendered debug information.
*/
public function renderInfo(): string;

}
136 changes: 54 additions & 82 deletions src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,25 @@ public function setScreenshotParameters(string $dir, bool $fail, string $fail_pr
return $this;
}

/**
* Get screenshot directory.
*
* @return string
* Screenshot directory.
*/
public function getDir(): string {
return $this->dir;
}

/**
* Init values required for screenshots.
*
* @param \Behat\Behat\Hook\Scope\BeforeScenarioScope $scope
* Scenario scope.
*
* @BeforeScenario
* @BeforeScenario @javascript
*/
public function beforeScenarioInit(BeforeScenarioScope $scope): void {
if (!$scope->getScenario()->hasTag('javascript')) {
return;
}

$driver = $this->getSession()->getDriver();

try {
Expand Down Expand Up @@ -130,33 +136,25 @@ public function beforeStepInit(BeforeStepScope $scope): void {
*/
public function printLastResponseOnError(AfterStepScope $event): void {
if (!$event->getTestResult()->isPassed() && $this->fail) {
$this->iSaveScreenshot(TRUE);
$this->iSaveScreenshot(['is_failure' => TRUE]);
}
}

/**
* Save screenshot content into a file.
*
* @param bool $is_failure
* Denotes if this was called in a context of the failed
* test.
* @param string|null $filename
* File name.
*
* @throws \Behat\Mink\Exception\DriverException
* @throws \Behat\Mink\Exception\UnsupportedDriverActionException
* {@inheritdoc}
*
* @When save screenshot
* @When I save screenshot
* @Then save screenshot
*/
public function iSaveScreenshot(bool $is_failure = FALSE, ?string $filename = NULL): void {
$file_name = $this->makeFileName('html', $filename, $is_failure);
public function iSaveScreenshot(array $options = []): void {
$filename = isset($options['filename']) && is_scalar($options['filename']) ? strval($options['filename']) : NULL;
$is_failure = isset($options['is_failure']) && is_scalar($options['is_failure']) && $options['is_failure'];

$driver = $this->getSession()->getDriver();
$info = $this->renderInfo();

try {
$driver = $this->getSession()->getDriver();
$content = $driver->getContent();

$info = $this->renderInfo();
$content = empty($info) ? $content : nl2br($info) . "<hr/>\n" . $content;
}
catch (DriverException) {
Expand All @@ -165,25 +163,26 @@ public function iSaveScreenshot(bool $is_failure = FALSE, ?string $filename = NU
return;
}

$this->saveScreenshotContent($file_name, $content);
$filename_html = $this->makeFileName('html', $filename, $is_failure);
$this->saveScreenshotContent($filename_html, $content);

// Drivers that do not support making screenshots, including Goutte
// driver that is shipped with Behat, throw exception. For such drivers,
// driver which is shipped with Behat, throw exception. For such drivers,
// screenshot stored as an HTML page (without referenced assets).
try {
$driver = $this->getSession()->getDriver();
$content = $driver->getScreenshot();
// Preserve filename, but change the extension - this is to group
// content and screenshot files together by name.
$file_name = $this->makeFileName('png', $filename, $is_failure);
$this->saveScreenshotContent($file_name, $content);
}
// @codeCoverageIgnoreStart
catch (UnsupportedDriverActionException) {
// Nothing to do here - drivers without support for screenshots
// simply do not have them created.
return;
}
// @codeCoverageIgnoreEnd
// Re-create the filename with a different extension to group content
// and screenshot files together by name.
$filename_png = $this->makeFileName('png', $filename, $is_failure);
$this->saveScreenshotContent($filename_png, $content);
}

/**
Expand All @@ -196,9 +195,10 @@ public function iSaveScreenshot(bool $is_failure = FALSE, ?string $filename = NU
* @throws \Behat\Mink\Exception\UnsupportedDriverActionException
*
* @When I save screenshot with name :filename
* @Then save screenshot with name :filename
*/
public function iSaveScreenshotWithName(string $filename): void {
$this->iSaveScreenshot(FALSE, $filename);
$this->iSaveScreenshot(['filename' => $filename]);
}

/**
Expand All @@ -212,8 +212,8 @@ public function iSaveScreenshotWithName(string $filename): void {
* @throws \Behat\Mink\Exception\DriverException
* @throws \Behat\Mink\Exception\UnsupportedDriverActionException
*
* @When save :width x :height screenshot
* @When I save :width x :height screenshot
* @Then save :width x :height screenshot
*/
public function iSaveSizedScreenshot(string|int $width = 1440, string|int $height = 900): void {
try {
Expand All @@ -226,6 +226,22 @@ public function iSaveSizedScreenshot(string|int $width = 1440, string|int $heigh
$this->iSaveScreenshot();
}

/**
* Save screenshot content into a file.
*
* @param string $filename
* File name to write.
* @param string $content
* Content to write into a file.
*/
public function saveScreenshotContent(string $filename, string $content): void {
(new Filesystem())->mkdir($this->dir, 0755);
$success = file_put_contents($this->dir . DIRECTORY_SEPARATOR . $filename, $content);
if ($success === FALSE) {
throw new \RuntimeException(sprintf('Failed to save screenshot to %s', $filename));
}
}

/**
* Get before step scope.
*
Expand All @@ -237,22 +253,14 @@ public function getBeforeStepScope(): BeforeStepScope {
}

/**
* Adds information to context.
*
* @param string $label
* Debug information label.
* @param string $value
* Debug information value.
* {@inheritdoc}
*/
public function appendInfo(string $label, string $value): void {
$this->info[$label] = $value;
}

/**
* Render information.
*
* @return string
* Rendered debug information.
* {@inheritdoc}
*/
public function renderInfo(): string {
$this->compileInfo();
Expand Down Expand Up @@ -286,16 +294,6 @@ protected function compileInfo(): void {
}
}

/**
* Get screenshot directory.
*
* @return string
* Screenshot directory.
*/
public function getDir(): string {
return $this->dir;
}

/**
* Get current timestamp.
*
Expand All @@ -304,36 +302,10 @@ public function getDir(): string {
*
* @codeCoverageIgnore
*/
public function getCurrentTime(): int {
protected function getCurrentTime(): int {
return time();
}

/**
* Save screenshot content into a file.
*
* @param string $filename
* File name to write.
* @param string $content
* Content to write into a file.
*/
protected function saveScreenshotContent(string $filename, string $content): void {
$this->prepareDir($this->dir);
$success = file_put_contents($this->dir . DIRECTORY_SEPARATOR . $filename, $content);
if ($success === FALSE) {
throw new \RuntimeException(sprintf('Failed to save screenshot to %s', $filename));
}
}

/**
* Prepare directory.
*
* @param string $dir
* Name of preparing directory.
*/
protected function prepareDir(string $dir): void {
(new Filesystem())->mkdir($dir, 0755);
}

/**
* Make screenshot filename.
*
Expand Down Expand Up @@ -385,12 +357,12 @@ protected function makeFileName(string $ext, ?string $filename = NULL, bool $is_

$data = [
'ext' => $ext,
'step_name' => $step->getText(),
'step_line' => $step->getLine(),
'fail_prefix' => $this->failPrefix,
'feature_file' => $feature->getFile(),
'url' => $url,
'step_line' => $step->getLine(),
'step_name' => $step->getText(),
'timestamp' => $this->getCurrentTime(),
'fail_prefix' => $this->failPrefix,
'url' => $url,
];

return Tokenizer::replaceTokens($filename, $data);
Expand Down

0 comments on commit 328aee8

Please sign in to comment.