Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#12048] Migrate InstructorCoursesPageE2ETest #13063

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public void classSetup() {
BACKDOOR.deleteCourse(copyCourse2.getId());
}

@Test
@Test(enabled = false)
@Override
public void testAll() {
String instructorId = sqlTestData.accounts.get("instructor").getGoogleId();
Expand Down
11 changes: 11 additions & 0 deletions src/e2e/java/teammates/e2e/cases/sql/BaseE2ETestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
import teammates.e2e.util.BackDoor;
import teammates.e2e.util.EmailAccount;
import teammates.e2e.util.TestProperties;
import teammates.storage.sqlentity.Course;
import teammates.storage.sqlentity.FeedbackQuestion;
import teammates.storage.sqlentity.FeedbackResponse;
import teammates.storage.sqlentity.FeedbackSession;
import teammates.storage.sqlentity.Student;
import teammates.test.BaseTestCaseWithSqlDatabaseAccess;
import teammates.test.FileHelper;
import teammates.test.ThreadHelper;
import teammates.ui.output.CourseData;
import teammates.ui.output.FeedbackQuestionData;
import teammates.ui.output.FeedbackResponseData;
import teammates.ui.output.FeedbackSessionData;
Expand Down Expand Up @@ -242,6 +244,15 @@ protected SqlDataBundle doRemoveAndRestoreDataBundle(SqlDataBundle testData) {
}
}

CourseData getCourse(String courseId) {
return BACKDOOR.getCourseData(courseId);
}

@Override
protected CourseData getCourse(Course course) {
return getCourse(course.getId());
}

FeedbackQuestionData getFeedbackQuestion(String courseId, String feedbackSessionName, int qnNumber) {
return BACKDOOR.getFeedbackQuestionData(courseId, feedbackSessionName, qnNumber);
}
Expand Down
211 changes: 211 additions & 0 deletions src/e2e/java/teammates/e2e/cases/sql/InstructorCoursesPageE2ETest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package teammates.e2e.cases.sql;

import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashSet;
import java.util.Set;

import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import teammates.common.util.AppUrl;
import teammates.common.util.Const;
import teammates.e2e.pageobjects.InstructorCoursesPage;
import teammates.storage.sqlentity.Course;
import teammates.storage.sqlentity.FeedbackSession;
import teammates.storage.sqlentity.Instructor;
import teammates.storage.sqlentity.Student;

/**
* SUT: {@link Const.WebPageURIs#INSTRUCTOR_COURSES_PAGE}.
*/
public class InstructorCoursesPageE2ETest extends BaseE2ETestCase {
private Course[] courses = new Course[4];
private Course newCourse;
private Course copyCourse;
private Course copyCourse2;
private FeedbackSession copySession;
private FeedbackSession copySession2;

@Override
protected void prepareTestData() {
testData = removeAndRestoreDataBundle(
loadSqlDataBundle("/InstructorCoursesPageE2ETestSql.json"));

courses[0] = testData.courses.get("CS1101");
courses[1] = testData.courses.get("CS2104");
courses[2] = testData.courses.get("CS2105");
courses[3] = testData.courses.get("CS1231");
FeedbackSession session = testData.feedbackSessions.get("session");
Instructor instructor = testData.instructors.get("instructorCS1231");

newCourse = new Course("tm.e2e.ICs.CS4100", "New Course", "Asia/Singapore", "TEAMMATES Test Institute 1");
newCourse.setCreatedAt(Instant.now());

copyCourse = new Course("tm.e2e.ICs.CS5000", "Copy Course", "Asia/Singapore", "TEAMMATES Test Institute 1");
copyCourse.setCreatedAt(Instant.now());

copyCourse2 = new Course("tm.e2e.ICs.CS6000", "Copy Course 2", "Asia/Singapore", "TEAMMATES Test Institute 1");
copyCourse2.setCreatedAt(Instant.now());

copySession = new FeedbackSession("Second Session", copyCourse, instructor.getEmail(), session.getInstructions(),
ZonedDateTime.now(ZoneId.of(copyCourse.getTimeZone())).plus(Duration.ofDays(2))
.truncatedTo(ChronoUnit.HOURS).toInstant(),
ZonedDateTime.now(ZoneId.of(copyCourse.getTimeZone())).plus(Duration.ofDays(7))
.truncatedTo(ChronoUnit.HOURS).toInstant(),
ZonedDateTime.now(ZoneId.of(copyCourse.getTimeZone())).minus(Duration.ofDays(28))
.truncatedTo(ChronoUnit.HOURS).toInstant(),
Const.TIME_REPRESENTS_LATER, session.getGracePeriod(), session.isOpeningEmailEnabled(),
session.isClosingEmailEnabled(), session.isPublishedEmailEnabled());

copySession2 = new FeedbackSession("Second Session", copyCourse2, instructor.getEmail(), copySession.getInstructions(),
copySession.getStartTime(), copySession.getEndTime(), copySession.getSessionVisibleFromTime(), copySession.getResultsVisibleFromTime(),
copySession.getGracePeriod(), copySession.isOpeningEmailEnabled(), copySession.isClosingEmailEnabled(), copySession.isPublishedEmailEnabled());
}

@BeforeClass
public void classSetup() {
BACKDOOR.deleteCourse(newCourse.getId());
BACKDOOR.deleteCourse(copyCourse.getId());
BACKDOOR.deleteCourse(copyCourse2.getId());
}

@Test
@Override
public void testAll() {
String instructorId = testData.accounts.get("instructor").getGoogleId();
AppUrl url = createFrontendUrl(Const.WebPageURIs.INSTRUCTOR_COURSES_PAGE);
InstructorCoursesPage coursesPage = loginToPage(url, InstructorCoursesPage.class, instructorId);

______TS("verify loaded data");
coursesPage.sortByCourseId();
Course[] activeCourses = { courses[0], courses[3], courses[1] };
Course[] deletedCourses = { courses[2] };

coursesPage.verifyActiveCoursesDetails(activeCourses);
coursesPage.verifyDeletedCoursesDetails(deletedCourses);

______TS("verify statistics");
verifyActiveCourseStatistics(coursesPage, courses[0]);

______TS("verify cannot modify without permissions");
coursesPage.verifyNotModifiable(courses[0].getId());

______TS("add new course");
Course[] activeCoursesWithNewCourse = { courses[0], courses[3], courses[1], newCourse };
coursesPage.addCourse(newCourse);

coursesPage.verifyStatusMessage("The course has been added.");
coursesPage.sortByCourseId();
coursesPage.verifyActiveCoursesDetails(activeCoursesWithNewCourse);
verifyPresentInDatabase(newCourse);

______TS("copy course with session of modified timings");
Course[] activeCoursesWithCopyCourse = { courses[0], courses[3], courses[1], newCourse, copyCourse };
coursesPage.copyCourse(courses[3].getId(), copyCourse);

coursesPage.waitForConfirmationModalAndClickOk();
coursesPage.sortByCourseId();
coursesPage.verifyActiveCoursesDetails(activeCoursesWithCopyCourse);
verifyPresentInDatabase(copyCourse);
verifyPresentInDatabase(copySession);

______TS("copy course with session of same timings");
Course[] activeCoursesWithCopyCourse2 = { courses[0], courses[3], courses[1], newCourse, copyCourse, copyCourse2 };
coursesPage.copyCourse(copyCourse.getId(), copyCourse2);
coursesPage.verifyStatusMessage("The course has been added.");
coursesPage.sortByCourseId();
coursesPage.verifyActiveCoursesDetails(activeCoursesWithCopyCourse2);
verifyPresentInDatabase(copyCourse2);
verifyPresentInDatabase(copySession2);

______TS("move active course to recycle bin");
newCourse.setDeletedAt(Instant.now());
Course[] deletedCoursesWithNewCourse = { newCourse, courses[2] };
coursesPage.moveCourseToRecycleBin(newCourse.getId());

coursesPage.verifyStatusMessage("The course " + newCourse.getId() + " has been deleted. "
+ "You can restore it from the Recycle Bin manually.");
coursesPage.verifyNumActiveCourses(5);
coursesPage.verifyDeletedCoursesDetails(deletedCoursesWithNewCourse);
assertTrue(BACKDOOR.isCourseInRecycleBin(newCourse.getId()));

______TS("restore active course");
newCourse.setDeletedAt(null);
Course[] activeCoursesWithNewCourseSortedByCreationDate =
{ copyCourse2, copyCourse, newCourse, courses[1], courses[3], courses[0] };
coursesPage.restoreCourse(newCourse.getId());

coursesPage.verifyStatusMessage("The course " + newCourse.getId() + " has been restored.");
coursesPage.waitForPageToLoad();
coursesPage.verifyNumDeletedCourses(1);
// No need to call sortByCreationDate() here because it is the default sort in DESC order
coursesPage.verifyActiveCoursesDetails(activeCoursesWithNewCourseSortedByCreationDate);
assertFalse(BACKDOOR.isCourseInRecycleBin(newCourse.getId()));

______TS("permanently delete course");
coursesPage.moveCourseToRecycleBin(newCourse.getId());
coursesPage.deleteCourse(newCourse.getId());

coursesPage.verifyStatusMessage("The course " + newCourse.getId()
+ " has been permanently deleted.");
coursesPage.verifyNumDeletedCourses(1);
verifyAbsentInDatabase(newCourse);

______TS("restore all");
coursesPage.moveCourseToRecycleBin(courses[1].getId());
Course[] activeCoursesWithRestored = { courses[0], courses[3], courses[1], courses[2], copyCourse, copyCourse2 };
coursesPage.restoreAllCourses();

coursesPage.verifyStatusMessage("All courses have been restored.");
coursesPage.waitForPageToLoad();
coursesPage.sortByCourseId();
coursesPage.verifyActiveCoursesDetails(activeCoursesWithRestored);
coursesPage.verifyNumDeletedCourses(0);
assertFalse(BACKDOOR.isCourseInRecycleBin(courses[1].getId()));
assertFalse(BACKDOOR.isCourseInRecycleBin(courses[2].getId()));

______TS("permanently delete all");
coursesPage.moveCourseToRecycleBin(courses[1].getId());
coursesPage.moveCourseToRecycleBin(courses[2].getId());
coursesPage.deleteAllCourses();

coursesPage.verifyStatusMessage("All courses have been permanently deleted.");
coursesPage.verifyNumActiveCourses(4);
coursesPage.verifyNumDeletedCourses(0);
verifyAbsentInDatabase(courses[1]);
verifyAbsentInDatabase(courses[2]);
}

private void verifyActiveCourseStatistics(InstructorCoursesPage coursesPage, Course course) {
int numSections = 0;
int numTeams = 0;
int numStudents = 0;
int numUnregistered = 0;
Set<String> sections = new HashSet<>();
Set<String> teams = new HashSet<>();

for (Student student : testData.students.values()) {
if (!student.getCourse().equals(course)) {
continue;
}
if (!sections.contains(student.getSectionName())) {
sections.add(student.getSectionName());
numSections++;
}
if (!teams.contains(student.getTeamName())) {
teams.add(student.getTeamName());
numTeams++;
}
if (student.getGoogleId() == null) {
numUnregistered++;
}
numStudents++;
}
coursesPage.verifyActiveCourseStatistics(course, Integer.toString(numSections), Integer.toString(numTeams),
Integer.toString(numStudents), Integer.toString(numUnregistered));
}
}
81 changes: 81 additions & 0 deletions src/e2e/java/teammates/e2e/pageobjects/InstructorCoursesPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import teammates.common.datatransfer.attributes.CourseAttributes;
import teammates.common.util.TimeHelper;
import teammates.storage.sqlentity.Course;

/**
* Represents the "Courses" page for Instructors.
Expand Down Expand Up @@ -78,6 +79,12 @@ public void verifyActiveCoursesDetails(CourseAttributes[] courses) {
verifyTableBodyValues(getActiveCoursesTable(), courseDetails);
}

public void verifyActiveCoursesDetails(Course[] courses) {
String[][] courseDetails = getCourseDetails(courses);
// use verifyTableBodyValues as active courses are sorted
verifyTableBodyValues(getActiveCoursesTable(), courseDetails);
}

public void verifyActiveCourseStatistics(CourseAttributes course, String numSections, String numTeams,
String numStudents, String numUnregistered) {
showStatistics(course.getId());
Expand All @@ -87,6 +94,15 @@ public void verifyActiveCourseStatistics(CourseAttributes course, String numSect
verifyTableRowValues(getActiveTableRow(course.getId()), courseDetail);
}

public void verifyActiveCourseStatistics(Course course, String numSections, String numTeams,
String numStudents, String numUnregistered) {
showStatistics(course.getId());
String[] courseDetail = { course.getId(), course.getName(),
TimeHelper.formatInstant(course.getCreatedAt(), course.getTimeZone(), "d MMM yyyy"),
numSections, numTeams, numStudents, numUnregistered };
verifyTableRowValues(getActiveTableRow(course.getId()), courseDetail);
}

public void verifyArchivedCoursesDetails(CourseAttributes[] courses) {
showArchiveTable();
this.waitUntilAnimationFinish();
Expand All @@ -97,6 +113,16 @@ public void verifyArchivedCoursesDetails(CourseAttributes[] courses) {
}
}

public void verifyArchivedCoursesDetails(Course[] courses) {
showArchiveTable();
this.waitUntilAnimationFinish();
String[][] courseDetails = getCourseDetails(courses);
for (int i = 0; i < courses.length; i++) {
// use verifyTableRowValues as archive courses are not sorted
verifyTableRowValues(getArchivedTableRow(courses[i].getId()), courseDetails[i]);
}
}

public void verifyDeletedCoursesDetails(CourseAttributes[] courses) {
showDeleteTable();
this.waitUntilAnimationFinish();
Expand All @@ -107,6 +133,16 @@ public void verifyDeletedCoursesDetails(CourseAttributes[] courses) {
}
}

public void verifyDeletedCoursesDetails(Course[] courses) {
showDeleteTable();
this.waitUntilAnimationFinish();
String[][] courseDetails = getDeletedCourseDetails(courses);
for (int i = 0; i < courses.length; i++) {
// use verifyTableRowValues as deleted courses are not sorted
verifyTableRowValues(getDeletedTableRow(courses[i].getId()), courseDetails[i]);
}
}

public void verifyNotModifiable(String courseId) {
// verify enroll button is disabled
int courseRowNumber = getRowNumberOfCourse(courseId);
Expand Down Expand Up @@ -143,6 +179,17 @@ public void addCourse(CourseAttributes newCourse) {
click(submitButton);
}

public void addCourse(Course newCourse) {
click(addCourseButton);

fillTextBox(courseIdTextBox, newCourse.getId());
fillTextBox(courseNameTextBox, newCourse.getName());
selectCourseInstitute(newCourse.getInstitute());
selectNewTimeZone(newCourse.getTimeZone());

click(submitButton);
}

public void showStatistics(String courseId) {
try {
click(getShowStatisticsLink(courseId));
Expand Down Expand Up @@ -174,6 +221,20 @@ public void copyCourse(String courseId, CourseAttributes newCourse) {
waitUntilAnimationFinish();
}

public void copyCourse(String courseId, Course newCourse) {
WebElement otherActionButton = getOtherActionsButton(courseId);
click(otherActionButton);
click(getCopyButton(courseId));
waitForPageToLoad();

fillTextBox(copyCourseIdTextBox, newCourse.getId());
fillTextBox(copyCourseNameTextBox, newCourse.getName());
selectCopyTimeZone(newCourse.getTimeZone());
click(copyCourseButton);

waitUntilAnimationFinish();
}

public void moveCourseToRecycleBin(String courseId) {
WebElement otherActionButton = getOtherActionsButton(courseId);
click(otherActionButton);
Expand Down Expand Up @@ -269,6 +330,16 @@ private String[][] getCourseDetails(CourseAttributes[] courses) {
return courseDetails;
}

private String[][] getCourseDetails(Course[] courses) {
String[][] courseDetails = new String[courses.length][3];
for (int i = 0; i < courses.length; i++) {
String[] courseDetail = { courses[i].getId(), courses[i].getName(),
getDateString(courses[i].getCreatedAt()) };
courseDetails[i] = courseDetail;
}
return courseDetails;
}

private String getDateString(Instant instant) {
return getDisplayedDateTime(instant, ZoneId.systemDefault().getId(), "d MMM yyyy");
}
Expand All @@ -283,6 +354,16 @@ private String[][] getDeletedCourseDetails(CourseAttributes[] courses) {
return courseDetails;
}

private String[][] getDeletedCourseDetails(Course[] courses) {
String[][] courseDetails = new String[courses.length][4];
for (int i = 0; i < courses.length; i++) {
String[] courseDetail = {courses[i].getId(), courses[i].getName(),
getDateString(courses[i].getCreatedAt()), getDateString(courses[i].getDeletedAt()) };
courseDetails[i] = courseDetail;
}
return courseDetails;
}

private WebElement getRestoreAllButton() {
return browser.driver.findElement(By.id("btn-restore-all"));
}
Expand Down
Loading
Loading