From f0174c5125d57d8d17a2a3bf847d07055b522714 Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Fri, 3 Nov 2017 20:47:36 +0100 Subject: [PATCH] no-jira: add 2 seleniums test for the numerical input editor --- .../FIBNumericalEntrySettingsController.java | 6 + .../java/org/olat/selenium/ImsQTI21Test.java | 345 +++++++++++++++++- .../selenium/page/qti/QTI21EditorPage.java | 5 + .../page/qti/QTI21GapEntriesEditorPage.java | 83 +++++ 4 files changed, 438 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBNumericalEntrySettingsController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBNumericalEntrySettingsController.java index 4b338911918..96f165f1e2d 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBNumericalEntrySettingsController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBNumericalEntrySettingsController.java @@ -78,9 +78,12 @@ public class FIBNumericalEntrySettingsController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + formLayout.setElementCssClass("o_sel_gap_numeric_form"); + Double solution = interaction.getSolution(); String solString = solution == null ? "" : solution.toString(); solutionEl = uifactory.addTextElement("fib.solution", "fib.solution", 256, solString, formLayout); + solutionEl.setElementCssClass("o_sel_gap_numeric_solution"); solutionEl.setEnabled(!restrictedEdit); if(!restrictedEdit && !StringHelper.containsNonWhitespace(solString)) { solutionEl.setFocus(true); @@ -88,6 +91,7 @@ public class FIBNumericalEntrySettingsController extends FormBasicController { String placeholder = interaction.getPlaceholder(); placeholderEl = uifactory.addTextElement("fib.placeholder", "fib.placeholder", 256, placeholder, formLayout); + placeholderEl.setElementCssClass("o_sel_gap_numeric_placeholder"); placeholderEl.setEnabled(!restrictedEdit); Integer expectedLength = interaction.getExpectedLength(); @@ -131,6 +135,7 @@ public class FIBNumericalEntrySettingsController extends FormBasicController { } lowerToleranceEl = uifactory.addTextElement("fib.tolerance.low", "fib.tolerance.low", 8, lowerToleranceString, formLayout); lowerToleranceEl.setExampleKey("fib.tolerance.mode.absolute.example", null); + lowerToleranceEl.setElementCssClass("o_sel_gap_numeric_lower_bound"); lowerToleranceEl.setEnabled(!restrictedEdit); Double upperTolerance = interaction.getUpperTolerance(); @@ -150,6 +155,7 @@ public class FIBNumericalEntrySettingsController extends FormBasicController { } upperToleranceEl = uifactory.addTextElement("fib.tolerance.up", "fib.tolerance.up", 8, upperToleranceString, formLayout); upperToleranceEl.setExampleKey("fib.tolerance.mode.absolute.example", null); + upperToleranceEl.setElementCssClass("o_sel_gap_numeric_upper_bound"); upperToleranceEl.setEnabled(!restrictedEdit); updateToleranceUpAndLow(); diff --git a/src/test/java/org/olat/selenium/ImsQTI21Test.java b/src/test/java/org/olat/selenium/ImsQTI21Test.java index 3755cdfca5a..81c6773ce83 100644 --- a/src/test/java/org/olat/selenium/ImsQTI21Test.java +++ b/src/test/java/org/olat/selenium/ImsQTI21Test.java @@ -65,6 +65,7 @@ import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.ToleranceMode; import uk.ac.ed.ph.jqtiplus.value.Cardinality; /** @@ -1969,7 +1970,7 @@ public class ImsQTI21Test { UserVO rei = new UserRestClient(deploymentUrl).createRandomUser("Rei"); authorLoginPage.loginAs(author.getLogin(), author.getPassword()); - String qtiTestTitle = "Hotspot QTI 2.1 " + UUID.randomUUID(); + String qtiTestTitle = "FIB QTI 2.1 " + UUID.randomUUID(); navBar .openAuthoringEnvironment() .createQTI21Test(qtiTestTitle) @@ -2117,6 +2118,348 @@ public class ImsQTI21Test { .assertOnAssessmentTestScore(6);// 2 points from the first question, 4 from the second } + + /** + * An author make a test with 2 questions using numerical input, + * the first with the score set if all answers are correct, the second + * with scoring per answers. The numerical input have all the tolerance + * mode set to EXACT.<br> + * A first user make the test, but doesn't answer all questions + * correctly, log out and a second user make the perfect test. + * + * @param authorLoginPage + * @param participantBrowser + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void qti21EditorNumericalInput_exact(@InitialPage LoginPage authorLoginPage, + @Drone @User WebDriver participantBrowser) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO ryomou = new UserRestClient(deploymentUrl).createRandomUser("Ryomou"); + UserVO rei = new UserRestClient(deploymentUrl).createRandomUser("Rei"); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + String qtiTestTitle = "Numerical QTI 2.1 " + UUID.randomUUID(); + navBar + .openAuthoringEnvironment() + .createQTI21Test(qtiTestTitle) + .clickToolbarBack(); + + QTI21Page qtiPage = QTI21Page + .getQTI12Page(browser); + QTI21EditorPage qtiEditor = qtiPage + .edit(); + //start a blank test + qtiEditor + .selectNode("Single choice") + .deleteNode(); + + //add a numerical input: all answers score, tolerance exact + QTI21GapEntriesEditorPage fibEditor = qtiEditor + .addNumerical() + .appendContent("One plus two: ") + .addNumericalInput("3", "three", ToleranceMode.EXACT, null, null) + .saveNumericInput() + .editNumericalInput("9", "nine", ToleranceMode.EXACT, null, null, 2) + .saveNumericInput() + .save(); + //set max score + fibEditor + .selectScores() + .selectAssessmentMode(ScoreEvaluation.allCorrectAnswers) + .setMaxScore("2") + .save(); + // set feedbacks + fibEditor + .selectFeedbacks() + .setHint("Hint", "The second is the first power two") + .setCorrectSolution("Correct solution", "I know you know") + .setCorrectFeedback("Correct feedback", "Your answer is correct") + .setIncorrectFeedback("Incorrect", "Your answer is not correct") + .save(); + + //add a gap entry: score per answer, tolerance exact + fibEditor = qtiEditor + .addNumerical() + .appendContent("More difficult: 34 + 23 ") + .addNumericalInput("57", "57", ToleranceMode.EXACT, null, null) + .saveNumericInput() + .editNumericalInput("8", "64squareroot",ToleranceMode.EXACT, null, null, 2) + .saveNumericInput() + .save(); + //set max score + fibEditor + .selectScores() + .selectAssessmentMode(ScoreEvaluation.perAnswer) + .setMaxScore("4") + .setScore("57", "2") + .setScore("8", "3") + .save(); + // set feedbacks + fibEditor + .selectFeedbacks() + .setHint("Hint", "The second is the square root of 64") + .setCorrectSolution("Correct solution", "This is an information about the correct solution") + .setCorrectFeedback("Correct feedback", "Your answer is correct") + .setIncorrectFeedback("Incorrect", "Your answer is not correct") + .save(); + + qtiPage + .clickToolbarBack(); + // access to all + qtiPage + .accessConfiguration() + .setUserAccess(UserAccess.guest) + .clickToolbarBack(); + // show results + qtiPage + .options() + .showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions()) + .save(); + + //a user search the content package + LoginPage userLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + userLoginPage + .loginAs(ryomou.getLogin(), ryomou.getPassword()) + .resume(); + NavigationPage userNavBar = new NavigationPage(participantBrowser); + userNavBar + .openMyCourses() + .openSearch() + .extendedSearch(qtiTestTitle) + .select(qtiTestTitle) + .start(); + + // first user make the test + QTI21Page ryomouQtiPage = QTI21Page + .getQTI12Page(participantBrowser); + ryomouQtiPage + .assertOnAssessmentItem() + .answerGapTextWithPlaceholder("2", "three") + .answerGapTextWithPlaceholder("25", "nine") + .saveAnswer() + .assertFeedback("Incorrect") + .assertCorrectSolution("Correct solution") + .hint() + .assertFeedback("Hint") + .answerGapTextWithPlaceholder("3", "three") + .answerGapTextWithPlaceholder("9", "nine") + .saveAnswer() + .assertFeedback("Correct feedback") + .nextAnswer() + .answerGapTextWithPlaceholder("57", "57") + .answerGapTextWithPlaceholder("9", "64squareroot") + .saveAnswer() + .assertCorrectSolution("Correct solution") + .assertFeedback("Incorrect") + .endTest() + .assertOnAssessmentResults() + .assertOnAssessmentTestScore(4);// 2 points from the first question, 4 from the second + + + //a second user search the content package + LoginPage reiLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + reiLoginPage + .loginAs(rei.getLogin(), rei.getPassword()) + .resume(); + NavigationPage reiNavBar = new NavigationPage(participantBrowser); + reiNavBar + .openMyCourses() + .openSearch() + .extendedSearch(qtiTestTitle) + .select(qtiTestTitle) + .start(); + + // make the test with all the correct answers + QTI21Page + .getQTI12Page(participantBrowser) + .assertOnAssessmentItem() + .answerGapTextWithPlaceholder("3", "three") + .answerGapTextWithPlaceholder("9", "nine") + .saveAnswer() + .assertFeedback("Correct feedback") + .nextAnswer() + .answerGapTextWithPlaceholder("57", "57") + .answerGapTextWithPlaceholder("8", "64squareroot") + .saveAnswer() + .endTest() + .assertOnAssessmentResults() + .assertOnAssessmentTestScore(6);// 2 points from the first question, 4 from the second + } + + /** + * An author make a test with 2 questions using numerical input to + * test the absolute tolerance mode.<br> + * A first user make the test, but doesn't answer all questions + * correctly, log out and a second user make the perfect test but + * on the limit. + * + * @param authorLoginPage + * @param participantBrowser + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void qti21EditorNumericalInput_absolut(@InitialPage LoginPage authorLoginPage, + @Drone @User WebDriver participantBrowser) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO ryomou = new UserRestClient(deploymentUrl).createRandomUser("Ryomou"); + UserVO rei = new UserRestClient(deploymentUrl).createRandomUser("Rei"); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + String qtiTestTitle = "Numerical QTI 2.1 " + UUID.randomUUID(); + navBar + .openAuthoringEnvironment() + .createQTI21Test(qtiTestTitle) + .clickToolbarBack(); + + QTI21Page qtiPage = QTI21Page + .getQTI12Page(browser); + QTI21EditorPage qtiEditor = qtiPage + .edit(); + //start a blank test + qtiEditor + .selectNode("Single choice") + .deleteNode(); + + //add a numerical input: 3.1 - 3.2 + QTI21GapEntriesEditorPage fibEditor = qtiEditor + .addNumerical() + .appendContent("Usefull for circles ") + .editNumericalInput("3.1416", "pi", ToleranceMode.ABSOLUTE, "3.2", "3.1", 1) + .saveNumericInput() + .save(); + // use standard score setting + // set feedbacks + fibEditor + .selectFeedbacks() + .setCorrectFeedback("Correct feedback", "Your answer is correct") + .setIncorrectFeedback("Incorrect", "Out of bounds") + .save(); + + //add a numerical input which represent a rounding issue + fibEditor = qtiEditor + .addNumerical() + .appendContent("Check rounding issue ") + .editNumericalInput("14.923", "rounding", ToleranceMode.ABSOLUTE, "14.925", "14.915", 1) + .saveNumericInput() + .save(); + // set feedbacks + fibEditor + .selectFeedbacks() + .setCorrectFeedback("Correct feedback", "Your answer is correct") + .setIncorrectFeedback("Incorrect", "Your answer is not correct") + .save(); + + //add a numerical input with negative values + fibEditor = qtiEditor + .addNumerical() + .appendContent("Check rounding issue ") + .editNumericalInput("-14.923", "negative", ToleranceMode.ABSOLUTE, "-14.921", "-14.931", 1) + .saveNumericInput() + .save(); + // set feedbacks + fibEditor + .selectFeedbacks() + .setCorrectFeedback("Correct feedback", "Your answer is correct") + .setIncorrectFeedback("Incorrect", "Your answer is not correct") + .save(); + + qtiPage + .clickToolbarBack(); + // access to all + qtiPage + .accessConfiguration() + .setUserAccess(UserAccess.guest) + .clickToolbarBack(); + // show results + qtiPage + .options() + .showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions()) + .save(); + + //a user search the content package + LoginPage userLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + userLoginPage + .loginAs(ryomou.getLogin(), ryomou.getPassword()) + .resume(); + NavigationPage userNavBar = new NavigationPage(participantBrowser); + userNavBar + .openMyCourses() + .openSearch() + .extendedSearch(qtiTestTitle) + .select(qtiTestTitle) + .start(); + + // first user make the test + QTI21Page ryomouQtiPage = QTI21Page + .getQTI12Page(participantBrowser); + ryomouQtiPage + .assertOnAssessmentItem() + .answerGapTextWithPlaceholder("3", "pi") + .saveAnswer() + .assertFeedback("Incorrect") + .answerGapTextWithPlaceholder("3.15", "pi") + .saveAnswer() + .assertFeedback("Correct feedback") + .nextAnswer() + .answerGapTextWithPlaceholder("14.914", "rounding") + .saveAnswer() + .assertFeedback("Incorrect") + .answerGapTextWithPlaceholder("14.915", "rounding") + .saveAnswer() + .assertFeedback("Correct feedback") + .nextAnswer() + .answerGapTextWithPlaceholder("-14.932", "negative") + .saveAnswer() + .assertFeedback("Incorrect") + .answerGapTextWithPlaceholder("-14.920", "negative") + .saveAnswer() + .endTest() + .assertOnAssessmentResults() + .assertOnAssessmentTestScore(2);// 1 point + 1 point + 0 point + + + //a second user search the content package + LoginPage reiLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + reiLoginPage + .loginAs(rei.getLogin(), rei.getPassword()) + .resume(); + NavigationPage reiNavBar = new NavigationPage(participantBrowser); + reiNavBar + .openMyCourses() + .openSearch() + .extendedSearch(qtiTestTitle) + .select(qtiTestTitle) + .start(); + + // make the test with all the correct answers + QTI21Page + .getQTI12Page(participantBrowser) + .assertOnAssessmentItem() + .answerGapTextWithPlaceholder("3.2", "pi") + .saveAnswer() + .assertFeedback("Correct feedback") + .nextAnswer() + .answerGapTextWithPlaceholder("14.925", "rounding") + .saveAnswer() + .assertFeedback("Correct feedback") + .nextAnswer() + .answerGapTextWithPlaceholder("-14.921", "negative") + .saveAnswer() + .assertFeedback("Correct feedback") + .endTest() + .assertOnAssessmentResults() + .assertOnAssessmentTestScore(3); + } + /** * An author make a test with 2 matches. A match with "multiple selection" * and score "all answers", a second with "single selection" and score diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21EditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21EditorPage.java index da88b562678..9559fcdca35 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21EditorPage.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21EditorPage.java @@ -147,6 +147,11 @@ public class QTI21EditorPage { return new QTI21GapEntriesEditorPage(browser); } + public QTI21GapEntriesEditorPage addNumerical() { + addQuestion(QTI21QuestionType.numerical); + return new QTI21GapEntriesEditorPage(browser); + } + private QTI21EditorPage addQuestion(QTI21QuestionType type) { openElementsMenu(); diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21GapEntriesEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21GapEntriesEditorPage.java index 8213ce301d1..9737e0ae266 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21GapEntriesEditorPage.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21GapEntriesEditorPage.java @@ -23,6 +23,9 @@ import org.olat.selenium.page.graphene.OOGraphene; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.Select; + +import uk.ac.ed.ph.jqtiplus.node.expression.operator.ToleranceMode; /** * @@ -106,6 +109,86 @@ public class QTI21GapEntriesEditorPage extends QTI21AssessmentItemEditorPage { return this; } + /** + * Add a new numerical input. Use the placeholder to locate + * the gap during the test. + * + * @param solution The solution + * @param placeholder The placeholder + * @return Itself + */ + public QTI21GapEntriesEditorPage addNumericalInput(String solution, String placeholder, + ToleranceMode toleranceMode, String uperrBound, String lowerBound) { + By addGapBy = By.xpath("//div[contains(@class,'o_sel_assessment_item_fib_text')]//button[i[contains(@class,'mce-i-gapnumerical')]]"); + browser.findElement(addGapBy).click(); + OOGraphene.waitModalDialog(browser); + return fillNumericalInputSettings(solution, placeholder, toleranceMode, uperrBound, lowerBound); + } + + /** + * Edit an existing numerical input of type text. Use the placeholder to locate + * the gap during the test. + * + * @param solution The solution + * @param placeholder The placeholder + * @param index The index of the entry in the paragraph + * @return Itself + */ + public QTI21GapEntriesEditorPage editNumericalInput(String solution, String placeholder, + ToleranceMode toleranceMode, String uperrBound, String lowerBound, int index) { + By frameBy = By.cssSelector("div.o_sel_assessment_item_fib_text div.mce-edit-area iframe"); + WebElement frameEl = browser.findElement(frameBy); + browser.switchTo().frame(frameEl); + + By gapEntryBy = By.xpath("//p/span[@class='textentryinteraction'][" + index + "]/a"); + browser.findElement(gapEntryBy).click(); + + browser.switchTo().defaultContent(); + OOGraphene.waitModalDialog(browser); + return fillNumericalInputSettings(solution, placeholder, toleranceMode, uperrBound, lowerBound); + } + + private QTI21GapEntriesEditorPage fillNumericalInputSettings(String solution, String placeholder, + ToleranceMode toleranceMode, String upperBound, String lowerBound) { + By solutionBy = By.cssSelector("fieldset.o_sel_gap_numeric_form div.o_sel_gap_numeric_solution input[type=text]"); + WebElement solutionEl = browser.findElement(solutionBy); + solutionEl.clear(); + solutionEl.sendKeys(solution); + + By placeholderBy = By.cssSelector("fieldset.o_sel_gap_numeric_form div.o_sel_gap_numeric_placeholder input[type=text]"); + browser.findElement(placeholderBy).sendKeys(placeholder); + + By toleranceModeBy = By.xpath("//select[contains(@id,'fib_tolerance_mode')]"); + WebElement toleranceModeEl = browser.findElement(toleranceModeBy); + new Select(toleranceModeEl).selectByValue(toleranceMode.name()); + OOGraphene.waitBusy(browser); + + By upperBoundBy = By.cssSelector("fieldset.o_sel_gap_numeric_form div.o_sel_gap_numeric_upper_bound input[type=text]"); + if(toleranceMode == ToleranceMode.EXACT) { + OOGraphene.waitElementDisappears(upperBoundBy, 5, browser); + } else { + OOGraphene.waitElement(upperBoundBy, browser); + + browser.findElement(upperBoundBy).sendKeys(upperBound); + By lowerBoundBy = By.cssSelector("fieldset.o_sel_gap_numeric_form div.o_sel_gap_numeric_lower_bound input[type=text]"); + browser.findElement(lowerBoundBy).sendKeys(lowerBound); + } + return this; + } + + /** + * Save and close the modal dialog to edit the numerical input. + * + * @return Itself + */ + public QTI21GapEntriesEditorPage saveNumericInput() { + By saveBy = By.cssSelector("fieldset.o_sel_gap_numeric_form button.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + /** * Save the whole interaction. * -- GitLab