From 0e08dd0dfe2ff31ec42564000607e0fc26c5f810 Mon Sep 17 00:00:00 2001 From: "tan.nguyen" Date: Tue, 23 Jul 2024 14:02:59 +0700 Subject: [PATCH 1/4] Add unit test for BehatScreenshotExtension --- .../Unit/BehatScreenshotExtensionTest.php | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/phpunit/Unit/BehatScreenshotExtensionTest.php diff --git a/tests/phpunit/Unit/BehatScreenshotExtensionTest.php b/tests/phpunit/Unit/BehatScreenshotExtensionTest.php new file mode 100644 index 0000000..f2886f3 --- /dev/null +++ b/tests/phpunit/Unit/BehatScreenshotExtensionTest.php @@ -0,0 +1,67 @@ +assertEquals('drevops_screenshot', $extension->getConfigKey()); + } + + public function testLoad(): void { + $container = new ContainerBuilder(); + $config = [ + 'dir' => '%paths.base%/screenshots', + 'fail' => TRUE, + 'fail_prefix' => 'failed_', + 'purge' => FALSE, + 'filenamePattern' => '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', + 'filenamePatternFailed' => '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + ]; + + $extension = new BehatScreenshotExtension(); + $extension->load($container, $config); + + $this->assertTrue($container->hasDefinition('drevops_screenshot.screenshot_context_initializer')); + + $definition = $container->getDefinition('drevops_screenshot.screenshot_context_initializer'); + $this->assertEquals(ScreenshotContextInitializer::class, $definition->getClass()); + $this->assertEquals( + [ + $config['dir'], + $config['fail'], + $config['fail_prefix'], + $config['purge'], + $config['filenamePattern'], + $config['filenamePatternFailed'], + ], + $definition->getArguments() + ); + } + + public function testConfigure(): void { + $builder = new ArrayNodeDefinition('root'); + + $extension = new BehatScreenshotExtension(); + $extension->configure($builder); + + $this->assertCount(6, $builder->getChildNodeDefinitions()); + } + +} From a9bcb3872af1d3e7dd0ff47577d5976a869475f5 Mon Sep 17 00:00:00 2001 From: "tan.nguyen" Date: Tue, 23 Jul 2024 15:23:17 +0700 Subject: [PATCH 2/4] Update tests. --- .../Context/ScreenshotContext.php | 14 ++++++++++++-- .../phpunit/Unit/BehatScreenshotExtensionTest.php | 2 -- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php index 84e46dd..bb62fb6 100644 --- a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php +++ b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php @@ -269,8 +269,8 @@ protected function makeFileName(string $ext, string $filename = NULL, bool $fail $filename .= '.{ext}'; } - $feature = $this->beforeStepScope->getFeature(); - $step = $this->beforeStepScope->getStep(); + $feature = $this->getBeforeStepScope()->getFeature(); + $step = $this->getBeforeStepScope()->getStep(); try { $url = $this->getSession()->getCurrentUrl(); @@ -292,4 +292,14 @@ protected function makeFileName(string $ext, string $filename = NULL, bool $fail return Tokenizer::replaceTokens($filename, $data); } + /** + * Get before step scope. + * + * @return \Behat\Behat\Hook\Scope\BeforeStepScope + * The before step scope. + */ + public function getBeforeStepScope(): BeforeStepScope { + return $this->beforeStepScope; + } + } diff --git a/tests/phpunit/Unit/BehatScreenshotExtensionTest.php b/tests/phpunit/Unit/BehatScreenshotExtensionTest.php index f2886f3..6633a76 100644 --- a/tests/phpunit/Unit/BehatScreenshotExtensionTest.php +++ b/tests/phpunit/Unit/BehatScreenshotExtensionTest.php @@ -9,8 +9,6 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; -use Symfony\Component\Config\Definition\Builder\NodeBuilder; -use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; /** From 985e0418172fa12ef48280da5da40106df5666d4 Mon Sep 17 00:00:00 2001 From: "tan.nguyen" Date: Tue, 23 Jul 2024 16:04:35 +0700 Subject: [PATCH 3/4] Add test for ScreenshotContext --- tests/phpunit/Unit/ScreenshotContextTest.php | 154 +++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 tests/phpunit/Unit/ScreenshotContextTest.php diff --git a/tests/phpunit/Unit/ScreenshotContextTest.php b/tests/phpunit/Unit/ScreenshotContextTest.php new file mode 100644 index 0000000..66d1bb4 --- /dev/null +++ b/tests/phpunit/Unit/ScreenshotContextTest.php @@ -0,0 +1,154 @@ +createMock(Environment::class); + $feature_node = $this->createMock(FeatureNode::class); + $scenario = $this->createMock(ScenarioInterface::class); + $scenario + ->method('hasTag')->with('javascript')->willReturn(TRUE); + $session = $this->createMock(Session::class); + $driver = $this->createMock(Selenium2Driver::class); + $driver->method('start')->willThrowException(new \Exception('Test Exception.')); + $session->method('getDriver')->willReturn($driver); + + $this->expectException(\RuntimeException::class); + + $screenshot_context = $this->createPartialMock(ScreenshotContext::class, ['getSession']); + $screenshot_context->method('getSession')->willReturn($session); + + $scope = new BeforeScenarioScope($env, $feature_node, $scenario); + $screenshot_context->beforeScenarioInit($scope); + } + + public function testBeforeStepInit(): void { + $env = $this->createMock(Environment::class); + $feature_node = $this->createMock(FeatureNode::class); + $step_node = $this->createMock(StepNode::class); + + $feature_node->method('getFile')->willReturn(TRUE); + $screenshot_context = new ScreenshotContext(); + $scope = new BeforeStepScope($env, $feature_node, $step_node); + $screenshot_context->beforeStepInit($scope); + $this->assertEquals($scope, $screenshot_context->getBeforeStepScope()); + } + + public function testBeforeStepInitThrowError(): void { + $env = $this->createMock(Environment::class); + $feature_node = $this->createMock(FeatureNode::class); + $step_node = $this->createMock(StepNode::class); + + $feature_node->method('getFile')->willReturn(FALSE); + $this->expectException(\RuntimeException::class); + + $screenshot_context = new ScreenshotContext(); + $scope = new BeforeStepScope($env, $feature_node, $step_node); + $screenshot_context->beforeStepInit($scope); + } + + public function testPrintLastResponseOnError(): void { + $env = $this->createMock(Environment::class); + $feature_node = $this->createMock(FeatureNode::class); + $step_node = $this->createMock(StepNode::class); + $result = $this->createMock(StepResult::class); + $result->method('isPassed')->willReturn(FALSE); + $scope = new AfterStepScope($env, $feature_node, $step_node, $result); + + $screenshot_context = new ScreenshotContext(); + $screenshot_context->setScreenshotParameters( + '/tmp', + TRUE, + 'failed_', + '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}' + ); + $screenshot_context = $this->createPartialMock(ScreenshotContext::class, ['iSaveScreenshot']); + $screenshot_context->setScreenshotParameters( + '/tmp', + TRUE, + 'failed_', + '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + ); + $screenshot_context->expects($this->once())->method('iSaveScreenshot'); + $screenshot_context->printLastResponseOnError($scope); + } + + public function testIsaveSizedScreenshot(): void { + $screenshot_context = $this->createPartialMock(ScreenshotContext::class, ['getSession', 'iSaveScreenshot']); + $session = $this->createMock(Session::class); + $exception = $this->createMock(UnsupportedDriverActionException::class); + $session->method('resizeWindow')->willThrowException($exception); + $screenshot_context->method('getSession')->willReturn($session); + $screenshot_context->expects($this->once())->method('iSaveScreenshot'); + $screenshot_context->iSaveSizedScreenshot(); + } + + public function testIsaveSizedScreenshotWithName(): void { + $screenshot_context = $this->createPartialMock(ScreenshotContext::class, ['iSaveScreenshot']); + $screenshot_context->expects($this->once())->method('iSaveScreenshot'); + $screenshot_context->iSaveScreenshotWithName('test-file-name'); + } + + public function testIsaveScreenshot(): void { + $screenshot_context = $this->createPartialMock(ScreenshotContext::class, [ + 'getSession', + 'makeFileName', + 'saveScreenshotData', + ]); + $session = $this->createMock(Session::class); + $driver = $this->createMock(Selenium2Driver::class); + $driver->method('getContent')->willReturn('test-content'); + $driver->method('getScreenshot')->willReturn('test-content'); + $session->method('getDriver')->willReturn($driver); + $screenshot_context->method('getSession')->willReturn($session); + $screenshot_context->method('makeFileName')->willReturn('test-file-name'); + + $screenshot_context->expects($this->exactly(2))->method('saveScreenshotData'); + $screenshot_context->iSaveScreenshot(); + } + + public function testIsaveScreenshotThrowException(): void { + $screenshot_context = $this->createPartialMock(ScreenshotContext::class, [ + 'getSession', + 'makeFileName', + 'saveScreenshotData', + ]); + $session = $this->createMock(Session::class); + $driver = $this->createMock(Selenium2Driver::class); + $exception = $this->createMock(DriverException::class); + $driver->method('getContent')->willThrowException($exception); + $session->method('getDriver')->willReturn($driver); + $screenshot_context->method('getSession')->willReturn($session); + $screenshot_context->method('makeFileName')->willReturn('test-file-name'); + + $screenshot_context->expects($this->never())->method('saveScreenshotData'); + $screenshot_context->iSaveScreenshot(); + } + +} From a830ce170f74922b2c1ef3fe5c2fb4063dc1d53e Mon Sep 17 00:00:00 2001 From: "tan.nguyen" Date: Wed, 24 Jul 2024 11:03:09 +0700 Subject: [PATCH 4/4] Update tests. --- .../Context/ScreenshotContext.php | 32 ++- tests/phpunit/Unit/ScreenshotContextTest.php | 196 +++++++++++++++++- 2 files changed, 215 insertions(+), 13 deletions(-) diff --git a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php index bb62fb6..77645e1 100644 --- a/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php +++ b/src/DrevOps/BehatScreenshotExtension/Context/ScreenshotContext.php @@ -215,6 +215,26 @@ public function iSaveSizedScreenshot(string|int $width = 1440, string|int $heigh $this->iSaveScreenshot(); } + /** + * Get before step scope. + * + * @return \Behat\Behat\Hook\Scope\BeforeStepScope + * The before step scope. + */ + public function getBeforeStepScope(): BeforeStepScope { + return $this->beforeStepScope; + } + + /** + * Get current timestamp. + * + * @return int + * Current timestamp. + */ + public function getCurrentTime(): int { + return time(); + } + /** * Save screenshot data into a file. * @@ -285,21 +305,11 @@ protected function makeFileName(string $ext, string $filename = NULL, bool $fail 'step_line' => $step->getLine(), 'feature_file' => $feature->getFile(), 'url' => $url, - 'time' => time(), + 'time' => $this->getCurrentTime(), 'fail_prefix' => $this->failPrefix, ]; return Tokenizer::replaceTokens($filename, $data); } - /** - * Get before step scope. - * - * @return \Behat\Behat\Hook\Scope\BeforeStepScope - * The before step scope. - */ - public function getBeforeStepScope(): BeforeStepScope { - return $this->beforeStepScope; - } - } diff --git a/tests/phpunit/Unit/ScreenshotContextTest.php b/tests/phpunit/Unit/ScreenshotContextTest.php index 66d1bb4..db728ca 100644 --- a/tests/phpunit/Unit/ScreenshotContextTest.php +++ b/tests/phpunit/Unit/ScreenshotContextTest.php @@ -18,6 +18,7 @@ use Behat\Testwork\Environment\Environment; use DrevOps\BehatScreenshotExtension\Context\ScreenshotContext; use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; /** @@ -81,7 +82,7 @@ public function testPrintLastResponseOnError(): void { $screenshot_context = new ScreenshotContext(); $screenshot_context->setScreenshotParameters( - '/tmp', + sys_get_temp_dir(), TRUE, 'failed_', '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', @@ -89,7 +90,7 @@ public function testPrintLastResponseOnError(): void { ); $screenshot_context = $this->createPartialMock(ScreenshotContext::class, ['iSaveScreenshot']); $screenshot_context->setScreenshotParameters( - '/tmp', + sys_get_temp_dir(), TRUE, 'failed_', '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', @@ -151,4 +152,195 @@ public function testIsaveScreenshotThrowException(): void { $screenshot_context->iSaveScreenshot(); } + #[DataProvider('saveScreenshotDataDataProvider')] + public function testSaveScreenshotData(string $filename, string $data): void { + $screenshot_context = new ScreenshotContext(); + $screenshot_context->setScreenshotParameters( + sys_get_temp_dir(), + TRUE, + 'failed_', + '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + ); + $screenshot_context_reflection = new \ReflectionClass($screenshot_context); + $method = $screenshot_context_reflection->getMethod('saveScreenshotData'); + $method->setAccessible(TRUE); + $method->invokeArgs($screenshot_context, [$filename, $data]); + $filepath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $filename; + $this->assertFileExists($filepath); + $this->assertEquals(file_get_contents($filepath), $data); + + unlink($filepath); + } + + /** + * Data provider for testSaveScreenshotData method. + */ + public static function saveScreenshotDataDataProvider(): array { + return [ + ['test-save-screenshot-1.txt', 'test-data-1'], + ['test-save-screenshot-2.txt', 'test-data-2'], + ]; + } + + /** + * 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, + 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, + ): void { + $screenshot_context = $this->createPartialMock(ScreenshotContext::class, [ + 'getBeforeStepScope', + 'getSession', + 'getCurrentTime', + ]); + $session = $this->createMock(Session::class); + if ($url instanceof \Exception) { + $session->method('getCurrentUrl')->willThrowException($url); + } + else { + $session->method('getCurrentUrl')->willReturn($url); + } + + $screenshot_context->method('getCurrentTime')->willReturn($current_time); + $screenshot_context->method('getSession')->willReturn($session); + $env = $this->createMock(Environment::class); + $feature_node = $this->createMock(FeatureNode::class); + $step_node = $this->createMock(StepNode::class); + $step_node->method('getText')->willReturn($step_text); + $step_node->method('getLine')->willReturn($step_line); + $feature_node->method('getFile')->willReturn($feature_file); + $scope = new BeforeStepScope($env, $feature_node, $step_node); + $screenshot_context->method('getBeforeStepScope')->willReturn($scope); + + $screenshot_context->setScreenshotParameters( + 'test-dir', + $fail, + $fail_prefix, + $file_name_pattern, + $file_name_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); + } + + public static function makeFileNameProvider(): array { + return [ + [ + 'html', + NULL, + FALSE, + 'test-url', + 1721791661, + 'test-step-name', + 12, + 'test-feature-file', + 'failed_', + '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '1721791661.test-feature-file.feature_12.html', + ], + [ + 'png', + '{datetime:U}.{feature_file}.feature_{step_name}.feature_{step_line}.{ext}', + FALSE, + 'test-url', + 1721791661, + 'test-step-name', + 12, + 'test-feature-file', + 'failed_', + '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '1721791661.test-feature-file.feature_test-step-name.feature_12.png', + ], + [ + 'png', + '{datetime:U}.{feature_file}.feature_{step_name}.feature_{step_line}', + FALSE, + 'test-url', + 1721791661, + 'test-step-name', + 12, + 'test-feature-file', + 'failed_', + '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '1721791661.test-feature-file.feature_test-step-name.feature_12.png', + ], + [ + 'png', + '{datetime:U}.{feature_file}.feature_{step_name}.feature_{step_line}', + TRUE, + 'test-url', + 1721791661, + 'test-step-name', + 12, + 'test-feature-file', + 'failed_', + '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '1721791661.failed_test-feature-file.feature_12.png', + ], + [ + 'png', + '{datetime:U}.{feature_file}.feature_{step_name}.feature_{step_line}', + FALSE, + new \Exception('test'), + 1721791661, + 'test-step-name', + 12, + 'test-feature-file', + 'failed_', + '{datetime:U}.{feature_file}.feature_{step_line}.{ext}', + '{datetime:U}.{fail_prefix}{feature_file}.feature_{step_line}.{ext}', + '1721791661.test-feature-file.feature_test-step-name.feature_12.png', + ], + ]; + } + }