/** * <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 java.io.File; import java.util.List; import org.junit.Assert; 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.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; /** * * Initial date: 06.05.2016<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class QTI21Page { private final By toolsMenu = By.cssSelector("ul.o_sel_repository_tools"); private final By settingsMenu = By.cssSelector("ul.o_sel_course_settings"); private WebDriver browser; private QTI21Page(WebDriver browser) { this.browser = browser; } public static QTI21Page getQTI12Page(WebDriver browser) { By mainBy = By.id("o_main_wrapper"); OOGraphene.waitElement(mainBy, 5, browser); WebElement main = browser.findElement(mainBy); Assert.assertTrue(main.isDisplayed()); return new QTI21Page(browser); } public QTI21Page start() { By startBy = By.cssSelector("a.o_sel_start_qti21assessment"); WebElement startButton = browser.findElement(startBy); startButton.click(); OOGraphene.waitBusy(browser); By mainBy = By.cssSelector("div.qtiworks.o_assessmenttest"); OOGraphene.waitElement(mainBy, 5, browser); return this; } public QTI21Page assertOnCourseAttempts(int numOfAttemtps) { By attemptBy = By.xpath("//div[contains(@class,'o_course_run')]//table//tr[contains(@class,'o_attempts')]//td[text()[contains(.,'" + numOfAttemtps + "')]]"); OOGraphene.waitElement(attemptBy, 5, browser); WebElement attemptEl = browser.findElement(attemptBy); Assert.assertTrue(attemptEl.isDisplayed()); return this; } public QTI21Page startTestPart() { By startBy = By.xpath("//button[contains(@onclick,'advanceTestPart')]"); browser.findElement(startBy).click(); OOGraphene.waitBusy(browser); By menuBy = By.id("o_qti_menu"); OOGraphene.waitElement(menuBy, 5, browser); return this; } public QTI21Page assertOnAssessmentItem() { By assessmentItemBy = By.cssSelector("div.qtiworks.o_assessmentitem.o_assessmenttest"); OOGraphene.waitElement(assessmentItemBy, 5, browser); return this; } public QTI21Page assertOnAssessmentItem(String title) { By itemTitleBy = By.xpath("//div[@class='o_assessmentitem_wrapper']/h4[contains(normalize-space(.),'" + title + "')]"); OOGraphene.waitElement(itemTitleBy, 5, browser); return this; } public QTI21Page selectItem(String title) { By itemBy = By.xpath("//div[@id='o_qti_menu']//li[contains(@class,'o_qti_menu_item')]//a[span[contains(normalize-space(.),'" + title + "')]]"); OOGraphene.waitElement(itemBy, 5, browser); browser.findElement(itemBy).click(); OOGraphene.waitBusy(browser); return this; } public QTI21Page answerSingleChoice(String answer) { By choiceBy = By.xpath("//tr[contains(@class,'choiceinteraction')][td[contains(@class,'choiceInteraction')][label/p[contains(normalize-space(text()),'" + answer + "')]]]/td[contains(@class,'control')]/input[@type='radio']"); browser.findElement(choiceBy).click(); return this; } public QTI21Page answerMultipleChoice(String... answers) { for(String answer:answers) { By choiceBy = By.xpath("//tr[contains(@class,'choiceinteraction')][td[contains(@class,'choiceInteraction')][label/p[contains(text(),'" + answer + "')]]]/td[contains(@class,'control')]/input[@type='checkbox']"); browser.findElement(choiceBy).click(); } return this; } public QTI21Page deselectAnswerMultipleChoice(String... answers) { for(String answer:answers) { By choiceBy = By.xpath("//tr[contains(@class,'choiceinteraction')][td[contains(@class,'choiceInteraction')][label/p[contains(text(),'" + answer + "')]]]/td[contains(@class,'control')]/input[@type='checkbox']"); OOGraphene.check(browser.findElement(choiceBy), Boolean.FALSE); } 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 + "']"); List<WebElement> elements = browser.findElements(areaBy); Assert.assertEquals("Hotspot of shape " + shape, 1, elements.size()); elements.get(0).click(); return this; } public QTI21Page answerCorrectKPrim(String... choices) { for(String choice:choices) { By incorrectBy = By.xpath("//tr[td/p[contains(text(),'" + choice + "')]]/td[contains(@class,'o_qti_item_kprim_input o_qti_item_kprim_input_wrong')]/input[@type='checkbox']"); WebElement incorrectEl = browser.findElement(incorrectBy); OOGraphene.check(incorrectEl, Boolean.FALSE); By correctBy = By.xpath("//tr[td/p[contains(text(),'" + choice + "')]]/td[contains(@class,'o_qti_item_kprim_input o_qti_item_kprim_input_correct')]/input[@type='checkbox']"); WebElement correctEl = browser.findElement(correctBy); OOGraphene.check(correctEl, Boolean.TRUE); } return this; } public QTI21Page answerIncorrectKPrim(String... choices) { for(String choice:choices) { By correctBy = By.xpath("//tr[td/p[contains(text(),'" + choice + "')]]/td[contains(@class,'o_qti_item_kprim_input o_qti_item_kprim_input_correct')]/input[@type='checkbox']"); WebElement correctEl = browser.findElement(correctBy); OOGraphene.check(correctEl, Boolean.FALSE); By incorrectBy = By.xpath("//tr[td/p[contains(text(),'" + choice + "')]]/td[contains(@class,'o_qti_item_kprim_input o_qti_item_kprim_input_wrong')]/input[@type='checkbox']"); WebElement incorrectEl = browser.findElement(incorrectBy); OOGraphene.check(incorrectEl, Boolean.TRUE); } return this; } public QTI21Page answerGapText(String text, String responseId) { By gapBy = By.xpath("//span[contains(@class,'textEntryInteraction')]/input[@type='text'][contains(@name,'" + responseId + "')]"); WebElement gapEl = browser.findElement(gapBy); gapEl.clear(); gapEl.sendKeys(text); return this; } public QTI21Page answerMatch(String source, String target, boolean match) { By matchBy = By.xpath("//div[contains(@class,'matchInteraction')]/table//tr[th/p[contains(text(),'" + source + "')]]/td[count(//div[contains(@class,'matchInteraction')]/table//tr/th[p[contains(text(),'" + target + "')]]/preceding-sibling::th)]/input"); WebElement matchEl = browser.findElement(matchBy); OOGraphene.check(matchEl, match); return this; } public QTI21Page answerUpload(File file) { By inputBy = By.cssSelector(".uploadInteraction input[type='file']"); OOGraphene.uploadFile(inputBy, file, browser); return this; } public QTI21Page answerEssay(String text) { By inputBy = By.cssSelector(".extendedTextInteraction textarea"); WebElement essayEl = browser.findElement(inputBy); essayEl.clear(); essayEl.sendKeys(text); return this; } public QTI21Page answerDrawing() { By drawingBy = By.className("drawingInteraction"); WebElement drawingEl = browser.findElement(drawingBy); new Actions(browser) .moveToElement(drawingEl, 30, 30) .clickAndHold() .moveByOffset(100, 200) .release() .build() .perform(); OOGraphene.waitingALittleBit(); return this; } public QTI21Page saveAnswer() { By saveAnswerBy = By.cssSelector("button.o_sel_assessment_item_submit"); browser.findElement(saveAnswerBy).click(); OOGraphene.waitBusy(browser); return this; } public QTI21Page nextAnswer() { By nextAnswerBy = By.cssSelector("button.o_sel_next_question"); browser.findElement(nextAnswerBy).click(); OOGraphene.waitBusy(browser); return this; } public QTI21Page assertFeedback(String title) { By feedbackBy = By.xpath("//div[contains(@class,'modalFeedback')]/h4[contains(text(),'" + title + "')]"); OOGraphene.waitElement(feedbackBy, 5, browser); return this; } public QTI21Page assertCorrectSolution(String title) { By feedbackBy = By.xpath("//div[contains(@class,'modalFeedback')]/h4/a[contains(text(),'" + title + "')]"); OOGraphene.waitElement(feedbackBy, 5, browser); return this; } public QTI21Page hint() { By hintBy = By.cssSelector("a.o_sel_assessment_item_hint"); browser.findElement(hintBy).click(); OOGraphene.waitBusy(browser); return this; } public QTI21Page endTestPart() { return endTest(); } public QTI21Page suspendTest() { By suspendBy = By.cssSelector("a.o_sel_suspend_test"); browser.findElement(suspendBy).click(); OOGraphene.waitBusy(browser); confirm(); return this; } public QTI21Page endTest() { By endBy = By.cssSelector("a.o_sel_end_testpart"); browser.findElement(endBy).click(); OOGraphene.waitBusy(browser); confirm(); return this; } public QTI21Page closeTest() { By closeBy = By.cssSelector("a.o_sel_close_test"); OOGraphene.waitElement(closeBy, 5, browser); browser.findElement(closeBy).click(); OOGraphene.waitBusy(browser); confirm(); return this; } /** * Close the report with the assessment results. * * @return Itself */ public QTI21Page closeAssessmentResults() { By closeBy = By.cssSelector("a.o_sel_close_results"); OOGraphene.waitElement(closeBy, 5, browser); browser.findElement(closeBy).click(); OOGraphene.waitBusy(browser); return this; } public QTI21Page showAssessmentResults() { By showBy = By.cssSelector("a.o_qti_show_assessment_results"); OOGraphene.waitElement(showBy, 5, browser); browser.findElement(showBy).click(); OOGraphene.waitBusy(browser); By hideBy = By.cssSelector("a.o_qti_hide_assessment_results"); OOGraphene.waitElement(hideBy, 5, browser); return this; } /** * This check specifically if the metadata of the test are visible. * * @return Itself */ public QTI21Page assertOnAssessmentResults() { By resultsBy = By.cssSelector("div.o_sel_results_details"); OOGraphene.waitElement(resultsBy, 5, browser); return this; } /** * This check specifically if the metadata of the test are visible. * * @param timeout * @return */ public QTI21Page assertOnAssessmentResults(int timeout) { By resultsBy = By.cssSelector("div.o_sel_results_details"); OOGraphene.waitElement(resultsBy, timeout, browser); return this; } public QTI21Page assertOnCourseAssessmentTestScore(int score) { By resultsBy = By.xpath("//div[contains(@class,'o_personal')]//tr[contains(@class,'o_score')]/td[contains(text(),'" + score + "')]"); OOGraphene.waitElement(resultsBy, 5, browser); return this; } public QTI21Page assertOnAssessmentTestScore(int score) { By resultsBy = By.xpath("//div[contains(@class,'o_sel_results_details')]//tr[contains(@class,'o_sel_assessmenttest_score')]/td[contains(text(),'" + score + "')]"); OOGraphene.waitElement(resultsBy, 5, browser); return this; } public QTI21Page assertOnAssessmentTestPassed() { By notPassedBy = By.cssSelector("div.o_sel_results_details tr.o_state.o_passed "); OOGraphene.waitElement(notPassedBy, 5, browser); return this; } public QTI21Page assertOnAssessmentTestNotPassed() { By notPassedBy = By.cssSelector("div.o_sel_results_details tr.o_state.o_failed "); OOGraphene.waitElement(notPassedBy, 5, browser); return this; } public QTI21Page assertOnAssessmentTestMaxScore(int score) { By resultsBy = By.xpath("//div[contains(@class,'o_sel_results_details')]//tr[contains(@class,'o_sel_assessmenttest_maxscore')]/td[contains(text(),'" + score + "')]"); OOGraphene.waitElement(resultsBy, 5, browser); 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 assertOnAssessmentResultEssay(String text) { By uploadBy = By.xpath("//div[contains(@class,'o_assessment_test_results')]//div[contains(@class,'extendedTextInteraction')]/textarea[contains(text(),'" + text + "')]"); OOGraphene.waitElement(uploadBy, 5, browser); return this; } public QTI21Page assertOnDrawing() { By drawingBy = By.className("drawingInteraction"); OOGraphene.waitElement(drawingBy, 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); List<WebElement> feedbackEls = browser.findElements(feedbackBy); Assert.assertEquals(1, feedbackEls.size()); return this; } /** * Check if the assessment terminated message is visible. * * @return Itself */ public QTI21Page assertOnAssessmentTestTerminated() { By terminatedBy = By.cssSelector("div.o_sel_assessment_test_terminated"); OOGraphene.waitElement(terminatedBy, 5, browser); return this; } /** * Check if the assessment terminated message is visible. * * @return Itself */ public QTI21Page assertOnAssessmentTestTerminated(int timeout) { By terminatedBy = By.cssSelector("div.o_sel_assessment_test_terminated"); OOGraphene.waitElement(terminatedBy, timeout, browser); return this; } /** * Yes in a dialog box controller. */ private void confirm() { // confirm By confirmButtonBy = By.cssSelector("div.modal-dialog div.modal-footer a"); OOGraphene.waitElement(confirmButtonBy, 5, browser); List<WebElement> buttonsEl = browser.findElements(confirmButtonBy); buttonsEl.get(0).click(); OOGraphene.waitBusy(browser); } public QTI21EditorPage edit() { if(!browser.findElement(toolsMenu).isDisplayed()) { openToolsMenu(); } By editBy = By.xpath("//ul[contains(@class,'o_sel_repository_tools')]//a[contains(@onclick,'edit.cmd')]"); browser.findElement(editBy).click(); OOGraphene.waitBusy(browser); QTI21EditorPage editor = new QTI21EditorPage(browser); editor.assertOnEditor(); return editor; } public QTI21OptionsPage options() { if(!browser.findElement(settingsMenu).isDisplayed()) { openSettingsMenu(); } By optionsBy = By.cssSelector("ul.o_sel_course_settings a.o_sel_qti_resource_options"); OOGraphene.waitElement(optionsBy, browser); browser.findElement(optionsBy).click(); OOGraphene.waitBusy(browser); return new QTI21OptionsPage(browser); } /** * Open the access configuration * * @return */ public RepositoryAccessPage accessConfiguration() { if(!browser.findElement(settingsMenu).isDisplayed()) { openSettingsMenu(); } By accessConfigBy = By.cssSelector("a.o_sel_course_access"); browser.findElement(accessConfigBy).click(); OOGraphene.waitBusy(browser); By mainId = By.id("o_main_container"); OOGraphene.waitElement(mainId, 5, browser); return new RepositoryAccessPage(browser); } /** * Click the editor link in the tools drop-down * @return */ public QTI21Page openToolsMenu() { By toolsMenuCaret = By.cssSelector("a.o_sel_repository_tools"); browser.findElement(toolsMenuCaret).click(); OOGraphene.waitElement(toolsMenu, browser); return this; } public QTI21Page openSettingsMenu() { By settingsMenuCaret = By.cssSelector("a.o_sel_course_settings"); OOGraphene.waitElement(settingsMenuCaret, browser); browser.findElement(settingsMenuCaret).click(); OOGraphene.waitElement(settingsMenu, browser); return this; } public QTI21Page clickToolbarBack() { OOGraphene.closeBlueMessageWindow(browser); browser.findElement(NavigationPage.toolbarBackBy).click(); OOGraphene.waitBusy(browser); return QTI21Page.getQTI12Page(browser); } }