[Behat] Migrate phpspec to PHPUnit tests

This commit is contained in:
Grzegorz Sadowski 2025-05-23 14:58:03 +02:00
parent eb8b4f00af
commit eddc8e3efd
No known key found for this signature in database
GPG key ID: EF87FF4E6E3BD364
27 changed files with 1025 additions and 864 deletions

View file

@ -284,7 +284,7 @@
"autoload-dev": {
"psr-4": {
"Sylius\\Tests\\": "tests/",
"spec\\Sylius\\Behat\\": "src/Sylius/Behat/spec/",
"Tests\\Sylius\\Behat\\": "src/Sylius/Behat/tests/",
"spec\\Sylius\\Component\\Addressing\\": "src/Sylius/Component/Addressing/spec/",
"spec\\Sylius\\Component\\Attribute\\": "src/Sylius/Component/Attribute/spec/",
"spec\\Sylius\\Component\\Channel\\": "src/Sylius/Component/Channel/spec/",

View file

@ -40,5 +40,3 @@ suites:
TaxonomyBundle: { namespace: Sylius\Bundle\TaxonomyBundle, psr4_prefix: Sylius\Bundle\TaxonomyBundle, spec_path: src/Sylius/Bundle/TaxonomyBundle, src_path: src/Sylius/Bundle/TaxonomyBundle }
UiBundle: { namespace: Sylius\Bundle\UiBundle, psr4_prefix: Sylius\Bundle\UiBundle, spec_path: src/Sylius/Bundle/UiBundle, src_path: src/Sylius/Bundle/UiBundle }
UserBundle: { namespace: Sylius\Bundle\UserBundle, psr4_prefix: Sylius\Bundle\UserBundle, spec_path: src/Sylius/Bundle/UserBundle, src_path: src/Sylius/Bundle/UserBundle }
Behat: { namespace: Sylius\Behat, psr4_prefix: Sylius\Behat, spec_path: src/Sylius/Behat, src_path: src/Sylius/Behat }

View file

@ -1,15 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.de/manual/current/en/appendixes.configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/8.5/phpunit.xsd"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
bootstrap="config/bootstrap.php"
convertDeprecationsToExceptions="true"
>
<testsuites>
<testsuite name="Sylius Test Suite">
<testsuite name="all">
<directory>tests</directory>
<directory>src/Sylius/Behat/tests</directory>
</testsuite>
<testsuite name="sylius">
<directory>tests</directory>
</testsuite>
<testsuite name="sylius-behat">
<directory>src/Sylius/Behat/tests</directory>
</testsuite>
</testsuites>

View file

@ -12,7 +12,7 @@ use Rector\Visibility\Rector\ClassMethod\ExplicitPublicClassMethodRector;
return RectorConfig::configure()
->withPaths([
// __DIR__ . '/src/Sylius/Addressing/Locale/spec',
__DIR__ . '/src/Sylius/Behat/spec',
])
->withImportNames(removeUnusedImports: true)
->withSets([

View file

@ -1,31 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Behat;
use PhpSpec\ObjectBehavior;
final class NotificationTypeSpec extends ObjectBehavior
{
function it_initialize_with_success_value()
{
$this->beConstructedThrough('success');
$this->__toString()->shouldReturn('success');
}
function it_initialize_with_failure_value()
{
$this->beConstructedThrough('failure');
$this->__toString()->shouldReturn('failure');
}
}

View file

@ -1,97 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Behat\Service\Converter;
use ApiPlatform\Metadata\IriConverterInterface as BaseIriConverterInterface;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\UrlGeneratorInterface;
use PhpSpec\ObjectBehavior;
use Sylius\Behat\Service\Converter\IriConverterInterface;
use Sylius\Bundle\ApiBundle\Provider\PathPrefixes;
use Sylius\Bundle\ApiBundle\Resolver\OperationResolverInterface;
use Sylius\Component\Addressing\Model\Country;
use Sylius\Component\Addressing\Model\CountryInterface;
final class IriConverterSpec extends ObjectBehavior
{
function let(
BaseIriConverterInterface $decoratedIriConverter,
OperationResolverInterface $operationResolver,
): void {
$this->beConstructedWith($decoratedIriConverter, $operationResolver);
}
function it_implements_the_behat_iri_converter_interface(): void
{
$this->shouldImplement(IriConverterInterface::class);
}
function it_uses_inner_iri_converter_to_get_resource_from_iri(
IriConverterInterface $decoratedIriConverter,
CountryInterface $country,
): void {
$decoratedIriConverter->getResourceFromIri('api/v2/admin/countries/CODE', [], null)->willReturn($country);
$this->getResourceFromIri('api/v2/admin/countries/CODE')->shouldReturn($country);
}
function it_uses_inner_iri_converter_to_get_iri_from_resource(
IriConverterInterface $decoratedIriConverter,
CountryInterface $country,
): void {
$decoratedIriConverter
->getIriFromResource($country->getWrappedObject(), UrlGeneratorInterface::ABS_PATH, null, [])
->willReturn('api/v2/admin/countries/CODE')
;
$this->getIriFromResource($country->getWrappedObject())->shouldReturn('api/v2/admin/countries/CODE');
}
function it_provides_iri_from_resource_in_given_section(
IriConverterInterface $decoratedIriConverter,
OperationResolverInterface $operationResolver,
CountryInterface $country,
Operation $operation,
): void {
$operationResolver
->resolve(Country::class, PathPrefixes::ADMIN_PREFIX, null)
->willReturn($operation)
;
$decoratedIriConverter
->getIriFromResource(
$country->getWrappedObject(),
UrlGeneratorInterface::ABS_PATH,
$operation,
[
'force_resource_class' => Country::class,
],
)
->willReturn('api/v2/admin/countries/CODE')
;
$this
->getIriFromResourceInSection(
$country->getWrappedObject(),
PathPrefixes::ADMIN_PREFIX,
UrlGeneratorInterface::ABS_PATH,
null,
[
'force_resource_class' => Country::class,
],
)
->shouldReturn('api/v2/admin/countries/CODE')
;
}
}

View file

@ -1,36 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Behat\Service\Generator;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Core\Generator\ImagePathGeneratorInterface;
use Sylius\Component\Core\Model\ImageInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
final class UploadedImagePathGeneratorSpec extends ObjectBehavior
{
function it_implements_image_path_generator_interface(): void
{
$this->shouldImplement(ImagePathGeneratorInterface::class);
}
function it_generates_random_hashed_path_keeping_the_image_name(ImageInterface $image): void
{
$file = new UploadedFile(__DIR__ . '/ford.jpg', 'ford.jpg', null, null, true);
$image->getFile()->willReturn($file);
$this->generate($image)->shouldMatch('/[a-z0-9]{2}\/[a-z0-9]{2}\/[a-zA-Z0-9]+[_-]*\/ford[.]jpg/i');
}
}

View file

@ -1,91 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Behat\Service;
use Behat\Mink\Element\NodeElement;
use PhpSpec\ObjectBehavior;
use Sylius\Behat\Exception\NotificationExpectationMismatchException;
use Sylius\Behat\NotificationType;
use Sylius\Behat\Service\Accessor\NotificationAccessorInterface;
use Sylius\Behat\Service\NotificationChecker;
use Sylius\Behat\Service\NotificationCheckerInterface;
final class NotificationCheckerSpec extends ObjectBehavior
{
function let(NotificationAccessorInterface $notificationAccessor)
{
$this->beConstructedWith($notificationAccessor, ['failure' => 'negative', 'success' => 'alert-success']);
}
function it_is_initializable()
{
$this->shouldHaveType(NotificationChecker::class);
}
function it_implements_notification_checker_interface()
{
$this->shouldImplement(NotificationCheckerInterface::class);
}
function it_checks_if_successful_notification_with_specific_message_has_appeared(
NotificationAccessorInterface $notificationAccessor,
NodeElement $firstMessage,
NodeElement $secondMessage,
) {
$notificationAccessor->getMessageElements()->willReturn([$firstMessage, $secondMessage]);
$firstMessage->getText()->willReturn('Some resource has been successfully edited.');
$firstMessage->hasClass('alert-success')->willReturn(true);
$secondMessage->getText()->willReturn('Some resource has been successfully deleted.');
$secondMessage->hasClass('alert-success')->willReturn(true);
$this->checkNotification('Some resource has been successfully deleted.', NotificationType::success());
}
function it_checks_if_failure_notification_with_specific_message_has_appeared(
NotificationAccessorInterface $notificationAccessor,
NodeElement $firstMessage,
NodeElement $secondMessage,
) {
$notificationAccessor->getMessageElements()->willReturn([$firstMessage, $secondMessage]);
$firstMessage->getText()->willReturn('Some resource has been successfully edited.');
$firstMessage->hasClass('negative')->willReturn(false);
$secondMessage->getText()->willReturn('Some resource could not be deleted.');
$secondMessage->hasClass('negative')->willReturn(true);
$this->checkNotification('Some resource could not be deleted.', NotificationType::failure());
}
function it_throws_exception_if_no_message_with_given_content_and_type_has_been_found(
NotificationAccessorInterface $notificationAccessor,
NodeElement $firstMessage,
NodeElement $secondMessage,
) {
$notificationAccessor->getMessageElements()->willReturn([$firstMessage, $secondMessage]);
$firstMessage->getText()->willReturn('Some resource has been successfully edited.');
$firstMessage->hasClass('negative')->willReturn(false);
$secondMessage->getText()->willReturn('Some resource could not be deleted.');
$secondMessage->hasClass('negative')->willReturn(true);
$this
->shouldThrow(NotificationExpectationMismatchException::class)
->during('checkNotification', ['Some resource has been successfully created.', NotificationType::failure()])
;
}
}

View file

@ -1,54 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Behat\Service\Provider;
use PhpSpec\ObjectBehavior;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Sylius\Behat\Service\MessageSendCacher;
use Sylius\Behat\Service\Provider\EmailMessagesProviderInterface;
use Symfony\Component\Mime\Email;
final class EmailMessagesProviderSpec extends ObjectBehavior
{
function let(CacheItemPoolInterface $cacheItemPool): void
{
$this->beConstructedWith($cacheItemPool);
}
function it_implements_email_messages_provider_interface(): void
{
$this->shouldImplement(EmailMessagesProviderInterface::class);
}
function it_provides_email_messages(
CacheItemPoolInterface $cacheItemPool,
CacheItemInterface $cacheItem,
): void {
$emailMessages = [new Email(), new Email(), new Email()];
$cacheItem->get()->willReturn($emailMessages);
$cacheItemPool->hasItem(MessageSendCacher::CACHE_KEY)->willReturn(true);
$cacheItemPool->getItem(MessageSendCacher::CACHE_KEY)->willReturn($cacheItem);
$this->provide()->shouldReturn($emailMessages);
}
function it_returns_an_empty_array_if_cache_key_does_not_exist(CacheItemPoolInterface $cacheItemPool): void
{
$cacheItemPool->hasItem(MessageSendCacher::CACHE_KEY)->willReturn(false);
$this->provide()->shouldReturn([]);
}
}

View file

@ -1,69 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Behat\Service\Resolver;
use Behat\Mink\Session;
use FriendsOfBehat\PageObjectExtension\Page\SymfonyPageInterface;
use PhpSpec\ObjectBehavior;
use Sylius\Behat\Service\Resolver\CurrentPageResolver;
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
final class CurrentPageResolverSpec extends ObjectBehavior
{
function let(Session $session, UrlMatcherInterface $urlMatcher)
{
$this->beConstructedWith($session, $urlMatcher);
}
function it_is_initializable()
{
$this->shouldHaveType(CurrentPageResolver::class);
}
function it_implements_current_page_resolver_interface()
{
$this->shouldImplement(CurrentPageResolverInterface::class);
}
function it_returns_current_page_based_on_matched_route(
Session $session,
SymfonyPageInterface $createPage,
SymfonyPageInterface $updatePage,
UrlMatcherInterface $urlMatcher,
) {
$session->getCurrentUrl()->willReturn('https://sylius.com/resource/new');
$urlMatcher->match('/resource/new')->willReturn(['_route' => 'sylius_resource_create']);
$createPage->getRouteName()->willReturn('sylius_resource_create');
$updatePage->getRouteName()->willReturn('sylius_resource_update');
$this->getCurrentPageWithForm([$createPage, $updatePage])->shouldReturn($createPage);
}
function it_throws_an_exception_if_neither_create_nor_update_key_word_has_been_found(
Session $session,
SymfonyPageInterface $createPage,
SymfonyPageInterface $updatePage,
UrlMatcherInterface $urlMatcher,
) {
$session->getCurrentUrl()->willReturn('https://sylius.com/resource/show');
$urlMatcher->match('/resource/show')->willReturn(['_route' => 'sylius_resource_show']);
$createPage->getRouteName()->willReturn('sylius_resource_create');
$updatePage->getRouteName()->willReturn('sylius_resource_update');
$this->shouldThrow(\LogicException::class)->during('getCurrentPageWithForm', [[$createPage, $updatePage]]);
}
}

View file

@ -1,135 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Behat\Service;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Behat\Service\SecurityService;
use Sylius\Behat\Service\SecurityServiceInterface;
use Sylius\Behat\Service\Setter\CookieSetterInterface;
use Sylius\Component\Core\Model\ShopUserInterface;
use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionFactoryInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
final class SecurityServiceSpec extends ObjectBehavior
{
function let(
RequestStack $requestStack,
CookieSetterInterface $cookieSetter,
SessionFactoryInterface $sessionFactory,
SessionInterface $session,
): void {
$sessionFactory->createSession()->willReturn($session);
$this->beConstructedWith($requestStack, $cookieSetter, 'shop', $sessionFactory);
}
function it_is_initializable(): void
{
$this->shouldHaveType(SecurityService::class);
}
function it_implements_security_service_interface(): void
{
$this->shouldImplement(SecurityServiceInterface::class);
}
function it_logs_user_in_when_session_factory_is_not_available(
RequestStack $requestStack,
CookieSetterInterface $cookieSetter,
SessionInterface $session,
ShopUserInterface $shopUser,
): void {
$this->beConstructedWith($requestStack, $cookieSetter, 'shop');
$shopUser->getRoles()->willReturn(['ROLE_USER']);
$shopUser->getPassword()->willReturn('xyz');
$shopUser->__serialize()->willReturn(['serialized_user']);
$requestStack->getSession()->willReturn($session);
$session->set('_security_shop', Argument::any())->shouldBeCalled();
$session->save()->shouldBeCalled();
$session->getName()->willReturn('MOCKEDSID');
$session->getId()->willReturn('xyzc123');
$cookieSetter->setCookie('MOCKEDSID', 'xyzc123')->shouldBeCalled();
$this->logIn($shopUser);
}
function it_logs_user_in(
RequestStack $requestStack,
CookieSetterInterface $cookieSetter,
SessionFactoryInterface $sessionFactory,
SessionInterface $session,
ShopUserInterface $shopUser,
): void {
$sessionFactory->createSession()->willReturn($session);
$shopUser->getRoles()->willReturn(['ROLE_USER']);
$shopUser->getPassword()->willReturn('xyz');
$shopUser->__serialize()->willReturn(['serialized_user']);
$requestStack->push(Argument::type(Request::class))->shouldBeCalled();
$requestStack->getSession()->willReturn($session);
$session->set('_security_shop', Argument::any())->shouldBeCalled();
$session->save()->shouldBeCalled();
$session->getName()->willReturn('MOCKEDSID');
$session->getId()->willReturn('xyzc123');
$cookieSetter->setCookie('MOCKEDSID', 'xyzc123')->shouldBeCalled();
$this->logIn($shopUser);
}
function it_does_nothing_when_there_is_no_session_during_log_out(
RequestStack $requestStack,
CookieSetterInterface $cookieSetter,
): void {
$requestStack->getSession()->willThrow(SessionNotFoundException::class);
$cookieSetter->setCookie(Argument::cetera())->shouldNotBeCalled();
$this->logOut();
}
function it_logs_user_out(
RequestStack $requestStack,
SessionInterface $session,
CookieSetterInterface $cookieSetter,
): void {
$requestStack->getSession()->willReturn($session);
$session->set('_security_shop', null)->shouldBeCalled();
$session->save()->shouldBeCalled();
$session->getName()->willReturn('MOCKEDSID');
$session->getId()->willReturn('xyzc123');
$cookieSetter->setCookie('MOCKEDSID', 'xyzc123')->shouldBeCalled();
$this->logOut();
}
function it_throws_token_not_found_exception(
RequestStack $requestStack,
SessionInterface $session,
): void {
$requestStack->getSession()->willReturn($session);
$session->get('_security_shop')->willReturn(null);
$this->shouldThrow(TokenNotFoundException::class)->during('getCurrentToken');
}
}

View file

@ -1,131 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Behat\Service;
use Behat\Mink\Mink;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Behat\Service\SecurityServiceInterface;
use Sylius\Behat\Service\SessionManagerInterface;
use Sylius\Behat\Service\SharedStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
final class SessionManagerSpec extends ObjectBehavior
{
function let(Mink $mink, SharedStorageInterface $sharedStorage, SecurityServiceInterface $securityService)
{
$this->beConstructedWith($mink, $sharedStorage, $securityService);
}
function it_implements_session_service_interface(): void
{
$this->shouldImplement(SessionManagerInterface::class);
}
function it_changes_session_and_does_not_restore_session_token_if_session_was_not_called_before(
Mink $mink,
SharedStorageInterface $sharedStorage,
SecurityServiceInterface $securityService,
TokenInterface $token,
): void {
$mink->getDefaultSessionName()->willReturn('default_session');
$securityService->getCurrentToken()->willReturn($token);
$token->__toString()->willReturn('{JSON_TOKEN}');
$sharedStorage->set('behat_previous_session_name', 'default_session')->shouldBeCalled();
$sharedStorage->set('behat_previous_session_token_default_session', $token)->shouldBeCalled();
$mink->setDefaultSessionName('chrome_headless_second_session')->shouldBeCalled();
$mink->restartSessions()->shouldBeCalled();
$sharedStorage->has('behat_previous_session_token_chrome_headless_second_session')->willReturn(false);
$securityService->restoreToken(Argument::any())->shouldNotBeCalled();
$this->changeSession();
}
function it_changes_session_and_restores_session_token_if_session_was_called_before(
Mink $mink,
SharedStorageInterface $sharedStorage,
SecurityServiceInterface $securityService,
TokenInterface $token,
TokenInterface $previousToken,
): void {
$mink->getDefaultSessionName()->willReturn('default_session');
$securityService->getCurrentToken()->willReturn($token);
$token->__toString()->willReturn('{JSON_TOKEN}');
$sharedStorage->set('behat_previous_session_name', 'default_session')->shouldBeCalled();
$sharedStorage->set('behat_previous_session_token_default_session', $token)->shouldBeCalled();
$mink->setDefaultSessionName('chrome_headless_second_session')->shouldBeCalled();
$mink->restartSessions()->shouldBeCalled();
$sharedStorage->has('behat_previous_session_token_chrome_headless_second_session')->willReturn(true);
$sharedStorage->get('behat_previous_session_token_chrome_headless_second_session')->willReturn($previousToken);
$securityService->restoreToken($previousToken)->shouldBeCalled();
$this->changeSession();
}
function it_restores_session_and_token(
Mink $mink,
SharedStorageInterface $sharedStorage,
SecurityServiceInterface $securityService,
TokenInterface $token,
TokenInterface $defaultToken,
): void {
$sharedStorage->has('behat_previous_session_name')->willReturn(true);
$sharedStorage->get('behat_previous_session_name')->willReturn('previous_session');
$mink->getDefaultSessionName()->willReturn('default_session');
$defaultToken->__toString()->willReturn('{JSON_DEFAULT_TOKEN}');
$sharedStorage->set('behat_previous_session_name', 'default_session')->shouldBeCalled();
$sharedStorage->set('behat_previous_session_token_default_session', $defaultToken)->shouldBeCalled();
$mink->setDefaultSessionName('previous_session')->shouldBeCalled();
$mink->restartSessions()->shouldBeCalled();
$securityService->getCurrentToken()->willReturn($defaultToken);
$sharedStorage->has('behat_previous_session_token_previous_session')->willReturn(true);
$sharedStorage->get('behat_previous_session_token_previous_session')->willReturn($token);
$securityService->restoreToken($token)->shouldBeCalled();
$this->restorePreviousSession();
}
function it_does_not_restore_session_and_token_if_previous_session_was_never_called(
Mink $mink,
SharedStorageInterface $sharedStorage,
SecurityServiceInterface $securityService,
TokenInterface $token,
): void {
$sharedStorage->has('behat_previous_session_name')->willReturn(false);
$mink->getDefaultSessionName()->shouldNotBeCalled();
$sharedStorage->set('behat_previous_session_name', 'default_session')->shouldNotBeCalled();
$mink->setDefaultSessionName('previous_session')->shouldNotBeCalled();
$mink->restartSessions()->shouldNotBeCalled();
$securityService->restoreToken($token)->shouldNotBeCalled();
$this->restorePreviousSession();
}
}

View file

@ -1,49 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Behat\Service\Setter;
use PhpSpec\ObjectBehavior;
use Sylius\Behat\Service\Setter\ChannelContextSetter;
use Sylius\Behat\Service\Setter\ChannelContextSetterInterface;
use Sylius\Behat\Service\Setter\CookieSetterInterface;
use Sylius\Component\Channel\Model\ChannelInterface;
final class ChannelContextSetterSpec extends ObjectBehavior
{
function let(CookieSetterInterface $cookieSetter)
{
$this->beConstructedWith($cookieSetter);
}
function it_is_initializable()
{
$this->shouldHaveType(ChannelContextSetter::class);
}
function it_implements_channel_context_setter_interface()
{
$this->shouldImplement(ChannelContextSetterInterface::class);
}
function it_sets_channel_as_current(
CookieSetterInterface $cookieSetter,
ChannelInterface $channel,
) {
$channel->getCode()->willReturn('CHANNEL_CODE');
$cookieSetter->setCookie('_channel_code', 'CHANNEL_CODE')->shouldBeCalled();
$this->setChannel($channel);
}
}

View file

@ -1,83 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Behat\Service;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Behat\Service\SecurityServiceInterface;
use Sylius\Behat\Service\SharedSecurityService;
use Sylius\Behat\Service\SharedSecurityServiceInterface;
use Sylius\Component\Core\Model\AdminUserInterface;
use Sylius\Component\Order\Model\OrderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
final class SharedSecurityServiceSpec extends ObjectBehavior
{
function let(SecurityServiceInterface $adminSecurityService)
{
$this->beConstructedWith($adminSecurityService);
}
function it_is_initializable()
{
$this->shouldHaveType(SharedSecurityService::class);
}
function it_implements_shared_security_service()
{
$this->shouldImplement(SharedSecurityServiceInterface::class);
}
function it_performs_action_as_given_admin_user_and_restore_previous_token(
SecurityServiceInterface $adminSecurityService,
TokenInterface $token,
OrderInterface $order,
AdminUserInterface $adminUser,
) {
$adminSecurityService->getCurrentToken()->willReturn($token);
$adminSecurityService->logIn($adminUser)->shouldBeCalled();
$order->completeCheckout()->shouldBeCalled();
$adminSecurityService->restoreToken($token)->shouldBeCalled();
$adminSecurityService->logOut()->shouldNotBeCalled();
$wrappedOrder = $order->getWrappedObject();
$this->performActionAsAdminUser(
$adminUser,
function () use ($wrappedOrder) {
$wrappedOrder->completeCheckout();
},
);
}
function it_performs_action_as_given_admin_user_and_logout(
SecurityServiceInterface $adminSecurityService,
OrderInterface $order,
AdminUserInterface $adminUser,
) {
$adminSecurityService->getCurrentToken()->willThrow(TokenNotFoundException::class);
$adminSecurityService->logIn($adminUser)->shouldBeCalled();
$order->completeCheckout()->shouldBeCalled();
$adminSecurityService->restoreToken(Argument::any())->shouldNotBeCalled();
$adminSecurityService->logOut()->shouldBeCalled();
$wrappedOrder = $order->getWrappedObject();
$this->performActionAsAdminUser(
$adminUser,
function () use ($wrappedOrder) {
$wrappedOrder->completeCheckout();
},
);
}
}

View file

@ -1,80 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Behat\Service;
use PhpSpec\ObjectBehavior;
use Sylius\Behat\Service\SharedStorage;
use Sylius\Behat\Service\SharedStorageInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Core\Model\ProductInterface;
final class SharedStorageSpec extends ObjectBehavior
{
function it_is_initializable(): void
{
$this->shouldHaveType(SharedStorage::class);
}
function it_implements_shared_storage_interface(): void
{
$this->shouldImplement(SharedStorageInterface::class);
}
function it_has_resources_in_clipboard(ChannelInterface $channel, ProductInterface $product): void
{
$this->set('channel1', $channel);
$this->get('channel1')->shouldReturn($channel);
$this->set('product1', $product);
$this->get('product1')->shouldReturn($product);
}
function it_returns_latest_added_resource(ChannelInterface $channel, ProductInterface $product): void
{
$this->set('channel1', $channel);
$this->set('product1', $product);
$this->getLatestResource()->shouldReturn($product);
}
function it_overrides_existing_resource_key(ChannelInterface $firstChannel, ChannelInterface $secondChannel): void
{
$this->set('channel', $firstChannel);
$this->set('channel', $secondChannel);
$this->get('channel')->shouldReturn($secondChannel);
}
function its_clipboard_can_be_set(ChannelInterface $channel): void
{
$this->setClipboard(['channel' => $channel]);
$this->get('channel')->shouldReturn($channel);
}
function it_checks_if_resource_under_given_key_exist(ChannelInterface $channel): void
{
$this->setClipboard(['channel' => $channel]);
$this->has('channel')->shouldReturn(true);
}
function it_removes_existing_key(): void
{
$this->set('key', 'value');
$this->remove('key');
$this->has('key')->shouldReturn(false);
}
}

View file

@ -0,0 +1,40 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Tests\Sylius\Behat;
use PHPUnit\Framework\TestCase;
use Sylius\Behat\NotificationType;
final class NotificationTypeTest extends TestCase
{
public function testInitializeWithSuccessValue(): void
{
$this->assertSame('success', NotificationType::success()->__toString());
}
public function testInitializeWithFailureValue(): void
{
$this->assertSame('failure', NotificationType::failure()->__toString());
}
public function testInitializeWithErrorValue(): void
{
$this->assertSame('error', NotificationType::error()->__toString());
}
public function testInitializeWithInfoValue(): void
{
$this->assertSame('info', NotificationType::info()->__toString());
}
}

View file

@ -0,0 +1,107 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Tests\Sylius\Behat\Service\Converter;
use ApiPlatform\Metadata\IriConverterInterface as BaseIriConverterInterface;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\UrlGeneratorInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sylius\Behat\Service\Converter\IriConverter;
use Sylius\Behat\Service\Converter\IriConverterInterface;
use Sylius\Bundle\ApiBundle\Provider\PathPrefixes;
use Sylius\Bundle\ApiBundle\Resolver\OperationResolverInterface;
use Sylius\Component\Addressing\Model\Country;
use Sylius\Component\Addressing\Model\CountryInterface;
final class IriConverterTest extends TestCase
{
private BaseIriConverterInterface&MockObject $decoratedIriConverter;
private OperationResolverInterface&MockObject $operationResolver;
private IriConverter $iriConverter;
protected function setUp(): void
{
$this->decoratedIriConverter = $this->createMock(BaseIriConverterInterface::class);
$this->operationResolver = $this->createMock(OperationResolverInterface::class);
$this->iriConverter = new IriConverter($this->decoratedIriConverter, $this->operationResolver);
}
public function testImplementsTheBehatIriConverterInterface(): void
{
$this->assertInstanceOf(IriConverterInterface::class, $this->iriConverter);
}
public function testUsesInnerIriConverterToGetResourceFromIri(): void
{
/** @var CountryInterface&MockObject $country */
$country = $this->createMock(CountryInterface::class);
$this->decoratedIriConverter->expects($this->once())->method('getResourceFromIri')->with('api/v2/admin/countries/CODE', [], null)->willReturn($country);
$this->assertSame($country, $this->iriConverter->getResourceFromIri('api/v2/admin/countries/CODE'));
}
public function testUsesInnerIriConverterToGetIriFromResource(): void
{
/** @var CountryInterface&MockObject $country */
$country = $this->createMock(CountryInterface::class);
$this->decoratedIriConverter
->expects($this->once())
->method('getIriFromResource')
->with($country, UrlGeneratorInterface::ABS_PATH, null, [])
->willReturn('api/v2/admin/countries/CODE')
;
$this->assertSame('api/v2/admin/countries/CODE', $this->iriConverter->getIriFromResource($country));
}
public function testProvidesIriFromResourceInGivenSection(): void
{
/** @var CountryInterface&MockObject $country */
$country = $this->createMock(CountryInterface::class);
/** @var Operation&MockObject $operation */
$operation = $this->createMock(Operation::class);
$this->operationResolver
->expects($this->once())
->method('resolve')
->with(Country::class, PathPrefixes::ADMIN_PREFIX, null)
->willReturn($operation)
;
$this->decoratedIriConverter
->expects($this->once())
->method('getIriFromResource')
->with($country, UrlGeneratorInterface::ABS_PATH, $operation, ['force_resource_class' => Country::class])
->willReturn('api/v2/admin/countries/CODE')
;
$this->assertSame(
'api/v2/admin/countries/CODE',
$this->iriConverter->getIriFromResourceInSection(
$country,
PathPrefixes::ADMIN_PREFIX,
UrlGeneratorInterface::ABS_PATH,
null,
[
'force_resource_class' => Country::class,
],
))
;
}
}

View file

@ -0,0 +1,50 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Tests\Sylius\Behat\Service\Generator;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sylius\Behat\Service\Generator\UploadedImagePathGenerator;
use Sylius\Component\Core\Generator\ImagePathGeneratorInterface;
use Sylius\Component\Core\Model\ImageInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
final class UploadedImagePathGeneratorTest extends TestCase
{
private UploadedImagePathGenerator $uploadedImagePathGenerator;
protected function setUp(): void
{
$this->uploadedImagePathGenerator = new UploadedImagePathGenerator();
}
public function testImplementsImagePathGeneratorInterface(): void
{
$this->assertInstanceOf(ImagePathGeneratorInterface::class, $this->uploadedImagePathGenerator);
}
public function testGeneratesRandomHashedPathKeepingTheImageName(): void
{
/** @var ImageInterface&MockObject $image */
$image = $this->createMock(ImageInterface::class);
$file = new UploadedFile(__DIR__ . '/ford.jpg', 'ford.jpg', null, null, true);
$image->expects($this->once())->method('getFile')->willReturn($file);
$this->assertMatchesRegularExpression(
'/[a-z0-9]{2}\/[a-z0-9]{2}\/[a-zA-Z0-9]+[_-]*\/ford[.]jpg/i',
$this->uploadedImagePathGenerator->generate($image),
);
}
}

View file

Before

Width:  |  Height:  |  Size: 505 KiB

After

Width:  |  Height:  |  Size: 505 KiB

View file

@ -0,0 +1,91 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Tests\Sylius\Behat\Service;
use Behat\Mink\Element\NodeElement;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sylius\Behat\Exception\NotificationExpectationMismatchException;
use Sylius\Behat\NotificationType;
use Sylius\Behat\Service\Accessor\NotificationAccessorInterface;
use Sylius\Behat\Service\NotificationChecker;
use Sylius\Behat\Service\NotificationCheckerInterface;
final class NotificationCheckerTest extends TestCase
{
private NotificationAccessorInterface&MockObject $notificationAccessor;
private NotificationChecker $notificationChecker;
protected function setUp(): void
{
$this->notificationAccessor = $this->createMock(NotificationAccessorInterface::class);
$this->notificationChecker = new NotificationChecker($this->notificationAccessor, ['failure' => 'negative', 'success' => 'alert-success']);
}
public function testImplementsNotificationCheckerInterface(): void
{
$this->assertInstanceOf(NotificationCheckerInterface::class, $this->notificationChecker);
}
public function testChecksIfSuccessfulNotificationWithSpecificMessageHasAppeared(): void
{
/** @var NodeElement&MockObject $firstMessage */
$firstMessage = $this->createMock(NodeElement::class);
/** @var NodeElement&MockObject $secondMessage */
$secondMessage = $this->createMock(NodeElement::class);
$this->notificationAccessor->expects($this->once())->method('getMessageElements')->willReturn([$firstMessage, $secondMessage]);
$firstMessage->expects($this->once())->method('getText')->willReturn('Some resource has been successfully edited.');
$firstMessage->expects($this->never())->method('hasClass')->with('alert-success')->willReturn(true);
$secondMessage->expects($this->once())->method('getText')->willReturn('Some resource has been successfully deleted.');
$secondMessage->expects($this->once())->method('hasClass')->with('alert-success')->willReturn(true);
$this->notificationChecker->checkNotification('Some resource has been successfully deleted.', NotificationType::success());
}
public function testChecksIfFailureNotificationWithSpecificMessageHasAppeared(): void
{
/** @var NodeElement&MockObject $firstMessage */
$firstMessage = $this->createMock(NodeElement::class);
/** @var NodeElement&MockObject $secondMessage */
$secondMessage = $this->createMock(NodeElement::class);
$this->notificationAccessor->expects($this->once())->method('getMessageElements')->willReturn([$firstMessage, $secondMessage]);
$firstMessage->expects($this->once())->method('getText')->willReturn('Some resource has been successfully edited.');
$firstMessage->expects($this->never())->method('hasClass')->with('negative')->willReturn(false);
$secondMessage->expects($this->once())->method('getText')->willReturn('Some resource could not be deleted.');
$secondMessage->expects($this->once())->method('hasClass')->with('negative')->willReturn(true);
$this->notificationChecker->checkNotification('Some resource could not be deleted.', NotificationType::failure());
}
public function testThrowsExceptionIfNoMessageWithGivenContentAndTypeHasBeenFound(): void
{
/** @var NodeElement&MockObject $firstMessage */
$firstMessage = $this->createMock(NodeElement::class);
/** @var NodeElement&MockObject $secondMessage */
$secondMessage = $this->createMock(NodeElement::class);
$this->notificationAccessor->expects($this->once())->method('getMessageElements')->willReturn([$firstMessage, $secondMessage]);
$firstMessage->expects($this->once())->method('getText')->willReturn('Some resource has been successfully edited.');
$firstMessage->expects($this->never())->method('hasClass')->with('negative')->willReturn(false);
$secondMessage->expects($this->once())->method('getText')->willReturn('Some resource could not be deleted.');
$secondMessage->expects($this->never())->method('hasClass')->with('negative')->willReturn(true);
$this->expectException(NotificationExpectationMismatchException::class);
$this->notificationChecker->checkNotification('Some resource has been successfully created.', NotificationType::failure());
}
}

View file

@ -0,0 +1,62 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Tests\Sylius\Behat\Service\Provider;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Sylius\Behat\Service\MessageSendCacher;
use Sylius\Behat\Service\Provider\EmailMessagesProvider;
use Sylius\Behat\Service\Provider\EmailMessagesProviderInterface;
use Symfony\Component\Mime\Email;
final class EmailMessagesProviderTest extends TestCase
{
private CacheItemPoolInterface&MockObject $cacheItemPool;
private EmailMessagesProvider $emailMessagesProvider;
protected function setUp(): void
{
$this->cacheItemPool = $this->createMock(CacheItemPoolInterface::class);
$this->emailMessagesProvider = new EmailMessagesProvider($this->cacheItemPool);
}
public function testImplementsEmailMessagesProviderInterface(): void
{
$this->assertInstanceOf(EmailMessagesProviderInterface::class, $this->emailMessagesProvider);
}
public function testProvidesEmailMessages(): void
{
/** @var CacheItemInterface&MockObject $cacheItem */
$cacheItem = $this->createMock(CacheItemInterface::class);
$emailMessages = [new Email(), new Email(), new Email()];
$cacheItem->expects($this->once())->method('get')->willReturn($emailMessages);
$this->cacheItemPool->expects($this->once())->method('hasItem')->with(MessageSendCacher::CACHE_KEY)->willReturn(true);
$this->cacheItemPool->expects($this->once())->method('getItem')->with(MessageSendCacher::CACHE_KEY)->willReturn($cacheItem);
$this->assertSame($emailMessages, $this->emailMessagesProvider->provide());
}
public function testReturnsAnEmptyArrayIfCacheKeyDoesNotExist(): void
{
$this->cacheItemPool->expects($this->once())->method('hasItem')->with(MessageSendCacher::CACHE_KEY)->willReturn(false);
$this->assertSame([], $this->emailMessagesProvider->provide());
}
}

View file

@ -0,0 +1,76 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Tests\Sylius\Behat\Service\Resolver;
use Behat\Mink\Session;
use FriendsOfBehat\PageObjectExtension\Page\SymfonyPageInterface;
use LogicException;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sylius\Behat\Service\Resolver\CurrentPageResolver;
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
final class CurrentPageResolverTest extends TestCase
{
private Session&MockObject $session;
private UrlMatcherInterface&MockObject $urlMatcher;
private CurrentPageResolver $currentPageResolver;
protected function setUp(): void
{
$this->session = $this->createMock(Session::class);
$this->urlMatcher = $this->createMock(UrlMatcherInterface::class);
$this->currentPageResolver = new CurrentPageResolver($this->session, $this->urlMatcher);
}
public function testImplementsCurrentPageResolverInterface(): void
{
$this->assertInstanceOf(CurrentPageResolverInterface::class, $this->currentPageResolver);
}
public function testReturnsCurrentPageBasedOnMatchedRoute(): void
{
/** @var SymfonyPageInterface&MockObject $createPage */
$createPage = $this->createMock(SymfonyPageInterface::class);
/** @var SymfonyPageInterface&MockObject $updatePage */
$updatePage = $this->createMock(SymfonyPageInterface::class);
$this->session->expects($this->once())->method('getCurrentUrl')->willReturn('https://sylius.com/resource/new');
$this->urlMatcher->expects($this->once())->method('match')->with('/resource/new')->willReturn(['_route' => 'sylius_resource_create']);
$createPage->expects($this->once())->method('getRouteName')->willReturn('sylius_resource_create');
$updatePage->expects($this->never())->method('getRouteName')->willReturn('sylius_resource_update');
$this->assertSame($createPage, $this->currentPageResolver->getCurrentPageWithForm([$createPage, $updatePage]));
}
public function testThrowsAnExceptionIfNeitherCreateNorUpdateKeyWordHasBeenFound(): void
{
/** @var SymfonyPageInterface&MockObject $createPage */
$createPage = $this->createMock(SymfonyPageInterface::class);
/** @var SymfonyPageInterface&MockObject $updatePage */
$updatePage = $this->createMock(SymfonyPageInterface::class);
$this->session->expects($this->once())->method('getCurrentUrl')->willReturn('https://sylius.com/resource/show');
$this->urlMatcher->expects($this->once())->method('match')->with('/resource/show')->willReturn(['_route' => 'sylius_resource_show']);
$createPage->expects($this->once())->method('getRouteName')->willReturn('sylius_resource_create');
$updatePage->expects($this->once())->method('getRouteName')->willReturn('sylius_resource_update');
$this->expectException(LogicException::class);
$this->currentPageResolver->getCurrentPageWithForm([$createPage, $updatePage]);
}
}

View file

@ -0,0 +1,134 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Tests\Sylius\Behat\Service;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sylius\Behat\Service\SecurityService;
use Sylius\Behat\Service\SecurityServiceInterface;
use Sylius\Behat\Service\Setter\CookieSetterInterface;
use Sylius\Component\Core\Model\ShopUserInterface;
use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionFactoryInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
final class SecurityServiceTest extends TestCase
{
private RequestStack&MockObject $requestStack;
private CookieSetterInterface&MockObject $cookieSetter;
private SessionFactoryInterface&MockObject $sessionFactory;
private SessionInterface&MockObject $session;
private SecurityService $securityService;
protected function setUp(): void
{
$this->requestStack = $this->createMock(RequestStack::class);
$this->cookieSetter = $this->createMock(CookieSetterInterface::class);
$this->sessionFactory = $this->createMock(SessionFactoryInterface::class);
$this->session = $this->createMock(SessionInterface::class);
$this->securityService = new SecurityService(
$this->requestStack,
$this->cookieSetter,
'shop',
$this->sessionFactory,
);
}
public function testImplementsSecurityServiceInterface(): void
{
$this->assertInstanceOf(SecurityServiceInterface::class, $this->securityService);
}
public function testLogsUserInWhenSessionFactoryIsNotAvailable(): void
{
/** @var ShopUserInterface&MockObject $shopUser */
$shopUser = $this->createMock(ShopUserInterface::class);
$shopUser->expects($this->once())->method('getRoles')->willReturn(['ROLE_USER']);
$shopUser->expects($this->once())->method('__serialize')->willReturn(['serialized_user']);
$this->requestStack->expects($this->once())->method('getSession')->willReturn($this->session);
$this->session->expects($this->once())->method('set');
$this->session->expects($this->once())->method('save');
$this->session->expects($this->once())->method('getName')->willReturn('MOCKEDSID');
$this->session->expects($this->once())->method('getId')->willReturn('xyzc123');
$this->cookieSetter->expects($this->once())->method('setCookie')->with('MOCKEDSID', 'xyzc123');
$this->securityService->logIn($shopUser);
}
public function testLogsUserIn(): void
{
/** @var ShopUserInterface&MockObject $shopUser */
$shopUser = $this->createMock(ShopUserInterface::class);
$this->sessionFactory->expects($this->once())->method('createSession')->willReturn($this->session);
$shopUser->expects($this->once())->method('getRoles')->willReturn(['ROLE_USER']);
$shopUser->expects($this->once())->method('__serialize')->willReturn(['serialized_user']);
$this->requestStack->expects($this->once())->method('push')->with($this->isInstanceOf(Request::class));
$this->requestStack->expects($this->once())->method('getSession')->willReturn($this->session);
$this->session->expects($this->once())->method('set');
$this->session->expects($this->once())->method('save');
$this->session->expects($this->once())->method('getName')->willReturn('MOCKEDSID');
$this->session->expects($this->once())->method('getId')->willReturn('xyzc123');
$this->cookieSetter->expects($this->once())->method('setCookie')->with('MOCKEDSID', 'xyzc123');
$this->securityService->logIn($shopUser);
}
public function testDoesNothingWhenThereIsNoSessionDuringLogOut(): void
{
$this->requestStack->expects($this->once())->method('getSession')->willThrowException(new SessionNotFoundException());
$this->cookieSetter->expects($this->never())->method('setCookie')->with($this->any());
$this->securityService->logOut();
}
public function testLogsUserOut(): void
{
$this->requestStack->expects($this->once())->method('getSession')->willReturn($this->session);
$this->session->expects($this->once())->method('set')->with('_security_shop', null);
$this->session->expects($this->once())->method('save');
$this->session->expects($this->once())->method('getName')->willReturn('MOCKEDSID');
$this->session->expects($this->once())->method('getId')->willReturn('xyzc123');
$this->cookieSetter->expects($this->once())->method('setCookie')->with('MOCKEDSID', 'xyzc123');
$this->securityService->logOut();
}
public function testThrowsTokenNotFoundException(): void
{
$this->requestStack->expects($this->once())->method('getSession')->willReturn($this->session);
$this->session->expects($this->once())->method('get')->with('_security_shop')->willReturn(null);
$this->expectException(TokenNotFoundException::class);
$this->securityService->getCurrentToken();
}
}

View file

@ -0,0 +1,210 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Tests\Sylius\Behat\Service;
use Behat\Mink\Mink;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sylius\Behat\Service\SecurityServiceInterface;
use Sylius\Behat\Service\SessionManager;
use Sylius\Behat\Service\SessionManagerInterface;
use Sylius\Behat\Service\SharedStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
final class SessionManagerTest extends TestCase
{
private Mink&MockObject $mink;
private SharedStorageInterface&MockObject $sharedStorage;
private SecurityServiceInterface&MockObject $securityService;
private SessionManager $sessionManager;
protected function setUp(): void
{
$this->mink = $this->createMock(Mink::class);
$this->sharedStorage = $this->createMock(SharedStorageInterface::class);
$this->securityService = $this->createMock(SecurityServiceInterface::class);
$this->sessionManager = new SessionManager($this->mink, $this->sharedStorage, $this->securityService);
}
public function testImplementsSessionServiceInterface(): void
{
$this->assertInstanceOf(SessionManagerInterface::class, $this->sessionManager);
}
public function testChangesSessionAndDoesNotRestoreSessionTokenIfSessionWasNotCalledBefore(): void
{
/** @var TokenInterface&MockObject $token */
$token = $this->createMock(TokenInterface::class);
$setCount = $this->exactly(2);
$this->sharedStorage
->expects($setCount)
->method('set')
->willReturnCallback(function (string $key, mixed $value) use ($setCount, $token) {
if ($setCount->numberOfInvocations() === 1) {
$this->assertSame($key, 'behat_previous_session_name', 'default_session');
$this->assertSame($value, 'default_session');
}
if ($setCount->numberOfInvocations() === 2) {
$this->assertSame($key, 'behat_previous_session_token_default_session', 'default_session');
$this->assertSame($value, $token);
}
})
;
$this->sharedStorage
->expects($this->once())
->method('has')
->with('behat_previous_session_token_chrome_headless_second_session')
->willReturn(false)
;
$this->mink->expects($this->once())->method('getDefaultSessionName')->willReturn('default_session');
$this->mink->expects($this->once())->method('setDefaultSessionName')->with('chrome_headless_second_session');
$this->mink->expects($this->once())->method('restartSessions');
$this->securityService->expects($this->once())->method('getCurrentToken')->willReturn($token);
$this->securityService->expects($this->never())->method('restoreToken');
$this->sessionManager->changeSession();
}
public function testChangesSessionAndRestoresSessionTokenIfSessionWasCalledBefore(): void
{
/** @var TokenInterface&MockObject $token */
$token = $this->createMock(TokenInterface::class);
/** @var TokenInterface&MockObject $previousToken */
$previousToken = $this->createMock(TokenInterface::class);
$this->mink->expects($this->once())->method('getDefaultSessionName')->willReturn('default_session');
$this->securityService->expects($this->once())->method('getCurrentToken')->willReturn($token);
$setCount = $this->exactly(2);
$this->sharedStorage
->expects($setCount)
->method('set')
->willReturnCallback(function (string $key, mixed $value) use ($setCount, $token) {
if ($setCount->numberOfInvocations() === 1) {
$this->assertSame($key, 'behat_previous_session_name', 'default_session');
$this->assertSame($value, 'default_session');
}
if ($setCount->numberOfInvocations() === 2) {
$this->assertSame($key, 'behat_previous_session_token_default_session', 'default_session');
$this->assertSame($value, $token);
}
})
;
$this->mink->expects($this->once())->method('setDefaultSessionName')->with('chrome_headless_second_session');
$this->mink->expects($this->once())->method('restartSessions');
$this->sharedStorage
->expects($this->once())
->method('has')
->with('behat_previous_session_token_chrome_headless_second_session')
->willReturn(true)
;
$this->sharedStorage
->expects($this->once())
->method('get')
->with('behat_previous_session_token_chrome_headless_second_session')
->willReturn($previousToken)
;
$this->securityService->expects($this->once())->method('restoreToken')->with($previousToken);
$this->sessionManager->changeSession();
}
public function testRestoresSessionAndToken(): void
{
/** @var TokenInterface&MockObject $token */
$token = $this->createMock(TokenInterface::class);
/** @var TokenInterface&MockObject $defaultToken */
$defaultToken = $this->createMock(TokenInterface::class);
$this->sharedStorage
->expects($this->exactly(2))
->method('has')
->willReturnCallback(function (string $key): bool {
return match ($key) {
'behat_previous_session_name' => true,
'behat_previous_session_token_previous_session' => true,
default => throw new \UnhandledMatchError(),
};
})
;
$this->sharedStorage
->expects($this->exactly(2))
->method('get')
->willReturnCallback(function (string $key) use ($token): mixed {
return match ($key) {
'behat_previous_session_name' => 'previous_session',
'behat_previous_session_token_previous_session' => $token,
default => throw new \UnhandledMatchError(),
};
})
;
$setCount = $this->exactly(2);
$this->sharedStorage
->expects($setCount)
->method('set')
->willReturnCallback(function (string $key, mixed $value) use ($setCount, $defaultToken) {
if ($setCount->numberOfInvocations() === 1) {
$this->assertSame($key, 'behat_previous_session_name', 'default_session');
$this->assertSame($value, 'default_session');
}
if ($setCount->numberOfInvocations() === 2) {
$this->assertSame($key, 'behat_previous_session_token_default_session', 'default_session');
$this->assertSame($value, $defaultToken);
}
})
;
$this->mink->expects($this->once())->method('getDefaultSessionName')->willReturn('default_session');
$this->mink->expects($this->once())->method('setDefaultSessionName')->with('previous_session');
$this->mink->expects($this->once())->method('restartSessions');
$this->securityService->expects($this->once())->method('getCurrentToken')->willReturn($defaultToken);
$this->securityService->expects($this->once())->method('restoreToken')->with($token);
$this->sessionManager->restorePreviousSession();
}
public function testDoesNotRestoreSessionAndTokenIfPreviousSessionWasNeverCalled(): void
{
/** @var TokenInterface&MockObject $token */
$token = $this->createMock(TokenInterface::class);
$this->sharedStorage
->expects($this->once())
->method('has')
->with('behat_previous_session_name')
->willReturn(false)
;
$this->sharedStorage->expects($this->never())->method('set')->with('behat_previous_session_name', 'default_session');
$this->mink->expects($this->never())->method('getDefaultSessionName');
$this->mink->expects($this->never())->method('setDefaultSessionName')->with('previous_session');
$this->mink->expects($this->never())->method('restartSessions');
$this->securityService->expects($this->never())->method('restoreToken')->with($token);
$this->sessionManager->restorePreviousSession();
}
}

View file

@ -0,0 +1,51 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Tests\Sylius\Behat\Service\Setter;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sylius\Behat\Service\Setter\ChannelContextSetter;
use Sylius\Behat\Service\Setter\ChannelContextSetterInterface;
use Sylius\Behat\Service\Setter\CookieSetterInterface;
use Sylius\Component\Channel\Model\ChannelInterface;
final class ChannelContextSetterTest extends TestCase
{
private CookieSetterInterface&MockObject $cookieSetter;
private ChannelContextSetter $channelContextSetter;
protected function setUp(): void
{
$this->cookieSetter = $this->createMock(CookieSetterInterface::class);
$this->channelContextSetter = new ChannelContextSetter($this->cookieSetter);
}
public function testImplementsChannelContextSetterInterface(): void
{
$this->assertInstanceOf(ChannelContextSetterInterface::class, $this->channelContextSetter);
}
public function testSetsChannelAsCurrent(): void
{
/** @var ChannelInterface&MockObject $channel */
$channel = $this->createMock(ChannelInterface::class);
$channel->expects($this->once())->method('getCode')->willReturn('CHANNEL_CODE');
$this->cookieSetter->expects($this->once())->method('setCookie')->with('_channel_code', 'CHANNEL_CODE');
$this->channelContextSetter->setChannel($channel);
}
}

View file

@ -0,0 +1,87 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Tests\Sylius\Behat\Service;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sylius\Behat\Service\SecurityServiceInterface;
use Sylius\Behat\Service\SharedSecurityService;
use Sylius\Behat\Service\SharedSecurityServiceInterface;
use Sylius\Component\Core\Model\AdminUserInterface;
use Sylius\Component\Order\Model\OrderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
final class SharedSecurityServiceTest extends TestCase
{
private SecurityServiceInterface&MockObject $adminSecurityService;
private SharedSecurityService $sharedSecurityService;
protected function setUp(): void
{
$this->adminSecurityService = $this->createMock(SecurityServiceInterface::class);
$this->sharedSecurityService = new SharedSecurityService($this->adminSecurityService);
}
public function testImplementsSharedSecurityService(): void
{
$this->assertInstanceOf(SharedSecurityServiceInterface::class, $this->sharedSecurityService);
}
public function testPerformsActionAsGivenAdminUserAndRestorePreviousToken(): void
{
/** @var TokenInterface&MockObject $token */
$token = $this->createMock(TokenInterface::class);
/** @var OrderInterface&MockObject $order */
$order = $this->createMock(OrderInterface::class);
/** @var AdminUserInterface&MockObject $adminUser */
$adminUser = $this->createMock(AdminUserInterface::class);
$this->adminSecurityService->expects($this->once())->method('getCurrentToken')->willReturn($token);
$this->adminSecurityService->expects($this->once())->method('logIn')->with($adminUser);
$order->expects($this->once())->method('completeCheckout');
$this->adminSecurityService->expects($this->once())->method('restoreToken')->with($token);
$this->adminSecurityService->expects($this->never())->method('logOut');
$this->sharedSecurityService->performActionAsAdminUser(
$adminUser,
function () use ($order) {
$order->completeCheckout();
},
);
}
public function testPerformsActionAsGivenAdminUserAndLogout(): void
{
/** @var OrderInterface&MockObject $order */
$order = $this->createMock(OrderInterface::class);
/** @var AdminUserInterface&MockObject $adminUser */
$adminUser = $this->createMock(AdminUserInterface::class);
$this->adminSecurityService->expects($this->once())->method('getCurrentToken')->willThrowException(new TokenNotFoundException());
$this->adminSecurityService->expects($this->once())->method('logIn')->with($adminUser);
$order->expects($this->once())->method('completeCheckout');
$this->adminSecurityService->expects($this->never())->method('restoreToken');
$this->adminSecurityService->expects($this->once())->method('logOut');
$this->sharedSecurityService->performActionAsAdminUser(
$adminUser,
function () use ($order) {
$order->completeCheckout();
},
);
}
}

View file

@ -0,0 +1,104 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Tests\Sylius\Behat\Service;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sylius\Behat\Service\SharedStorage;
use Sylius\Behat\Service\SharedStorageInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Core\Model\ProductInterface;
final class SharedStorageTest extends TestCase
{
private SharedStorage $sharedStorage;
protected function setUp(): void
{
$this->sharedStorage = new SharedStorage();
}
public function testImplementsSharedStorageInterface(): void
{
$this->assertInstanceOf(SharedStorageInterface::class, $this->sharedStorage);
}
public function testHasResourcesInClipboard(): void
{
/** @var ChannelInterface&MockObject $channel */
$channel = $this->createMock(ChannelInterface::class);
/** @var ProductInterface&MockObject $product */
$product = $this->createMock(ProductInterface::class);
$this->sharedStorage->set('channel', $channel);
$this->assertSame($channel, $this->sharedStorage->get('channel'));
$this->sharedStorage->set('product', $product);
$this->assertSame($product, $this->sharedStorage->get('product'));
}
public function testReturnsLatestAddedResource(): void
{
/** @var ChannelInterface&MockObject $channel */
$channel = $this->createMock(ChannelInterface::class);
/** @var ProductInterface&MockObject $product */
$product = $this->createMock(ProductInterface::class);
$this->sharedStorage->set('channel', $channel);
$this->sharedStorage->set('product', $product);
$this->assertSame($product, $this->sharedStorage->getLatestResource());
}
public function testOverridesExistingResourceKey(): void
{
/** @var ChannelInterface&MockObject $firstChannel */
$firstChannel = $this->createMock(ChannelInterface::class);
/** @var ChannelInterface&MockObject $secondChannel */
$secondChannel = $this->createMock(ChannelInterface::class);
$this->sharedStorage->set('channel', $firstChannel);
$this->sharedStorage->set('channel', $secondChannel);
$this->assertSame($secondChannel, $this->sharedStorage->get('channel'));
}
public function testItsClipboardCanBeSet(): void
{
/** @var ChannelInterface&MockObject $channel */
$channel = $this->createMock(ChannelInterface::class);
$this->sharedStorage->setClipboard(['channel' => $channel]);
$this->assertSame($channel, $this->sharedStorage->get('channel'));
}
public function testChecksIfResourceUnderGivenKeyExist(): void
{
/** @var ChannelInterface&MockObject $channel */
$channel = $this->createMock(ChannelInterface::class);
$this->sharedStorage->setClipboard(['channel' => $channel]);
$this->assertTrue($this->sharedStorage->has('channel'));
}
public function testRemovesExistingKey(): void
{
$this->sharedStorage->set('key', 'value');
$this->sharedStorage->remove('key');
$this->assertFalse($this->sharedStorage->has('key'));
}
}