diff --git a/.gitignore b/.gitignore
index f0c5241..c58e3f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
composer.lock
vendor
.php_cs.cache
+.phpunit.result.cache
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..bc5fc14
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,46 @@
+# Changelog
+
+[![Build Status](https://travis-ci.org/OskarStark/SonataAdminBehatContext.svg?branch=master)](https://travis-ci.org/OskarStark/SonataAdminBehatContext)
+
+## Upgrading from 1.x to 2.0
+
+- The `friends-of-behat/symfony-extension` is used instead of `behat/symfony2-extension` (that is not maintained anymore)
+- The context `SonataAdminContext` has been split into two separate contexts.
+
+ - `SonataAdminContext` contains step definitions for `sonata-project/admin-bundle`.
+ - `SonataAdminUserBundleContext` contains step definitions for `sonata-project/user-bundle`.
+
+Before:
+```yaml
+# behat.yml.dist
+default:
+ suites:
+ default:
+ contexts:
+ - OStark\Context\SonataAdminContext:
+ userManager: '@sonata.user.user_manager'
+ tokenStorage: '@security.token_storage'
+ session: '@session'
+```
+
+After:
+```yaml
+# behat.yml.dist
+default:
+ suites:
+ default:
+ contexts:
+ - OStark\Context\SonataAdminContext:
+ # needed only if you are using sonata-project/user-bundle
+ - OStark\Context\SonataAdminUserBundleContext:
+
+# config/services_test.yaml
+services:
+ OStark\Context\SonataAdminUserBundleContext:
+ arguments:
+ - '@sonata.user.user_manager'
+ - '@security.token_storage'
+ - '@session'
+ - '@service_container'
+
+```
diff --git a/README.md b/README.md
index 13dadeb..b14b159 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,8 @@ default:
default:
contexts:
- OStark\Context\SonataAdminContext:
+ # this can be disabled if you do not use the SonataAdminUserBundle
+ - OStark\Context\SonataAdminUserBundleContext:
userManager: '@sonata.user.user_manager'
tokenStorage: '@security.token_storage'
session: '@session'
diff --git a/composer.json b/composer.json
index 52340e5..daee4bf 100644
--- a/composer.json
+++ b/composer.json
@@ -21,14 +21,14 @@
"php": ">=7.1",
"behat/behat": "^3.0",
"behat/mink-extension": "^2.3",
- "behat/symfony2-extension": "^2.1",
- "sonata-project/user-bundle": "^4.0"
+ "friends-of-behat/symfony-extension": "^2.1"
},
"require-dev": {
"behat/mink-goutte-driver": "^1.1",
"behat/mink-selenium2-driver": "^1.3",
"guzzlehttp/guzzle": "^6.3",
- "phpunit/phpunit": "^6.0",
+ "phpunit/phpunit": "^7.0|^8.5.21",
+ "sonata-project/user-bundle": "^4.0",
"symfony/browser-kit": "^4.3"
},
"config": {
@@ -43,5 +43,8 @@
"psr-4": {
"Tests\\OStark\\": "tests/"
}
+ },
+ "suggest": {
+ "sonata-project/user-bundle": "Allows User & Authentication scenarios"
}
}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 597b238..8ec4d7d 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -13,5 +13,9 @@
tests
-
+
+
+ src
+
+
diff --git a/src/Context/SonataAdminContext.php b/src/Context/SonataAdminContext.php
index a4e6f77..529768e 100644
--- a/src/Context/SonataAdminContext.php
+++ b/src/Context/SonataAdminContext.php
@@ -13,72 +13,22 @@
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use Behat\Gherkin\Node\TableNode;
-use Behat\Mink\Driver\BrowserKitDriver;
-use Behat\Mink\Driver\Selenium2Driver;
use Behat\Mink\Element\NodeElement;
use Behat\Mink\Exception\ElementNotFoundException;
use Behat\Mink\Exception\ExpectationException;
-use Behat\Mink\Exception\UnsupportedDriverActionException;
use Behat\MinkExtension\Context\MinkContext;
use Behat\MinkExtension\Context\RawMinkContext;
-use Behat\Symfony2Extension\Context\KernelAwareContext;
-use Sonata\UserBundle\Model\UserManagerInterface;
-use Symfony\Component\BrowserKit\Cookie;
-use Symfony\Component\HttpFoundation\Session\Session;
-use Symfony\Component\HttpKernel\KernelInterface;
-use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
-use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
-use Symfony\Component\Security\Core\User\UserInterface;
/**
* Defines features for the SonataAdmin context.
*/
-final class SonataAdminContext extends RawMinkContext implements KernelAwareContext
+final class SonataAdminContext extends RawMinkContext
{
- const DEFAULT_USERNAME = 'test@example.com';
-
- /**
- * @var UserInterface
- */
- private $user;
-
- /**
- * @var UserManagerInterface
- */
- protected $userManager;
-
- /**
- * @var TokenStorageInterface
- */
- protected $tokenStorage;
-
- /**
- * @var Session
- */
- protected $session;
-
- /**
- * @var KernelInterface
- */
- protected $kernel;
-
/**
* @var MinkContext
*/
private $minkContext;
- public function __construct(UserManagerInterface $userManager, TokenStorageInterface $tokenStorage, Session $session)
- {
- $this->userManager = $userManager;
- $this->tokenStorage = $tokenStorage;
- $this->session = $session;
- }
-
- public function setKernel(KernelInterface $kernel)
- {
- $this->kernel = $kernel;
- }
-
/**
* @BeforeScenario
*/
@@ -323,86 +273,6 @@ public function iCloseFlashMessage()
$xButton->click();
}
- /**
- * @When /^(?:|I )delete last created user$/
- *
- * @codeCoverageIgnore Selenium2Driver needed
- */
- public function deleteLastCreatedUser()
- {
- $user = $this->userManager->findBy([], ['createdAt' => 'DESC'], 1);
- $this->userManager->deleteUser(current($user));
- }
-
- /**
- * @Given /^I am an authenticated User$/
- *
- * @throws ExpectationException
- * @throws UnsupportedDriverActionException
- *
- * @codeCoverageIgnore Selenium2Driver needed
- */
- public function iAmAnAuthenticatedUser()
- {
- $user = $this->userManager->createUser();
-
- $user->setEmail(self::DEFAULT_USERNAME);
- $user->setUsername(self::DEFAULT_USERNAME);
- $user->setPlainPassword('foobar');
-
- $this->userManager->updateUser($user);
-
- $this->user = $user;
-
- $this->createUserSession($user);
- }
-
- /**
- * @Given /^I have role "([^"]*)"$/
- *
- * @param string $role
- *
- * @throws ExpectationException
- * @throws UnsupportedDriverActionException
- *
- * @codeCoverageIgnore Selenium2Driver needed
- */
- public function iHaveRole($role)
- {
- $user = $this->getCurrentUser();
-
- $user->setRoles([$role]);
- $this->userManager->updateUser($user);
-
- $this->user = $user;
-
- $this->createUserSession($user);
- }
-
- /**
- * @Given /^I am authenticated as User "([^"]*)"$/
- *
- * @param string $username
- *
- * @throws ExpectationException
- * @throws UnsupportedDriverActionException
- *
- * @codeCoverageIgnore Selenium2Driver needed
- */
- public function iAmAuthenticatedAsUser($username)
- {
- $driver = $this->getSession()->getDriver();
-
- $user = $this->userManager->findOneBy(['username' => $username]);
- if (null === $user) {
- throw new ExpectationException(sprintf('User with username "%s" does not exist', $username), $driver);
- }
-
- $this->user = $user;
-
- $this->createUserSession($user);
- }
-
/**
* @When /^(?:|I )logout User$/
*
@@ -648,54 +518,6 @@ public function theFieldShouldNotBeEmtpy($field)
$this->assertSession()->fieldValueNotEquals($field, '');
}
- /**
- * @throws UnsupportedDriverActionException
- *
- * @codeCoverageIgnore Selenium2Driver needed
- */
- private function createUserSession(UserInterface $user)
- {
- $providerKey = $this->kernel->getContainer()->getParameter('fos_user.firewall_name');
-
- $token = new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());
- $this->tokenStorage->setToken($token);
-
- $authenticated = $this->tokenStorage->getToken()->isAuthenticated();
- if (!$authenticated) {
- throw new \RuntimeException('Not authenticated!');
- }
-
- $this->session->set('_security_'.$providerKey, serialize($token));
- $this->session->save();
-
- $driver = $this->getSession()->getDriver();
- if ($driver instanceof BrowserKitDriver) {
- $client = $driver->getClient();
- $cookie = new Cookie($this->session->getName(), $this->session->getId());
- $client->getCookieJar()->set($cookie);
- } elseif ($driver instanceof Selenium2Driver) {
- $this->visitPath('/'); // this step is needed, otherwise the user is not logged in the first time!
- } else {
- throw new UnsupportedDriverActionException('The Driver is not supported!', $driver);
- }
-
- $this->getSession()->setCookie($this->session->getName(), $this->session->getId());
- }
-
- private function getCurrentUser(): UserInterface
- {
- if (null != $this->user) {
- return $this->user;
- }
-
- $user = $this->userManager->findOneBy(['username' => self::DEFAULT_USERNAME]);
- if (null === $user) {
- throw new ExpectationException(sprintf('User with username "%s" does not exist', self::DEFAULT_USERNAME), $this->getSession()->getDriver());
- }
-
- return $user;
- }
-
/**
* Returns fixed step argument (with \\" replaced back to ").
*
@@ -773,9 +595,4 @@ private function notFindElement(string $locator, string $type): void
throw new ExpectationException(sprintf('%s found, but should not!', $type), $this->getSession()->getDriver());
}
}
-
- public static function getAcceptedSnippetType()
- {
- return 'regex';
- }
}
diff --git a/src/Context/SonataAdminUserBundleContext.php b/src/Context/SonataAdminUserBundleContext.php
new file mode 100644
index 0000000..8dae6cd
--- /dev/null
+++ b/src/Context/SonataAdminUserBundleContext.php
@@ -0,0 +1,199 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace OStark\Context;
+
+use Behat\Mink\Driver\BrowserKitDriver;
+use Behat\Mink\Driver\Selenium2Driver;
+use Behat\Mink\Exception\ExpectationException;
+use Behat\Mink\Exception\UnsupportedDriverActionException;
+use Behat\MinkExtension\Context\RawMinkContext;
+use Sonata\UserBundle\Entity\UserManager;
+use Sonata\UserBundle\Model\UserManagerInterface;
+use Symfony\Component\BrowserKit\Cookie;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\User\UserInterface;
+
+/**
+ * Defines features for the SonataAdmin context that make use of the Sonata UserBundle.
+ */
+final class SonataAdminUserBundleContext extends RawMinkContext
+{
+ const DEFAULT_USERNAME = 'test@example.com';
+
+ /**
+ * @var UserInterface
+ */
+ private $user;
+
+ /**
+ * @var UserManagerInterface
+ */
+ protected $userManager;
+
+ /**
+ * @var TokenStorageInterface
+ */
+ protected $tokenStorage;
+
+ /**
+ * @var Session
+ */
+ protected $session;
+
+ /**
+ * @var ContainerInterface
+ */
+ protected $container;
+
+ public function __construct(
+ UserManager $userManager,
+ TokenStorageInterface $tokenStorage,
+ Session $session,
+ ContainerInterface $container
+ ) {
+ $this->userManager = $userManager;
+ $this->tokenStorage = $tokenStorage;
+ $this->session = $session;
+ $this->container = $container;
+ }
+
+ /**
+ * @When /^(?:|I )delete last created user$/
+ *
+ * @codeCoverageIgnore Selenium2Driver needed
+ */
+ public function deleteLastCreatedUser()
+ {
+ $user = $this->userManager->findBy([], ['createdAt' => 'DESC'], 1);
+ $this->userManager->deleteUser(current($user));
+ }
+
+ /**
+ * @Given /^I am an authenticated User$/
+ *
+ * @throws ExpectationException
+ * @throws UnsupportedDriverActionException
+ *
+ * @codeCoverageIgnore Selenium2Driver needed
+ */
+ public function iAmAnAuthenticatedUser()
+ {
+ $user = $this->userManager->createUser();
+
+ $user->setEmail(self::DEFAULT_USERNAME);
+ $user->setUsername(self::DEFAULT_USERNAME);
+ $user->setPlainPassword('foobar');
+
+ $this->userManager->updateUser($user);
+
+ $this->user = $user;
+
+ $this->createUserSession($user);
+ }
+
+ /**
+ * @Given /^I have role "([^"]*)"$/
+ *
+ * @param string $role
+ *
+ * @throws ExpectationException
+ * @throws UnsupportedDriverActionException
+ *
+ * @codeCoverageIgnore Selenium2Driver needed
+ */
+ public function iHaveRole($role)
+ {
+ $user = $this->getCurrentUser();
+
+ $user->setRoles([$role]);
+ $this->userManager->updateUser($user);
+
+ $this->user = $user;
+
+ $this->createUserSession($user);
+ }
+
+ /**
+ * @Given /^I am authenticated as User "([^"]*)"$/
+ *
+ * @param string $username
+ *
+ * @throws ExpectationException
+ * @throws UnsupportedDriverActionException
+ *
+ * @codeCoverageIgnore Selenium2Driver needed
+ */
+ public function iAmAuthenticatedAsUser($username)
+ {
+ $driver = $this->getSession()->getDriver();
+
+ $user = $this->userManager->findOneBy(['username' => $username]);
+ if (null === $user) {
+ throw new ExpectationException(sprintf('User with username "%s" does not exist', $username), $driver);
+ }
+
+ $this->user = $user;
+
+ $this->createUserSession($user);
+ }
+
+ /**
+ * @throws UnsupportedDriverActionException
+ *
+ * @codeCoverageIgnore Selenium2Driver needed
+ */
+ private function createUserSession(UserInterface $user)
+ {
+ $providerKey = $this->container->getParameter('fos_user.firewall_name');
+
+ $token = new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());
+ $this->tokenStorage->setToken($token);
+
+ $authenticated = $this->tokenStorage->getToken()->isAuthenticated();
+ if (!$authenticated) {
+ throw new \RuntimeException('Not authenticated!');
+ }
+
+ $this->session->set('_security_'.$providerKey, serialize($token));
+ $this->session->save();
+
+ $driver = $this->getSession()->getDriver();
+ if ($driver instanceof BrowserKitDriver) {
+ $client = $driver->getClient();
+ $cookie = new Cookie($this->session->getName(), $this->session->getId());
+ $client->getCookieJar()->set($cookie);
+ } elseif ($driver instanceof Selenium2Driver) {
+ $this->visitPath('/'); // this step is needed, otherwise the user is not logged in the first time!
+ } else {
+ throw new UnsupportedDriverActionException('The Driver is not supported!', $driver);
+ }
+
+ $this->getSession()->setCookie($this->session->getName(), $this->session->getId());
+ }
+
+ private function getCurrentUser(): UserInterface
+ {
+ if (null != $this->user) {
+ return $this->user;
+ }
+
+ $user = $this->userManager->findOneBy(['username' => self::DEFAULT_USERNAME]);
+ if (null === $user) {
+ throw new ExpectationException(sprintf('User with username "%s" does not exist', self::DEFAULT_USERNAME), $this->getSession()->getDriver());
+ }
+
+ return $user;
+ }
+}
diff --git a/tests/Context/SonataAdminContextTest.php b/tests/Context/SonataAdminContextTest.php
index 0a41ed9..df25154 100644
--- a/tests/Context/SonataAdminContextTest.php
+++ b/tests/Context/SonataAdminContextTest.php
@@ -14,9 +14,6 @@
use Behat\Mink\Element\NodeElement;
use OStark\Context\SonataAdminContext;
use OStark\Test\BaseTestCase;
-use Sonata\UserBundle\Model\UserManagerInterface;
-use Symfony\Component\HttpFoundation\Session\Session;
-use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class SonataAdminContextTest extends BaseTestCase
{
@@ -25,13 +22,9 @@ class SonataAdminContextTest extends BaseTestCase
*/
private $context;
- protected function setUp()
+ protected function setUp(): void
{
- $this->context = new SonataAdminContext(
- $this->createMock(UserManagerInterface::class),
- $this->createMock(TokenStorageInterface::class),
- $this->createMock(Session::class)
- );
+ $this->context = new SonataAdminContext();
}
/**
diff --git a/tests/Context/SonataAdminUserBundleContextTest.php b/tests/Context/SonataAdminUserBundleContextTest.php
new file mode 100644
index 0000000..de430f6
--- /dev/null
+++ b/tests/Context/SonataAdminUserBundleContextTest.php
@@ -0,0 +1,181 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Tests\OStark\Context;
+
+use Behat\Mink\Mink;
+use FOS\UserBundle\Model\UserInterface;
+use OStark\Context\SonataAdminUserBundleContext;
+use OStark\Test\BaseTestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+use Sonata\UserBundle\Entity\BaseUser;
+use Sonata\UserBundle\Model\UserManagerInterface;
+use Symfony\Component\DependencyInjection\Container;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+
+class SonataAdminUserBundleContextTest extends BaseTestCase
+{
+ /**
+ * @var SonataAdminUserBundleContext
+ */
+ private $context;
+
+ /**
+ * @var MockObject&UserManagerInterface
+ */
+ private $userManager;
+
+ /**
+ * @var MockObject&Session
+ */
+ private $session;
+
+ /**
+ * @var MockObject&TokenStorageInterface
+ */
+ private $tokenStorage;
+
+ /**
+ * @var Mink
+ */
+ private $mink;
+
+ protected function setUp(): void
+ {
+ $this->session = new Session(new MockArraySessionStorage());
+ $this->tokenStorage = new TokenStorage();
+
+ $container = new Container();
+ $container->setParameter('fos_user.firewall_name', 'foo');
+
+ $this->context = new SonataAdminUserBundleContext(
+ $this->userManager = $this->createMock(\Sonata\UserBundle\Entity\UserManager::class),
+ $this->tokenStorage,
+ $this->session,
+ $container
+ );
+
+ $this->mink = self::setupMink('
');
+ $this->context->setMink($this->mink);
+ }
+
+ /**
+ * @test
+ */
+ public function deleteLastCreatedUser()
+ {
+ $users = [$this->createMock(UserInterface::class)];
+ $this->userManager
+ ->expects(self::once())
+ ->method('findBy')
+ ->with([], ['createdAt' => 'DESC'], 1)
+ ->willReturn($users);
+
+ $this->userManager
+ ->expects(self::once())
+ ->method('deleteUser')
+ ->with($users[0]);
+
+ $this->context->deleteLastCreatedUser();
+ }
+
+ /**
+ * @test
+ */
+ public function iAmAnAuthenticatedUser()
+ {
+ $user = new BaseUser();
+
+ $this->userManager
+ ->expects(self::once())
+ ->method('createUser')
+ ->willReturn($user);
+
+ $this->userManager
+ ->expects(self::once())
+ ->method('updateUser')
+ ->with($user);
+
+ $this->context->iAmAnAuthenticatedUser();
+
+ self::assertSame('test@example.com', $user->getUsername());
+ $this->assertSessionDataValid($user);
+ }
+
+ /**
+ * @test
+ */
+ public function iHaveRole()
+ {
+ $user = new BaseUser();
+
+ $this->userManager
+ ->expects(self::once())
+ ->method('findOneBy')
+ ->with(['username' => 'test@example.com'])
+ ->willReturn($user);
+
+ $this->userManager
+ ->expects(self::never())
+ ->method('createUser');
+
+ $this->userManager
+ ->expects(self::once())
+ ->method('updateUser')
+ ->with($user);
+
+ $this->context->iHaveRole('foo');
+
+ self::assertSame(['FOO', 'ROLE_USER'], $user->getRoles());
+
+ $this->assertSessionDataValid($user);
+ }
+
+ /**
+ * @test
+ */
+ public function iAmAuthenticatedAsUser()
+ {
+ $user = new BaseUser();
+
+ $this->userManager
+ ->expects(self::once())
+ ->method('findOneBy')
+ ->with(['username' => 'me@example.com'])
+ ->willReturn($user);
+
+ $this->userManager
+ ->expects(self::never())
+ ->method('createUser');
+
+ $this->userManager
+ ->expects(self::never())
+ ->method('updateUser');
+
+ $this->context->iAmAuthenticatedAsUser('me@example.com');
+
+ self::assertSame(['ROLE_USER'], $user->getRoles());
+
+ $this->assertSessionDataValid($user);
+ }
+
+ private function assertSessionDataValid(BaseUser $user): void
+ {
+ self::assertTrue($this->session->has('_security_foo'));
+ self::assertSame($this->session->getId(), $this->mink->getSession()->getCookie($this->session->getName()));
+ self::assertInstanceOf(UsernamePasswordToken::class, $this->tokenStorage->getToken());
+ self::assertSame($user, $this->tokenStorage->getToken()->getUser());
+ }
+}