From 849e94dee6d94e928674abfc4a488e9269e5e4b1 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 15 Mar 2024 13:21:11 +0200 Subject: [PATCH] Ability to determine session freshness state --- CHANGELOG.md | 1 + docs/configuration.rst | 4 +- .../per_test_case_browser_config.php | 36 +++++++++ .../Session/AbstractSessionStrategy.php | 74 +++++++++++++++++++ .../PHPUnit/Session/ISessionStrategy.php | 7 ++ .../Session/IsolatedSessionStrategy.php | 33 ++------- .../PHPUnit/Session/SharedSessionStrategy.php | 36 +++------ ...hp => AbstractSessionStrategyTestCase.php} | 7 +- .../Session/IsolatedSessionStrategyTest.php | 14 +++- .../Session/SharedSessionStrategyTest.php | 36 ++++++--- 10 files changed, 183 insertions(+), 65 deletions(-) create mode 100644 library/aik099/PHPUnit/Session/AbstractSessionStrategy.php rename tests/aik099/PHPUnit/Session/{SessionStrategyTestCase.php => AbstractSessionStrategyTestCase.php} (79%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dbfc38..ffde367 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Specify failed PHPUnit assertion text to the BrowserStack ("reason" field)/SauceLabs("custom-data" field) test. - Added the `$auto_create` parameter to the `BrowserTestCase::getSession` method, which allows to verify is session is already started. +- Added the `ISessionStrategy::isFreshSession` method to indicate fact, that previous `ISessionStrategy::session` call have created a new session instead of reusing a previously created one. Can be used to perform a login once per a test case class. ### Changed - Bumped minimum PHP version to 5.6. diff --git a/docs/configuration.rst b/docs/configuration.rst index 21da167..c563f1b 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -29,13 +29,13 @@ in that test case class. Browser Session Sharing ^^^^^^^^^^^^^^^^^^^^^^^ As a benefit of the shared (per test case) browser configuration, that was described above is an ability -to not only to share the browser configuration, that is used to create `Mink`_ session, but to actually share +to not only share the browser configuration, that is used to create `Mink`_ session, but to actually share created sessions between all tests in a single test case. This can be done by adding the ``sessionStrategy`` option (line 15) to the browser configuration. .. literalinclude:: examples/configuration/per_test_case_browser_config.php :linenos: - :emphasize-lines: 15 + :emphasize-lines: 15,26,48 Selecting the Mink Driver ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/examples/configuration/per_test_case_browser_config.php b/docs/examples/configuration/per_test_case_browser_config.php index 87f7a1a..5320cd8 100644 --- a/docs/examples/configuration/per_test_case_browser_config.php +++ b/docs/examples/configuration/per_test_case_browser_config.php @@ -16,4 +16,40 @@ class CommonBrowserConfigTest extends BrowserTestCase ), ); + /** + * @before + */ + public function setUpTest() + { + parent::setUpTest(); + + if ( $this->getSessionStrategy()->isFreshSession() ) { + // login once before any of the tests was started + } + } + + public function testOne() + { + // user will be already logged-in regardless + // of the test execution order/filtering + } + + public function testTwo() + { + // user will be already logged-in regardless + // of the test execution order/filtering + } + + /** + * @after + */ + public function tearDownTest() + { + if ( $this->getSessionStrategy()->isFreshSession() ) { + // logout once after all of the tests were finished + } + + parent::tearDownTest(); + } + } diff --git a/library/aik099/PHPUnit/Session/AbstractSessionStrategy.php b/library/aik099/PHPUnit/Session/AbstractSessionStrategy.php new file mode 100644 index 0000000..09f30f6 --- /dev/null +++ b/library/aik099/PHPUnit/Session/AbstractSessionStrategy.php @@ -0,0 +1,74 @@ + + * @link https://github.com/aik099/phpunit-mink + */ + +namespace aik099\PHPUnit\Session; + + +use aik099\PHPUnit\BrowserTestCase; +use Behat\Mink\Session; + +abstract class AbstractSessionStrategy implements ISessionStrategy +{ + + /** + * Determines if the session was just started. + * + * @var boolean|null + */ + protected $isFreshSession; + + /** + * @inheritDoc + */ + public function isFreshSession() + { + return $this->isFreshSession; + } + + /** + * @inheritDoc + */ + public function onTestEnded(BrowserTestCase $test_case) + { + + } + + /** + * @inheritDoc + */ + public function onTestFailed(BrowserTestCase $test_case, $exception) + { + + } + + /** + * @inheritDoc + */ + public function onTestSuiteEnded(BrowserTestCase $test_case) + { + + } + + /** + * Stops the session. + * + * @param Session|null $session Session. + * + * @return void + */ + protected function stopSession(Session $session = null) + { + if ( $session !== null && $session->isStarted() ) { + $session->stop(); + $this->isFreshSession = null; + } + } + +} diff --git a/library/aik099/PHPUnit/Session/ISessionStrategy.php b/library/aik099/PHPUnit/Session/ISessionStrategy.php index 41656f0..3f3b159 100644 --- a/library/aik099/PHPUnit/Session/ISessionStrategy.php +++ b/library/aik099/PHPUnit/Session/ISessionStrategy.php @@ -32,6 +32,13 @@ interface ISessionStrategy */ public function session(BrowserConfiguration $browser); + /** + * Determines if the session was just started. + * + * @return boolean|null + */ + public function isFreshSession(); + /** * Hook, called from "BrowserTestCase::tearDownTest" method. * diff --git a/library/aik099/PHPUnit/Session/IsolatedSessionStrategy.php b/library/aik099/PHPUnit/Session/IsolatedSessionStrategy.php index ecae412..2cdbf18 100644 --- a/library/aik099/PHPUnit/Session/IsolatedSessionStrategy.php +++ b/library/aik099/PHPUnit/Session/IsolatedSessionStrategy.php @@ -20,7 +20,7 @@ * * @method \Mockery\Expectation shouldReceive(string $name) */ -class IsolatedSessionStrategy implements ISessionStrategy +class IsolatedSessionStrategy extends AbstractSessionStrategy { /** @@ -41,15 +41,14 @@ public function __construct(ISessionFactory $session_factory) } /** - * Returns Mink session with given browser configuration. - * - * @param BrowserConfiguration $browser Browser configuration for a session. - * - * @return Session + * @inheritDoc */ public function session(BrowserConfiguration $browser) { - return $this->_sessionFactory->createSession($browser); + $session = $this->_sessionFactory->createSession($browser); + $this->isFreshSession = true; + + return $session; } /** @@ -59,25 +58,7 @@ public function onTestEnded(BrowserTestCase $test_case) { $session = $test_case->getSession(false); - if ( $session !== null && $session->isStarted() ) { - $session->stop(); - } - } - - /** - * @inheritDoc - */ - public function onTestFailed(BrowserTestCase $test_case, $exception) - { - - } - - /** - * @inheritDoc - */ - public function onTestSuiteEnded(BrowserTestCase $test_case) - { - + $this->stopSession($session); } } diff --git a/library/aik099/PHPUnit/Session/SharedSessionStrategy.php b/library/aik099/PHPUnit/Session/SharedSessionStrategy.php index 9a8b4f6..9b003dc 100644 --- a/library/aik099/PHPUnit/Session/SharedSessionStrategy.php +++ b/library/aik099/PHPUnit/Session/SharedSessionStrategy.php @@ -22,7 +22,7 @@ * * @method \Mockery\Expectation shouldReceive(string $name) */ -class SharedSessionStrategy implements ISessionStrategy +class SharedSessionStrategy extends AbstractSessionStrategy { /** @@ -57,23 +57,21 @@ public function __construct(ISessionStrategy $original_strategy) } /** - * Returns Mink session with given browser configuration. - * - * @param BrowserConfiguration $browser Browser configuration for a session. - * - * @return Session + * @inheritDoc */ public function session(BrowserConfiguration $browser) { if ( $this->_lastTestFailed ) { - $this->stopSession(); + $this->stopAndForgetSession(); $this->_lastTestFailed = false; } if ( $this->_session === null ) { $this->_session = $this->_originalStrategy->session($browser); + $this->isFreshSession = $this->_originalStrategy->isFreshSession(); } else { + $this->isFreshSession = false; $this->_switchToMainWindow(); } @@ -81,18 +79,16 @@ public function session(BrowserConfiguration $browser) } /** - * Stops session. + * Stops and forgets a session. * * @return void */ - protected function stopSession() + protected function stopAndForgetSession() { - if ( $this->_session === null ) { - return; + if ( $this->_session !== null ) { + $this->stopSession($this->_session); + $this->_session = null; } - - $this->_session->stop(); - $this->_session = null; } /** @@ -105,14 +101,6 @@ private function _switchToMainWindow() $this->_session->switchToWindow(null); } - /** - * @inheritDoc - */ - public function onTestEnded(BrowserTestCase $test_case) - { - - } - /** * @inheritDoc */ @@ -132,9 +120,7 @@ public function onTestSuiteEnded(BrowserTestCase $test_case) { $session = $test_case->getSession(false); - if ( $session !== null && $session->isStarted() ) { - $session->stop(); - } + $this->stopSession($session); } } diff --git a/tests/aik099/PHPUnit/Session/SessionStrategyTestCase.php b/tests/aik099/PHPUnit/Session/AbstractSessionStrategyTestCase.php similarity index 79% rename from tests/aik099/PHPUnit/Session/SessionStrategyTestCase.php rename to tests/aik099/PHPUnit/Session/AbstractSessionStrategyTestCase.php index a3e4354..ffbff9a 100644 --- a/tests/aik099/PHPUnit/Session/SessionStrategyTestCase.php +++ b/tests/aik099/PHPUnit/Session/AbstractSessionStrategyTestCase.php @@ -17,7 +17,7 @@ use Behat\Mink\Session; use aik099\PHPUnit\BrowserTestCase; -class SessionStrategyTestCase extends AbstractTestCase +abstract class AbstractSessionStrategyTestCase extends AbstractTestCase { const BROWSER_CLASS = BrowserConfiguration::class; @@ -33,4 +33,9 @@ class SessionStrategyTestCase extends AbstractTestCase */ protected $strategy; + public function testUnknownSessionFreshnessStateUntilItsStarted() + { + $this->assertNull($this->strategy->isFreshSession()); + } + } diff --git a/tests/aik099/PHPUnit/Session/IsolatedSessionStrategyTest.php b/tests/aik099/PHPUnit/Session/IsolatedSessionStrategyTest.php index 3f40dfd..664c7e2 100644 --- a/tests/aik099/PHPUnit/Session/IsolatedSessionStrategyTest.php +++ b/tests/aik099/PHPUnit/Session/IsolatedSessionStrategyTest.php @@ -16,7 +16,7 @@ use Mockery as m; use Mockery\MockInterface; -class IsolatedSessionStrategyTest extends SessionStrategyTestCase +class IsolatedSessionStrategyTest extends AbstractSessionStrategyTestCase { /** @@ -57,6 +57,18 @@ public function testSession() $this->assertEquals($session2, $this->strategy->session($browser)); } + public function testIsFreshSessionAfterSessionIsStarted() + { + $browser = m::mock(self::BROWSER_CLASS); + $session = m::mock(self::SESSION_CLASS); + + $this->_factory->shouldReceive('createSession')->with($browser)->once()->andReturn($session); + + $this->strategy->session($browser); + + $this->assertTrue($this->strategy->isFreshSession()); + } + /** * Test description. * diff --git a/tests/aik099/PHPUnit/Session/SharedSessionStrategyTest.php b/tests/aik099/PHPUnit/Session/SharedSessionStrategyTest.php index aa0abe1..28a84d9 100644 --- a/tests/aik099/PHPUnit/Session/SharedSessionStrategyTest.php +++ b/tests/aik099/PHPUnit/Session/SharedSessionStrategyTest.php @@ -12,6 +12,7 @@ use aik099\PHPUnit\BrowserConfiguration\BrowserConfiguration; +use aik099\PHPUnit\Session\ISessionStrategy; use aik099\PHPUnit\Session\IsolatedSessionStrategy; use aik099\PHPUnit\Session\SharedSessionStrategy; use Behat\Mink\Session; @@ -20,7 +21,7 @@ use Mockery as m; use Mockery\MockInterface; -class SharedSessionStrategyTest extends SessionStrategyTestCase +class SharedSessionStrategyTest extends AbstractSessionStrategyTestCase { /** @@ -28,7 +29,7 @@ class SharedSessionStrategyTest extends SessionStrategyTestCase * * @var IsolatedSessionStrategy */ - private $_isolatedStrategy; + private $_originalStrategy; /** * First created session. @@ -52,8 +53,8 @@ protected function setUpTest() $this->_session1 = $this->createSession(); $this->_session2 = $this->createSession(); - $this->_isolatedStrategy = m::mock(IsolatedSessionStrategy::class); - $this->strategy = new SharedSessionStrategy($this->_isolatedStrategy); + $this->_originalStrategy = m::mock(ISessionStrategy::class); + $this->strategy = new SharedSessionStrategy($this->_originalStrategy); } /** @@ -68,17 +69,20 @@ public function testSessionSharing(\Exception $e = null) { /** @var BrowserConfiguration $browser */ $browser = m::mock(self::BROWSER_CLASS); - $this->_isolatedStrategy->shouldReceive('session')->once()->with($browser)->andReturn($this->_session1); + $this->_originalStrategy->shouldReceive('session')->once()->with($browser)->andReturn($this->_session1); + $this->_originalStrategy->shouldReceive('isFreshSession')->once()->andReturn(true); $this->_session1->shouldReceive('switchToWindow')->once(); $this->assertSame($this->_session1, $this->strategy->session($browser)); + $this->assertTrue($this->strategy->isFreshSession(), 'First created session must be fresh'); if ( isset($e) ) { $this->_sessionFailure($e); } $this->assertSame($this->_session1, $this->strategy->session($browser)); + $this->assertFalse($this->strategy->isFreshSession(), 'Reused session must not be fresh'); } /** @@ -89,9 +93,9 @@ public function testSessionSharing(\Exception $e = null) public static function ignoreExceptionDataProvider() { return array( - array(null), - array(new IncompleteTestError()), - array(new SkippedTestError()), + 'no error' => array(null), + 'incomplete test' => array(new IncompleteTestError()), + 'skipped test' => array(new SkippedTestError()), ); } @@ -105,22 +109,31 @@ public function testSessionResetOnFailure() /** @var BrowserConfiguration $browser */ $browser = m::mock(self::BROWSER_CLASS); - $this->_isolatedStrategy + $this->_originalStrategy ->shouldReceive('session') ->with($browser) ->twice() ->andReturn($this->_session1, $this->_session2); + $this->_originalStrategy + ->shouldReceive('isFreshSession') + ->twice() + ->andReturn(true); + $this->_session1->shouldReceive('isStarted')->once()->andReturn(true); $this->_session1->shouldReceive('stop')->once(); $this->_session2->shouldReceive('switchToWindow')->once(); $session = $this->strategy->session($browser); $this->assertSame($this->_session1, $session); + $this->assertTrue($this->strategy->isFreshSession(), 'First created session must be fresh'); $this->_sessionFailure(new \Exception()); $this->assertSame($this->_session2, $this->strategy->session($browser)); + $this->assertTrue($this->strategy->isFreshSession(), 'First created session after failure must be fresh'); + $this->assertSame($this->_session2, $this->strategy->session($browser)); + $this->assertFalse($this->strategy->isFreshSession(), 'Reused session must not be fresh'); } /** @@ -132,8 +145,11 @@ public function testImmediateSessionFailure() { $this->_sessionFailure(new \Exception()); - $this->_isolatedStrategy->shouldReceive('session')->once()->andReturn($this->_session1); + $this->_originalStrategy->shouldReceive('session')->once()->andReturn($this->_session1); + $this->_originalStrategy->shouldReceive('isFreshSession')->once()->andReturn(true); + $this->assertSame($this->_session1, $this->strategy->session(m::mock(self::BROWSER_CLASS))); + $this->assertTrue($this->strategy->isFreshSession(), 'First created session after failure must be fresh'); } /**