From ce9c661e66890258d385300cb5e9e57621bed530 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sun, 19 Jan 2025 12:20:17 +1100 Subject: [PATCH] Updated extension options to be consistent. --- README.md | 184 +++++++++++------- behat.yml | 2 +- behat.yml.dist | 7 +- .../ScreenshotContextInitializer.php | 14 +- .../ScreenshotAwareContextInterface.php | 6 +- .../Context/ScreenshotContext.php | 36 ++-- .../BehatScreenshotExtension.php | 22 +-- .../BehatScreenshotExtension/Tokenizer.php | 14 +- tests/behat/bootstrap/BehatCliContext.php | 2 +- tests/behat/bootstrap/BehatCliTrait.php | 4 +- tests/behat/features/behatcli.feature | 2 +- .../features/screenshot_behatcli.feature | 30 +-- .../Unit/BehatScreenshotExtensionTest.php | 22 +-- tests/phpunit/Unit/ScreenshotContextTest.php | 71 ++----- .../phpunit/Unit/Tokenizer/TokenizerTest.php | 32 +-- 15 files changed, 231 insertions(+), 217 deletions(-) diff --git a/README.md b/README.md index 6ddab54..82fa004 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -

+

Behat screenshot logo -

+
-

Behat Screenshot Extension

+

Behat extension to create screenshots

@@ -21,23 +21,14 @@ --- -

Behat extension and step definitions to create HTML and image screenshots on demand or when tests fail. -
-

- ## Features -* Create a screenshot using `I save screenshot` or `save screenshot` step - definition. -* Create a screenshot when test fails. -* Screenshot is saved as HTML page for Goutte driver. -* Screenshot is saved as both HTML and PNG image for Selenium driver. -* Screenshot directory can be specified through environment - variable `BEHAT_SCREENSHOT_DIR` (useful for CI systems to override values - in `behat.yml`). -* Screenshots can be purged after every test run by setting `purge: true` ( - useful during test debugging) or setting environment - variable `BEHAT_SCREENSHOT_PURGE=1`. +* Captures a screenshot using the `I save screenshot` step. +* Automatically captures a screenshot when a test fails. +* Supports both HTML and PNG screenshots. +* Configurable screenshot directory. +* Automatically purges screenshots after each test run. +* Adds configurable additional information to screenshots. ## Installation @@ -72,93 +63,140 @@ default: extensions: DrevOps\BehatScreenshotExtension: dir: '%paths.base%/screenshots' - fail: true - fail_prefix: 'failed_' + on_failed: true purge: false - filenamePattern: '{datetime:u}.{feature_file}.feature_{step_line}.{ext}' - filenamePatternFailed: '{datetime:u}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}' + failed_prefix: 'failed_' + filename_pattern: '{datetime:u}.{feature_file}.feature_{step_line}.{ext}' + filename_pattern_failed: '{datetime:u}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}' ``` In your feature: ```gherkin - Given I am on "http://google.com" +Given I am on "http://google.com" Then I save screenshot ``` -You may optionally specify size of browser window in the screenshot step: +You may optionally specify the size of the browser window in the screenshot +step: ```gherkin - Then I save 1440 x 900 screenshot -And I save 800 x 600 screenshot +Then I save 1440 x 900 screenshot ``` -## Options +or a file name: -| Name | Default value | Description | -|-------------------------|----------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| -| `dir` | `%paths.base%/screenshots` | Path to directory to save screenshots. Directory structure will be created if the directory does not exist. | -| `fail` | `true` | Capture screenshot on test failure. | -| `fail_prefix` | `failed_` | Prefix failed screenshots with `fail_` string. Useful to distinguish failed and intended screenshots. | -| `purge` | `false` | Remove all files from the screenshots directory on each test run. Useful during debugging of tests. | -| `info_types` | `url`, `feature`, `step`, `datetime` | Show additional information on screenshots. Comma-separated list of `url`, `feature`, `step`, `datetime`, or remove to disable. Ordered as listed. | -| `filenamePattern` | `{datetime:u}.{feature_file}.feature_{step_line}.{ext}` | File name pattern for successful assertions. | -| `filenamePatternFailed` | `{datetime:u}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}` | File name pattern for failed assertions. | -| `filenamePatternFailed` | `{datetime:u}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}` | File name pattern for failed assertions. | - -### Supported tokens - -| Token | Substituted with | Example value(s) | -|--------------------|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------| -| `{ext}` | The extension of the file captured | `html` or `png` | -| `{fail_prefix}` | The value of fail_prefix from configuration | `failed_`, `error_` (do include the `_` suffix, if required) | -| `{url}` | Full URL | `http_example_com_mypath_subpath__query__myquery_1_plus_2_plus_3_and_another1_4__fragment__somefragment` | -| `{url_origin}` | Scheme with domain | `http_example_com` | -| `{url_relative}` | Path + query + fragment | `mypath_subpath__query__myquery_1_plus_2_plus_3_and_another1_4__fragment__somefragment` | -| `{url_domain}` | Domain | `example_com` | -| `{url_path}` | Path | `mypath_subpath` | -| `{url_query}` | Query | `myquery_1_plus_2_plus_3_and_another1_4` | -| `{url_fragment}` | Fragment | `somefragment` | -| `{feature_file}` | The filename of the `.feature` file currently being executed, without extension | `my_example.feature` -> `my_example` | -| `{step_line}` | Step line number | `1`, `10`, `100` | -| `{step_line:%03d}` | Step line number with leading zeros. Modifiers are from `sprintf()`. | `001`, `010`, `100` | -| `{step_name}` | Step name without `Given/When/Then` and lower-cased. | `i_am_on_the_test_page` | -| `{datetime}` | Current date and time. defaults to `Ymd_His` format. | `20010310_171618` | -| `{datetime:U}` | Current date and time as microtime. Modifiers are from `date()`. | `1697490961192498` | - -## Maintenance +```gherkin +Then I save screenshot to "my_screenshot.png" +``` -### Local development setup +## Options -### Install dependencies. +| Name | Default value | Description | +|---------------------------|------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| +| `dir` | `%paths.base%/screenshots` | Path to directory to save screenshots. Directory structure will be created if the directory does not exist. Override with `BEHAT_SCREENSHOT_DIR` env var. | +| `on_failed` | `true` | Capture screenshot on failed test. | +| `purge` | `false` | Remove all files from the screenshots directory on each test run. Useful during debugging of tests. | +| `info_types` | `url`, `feature`, `step`, `datetime` | Show additional information on screenshots. Comma-separated list of `url`, `feature`, `step`, `datetime`, or remove to disable. Ordered as listed. | +| `failed_prefix` | `failed_` | Prefix failed screenshots with `failed_` string. Useful to distinguish failed and intended screenshots. | +| `filename_pattern` | `{datetime:u}.{feature_file}.feature_{step_line}.{ext}` | File name pattern for successful assertions. | +| `filename_pattern_failed` | `{datetime:u}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}` | File name pattern for failed assertions. | + +### File name tokens + +| Token | Substituted with | Example value(s) | +|--------------------|---------------------------------------------------------------------------------|-------------------------------------------------------------------| +| `{ext}` | The extension of the file captured | `html` or `png` | +| `{failed_prefix}` | The value of failed_prefix from configuration | `failed_`, `error_` (do include the `_` suffix, if required) | +| `{url}` | Full URL | `http_example_com_mypath_subpath_query_myquery_1_plus_2_fragment` | +| `{url_origin}` | Scheme with domain | `http_example_com` | +| `{url_relative}` | Path + query + fragment | `mypath_subpath_query_myquery_1_plus_2_fragment` | +| `{url_domain}` | Domain | `example_com` | +| `{url_path}` | Path | `mypath_subpath` | +| `{url_query}` | Query | `myquery_1_plus_2` | +| `{url_fragment}` | Fragment | `somefragment` | +| `{feature_file}` | The filename of the `.feature` file currently being executed, without extension | `my_example.feature` -> `my_example` | +| `{step_line}` | Step line number | `1`, `10`, `100` | +| `{step_line:%03d}` | Step line number with leading zeros. Modifiers are from `sprintf()`. | `001`, `010`, `100` | +| `{step_name}` | Step name without `Given/When/Then` and lower-cased. | `i_am_on_the_test_page` | +| `{datetime}` | Current date and time. defaults to `Ymd_His` format. | `20010310_171618` | +| `{datetime:U}` | Current date and time as microtime. Modifiers are from `date()`. | `1697490961192498` | + +## Auto-purge + +By default, the `purge` option is disabled. This means that the screenshot +directory will not be cleared after each test run. This is useful when you want +to keep the screenshots for debugging purposes. + +If you want to clear the directory after each test run, you can enable the +`purge` option in the configuration. -```shell -composer install +```yaml +default: + extensions: + DrevOps\BehatScreenshotExtension: + purge: true ``` -### Lint code +Alternatively, you can use `BEHAT_SCREENSHOT_PURGE` environment variable to +enable the auto-purge feature for a specific test run. ```shell -composer lint +BEHAT_SCREENSHOT_PURGE=1 vendor/bin/behat ``` -### Fix code style +## Additional information on screenshots -```shell -composer lint-fix +You can enable additional information on screenshots by setting `info_types` in +the configuration. The order of the types will be the order of the information +displayed on the screenshot. + +By default, the information displayed is the URL, feature file name, step line: + +```html +Current URL: http://example.com
+Feature: My feature
+Step: I save screenshot (line 8)
+Datetime: 2025-01-19 00:01:10 +
+ + +... + ``` -### Run tests +More information can be added by setting the `info_types` configuration option +and using `addInfo()` method in your context class. + +```php +/** + * @BeforeScenario + */ +public function beforeScenarioUpdateBaseUrl(BeforeScenarioScope $scope): void { + $environment = $scope->getEnvironment(); + if ($environment instanceof InitializedContextEnvironment) { + foreach ($environment->getContexts() as $context) { + if ($context instanceof ScreenshotContext) { + $context->addInfo('Custom info', 'My custom info'); + } + } + } +} +``` -#### Unit tests +## Maintenance ```shell -composer test-unit # Run unit tests. +composer install +composer lint +composer lint-fix +composer test-unit +composer test-bdd ``` -#### BDD tests +### BDD tests -We have tests for Selenium and Headless drivers. Selenium requires a Docker +There are tests for Selenium and Headless drivers. Selenium requires a Docker container and headless requires a Chromium browser (we will make this more streamlined in the future). diff --git a/behat.yml b/behat.yml index 87251fd..8909ab9 100644 --- a/behat.yml +++ b/behat.yml @@ -37,7 +37,7 @@ default: DrevOps\BehatScreenshotExtension: dir: '%paths.base%/.logs/screenshots' - fail: true + on_failed: true purge: true info_types: - url diff --git a/behat.yml.dist b/behat.yml.dist index 0f49984..fefc22e 100644 --- a/behat.yml.dist +++ b/behat.yml.dist @@ -7,12 +7,13 @@ default: extensions: DrevOps\BehatScreenshotExtension: dir: %paths.base%/screenshots - fail: true + on_failed: true purge: false info_types: - url - feature - step - datetime - filenamePattern: '{datetime:u}.{feature_file}.feature_{step_line}.{ext}' - filenamePatternFailed: '{datetime:u}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}' + failed_prefix: failed_ + filename_pattern: '{datetime:u}.{feature_file}.feature_{step_line}.{ext}' + filename_pattern_failed: '{datetime:u}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}' diff --git a/src/DrevOps/BehatScreenshotExtension/Context/Initializer/ScreenshotContextInitializer.php b/src/DrevOps/BehatScreenshotExtension/Context/Initializer/ScreenshotContextInitializer.php index 417f147..fde4ac9 100644 --- a/src/DrevOps/BehatScreenshotExtension/Context/Initializer/ScreenshotContextInitializer.php +++ b/src/DrevOps/BehatScreenshotExtension/Context/Initializer/ScreenshotContextInitializer.php @@ -25,9 +25,9 @@ class ScreenshotContextInitializer implements ContextInitializer { * * @param string $dir * Screenshot dir. - * @param bool $fail - * Create screenshot on test failure. - * @param string $failPrefix + * @param bool $onFailed + * Create screenshot on failed test. + * @param string $failedPrefix * File name prefix for a failed test. * @param bool $purge * Purge dir before start script. @@ -42,8 +42,8 @@ class ScreenshotContextInitializer implements ContextInitializer { */ public function __construct( protected string $dir, - protected bool $fail, - private readonly string $failPrefix, + protected bool $onFailed, + private readonly string $failedPrefix, protected bool $purge, protected string $filenamePattern, protected string $filenamePatternFailed, @@ -68,8 +68,8 @@ public function initializeContext(Context $context): void { $context->setScreenshotParameters( $dir, - $this->fail, - $this->failPrefix, + $this->onFailed, + $this->failedPrefix, $this->filenamePattern, $this->filenamePatternFailed, $this->infoTypes diff --git a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotAwareContextInterface.php b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotAwareContextInterface.php index 1de8dcc..7df5132 100644 --- a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotAwareContextInterface.php +++ b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotAwareContextInterface.php @@ -16,9 +16,9 @@ interface ScreenshotAwareContextInterface extends Context { * * @param string $dir * Directory to store screenshots. - * @param bool $fail + * @param bool $on_failed * Create screenshots on fail. - * @param string $fail_prefix + * @param string $failed_prefix * File name prefix for a failed test. * @param string $filename_pattern * File name pattern. @@ -29,7 +29,7 @@ interface ScreenshotAwareContextInterface extends Context { * * @return $this */ - public function setScreenshotParameters(string $dir, bool $fail, string $fail_prefix, string $filename_pattern, string $filename_pattern_failed, array $info_types): static; + public function setScreenshotParameters(string $dir, bool $on_failed, string $failed_prefix, string $filename_pattern, string $filename_pattern_failed, array $info_types): static; /** * Save screenshot content into a file. diff --git a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php index b6419f1..b264d56 100644 --- a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php +++ b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php @@ -19,19 +19,19 @@ class ScreenshotContext extends RawMinkContext implements ScreenshotAwareContextInterface { /** - * Makes screenshot when fail. + * Screenshot directory path. */ - protected bool $fail = FALSE; + protected string $dir = ''; /** - * Prefix for failed screenshot files. + * Make screenshots on failed tests. */ - protected string $failPrefix = ''; + protected bool $onFailed = FALSE; /** - * Screenshot directory name. + * Prefix for failed screenshot files. */ - protected string $dir = ''; + protected string $failedPrefix = ''; /** * Filename pattern. @@ -65,10 +65,10 @@ class ScreenshotContext extends RawMinkContext implements ScreenshotAwareContext /** * {@inheritdoc} */ - public function setScreenshotParameters(string $dir, bool $fail, string $fail_prefix, string $filename_pattern, string $filename_pattern_failed, array $info_types): static { + public function setScreenshotParameters(string $dir, bool $on_failed, string $failed_prefix, string $filename_pattern, string $filename_pattern_failed, array $info_types): static { $this->dir = $dir; - $this->fail = $fail; - $this->failPrefix = $fail_prefix; + $this->onFailed = $on_failed; + $this->failedPrefix = $failed_prefix; $this->filenamePattern = $filename_pattern; $this->filenamePatternFailed = $filename_pattern_failed; $this->infoTypes = $info_types; @@ -135,8 +135,8 @@ public function beforeStepInit(BeforeStepScope $scope): void { * @AfterStep */ public function printLastResponseOnError(AfterStepScope $event): void { - if (!$event->getTestResult()->isPassed() && $this->fail) { - $this->iSaveScreenshot(['is_failure' => TRUE]); + if (!$event->getTestResult()->isPassed() && $this->onFailed) { + $this->iSaveScreenshot(['is_failed' => TRUE]); } } @@ -148,7 +148,7 @@ public function printLastResponseOnError(AfterStepScope $event): void { */ 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']; + $is_failed = isset($options['is_failed']) && is_scalar($options['is_failed']) && $options['is_failed']; $driver = $this->getSession()->getDriver(); $info = $this->renderInfo(); @@ -163,7 +163,7 @@ public function iSaveScreenshot(array $options = []): void { return; } - $filename_html = $this->makeFileName('html', $filename, $is_failure); + $filename_html = $this->makeFileName('html', $filename, $is_failed); $this->saveScreenshotContent($filename_html, $content); // Drivers that do not support making screenshots, including Goutte @@ -181,7 +181,7 @@ public function iSaveScreenshot(array $options = []): void { // @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); + $filename_png = $this->makeFileName('png', $filename, $is_failed); $this->saveScreenshotContent($filename_png, $content); } @@ -315,7 +315,7 @@ protected function getCurrentTime(): int { * File extension without dot. * @param string|null $filename * Optional file name. - * @param bool $is_failure + * @param bool $is_failed * Make filename for fail case. * * @return string @@ -323,8 +323,8 @@ protected function getCurrentTime(): int { * * @throws \Exception */ - protected function makeFileName(string $ext, ?string $filename = NULL, bool $is_failure = FALSE): string { - if ($is_failure) { + protected function makeFileName(string $ext, ?string $filename = NULL, bool $is_failed = FALSE): string { + if ($is_failed) { $filename = $this->filenamePatternFailed; } elseif (empty($filename)) { @@ -357,7 +357,7 @@ protected function makeFileName(string $ext, ?string $filename = NULL, bool $is_ $data = [ 'ext' => $ext, - 'fail_prefix' => $this->failPrefix, + 'failed_prefix' => $this->failedPrefix, 'feature_file' => $feature->getFile(), 'step_line' => $step->getLine(), 'step_name' => $step->getText(), diff --git a/src/DrevOps/BehatScreenshotExtension/ServiceContainer/BehatScreenshotExtension.php b/src/DrevOps/BehatScreenshotExtension/ServiceContainer/BehatScreenshotExtension.php index dee652e..04b438a 100644 --- a/src/DrevOps/BehatScreenshotExtension/ServiceContainer/BehatScreenshotExtension.php +++ b/src/DrevOps/BehatScreenshotExtension/ServiceContainer/BehatScreenshotExtension.php @@ -20,7 +20,7 @@ class BehatScreenshotExtension implements ExtensionInterface { /** * Extension configuration ID. */ - const MOD_ID = 'drevops_screenshot'; + const MOD_ID = 'drevops_behat_screenshot'; /** * {@inheritdoc} @@ -57,11 +57,11 @@ public function configure(ArrayNodeDefinition $builder): void { ->cannotBeEmpty() ->defaultValue('%paths.base%/screenshots') ->end() - ->scalarNode('fail') + ->scalarNode('on_failed') ->cannotBeEmpty() ->defaultValue(TRUE) ->end() - ->scalarNode('fail_prefix') + ->scalarNode('failed_prefix') ->cannotBeEmpty() ->defaultValue('failed_') ->end() @@ -69,13 +69,13 @@ public function configure(ArrayNodeDefinition $builder): void { ->cannotBeEmpty() ->defaultValue(FALSE) ->end() - ->scalarNode('filenamePattern') + ->scalarNode('filename_pattern') ->cannotBeEmpty() ->defaultValue('{datetime:U}.{feature_file}.feature_{step_line}.{ext}') ->end() - ->scalarNode('filenamePatternFailed') + ->scalarNode('filename_pattern_failed') ->cannotBeEmpty() - ->defaultValue('{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}') + ->defaultValue('{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}') ->end() ->arrayNode('info_types') ->defaultValue([]) @@ -91,15 +91,15 @@ public function configure(ArrayNodeDefinition $builder): void { public function load(ContainerBuilder $container, array $config): void { $definition = new Definition(ScreenshotContextInitializer::class, [ $config['dir'], - $config['fail'], - $config['fail_prefix'], + $config['on_failed'], + $config['failed_prefix'], $config['purge'], - $config['filenamePattern'], - $config['filenamePatternFailed'], + $config['filename_pattern'], + $config['filename_pattern_failed'], $config['info_types'], ]); $definition->addTag(ContextExtension::INITIALIZER_TAG, ['priority' => 0]); - $container->setDefinition('drevops_screenshot.screenshot_context_initializer', $definition); + $container->setDefinition(static::MOD_ID . '.screenshot_context_initializer', $definition); } } diff --git a/src/DrevOps/BehatScreenshotExtension/Tokenizer.php b/src/DrevOps/BehatScreenshotExtension/Tokenizer.php index c48ce94..37d79e5 100644 --- a/src/DrevOps/BehatScreenshotExtension/Tokenizer.php +++ b/src/DrevOps/BehatScreenshotExtension/Tokenizer.php @@ -118,10 +118,14 @@ protected static function extractTokens(array $tokens, array $data): array { * Token replacement. */ protected static function buildTokenReplacement(string $token, string $name, ?string $qualifier = NULL, ?string $format = NULL, array $data = []): string { - $method = 'replace' . ucfirst($name) . 'Token'; + $method = 'replace' . str_replace('_', '', ucwords($name, '_')) . 'Token'; + if (is_callable([self::class, $method])) { + return self::$method($token, $name, $qualifier, $format, $data); + } + $method = 'replace' . str_replace('_', '', ucwords($name . '_' . $qualifier, '_')) . 'Token'; if (is_callable([self::class, $method])) { - $token = self::$method($token, $name, $qualifier, $format, $data); + return self::$method($token, $name, $qualifier, $format, $data); } return $token; @@ -230,10 +234,10 @@ protected static function replaceUrlToken(string $token, string $name, ?string $ } /** - * Replace {fail} token. + * Replace {failed_prefix} token. */ - protected static function replaceFailToken(string $token, string $name, ?string $qualifier = NULL, ?string $format = NULL, array $data = []): string { - return !empty($data['fail_prefix']) && is_string($data['fail_prefix']) ? $data['fail_prefix'] : $token; + protected static function replaceFailedPrefixToken(string $token, string $name, ?string $qualifier = NULL, ?string $format = NULL, array $data = []): string { + return !empty($data['failed_prefix']) && is_string($data['failed_prefix']) ? $data['failed_prefix'] : $token; } } diff --git a/tests/behat/bootstrap/BehatCliContext.php b/tests/behat/bootstrap/BehatCliContext.php index 762632a..39a6002 100644 --- a/tests/behat/bootstrap/BehatCliContext.php +++ b/tests/behat/bootstrap/BehatCliContext.php @@ -396,7 +396,7 @@ private function getExpectedOutput(PyStringNode $expectedText) { * @param string $success "fail" or "pass" */ public function itShouldFail($success) { - if ('fail' === $success) { + if ('on_failed' === $success) { if (0 === $this->getExitCode()) { echo 'Actual output:' . PHP_EOL . PHP_EOL . $this->getOutput(); } diff --git a/tests/behat/bootstrap/BehatCliTrait.php b/tests/behat/bootstrap/BehatCliTrait.php index 278a1ce..7c53a34 100644 --- a/tests/behat/bootstrap/BehatCliTrait.php +++ b/tests/behat/bootstrap/BehatCliTrait.php @@ -278,7 +278,7 @@ public function behatCliWriteScreenshotFixture(): void { * @Then it should fail with an error: */ public function behatCliAssertFailWithError(PyStringNode $message): void { - $this->itShouldFail('fail'); + $this->itShouldFail('on_failed'); Assert::assertStringContainsString(trim((string) $message), $this->getOutput()); // Enforce \Exception for all assertion exceptions. Non-assertion // exceptions should be thrown as \RuntimeException. @@ -290,7 +290,7 @@ public function behatCliAssertFailWithError(PyStringNode $message): void { * @Then it should fail with an exception: */ public function behatCliAssertFailWithException(PyStringNode $message): void { - $this->itShouldFail('fail'); + $this->itShouldFail('on_failed'); Assert::assertStringContainsString(trim((string) $message), $this->getOutput()); // Enforce \RuntimeException for all non-assertion exceptions. Assertion // exceptions should be thrown as \Exception. diff --git a/tests/behat/features/behatcli.feature b/tests/behat/features/behatcli.feature index 656cb3f..2ebd717 100644 --- a/tests/behat/features/behatcli.feature +++ b/tests/behat/features/behatcli.feature @@ -49,7 +49,7 @@ Feature: Behat CLI context selenium2: ~ base_url: http://0.0.0.0:8888 """ - And a file named "tests/behat/fixtures/screenshot.html" with: + And a file named "tests/behat/fixtures/screenshot.html" with: """ diff --git a/tests/behat/features/screenshot_behatcli.feature b/tests/behat/features/screenshot_behatcli.feature index 37f2f4d..3da975e 100644 --- a/tests/behat/features/screenshot_behatcli.feature +++ b/tests/behat/features/screenshot_behatcli.feature @@ -9,7 +9,7 @@ Feature: Screenshot context """ DrevOps\BehatScreenshotExtension: dir: "%paths.base%/screenshots" - fail: true + on_failed: true purge: true """ And scenario steps tagged with "@phpserver": @@ -37,11 +37,11 @@ Feature: Screenshot context Then it should pass And behat cli file wildcard "screenshots/*.stub.feature_7\.html" should exist - Scenario: Test Screenshot context with 'filenamePattern' override + Scenario: Test Screenshot context with 'filename_pattern' override Given screenshot context behat configuration with value: """ DrevOps\BehatScreenshotExtension: - filenamePattern: "{datetime:U}.{feature_file}.feature_{step_line:%03d}.{ext}" + filename_pattern: "{datetime:U}.{feature_file}.feature_{step_line:%03d}.{ext}" """ And scenario steps tagged with "@phpserver": """ @@ -88,11 +88,11 @@ Feature: Screenshot context Then it should fail And behat cli file wildcard "screenshots_custom/*.failed_stub.feature_6\.html" should exist - Scenario: Test Screenshot context with 'fail' set to 'true' which will save screenshot on fail + Scenario: Test Screenshot context with 'on_failed' set to 'true' which will save screenshot on fail Given screenshot context behat configuration with value: """ DrevOps\BehatScreenshotExtension: - fail: true + on_failed: true """ And scenario steps tagged with "@phpserver": """ @@ -103,11 +103,11 @@ Feature: Screenshot context Then it should fail And behat cli file wildcard "screenshots/*.failed_stub.feature_6\.html" should exist - Scenario: Test Screenshot context with 'fail' set to 'false' which will not save screenshot on fail + Scenario: Test Screenshot context with 'on_failed' set to 'false' which will not save screenshot on fail Given screenshot context behat configuration with value: """ DrevOps\BehatScreenshotExtension: - fail: false + on_failed: false """ And scenario steps tagged with "@phpserver": """ @@ -118,12 +118,12 @@ Feature: Screenshot context Then it should fail And behat cli file wildcard "screenshots/*.failed_stub.feature_6\.html" should not exist - Scenario: Test Screenshot context with 'filenamePatternFailed' override & save screenshot on fail + Scenario: Test Screenshot context with 'filename_pattern_failed' override & save screenshot on fail Given screenshot context behat configuration with value: """ DrevOps\BehatScreenshotExtension: - fail: true - filenamePatternFailed: "{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line:%03d}.{ext}" + on_failed: true + filename_pattern_failed: "{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line:%03d}.{ext}" """ And scenario steps tagged with "@phpserver": """ @@ -134,12 +134,12 @@ Feature: Screenshot context Then it should fail And behat cli file wildcard "screenshots/*.failed_stub.feature_006\.html" should exist - Scenario: Test Screenshot context with 'filenamePatternFailed' override & not save screenshot on fail + Scenario: Test Screenshot context with 'filename_pattern_failed' override & not save screenshot on fail Given screenshot context behat configuration with value: """ DrevOps\BehatScreenshotExtension: - fail: false - filenamePatternFailed: "{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line:%03d}.{ext}" + on_failed: false + filename_pattern_failed: "{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line:%03d}.{ext}" """ And scenario steps tagged with "@phpserver": """ @@ -231,7 +231,7 @@ Feature: Screenshot context And behat cli file wildcard "screenshots/*.failed_stub.feature_6\.html" should not exist Scenario: Test Screenshot context with env variable BEHAT_SCREENSHOT_PURGE set to '1' which will purge files between - runs and env variable BEHAT_SCREENSHOT_DIR set to 'screenshots_custom'. + runs and env variable BEHAT_SCREENSHOT_DIR set to 'screenshots_custom'. Given screenshot context behat configuration with value: """ DrevOps\BehatScreenshotExtension: ~ @@ -347,7 +347,7 @@ Feature: Screenshot context DrevOps\BehatScreenshotExtension: dir: "%paths.base%/screenshots" - fail: true + on_failed: true purge: true info_types: - url diff --git a/tests/phpunit/Unit/BehatScreenshotExtensionTest.php b/tests/phpunit/Unit/BehatScreenshotExtensionTest.php index 986b685..57300a1 100644 --- a/tests/phpunit/Unit/BehatScreenshotExtensionTest.php +++ b/tests/phpunit/Unit/BehatScreenshotExtensionTest.php @@ -19,36 +19,36 @@ class BehatScreenshotExtensionTest extends TestCase { public function testGetConfigKey(): void { $extension = new BehatScreenshotExtension(); - $this->assertEquals('drevops_screenshot', $extension->getConfigKey()); + $this->assertEquals('drevops_behat_screenshot', $extension->getConfigKey()); } public function testLoad(): void { $container = new ContainerBuilder(); $config = [ 'dir' => '%paths.base%/screenshots', - 'fail' => TRUE, - 'fail_prefix' => 'failed_', + 'on_failed' => TRUE, + 'failed_prefix' => 'failed_', 'purge' => FALSE, - 'filenamePattern' => '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', - 'filenamePatternFailed' => '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + 'filename_pattern' => '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', + 'filename_pattern_failed' => '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}', 'info_types' => FALSE, ]; $extension = new BehatScreenshotExtension(); $extension->load($container, $config); - $this->assertTrue($container->hasDefinition('drevops_screenshot.screenshot_context_initializer')); + $this->assertTrue($container->hasDefinition('drevops_behat_screenshot.screenshot_context_initializer')); - $definition = $container->getDefinition('drevops_screenshot.screenshot_context_initializer'); + $definition = $container->getDefinition('drevops_behat_screenshot.screenshot_context_initializer'); $this->assertEquals(ScreenshotContextInitializer::class, $definition->getClass()); $this->assertEquals( [ $config['dir'], - $config['fail'], - $config['fail_prefix'], + $config['on_failed'], + $config['failed_prefix'], $config['purge'], - $config['filenamePattern'], - $config['filenamePatternFailed'], + $config['filename_pattern'], + $config['filename_pattern_failed'], $config['info_types'], ], $definition->getArguments() diff --git a/tests/phpunit/Unit/ScreenshotContextTest.php b/tests/phpunit/Unit/ScreenshotContextTest.php index e1188a7..ddf9ccf 100644 --- a/tests/phpunit/Unit/ScreenshotContextTest.php +++ b/tests/phpunit/Unit/ScreenshotContextTest.php @@ -73,7 +73,7 @@ public function testPrintLastResponseOnError(): void { TRUE, 'failed_', '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', - '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}', [] ); $screenshot_context = $this->createPartialMock(ScreenshotContext::class, ['iSaveScreenshot']); @@ -82,7 +82,7 @@ public function testPrintLastResponseOnError(): void { TRUE, 'failed_', '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', - '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}', [], ); $screenshot_context->expects($this->once())->method('iSaveScreenshot'); @@ -149,7 +149,7 @@ public function testSaveScreenshotData(string $filename, string $data): void { TRUE, 'failed_', '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', - '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}', [], ); $screenshot_context_reflection = new \ReflectionClass($screenshot_context); @@ -173,51 +173,20 @@ public static function saveScreenshotDataDataProvider(): array { ]; } - /** - * Test make file name. - * - * @param string $ext - * Ext. - * @param mixed $filename - * Filename. - * @param bool $fail - * Fail. - * @param mixed $url - * URL. - * @param int $current_time - * Current time. - * @param string $step_text - * Step text. - * @param int $step_line - * Step line. - * @param string $feature_file - * Feature file. - * @param string $fail_prefix - * Fail prefix. - * @param string $file_name_pattern - * File name pattern. - * @param string $file_name_pattern_failed - * File name pattern failed. - * @param string $filename_expected - * File name expected. - * - * @throws \PHPUnit\Framework\MockObject\Exception - * @throws \ReflectionException - */ #[DataProvider('makeFileNameProvider')] public function testMakeFileName( string $ext, mixed $filename, - bool $fail, + bool $on_failed, mixed $url, int $current_time, string $step_text, int $step_line, string $feature_file, - string $fail_prefix, - string $file_name_pattern, - string $file_name_pattern_failed, - string $filename_expected, + string $failed_prefix, + string $filename_pattern, + string $filename_pattern_failed, + string $expected, ): void { $screenshot_context = $this->createPartialMock(ScreenshotContext::class, [ 'getBeforeStepScope', @@ -225,6 +194,7 @@ public function testMakeFileName( 'getCurrentTime', ]); $session = $this->createMock(Session::class); + if ($url instanceof \Exception) { $session->method('getCurrentUrl')->willThrowException($url); } @@ -245,18 +215,19 @@ public function testMakeFileName( $screenshot_context->setScreenshotParameters( 'test-dir', - $fail, - $fail_prefix, - $file_name_pattern, - $file_name_pattern_failed, + $on_failed, + $failed_prefix, + $filename_pattern, + $filename_pattern_failed, [], ); $screenshot_context_reflection = new \ReflectionClass($screenshot_context); $method = $screenshot_context_reflection->getMethod('makeFileName'); $method->setAccessible(TRUE); - $filename_processed = $method->invokeArgs($screenshot_context, [$ext, $filename, $fail]); - $this->assertEquals($filename_expected, $filename_processed); + $filename_processed = $method->invokeArgs($screenshot_context, [$ext, $filename, $on_failed]); + + $this->assertEquals($expected, $filename_processed); } public static function makeFileNameProvider(): array { @@ -272,7 +243,7 @@ public static function makeFileNameProvider(): array { 'test-feature-file', 'failed_', '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', - '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}', '1721791661.test-feature-file.feature_12.html', ], [ @@ -286,7 +257,7 @@ public static function makeFileNameProvider(): array { 'test-feature-file', 'failed_', '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', - '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}', '1721791661.test-feature-file.feature_test-step-name.feature_12.png', ], [ @@ -300,7 +271,7 @@ public static function makeFileNameProvider(): array { 'test-feature-file', 'failed_', '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', - '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}', '1721791661.test-feature-file.feature_test-step-name.feature_12.png', ], [ @@ -314,7 +285,7 @@ public static function makeFileNameProvider(): array { 'test-feature-file', 'failed_', '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', - '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}', '1721791661.failed_test-feature-file.feature_12.png', ], [ @@ -328,7 +299,7 @@ public static function makeFileNameProvider(): array { 'test-feature-file', 'failed_', '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', - '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}', '1721791661.test-feature-file.feature_test-step-name.feature_12.png', ], ]; diff --git a/tests/phpunit/Unit/Tokenizer/TokenizerTest.php b/tests/phpunit/Unit/Tokenizer/TokenizerTest.php index 52577ed..258d0fc 100644 --- a/tests/phpunit/Unit/Tokenizer/TokenizerTest.php +++ b/tests/phpunit/Unit/Tokenizer/TokenizerTest.php @@ -36,10 +36,10 @@ public static function dataProviderScanTokens(): array { ], ], [ - '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}', [ '{datetime:U}' => 'datetime:U', - '{fail_prefix}' => 'fail_prefix', + '{failed_prefix}' => 'failed_prefix', '{feature_file}' => 'feature_file', '{step_line}' => 'step_line', '{ext}' => 'ext', @@ -129,17 +129,17 @@ public static function dataProviderReplaceFeatureToken(): array { ]; } - #[DataProvider('dataProviderReplaceFailToken')] - public function testReplaceFailToken(string $token, string $name, ?string $qualifier, ?string $format, array $data, string $expected): void { - $replacement = $this->callProtectedMethod(Tokenizer::class, 'replaceFailToken', [$token, $name, $qualifier, $format, $data]); + #[DataProvider('dataProviderReplaceFailedPrefixToken')] + public function testReplaceFailedPrefixToken(string $token, string $name, ?string $qualifier, ?string $format, array $data, string $expected): void { + $replacement = $this->callProtectedMethod(Tokenizer::class, 'replaceFailedPrefixToken', [$token, $name, $qualifier, $format, $data]); $this->assertEquals($expected, $replacement); } - public static function dataProviderReplaceFailToken(): array { + public static function dataProviderReplaceFailedPrefixToken(): array { return [ - ['{fail}', 'fail', NULL, NULL, [], '{fail}'], - ['{fail}', 'fail', NULL, NULL, ['fail_prefix' => ''], '{fail}'], - ['{fail}', 'fail', NULL, NULL, ['fail_prefix' => 'HelloFail_'], 'HelloFail_'], + ['{failed_prefix}', 'failed_prefix', NULL, NULL, [], '{failed_prefix}'], + ['{failed_prefix}', 'failed_prefix', NULL, NULL, ['failed_prefix' => ''], '{failed_prefix}'], + ['{failed_prefix}', 'failed_prefix', NULL, NULL, ['failed_prefix' => 'HelloFail_'], 'HelloFail_'], ]; } @@ -191,7 +191,7 @@ public function testReplaceTokens(string $stringContainsTokens, array $data, str public static function dataProviderReplaceTokens(): array { $data = [ - 'fail_prefix' => 'foo-fail_', + 'failed_prefix' => 'foo-failed_', 'timestamp' => 1710219423, 'ext' => 'png', 'url' => 'http://example.com/foo?foo=foo-value#hello-fragment', @@ -207,19 +207,19 @@ public static function dataProviderReplaceTokens(): array { 'somestring', ], [ - '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}.{ext}', $data, - '1710219423.foo-fail_foo-file.feature_6.png', + '1710219423.foo-failed_foo-file.feature_6.png', ], [ - '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}_{step_name}.{ext}', + '{datetime:U}.{failed_prefix}{feature_file}.feature_{step_line}_{step_name}.{ext}', $data, - '1710219423.foo-fail_foo-file.feature_6_Foo_step_name.png', + '1710219423.foo-failed_foo-file.feature_6_Foo_step_name.png', ], [ - '{datetime}.{fail_prefix}{feature_file}.feature_{step_line}_{step_name}.{ext}', + '{datetime}.{failed_prefix}{feature_file}.feature_{step_line}_{step_name}.{ext}', $data, - '20240312_045703.foo-fail_foo-file.feature_6_Foo_step_name.png', + '20240312_045703.foo-failed_foo-file.feature_6_Foo_step_name.png', ], [ '{url}.{ext}',