Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/bundle/Resources/config/services/test/pages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,6 @@ services:
Ibexa\AdminUi\Behat\Page\UserSettingsPage: ~

Ibexa\AdminUi\Behat\Page\UserProfilePage: ~

Ibexa\AdminUi\Behat\Page\NotificationsViewAllPage: ~

147 changes: 143 additions & 4 deletions src/lib/Behat/BrowserContext/UserNotificationContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,24 @@
use Behat\Gherkin\Node\TableNode;
use Ibexa\AdminUi\Behat\Component\UpperMenu;
use Ibexa\AdminUi\Behat\Component\UserNotificationPopup;
use Ibexa\AdminUi\Behat\Page\NotificationsViewAllPage;
use PHPUnit\Framework\Assert;

final readonly class UserNotificationContext implements Context
{
public function __construct(
private UpperMenu $upperMenu,
private UserNotificationPopup $userNotificationPopup
) {
/** @var \Ibexa\AdminUi\Behat\Component\UpperMenu */
private UpperMenu $upperMenu;

/** @var \Ibexa\AdminUi\Behat\Component\UserNotificationPopup */
private UserNotificationPopup $userNotificationPopup;

private NotificationsViewAllPage $notificationsViewAllPage;

public function __construct(UpperMenu $upperMenu, UserNotificationPopup $userNotificationPopup, NotificationsViewAllPage $notificationsViewAllPage)
{
$this->upperMenu = $upperMenu;
$this->userNotificationPopup = $userNotificationPopup;
$this->notificationsViewAllPage = $notificationsViewAllPage;
}

/**
Expand All @@ -41,4 +51,133 @@ public function iGoToUserNotificationWithDetails(TableNode $notificationDetails)
$this->userNotificationPopup->verifyIsLoaded();
$this->userNotificationPopup->clickNotification($type, $description);
}

/**
* @Then the notification appears with details:
*/
public function notificationAppearsWithDetails(TableNode $notificationDetails): void
{
$type = $notificationDetails->getHash()[0]['Type'];
$author = $notificationDetails->getHash()[0]['Author'];
$description = $notificationDetails->getHash()[0]['Description'];
$date = $notificationDetails->getHash()[0]['Date'];

$this->userNotificationPopup->verifyIsLoaded();
$this->userNotificationPopup->verifyNotification($type, $author, $description, $date, true);
}

/**
* @When I open notification menu with description :description
*/
public function iOpenNotificationMenu(string $description): void
{
$this->userNotificationPopup->openNotificationMenu($description);
}

/**
* @When I perform the :action action on the notification
*/
public function iPerformNotificationAction(string $action): void
{
$this->userNotificationPopup->clickActionButton($action);
}

/**
* @Then the notification should have :expectedAction action available
*/
public function verifyNotificationAction(string $expectedAction): void
{
$this->userNotificationPopup->findActionButton($expectedAction);
}

/**
* @When I mark all notifications as read
*/
public function markAllNotificationsAsRead(): void
{
$this->userNotificationPopup->verifyIsLoaded();
$this->userNotificationPopup->clickOnMarkAllAsReadButton();
}

/**
* @When I go to the list of all notifications
*/
public function goToAllNotificationsList(): void
{
$this->userNotificationPopup->verifyIsLoaded();
$this->userNotificationPopup->clickViewAllNotificationsButton();
}

/**
* @Then there is :notificationTitle notification on list
*/
public function thereIsNotificationOnList(string $notificationTitle): void
{
$this->notificationsViewAllPage->verifyIsLoaded();
$this->notificationsViewAllPage->verifyNotificationIsOnList($notificationTitle);
}

/**
* @When I mark notification as unread with title :notificationTitle
*/
public function iMarkNotificationAsUnread(string $notificationTitle): void
{
$this->notificationsViewAllPage->markAsUnread($notificationTitle);
}

/**
* @Then the notification with title :notificationTitle has status :notificationStatus
*/
public function verifyNotificationStatus(string $notificationTitle, string $notificationStatus): void
{
Assert::assertEquals($notificationStatus, $this->notificationsViewAllPage->getStatusForNotification($notificationTitle));
}

/**
* @When I go to content of notification with title :notificationTitle
*/
public function iGoToContent(string $notificationTitle): void
{
$this->notificationsViewAllPage->goToContent($notificationTitle);
}

/**
* @When I delete notification with title :notificationTitle
*/
public function iDeleteNotification(string $notificationTitle): void
{
$this->notificationsViewAllPage->deleteNotification($notificationTitle);
}

/**
* @Then an empty notifications state in the popup should be visible
*/
public function emptyNotificationsStateInPopup(): void
{
$this->userNotificationPopup->assertEmptyStateVisible();
}

/**
* @Then an empty notifications state should be visible in the All Notifications view
*/
public function emptyNotificationsStateInAllNotificationsView(): void
{
$this->notificationsViewAllPage->assertEmptyStateVisible();
}

/**
* @Then the notifications popup counter should display :expectedCount
*/
public function iShouldSeeNotificationsCountInPopup(int $expectedCount): void
{
$this->userNotificationPopup->verifyNotificationsCount($expectedCount);
}

/**
* @Then I should see :expectedCount notifications in the All Notifications view
*/
public function thereShouldBeNotificationsInAllNotificationsView(int $expectedCount): void
{
$this->notificationsViewAllPage->verifyNotificationsCount($expectedCount);
}
}
128 changes: 128 additions & 0 deletions src/lib/Behat/Component/UserNotificationPopup.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@

use Exception;
use Ibexa\Behat\Browser\Component\Component;
use Ibexa\Behat\Browser\Element\Action\MouseOverAndClick;
use Ibexa\Behat\Browser\Element\Condition\ElementExistsCondition;
use Ibexa\Behat\Browser\Element\Condition\ElementNotExistsCondition;
use Ibexa\Behat\Browser\Element\Criterion\ChildElementTextCriterion;
use Ibexa\Behat\Browser\Element\Criterion\ElementTextCriterion;
use Ibexa\Behat\Browser\Element\ElementInterface;
use Ibexa\Behat\Browser\Locator\VisibleCSSLocator;

final class UserNotificationPopup extends Component
Expand Down Expand Up @@ -43,6 +49,120 @@
);
}

public function verifyNotification(string $expectedType, string $expectedAuthor, string $expectedDescription, ?string $expectedDate = null, bool $shouldExist = true): void
{
$notifications = $this->getHTMLPage()->setTimeout(5)->findAll($this->getLocator('notificationItem'));

foreach ($notifications as $notification) {
$criteria = [
new ChildElementTextCriterion($this->getLocator('notificationType'), $expectedType),
new ChildElementTextCriterion($this->getLocator('notificationDescriptionTitle'), $expectedAuthor),
new ChildElementTextCriterion($this->getLocator('notificationDescriptionText'), $expectedDescription),
];

if ($expectedDate !== null && $expectedDate !== 'XXXX-XX-XX') {
$criteria[] = new ChildElementTextCriterion($this->getLocator('notificationDate'), $expectedDate);
}

foreach ($criteria as $criterion) {
if (!$criterion->matches($notification)) {
continue 2;
}
}

if ($shouldExist) {
return;
} else {
throw new \Exception(sprintf(

Check warning on line 76 in src/lib/Behat/Component/UserNotificationPopup.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define and throw a dedicated exception instead of using a generic one.

See more on https://sonarcloud.io/project/issues?id=ibexa_admin-ui&issues=AZsNRrAYcqm6RPaXeBbE&open=AZsNRrAYcqm6RPaXeBbE&pullRequest=1799
'Notification of type "%s" with author "%s" and description "%s" should not exist, but was found.',
$expectedType,
$expectedAuthor,
$expectedDescription
));
}
}

if ($shouldExist) {
throw new \Exception(sprintf(

Check warning on line 86 in src/lib/Behat/Component/UserNotificationPopup.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define and throw a dedicated exception instead of using a generic one.

See more on https://sonarcloud.io/project/issues?id=ibexa_admin-ui&issues=AZsNRrAYcqm6RPaXeBbF&open=AZsNRrAYcqm6RPaXeBbF&pullRequest=1799
'Notification of type "%s" with author "%s" and description "%s" was not found.',
$expectedType,
$expectedAuthor,
$expectedDescription
));
}
}

public function openNotificationMenu(string $expectedDescription): void
{
$this->getHTMLPage()->setTimeout(5)->findAll($this->getLocator('notificationItem'))
->filterBy(new ChildElementTextCriterion($this->getLocator('notificationDescriptionText'), $expectedDescription))
->first()->find($this->getLocator('notificationMenuButton'))->click();

$this->getHTMLPage()
->setTimeout(10)
->waitUntilCondition(
new ElementExistsCondition(
$this->getHTMLPage(),
$this->getLocator('notificationActionsPopup'),
)
);
}

public function clickActionButton(string $buttonText): void
{
$this->getHTMLPage()
->setTimeout(10)
->findAll($this->getLocator('notificationMenuItemContent'))
->filterBy(new ElementTextCriterion($buttonText))->first()->execute(new MouseOverAndClick());

$this->getHTMLPage()
->setTimeout(10)
->waitUntilCondition(
new ElementNotExistsCondition(
$this->getHTMLPage(),
$this->getLocator('notificationActionsPopup')
)
);
}

public function findActionButton(string $buttonText): ElementInterface
{
$this->getHTMLPage()
->setTimeout(10)
->waitUntilCondition(
new ElementExistsCondition(
$this->getHTMLPage(),
$this->getLocator('notificationMenuItemContent')
)
);

return $this->getHTMLPage()
->setTimeout(10)
->findAll($this->getLocator('notificationMenuItemContent'))
->filterBy(new ElementTextCriterion($buttonText))
->first();
}

public function assertEmptyStateVisible(): void
{
$this->getHTMLPage()->setTimeout(5)->find($this->getLocator('notificationsEmptyText'))->assert()->isVisible();
}

public function clickOnMarkAllAsReadButton(): void
{
$this->getHTMLPage()->setTimeout(5)->find($this->getLocator('markAllAsReadButton'))->click();
}

public function clickViewAllNotificationsButton(): void
{
$this->getHTMLPage()->setTimeout(3)->find($this->getLocator('viewAllNotificationsButton'))->click();
}

public function verifyNotificationsCount(int $expectedCount): void
{
$this->getHTMLPage()->setTimeout(10)->find($this->getLocator('notificationsCount'))->assert()->textEquals('(' . $expectedCount . ')');
}

public function verifyIsLoaded(): void
{
$this->getHTMLPage()
Expand All @@ -59,6 +179,14 @@
new VisibleCSSLocator('notificationType', '.ibexa-notifications-modal__type-content .type__text'),
new VisibleCSSLocator('notificationDescriptionTitle', '.ibexa-notifications-modal__description .description__title'),
new VisibleCSSLocator('notificationDescriptionText', '.ibexa-notifications-modal__type-content .description__text'),
new VisibleCSSLocator('notificationDate', '.ibexa-notifications-modal__item--date'),
new VisibleCSSLocator('notificationMenuButton', '.ibexa-notifications-modal__actions'),
new VisibleCSSLocator('notificationMenuItemContent', '.ibexa-popup-menu__item-content.ibexa-multilevel-popup-menu__item-content'),
new VisibleCSSLocator('markAllAsReadButton', '.ibexa-notifications-modal__mark-all-read-btn'),
new VisibleCSSLocator('viewAllNotificationsButton', '.ibexa-notifications-modal__view-all-btn'),
new VisibleCSSLocator('notificationActionsPopup', '.ibexa-notification-actions-popup-menu:not(.ibexa-popup-menu--hidden)'),
new VisibleCSSLocator('notificationsEmptyText', '.ibexa-notifications-modal__empty-text'),
new VisibleCSSLocator('notificationsCount', '.ibexa-notifications-modal__count'),
];
}
}
Loading
Loading