/**
 * <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;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.UUID;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.page.InitialPage;
import org.jboss.arquillian.graphene.page.Page;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.olat.ims.qti21.QTI21AssessmentResultsOptions;
import org.olat.ims.qti21.model.xml.interactions.SimpleChoiceAssessmentItemBuilder.ScoreEvaluation;
import org.olat.selenium.page.LoginPage;
import org.olat.selenium.page.NavigationPage;
import org.olat.selenium.page.User;
import org.olat.selenium.page.course.CourseEditorPageFragment;
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.QTI21MultipleChoiceEditorPage;
import org.olat.selenium.page.qti.QTI21Page;
import org.olat.selenium.page.qti.QTI21SingleChoiceEditorPage;
import org.olat.selenium.page.repository.RepositoryAccessPage.UserAccess;
import org.olat.selenium.page.user.UserToolsPage;
import org.olat.test.ArquillianDeployments;
import org.olat.test.JunitTestHelper;
import org.olat.test.rest.UserRestClient;
import org.olat.user.restapi.UserVO;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

/**
 * 
 * Initial date: 03.05.2016<br>
 * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
 *
 */
@RunWith(Arquillian.class)
public class ImsQTI21Test {
	
	@Deployment(testable = false)
	public static WebArchive createDeployment() {
		return ArquillianDeployments.createDeployment();
	}

	@Drone
	private WebDriver browser;
	@ArquillianResource
	private URL deploymentUrl;
	@Page
	private NavigationPage navBar;
	
	/**
	 * Test the flow of the simplest possible test with our
	 * optimization (jump automatically to the next question,
	 * jump automatically the close test). The test has one
	 * part and 2 questions, no feedbacks, no review allowed...
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21TestFlow_noParts_noFeedbacks(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "With parts QTI 2.1 " + UUID.randomUUID();
		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/test_without_feedbacks.zip");
		File qtiTestFile = new File(qtiTestUrl.toURI());
		navBar
			.openAuthoringEnvironment()
			.uploadResource(qtiTestTitle, qtiTestFile)
			.clickToolbarRootCrumb();
		
		QTI21Page qtiPage = QTI21Page
				.getQTI12Page(browser);
		qtiPage
			.assertOnAssessmentItem()
			.answerSingleChoice("Incorrect response")
			.saveAnswer()
			.assertOnAssessmentItem("Second question")
			.selectItem("First question")
			.assertOnAssessmentItem("First question")
			.answerSingleChoice("Correct response")
			.saveAnswer()
			.answerMultipleChoice("Correct response")
			.saveAnswer()
			.endTest()//auto close because 1 part, no feedbacks
			.assertOnAssessmentTestTerminated();
	}
	
	/**
	 * Test the flow of a test with questions feedbacks and test
	 * feedback.
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21TestFlow_noParts_withFeedbacks(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "With parts QTI 2.1 " + UUID.randomUUID();
		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/test_with_feedbacks.zip");
		File qtiTestFile = new File(qtiTestUrl.toURI());
		navBar
			.openAuthoringEnvironment()
			.uploadResource(qtiTestTitle, qtiTestFile)
			.clickToolbarRootCrumb();
		
		QTI21Page qtiPage = QTI21Page
				.getQTI12Page(browser);
		qtiPage
			.assertOnAssessmentItem()
			.answerSingleChoice("Wrong answer")
			.saveAnswer()
			.assertFeedback("Oooops")
			.answerSingleChoice("Correct answer")
			.saveAnswer()
			.assertFeedback("Well done")
			.nextAnswer()
			.assertOnAssessmentItem("Numerical entry")
			.answerGapText("69", "_RESPONSE_1")
			.saveAnswer()
			.assertFeedback("Not really")
			.answerGapText("42", "_RESPONSE_1")
			.saveAnswer()
			.assertFeedback("Ok")
			.endTest()
			.assertOnAssessmentTestFeedback("All right")
			.closeTest()
			.assertOnAssessmentTestTerminated();
	}
	
	/**
	 * A test with a single part, feedback for questions and
	 * tests and the resource options "show results at the end
	 * of the test".
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21TestFlow_noParts_feedbacksAndResults(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "With parts QTI 2.1 " + UUID.randomUUID();
		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/test_with_feedbacks.zip");
		File qtiTestFile = new File(qtiTestUrl.toURI());
		navBar
			.openAuthoringEnvironment()
			.uploadResource(qtiTestTitle, qtiTestFile);
		
		QTI21Page qtiPage = QTI21Page
				.getQTI12Page(browser);
		qtiPage
			.clickToolbarBack()
			.options()
			.showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions())
			.save();
		
		qtiPage
			.clickToolbarBack()
			.assertOnAssessmentItem()
			.answerSingleChoice("Wrong answer")
			.saveAnswer()
			.assertFeedback("Oooops")
			.nextAnswer()
			.assertOnAssessmentItem("Numerical entry")
			.answerGapText("42", "_RESPONSE_1")
			.saveAnswer()
			.assertFeedback("Ok")
			.endTest()
			.assertOnAssessmentTestFeedback("Not for the best")
			.closeTest()
			.assertOnAssessmentTestMaxScore(2)
			.assertOnAssessmentTestScore(1)
			.assertOnAssessmentTestNotPassed();
	}
	
	/**
	 * A test with a single part, feedback for questions and
	 * tests and the resource options "show results at the end
	 * of the test".
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21TestFlow_parts_noFeedbacksButResults(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "With parts QTI 2.1 " + UUID.randomUUID();
		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/test_parts_without_feedbacks.zip");
		File qtiTestFile = new File(qtiTestUrl.toURI());
		navBar
			.openAuthoringEnvironment()
			.uploadResource(qtiTestTitle, qtiTestFile);
		
		QTI21Page qtiPage = QTI21Page
				.getQTI12Page(browser);
		qtiPage
			.clickToolbarBack()
			.options()
			.showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions())
			.save();
		
		qtiPage
			.clickToolbarBack()
			.startTestPart()
			.selectItem("First question")
			.assertOnAssessmentItem("First question")
			.answerSingleChoice("Correct")
			.saveAnswer()
			.assertOnAssessmentItem("Second question")
			.answerMultipleChoice("True")
			.saveAnswer()
			.endTestPart()
			.selectItem("Third question")
			.assertOnAssessmentItem("Third question")
			.answerMultipleChoice("Correct")
			.saveAnswer()
			.answerCorrectKPrim("True", "Right")
			.answerIncorrectKPrim("Wrong", "False")
			.saveAnswer()
			.endTestPart()
			.assertOnAssessmentTestMaxScore(4)
			.assertOnAssessmentTestScore(4)
			.assertOnAssessmentTestPassed();
	}
	
	/**
	 * Test with 2 parts and test feedbacks.
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21TestFlow_parts_feedbacks(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "With parts QTI 2.1 " + UUID.randomUUID();
		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/test_with_parts_and_test_feedbacks.zip");
		File qtiTestFile = new File(qtiTestUrl.toURI());
		navBar
			.openAuthoringEnvironment()
			.uploadResource(qtiTestTitle, qtiTestFile)
			.clickToolbarRootCrumb();
		
		QTI21Page qtiPage = QTI21Page
				.getQTI12Page(browser);

		qtiPage
			.startTestPart()
			.selectItem("First question")
			.assertOnAssessmentItem("First question")
			.answerSingleChoice("Correct answer")
			.saveAnswer()
			.assertOnAssessmentItem("Second question")
			.answerMultipleChoice("Valid answer")
			.saveAnswer()
			.endTestPart()
			.selectItem("Third question")
			.assertOnAssessmentItem("Third question")
			.answerSingleChoice("Right")
			.saveAnswer()
			.answerSingleChoice("Good")
			.saveAnswer()
			.endTestPart()
			.assertOnAssessmentTestFeedback("Well done")
			.closeTest()
			.assertOnAssessmentTestTerminated();
	}
	
	/**
	 * Test with time limit.
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21TestFlow_timeLimits(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "Timed QTI 2.1 " + UUID.randomUUID();
		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/test_time_limits.zip");
		File qtiTestFile = new File(qtiTestUrl.toURI());
		navBar
			.openAuthoringEnvironment()
			.uploadResource(qtiTestTitle, qtiTestFile)
			.clickToolbarRootCrumb();
		
		QTI21Page qtiPage = QTI21Page
				.getQTI12Page(browser);
		//check simple time limit
		qtiPage
			.assertOnAssessmentItem("Single choice")
			.answerSingleChoice("Correct answer")
			.saveAnswer()
			.assertOnAssessmentItem("Last choice")
			.answerSingleChoice("True")
			.saveAnswer()
			.assertOnAssessmentTestTerminated(15);
	}
	
	/**
	 * Test with time limit and wait for the results at the end.
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21TestFlow_timeLimits_results(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "Timed QTI 2.1 " + UUID.randomUUID();
		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/test_time_limits.zip");
		File qtiTestFile = new File(qtiTestUrl.toURI());
		navBar
			.openAuthoringEnvironment()
			.uploadResource(qtiTestTitle, qtiTestFile)
			.clickToolbarRootCrumb();
		
		QTI21Page qtiPage = QTI21Page
				.getQTI12Page(browser);
		qtiPage
			.options()
			.showResults(Boolean.TRUE, new QTI21AssessmentResultsOptions(true, true, false, false, false, false))
			.save();
		
		//check simple time limit
		qtiPage
			.clickToolbarBack()
			.assertOnAssessmentItem("Single choice")
			.answerSingleChoice("Correct answer")
			.saveAnswer()
			.assertOnAssessmentItem("Last choice")
			.answerSingleChoice("True")
			.saveAnswer()
			.assertOnAssessmentResults(15)
			.assertOnAssessmentTestPassed()
			.assertOnAssessmentTestMaxScore(2)
			.assertOnAssessmentTestScore(2);
	}
	
	/**
	 * Test suspend. An author upload a test, set "enable suspend"
	 * and make the test visible to registered users. A second user
	 * open the test, does nothing, suspends and log out (check a possible red
	 * screen in the next step), log in, answer 3 questions, suspends 
	 * and log out. It log in a last time and finish the test successfully.
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21TestFlow_suspend(@InitialPage LoginPage authorLoginPage,
			@Drone @User WebDriver ryomouBrowser)
	throws IOException, URISyntaxException {
		
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		UserVO ryomou = new UserRestClient(deploymentUrl).createRandomUser("Ryomou");
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "Suspend QTI 2.1 " + UUID.randomUUID();
		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/test_4_no_skipping.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())
			.enableSuspend()
			.save();
		
		qtiPage
			.accessConfiguration()
			.setUserAccess(UserAccess.registred)
			.clickToolbarBack();
		
		//check simple time limit
		qtiPage
			.assertOnAssessmentItem("Single choice");
		
		//a user search the content package
		LoginPage userLoginPage = LoginPage.getLoginPage(ryomouBrowser, deploymentUrl);
		userLoginPage
			.loginAs(ryomou.getLogin(), ryomou.getPassword())
			.resume();
		NavigationPage userNavBar = new NavigationPage(ryomouBrowser);
		userNavBar
			.openMyCourses()
			.openSearch()
			.extendedSearch(qtiTestTitle)
			.select(qtiTestTitle)
			.start();
		
		QTI21Page userQtiPage = QTI21Page
				.getQTI12Page(ryomouBrowser);
		userQtiPage
			.assertOnAssessmentItem("Single choice")
			.suspendTest();
		//log out
		new UserToolsPage(ryomouBrowser)
			.logout();
		
		//log in and resume test
		userLoginPage
			.loginAs(ryomou.getLogin(), ryomou.getPassword())
			.resume();
		userQtiPage = QTI21Page
				.getQTI12Page(ryomouBrowser);
		userQtiPage
			.assertOnAssessmentItem("Single choice")
			.answerSingleChoice("Correct")
			.saveAnswer()
			.answerMultipleChoice("Correct")
			.saveAnswer()
			.assertOnAssessmentItem("Kprim")
			.answerCorrectKPrim("True", "Right")
			.answerIncorrectKPrim("False", "Wrong")
			.saveAnswer()
			.suspendTest();
		
		//second log out
		new UserToolsPage(ryomouBrowser)
			.logout();
		
		//log in and resume test
		userLoginPage
			.loginAs(ryomou.getLogin(), ryomou.getPassword())
			.resume();
		userQtiPage = QTI21Page
				.getQTI12Page(ryomouBrowser);
		userQtiPage
			.assertOnAssessmentItem("Numerical input")
			.answerGapText("42", "_RESPONSE_1")
			.saveAnswer()
			.endTest()
			.assertOnAssessmentResults()
			.assertOnAssessmentTestMaxScore(4)
			.assertOnAssessmentTestScore(4)
			.assertOnAssessmentTestPassed();
	}
	
	/**
	 * Upload a test in QTI 2.1 format, create a course, bind
	 * the test in a course element, run it and check if
	 * the attempt go up.
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21Course(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "Simple QTI 2.1 " + UUID.randomUUID();
		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/simple_QTI_21_test.zip");
		File qtiTestFile = new File(qtiTestUrl.toURI());
		navBar
			.openAuthoringEnvironment()
			.uploadResource(qtiTestTitle, qtiTestFile);
		
		//create a course
		String courseTitle = "Course QTI 2.1 " + UUID.randomUUID();
		navBar
			.openAuthoringEnvironment()
			.createCourse(courseTitle)
			.clickToolbarBack();
		
		String testNodeTitle = "QTI21Test-1";
		
		//create a course element of type CP with the CP that we create above
		CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser)
			.edit();
		courseEditor
			.createNode("iqtest")
			.nodeTitle(testNodeTitle)
			.selectTabLearnContent()
			.chooseTest(qtiTestTitle);
		
		QTI21ConfigurationCEPage configPage = new QTI21ConfigurationCEPage(browser);
		configPage
			.selectConfiguration()
			.showScoreOnHomepage(true)
			.saveConfiguration();

		//publish the course
		courseEditor
			.publish()
			.quickPublish();
		
		//open the course and see the CP
		CoursePageFragment course = courseEditor
			.clickToolbarBack();
		
		course
			.clickTree()
			.selectWithTitle(testNodeTitle);
		
		//check that the title of the start page of test is correct
		WebElement testH2 = browser.findElement(By.cssSelector("div.o_course_run h2"));
		Assert.assertEquals(testNodeTitle, testH2.getText().trim());
		
		QTI21Page qtiPage = QTI21Page
				.getQTI12Page(browser);
		qtiPage
			.start()
			.answerSingleChoice("Right")
			.saveAnswer()
			.endTest()
			.assertOnCourseAttempts(1)
			.assertOnCourseAssessmentTestScore(1);
	}
	

	/**
	 * Upload a test in QTI 2.1 format, create a course, bind
	 * the test in a course element, customize the options
	 * with full window mode, show scores and assessment results.
	 * Then run it and check if the assessment results appears after
	 * closing the test and on the start page of the test course element.
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21Course_lmsHidden_results(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "Simple QTI 2.1 " + UUID.randomUUID();
		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/simple_QTI_21_test.zip");
		File qtiTestFile = new File(qtiTestUrl.toURI());
		navBar
			.openAuthoringEnvironment()
			.uploadResource(qtiTestTitle, qtiTestFile);
		
		//create a course
		String courseTitle = "Course QTI 2.1 " + UUID.randomUUID();
		navBar
			.openAuthoringEnvironment()
			.createCourse(courseTitle)
			.clickToolbarBack();
		
		String testNodeTitle = "QTI21Test-1";
		
		//create a course element of type CP with the CP that we create above
		CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser)
			.edit();
		courseEditor
			.createNode("iqtest")
			.nodeTitle(testNodeTitle)
			.selectTabLearnContent()
			.chooseTest(qtiTestTitle);
		
		QTI21ConfigurationCEPage configPage = new QTI21ConfigurationCEPage(browser);
		configPage
			.selectLayoutConfiguration()
			.overrideConfiguration()
			.fullWindow()
			.saveLayoutConfiguration();
		configPage
			.selectConfiguration()
			.showScoreOnHomepage(true)
			.showResultsOnHomepage(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions())
			.saveConfiguration();
		
		//publish the course
		courseEditor
			.publish()
			.quickPublish();
		
		//open the course and see the CP
		CoursePageFragment course = courseEditor
			.clickToolbarBack();
		
		course
			.clickTree()
			.selectWithTitle(testNodeTitle);
		
		//check that the title of the start page of test is correct
		WebElement testH2 = browser.findElement(By.cssSelector("div.o_course_run h2"));
		Assert.assertEquals(testNodeTitle, testH2.getText().trim());
		
		QTI21Page qtiPage = QTI21Page
				.getQTI12Page(browser);
		qtiPage
			.start()
			.answerSingleChoice("Right")
			.saveAnswer()
			.endTest()
			.assertOnAssessmentResults()
			.closeAssessmentResults()
			.assertOnCourseAttempts(1)
			.assertOnCourseAssessmentTestScore(1)
			.showAssessmentResults()
			.assertOnAssessmentResults();
	}
	
	/**
	 * Check if the hotspot interaction send a "correct" feedback.
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21GraphicInteraction(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "Simple 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
			.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()
			.answerHotspot("circle")
			.saveAnswer()
			.assertFeedback("Correct!")
			.endTest();
		//check the results
		qtiPage
			.assertOnAssessmentResults()
			.assertOnAssessmentTestScore(1)
			.assertOnAssessmentTestMaxScore(1);
	}
	
	/**
	 * Create a test, import the CSV example, remove the
	 * first single choice which come if someone create a
	 * test. Change the delivery settings of the test to
	 * show the detailled results.<br>
	 * Run the test and check the results. 
	 * 
	 * @param loginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void importQuestionsCSV(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "Excel QTI 2.1 " + UUID.randomUUID();
		navBar
			.openAuthoringEnvironment()
			.createQTI21Test(qtiTestTitle)
			.clickToolbarBack();

		QTI21Page qtiPage = QTI21Page
			.getQTI12Page(browser);
		QTI21EditorPage qtiEditor = qtiPage
			.edit();
		
		// import a single choice, a multiple and 2 gap texts
		qtiEditor
			.importTable()
			.importFile("qti21/import_qti21_excel.txt")
			.next()
			.assertOnNumberOfQuestions(5)
			.finish();
		
		//remove the single choice which come from the creation
		// of the test
		qtiEditor
			.selectNode("Single choice")
			.deleteNode();
		
		// go to options and show the results
		qtiPage
			.clickToolbarBack()
			.options()
			.showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions())
			.save();
		
		//go to the test
		qtiPage
			.clickToolbarBack()
			.assertOnAssessmentItem()
			.answerGapText("verbannen", "_RESPONSE_1")
			.saveAnswer()
			.nextAnswer()
			.answerGapText(",", "_RESPONSE_1")
			.answerGapText("", "_RESPONSE_2")
			.answerGapText("", "_RESPONSE_3")
			.saveAnswer()
			.answerMultipleChoice("Deutschland", "Brasilien", "S\u00FCdafrika")
			.saveAnswer()
			.answerSingleChoice("Italien")
			.saveAnswer()
			.answerCorrectKPrim("Deutschland", "Uruguay")
			.answerIncorrectKPrim("Frankreich", "Spanien")
			.saveAnswer()
			.endTest();
		
		//check the results
		qtiPage
			.assertOnAssessmentResults()
			.assertOnAssessmentTestScore(9)
			.assertOnAssessmentTestMaxScore(9);
	}
	

	/**
	 * Upload a test in QTI 2.1 format, create a course, bind
	 * the test in a course element, customize the options
	 * with full window mode, allow suspending the test,
	 * show scores and assessment results.<br>
	 * Then run it and at the middle of the test, suspend it, log out.
	 * Return with resume to the course and resume the test, finish it
	 * and check if the assessment results appears after
	 * closing the test and on the start page of the test course element.
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21Course_suspend(@InitialPage LoginPage authorLoginPage)
	throws IOException, URISyntaxException {
		
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload a test
		String qtiTestTitle = "No skipping QTI 2.1 " + UUID.randomUUID();
		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/qti21/test_4_no_skipping.zip");
		File qtiTestFile = new File(qtiTestUrl.toURI());
		navBar
			.openAuthoringEnvironment()
			.uploadResource(qtiTestTitle, qtiTestFile);
		
		//create a course
		String courseTitle = "Course QTI 2.1 " + UUID.randomUUID();
		navBar
			.openAuthoringEnvironment()
			.createCourse(courseTitle)
			.clickToolbarBack();
		
		String testNodeTitle = "QTI21Test-1";
		
		//create a course element of type CP with the CP that we create above
		CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser)
			.edit();
		courseEditor
			.createNode("iqtest")
			.nodeTitle(testNodeTitle)
			.selectTabLearnContent()
			.chooseTest(qtiTestTitle);
		
		QTI21ConfigurationCEPage configPage = new QTI21ConfigurationCEPage(browser);
		configPage
			.selectLayoutConfiguration()
			.overrideConfiguration()
			.fullWindow()
			.saveLayoutConfiguration();
		configPage
			.selectConfiguration()
			.showScoreOnHomepage(true)
			.showResultsOnHomepage(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions())
			.saveConfiguration()
			.selectLayoutConfiguration()
			.overrideConfiguration()
			.enableSuspend()
			.saveLayoutConfiguration();
		
		//publish the course
		courseEditor
			.publish()
			.quickPublish();
		
		//open the course and see the CP
		CoursePageFragment course = courseEditor
			.clickToolbarBack();
		
		course
			.clickTree()
			.selectWithTitle(testNodeTitle);
		
		//check that the title of the start page of test is correct
		WebElement testH2 = browser.findElement(By.cssSelector("div.o_course_run h2"));
		Assert.assertEquals(testNodeTitle, testH2.getText().trim());
		
		QTI21Page qtiPage = QTI21Page
				.getQTI12Page(browser);
		qtiPage
			.start()
			.answerSingleChoice("Correct")
			.saveAnswer()
			.answerMultipleChoice("Correct")
			.saveAnswer()
			.suspendTest();
		
		//log out
		new UserToolsPage(browser)
			.logout();
		// return
		authorLoginPage
			.loginAs(author.getLogin(), author.getPassword())
			.resume();
		//resume the course, resume the test
		qtiPage = QTI21Page
				.getQTI12Page(browser);
		qtiPage
			.start()
			.assertOnAssessmentItem("Kprim")
			.answerCorrectKPrim("True", "Right")
			.answerIncorrectKPrim("False", "Wrong")
			.saveAnswer()
			.answerGapText("43", "_RESPONSE_1")
			.saveAnswer()
			.endTest()
			.assertOnAssessmentResults()
			.assertOnAssessmentTestMaxScore(4)
			.assertOnAssessmentTestScore(4)
			.assertOnAssessmentTestPassed()
			.closeAssessmentResults();
		//check the result on the start page
		qtiPage
			.assertOnCourseAssessmentTestScore(4)
			.assertOnCourseAttempts(1);
	}
	
	/**
	 * Test different settings in the single choice editor. An author
	 * make a test with 2 single choices, one with score all answer correct,
	 * the second with score per answer and feedbacks.<br>
	 * A second user make the test and check the score at the end of
	 * the test.
	 * 
	 * @param authorLoginPage
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	@Test
	@RunAsClient
	public void qti21EditorSingleChoices(@InitialPage LoginPage authorLoginPage,
			@Drone @User WebDriver ryomouBrowser)
	throws IOException, URISyntaxException {
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		UserVO ryomou = new UserRestClient(deploymentUrl).createRandomUser("Ryomou");
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload 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 a single choice: all answers score
		QTI21SingleChoiceEditorPage scEditor = qtiEditor
			.addSingleChoice();
		scEditor
			.setAnswer(0, "Wrong")
			.addChoice(1)
			.setCorrect(1)
			.setAnswer(1, "Correct")
			.addChoice(2)
			.setAnswer(2, "Faux")
			.addChoice(3)
			.setAnswer(3, "Falsch")
			.save();
		// change max score
		scEditor
			.selectScores()
			.setMaxScore("3")
			.save();
		// set some feedbacks
		scEditor
			.selectFeedbacks()
			.setHint("Hint", "This is only an hint")
			.setCorrectSolution("Correct solution", "This is the correct solution")
			.setCorrectFeedback("Correct feedback", "This is correct")
			.setIncorrectFeedback("Incorrect", "Your answer is not correct")
			.save();
		
		//score per answers
		scEditor = qtiEditor
			.addSingleChoice()
			.setAnswer(0, "AlmostRight")
			.addChoice(1)
			.setAnswer(1, "NotRight")
			.addChoice(2)
			.setCorrect(2)
			.setAnswer(2, "RightAnswer")
			.addChoice(3)
			.setAnswer(3, "TheWrongOne")
			.save();
		scEditor
			.selectScores()
			.setMaxScore("2")
			.selectAssessmentMode(ScoreEvaluation.perAnswer)
			.setScore("Almost", "1")
			.setScore("NotRight", "0")
			.setScore("RightAnswer", "2")
			.setScore("TheWrongOne", "0")
			.save();
		scEditor
			.selectFeedbacks()
			.setHint("Hint", "The hint")
			.setCorrectSolution("Correct solution", "This is the correct solution")
			.setCorrectFeedback("Correct feedback", "This 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(ryomouBrowser, deploymentUrl);
		userLoginPage
			.loginAs(ryomou.getLogin(), ryomou.getPassword())
			.resume();
		NavigationPage userNavBar = new NavigationPage(ryomouBrowser);
		userNavBar
			.openMyCourses()
			.openSearch()
			.extendedSearch(qtiTestTitle)
			.select(qtiTestTitle)
			.start();
		
		// make the test
		QTI21Page ryomouQtiPage = QTI21Page
				.getQTI12Page(ryomouBrowser);
		ryomouQtiPage
			.assertOnAssessmentItem()
			.answerSingleChoice("Falsch")
			.saveAnswer()
			.assertFeedback("Incorrect")
			.assertCorrectSolution("Correct solution")
			.hint()
			.assertFeedback("Hint")
			.answerSingleChoice("Correct")
			.saveAnswer()
			.assertFeedback("Correct feedback")
			.nextAnswer()
			.answerSingleChoice("Almost")
			.saveAnswer()
			.assertCorrectSolution("Correct solution")
			.assertFeedback("Incorrect")
			.endTest()
			.assertOnAssessmentResults()
			.assertOnAssessmentTestScore(4);// 3 points from the first question, 1 from the second
	}
	
	/**
	 * An author make a test with 2 multiple choices, the first
	 * with the score set if all answers are correct, the second
	 * with scoring per answers.<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 qti21EditorMultipleChoices(@InitialPage LoginPage authorLoginPage,
			@Drone @User WebDriver participantBrowser)
	throws IOException, URISyntaxException {
		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
		UserVO ryomou = new UserRestClient(deploymentUrl).createRandomUser("Ryomou");
		UserVO eric = new UserRestClient(deploymentUrl).createRandomUser("Eric");
		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
		
		//upload 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 a single choice: all answers score
		QTI21MultipleChoiceEditorPage mcEditor = qtiEditor
			.addMultipleChoice();
		mcEditor
			.setAnswer(0, "Correct")
			.setCorrect(0)
			.addChoice(1)
			.setCorrect(1)
			.setAnswer(1, "OkToo")
			.addChoice(2)
			.setAnswer(2, "Faux")
			.addChoice(3)
			.setAnswer(3, "Falsch")
			.save();
		// change max score
		mcEditor
			.selectScores()
			.setMaxScore("3")
			.save();
		// set some feedbacks
		mcEditor
			.selectFeedbacks()
			.setHint("Hint", "This is only an hint")
			.setCorrectSolution("Correct solution", "This is the correct solution")
			.setCorrectFeedback("Correct feedback", "This is correct")
			.setIncorrectFeedback("Incorrect", "Your answer is not correct")
			.save();
		
		//score per answers
		mcEditor = qtiEditor
			.addMultipleChoice()
			.setCorrect(0)
			.setAnswer(0, "AlmostRight")
			.addChoice(1)
			.setAnswer(1, "NotRight")
			.addChoice(2)
			.setCorrect(2)
			.setAnswer(2, "RightAnswer")
			.addChoice(3)
			.setAnswer(3, "TheWrongOne")
			.save();
		mcEditor
			.selectScores()
			.setMaxScore("3")
			.selectAssessmentMode(ScoreEvaluation.perAnswer)
			.setScore("AlmostRight", "1")
			.setScore("NotRight", "0")
			.setScore("RightAnswer", "2")
			.setScore("TheWrongOne", "0")
			.save();
		mcEditor
			.selectFeedbacks()
			.setHint("Hint", "The hint")
			.setCorrectSolution("Correct solution", "This is the correct solution")
			.setCorrectFeedback("Correct feedback", "This 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();
		
		// make the test
		QTI21Page ryomouQtiPage = QTI21Page
				.getQTI12Page(participantBrowser);
		ryomouQtiPage
			.assertOnAssessmentItem()
			.answerMultipleChoice("Falsch")
			.answerMultipleChoice("OkToo")
			.saveAnswer()
			.assertFeedback("Incorrect")
			.assertCorrectSolution("Correct solution")
			.hint()
			.assertFeedback("Hint")
			.answerMultipleChoice("Falsch")
			.answerMultipleChoice("Correct")
			.saveAnswer()
			.assertFeedback("Correct feedback")
			.nextAnswer()
			.answerMultipleChoice("AlmostRight")
			.saveAnswer()
			.assertCorrectSolution("Correct solution")
			.assertFeedback("Incorrect")
			.endTest()
			.assertOnAssessmentResults()
			.assertOnAssessmentTestScore(4);// 3 points from the first question, 1 from the second
		

		//a second user search the content package
		LoginPage ericLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl);
		ericLoginPage
			.loginAs(eric.getLogin(), eric.getPassword())
			.resume();
		NavigationPage ericNavBar = new NavigationPage(participantBrowser);
		ericNavBar
			.openMyCourses()
			.openSearch()
			.extendedSearch(qtiTestTitle)
			.select(qtiTestTitle)
			.start();
		
		// make the test
		QTI21Page
			.getQTI12Page(participantBrowser)
			.assertOnAssessmentItem()
			.answerMultipleChoice("Correct", "OkToo")
			.saveAnswer()
			.assertFeedback("Correct feedback")
			.nextAnswer()
			.answerMultipleChoice("AlmostRight", "RightAnswer")
			.saveAnswer()
			.endTest()
			.assertOnAssessmentResults()
			.assertOnAssessmentTestScore(6);// 3 points from the first question, 3 from the second
	}
}