From 74bad92fc0d426cd72e132477d1f40a3a51423ae Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Fri, 12 May 2017 20:06:48 +0200 Subject: [PATCH] no-jira: selenium tests for QTI 2.1 editor, upload with specific feedbacks --- .../LobFeedbackEditorController.java | 10 +- .../interactions/UploadEditorController.java | 4 +- .../java/org/olat/selenium/ImsQTI21Test.java | 99 +++++++++++++++++++ .../selenium/page/qti/QTI21EditorPage.java | 5 + .../selenium/page/qti/QTI21LobEditorPage.java | 60 +++++++++++ .../page/qti/QTI21LobFeedbacksEditorPage.java | 77 +++++++++++++++ .../page/qti/QTI21MinimalScoreEditorPage.java | 57 +++++++++++ .../org/olat/selenium/page/qti/QTI21Page.java | 18 ++++ 8 files changed, 328 insertions(+), 2 deletions(-) create mode 100644 src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java create mode 100644 src/test/java/org/olat/selenium/page/qti/QTI21LobFeedbacksEditorPage.java create mode 100644 src/test/java/org/olat/selenium/page/qti/QTI21MinimalScoreEditorPage.java diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/LobFeedbackEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/LobFeedbackEditorController.java index a18235dda08..27800c8e87e 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/LobFeedbackEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/LobFeedbackEditorController.java @@ -75,7 +75,7 @@ public class LobFeedbackEditorController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormContextHelp("Test editor QTI 2.1 in detail#details_testeditor_feedback"); - + formLayout.setElementCssClass("o_sel_assessment_item_feedbacks"); String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString(); VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath); @@ -84,11 +84,13 @@ public class LobFeedbackEditorController extends FormBasicController { ModalFeedbackBuilder hint = itemBuilder.getHint(); String hintTitle = hint == null ? "" : hint.getTitle(); hintTitleEl = uifactory.addTextElement("hintTitle", "form.imd.hint.title", -1, hintTitle, formLayout); + hintTitleEl.setElementCssClass("o_sel_assessment_item_hint_title"); hintTitleEl.setUserObject(hint); hintTitleEl.setEnabled(!restrictedEdit); String hintText = hint == null ? "" : hint.getText(); hintTextEl = uifactory.addRichTextElementForQTI21("hintText", "form.imd.hint.text", hintText, 8, -1, itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); + hintTextEl.setElementCssClass("o_sel_assessment_item_hint"); hintTextEl.setEnabled(!restrictedEdit); hintTextEl.setHelpTextKey("feedback.hint.help", null); hintTextEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_feedback"); @@ -102,12 +104,14 @@ public class LobFeedbackEditorController extends FormBasicController { feedbackCorrectSolutionTitleEl = uifactory.addTextElement("correctSolutionTitle", "form.imd.correct.solution.title", -1, correctSolutionTitle, formLayout); feedbackCorrectSolutionTitleEl.setUserObject(correctSolutionFeedback); feedbackCorrectSolutionTitleEl.setEnabled(!restrictedEdit); + feedbackCorrectSolutionTitleEl.setElementCssClass("o_sel_assessment_item_correct_solution_title"); String correctSolutionText = correctSolutionFeedback == null ? "" : correctSolutionFeedback.getText(); feedbackCorrectSolutionTextEl = uifactory.addRichTextElementForQTI21("correctSolutionText", "form.imd.correct.solution.text.word", correctSolutionText, 8, -1, itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); feedbackCorrectSolutionTextEl.setEnabled(!restrictedEdit); feedbackCorrectSolutionTextEl.setHelpTextKey("feedback.correctsolution.help", null); feedbackCorrectSolutionTextEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_feedback"); + feedbackCorrectSolutionTextEl.setElementCssClass("o_sel_assessment_item_correct_solution"); RichTextConfiguration richTextConfig2 = feedbackCorrectSolutionTextEl.getEditorConfiguration(); richTextConfig2.setFileBrowserUploadRelPath("media");// set upload dir to the media dir } @@ -118,10 +122,12 @@ public class LobFeedbackEditorController extends FormBasicController { feedbackTitleEl = uifactory.addTextElement("answeredTitle", "form.imd.answered.title", -1, correctTitle, formLayout); feedbackTitleEl.setUserObject(answeredFeedback); feedbackTitleEl.setEnabled(!restrictedEdit); + feedbackTitleEl.setElementCssClass("o_sel_assessment_item_answered_feedback_title"); String correctText = answeredFeedback == null ? "" : answeredFeedback.getText(); feedbackTextEl = uifactory.addRichTextElementForQTI21("answeredText", "form.imd.answered.text", correctText, 8, -1, itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); feedbackTextEl.setEnabled(!restrictedEdit); + feedbackTextEl.setElementCssClass("o_sel_assessment_item_answered_feedback"); RichTextConfiguration richTextConfig = feedbackTextEl.getEditorConfiguration(); richTextConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir } @@ -132,10 +138,12 @@ public class LobFeedbackEditorController extends FormBasicController { feedbackEmptyTitleEl = uifactory.addTextElement("emptyTitle", "form.imd.empty.title", -1, emptyTitle, formLayout); feedbackEmptyTitleEl.setUserObject(emptyFeedback); feedbackEmptyTitleEl.setEnabled(!restrictedEdit); + feedbackEmptyTitleEl.setElementCssClass("o_sel_assessment_item_empty_feedback_title"); String emptyText = emptyFeedback == null ? "" : emptyFeedback.getText(); feedbackEmptyTextEl = uifactory.addRichTextElementForQTI21("emptyText", "form.imd.empty.text", emptyText, 8, -1, itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); feedbackEmptyTextEl.setEnabled(!restrictedEdit); + feedbackEmptyTextEl.setElementCssClass("o_sel_assessment_item_empty_feedback"); RichTextConfiguration emptyTextConfig = feedbackEmptyTextEl.getEditorConfiguration(); emptyTextConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir } diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/UploadEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/UploadEditorController.java index abe0cd12ac6..e3dbfd24311 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/UploadEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/UploadEditorController.java @@ -71,7 +71,7 @@ public class UploadEditorController extends FormBasicController { setFormContextHelp("Test editor QTI 2.1 in detail#details_testeditor_fragetypen_fileupload"); titleEl = uifactory.addTextElement("title", "form.imd.title", -1, itemBuilder.getTitle(), formLayout); - titleEl.setElementCssClass("o_sel_qti_title"); + titleEl.setElementCssClass("o_sel_assessment_item_title"); titleEl.setMandatory(true); String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString(); @@ -80,10 +80,12 @@ public class UploadEditorController extends FormBasicController { String description = itemBuilder.getQuestion(); textEl = uifactory.addRichTextElementForQTI21("desc", "form.imd.descr", description, 16, -1, itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); + textEl.setElementCssClass("o_sel_assessment_item_question"); // Submit Button FormLayoutContainer buttonsContainer = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonsContainer.setRootForm(mainForm); + buttonsContainer.setElementCssClass("o_sel_upload_save"); formLayout.add(buttonsContainer); uifactory.addFormSubmitButton("submit", buttonsContainer); } diff --git a/src/test/java/org/olat/selenium/ImsQTI21Test.java b/src/test/java/org/olat/selenium/ImsQTI21Test.java index 1c955a2e428..404ffd3b55c 100644 --- a/src/test/java/org/olat/selenium/ImsQTI21Test.java +++ b/src/test/java/org/olat/selenium/ImsQTI21Test.java @@ -46,6 +46,7 @@ import org.olat.selenium.page.course.CoursePageFragment; import org.olat.selenium.page.qti.QTI21ConfigurationCEPage; import org.olat.selenium.page.qti.QTI21EditorPage; import org.olat.selenium.page.qti.QTI21KprimEditorPage; +import org.olat.selenium.page.qti.QTI21LobEditorPage; import org.olat.selenium.page.qti.QTI21MatchEditorPage; import org.olat.selenium.page.qti.QTI21MultipleChoiceEditorPage; import org.olat.selenium.page.qti.QTI21Page; @@ -1610,4 +1611,102 @@ public class ImsQTI21Test { .assertOnAssessmentResults() .assertOnAssessmentTestScore(10);// 4 points from the first question, 6 from the second } + + /** + * An author make a test with 1 upload and feedbacks.<br> + * A user make the test, test hint and upload the file. + * + * @param authorLoginPage + * @param participantBrowser + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void qti21EditorUpload(@InitialPage LoginPage authorLoginPage, + @Drone @User WebDriver participantBrowser) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO rei = new UserRestClient(deploymentUrl).createRandomUser("Rei"); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //make a test + String qtiTestTitle = "Choices 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 an upload interaction + QTI21LobEditorPage uploadEditor = qtiEditor + .addUpload(); + uploadEditor + .setQuestion("Upload a file") + .save() + .selectScores() + .setMaxScore("2.0") + .save(); + uploadEditor + .selectFeedbacks() + .setHint("Hint", "Need a little help.") + .setCorrectSolution("Correct solution", "Only for Word") + .setAnsweredFeedback("Full", "You upload something") + .setEmpytFeedback("Empty", "You do not upload anything") + .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 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 + QTI21Page reiQtiPage = QTI21Page + .getQTI12Page(participantBrowser); + reiQtiPage + .assertOnAssessmentItem() + .saveAnswer() + .assertFeedback("Empty") + .hint() + .assertFeedback("Hint"); + + URL imageUrl = JunitTestHelper.class.getResource("file_resources/IMG_1482.JPG"); + File imageFile = new File(imageUrl.toURI()); + reiQtiPage + .answerUpload(imageFile) + .saveAnswer() + .assertFeedback("Full") + .endTest() + .assertOnAssessmentResults() + .assertOnAssessmentResultUpload("IMG_1482"); + } } 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 52327d46044..7b838d3d8f0 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21EditorPage.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21EditorPage.java @@ -103,6 +103,11 @@ public class QTI21EditorPage { return new QTI21MatchEditorPage(browser); } + public QTI21LobEditorPage addUpload() { + addQuestion(QTI21QuestionType.upload); + return new QTI21LobEditorPage(browser); + } + private QTI21EditorPage addQuestion(QTI21QuestionType type) { openElementsMenu(); diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java new file mode 100644 index 00000000000..3732c529769 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java @@ -0,0 +1,60 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.qti; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; + +/** + * Drive the upload, drawing editor. + * + * Initial date: 12 mai 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QTI21LobEditorPage extends QTI21AssessmentItemEditorPage { + + public QTI21LobEditorPage(WebDriver browser) { + super(browser); + } + + public QTI21LobEditorPage setQuestion(String question) { + OOGraphene.tinymce(question, "div.o_sel_assessment_item_question", browser); + return this; + } + + public QTI21LobEditorPage save() { + By saveBy = By.cssSelector("div.o_sel_upload_save button.btn.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + public QTI21MinimalScoreEditorPage selectScores() { + selectTab(By.className("o_sel_assessment_item_options")); + return new QTI21MinimalScoreEditorPage(browser); + } + + public QTI21LobFeedbacksEditorPage selectFeedbacks() { + selectTab(By.className("o_sel_assessment_item_feedbacks")); + return new QTI21LobFeedbacksEditorPage(browser); + } +} diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21LobFeedbacksEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21LobFeedbacksEditorPage.java new file mode 100644 index 00000000000..85cdb06111f --- /dev/null +++ b/src/test/java/org/olat/selenium/page/qti/QTI21LobFeedbacksEditorPage.java @@ -0,0 +1,77 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.qti; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; + +/** + * + * Drive the feedbackabck editor with the special empty / answered + * feedbacks. + * + * Initial date: 12 mai 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QTI21LobFeedbacksEditorPage { + + private final WebDriver browser; + + public QTI21LobFeedbacksEditorPage(WebDriver browser) { + this.browser = browser; + } + + public QTI21LobFeedbacksEditorPage setHint(String title, String hint) { + By titleBy = By.cssSelector("div.o_sel_assessment_item_hint_title input[type='text']"); + browser.findElement(titleBy).sendKeys(title); + OOGraphene.tinymce(hint, "div.o_sel_assessment_item_hint", browser); + return this; + } + + public QTI21LobFeedbacksEditorPage setCorrectSolution(String title, String correctSolution) { + By titleBy = By.cssSelector("div.o_sel_assessment_item_correct_solution_title input[type='text']"); + browser.findElement(titleBy).sendKeys(title); + OOGraphene.tinymce(correctSolution, "div.o_sel_assessment_item_correct_solution", browser); + return this; + } + + public QTI21LobFeedbacksEditorPage setAnsweredFeedback(String title, String feedback) { + By titleBy = By.cssSelector("div.o_sel_assessment_item_answered_feedback_title input[type='text']"); + browser.findElement(titleBy).sendKeys(title); + OOGraphene.tinymce(feedback, "div.o_sel_assessment_item_answered_feedback", browser); + return this; + } + + public QTI21LobFeedbacksEditorPage setEmpytFeedback(String title, String feedback) { + By titleBy = By.cssSelector("div.o_sel_assessment_item_empty_feedback_title input[type='text']"); + browser.findElement(titleBy).sendKeys(title); + OOGraphene.tinymce(feedback, "div.o_sel_assessment_item_empty_feedback", browser); + return this; + } + + public QTI21LobFeedbacksEditorPage save() { + By saveBy = By.cssSelector("fieldset.o_sel_assessment_item_feedbacks button.btn.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + return this; + } +} diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21MinimalScoreEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21MinimalScoreEditorPage.java new file mode 100644 index 00000000000..ae6c960715a --- /dev/null +++ b/src/test/java/org/olat/selenium/page/qti/QTI21MinimalScoreEditorPage.java @@ -0,0 +1,57 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.qti; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * Drive the minimal score editor with only the max score. + * + * Initial date: 12 mai 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QTI21MinimalScoreEditorPage { + + private final WebDriver browser; + + public QTI21MinimalScoreEditorPage(WebDriver browser) { + this.browser = browser; + } + + public QTI21MinimalScoreEditorPage setMaxScore(String maxScore) { + By maxScoreBy = By.cssSelector("div.o_sel_assessment_item_max_score input[type='text']"); + WebElement maxScoreEl = browser.findElement(maxScoreBy); + maxScoreEl.clear(); + maxScoreEl.sendKeys(maxScore); + return this; + } + + public QTI21MinimalScoreEditorPage save() { + By saveBy = By.cssSelector("fieldset.o_sel_assessment_item_options button.btn.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + +} diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java index a80b149944b..5e03f62c251 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java @@ -19,6 +19,7 @@ */ package org.olat.selenium.page.qti; +import java.io.File; import java.util.List; import org.junit.Assert; @@ -173,6 +174,12 @@ public class QTI21Page { return this; } + public QTI21Page answerUpload(File file) { + By inputBy = By.cssSelector(".uploadInteraction input[type='file']"); + OOGraphene.uploadFile(inputBy, file, browser); + return this; + } + public QTI21Page saveAnswer() { By saveAnswerBy = By.cssSelector("button.o_sel_assessment_item_submit"); browser.findElement(saveAnswerBy).click(); @@ -312,6 +319,17 @@ public class QTI21Page { return this; } + /** + * + * @param name The name of the file without extension + * @return Itself + */ + public QTI21Page assertOnAssessmentResultUpload(String name) { + By uploadBy = By.xpath("//div[contains(@class,'o_assessment_test_results')]//div[contains(@class,'uploadInteraction')]/a[contains(@href,'" + name + "')]"); + OOGraphene.waitElement(uploadBy, 5, browser); + return this; + } + public QTI21Page assertOnAssessmentTestFeedback(String feedback) { By feedbackBy = By.xpath("//div[contains(@class,'o_info')]/h3[contains(text(),'" + feedback + "')]"); OOGraphene.waitElement(feedbackBy, 5, browser); -- GitLab