@Override
  public void testNewQuestionFrame() {
    ______TS("RUBRIC: new question (frame) link");

    feedbackEditPage.clickNewQuestionButton();
    feedbackEditPage.selectNewQuestionType("RUBRIC");
    assertTrue(feedbackEditPage.verifyNewRubricQuestionFormIsDisplayed());
  }
  @Override
  public void testNewQuestionFrame() {
    ______TS("NUMSCALE: new question (frame) link");

    feedbackEditPage.clickNewQuestionButton();
    feedbackEditPage.selectNewQuestionType("NUMSCALE");

    assertTrue(feedbackEditPage.verifyNewNumScaleQuestionFormIsDisplayed());
  }
  @Override
  public void testAddQuestionAction() throws Exception {
    ______TS("NUMSCALE: add question action success");

    assertNull(BackDoor.getFeedbackQuestion(courseId, feedbackSessionName, 1));
    feedbackEditPage.enableOtherFeedbackPathOptionsForNewQuestion();
    feedbackEditPage.selectRecipientsToBeStudents();
    feedbackEditPage.clickAddQuestionButton();
    feedbackEditPage.verifyStatus(Const.StatusMessages.FEEDBACK_QUESTION_ADDED);
    assertNotNull(BackDoor.getFeedbackQuestion(courseId, feedbackSessionName, 1));
    feedbackEditPage.verifyHtmlMainContent("/instructorFeedbackNumScaleQuestionAddSuccess.html");
  }
  @Override
  public void testDeleteQuestionAction() {
    ______TS("NUMSCALE: qn delete then cancel");

    feedbackEditPage.clickDeleteQuestionLink(1);
    feedbackEditPage.waitForConfirmationModalAndClickCancel();
    assertNotNull(BackDoor.getFeedbackQuestion(courseId, feedbackSessionName, 1));

    ______TS("NUMSCALE: qn delete then accept");

    feedbackEditPage.clickDeleteQuestionLink(1);
    feedbackEditPage.waitForConfirmationModalAndClickOk();
    feedbackEditPage.verifyStatus(Const.StatusMessages.FEEDBACK_QUESTION_DELETED);
    assertNull(BackDoor.getFeedbackQuestion(courseId, feedbackSessionName, 1));
  }
 private void fillNumScaleBoxWithRecheck(
     boolean isMinScaleBox, int scale, int qnNumber, String expected) {
   int counter = 0;
   while (counter != 100) {
     if (isMinScaleBox) {
       feedbackEditPage.fillMinNumScaleBox(scale, qnNumber);
     } else {
       feedbackEditPage.fillMaxNumScaleBox(scale, qnNumber);
     }
     if (expected.equals(feedbackEditPage.getMaxNumScaleBox(qnNumber))) {
       return;
     }
     counter++;
     browser.driver.switchTo().window("");
   }
   assertEquals(expected, feedbackEditPage.getMaxNumScaleBox(qnNumber));
 }
  @Override
  public void testEditQuestionAction() throws Exception {
    ______TS("NUMSCALE: edit question success");

    feedbackEditPage.clickEditQuestionButton(1);
    feedbackEditPage.fillEditQuestionBox("edited numscale qn text", 1);
    feedbackEditPage.fillEditQuestionDescription("more details", 1);
    feedbackEditPage.fillMinNumScaleBox(3, 1);
    feedbackEditPage.fillMaxNumScaleBox(4, 1);
    feedbackEditPage.fillStepNumScaleBox(0.002, 1);
    assertEquals(
        "[Based on the above settings, acceptable responses are: 3, 3.002, 3.004, ..., 3.996, 3.998, 4]",
        feedbackEditPage.getNumScalePossibleValuesString(1));
    feedbackEditPage.clickSaveExistingQuestionButton(1);
    feedbackEditPage.verifyStatus(Const.StatusMessages.FEEDBACK_QUESTION_EDITED);

    feedbackEditPage.verifyHtmlMainContent("/instructorFeedbackNumScaleQuestionEditSuccess.html");
  }
  @Override
  public void testAddQuestionAction() throws Exception {
    ______TS("RUBRIC: add question action success");

    feedbackEditPage.clickNewQuestionButton();
    feedbackEditPage.selectNewQuestionType("RUBRIC");
    feedbackEditPage.fillNewQuestionBox("RUBRIC qn");
    feedbackEditPage.fillNewQuestionDescription("more details");
    assertNull(BackDoor.getFeedbackQuestion(courseId, feedbackSessionName, 1));
    feedbackEditPage.clickAddQuestionButton();
    feedbackEditPage.verifyStatus(Const.StatusMessages.FEEDBACK_QUESTION_ADDED);
    assertNotNull(BackDoor.getFeedbackQuestion(courseId, feedbackSessionName, 1));
    feedbackEditPage.verifyHtmlMainContent("/instructorFeedbackRubricQuestionAddSuccess.html");
  }
  @Override
  public void testInputValidation() {

    ______TS("empty question text");

    feedbackEditPage.clickAddQuestionButton();
    feedbackEditPage.verifyStatus(Const.StatusMessages.FEEDBACK_QUESTION_TEXTINVALID);

    ______TS("empty weight test");

    feedbackEditPage.fillNewQuestionBox("empty weight test");
    feedbackEditPage.fillNewQuestionDescription("more details");
    feedbackEditPage.clickAssignWeightsCheckbox(-1);
    feedbackEditPage.fillRubricWeightBox("", -1, 3);
    feedbackEditPage.clickAddQuestionButton();

    feedbackEditPage.verifyStatus(Const.FeedbackQuestion.RUBRIC_ERROR_INVALID_WEIGHT);
  }
  @Override
  public void testInputValidation() {

    ______TS("empty options");

    feedbackEditPage.fillNewQuestionBox("NumScale qn");
    feedbackEditPage.fillNewQuestionDescription("more details");
    feedbackEditPage.fillMinNumScaleBox("", -1);
    feedbackEditPage.fillStepNumScaleBox("", -1);
    feedbackEditPage.fillMaxNumScaleBox("", -1);

    assertEquals(
        "[Please enter valid numbers for all the options.]",
        feedbackEditPage.getNumScalePossibleValuesString(-1));

    feedbackEditPage.clickAddQuestionButton();

    feedbackEditPage.verifyStatus("Please enter valid options. The min/max/step cannot be empty.");

    ______TS("invalid options");

    feedbackEditPage.fillNewQuestionBox("NumScale qn");
    feedbackEditPage.fillNewQuestionDescription("more details");
    feedbackEditPage.fillMinNumScaleBox("1", -1);
    feedbackEditPage.fillStepNumScaleBox("0.3", -1);
    feedbackEditPage.fillMaxNumScaleBox("5", -1);

    assertEquals(
        "[The interval 1 - 5 is not divisible by the specified increment.]",
        feedbackEditPage.getNumScalePossibleValuesString(-1));

    feedbackEditPage.clickAddQuestionButton();

    feedbackEditPage.verifyStatus(
        "Please enter valid options. "
            + "The interval is not divisible by the specified increment.");

    ______TS("possible floating point error");

    feedbackEditPage.fillNewQuestionBox("NumScale qn");
    feedbackEditPage.fillNewQuestionDescription("more details");
    feedbackEditPage.fillMinNumScaleBox("1", -1);
    feedbackEditPage.fillStepNumScaleBox("0.001", -1);
    feedbackEditPage.fillMaxNumScaleBox("5555", -1);

    assertEquals(
        "[Based on the above settings, acceptable responses are: 1, 1.001, 1.002, ..., "
            + "5554.998, 5554.999, 5555]",
        feedbackEditPage.getNumScalePossibleValuesString(-1));

    ______TS("more than three dp step rounding test");

    feedbackEditPage.fillMaxNumScaleBox("1002", -1);
    feedbackEditPage.fillStepNumScaleBox("1.00123456789", -1);

    assertEquals(
        "[Based on the above settings, acceptable responses are: 1, 2.001, 3.002, ..., "
            + "999.998, 1000.999, 1002]",
        feedbackEditPage.getNumScalePossibleValuesString(-1));

    ______TS("NUMSCALE: min >= max test");
    // Tests javascript that automatically makes max = min+1 when max is <= min.
    feedbackEditPage.fillMinNumScaleBox(1, -1);
    feedbackEditPage.fillStepNumScaleBox(1, -1);
    feedbackEditPage.fillMaxNumScaleBox(5, -1);
    assertEquals(
        "[Based on the above settings, acceptable responses are: 1, 2, 3, 4, 5]",
        feedbackEditPage.getNumScalePossibleValuesString(-1));

    fillNumScaleBoxWithRecheck(true, 6, -1, "7");
    fillNumScaleBoxWithRecheck(false, 6, -1, "7");

    // Reset values
    feedbackEditPage.fillMinNumScaleBox(1, -1);
    feedbackEditPage.fillMaxNumScaleBox(5, -1);
  }
 @Override
 public void testCustomizeOptions() {
   feedbackEditPage.fillNewQuestionBox("NumScale qn");
   feedbackEditPage.fillNewQuestionDescription("more details");
   assertEquals(
       "[Based on the above settings, acceptable responses are: 1, 2, 3, 4, 5]",
       feedbackEditPage.getNumScalePossibleValuesString(-1));
   feedbackEditPage.fillStepNumScaleBox(0.3, -1);
   assertEquals(
       "[The interval 1 - 5 is not divisible by the specified increment.]",
       feedbackEditPage.getNumScalePossibleValuesString(-1));
   feedbackEditPage.fillMinNumScaleBox(5, -1);
   feedbackEditPage.fillMaxNumScaleBox(6, -1);
   feedbackEditPage.fillStepNumScaleBox(0.001, -1);
   assertEquals(
       "[Based on the above settings, acceptable responses are: 5, 5.001, 5.002, ..., 5.998, 5.999, 6]",
       feedbackEditPage.getNumScalePossibleValuesString(-1));
   feedbackEditPage.fillMinNumScaleBox(0, -1);
   feedbackEditPage.fillMaxNumScaleBox(1, -1);
   feedbackEditPage.fillStepNumScaleBox(0.1, -1);
   assertEquals(
       "[Based on the above settings, acceptable responses are: 0, 0.1, 0.2, ..., 0.8, 0.9, 1]",
       feedbackEditPage.getNumScalePossibleValuesString(-1));
 }
  @SuppressWarnings("deprecation")
  private void testCreateInstructorAction() throws Exception {

    InstructorAttributes instructor = new InstructorAttributes();

    String shortName = "Instrúctör";
    instructor.name = "AHPUiT Instrúctör";
    instructor.email = "*****@*****.**";
    String institute = "TEAMMATES Test Institute 1";
    String demoCourseId = "AHPUiT.instr1.gma-demo";

    ______TS(
        "action success : create instructor account and the account is created successfully after user's verification");

    BackDoor.deleteAccount(TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT);
    BackDoor.deleteCourse(demoCourseId);
    BackDoor.deleteInstructor(demoCourseId, instructor.email);

    homePage.createInstructor(shortName, instructor, institute);

    String expectedjoinUrl = Config.APP_URL + Const.ActionURIs.INSTRUCTOR_COURSE_JOIN;

    expectedjoinUrl =
        Url.addParamToUrl(
            expectedjoinUrl,
            Const.ParamsNames.REGKEY,
            StringHelper.encrypt(BackDoor.getKeyForInstructor(demoCourseId, instructor.email)));

    expectedjoinUrl =
        Url.addParamToUrl(expectedjoinUrl, Const.ParamsNames.INSTRUCTOR_INSTITUTION, institute);

    homePage
        .getStatus()
        .contains(
            "Instructor AHPUiT Instrúctör has been successfully created with join link:\n"
                + expectedjoinUrl);
    homePage.logout();
    // verify the instructor and the demo course have been created
    assertNotNull(BackDoor.getCourse(demoCourseId));
    assertNotNull(BackDoor.getInstructorByEmail(instructor.email, demoCourseId));

    // get the joinURL which sent to the requester's email
    String joinActionUrl =
        TestProperties.inst().TEAMMATES_URL + Const.ActionURIs.INSTRUCTOR_COURSE_JOIN;

    String joinLink =
        Url.addParamToUrl(
            joinActionUrl,
            Const.ParamsNames.REGKEY,
            StringHelper.encrypt(BackDoor.getKeyForInstructor(demoCourseId, instructor.email)));

    joinLink = Url.addParamToUrl(joinLink, Const.ParamsNames.INSTRUCTOR_INSTITUTION, institute);

    // simulate the user's verification here because it is added by admin
    browser.driver.get(joinLink);
    confirmationPage =
        createCorrectLoginPageType(browser.driver.getPageSource())
            .loginAsJoiningInstructor(
                TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT,
                TestProperties.inst().TEST_INSTRUCTOR_PASSWORD);
    confirmationPage.clickCancelButton();

    browser.driver.get(joinLink);
    confirmationPage =
        createCorrectLoginPageType(browser.driver.getPageSource())
            .loginAsJoiningInstructor(
                TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT,
                TestProperties.inst().TEST_INSTRUCTOR_PASSWORD);
    confirmationPage.clickConfirmButton();

    // check a account has been created for the requester successfully
    assertNotNull(BackDoor.getAccount(TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT));

    // verify sample course is accessible for newly joined instructor as an instructor

    ______TS("new instructor can see sample course in homepage");
    InstructorHomePage instructorHomePage =
        AppPage.getNewPageInstance(browser, InstructorHomePage.class);
    instructorHomePage.verifyHtmlMainContent("/newlyJoinedInstructorHomePage.html");

    ______TS("new instructor can access sample coure enroll page");
    InstructorCourseEnrollPage enrollPage = instructorHomePage.clickCourseErollLink(demoCourseId);
    enrollPage.verifyHtmlMainContent("/newlyJoinedInstructorCourseEnrollPage.html");

    ______TS("new instructor can access sample coure details page");
    instructorHomePage = enrollPage.goToPreviousPage(InstructorHomePage.class);
    InstructorCourseDetailsPage detailsPage = instructorHomePage.clickCourseViewLink(demoCourseId);
    detailsPage.verifyHtmlMainContent("/newlyJoinedInstructorCourseDetailsPage.html");

    ______TS("new instructor can access sample coure edit page");
    instructorHomePage = detailsPage.goToPreviousPage(InstructorHomePage.class);
    InstructorCourseEditPage editPage = instructorHomePage.clickCourseEditLink(demoCourseId);
    editPage.verifyHtmlMainContent("/newlyJoinedInstructorCourseEditPage.html");

    ______TS("new instructor can access sample coure feedback session adding page");
    instructorHomePage = editPage.goToPreviousPage(InstructorHomePage.class);
    InstructorFeedbacksPage feedbacksPage =
        instructorHomePage.clickCourseAddEvaluationLink(demoCourseId);
    feedbacksPage.verifyHtmlMainContent("/newlyJoinedInstructorFeedbacksPage.html");

    ______TS("new instructor can archive sample course");
    instructorHomePage = feedbacksPage.goToPreviousPage(InstructorHomePage.class);
    instructorHomePage.clickArchiveCourseLinkAndConfirm(demoCourseId);
    instructorHomePage.verifyHtmlMainContent(
        "/newlyJoinedInstructorHomePageSampleCourseArchived.html");

    ______TS("new instructor can unarchive sample course");
    String url =
        Url.addParamToUrl(
            TestProperties.inst().TEAMMATES_URL + Const.ActionURIs.INSTRUCTOR_COURSES_PAGE,
            Const.ParamsNames.USER_ID,
            TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT);
    browser.driver.get(url);
    InstructorCoursesPage coursesPage =
        AppPage.getNewPageInstance(browser, InstructorCoursesPage.class);
    coursesPage.unarchiveCourse(demoCourseId);
    coursesPage.verifyHtmlMainContent(
        "/newlyJoinedInstructorCoursesPageSampleCourseUnarhived.html");

    ______TS("new instructor can access sample course students page");
    coursesPage
        .loadStudentsTab()
        .verifyHtmlMainContent("/newlyJoinedInstructorStudentListPage.html");
    ______TS("new instructor can access sample course comments page");
    coursesPage
        .loadInstructorCommentsTab()
        .verifyHtmlMainContent("/newlyJoinedInstructorCommentsPage.html");

    ______TS("new instructor can view feedbackSession result of sample course");
    coursesPage.loadInstructorHomeTab();
    instructorHomePage = AppPage.getNewPageInstance(browser, InstructorHomePage.class);
    instructorHomePage
        .clickFeedbackSessionViewResultsLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session")
        .verifyHtmlMainContent("/newlyJoinedInstructorFeedbackResultsPage.html");

    ______TS("new instructor can edit feedbackSession of sample course");
    instructorHomePage.loadInstructorHomeTab();
    InstructorFeedbackEditPage feedbackEditPage =
        instructorHomePage.clickFeedbackSessionEditLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session");

    feedbackEditPage.clickEditSessionButton();

    FeedbackSessionAttributes feedbackSession =
        BackDoor.getFeedbackSession("AHPUiT.instr1.gma-demo", "Second team feedback session");
    feedbackEditPage.editFeedbackSession(
        feedbackSession.startTime,
        feedbackSession.endTime,
        new Text("updated instructions"),
        feedbackSession.gracePeriod);
    instructorHomePage.verifyHtmlMainContent(
        "/newlyJoinedInstructorFeedbackSessionSuccessEdited.html");

    ______TS("new instructor can click submit button of sample feedbackSession");
    instructorHomePage.loadInstructorHomeTab();
    FeedbackSubmitPage fbsp =
        instructorHomePage.clickFeedbackSessionSubmitLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session");
    fbsp.verifyHtmlMainContent("/newlyJoinedInstructorFeedbackSubmissionEditPage.html");

    ______TS("new instructor can send reminder of sample course");
    instructorHomePage.loadInstructorHomeTab();
    feedbacksPage =
        instructorHomePage.clickFeedbackSessionRemindLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session");
    feedbacksPage.verifyHtmlMainContent("/newlyJoinedInstructorFeedbackSessionRemind.html");

    ______TS("new instructor can unpublish feedbackSession of sample course");
    instructorHomePage.loadInstructorHomeTab();
    feedbacksPage =
        instructorHomePage.clickFeedbackSessionUnpublishLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session");
    feedbacksPage.verifyHtmlMainContent("/newlyJoinedInstructorFeedbackSessionUnpublished.html");

    ______TS("new instructor can publish feedbackSession of sample course");
    instructorHomePage.loadInstructorHomeTab();
    feedbacksPage =
        instructorHomePage.clickFeedbackSessionPublishLink(
            "AHPUiT.instr1.gma-demo", "Second team feedback session");
    feedbacksPage.verifyHtmlMainContent("/newlyJoinedInstructorFeedbackSessionPublished.html");

    feedbacksPage.logout();

    ______TS("action failure : invalid parameter");

    Url homeUrl = createUrl(Const.ActionURIs.ADMIN_HOME_PAGE);
    homePage = loginAdminToPage(browser, homeUrl, AdminHomePage.class);

    instructor.email = "AHPUiT.email.tmt";
    homePage
        .createInstructor(shortName, instructor, institute)
        .verifyStatus(
            String.format(
                FieldValidator.EMAIL_ERROR_MESSAGE,
                instructor.email,
                FieldValidator.REASON_INCORRECT_FORMAT));

    ______TS("action success: course is accessible for newly joined instructor as student");
    // in staging server, the student account uses the hardcoded email above, so this can only be
    // test on dev server
    if (!TestProperties.inst().TEAMMATES_URL.contains("local")) {

      BackDoor.deleteCourse(demoCourseId);
      BackDoor.deleteAccount(TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT);
      BackDoor.deleteInstructor(demoCourseId, instructor.email);
      return;
    }

    // verify sample course is accessible for newly joined instructor as an student

    StudentHomePage studentHomePage =
        HomePage.getNewInstance(browser)
            .clickStudentLogin()
            .loginAsStudent(
                TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT,
                TestProperties.inst().TEST_INSTRUCTOR_PASSWORD);

    studentHomePage.verifyContains(demoCourseId);
    studentHomePage.clickViewTeam();

    StudentCourseDetailsPage courseDetailsPage =
        AppPage.getNewPageInstance(browser, StudentCourseDetailsPage.class);
    courseDetailsPage.verifyHtmlMainContent("/newlyJoinedInstructorStudentCourseDetailsPage.html");

    studentHomePage = courseDetailsPage.goToPreviousPage(StudentHomePage.class);
    studentHomePage.getViewFeedbackButton("First team feedback session").click();
    StudentFeedbackResultsPage sfrp =
        AppPage.getNewPageInstance(browser, StudentFeedbackResultsPage.class);
    sfrp.verifyHtmlMainContent("/newlyJoinedInstructorStudentFeedbackResultsPage.html");

    studentHomePage = sfrp.goToPreviousPage(StudentHomePage.class);
    studentHomePage.getEditFeedbackButton("First team feedback session").click();
    FeedbackSubmitPage fsp = AppPage.getNewPageInstance(browser, FeedbackSubmitPage.class);
    fsp.verifyHtmlMainContent("/newlyJoinedInstructorStudentFeedbackSubmissionEdit.html");

    studentHomePage = fsp.loadStudentHomeTab();
    StudentCommentsPage scp = studentHomePage.loadStudentCommentsTab();
    scp.verifyHtmlMainContent("/newlyJoinedInstructorStudentCommentsPage.html");

    studentHomePage = scp.loadStudentHomeTab();

    StudentProfilePage spp = studentHomePage.loadProfileTab();
    spp.verifyContains("Student Profile");
    spp.verifyContains("AHPUiT Instrúctör");

    studentHomePage.logout();

    // login in as instructor again to test sample course deletion
    instructorHomePage =
        HomePage.getNewInstance(browser)
            .clickInstructorLogin()
            .loginAsInstructor(
                TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT,
                TestProperties.inst().TEST_INSTRUCTOR_PASSWORD);

    instructorHomePage.clickAndConfirm(instructorHomePage.getDeleteCourseLink(demoCourseId));
    assertTrue(
        instructorHomePage
            .getStatus()
            .contains("The course " + demoCourseId + " has been deleted."));

    instructorHomePage.logout();

    BackDoor.deleteAccount(TestProperties.inst().TEST_INSTRUCTOR_ACCOUNT);
    BackDoor.deleteCourse(demoCourseId);
    BackDoor.deleteInstructor(demoCourseId, instructor.email);
  }
  private void testInputJsValidationForRubricQuestion() {
    // this tests whether the JS validation disallows empty rubric options

    ______TS("JS validation test");

    // add a new question
    feedbackEditPage.clickNewQuestionButton();
    feedbackEditPage.selectNewQuestionType("RUBRIC");

    // start editing it
    feedbackEditPage.fillNewQuestionBox("RUBRIC qn JS validation test");
    feedbackEditPage.fillNewQuestionDescription("more details");
    feedbackEditPage.clickAddQuestionButton();

    feedbackEditPage.clickEditQuestionButton(1);

    // try to remove everything
    feedbackEditPage.clickRemoveRubricRowLinkAndConfirm(1, 1);
    feedbackEditPage.clickRemoveRubricRowLinkAndConfirm(1, 0);
    feedbackEditPage.clickRemoveRubricColLinkAndConfirm(1, 3);
    feedbackEditPage.clickRemoveRubricColLinkAndConfirm(1, 2);
    feedbackEditPage.clickRemoveRubricColLinkAndConfirm(1, 1);
    feedbackEditPage.clickRemoveRubricColLinkAndConfirm(1, 0);

    // TODO check if the rubric column and link is indeed empty

    // add something so that we know that the elements are still there
    // and so that we don't get empty sub question error
    feedbackEditPage.fillRubricSubQuestionBox("New sub-question text", 1, 0);
    feedbackEditPage.fillRubricDescriptionBox("New(0) description", 1, 0, 0);

    feedbackEditPage.clickSaveExistingQuestionButton(1);

    feedbackEditPage.verifyStatus(
        "Too little choices for Rubric question. Minimum number of options is: 2");
  }
  @Override
  public void testEditQuestionAction() throws Exception {
    ______TS("RUBRIC: edit question success");

    // Click edit button
    feedbackEditPage.clickEditQuestionButton(1);

    // Check that fields are editable
    feedbackEditPage.verifyHtmlMainContent("/instructorFeedbackRubricQuestionEdit.html");

    feedbackEditPage.fillEditQuestionBox("edited RUBRIC qn text", 1);
    feedbackEditPage.fillEditQuestionDescription("more details", 1);
    feedbackEditPage.clickSaveExistingQuestionButton(1);
    feedbackEditPage.verifyStatus(Const.StatusMessages.FEEDBACK_QUESTION_EDITED);

    // Check question text is updated
    feedbackEditPage.verifyHtmlMainContent("/instructorFeedbackRubricQuestionEditSuccess.html");

    ______TS("RUBRIC: edit sub-questions success");
    feedbackEditPage.clickEditQuestionButton(1);

    // Edit sub-question for row 1
    feedbackEditPage.fillRubricSubQuestionBox("New(0) sub-question text", 1, 0);

    // Add new sub-question
    feedbackEditPage.clickAddRubricRowLink(1);
    feedbackEditPage.fillRubricSubQuestionBox("New(1) sub-question text", 1, 2);

    // Remove existing sub-questions
    feedbackEditPage.clickRemoveRubricRowLinkAndConfirm(1, 0);
    feedbackEditPage.clickRemoveRubricRowLinkAndConfirm(1, 1);

    // Add new sub-question
    feedbackEditPage.clickAddRubricRowLink(1);
    feedbackEditPage.fillRubricSubQuestionBox("New(2) sub-question text", 1, 3);

    // Remove new sub-question
    feedbackEditPage.clickRemoveRubricRowLinkAndConfirm(1, 2);

    // Should end up with 1 question

    feedbackEditPage.clickSaveExistingQuestionButton(1);
    feedbackEditPage.verifyHtmlMainContent(
        "/instructorFeedbackRubricQuestionEditSubQuestionSuccess.html");

    ______TS("RUBRIC: edit choices success");
    feedbackEditPage.clickEditQuestionButton(1);

    // Edit choice for col 1
    feedbackEditPage.fillRubricChoiceBox("New(0) choice", 1, 0);

    // Add new choice
    feedbackEditPage.clickAddRubricColLink(1);
    feedbackEditPage.fillRubricChoiceBox("New(1) choice", 1, 4);

    // Remove existing choice
    feedbackEditPage.clickRemoveRubricColLinkAndConfirm(1, 0);

    // Add new choice
    feedbackEditPage.clickAddRubricColLink(1);
    feedbackEditPage.fillRubricChoiceBox("New(2) choice", 1, 5);

    // Remove new choice
    feedbackEditPage.clickRemoveRubricColLinkAndConfirm(1, 4);

    // Should end up with 4 choices, including (1) and (2)

    feedbackEditPage.clickSaveExistingQuestionButton(1);
    feedbackEditPage.verifyHtmlMainContent(
        "/instructorFeedbackRubricQuestionEditChoiceSuccess.html");

    ______TS("RUBRIC: edit weight success");
    feedbackEditPage.clickEditQuestionButton(1);

    // Edit the weight of the first choice
    feedbackEditPage.clickAssignWeightsCheckbox(1);
    feedbackEditPage.fillRubricWeightBox("2.25", 1, 0);

    feedbackEditPage.clickSaveExistingQuestionButton(1);
    feedbackEditPage.verifyHtmlMainContent(
        "/instructorFeedbackRubricQuestionEditWeightSuccess.html");

    ______TS("RUBRIC: edit descriptions success");
    feedbackEditPage.clickEditQuestionButton(1);

    // Edit description for 0-0
    feedbackEditPage.fillRubricDescriptionBox("New(0) description", 1, 0, 0);

    // Edit description for a new row, to test if the js generated html works.
    feedbackEditPage.clickAddRubricRowLink(1);
    feedbackEditPage.fillRubricSubQuestionBox("New sub-question text", 1, 1);

    feedbackEditPage.fillRubricDescriptionBox("New(1) description", 1, 1, 0);

    // Should end up with 2 rubric descriptions, (0) and (1)

    feedbackEditPage.clickSaveExistingQuestionButton(1);

    feedbackEditPage.verifyHtmlMainContent(
        "/instructorFeedbackRubricQuestionEditDescriptionSuccess.html");
  }
  @Test
  public void allTests() throws Exception {
    feedbackEditPage = getFeedbackEditPage();

    ______TS("Submit empty course list");
    feedbackEditPage.clickFsCopyButton();
    feedbackEditPage.getFsCopyToModal().waitForModalToLoad();

    // Full HTML verification already done in InstructorFeedbackEditPageUiTest
    feedbackEditPage.verifyHtmlMainContent("/instructorFeedbackEditCopyPage.html");

    feedbackEditPage.getFsCopyToModal().clickSubmitButton();
    feedbackEditPage.getFsCopyToModal().waitForFormSubmissionErrorMessagePresence();
    assertTrue(feedbackEditPage.getFsCopyToModal().isFormSubmissionStatusMessageVisible());
    feedbackEditPage
        .getFsCopyToModal()
        .verifyStatusMessage(Const.StatusMessages.FEEDBACK_SESSION_COPY_NONESELECTED);

    feedbackEditPage.getFsCopyToModal().clickCloseButton();

    ______TS("Copying fails due to fs with same name in course selected");
    feedbackEditPage.clickFsCopyButton();
    feedbackEditPage.getFsCopyToModal().waitForModalToLoad();
    feedbackEditPage.getFsCopyToModal().fillFormWithAllCoursesSelected(feedbackSessionName);

    feedbackEditPage.getFsCopyToModal().clickSubmitButton();
    feedbackEditPage.getFsCopyToModal().waitForFormSubmissionErrorMessagePresence();
    assertTrue(feedbackEditPage.getFsCopyToModal().isFormSubmissionStatusMessageVisible());

    feedbackEditPage
        .getFsCopyToModal()
        .verifyStatusMessage(
            String.format(
                Const.StatusMessages.FEEDBACK_SESSION_COPY_ALREADYEXISTS,
                feedbackSessionName,
                testData.courses.get("course").getId()));

    // Full HTML verification already done in InstructorFeedbackEditPageUiTest
    feedbackEditPage.verifyHtmlMainContent("/instructorFeedbackEditCopyFail.html");

    feedbackEditPage.getFsCopyToModal().clickCloseButton();

    ______TS("Copying fails due to fs with invalid name");
    feedbackEditPage.clickFsCopyButton();
    feedbackEditPage.getFsCopyToModal().waitForModalToLoad();
    feedbackEditPage
        .getFsCopyToModal()
        .fillFormWithAllCoursesSelected("Invalid name | for feedback session");

    feedbackEditPage.getFsCopyToModal().clickSubmitButton();

    feedbackEditPage.getFsCopyToModal().waitForFormSubmissionErrorMessagePresence();
    assertTrue(feedbackEditPage.getFsCopyToModal().isFormSubmissionStatusMessageVisible());
    feedbackEditPage
        .getFsCopyToModal()
        .verifyStatusMessage(
            "\"Invalid name | for feedback session\" is not acceptable to TEAMMATES as "
                + "feedback session name because it contains invalid characters. "
                + "All feedback session name must start with an alphanumeric character, "
                + "and cannot contain any vertical bar (|) or percent sign (%).");

    feedbackEditPage.getFsCopyToModal().clickCloseButton();

    ______TS("Successful case");
    feedbackEditPage.clickFsCopyButton();
    feedbackEditPage.getFsCopyToModal().waitForModalToLoad();
    feedbackEditPage.getFsCopyToModal().fillFormWithAllCoursesSelected("New name!");

    feedbackEditPage.getFsCopyToModal().clickSubmitButton();
    feedbackEditPage.waitForPageToLoad();

    feedbackEditPage.verifyStatus(Const.StatusMessages.FEEDBACK_SESSION_COPIED);
    feedbackEditPage.waitForElementPresence(By.id("table-sessions"));

    // Full HTML verification already done in InstructorFeedbackEditPageUiTest
    feedbackEditPage.verifyHtmlMainContent("/instructorFeedbackEditCopySuccess.html");
  }