diff --git a/src/e2e/java/teammates/e2e/cases/sql/BaseE2ETestCase.java b/src/e2e/java/teammates/e2e/cases/sql/BaseE2ETestCase.java index 860616c0c40..54d8f3f46ca 100644 --- a/src/e2e/java/teammates/e2e/cases/sql/BaseE2ETestCase.java +++ b/src/e2e/java/teammates/e2e/cases/sql/BaseE2ETestCase.java @@ -20,9 +20,13 @@ import teammates.e2e.util.BackDoor; import teammates.e2e.util.EmailAccount; import teammates.e2e.util.TestProperties; +import teammates.storage.sqlentity.FeedbackQuestion; +import teammates.storage.sqlentity.FeedbackResponse; import teammates.test.BaseTestCaseWithSqlDatabaseAccess; import teammates.test.FileHelper; import teammates.test.ThreadHelper; +import teammates.ui.output.FeedbackQuestionData; +import teammates.ui.output.FeedbackResponseData; /** * Base class for all browser tests. @@ -224,13 +228,30 @@ protected void verifyEmailSent(String email, String subject) { * Removes and restores the databundle using BACKDOOR. */ @Override - protected boolean doRemoveAndRestoreDataBundle(SqlDataBundle testData) { + protected SqlDataBundle doRemoveAndRestoreDataBundle(SqlDataBundle testData) { try { - BACKDOOR.removeAndRestoreSqlDataBundle(testData); - return true; + return BACKDOOR.removeAndRestoreSqlDataBundle(testData); } catch (HttpRequestFailedException e) { e.printStackTrace(); - return false; + return null; } } + + FeedbackQuestionData getFeedbackQuestion(String courseId, String feedbackSessionName, int qnNumber) { + return BACKDOOR.getFeedbackQuestionData(courseId, feedbackSessionName, qnNumber); + } + + @Override + protected FeedbackQuestionData getFeedbackQuestion(FeedbackQuestion fq) { + return getFeedbackQuestion(fq.getCourseId(), fq.getFeedbackSession().getName(), fq.getQuestionNumber()); + } + + FeedbackResponseData getFeedbackResponse(String questionId, String giver, String recipient) { + return BACKDOOR.getFeedbackResponseData(questionId, recipient, recipient); + } + + @Override + protected FeedbackResponseData getFeedbackResponse(FeedbackResponse fr) { + return getFeedbackResponse(fr.getFeedbackQuestion().getId().toString(), fr.getGiver(), fr.getRecipient()); + } } diff --git a/src/e2e/java/teammates/e2e/cases/sql/BaseFeedbackQuestionE2ETest.java b/src/e2e/java/teammates/e2e/cases/sql/BaseFeedbackQuestionE2ETest.java new file mode 100644 index 00000000000..1597a6bd1d0 --- /dev/null +++ b/src/e2e/java/teammates/e2e/cases/sql/BaseFeedbackQuestionE2ETest.java @@ -0,0 +1,58 @@ +package teammates.e2e.cases.sql; + +import teammates.common.util.AppUrl; +import teammates.common.util.Const; +import teammates.e2e.pageobjects.FeedbackSubmitPage; +import teammates.e2e.pageobjects.InstructorFeedbackEditPage; +import teammates.storage.sqlentity.Course; +import teammates.storage.sqlentity.FeedbackSession; +import teammates.storage.sqlentity.Instructor; +import teammates.storage.sqlentity.Student; + +/** + * Base class for all feedback question related browser tests. + * + *
SUT: {@link Const.WebPageURIs#INSTRUCTOR_SESSION_EDIT_PAGE}, {@link Const.WebPageURIs#SESSION_SUBMISSION_PAGE}. + * + *
Only UI-intensive operations, e.g. question creation and response submission, are tested separately. + * This is so that if any part of the testing fails (due to regression or inherent instability), only the + * specific test for the specific feedback question needs to be re-run. + * + *
For the above reason, viewing feedback responses/results is not considered to be under this test case. + * This is because viewing results is a fast action and combining all question types together under one test case + * will save some testing time. + */ +public abstract class BaseFeedbackQuestionE2ETest extends BaseE2ETestCase { + Instructor instructor; + Course course; + FeedbackSession feedbackSession; + Student student; + + abstract void testEditPage(); + + abstract void testSubmitPage(); + + InstructorFeedbackEditPage loginToFeedbackEditPage() { + AppUrl url = createFrontendUrl(Const.WebPageURIs.INSTRUCTOR_SESSION_EDIT_PAGE) + .withCourseId(course.getId()) + .withSessionName(feedbackSession.getName()); + + return loginToPage(url, InstructorFeedbackEditPage.class, instructor.getGoogleId()); + } + + FeedbackSubmitPage loginToFeedbackSubmitPage() { + AppUrl url = createFrontendUrl(Const.WebPageURIs.STUDENT_SESSION_SUBMISSION_PAGE) + .withCourseId(student.getCourse().getId()) + .withSessionName(feedbackSession.getName()); + + return loginToPage(url, FeedbackSubmitPage.class, student.getGoogleId()); + } + + FeedbackSubmitPage getFeedbackSubmitPage() { + AppUrl url = createFrontendUrl(Const.WebPageURIs.STUDENT_SESSION_SUBMISSION_PAGE) + .withCourseId(student.getCourse().getId()) + .withSessionName(feedbackSession.getName()); + + return getNewPageInstance(url, FeedbackSubmitPage.class); + } +} diff --git a/src/e2e/java/teammates/e2e/cases/sql/FeedbackTextQuestionE2ETest.java b/src/e2e/java/teammates/e2e/cases/sql/FeedbackTextQuestionE2ETest.java new file mode 100644 index 00000000000..88662c3adbb --- /dev/null +++ b/src/e2e/java/teammates/e2e/cases/sql/FeedbackTextQuestionE2ETest.java @@ -0,0 +1,111 @@ +package teammates.e2e.cases.sql; + +import org.testng.annotations.Test; + +import teammates.common.datatransfer.questions.FeedbackTextQuestionDetails; +import teammates.common.datatransfer.questions.FeedbackTextResponseDetails; +import teammates.e2e.pageobjects.FeedbackSubmitPage; +import teammates.e2e.pageobjects.InstructorFeedbackEditPage; +import teammates.storage.sqlentity.FeedbackQuestion; +import teammates.storage.sqlentity.FeedbackResponse; +import teammates.storage.sqlentity.Instructor; + +/** + * SUT: {@link Const.WebPageURIs#INSTRUCTOR_SESSION_EDIT_PAGE}, {@link Const.WebPageURIs#SESSION_SUBMISSION_PAGE} + * specifically for text questions. + */ +public class FeedbackTextQuestionE2ETest extends BaseFeedbackQuestionE2ETest { + + @Override + protected void prepareTestData() { + testData = removeAndRestoreDataBundle(loadSqlDataBundle("/FeedbackTextQuestionE2ESqlTest.json")); + + instructor = testData.instructors.get("instructor"); + course = testData.courses.get("course"); + feedbackSession = testData.feedbackSessions.get("openSession"); + student = testData.students.get("alice.tmms@FTextQn.CS2104"); + } + + @Test + @Override + public void testAll() { + testEditPage(); + logout(); + testSubmitPage(); + } + + @Override + protected void testEditPage() { + InstructorFeedbackEditPage feedbackEditPage = loginToFeedbackEditPage(); + + ______TS("verify loaded question"); + FeedbackQuestion loadedQuestion = testData.feedbackQuestions.get("qn1ForFirstSession"); + FeedbackTextQuestionDetails questionDetails = (FeedbackTextQuestionDetails) loadedQuestion.getQuestionDetailsCopy(); + feedbackEditPage.verifyTextQuestionDetails(1, questionDetails); + + ______TS("add new question"); + // add new question exactly like loaded question + loadedQuestion.setQuestionNumber(2); + feedbackEditPage.addTextQuestion(loadedQuestion); + + feedbackEditPage.verifyTextQuestionDetails(2, questionDetails); + verifyPresentInDatabase(loadedQuestion); + + ______TS("copy question"); + FeedbackQuestion copiedQuestion = testData.feedbackQuestions.get("qn1ForSecondSession"); + questionDetails = (FeedbackTextQuestionDetails) copiedQuestion.getQuestionDetailsCopy(); + feedbackEditPage.copyQuestion(copiedQuestion.getCourseId(), + copiedQuestion.getQuestionDetailsCopy().getQuestionText()); + copiedQuestion.setQuestionNumber(3); + copiedQuestion.setFeedbackSession(feedbackSession); + + feedbackEditPage.verifyTextQuestionDetails(3, questionDetails); + verifyPresentInDatabase(copiedQuestion); + + ______TS("edit question"); + questionDetails.setRecommendedLength(200); + copiedQuestion.setQuestionDetails(questionDetails); + feedbackEditPage.editTextQuestion(3, questionDetails); + + feedbackEditPage.verifyTextQuestionDetails(3, questionDetails); + verifyPresentInDatabase(copiedQuestion); + } + + @Override + protected void testSubmitPage() { + FeedbackSubmitPage feedbackSubmitPage = loginToFeedbackSubmitPage(); + + ______TS("verify loaded question"); + FeedbackQuestion question = testData.feedbackQuestions.get("qn1ForFirstSession"); + Instructor receiver = testData.instructors.get("instructor"); + question.setQuestionNumber(1); + feedbackSubmitPage.verifyTextQuestion(1, (FeedbackTextQuestionDetails) question.getQuestionDetailsCopy()); + + ______TS("submit response"); + FeedbackResponse response = getResponse(question, receiver, "
This is the response for qn 1
"); + feedbackSubmitPage.fillTextResponse(1, receiver.getName(), response); + feedbackSubmitPage.clickSubmitQuestionButton(1); + + // TODO: uncomment when SubmitFeedbackResponse is working + // verifyPresentInDatabase(response); + + // ______TS("check previous response"); + // feedbackSubmitPage = getFeedbackSubmitPage(); + // feedbackSubmitPage.verifyTextResponse(1, receiver.getName(), response); + + // ______TS("edit response"); + // FeedbackResponse editedResponse = getResponse(question, receiver, "Edited response
"); + // feedbackSubmitPage.fillTextResponse(1, receiver.getName(), editedResponse); + // feedbackSubmitPage.clickSubmitQuestionButton(1); + + // feedbackSubmitPage = getFeedbackSubmitPage(); + // feedbackSubmitPage.verifyTextResponse(1, receiver.getName(), response); + // verifyPresentInDatabase(editedResponse); + } + + private FeedbackResponse getResponse(FeedbackQuestion feedbackQuestion, Instructor instructor, String answer) { + FeedbackTextResponseDetails details = new FeedbackTextResponseDetails(answer); + return FeedbackResponse.makeResponse( + feedbackQuestion, student.getEmail(), null, instructor.getEmail(), null, details); + } +} diff --git a/src/e2e/java/teammates/e2e/pageobjects/FeedbackSubmitPage.java b/src/e2e/java/teammates/e2e/pageobjects/FeedbackSubmitPage.java index 4cd29ce955e..33f3215d638 100644 --- a/src/e2e/java/teammates/e2e/pageobjects/FeedbackSubmitPage.java +++ b/src/e2e/java/teammates/e2e/pageobjects/FeedbackSubmitPage.java @@ -37,6 +37,7 @@ import teammates.common.datatransfer.questions.FeedbackTextQuestionDetails; import teammates.common.datatransfer.questions.FeedbackTextResponseDetails; import teammates.common.util.Const; +import teammates.storage.sqlentity.FeedbackResponse; /** * Represents the feedback submission page of the website. @@ -155,6 +156,12 @@ public void fillTextResponse(int qnNumber, String recipient, FeedbackResponseAtt writeToRichTextEditor(getTextResponseEditor(qnNumber, recipient), responseDetails.getAnswer()); } + public void fillTextResponse(int qnNumber, String recipient, FeedbackResponse response) { + FeedbackTextResponseDetails responseDetails = + (FeedbackTextResponseDetails) response.getFeedbackResponseDetailsCopy(); + writeToRichTextEditor(getTextResponseEditor(qnNumber, recipient), responseDetails.getAnswer()); + } + public void verifyTextResponse(int qnNumber, String recipient, FeedbackResponseAttributes response) { FeedbackTextResponseDetails responseDetails = (FeedbackTextResponseDetails) response.getResponseDetailsCopy(); int responseLength = responseDetails.getAnswer().split(" ").length; @@ -163,6 +170,15 @@ public void verifyTextResponse(int qnNumber, String recipient, FeedbackResponseA + " words"); } + public void verifyTextResponse(int qnNumber, String recipient, FeedbackResponse response) { + FeedbackTextResponseDetails responseDetails = + (FeedbackTextResponseDetails) response.getFeedbackResponseDetailsCopy(); + int responseLength = responseDetails.getAnswer().split(" ").length; + assertEquals(getEditorRichText(getTextResponseEditor(qnNumber, recipient)), responseDetails.getAnswer()); + assertEquals(getResponseLengthText(qnNumber, recipient), "Response length: " + responseLength + + " words"); + } + public void verifyMcqQuestion(int qnNumber, String recipient, FeedbackMcqQuestionDetails questionDetails) { ListInstructions for first session
", + "createdTime": "2012-04-01T23:59:00Z", + "startTime": "2012-04-01T22:00:00Z", + "endTime": "2026-04-30T22:00:00Z", + "sessionVisibleFromTime": "2012-04-01T22:00:00Z", + "resultsVisibleFromTime": "2026-05-01T22:00:00Z", + "timeZone": "Africa/Johannesburg", + "gracePeriod": 10, + "sentOpenEmail": false, + "sentClosingEmail": false, + "sentClosedEmail": false, + "sentPublishedEmail": false, + "isOpeningEmailEnabled": true, + "isClosingEmailEnabled": true, + "isPublishedEmailEnabled": true, + "studentDeadlines": {}, + "instructorDeadlines": {}, + "id": "00000000-0000-4000-8000-000000000701", + "course": { + "id": "tm.e2e.FTextQn.CS2104" + }, + "name": "First Session" + }, + "openSession2": { + "creatorEmail": "tmms.test@gmail.tmt", + "instructions": "Instructions for Second session
", + "createdTime": "2012-04-01T23:59:00Z", + "startTime": "2012-04-01T22:00:00Z", + "endTime": "2026-04-30T22:00:00Z", + "sessionVisibleFromTime": "2012-04-01T22:00:00Z", + "resultsVisibleFromTime": "2026-05-01T22:00:00Z", + "timeZone": "Africa/Johannesburg", + "gracePeriod": 10, + "sentOpenEmail": false, + "sentClosingEmail": false, + "sentClosedEmail": false, + "sentPublishedEmail": false, + "isOpeningEmailEnabled": true, + "isClosingEmailEnabled": true, + "isPublishedEmailEnabled": true, + "studentDeadlines": {}, + "instructorDeadlines": {}, + "id": "00000000-0000-4000-8000-000000000702", + "course": { + "id": "tm.e2e.FTextQn.CS1101" + }, + "name": "Second Session" + } + }, + "feedbackQuestions": { + "qn1ForFirstSession": { + "id": "00000000-0000-4000-8000-000000000801", + "feedbackSession": { + "id": "00000000-0000-4000-8000-000000000701" + }, + "questionDetails": { + "questionType": "TEXT", + "questionText": "What did this instructor do well?", + "recommendedLength": 1000 + }, + "description": "Testing description for first session
", + "questionNumber": 1, + "giverType": "STUDENTS", + "recipientType": "INSTRUCTORS", + "numOfEntitiesToGiveFeedbackTo": 1, + "showResponsesTo": ["INSTRUCTORS"], + "showGiverNameTo": ["INSTRUCTORS"], + "showRecipientNameTo": ["INSTRUCTORS"] + }, + "qn1ForSecondSession": { + "id": "00000000-0000-4000-8000-000000000802", + "feedbackSession": { + "id": "00000000-0000-4000-8000-000000000702" + }, + "questionDetails": { + "questionType": "TEXT", + "questionText": "How can this instructor improve?", + "recommendedLength": 100 + }, + "description": "Testing description for second session
", + "questionNumber": 1, + "giverType": "STUDENTS", + "recipientType": "INSTRUCTORS", + "numOfEntitiesToGiveFeedbackTo": 1, + "showResponsesTo": ["INSTRUCTORS"], + "showGiverNameTo": ["INSTRUCTORS"], + "showRecipientNameTo": ["INSTRUCTORS"] + } + }, + "notifications": {}, + "readNotifications": {}, + "feedbackResponseComments": {}, + "students": { + "alice.tmms@FTextQn.CS2104": { + "id": "00000000-0000-4000-8000-000000000604", + "account": { + "id": "00000000-0000-4000-8000-000000000002" + }, + "course": { + "id": "tm.e2e.FTextQn.CS2104" + }, + "team": { + "id": "00000000-0000-4000-8000-000000000201" + }, + "email": "alice.b.tmms@gmail.tmt", + "name": "Alice Betsy", + "comments": "This student's name is Alice Betsy" + } + } +} diff --git a/src/main/java/teammates/ui/webapi/GetFeedbackQuestionsAction.java b/src/main/java/teammates/ui/webapi/GetFeedbackQuestionsAction.java index 331641cc9f1..ff3926300c5 100644 --- a/src/main/java/teammates/ui/webapi/GetFeedbackQuestionsAction.java +++ b/src/main/java/teammates/ui/webapi/GetFeedbackQuestionsAction.java @@ -142,13 +142,13 @@ public JsonResult execute() { switch (intent) { case STUDENT_SUBMISSION: questions = sqlLogic.getFeedbackQuestionsForStudents(feedbackSession); - StudentAttributes studentAttributes = getStudentOfCourseFromRequest(courseId); + Student student = getSqlStudentOfCourseFromRequest(courseId); questions.forEach(question -> sqlLogic.populateFieldsToGenerateInQuestion(question, courseId, - studentAttributes.getEmail(), studentAttributes.getTeam())); + student.getEmail(), student.getTeamName())); break; case INSTRUCTOR_SUBMISSION: - InstructorAttributes instructor = getInstructorOfCourseFromRequest(courseId); + Instructor instructor = getSqlInstructorOfCourseFromRequest(courseId); questions = sqlLogic.getFeedbackQuestionsForInstructors(feedbackSession, instructor.getEmail()); questions.forEach(question -> sqlLogic.populateFieldsToGenerateInQuestion(question, courseId, diff --git a/src/test/java/teammates/test/AbstractBackDoor.java b/src/test/java/teammates/test/AbstractBackDoor.java index 5cbcc012808..16c62c5e3ed 100644 --- a/src/test/java/teammates/test/AbstractBackDoor.java +++ b/src/test/java/teammates/test/AbstractBackDoor.java @@ -673,10 +673,10 @@ public FeedbackSessionAttributes getSoftDeletedSession(String feedbackSessionNam } /** - * Get feedback question from database. + * Get feedback question data from database. */ - public FeedbackQuestionAttributes getFeedbackQuestion(String courseId, String feedbackSessionName, - int qnNumber) { + public FeedbackQuestionData getFeedbackQuestionData(String courseId, String feedbackSessionName, + int qnNumber) { Map