diff --git a/src/main/java/teammates/common/datatransfer/attributes/TopicAttributes.java b/src/main/java/teammates/common/datatransfer/attributes/TopicAttributes.java index 18964f6..5baccd3 100644 --- a/src/main/java/teammates/common/datatransfer/attributes/TopicAttributes.java +++ b/src/main/java/teammates/common/datatransfer/attributes/TopicAttributes.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; +import teammates.common.util.Assumption; import teammates.common.util.FieldValidator; import teammates.common.util.JsonUtils; import teammates.common.util.SanitizationHelper; @@ -11,7 +12,7 @@ public class TopicAttributes extends EntityAttributes { - /* Variable declarations */ + /* Variable declarations */ public String id; public String creator; public String name; @@ -35,29 +36,29 @@ public TopicAttributes(String topicID, String creator, String name, String desc, public static Builder builder(String topicID, String creator, String name, String desc, ArrayList replies, Integer count,Integer viewCounter) { return new Builder(topicID, creator, name, desc, replies, count,viewCounter); } - + /* Getters */ - + public Integer getViewCounter() { return viewCounter; } - + public String getId() { return id; } - + public String getName() { return name; } - + public String getCreator() { return creator; } - + public String getDesc() { return desc; } - + public void setCount(Integer count) { this.count = count; } @@ -65,24 +66,24 @@ public void setCount(Integer count) { public ArrayList getReplies(){ return replies; } - + public Integer getCount() { return count; } - + /* Setters */ - + public void setViewCounter(Integer viewCounter) { this.viewCounter = viewCounter; } - + public void setReplies(ArrayList replies) { this.replies = replies; } - - + + /* Function to add a reply to the topic count iterated as it is used as partial key to identify reply*/ public void addReply(RepliesAttributes reply) { @@ -93,7 +94,7 @@ public void addReply(RepliesAttributes reply) replies.add(reply); count++; } - + /* Used to validate strings stored in topic */ @Override public List getInvalidityInfo() { FieldValidator validator = new FieldValidator(); @@ -115,32 +116,32 @@ public Topic toEntity() { } return new Topic(getId(), getCreator(), getName(), getDesc(), repliesEntity, count,viewCounter); } - + /* Inherited methods, not all necessary for our functionality */ @Override public String getIdentificationString() { return null; } - + @Override public String getEntityTypeAsString() { return "Topic"; } - + @Override public String getBackupIdentifier() { return null; } - + @Override public String getJsonString() { return JsonUtils.toJson(this, TopicAttributes.class); } - + @Override public void sanitizeForSaving() { } - + /* Takes ArrayList of Reply entities, returns array of RepliesAttributes */ /* Required in order to take objects from database and build them back up to a usable state */ public static ArrayList getRepliesAtt(ArrayList replies) @@ -151,28 +152,36 @@ public static ArrayList getRepliesAtt(ArrayList replie for(Reply reply:replies) { repliesAtt.add(new RepliesAttributes(reply.getDesc(), reply.getStudentName(), reply.getId(), reply.getDateTime(),reply.getLike(),reply.getDislike())); - } + } return repliesAtt; } return null; } - + public void removeReply(RepliesAttributes reply) { replies.remove(reply); } - + /* Calls above method, is used to return a TopicAttributes instance based on a Topic entity in database */ public static class Builder { + private static final String REQUIRED_FIELD_CANNOT_BE_NULL = "Non-null value expected"; private final TopicAttributes topicAttributes; - + public Builder(String topicID, String creator, String name, String desc, ArrayList replies, Integer count,Integer viewCounter) { + validateRequiredFields(name, desc); ArrayList repliesAtt = getRepliesAtt(replies); topicAttributes = new TopicAttributes(topicID, creator, name, desc, repliesAtt, count,viewCounter); } - + public TopicAttributes build() { return topicAttributes; } + + private void validateRequiredFields(Object... objects) { + for (Object object : objects) { + Assumption.assertNotNull(REQUIRED_FIELD_CANNOT_BE_NULL, object); + } + } } } diff --git a/src/main/java/teammates/common/util/AppUrl.java b/src/main/java/teammates/common/util/AppUrl.java index 099b4cb..56a4f1e 100755 --- a/src/main/java/teammates/common/util/AppUrl.java +++ b/src/main/java/teammates/common/util/AppUrl.java @@ -25,6 +25,18 @@ public AppUrl withInstructorInstitution(String institute) { public AppUrl withCourseId(String courseId) { return withParam(Const.ParamsNames.COURSE_ID, courseId); } + + public AppUrl withTopicName(String topicName) { + return withParam(Const.ParamsNames.TOPIC_NAME, topicName); + } + + public AppUrl withTopicId(String topicId) { + return withParam(Const.ParamsNames.TOPIC_ID, topicId); + } + + public AppUrl withReplyId(int replyId) { + return withParam(Const.ParamsNames.REPLY_ID, Integer.toString(replyId)); + } public AppUrl withSessionName(String feedbackSessionName) { return withParam(Const.ParamsNames.FEEDBACK_SESSION_NAME, feedbackSessionName); @@ -45,5 +57,4 @@ public AppUrl withQuestionNumber(String questionNumber) { public AppUrl withEnableSessionEditDetails(boolean shouldLoadInEditMode) { return withParam(Const.ParamsNames.FEEDBACK_SESSION_ENABLE_EDIT, Boolean.toString(shouldLoadInEditMode)); } - } diff --git a/src/main/java/teammates/storage/api/TopicsDb.java b/src/main/java/teammates/storage/api/TopicsDb.java index b6cee60..7367fed 100644 --- a/src/main/java/teammates/storage/api/TopicsDb.java +++ b/src/main/java/teammates/storage/api/TopicsDb.java @@ -39,7 +39,7 @@ protected LoadType load() { * Return a topic based of the topicId * @param topicId Name of the topic */ - + public TopicAttributes getTopic(String topicId) { Assumption.assertNotNull(Const.StatusCodes.DBLEVEL_NULL_INPUT, topicId); return makeAttributesOrNull(getTopicEntity(topicId)); @@ -55,7 +55,7 @@ public List getTopics(List topicIds) { return makeAttributes(getTopicEntities(topicIds)); } - + /** * Updates a topic by asserting that a topic with the same id is contained within database already, * if so the topic is overwritten by new topic with new values @@ -155,9 +155,7 @@ public void deleteTopic(String topicID) { Assumption.assertNotNull(Const.StatusCodes.DBLEVEL_NULL_INPUT, topicID); //Only the key is important, the rest are irrelevant deleteEntity(TopicAttributes - .builder(topicID, null, null, null, null, null,null) + .builder(topicID, "Non-existing", "Non-existing", "Non-existing", null, null,null) .build()); - - } } diff --git a/src/test/java/.DS_Store b/src/test/java/.DS_Store new file mode 100644 index 0000000..98e9d00 Binary files /dev/null and b/src/test/java/.DS_Store differ diff --git a/src/test/java/teammates/.DS_Store b/src/test/java/teammates/.DS_Store new file mode 100644 index 0000000..534b870 Binary files /dev/null and b/src/test/java/teammates/.DS_Store differ diff --git a/src/test/java/teammates/test/.DS_Store b/src/test/java/teammates/test/.DS_Store new file mode 100644 index 0000000..bfce276 Binary files /dev/null and b/src/test/java/teammates/test/.DS_Store differ diff --git a/src/test/java/teammates/test/cases/.DS_Store b/src/test/java/teammates/test/cases/.DS_Store new file mode 100644 index 0000000..cde1999 Binary files /dev/null and b/src/test/java/teammates/test/cases/.DS_Store differ diff --git a/src/test/java/teammates/test/cases/BaseTestCaseWithDatastoreAccess.java b/src/test/java/teammates/test/cases/BaseTestCaseWithDatastoreAccess.java index ecb731a..9054c9c 100755 --- a/src/test/java/teammates/test/cases/BaseTestCaseWithDatastoreAccess.java +++ b/src/test/java/teammates/test/cases/BaseTestCaseWithDatastoreAccess.java @@ -79,7 +79,7 @@ private EntityAttributes getEntity(EntityAttributes expected) { } else if (expected instanceof StudentAttributes) { return getStudent((StudentAttributes) expected); - + } else if (expected instanceof TopicAttributes) { return getTopic((TopicAttributes) expected); @@ -126,6 +126,7 @@ private void verifyEquals(EntityAttributes expected, EntityAttributes actu } else if (expected instanceof TopicAttributes) { TopicAttributes expectedTopic = (TopicAttributes) expected; TopicAttributes actualTopic = (TopicAttributes) actual; + equalizeIrrelevantData(expectedTopic, actualTopic); assertEquals(JsonUtils.toJson(expectedTopic), JsonUtils.toJson(actualTopic)); } else if (expected instanceof FeedbackQuestionAttributes) { @@ -188,13 +189,20 @@ private void equalizeIrrelevantData(AccountAttributes expected, AccountAttribute } protected abstract CourseAttributes getCourse(CourseAttributes course); - + protected abstract TopicAttributes getTopic(TopicAttributes topic); private void equalizeIrrelevantData(CourseAttributes expected, CourseAttributes actual) { // Ignore time field as it is stamped at the time of creation in testing expected.createdAt = actual.createdAt; } + + private void equalizeIrrelevantData(TopicAttributes expected, TopicAttributes actual) { + System.out.println(actual.toString()); + expected.id = actual.id; + expected.replies = actual.replies; + expected.viewCounter = actual.viewCounter; + } protected abstract FeedbackQuestionAttributes getFeedbackQuestion(FeedbackQuestionAttributes fq); diff --git a/src/test/java/teammates/test/cases/browsertests/StudentDiscussionBoardPageUiTest.java b/src/test/java/teammates/test/cases/browsertests/StudentDiscussionBoardPageUiTest.java index 40584b5..3823bc2 100644 --- a/src/test/java/teammates/test/cases/browsertests/StudentDiscussionBoardPageUiTest.java +++ b/src/test/java/teammates/test/cases/browsertests/StudentDiscussionBoardPageUiTest.java @@ -1,67 +1,79 @@ -//package teammates.test.cases.browsertests; -// -//import org.junit.BeforeClass; -//import org.testng.annotations.Test; -// -//import teammates.common.datatransfer.attributes.TopicAttributes; -//import teammates.common.util.AppUrl; -//import teammates.common.util.Const; -//import teammates.test.driver.BackDoor; -//import teammates.test.pageobjects.StudentDiscussionBoardPage; -//import teammates.test.pageobjects.StudentHomePage; -// -//public class StudentDiscussionBoardPageUiTest extends BaseUiTestCase { -// private StudentDiscussionBoardPage discussionBoardPage; -// -// private TopicAttributes validTopic = -// TopicAttributes -// .builder("A1Help", "I need help") -// .build(); -// -// protected void prepareTestData() { -// testData = loadDataBundle("/StudentDiscussionBoardPageUiTest.json"); -// removeAndRestoreDataBundle(testData); -// } -// -// @BeforeClass -// public void classSetup() { -// BackDoor.deleteTopic(validTopic.getName()); // delete if it exists -// } -// -// @Test -// public void allTests() throws Exception { -// prepareTestData(); -// testNavLinkToPage(); -// testAddAction(); -// testDeleteAction(); -// } -// -// private void testAddAction() throws Exception { -// discussionBoardPage = getDiscussionBoadPageForStudent("studentWithEmptyProfile"); -// -// ______TS("Add action success"); -// discussionBoardPage.addTopic(validTopic.getName(), validTopic.getDesc()); -// // Assert the page contains the topic -// assertTrue(discussionBoardPage.containsTestTopic()); -// } -// -// private void testDeleteAction() throws Exception { -// // Called, assuming the valid topic had been added -// discussionBoardPage.deleteTopic(validTopic.getName()); -// // Assert the page doesn't contain the topic -// assertFalse(discussionBoardPage.containsTestTopic()); -// } -// -// private void testNavLinkToPage() { -// AppUrl profileUrl = createUrl(Const.ActionURIs.STUDENT_HOME_PAGE) -// .withUserId(testData.accounts.get("studentWithEmptyProfile").googleId); -// StudentHomePage shp = loginAdminToPage(profileUrl, StudentHomePage.class); -// discussionBoardPage = shp.loadDiscussionBoardTab(); -// } -// -// private StudentDiscussionBoardPage getDiscussionBoadPageForStudent(String studentId) { -// AppUrl profileUrl = createUrl(Const.ActionURIs.STUDENT_DISCUSSION_BOARD_PAGE) -// .withUserId(testData.accounts.get(studentId).googleId); -// return loginAdminToPage(profileUrl, StudentDiscussionBoardPage.class); -// } -//} +package teammates.test.cases.browsertests; + +import org.junit.BeforeClass; +import org.testng.annotations.Test; +import java.util.ArrayList; +import java.util.UUID; + +import teammates.common.datatransfer.attributes.TopicAttributes; +import teammates.common.util.AppUrl; +import teammates.common.util.Const; +import teammates.test.pageobjects.StudentDiscussionBoardPage; +import teammates.test.pageobjects.StudentHomePage; +import teammates.storage.entity.Reply; + +public class StudentDiscussionBoardPageUiTest extends BaseUiTestCase { + private StudentDiscussionBoardPage discussionBoardPage; + private String uniqueID = UUID.randomUUID().toString(); + // Create a valid topic for testing + private TopicAttributes validTopic = + TopicAttributes + .builder(uniqueID, "Benny Charles", "A1Help", "I need help", new ArrayList(), 0, 0) + .build(); + + protected void prepareTestData() { + // Load the test data (account used to test) + testData = loadDataBundle("/StudentDiscussionBoardPageUiTest.json"); + removeAndRestoreDataBundle(testData); + } + + @BeforeClass + public void classSetup() { + // Delete existing test topic if there is one + discussionBoardPage = getDiscussionBoardPageForStudent("studentWithEmptyProfile"); + discussionBoardPage = discussionBoardPage.deleteTopic(validTopic.getName()); + } + + @Test + public void allTests() throws Exception { + prepareTestData(); + testNavLinkToPage(); + testAddAction(); + testCancelDeleteAction(); + testDeleteAction(); + } + +protected void testAddAction() throws Exception { + // Create a new topic + ______TS("Add action success"); + discussionBoardPage.addTopic(validTopic.getName(), validTopic.getDesc()); + // Assert the page contains the topic + assertTrue(discussionBoardPage.containsTestTopic()); + } + + private void testCancelDeleteAction() throws Exception { + discussionBoardPage.cancelDeleteTopic(validTopic.getName()); + // Assert the page still contains the topic + assertTrue(discussionBoardPage.containsTestTopic()); + } + + private void testDeleteAction() throws Exception { + // Called, assuming the valid topic had been added + discussionBoardPage.deleteTopic(validTopic.getName()); + // Assert the page doesn't contain the topic + assertFalse(discussionBoardPage.containsTestTopic()); + } + + private void testNavLinkToPage() { + AppUrl profileUrl = createUrl(Const.ActionURIs.STUDENT_HOME_PAGE) + .withUserId(testData.accounts.get("studentWithEmptyProfile").googleId); + StudentHomePage shp = loginAdminToPage(profileUrl, StudentHomePage.class); + discussionBoardPage = shp.loadDiscussionBoardTab(); + } + + private StudentDiscussionBoardPage getDiscussionBoardPageForStudent(String studentId) { + AppUrl profileUrl = createUrl(Const.ActionURIs.STUDENT_DISCUSSION_BOARD_PAGE) + .withUserId(testData.accounts.get(studentId).googleId); + return loginAdminToPage(profileUrl, StudentDiscussionBoardPage.class); + } +} diff --git a/src/test/java/teammates/test/cases/browsertests/StudentDiscussionBoardTopicEditPageUiTest.java b/src/test/java/teammates/test/cases/browsertests/StudentDiscussionBoardTopicEditPageUiTest.java new file mode 100644 index 0000000..c5c7224 --- /dev/null +++ b/src/test/java/teammates/test/cases/browsertests/StudentDiscussionBoardTopicEditPageUiTest.java @@ -0,0 +1,88 @@ +package teammates.test.cases.browsertests; + +import org.testng.annotations.Test; + +import teammates.common.util.AppUrl; +import teammates.common.util.Const; +import teammates.test.pageobjects.StudentDiscussionBoardTopicEditPage; +import teammates.test.pageobjects.StudentDiscussionBoardPage; + +public class StudentDiscussionBoardTopicEditPageUiTest extends BaseUiTestCase { + private StudentDiscussionBoardTopicEditPage topicEditPage; + private StudentDiscussionBoardPage discussionBoardPage; + private String topicId, topicName, topicDesc, newTopicName, newTopicDesc; + + @Override + protected void prepareTestData() throws Exception { + testData = loadDataBundle("/StudentDiscussionBoardTopicEditPageUiTest.json"); + removeAndRestoreDataBundle(testData); + // Following strings created locally, rather than storing in the json file + topicName = "TESTING_EDIT_PAGE_TOPIC"; + topicDesc = "testing_edit_page_desc"; + newTopicName = "CHANGED_TESTING_EDIT_PAGE_TOPIC"; + newTopicDesc = "changed_testing_edit_page_desc"; + } + + @Test + public void allTests() throws Exception { + prepareTestData(); + // Manually create the test on the discussion board using Selenium + discussionBoardPage = createTestTopic(); + // Load the newly created edit topic page + topicEditPage = getTopicEditPage(topicName); + testEditTopicAction(); + testCancelDeleteTopicAction(); + testDeleteTopicAction(); + } + + private void testEditTopicAction() { + // Edit the topic + topicEditPage.editTopic(newTopicName, newTopicDesc); + topicEditPage = getTopicEditPage(newTopicName); + assertTrue(topicEditPage.containsExpectedTopic(newTopicName, newTopicDesc)); + } + + private void testCancelDeleteTopicAction() { + // Cancel the deletion + topicEditPage.cancelDeleteTopic(); + assertTrue(topicEditPage.containsExpectedTopic(newTopicName, newTopicDesc)); + } + + private void testDeleteTopicAction() { + // Delete the topic + topicEditPage.deleteTopic(); + assertFalse(topicEditPage.containsExpectedTopic(newTopicName, newTopicDesc)); + } + + private StudentDiscussionBoardPage createTestTopic() { + // Manually create the test on the discussion board using Selenium + discussionBoardPage = getDiscussionBoardPage(); + discussionBoardPage.addTopic(topicName, topicDesc); + return discussionBoardPage; + } + + private StudentDiscussionBoardPage getDiscussionBoardPage() { + // Return the student discussion board page + AppUrl profileUrl = createUrl(Const.ActionURIs.STUDENT_DISCUSSION_BOARD_PAGE) + .withUserId(testData.accounts.get("studentWithEmptyProfile").googleId); + return loginAdminToPage(profileUrl, StudentDiscussionBoardPage.class); + } + + private StudentDiscussionBoardTopicEditPage getTopicEditPage(String topicName) { + // Load a discussion board page + discussionBoardPage = getDiscussionBoardPage(); + // Get the edit page link for a pre-existing testing topic + String topicEditPageUrl = discussionBoardPage.getEditLink(topicName); + + // Get the id of the topic from the edit link + // There was no easy way to get the id, which was crucial for creating the edit topic page + topicId = topicEditPageUrl.split("topicId=")[1].split("&")[0]; + + // Load the edit topic page for the pre-existing testing topic + AppUrl topicEditPageLink = createUrl(Const.ActionURIs.STUDENT_DISCUSSION_BOARD_EDIT_TOPIC_PAGE) + .withTopicName(topicName) + .withTopicId(topicId) + .withUserId(testData.accounts.get("studentWithEmptyProfile").googleId); + return loginAdminToPage(topicEditPageLink, StudentDiscussionBoardTopicEditPage.class); + } +} diff --git a/src/test/java/teammates/test/cases/browsertests/StudentRepliesBoardEditPageUiTest.java b/src/test/java/teammates/test/cases/browsertests/StudentRepliesBoardEditPageUiTest.java new file mode 100644 index 0000000..198ea5a --- /dev/null +++ b/src/test/java/teammates/test/cases/browsertests/StudentRepliesBoardEditPageUiTest.java @@ -0,0 +1,122 @@ +package teammates.test.cases.browsertests; + +import org.testng.annotations.Test; + +import teammates.common.util.AppUrl; +import teammates.common.util.Const; +import teammates.test.pageobjects.StudentDiscussionBoardPage; +import teammates.test.pageobjects.StudentRepliesBoardEditPage; +import teammates.test.pageobjects.StudentRepliesBoardPage; + +public class StudentRepliesBoardEditPageUiTest extends BaseUiTestCase { + private StudentDiscussionBoardPage discussionBoardPage; + private StudentRepliesBoardPage repliesBoardPage; + private StudentRepliesBoardEditPage repliesBoardEditPage; + private String topicId, topicName, topicDesc, replyDesc, newReplyDesc; + + @Override + protected void prepareTestData() throws Exception { + testData = loadDataBundle("/StudentRepliesBoardPageUiTest.json"); + removeAndRestoreDataBundle(testData); + + topicName = "TESTING_REPLIES_BOARD_EDIT_PAGE"; + topicDesc = "testing_replies_board_edit_pagedesc"; + replyDesc = "this_is_a_test_reply"; + newReplyDesc = "this_is_a_changed_test_reply"; + } + + @Test + public void allTests() throws Exception { + prepareTestData(); + + // Create the test topic and get the replies board for that topic + discussionBoardPage = createTestTopic(); + repliesBoardPage = getRepliesBoardPage(topicName); + // Create the test reply and get the replies board edit page for that reply + repliesBoardPage.addReply(replyDesc); + repliesBoardEditPage = getRepliesBoardEditPage(); + + testContent(); + testEditReply(); + testCancelDeleteReply(); + testDeleteReply(); + deleteTestData(); + } + + private void testContent() { + assertTrue(repliesBoardEditPage.containsExpectedPageContents()); + } + + private void testEditReply() { + // Get the replies board edit page + repliesBoardEditPage = getRepliesBoardEditPage(); + repliesBoardEditPage.editReply(newReplyDesc); + // Get the replies board page and assert the reply has been edited + repliesBoardPage = getRepliesBoardPage(topicName); + assertTrue(repliesBoardPage.containsExpectedReply( + testData.accounts.get("studentWithEmptyProfile").name, newReplyDesc)); + } + + private void testCancelDeleteReply() { + // Get the replies board edit page + repliesBoardEditPage = getRepliesBoardEditPage(); + repliesBoardEditPage.cancelDeleteReply(); + // Get the replies board page and assert the reply still exists + repliesBoardPage = getRepliesBoardPage(topicName); + assertTrue(repliesBoardPage.containsExpectedReply( + testData.accounts.get("studentWithEmptyProfile").name, newReplyDesc)); + } + + private void testDeleteReply() { + // Get the replies board edit page + repliesBoardEditPage = getRepliesBoardEditPage(); + repliesBoardEditPage.deleteReply(); + // Get thre replies board page and assert the reply is gone + repliesBoardPage = getRepliesBoardPage(topicName); + assertFalse(repliesBoardPage.containsExpectedReply( + testData.accounts.get("studentWithEmptyProfile").name, newReplyDesc)); + } + + private StudentDiscussionBoardPage createTestTopic() { + // Manually create the test on the discussion board using Selenium + discussionBoardPage = getDiscussionBoardPage(); + discussionBoardPage.addTopic(topicName, topicDesc); + return discussionBoardPage; + } + + private StudentDiscussionBoardPage getDiscussionBoardPage() { + // Return the student discussion board page + AppUrl profileUrl = createUrl(Const.ActionURIs.STUDENT_DISCUSSION_BOARD_PAGE) + .withUserId(testData.accounts.get("studentWithEmptyProfile").googleId); + return loginAdminToPage(profileUrl, StudentDiscussionBoardPage.class); + } + + private StudentRepliesBoardPage getRepliesBoardPage(String topicName) { + // Load a discussion board page + discussionBoardPage = getDiscussionBoardPage(); + String topicEditPageUrl = discussionBoardPage.getEditLink(topicName); + // Get the id from the edit topic page url + topicId = topicEditPageUrl.split("topicId=")[1].split("&")[0]; + + AppUrl repliesBoardPageLink = createUrl(Const.ActionURIs.STUDENT_REPLIES_BOARD_PAGE) + .withTopicName(topicName) + .withTopicId(topicId) + .withUserId(testData.accounts.get("studentWithEmptyProfile").googleId); + return loginAdminToPage(repliesBoardPageLink, StudentRepliesBoardPage.class); + } + + private StudentRepliesBoardEditPage getRepliesBoardEditPage() { + // Get the replies board edit page for the test reply + // Since there is only one test reply, there is no need to get the replyId + AppUrl repliesBoardEditPageLink = createUrl(Const.ActionURIs.STUDENT_REPLIES_EDIT_PAGE) + .withTopicId(topicId) + .withReplyId(0); + return loginAdminToPage(repliesBoardEditPageLink, StudentRepliesBoardEditPage.class); + } + + private void deleteTestData() { + // Delete the testing topic + discussionBoardPage = getDiscussionBoardPage(); + discussionBoardPage.deleteTopic(topicName); + } +} diff --git a/src/test/java/teammates/test/cases/browsertests/StudentRepliesBoardPageUiTest.java b/src/test/java/teammates/test/cases/browsertests/StudentRepliesBoardPageUiTest.java new file mode 100644 index 0000000..4dff397 --- /dev/null +++ b/src/test/java/teammates/test/cases/browsertests/StudentRepliesBoardPageUiTest.java @@ -0,0 +1,113 @@ +package teammates.test.cases.browsertests; + +import org.testng.annotations.Test; + +import teammates.common.util.AppUrl; +import teammates.common.util.Const; +import teammates.test.pageobjects.StudentDiscussionBoardPage; +import teammates.test.pageobjects.StudentRepliesBoardPage; + +public class StudentRepliesBoardPageUiTest extends BaseUiTestCase { + private StudentDiscussionBoardPage discussionBoardPage; + private StudentRepliesBoardPage repliesBoardPage; + private String topicId, topicName, topicDesc, replyDesc; + + @Override + protected void prepareTestData() throws Exception { + testData = loadDataBundle("/StudentRepliesBoardPageUiTest.json"); + removeAndRestoreDataBundle(testData); + + topicName = "TESTING_REPLIES_BOARD"; + topicDesc = "testing_replies_board_desc"; + replyDesc = "this_is_a_test_reply"; + } + + @Test + public void allTests() throws Exception { + prepareTestData(); + + // Create the test topic and get the replies board for that topic + discussionBoardPage = createTestTopic(); + repliesBoardPage = getRepliesBoardPage(topicName); + + testContent(); + testAddAction(); + testLikeAction(); + testDislikeAction(); + testCancelDeleteAction(); + testDeleteAction(); + deleteTestData(); + } + + private void testContent() { + assertTrue(repliesBoardPage.containsExpectedTopic(topicName, topicDesc)); + } + + private void testAddAction() throws Exception { + repliesBoardPage.addReply(replyDesc); + // Get the replies board page and assert the reply has been added + repliesBoardPage = getRepliesBoardPage(topicName); + assertTrue(repliesBoardPage.containsExpectedReply( + testData.accounts.get("studentWithEmptyProfile").name, replyDesc)); + } + + private void testLikeAction() throws Exception { + // Assert the like button increments the likes by one + assertTrue(repliesBoardPage.likeReply(replyDesc)); + } + + private void testDislikeAction() throws Exception { + // Assert the dislike button increments the dislikes by one + assertTrue(repliesBoardPage.dislikeReply(replyDesc)); + } + + private void testCancelDeleteAction() throws Exception { + repliesBoardPage.cancelDeleteReply(replyDesc); + // Get the replies board page and assert the reply still exists + repliesBoardPage = getRepliesBoardPage(topicName); + assertTrue(repliesBoardPage.containsExpectedReply( + testData.accounts.get("studentWithEmptyProfile").name, replyDesc)); + } + + private void testDeleteAction() throws Exception { + repliesBoardPage.deleteReply(replyDesc); + // Get the replies board page and assert the reply has been deleted + repliesBoardPage = getRepliesBoardPage(topicName); + assertFalse(repliesBoardPage.containsExpectedReply( + testData.accounts.get("studentWithEmptyProfile").name, replyDesc)); + } + + private StudentDiscussionBoardPage createTestTopic() { + // Manually create the test on the discussion board using Selenium + discussionBoardPage = getDiscussionBoardPage(); + discussionBoardPage.addTopic(topicName, topicDesc); + return discussionBoardPage; + } + + private StudentDiscussionBoardPage getDiscussionBoardPage() { + // Return the student discussion board page + AppUrl profileUrl = createUrl(Const.ActionURIs.STUDENT_DISCUSSION_BOARD_PAGE) + .withUserId(testData.accounts.get("studentWithEmptyProfile").googleId); + return loginAdminToPage(profileUrl, StudentDiscussionBoardPage.class); + } + + private StudentRepliesBoardPage getRepliesBoardPage(String topicName) { + // Load a discussion board page + discussionBoardPage = getDiscussionBoardPage(); + String topicEditPageUrl = discussionBoardPage.getEditLink(topicName); + // Get the id from the edit topic page url + topicId = topicEditPageUrl.split("topicId=")[1].split("&")[0]; + + AppUrl repliesBoardPageLink = createUrl(Const.ActionURIs.STUDENT_REPLIES_BOARD_PAGE) + .withTopicName(topicName) + .withTopicId(topicId) + .withUserId(testData.accounts.get("studentWithEmptyProfile").googleId); + return loginAdminToPage(repliesBoardPageLink, StudentRepliesBoardPage.class); + } + + private void deleteTestData() { + // Delete the testing topic + discussionBoardPage = getDiscussionBoardPage(); + discussionBoardPage.deleteTopic(topicName); + } +} diff --git a/src/test/java/teammates/test/cases/datatransfer/TopicAttributesTest.java b/src/test/java/teammates/test/cases/datatransfer/TopicAttributesTest.java index 01e9ee5..77953f2 100644 --- a/src/test/java/teammates/test/cases/datatransfer/TopicAttributesTest.java +++ b/src/test/java/teammates/test/cases/datatransfer/TopicAttributesTest.java @@ -1,46 +1,51 @@ -//package teammates.test.cases.datatransfer; -// -//import org.testng.annotations.Test; -// -//import teammates.common.datatransfer.attributes.TopicAttributes; -//import teammates.test.cases.BaseTestCase; -// -//public class TopicAttributesTest extends BaseTestCase { -// -// private String validName = "A1Help"; -// private String validDesc = "I need help"; -// -// // Test 1a. -// @Test -// public void testStandardBuilder() { -// TopicAttributes topicAttributes = TopicAttributes -// .builder(validName, validDesc) -// .build(); -// assertEquals(validName, topicAttributes.getName()); -// assertEquals(validDesc, topicAttributes.getDesc()); -// } -// -// // Test 1b. -// @Test -// public void testBuilderWithNullDescription() { -// try { -// TopicAttributes.builder(validName, null) -// .build(); -// signalFailureToDetectException(); -// } catch (AssertionError e) { -// assertEquals("Non-null value expected", e.getMessage()); -// } -// } -// -// // Test 1c. -// @Test -// public void testBuilderWithNullName() { -// try { -// TopicAttributes.builder(null, validDesc) -// .build(); -// signalFailureToDetectException(); -// } catch (AssertionError e) { -// assertEquals("Non-null value expected", e.getMessage()); -// } -// } -//} +package teammates.test.cases.datatransfer; + +import java.util.ArrayList; +import java.util.UUID; + +import org.testng.annotations.Test; + +import teammates.common.datatransfer.attributes.TopicAttributes; +import teammates.storage.entity.Reply; +import teammates.test.cases.BaseTestCase; + +public class TopicAttributesTest extends BaseTestCase { + private String testName = "Benny Charles"; + private String validName = "A1Help"; + private String validDesc = "I need help"; + + // Test 1a. + @Test + public void testStandardBuilder() { + TopicAttributes validTopic = + TopicAttributes + .builder(UUID.randomUUID().toString(), testName, "A1Help", "I need help", new ArrayList(), 0, 0) + .build(); + assertEquals(validName, validTopic.getName()); + assertEquals(validDesc, validTopic.getDesc()); + } + + // Test 1b. + @Test + public void testBuilderWithNullDescription() { + try { + TopicAttributes.builder(UUID.randomUUID().toString(), testName, validName, null, new ArrayList(), 0, 0) + .build(); + signalFailureToDetectException(); + } catch (AssertionError e) { + assertEquals("Non-null value expected", e.getMessage()); + } + } + + // Test 1c. + @Test + public void testBuilderWithNullName() { + try { + TopicAttributes.builder(UUID.randomUUID().toString(), testName, null, validDesc, new ArrayList(), 0, 0) + .build(); + signalFailureToDetectException(); + } catch (AssertionError e) { + assertEquals("Non-null value expected", e.getMessage()); + } + } +} diff --git a/src/test/java/teammates/test/cases/logic/TopicsLogicTest.java b/src/test/java/teammates/test/cases/logic/TopicsLogicTest.java index 9701a1b..79774c1 100644 --- a/src/test/java/teammates/test/cases/logic/TopicsLogicTest.java +++ b/src/test/java/teammates/test/cases/logic/TopicsLogicTest.java @@ -1,13 +1,29 @@ package teammates.test.cases.logic; +import java.util.ArrayList; +import java.util.UUID; + import org.testng.annotations.Test; import teammates.common.datatransfer.attributes.TopicAttributes; import teammates.logic.core.TopicsLogic; +import teammates.storage.api.TopicsDb; +import teammates.storage.entity.Reply; public class TopicsLogicTest extends BaseLogicTest { -/* private static final TopicsLogic topicsLogic = TopicsLogic.inst(); + private static final TopicsLogic topicsLogic = TopicsLogic.inst(); + private static final TopicsDb topicsDb = new TopicsDb(); + private String testName = "Benny Charles"; + + private TopicAttributes validTopic1 = + TopicAttributes + .builder(UUID.randomUUID().toString(), testName, "A1Help", "I need help", new ArrayList(), 0, 0) + .build(); + private TopicAttributes validTopic2 = + TopicAttributes + .builder(UUID.randomUUID().toString(), testName, "A2Help", "I need help", new ArrayList(), 0, 0) + .build(); @Test public void testAll() throws Exception { @@ -16,38 +32,43 @@ public void testAll() throws Exception { } private void testCreateTopic() throws Exception { - ______TS("typical case"); - TopicAttributes topicAttributes = TopicAttributes - .builder("A1Help", "I need help") - .build(); - topicsLogic.createTopic(topicAttributes.getName(), topicAttributes.getDesc()); - verifyPresentInDatastore(topicAttributes); + topicsLogic.createTopic(validTopic1.getId(), validTopic1.getCreator(), validTopic1.getName(), + validTopic1.getDesc(), new ArrayList(), validTopic1.getCount(), + validTopic1.getViewCounter()); + verifyPresent(validTopic1.getId()); ______TS("Null description"); try { - topicsLogic.createTopic(topicAttributes.getName(), null); + topicsLogic.createTopic(validTopic2.getId(), validTopic2.getCreator(), validTopic2.getName(), + null, new ArrayList(), validTopic2.getCount(), + validTopic2.getViewCounter()); signalFailureToDetectException(); } catch (AssertionError e) { assertEquals("Non-null value expected", e.getMessage()); } + verifyAbsentInDatastore(validTopic2); ______TS("Null name"); try { - topicsLogic.createTopic(null, topicAttributes.getDesc()); + topicsLogic.createTopic(validTopic2.getId(), validTopic2.getCreator(), null, + validTopic2.getDesc(), new ArrayList(), validTopic2.getCount(), + validTopic2.getViewCounter()); signalFailureToDetectException(); } catch (AssertionError e) { assertEquals("Non-null value expected", e.getMessage()); } + verifyAbsentInDatastore(validTopic2); } private void testDeleteTopic() { - // Run assuming the topic is still in the datastore - ______TS("typical case"); - TopicAttributes topicAttributes = TopicAttributes - .builder("A1Help", "I need help") - .build(); - topicsLogic.deleteTopicCascade(topicAttributes.getName()); - verifyAbsentInDatastore(topicAttributes); - }*/ + // Run assuming the topic is still in the datastore + ______TS("typical case"); + topicsLogic.deleteTopicCascade(validTopic1.getId()); + verifyAbsentInDatastore(validTopic1); + } + + private void verifyPresent(String topicId) { + assertNotNull(topicsDb.getTopic(topicId)); + } } diff --git a/src/test/java/teammates/test/cases/pagedata/StudentDiscussionBoardPageDataTest.java b/src/test/java/teammates/test/cases/pagedata/StudentDiscussionBoardPageDataTest.java index b175d14..f83cca1 100644 --- a/src/test/java/teammates/test/cases/pagedata/StudentDiscussionBoardPageDataTest.java +++ b/src/test/java/teammates/test/cases/pagedata/StudentDiscussionBoardPageDataTest.java @@ -4,76 +4,87 @@ import java.util.ArrayList; import java.util.List; +import java.util.UUID; -import teammates.common.util.Const; -import teammates.common.util.StringHelper; +import teammates.storage.entity.Reply; import teammates.test.cases.BaseTestCase; import teammates.ui.pagedata.StudentDiscussionBoardPageData; +import teammates.ui.template.ActiveTopicsTable; +import teammates.ui.template.ActiveTopicsTableRow; import teammates.common.datatransfer.attributes.AccountAttributes; import teammates.common.datatransfer.attributes.TopicAttributes; -import teammates.common.datatransfer.TopicDetailsBundle; public class StudentDiscussionBoardPageDataTest extends BaseTestCase { + private ArrayList falseData; + private AccountAttributes acct; + private String testName = "Benny Charles"; - // private TopicDetailsBundle tdb; - // private ArrayList falseData; - // private AccountAttributes acct; - // - // private StudentDiscussionBoardPageData sdbpd; - // - // @Test - // public void testAll() { - // testWithNoTopics(); - // testWithTopics(); - // } - // - // private void testWithNoTopics() { - // sdbpd = initializeData(); - // testNoTopics(sdbpd.getTopics()); - // } - // - // private void testWithTopics() { - // sdbpd = initializeData(); - // sdbpd = createFalseData(sdbpd); - // testTopics(sdbpd.getTopics()); - // } - // - // private StudentDiscussionBoardPageData initializeData() { - // acct = AccountAttributes.builder() - // .withGoogleId("valid.id") - // .withName("full name") - // .withEmail("e@email.com") - // .withInstitute("inst") - // .withIsInstructor(false) - // // .withStudentProfileAttributes(spa) - // .build(); - // return new StudentDiscussionBoardPageData(acct, dummySessionToken); - // } - // - // private StudentDiscussionBoardPageData createFalseData(StudentDiscussionBoardPageData data) { - // data.topics = new ArrayList(); - // falseData = new ArrayList(); - // - // falseData.add(new TopicDetailsBundle(new TopicAttributes("Testing Topic One", "This is the description for Topic One."))); - // falseData.add(new TopicDetailsBundle(new TopicAttributes("Testing Topic Two", "This is the description for Topic Two."))); - // - // data.topics = falseData; - // return data; - // } - // - // private void testNoTopics(List topics) { - // assertTrue(topics == null); - // } - // - // private void testTopics(List topics) { - // for(int i=0; i(); + + TopicAttributes validTopic = + TopicAttributes + .builder(UUID.randomUUID().toString(), testName, "A1Help", "I need help", new ArrayList(), 0, 0) + .build(); + TopicAttributes validTopic2 = + TopicAttributes + .builder(UUID.randomUUID().toString(), testName, "A2Help", "I need help", new ArrayList(), 0, 0) + .build(); + + // Add the topics + falseData.add(validTopic); + falseData.add(validTopic2); + data.init(falseData); + return data; + } + + private void testNoTopics(ActiveTopicsTable topics) { + assertTrue(topics == null); + } + + private void testTopics(ActiveTopicsTable topics) { + List rows = topics.getRows(); + + for(int i=0; iDiscussion Board"); + return getPageSource().contains("

Add New Topic

"); } public boolean containsTestTopic() { @@ -44,9 +44,17 @@ public StudentDiscussionBoardPage addTopic(String topicName, String topicDesc) { return this; } + public StudentDiscussionBoardPage cancelDeleteTopic(String topicName) { + click(getDeleteLink(topicName)); + waitForPageToLoad(); + click(cancelButton); + return this; + } + public StudentDiscussionBoardPage deleteTopic(String topicName) { click(getDeleteLink(topicName)); waitForPageToLoad(); + click(deleteButton); return this; } @@ -55,6 +63,11 @@ public WebElement getDeleteLink(String topicName) { return getDeleteLinkInRow(topicRowNumber); } + public String getEditLink(String topicName) { + int topicRowNumber = getRowNumberOfTopic(topicName); + return getEditLinkInRow(topicRowNumber); + } + private int getTopicCount() { // id should be renamed to tableActiveTopics By activeCoursesTable = By.id("tableActiveCourses"); @@ -80,4 +93,8 @@ public WebElement getDeleteLinkInRow(int rowId) { return browser.driver.findElement(deleteLink); } + public String getEditLinkInRow(int rowId) { + By editLink = By.className("topic_edit" + rowId); + return browser.driver.findElement(editLink).getAttribute("href"); + } } diff --git a/src/test/java/teammates/test/pageobjects/StudentDiscussionBoardTopicEditPage.java b/src/test/java/teammates/test/pageobjects/StudentDiscussionBoardTopicEditPage.java new file mode 100644 index 0000000..a3707e3 --- /dev/null +++ b/src/test/java/teammates/test/pageobjects/StudentDiscussionBoardTopicEditPage.java @@ -0,0 +1,65 @@ +package teammates.test.pageobjects; + +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +public class StudentDiscussionBoardTopicEditPage extends AppPage { + + @FindBy(id = "btnEditTopic") + private WebElement editTopicButton; + + @FindBy(id = "topicname") + private WebElement topicNameTextBox; + + @FindBy(id = "topicdesc") + private WebElement topicDescTextBox; + + @FindBy(id = "btnSaveTopic") + private WebElement saveTopicButton; + + @FindBy(id = "btnDeleteTopic") + private WebElement deleteTopicButton; + + @FindBy(className = "modal-btn-ok") + private WebElement confirmDeleteButton; + + @FindBy(className = "modal-btn-cancel") + private WebElement cancelDeleteButton; + + public StudentDiscussionBoardTopicEditPage(Browser browser) { + super(browser); + } + + @Override + public boolean containsExpectedPageContents() { + return getPageSource().contains("

Edit Topic

"); + } + + public boolean containsExpectedTopic(String topicName, String topicDesc) { + return getPageSource().contains(topicName) && getPageSource().contains(topicDesc); + } + + public StudentDiscussionBoardTopicEditPage editTopic(String topicName, String topicDesc) { + click(editTopicButton); + waitForPageToLoad(); + fillTextBox(topicNameTextBox, topicName); + fillTextBox(topicDescTextBox, topicDesc); + click(saveTopicButton); + return this; + } + + public StudentDiscussionBoardTopicEditPage cancelDeleteTopic() { + click(deleteTopicButton); + waitForPageToLoad(); + click(cancelDeleteButton); + return this; + } + + public StudentDiscussionBoardTopicEditPage deleteTopic() { + click(deleteTopicButton); + waitForPageToLoad(); + click(confirmDeleteButton); + return this; + } + +} diff --git a/src/test/java/teammates/test/pageobjects/StudentRepliesBoardEditPage.java b/src/test/java/teammates/test/pageobjects/StudentRepliesBoardEditPage.java new file mode 100644 index 0000000..4dcec50 --- /dev/null +++ b/src/test/java/teammates/test/pageobjects/StudentRepliesBoardEditPage.java @@ -0,0 +1,57 @@ +package teammates.test.pageobjects; + +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +public class StudentRepliesBoardEditPage extends AppPage { + + @FindBy(id = "replyDesc") + private WebElement replyDescTextBox; + + @FindBy(id = "btnEditReply") + private WebElement editButton; + + @FindBy(id = "btnDeleteReply") + private WebElement deleteButton; + + @FindBy(id = "btnSaveReply") + private WebElement saveButton; + + @FindBy(className = "modal-btn-ok") + private WebElement confirmDeleteButton; + + @FindBy(className = "modal-btn-cancel") + private WebElement cancelDeleteButton; + + public StudentRepliesBoardEditPage(Browser browser) { + super(browser); + } + + @Override + public boolean containsExpectedPageContents() { + return getPageSource().contains("

Edit Reply

"); + } + + public StudentRepliesBoardEditPage editReply(String newReplyDesc) { + click(editButton); + waitForPageToLoad(); + fillTextBox(replyDescTextBox, newReplyDesc); + click(saveButton); + return this; + } + + public StudentRepliesBoardEditPage cancelDeleteReply() { + click(deleteButton); + waitForPageToLoad(); + click(cancelDeleteButton); + return this; + } + + public StudentRepliesBoardEditPage deleteReply() { + click(deleteButton); + waitForPageToLoad(); + click(confirmDeleteButton); + return this; + } + +} diff --git a/src/test/java/teammates/test/pageobjects/StudentRepliesBoardPage.java b/src/test/java/teammates/test/pageobjects/StudentRepliesBoardPage.java new file mode 100644 index 0000000..03ebce0 --- /dev/null +++ b/src/test/java/teammates/test/pageobjects/StudentRepliesBoardPage.java @@ -0,0 +1,93 @@ +package teammates.test.pageobjects; + +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +public class StudentRepliesBoardPage extends AppPage { + + @FindBy(id = "replyDesc") + private WebElement replyDescTextBox; + + @FindBy(id = "btnAddReply") + private WebElement submitButton; + + @FindBy(className = "label-success") + private WebElement likes; + + @FindBy(className = "upvote") + private WebElement likeButton; + + @FindBy(className = "label-danger") + private WebElement dislikes; + + @FindBy(className = "downvote") + private WebElement dislikeButton; + + @FindBy(className = "reply_delete") + private WebElement deleteButton; + + @FindBy(className = "modal-btn-cancel") + private WebElement cancelDeleteButton; + + @FindBy(className = "modal-btn-ok") + private WebElement confirmDeleteButton; + + public StudentRepliesBoardPage(Browser browser) { + super(browser); + } + + @Override + public boolean containsExpectedPageContents() { + return getPageSource().contains("

Replies Board

"); + } + + public boolean containsExpectedTopic(String topicName, String topicDesc) { + return getPageSource().contains(topicName) && getPageSource().contains(topicDesc); + } + + public boolean containsExpectedReply(String creator, String replyDesc) { + return getPageSource().contains(creator) && getPageSource().contains(replyDesc); + } + + public StudentRepliesBoardPage addReply(String replyDesc) { + fillTextBox(replyDescTextBox, replyDesc); + click(submitButton); + waitForPageToLoad(); + return this; + } + + public boolean likeReply(String replyDesc) { + // Record the likes before clicking the like button + int l1 = Integer.parseInt(likes.getText().split(" ")[0]); + click(likeButton); + // Record the likes after clicking the like button + int l2 = Integer.parseInt(likes.getText().split(" ")[0]); + return l2 == l1 + 1 ? true : false; + } + + public boolean dislikeReply(String replyDesc) { + // Record the dislikes before clicking the dislike button + int d1 = Integer.parseInt(dislikes.getText().split(" ")[0]); + click(dislikeButton); + // Record the dislikes after clicking the dislike button + int d2 = Integer.parseInt(dislikes.getText().split(" ")[0]); + return d2 == d1 + 1 ? true : false; + + } + + public StudentRepliesBoardPage cancelDeleteReply(String replyDesc) { + click(deleteButton); + waitForPageToLoad(); + click(cancelDeleteButton); + waitForPageToLoad(); + return this; + } + + public StudentRepliesBoardPage deleteReply(String replyDesc) { + click(deleteButton); + waitForPageToLoad(); + click(confirmDeleteButton); + waitForPageToLoad(); + return this; + } +} diff --git a/src/test/resources/data/StudentDiscussionBoardTopicEditPageUiTest.json b/src/test/resources/data/StudentDiscussionBoardTopicEditPageUiTest.json new file mode 100644 index 0000000..1bbcb28 --- /dev/null +++ b/src/test/resources/data/StudentDiscussionBoardTopicEditPageUiTest.json @@ -0,0 +1,12 @@ +{ + "accounts": { + "studentWithEmptyProfile": { + "googleId": "SHomeUiT.benny.c", + "name": "Benny Charles", + "isInstructor": false, + "email": "SHomeUiT.benny.c@gmail.tmt", + "institute": "TEAMMATES Test Institute 1" + } + }, + "topics": {} +} diff --git a/src/test/resources/data/StudentRepliesBoardPageUiTest.json b/src/test/resources/data/StudentRepliesBoardPageUiTest.json new file mode 100644 index 0000000..1bbcb28 --- /dev/null +++ b/src/test/resources/data/StudentRepliesBoardPageUiTest.json @@ -0,0 +1,12 @@ +{ + "accounts": { + "studentWithEmptyProfile": { + "googleId": "SHomeUiT.benny.c", + "name": "Benny Charles", + "isInstructor": false, + "email": "SHomeUiT.benny.c@gmail.tmt", + "institute": "TEAMMATES Test Institute 1" + } + }, + "topics": {} +}