From 4894bc1f714a6d3ec8230454370c519027a13ca8 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sun, 19 Jan 2025 11:08:47 +1100 Subject: [PATCH] Refactored to have a consistent interface. --- .../ScreenshotContextInitializer.php | 48 +------ .../ScreenshotAwareContextInterface.php | 26 ++++ .../Context/ScreenshotContext.php | 136 +++++++----------- 3 files changed, 86 insertions(+), 124 deletions(-) diff --git a/src/DrevOps/BehatScreenshotExtension/Context/Initializer/ScreenshotContextInitializer.php b/src/DrevOps/BehatScreenshotExtension/Context/Initializer/ScreenshotContextInitializer.php index b912ab2..417f147 100644 --- a/src/DrevOps/BehatScreenshotExtension/Context/Initializer/ScreenshotContextInitializer.php +++ b/src/DrevOps/BehatScreenshotExtension/Context/Initializer/ScreenshotContextInitializer.php @@ -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; } @@ -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; - } - } diff --git a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotAwareContextInterface.php b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotAwareContextInterface.php index 0cee657..1de8dcc 100644 --- a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotAwareContextInterface.php +++ b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotAwareContextInterface.php @@ -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 $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; + } diff --git a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php index a4e2d9e..b6419f1 100644 --- a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php +++ b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php @@ -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 { @@ -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) . "
\n" . $content; } catch (DriverException) { @@ -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); } /** @@ -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]); } /** @@ -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 { @@ -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. * @@ -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(); @@ -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. * @@ -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. * @@ -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);