Skip to content

Commit

Permalink
[#12048] Migrate student notification page e2e test (#12773)
Browse files Browse the repository at this point in the history
* Persist ReadNotifications in databundle

* Add remove or replace sql databundle methods into base test case

* Remove unnecessary checking of account migrated

* Migrate StudentNotificationPageE2ETest

* Fix lint issues

* Return sqldatabundle for tests

* Revert changes to NotificationPage to use notification id instead

* Add assertion for readNotifications from account

* fix architectureTest

---------

Co-authored-by: Wei Qing <[email protected]>
  • Loading branch information
cedricongjh and weiquu authored Feb 24, 2024
1 parent df49335 commit affcc46
Show file tree
Hide file tree
Showing 18 changed files with 280 additions and 124 deletions.
16 changes: 16 additions & 0 deletions src/e2e/java/teammates/e2e/cases/BaseE2ETestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.testng.annotations.BeforeClass;

import teammates.common.datatransfer.DataBundle;
import teammates.common.datatransfer.SqlDataBundle;
import teammates.common.datatransfer.attributes.AccountAttributes;
import teammates.common.datatransfer.attributes.AccountRequestAttributes;
import teammates.common.datatransfer.attributes.CourseAttributes;
Expand Down Expand Up @@ -53,6 +54,11 @@ public abstract class BaseE2ETestCase extends BaseTestCaseWithDatabaseAccess {
*/
protected DataBundle testData;

/**
* Sql Data to be used in the test.
*/
protected SqlDataBundle sqlTestData;

private Browser browser;

@BeforeClass
Expand Down Expand Up @@ -353,6 +359,16 @@ protected boolean doRemoveAndRestoreDataBundle(DataBundle testData) {
}
}

@Override
protected SqlDataBundle doRemoveAndRestoreSqlDataBundle(SqlDataBundle testData) {
try {
return BACKDOOR.removeAndRestoreSqlDataBundle(testData);
} catch (HttpRequestFailedException e) {
e.printStackTrace();
return null;
}
}

@Override
protected boolean doPutDocuments(DataBundle testData) {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package teammates.e2e.cases;

import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;

import teammates.common.datatransfer.attributes.AccountAttributes;
import teammates.common.datatransfer.attributes.NotificationAttributes;
import teammates.common.util.AppUrl;
import teammates.common.util.Const;
import teammates.e2e.pageobjects.StudentNotificationsPage;
import teammates.storage.sqlentity.Account;
import teammates.storage.sqlentity.Notification;
import teammates.ui.output.AccountData;

/**
* SUT: {@link Const.WebPageURIs#STUDENT_NOTIFICATIONS_PAGE}.
Expand All @@ -22,52 +23,57 @@ public class StudentNotificationsPageE2ETest extends BaseE2ETestCase {
protected void prepareTestData() {
testData = loadDataBundle("/StudentNotificationsPageE2ETest.json");
removeAndRestoreDataBundle(testData);
sqlTestData = removeAndRestoreSqlDataBundle(
loadSqlDataBundle("/StudentNotificationsPageE2ETest_SqlEntities.json"));
}

@Test
@Override
public void testAll() {
AccountAttributes account = testData.accounts.get("SNotifs.student");
Account account = sqlTestData.accounts.get("SNotifs.student");
AppUrl notificationsPageUrl = createFrontendUrl(Const.WebPageURIs.STUDENT_NOTIFICATIONS_PAGE);
StudentNotificationsPage notificationsPage = loginToPage(notificationsPageUrl, StudentNotificationsPage.class,
account.getGoogleId());

______TS("verify that only active notifications with correct target user are shown");
NotificationAttributes[] notShownNotifications = {
testData.notifications.get("notification3"),
testData.notifications.get("expiredNotification1"),
Notification[] notShownNotifications = {
sqlTestData.notifications.get("notification3"),
sqlTestData.notifications.get("expiredNotification1"),
};
NotificationAttributes[] shownNotifications = {
testData.notifications.get("notification1"),
testData.notifications.get("notification2"),
testData.notifications.get("notification4"),
Notification[] shownNotifications = {
sqlTestData.notifications.get("notification1"),
sqlTestData.notifications.get("notification2"),
sqlTestData.notifications.get("notification4"),
};

Notification[] readNotifications = {
sqlTestData.notifications.get("notification4"),
};

Set<String> readNotificationsIds = Stream.of(readNotifications)
.map(readNotification -> readNotification.getId().toString())
.collect(Collectors.toSet());

notificationsPage.verifyNotShownNotifications(notShownNotifications);
notificationsPage.verifyShownNotifications(shownNotifications, account.getReadNotifications().keySet());
notificationsPage.verifyShownNotifications(shownNotifications, readNotificationsIds);

______TS("mark notification as read");
NotificationAttributes notificationToMarkAsRead = testData.notifications.get("notification2");
Notification notificationToMarkAsRead = sqlTestData.notifications.get("notification2");
notificationsPage.markNotificationAsRead(notificationToMarkAsRead);
notificationsPage.verifyStatusMessage("Notification marked as read.");

// Verify that account's readNotifications attribute is updated
Map<String, Instant> readNotifications = new HashMap<>();
readNotifications.put(notificationToMarkAsRead.getNotificationId(), notificationToMarkAsRead.getEndTime());
readNotifications.putAll(account.getReadNotifications());
account.setReadNotifications(readNotifications);
verifyPresentInDatabase(account);

notificationsPage.verifyNotificationTab(notificationToMarkAsRead, account.getReadNotifications().keySet());
AccountData accountFromDb = BACKDOOR.getAccountData(account.getGoogleId());
assertTrue(accountFromDb.getReadNotifications().containsKey(notificationToMarkAsRead.getId().toString()));

______TS("notification banner is not visible");
assertFalse(notificationsPage.isBannerVisible());
}

@AfterClass
public void classTeardown() {
for (NotificationAttributes notification : testData.notifications.values()) {
BACKDOOR.deleteNotification(notification.getNotificationId());
for (Notification notification : sqlTestData.notifications.values()) {
BACKDOOR.deleteNotification(notification.getId());
}
}

Expand Down
67 changes: 67 additions & 0 deletions src/e2e/java/teammates/e2e/pageobjects/UserNotificationsPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import teammates.common.datatransfer.NotificationStyle;
import teammates.common.datatransfer.attributes.NotificationAttributes;
import teammates.storage.sqlentity.Notification;

/**
* Page Object Model for user notifications page.
Expand Down Expand Up @@ -44,6 +45,14 @@ public void verifyNotShownNotifications(NotificationAttributes[] notifications)
}
}

public void verifyNotShownNotifications(Notification[] notifications) {
List<String> shownNotificationIds = notificationTabs.findElements(By.className("card"))
.stream().map(e -> e.getAttribute("id")).collect(Collectors.toList());
for (Notification notification : notifications) {
assertFalse(shownNotificationIds.contains(notification.getId().toString()));
}
}

public void verifyShownNotifications(NotificationAttributes[] notifications, Set<String> readNotificationIds) {
// Only validates that the preset notifications are present instead of checking every notification
// This is because the page will display all active notifications in the database, which is not predictable
Expand All @@ -52,6 +61,14 @@ public void verifyShownNotifications(NotificationAttributes[] notifications, Set
}
}

public void verifyShownNotifications(Notification[] notifications, Set<String> readNotificationIds) {
// Only validates that the preset notifications are present instead of checking every notification
// This is because the page will display all active notifications in the database, which is not predictable
for (Notification notification : notifications) {
verifyNotificationTab(notification, readNotificationIds);
}
}

public void verifyNotificationTab(NotificationAttributes notification, Set<String> readNotificationIds) {
boolean isRead = readNotificationIds.contains(notification.getNotificationId());
WebElement notificationTab = notificationTabs.findElement(By.id(notification.getNotificationId()));
Expand Down Expand Up @@ -91,12 +108,57 @@ public void verifyNotificationTab(NotificationAttributes notification, Set<Strin
}
}

public void verifyNotificationTab(Notification notification, Set<String> readNotificationIds) {
boolean isRead = readNotificationIds.contains(notification.getId().toString());
WebElement notificationTab = notificationTabs.findElement(By.id(notification.getId().toString()));

// Check text and style of notification header
WebElement cardHeader = notificationTab.findElement(By.className("card-header"));
assertEquals(getHeaderText(notification), cardHeader.getText());
assertTrue(cardHeader.getAttribute("class").contains(getHeaderClass(notification.getStyle())));

// Checks if tab is open if notification is unread, and closed if notification is read
String chevronClass = notificationTab.findElement(By.tagName("i")).getAttribute("class");
if (isRead) {
assertTrue(chevronClass.contains("fa-chevron-down"));
// Open tab if notification is unread
click(cardHeader);
waitForPageToLoad();
} else {
assertTrue(chevronClass.contains("fa-chevron-up"));
}

// Check notification message
WebElement notifMessage = notificationTab.findElement(By.className("notification-message"));
assertEquals(notification.getMessage(), notifMessage.getAttribute("innerHTML"));

List<WebElement> markAsReadBtnList = notificationTab.findElements(By.className("btn-mark-as-read"));

if (isRead) {
// Check that mark as read button cannot be found if notification is read
assertEquals(0, markAsReadBtnList.size());

// Close tab if notification is read
click(cardHeader);
waitForPageToLoad();
} else {
// Check style of mark as read button if notification is unread
assertTrue(markAsReadBtnList.get(0).getAttribute("class").contains(getButtonClass(notification.getStyle())));
}
}

public void markNotificationAsRead(NotificationAttributes notification) {
WebElement notificationTab = notificationTabs.findElement(By.id(notification.getNotificationId()));
click(notificationTab.findElement(By.className("btn-mark-as-read")));
waitForPageToLoad(true);
}

public void markNotificationAsRead(Notification notification) {
WebElement notificationTab = notificationTabs.findElement(By.id(notification.getId().toString()));
click(notificationTab.findElement(By.className("btn-mark-as-read")));
waitForPageToLoad(true);
}

private String getTimezone() {
return notificationsTimezone.getText().replace("All dates are displayed in ", "").replace(" time.", "");
}
Expand All @@ -106,6 +168,11 @@ private String getHeaderText(NotificationAttributes notification) {
getHeaderDateString(notification.getStartTime()), getHeaderDateString(notification.getEndTime()));
}

private String getHeaderText(Notification notification) {
return String.format("%s [%s - %s]", notification.getTitle(),
getHeaderDateString(notification.getStartTime()), getHeaderDateString(notification.getEndTime()));
}

private String getHeaderDateString(Instant date) {
return getDisplayedDateTime(date, getTimezone(), "dd MMM yyyy");
}
Expand Down
67 changes: 0 additions & 67 deletions src/e2e/resources/data/StudentNotificationsPageE2ETest.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@
{
"accounts": {
"SNotifs.student": {
"googleId": "tm.e2e.SNotifs.student",
"name": "Alice B",
"email": "[email protected]",
"readNotifications": {
"notification4": "2099-04-04T00:00:00Z"
}
}
},
"courses": {
"typicalCourse1": {
"id": "tm.e2e.SNotifs.course1",
Expand All @@ -27,62 +17,5 @@
"team": "Team 1</td></div>'\"",
"section": "None"
}
},
"notifications": {
"notification1": {
"notificationId": "notification1",
"startTime": "2011-01-01T00:00:00Z",
"endTime": "2099-01-01T00:00:00Z",
"createdAt": "2011-01-01T00:00:00Z",
"style": "DANGER",
"targetUser": "GENERAL",
"title": "E2E notif for general users",
"message": "<p>This notification is shown to general users</p>",
"shown": false
},
"notification2": {
"notificationId": "notification2",
"startTime": "2011-02-02T00:00:00Z",
"endTime": "2099-02-02T00:00:00Z",
"createdAt": "2011-01-01T00:00:00Z",
"style": "SUCCESS",
"targetUser": "STUDENT",
"title": "E2E notif for students",
"message": "<p>This notification is shown to students only</p>",
"shown": false
},
"notification3": {
"notificationId": "notification3",
"startTime": "2011-03-03T00:00:00Z",
"endTime": "2099-03-03T00:00:00Z",
"createdAt": "2011-01-01T00:00:00Z",
"style": "SUCCESS",
"targetUser": "INSTRUCTOR",
"title": "E2E notif for instructors",
"message": "<p>This notification is shown to instructors only</p>",
"shown": false
},
"notification4": {
"notificationId": "notification4",
"startTime": "2011-04-04T00:00:00Z",
"endTime": "2099-04-04T00:00:00Z",
"createdAt": "2011-01-01T00:00:00Z",
"style": "WARNING",
"targetUser": "GENERAL",
"title": "E2E read notification",
"message": "<p>This notification has been read by the user</p>",
"shown": false
},
"expiredNotification1": {
"notificationId": "expiredNotification1",
"startTime": "2011-01-01T00:00:00Z",
"endTime": "2011-02-02T00:00:00Z",
"createdAt": "2011-01-01T00:00:00Z",
"style": "DANGER",
"targetUser": "GENERAL",
"title": "E2E expired notification",
"message": "<p>This notification has expired</p>",
"shown": false
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"accounts": {
"SNotifs.student": {
"id": "00000000-0000-4000-8000-000000000001",
"googleId": "tm.e2e.SNotifs.student",
"name": "Alice B",
"email": "[email protected]"
}
},
"notifications": {
"notification1": {
"id": "00000000-0000-4000-8000-000000001101",
"startTime": "2011-01-01T00:00:00Z",
"endTime": "2099-01-01T00:00:00Z",
"style": "DANGER",
"targetUser": "GENERAL",
"title": "SNotifs.notification1",
"message": "<p>This notification is shown to general users</p>",
"shown": false
},
"notification2": {
"id": "00000000-0000-4000-8000-000000001102",
"startTime": "2011-02-02T00:00:00Z",
"endTime": "2099-02-02T00:00:00Z",
"style": "SUCCESS",
"targetUser": "STUDENT",
"title": "SNotifs.notification2",
"message": "<p>This notification is shown to students only</p>",
"shown": false
},
"notification3": {
"id": "00000000-0000-4000-8000-000000001103",
"startTime": "2011-03-03T00:00:00Z",
"endTime": "2099-03-03T00:00:00Z",
"style": "SUCCESS",
"targetUser": "INSTRUCTOR",
"title": "SNotifs.notification3",
"message": "<p>This notification is shown to instructors only</p>",
"shown": false
},
"notification4": {
"id": "00000000-0000-4000-8000-000000001104",
"startTime": "2011-04-04T00:00:00Z",
"endTime": "2099-04-04T00:00:00Z",
"style": "WARNING",
"targetUser": "GENERAL",
"title": "SNotifs.notification4",
"message": "<p>This notification has been read by the user</p>",
"shown": false
},
"expiredNotification1": {
"id": "00000000-0000-4000-8000-000000001105",
"startTime": "2011-01-01T00:00:00Z",
"endTime": "2011-02-02T00:00:00Z",
"style": "DANGER",
"targetUser": "GENERAL",
"title": "SNotifs.expiredNotification1",
"message": "<p>This notification has expired</p>",
"shown": false
}
},
"readNotifications": {
"notification4SNotifs.student": {
"id": "00000000-0000-4000-8000-000000002100",
"account": {
"id": "00000000-0000-4000-8000-000000000001"
},
"notification": {
"id": "00000000-0000-4000-8000-000000001104"
}
}
}
}
Loading

0 comments on commit affcc46

Please sign in to comment.