Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
485b2f6
Add optional section labels to respondent table
javieryeow Jun 27, 2026
6ac4a59
Replace send reminders modal with dedicated page
javieryeow Jun 27, 2026
2882771
Add send reminders page selection tests
javieryeow Jun 28, 2026
7fdcea6
Restore send reminders success toast after navigation
javieryeow Jun 28, 2026
7e21d71
Migrate reminder e2e flows to send reminders page
javieryeow Jun 28, 2026
b867fd6
Add dedicated send reminders e2e coverage
javieryeow Jun 28, 2026
1223aba
Remove obsolete send reminders modal
javieryeow Jun 28, 2026
3396633
Fix lint errors
javieryeow Jun 28, 2026
86874e1
fix stale download button for InstHomePageE2ETest
javieryeow Jun 29, 2026
0abe453
remove InstructorSessionsSendRemindersPageE2E
javieryeow Jun 29, 2026
4f92e15
chore: rerun ci
javieryeow Jun 29, 2026
b4df6bd
Fix send reminders spec after session visibility removal
javieryeow Jun 29, 2026
ce49b13
prevent sendReminders when user list empty
javieryeow Jun 29, 2026
c99c07a
fixed send-reminders page styles
javieryeow Jun 29, 2026
c7fc49e
apply bootstrap utility classes
javieryeow Jul 18, 2026
5eb9c81
revert downloadResults for InstructorHomePage
javieryeow Jul 18, 2026
664f4f2
remove cancel button and update test
javieryeow Jul 18, 2026
4a4f980
remove returnUrl from send reminders page
javieryeow Jul 19, 2026
7a2a857
remove send reminder test to verify failure
javieryeow Jul 19, 2026
0c57216
comment out unused import
javieryeow Jul 21, 2026
25e437f
fix lint issue
javieryeow Jul 21, 2026
25d3b28
use getNewPageInstance to reload page URL
javieryeow Jul 21, 2026
9125c9a
move send reminders tests to the end
javieryeow Jul 21, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import teammates.common.util.AppUrl;
import teammates.common.util.Const;
import teammates.e2e.pageobjects.InstructorFeedbackResultsPage;
import teammates.e2e.pageobjects.InstructorSessionSendRemindersPage;
import teammates.storage.entity.Course;
import teammates.storage.entity.FeedbackQuestion;
import teammates.storage.entity.FeedbackResponse;
Expand Down Expand Up @@ -352,9 +353,9 @@ private void testActions() {
resultsPage.verifyNoResponsePanelDetails(notResponded);

______TS("remind all who have not responded to any question");
resultsPage.remindAllNonResponders();
InstructorSessionSendRemindersPage sendRemindersPage = resultsPage.remindAllNonResponders();

resultsPage.verifyStatusMessage("Reminder e-mails have been sent out to those students and instructors."
sendRemindersPage.verifyStatusMessage("Reminder e-mails have been sent out to those students and instructors."
+ " Please allow up to 1 hour for all the notification emails to be sent out.");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import teammates.common.util.Const;
import teammates.common.util.TimeHelper;
import teammates.e2e.pageobjects.InstructorFeedbackSessionsPage;
import teammates.e2e.pageobjects.InstructorSessionSendRemindersPage;
import teammates.e2e.util.EntityCopyUtil;
import teammates.storage.entity.Course;
import teammates.storage.entity.FeedbackSession;
Expand Down Expand Up @@ -160,16 +161,19 @@ public void testAll() {
verifySessionPublishedState(openSession, FeedbackSessionPublishStatus.PUBLISHED);

______TS("send reminder email to selected student");
feedbackSessionsPage.sendReminderEmailToSelectedStudent(openSession, studentToEmail);
InstructorSessionSendRemindersPage sendRemindersPage =
feedbackSessionsPage.sendReminderEmailToSelectedStudent(openSession, studentToEmail);

feedbackSessionsPage.verifyStatusMessage("Reminder e-mails have been sent out to those students"
sendRemindersPage.verifyStatusMessage("Reminder e-mails have been sent out to those students"
+ " and instructors. Please allow up to 1 hour for all the notification emails to be sent out.");
feedbackSessionsPage = getNewPageInstance(url, InstructorFeedbackSessionsPage.class);

______TS("send reminder email to all student non-submitters");
feedbackSessionsPage.sendReminderEmailToNonSubmitters(openSession);
sendRemindersPage = feedbackSessionsPage.sendReminderEmailToNonSubmitters(openSession);

feedbackSessionsPage.verifyStatusMessage("Reminder e-mails have been sent out to those students"
sendRemindersPage.verifyStatusMessage("Reminder e-mails have been sent out to those students"
+ " and instructors. Please allow up to 1 hour for all the notification emails to be sent out.");
feedbackSessionsPage = getNewPageInstance(url, InstructorFeedbackSessionsPage.class);

______TS("resend results link");
feedbackSessionsPage.resendResultsLink(openSession, studentToEmail);
Expand Down
31 changes: 19 additions & 12 deletions src/e2e/java/teammates/e2e/cases/InstructorHomePageE2ETest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import teammates.common.util.AppUrl;
import teammates.common.util.Const;
import teammates.e2e.pageobjects.InstructorHomePage;
import teammates.e2e.pageobjects.InstructorSessionSendRemindersPage;
import teammates.e2e.util.EntityCopyUtil;
import teammates.storage.entity.Course;
import teammates.storage.entity.FeedbackSession;
Expand Down Expand Up @@ -151,18 +152,6 @@ public void testAll() {
homePage.verifySessionDetails(courseIndex, sessionIndex, feedbackSessionOpen);
verifySessionPublishedState(feedbackSessionOpen, true);

______TS("send reminder email to selected student");
homePage.sendReminderEmailToSelectedStudent(courseIndex, sessionIndex, studentToEmail);

homePage.verifyStatusMessage("Reminder e-mails have been sent out to those students"
+ " and instructors. Please allow up to 1 hour for all the notification emails to be sent out.");

______TS("send reminder email to all student non-submitters");
homePage.sendReminderEmailToNonSubmitters(courseIndex, sessionIndex);

homePage.verifyStatusMessage("Reminder e-mails have been sent out to those students"
+ " and instructors. Please allow up to 1 hour for all the notification emails to be sent out.");

______TS("resend results link");
homePage.resendResultsLink(courseIndex, sessionIndex, studentToEmail);

Expand Down Expand Up @@ -205,6 +194,24 @@ public void testAll() {
+ "You can restore it from the Recycle Bin manually.");
homePage.verifyNumCourses(1);
assertTrue(BACKDOOR.isCourseInRecycleBin(otherCourse.getId()));

______TS("send reminder email to selected student");
courseIndex = 0;
sessionIndex = 0;
homePage.verifySessionDetails(courseIndex, sessionIndex, feedbackSessionOpen);
InstructorSessionSendRemindersPage sendRemindersPage =
homePage.sendReminderEmailToSelectedStudent(courseIndex, sessionIndex, studentToEmail);

sendRemindersPage.verifyStatusMessage("Reminder e-mails have been sent out to those students"
+ " and instructors. Please allow up to 1 hour for all the notification emails to be sent out.");

______TS("send reminder email to all student non-submitters");
homePage = getNewPageInstance(url, InstructorHomePage.class);
homePage.verifySessionDetails(courseIndex, sessionIndex, feedbackSessionOpen);
sendRemindersPage = homePage.sendReminderEmailToNonSubmitters(courseIndex, sessionIndex);

sendRemindersPage.verifyStatusMessage("Reminder e-mails have been sent out to those students"
+ " and instructors. Please allow up to 1 hour for all the notification emails to be sent out.");
}

private String getExpectedResponseRate(FeedbackSession session) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,11 @@ public void verifyNoResponsePanelDetails(List<Student> noResponseStudents) {
verifyTableBodyValues(getNoResponseTable(), getExpectedNoResponseDetails(noResponseStudents));
}

public void remindAllNonResponders() {
public InstructorSessionSendRemindersPage remindAllNonResponders() {
click(remindAllButton);
click(waitForElementPresence(By.id("btn-confirm-send-reminder")));
InstructorSessionSendRemindersPage sendRemindersPage = changePageType(InstructorSessionSendRemindersPage.class);
sendRemindersPage.submitReminderToPreselectedNonSubmitters();
return sendRemindersPage;
}

public void includeGroupingByTeam(boolean isIncluded) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,21 +205,25 @@ public void showDeleteTable() {
}
}

public void sendReminderEmailToSelectedStudent(FeedbackSession session, Student student) {
public InstructorSessionSendRemindersPage sendReminderEmailToSelectedStudent(
FeedbackSession session, Student student) {
int rowId = getFeedbackSessionRowId(session.getCourseId(), session.getName());

click(waitForElementPresence(By.className("btn-remind-" + rowId)));
click(waitForElementPresence(By.className("btn-remind-selected-" + rowId)));
selectStudentToEmail(student.getEmail());
click(waitForElementPresence(By.id("btn-confirm-send-reminder")));
InstructorSessionSendRemindersPage sendRemindersPage = changePageType(InstructorSessionSendRemindersPage.class);
sendRemindersPage.submitReminderToSelectedStudent(student.getEmail());
return sendRemindersPage;
}

public void sendReminderEmailToNonSubmitters(FeedbackSession session) {
public InstructorSessionSendRemindersPage sendReminderEmailToNonSubmitters(FeedbackSession session) {
int rowId = getFeedbackSessionRowId(session.getCourseId(), session.getName());

click(waitForElementPresence(By.className("btn-remind-" + rowId)));
click(waitForElementPresence(By.className("btn-remind-all-" + rowId)));
click(waitForElementPresence(By.id("btn-confirm-send-reminder")));
InstructorSessionSendRemindersPage sendRemindersPage = changePageType(InstructorSessionSendRemindersPage.class);
sendRemindersPage.submitReminderToPreselectedNonSubmitters();
return sendRemindersPage;
}

public void resendResultsLink(FeedbackSession session, Student student) {
Expand Down Expand Up @@ -427,14 +431,11 @@ private void selectCourseToCopyToInModal(WebElement copyFsModal, String courseTo

private void selectStudentToEmail(String studentEmail) {
WebElement studentList = waitForElementVisibility(By.id("student-list-table"));
List<WebElement> rows = studentList.findElements(By.cssSelector("tbody tr"));

List<WebElement> rows = studentList.findElements(By.tagName("tr"));
for (WebElement row : rows) {
List<WebElement> cells = row.findElements(By.cssSelector("td"));
if (cells.isEmpty()) {
continue;
}
if (cells.get(4).getText().equals(studentEmail)) {
if (!cells.isEmpty() && cells.get(4).getText().equals(studentEmail)) {
click(cells.get(0).findElement(By.tagName("input")));
break;
}
Expand Down
23 changes: 11 additions & 12 deletions src/e2e/java/teammates/e2e/pageobjects/InstructorHomePage.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,27 +73,29 @@ public void unpublishSessionResults(int courseTabIndex, int sessionIndex) {
clickAndConfirm(unpublishButtons.get(unpublishButtons.size() - 1));
}

public void sendReminderEmailToSelectedStudent(int courseTabIndex, int sessionIndex, Student student) {
public InstructorSessionSendRemindersPage sendReminderEmailToSelectedStudent(
int courseTabIndex, int sessionIndex, Student student) {
WebElement courseTab = getCourseTab(courseTabIndex);
click(courseTab.findElement(By.className("btn-remind-" + sessionIndex)));
List<WebElement> remindSelectedButtons = browser.driver.findElements(
By.className("btn-remind-selected-" + sessionIndex)
);
click(remindSelectedButtons.get(remindSelectedButtons.size() - 1));
selectStudentToEmail(student.getEmail());
click(browser.driver.findElement(By.id("btn-confirm-send-reminder")));
click(courseTab.findElement(By.className("btn-remind-" + sessionIndex)));
InstructorSessionSendRemindersPage sendRemindersPage = changePageType(InstructorSessionSendRemindersPage.class);
sendRemindersPage.submitReminderToSelectedStudent(student.getEmail());
return sendRemindersPage;
}

public void sendReminderEmailToNonSubmitters(int courseTabIndex, int sessionIndex) {
public InstructorSessionSendRemindersPage sendReminderEmailToNonSubmitters(int courseTabIndex, int sessionIndex) {
WebElement courseTab = getCourseTab(courseTabIndex);
click(courseTab.findElement(By.className("btn-remind-" + sessionIndex)));
List<WebElement> remindSelectedButtons = browser.driver.findElements(
By.className("btn-remind-all-" + sessionIndex)
);
click(remindSelectedButtons.get(remindSelectedButtons.size() - 1));
click(waitForElementPresence(By.id("btn-confirm-send-reminder")));
click(courseTab.findElement(By.className("btn-remind-" + sessionIndex)));
InstructorSessionSendRemindersPage sendRemindersPage = changePageType(InstructorSessionSendRemindersPage.class);
sendRemindersPage.submitReminderToPreselectedNonSubmitters();
return sendRemindersPage;
}

public void resendResultsLink(int courseTabIndex, int sessionIndex, Student student) {
Expand Down Expand Up @@ -203,14 +205,11 @@ private void selectCourseToCopyToInModal(WebElement copyFsModal, String courseTo

private void selectStudentToEmail(String studentEmail) {
WebElement studentList = waitForElementPresence(By.id("student-list-table"));
List<WebElement> rows = studentList.findElements(By.cssSelector("tbody tr"));

List<WebElement> rows = studentList.findElements(By.tagName("tr"));
for (WebElement row : rows) {
List<WebElement> cells = row.findElements(By.cssSelector("td"));
if (cells.isEmpty()) {
continue;
}
if (cells.get(4).getText().equals(studentEmail)) {
if (!cells.isEmpty() && cells.get(4).getText().equals(studentEmail)) {
click(cells.get(0).findElement(By.tagName("input")));
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package teammates.e2e.pageobjects;

import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

/**
* Represents the instructor send reminders page.
*/
public class InstructorSessionSendRemindersPage extends AppPage {
public InstructorSessionSendRemindersPage(Browser browser) {
super(browser);
}

@Override
protected boolean containsExpectedPageContents() {
return getPageTitle().contains("Send Reminders");
}

public void submitReminderToSelectedStudent(String studentEmail) {
selectStudentByEmail(studentEmail);
submitReminders();
}

public void submitReminderToPreselectedNonSubmitters() {
submitReminders();
}

private void submitReminders() {
click(waitForElementPresence(By.id("btn-confirm-send-reminder")));
}

private void selectStudentByEmail(String studentEmail) {
WebElement studentList = waitForElementVisibility(By.id("student-list-table"));
List<WebElement> rows = studentList.findElements(By.cssSelector("tbody tr"));

for (WebElement row : rows) {
List<WebElement> cells = row.findElements(By.cssSelector("td"));
if (!cells.isEmpty() && cells.get(4).getText().equals(studentEmail)) {
click(cells.get(0).findElement(By.tagName("input")));
break;
}
}
}
}
2 changes: 2 additions & 0 deletions src/main/java/teammates/common/util/Const.java
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ public static class WebPageURIs {
public static final String INSTRUCTOR_SESSION_EDIT_PAGE = INSTRUCTOR_PAGE + "/sessions/{feedbackSessionId}/edit";
public static final String INSTRUCTOR_SESSION_INDIVIDUAL_EXTENSION_PAGE = INSTRUCTOR_PAGE
+ "/sessions/{feedbackSessionId}/individual-extension";
public static final String INSTRUCTOR_SESSION_SEND_REMINDERS_PAGE = INSTRUCTOR_PAGE
+ "/sessions/{feedbackSessionId}/send-reminders";
public static final String INSTRUCTOR_SESSION_RESULTS_PAGE = INSTRUCTOR_PAGE
+ "/sessions/{feedbackSessionId}/result";
public static final String INSTRUCTOR_SESSION_REPORT_PAGE = INSTRUCTOR_PAGE
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
@if (studentListInfoTableRowModels.length > 0) {
<div>
@if (studentTableLabel) {
<h1>{{ studentTableLabel }}</h1>
}
<table id="student-list-table" class="table table-bordered">
<thead>
<tr class="background-color-medium-gray">
Expand Down Expand Up @@ -148,6 +151,9 @@ <h4 class="p-2 bg-info">There are no students enrolled to remind.</h4>
<br />
@if (instructorListInfoTableRowModels.length > 0) {
<div>
@if (instructorTableLabel) {
<h1>{{ instructorTableLabel }}</h1>
}
<table id="instructor-list-table" class="table table-bordered">
<thead>
<tr class="background-color-medium-gray">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ export class RespondentListInfoTableComponent {
@Input()
shouldDisplayHasSubmittedSessionColumn = false;

@Input()
studentTableLabel = '';

@Input()
instructorTableLabel = '';

@Input()
studentListInfoTableRowModels: StudentListInfoTableRowModel[] = [];

Expand Down
Loading
Loading