diff --git a/src/test/java/org/olat/selenium/ImsQTI21InteractionsTest.java b/src/test/java/org/olat/selenium/ImsQTI21InteractionsTest.java index b54e8ec705c1bca7d86da95e57f783521c992284..781d4edff6a3977fce2d058b0575f425856f8a86 100644 --- a/src/test/java/org/olat/selenium/ImsQTI21InteractionsTest.java +++ b/src/test/java/org/olat/selenium/ImsQTI21InteractionsTest.java @@ -44,7 +44,9 @@ import org.openqa.selenium.WebDriver; /** - * This suite tests the interactions in runtime and only in runtime: + * This suite tests the interactions in runtime and only in runtime. The source used + * come from the IMS examples. + * * <ul> * <li>Hotspot * <li>Associate @@ -52,6 +54,12 @@ import org.openqa.selenium.WebDriver; * <li>Match * <li>Graphic Gap Match (with click and drop) * <li>End interaction with inline and modal feedbacks (classic hint) + * <li>Select point interaction + * <li>Position object interaction + * <li>Order interaction + * <li>Graphic order interaction + * <li>Inline choice + * <li>Slider * </ul> * * Initial date: 26 janv. 2018<br> @@ -83,7 +91,7 @@ public class ImsQTI21InteractionsTest extends Deployments { authorLoginPage.loginAs(author.getLogin(), author.getPassword()); //upload a test - String qtiTestTitle = "Simple QTI 2.1 " + UUID.randomUUID(); + String qtiTestTitle = "Hotspot QTI 2.1 " + UUID.randomUUID(); URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/simple_QTI_21_hotspot.zip"); File qtiTestFile = new File(qtiTestUrl.toURI()); navBar @@ -175,7 +183,7 @@ public class ImsQTI21InteractionsTest extends Deployments { authorLoginPage.loginAs(author.getLogin(), author.getPassword()); //upload a test - String qtiTestTitle = "Associate QTI 2.1 " + UUID.randomUUID(); + String qtiTestTitle = "Graphic associate QTI 2.1 " + UUID.randomUUID(); URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/simple_QTI_21_graphic_associate_ims.zip"); File qtiTestFile = new File(qtiTestUrl.toURI()); navBar @@ -315,7 +323,7 @@ public class ImsQTI21InteractionsTest extends Deployments { authorLoginPage.loginAs(author.getLogin(), author.getPassword()); //upload a test - String qtiTestTitle = "Simple QTI 2.1 " + UUID.randomUUID(); + String qtiTestTitle = "End QTI 2.1 " + UUID.randomUUID(); URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/simple_QTI_21_end_ims.zip"); File qtiTestFile = new File(qtiTestUrl.toURI()); navBar @@ -405,5 +413,275 @@ public class ImsQTI21InteractionsTest extends Deployments { .assertOnAssessmentResults() .assertOnAssessmentItemScore("Airport Tags", 3); } + + /** + * Check if the select point interaction returns 1 point + * if answered correctly. + * + * @param authorLoginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void qti21SelectPointInteraction(@InitialPage LoginPage authorLoginPage) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //upload a test + String qtiTestTitle = "Select point QTI 2.1 " + UUID.randomUUID(); + URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/simple_QTI_21_select_point_ims.zip"); + File qtiTestFile = new File(qtiTestUrl.toURI()); + navBar + .openAuthoringEnvironment() + .uploadResource(qtiTestTitle, qtiTestFile) + .clickToolbarRootCrumb(); + + QTI21Page qtiPage = QTI21Page + .getQTI12Page(browser); + qtiPage + .options() + .showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions()) + .save(); + // to the test and spot it + qtiPage + .clickToolbarBack() + .assertOnAssessmentItem() + .answerSelectPoint(100, 110) + .saveAnswer() + .endTest() + .closeTest(); + //check the results + qtiPage + .assertOnAssessmentResults() + .assertOnAssessmentItemScore("Where is Edinburgh", 1); + } + + /** + * Check if the graphic order interaction returns 1 point + * if answered correctly. + * + * @param authorLoginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void qti21GraphicOrderInteraction(@InitialPage LoginPage authorLoginPage) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //upload a test + String qtiTestTitle = "Graphic order QTI 2.1 " + UUID.randomUUID(); + URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/simple_QTI_21_graphic_order_ims.zip"); + File qtiTestFile = new File(qtiTestUrl.toURI()); + navBar + .openAuthoringEnvironment() + .uploadResource(qtiTestTitle, qtiTestFile) + .clickToolbarRootCrumb(); + + QTI21Page qtiPage = QTI21Page + .getQTI12Page(browser); + qtiPage + .options() + .showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions()) + .save(); + // to the test and spot it + qtiPage + .clickToolbarBack() + .assertOnAssessmentItem() + .answerGraphicOrderById("A") + .answerGraphicOrderById("D") + .answerGraphicOrderById("C") + .answerGraphicOrderById("B") + .saveAnswer() + .endTest() + .closeTest(); + //check the results + qtiPage + .assertOnAssessmentResults() + .assertOnAssessmentItemScore("Flying Home", 1); + } + + /** + * Check if the position object interaction returns 3 points + * if answered correctly. + * + * @param authorLoginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void qti21PositionObjectInteraction(@InitialPage LoginPage authorLoginPage) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //upload a test + String qtiTestTitle = "Position object QTI 2.1 " + UUID.randomUUID(); + URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/simple_QTI_21_position_object_ims.zip"); + File qtiTestFile = new File(qtiTestUrl.toURI()); + navBar + .openAuthoringEnvironment() + .uploadResource(qtiTestTitle, qtiTestFile) + .clickToolbarRootCrumb(); + + QTI21Page qtiPage = QTI21Page + .getQTI12Page(browser); + qtiPage + .options() + .showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions()) + .save(); + // to the test and spot it + qtiPage + .clickToolbarBack() + .assertOnAssessmentItem() + .answerPositionObject(0, 118, 184) + .answerPositionObject(1, 150, 235) + .answerPositionObject(2, 96, 114) + .saveAnswer() + .endTest() + .closeTest(); + //check the results + qtiPage + .assertOnAssessmentResults() + .assertOnAssessmentItemScore("Airport Locations", 3); + } + + /** + * Check if the position object interaction returns 3 points + * if answered correctly. + * + * @param authorLoginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void qti21InlineChoiceInteraction(@InitialPage LoginPage authorLoginPage) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //upload a test + String qtiTestTitle = "Inline choice QTI 2.1 " + UUID.randomUUID(); + URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/simple_QTI_21_inline_choice_ims.zip"); + File qtiTestFile = new File(qtiTestUrl.toURI()); + navBar + .openAuthoringEnvironment() + .uploadResource(qtiTestTitle, qtiTestFile) + .clickToolbarRootCrumb(); + + QTI21Page qtiPage = QTI21Page + .getQTI12Page(browser); + qtiPage + .options() + .showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions()) + .save(); + // to the test and spot it + qtiPage + .clickToolbarBack() + .assertOnAssessmentItem() + .answerInlineChoice("Y") + .saveAnswer() + .endTest() + .closeTest(); + //check the results + qtiPage + .assertOnAssessmentResults() + .assertOnAssessmentItemScore("Richard III", 1); + } + + /** + * Check if the slider interaction returns 1 point + * if answered correctly. + * + * @param authorLoginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void qti21SliderInteraction(@InitialPage LoginPage authorLoginPage) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //upload a test + String qtiTestTitle = "Slider QTI 2.1 " + UUID.randomUUID(); + URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/simple_QTI_21_slider_ims.zip"); + File qtiTestFile = new File(qtiTestUrl.toURI()); + navBar + .openAuthoringEnvironment() + .uploadResource(qtiTestTitle, qtiTestFile) + .clickToolbarRootCrumb(); + + QTI21Page qtiPage = QTI21Page + .getQTI12Page(browser); + qtiPage + .options() + .showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions()) + .save(); + // to the test and spot it + qtiPage + .clickToolbarBack() + .assertOnAssessmentItem() + .answerVerticalSlider(16) + .saveAnswer() + .endTest() + .closeTest(); + //check the results + qtiPage + .assertOnAssessmentResults() + .assertOnAssessmentItemScore("Jedi Knights", 1); + } + + /** + * Check if the gap match returns 3 points + * if answered correctly. + * + * @param authorLoginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void qti21GapMatchInteraction(@InitialPage LoginPage authorLoginPage) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //upload a test + String qtiTestTitle = "Gap match QTI 2.1 " + UUID.randomUUID(); + URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/simple_QTI_21_gap_match_ims.zip"); + File qtiTestFile = new File(qtiTestUrl.toURI()); + navBar + .openAuthoringEnvironment() + .uploadResource(qtiTestTitle, qtiTestFile) + .clickToolbarRootCrumb(); + + QTI21Page qtiPage = QTI21Page + .getQTI12Page(browser); + qtiPage + .options() + .showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions()) + .save(); + // to the test and spot it + qtiPage + .clickToolbarBack() + .assertOnAssessmentItem() + .answerGapMatch(1, "winter", true) + .answerGapMatch(2, "summer", true) + .saveAnswer() + .endTest() + .closeTest(); + //check the results + qtiPage + .assertOnAssessmentResults() + .assertOnAssessmentItemScore("Richard III", 3); + } } 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 7d31633102fc382a403317c24fcdd3d93f798ed6..08e92e1e004c8bb8100484677097b23f2084086a 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java @@ -27,9 +27,11 @@ import org.olat.selenium.page.NavigationPage; import org.olat.selenium.page.graphene.OOGraphene; import org.olat.selenium.page.repository.RepositoryAccessPage; import org.openqa.selenium.By; +import org.openqa.selenium.Dimension; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.support.ui.Select; /** * @@ -125,6 +127,20 @@ public class QTI21Page { return this; } + /** + * Select the key of the inline choice interaction. + * + * @param key The key to select + * @return Itself + */ + public QTI21Page answerInlineChoice(String key) { + By inlineBy = By.xpath("//span[@class='inlineChoiceInteraction']/select"); + OOGraphene.waitElement(inlineBy, browser); + WebElement inlineEl = browser.findElement(inlineBy); + new Select(inlineEl).selectByValue(key); + return this; + } + public QTI21Page answerHotspot(String shape) { OOGraphene.waitElement(By.className("hotspotInteraction"), browser); By areaBy = By.xpath("//div[contains(@class,'hotspotInteraction')]//map/area[@shape='" + shape + "']"); @@ -134,6 +150,20 @@ public class QTI21Page { return this; } + /** + * Select the area with the specified data-qti-id. + * @param id The id save in data-qti-id + * @return Itself + */ + public QTI21Page answerGraphicOrderById(String id) { + OOGraphene.waitElement(By.className("graphicOrderInteraction"), browser); + By areaBy = By.xpath("//div[contains(@class,'graphicOrderInteraction')]//map/area[@data-qti-id='" + id + "']"); + List<WebElement> elements = browser.findElements(areaBy); + Assert.assertEquals("Hotspot with data-qti-id " + id, 1, elements.size()); + elements.get(0).click(); + return this; + } + public QTI21Page answerHottext(int index) { OOGraphene.waitElement(By.className("hottextInteraction"), browser); By checkBy = By.xpath("//div[contains(@class,'hottextInteraction')]//p/span[@class='hottext'][" + index + "]/input[@type='checkbox']"); @@ -303,6 +333,21 @@ public class QTI21Page { return this; } + /** + * Select the gap match + * + * @param source The row to check + * @param target Text in the target + * @param match Select or deselect + * @return Itself + */ + public QTI21Page answerGapMatch(int row, String target, boolean match) { + By matchBy = By.xpath("//div[contains(@class,'gapMatchInteraction')]/table//tr[th[contains(text(),'" + row + "')]]/td[count(//div[contains(@class,'gapMatchInteraction')]/table//tr/th[text()[contains(.,'" + target + "')]]/preceding-sibling::th)]/input"); + WebElement matchEl = browser.findElement(matchBy); + OOGraphene.check(matchEl, match); + return this; + } + /** * Use the click and drop. * @@ -321,6 +366,75 @@ public class QTI21Page { return this; } + /** + * Select the point based on coordinates. + * + * @param x The x coordinate + * @param y The y coordinate + * @return Itself + */ + public QTI21Page answerSelectPoint(int x, int y) { + By canvasBy = By.xpath("//div[contains(@class,'selectPointInteraction')]/div/canvas"); + WebElement canvasEl = browser.findElement(canvasBy); + new Actions(browser) + .moveToElement(canvasEl, x, y) + .click() + .build() + .perform(); + return this; + } + + /** + * Select the object by its index (start with 0) and + * move it on the image and the specified coodinates. + * + * @param index The index of the object + * @param x The x target coordinate + * @param y The y target coordinate + * @return Itself + */ + public QTI21Page answerPositionObject(int index, int x, int y) { + By itemBy = By.xpath("//div[contains(@class,'positionObjectStage')]//div[@id='object-item-" + index + "']"); + OOGraphene.waitElement(itemBy, browser); + WebElement itemEl = browser.findElement(itemBy); + By targetBy = By.xpath("//div[@class='positionObjectStage']//img[contains(@id,'qtiworks_id_container_')]"); + WebElement targetEl = browser.findElement(targetBy); + new Actions(browser) + .moveToElement(itemEl, 5, 5) + .clickAndHold() + .moveToElement(targetEl, x, y) + .release() + .build() + .perform(); + return this; + } + + /** + * Select the point based on coordinates. + * + * @param x The x coordinate + * @return Itself + */ + public QTI21Page answerVerticalSlider(int val) { + By sliderBy = By.xpath("//div[contains(@class,'sliderInteraction')]/div[contains(@class,'sliderVertical')]/div[contains(@class,'sliderWidget')]"); + OOGraphene.waitElement(sliderBy, browser); + WebElement sliderEl = browser.findElement(sliderBy); + Dimension size = sliderEl.getSize(); + float height = (size.getHeight() / 100f) * val; + float scaledY = size.getHeight() - height; + + new Actions(browser) + .moveToElement(sliderEl, 5, Math.round(scaledY)) + .click() + .build() + .perform(); + + + By valueBy = By.xpath("//div[contains(@class,'sliderInteraction')]/div[contains(@class,'sliderVertical')]/div[contains(@class,'sliderValue')]/span[text()='" + val + "']"); + OOGraphene.waitElement(valueBy, browser); + return this; + } + public QTI21Page answerUpload(File file) { By inputBy = By.cssSelector(".uploadInteraction input[type='file']"); OOGraphene.uploadFile(inputBy, file, browser); diff --git a/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_gap_match_ims.zip b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_gap_match_ims.zip new file mode 100644 index 0000000000000000000000000000000000000000..9054f45e1c0ad30c32989d55e8cf996d7404e888 Binary files /dev/null and b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_gap_match_ims.zip differ diff --git a/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_graphic_order_ims.zip b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_graphic_order_ims.zip new file mode 100644 index 0000000000000000000000000000000000000000..c6295034b81d860a7ca91e82d09162b4f116b184 Binary files /dev/null and b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_graphic_order_ims.zip differ diff --git a/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_inline_choice_ims.zip b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_inline_choice_ims.zip new file mode 100644 index 0000000000000000000000000000000000000000..bc8ac24ad6b99d1a0f83c1df9e93b46cce59617f Binary files /dev/null and b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_inline_choice_ims.zip differ diff --git a/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_position_object_ims.zip b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_position_object_ims.zip new file mode 100644 index 0000000000000000000000000000000000000000..a4b7033e23ab14dd360fdf26656d25fad4b198db Binary files /dev/null and b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_position_object_ims.zip differ diff --git a/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_select_point_ims.zip b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_select_point_ims.zip new file mode 100644 index 0000000000000000000000000000000000000000..61be744db788c68d9df72b535acefc60ba03ddc2 Binary files /dev/null and b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_select_point_ims.zip differ diff --git a/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_slider_ims.zip b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_slider_ims.zip new file mode 100644 index 0000000000000000000000000000000000000000..5cb3f2b418ee8d38f31efea77864950ff644b1a2 Binary files /dev/null and b/src/test/java/org/olat/test/file_resources/qti21/simple_QTI_21_slider_ims.zip differ