diff --git a/src/test/java/org/olat/selenium/AssessmentTest.java b/src/test/java/org/olat/selenium/AssessmentTest.java
index 8ba2b269c9e0e56bc8f23ef9771f713a31eab17f..38ffea5ff450da2f267170b6ec3f7cc03ee0be05 100644
--- a/src/test/java/org/olat/selenium/AssessmentTest.java
+++ b/src/test/java/org/olat/selenium/AssessmentTest.java
@@ -34,7 +34,7 @@ import org.jboss.arquillian.test.api.ArquillianResource;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.olat.course.learningpath.FullyAssessedTrigger;
+import org.olat.repository.RepositoryEntryStatusEnum;
 import org.olat.repository.model.SingleRoleRepositoryEntrySecurity.Role;
 import org.olat.selenium.page.LoginPage;
 import org.olat.selenium.page.NavigationPage;
@@ -55,6 +55,8 @@ import org.olat.selenium.page.course.MembersPage;
 import org.olat.selenium.page.graphene.OOGraphene;
 import org.olat.selenium.page.group.GroupPage;
 import org.olat.selenium.page.qti.QTI12Page;
+import org.olat.selenium.page.qti.QTI21Page;
+import org.olat.selenium.page.repository.RepositoryEditDescriptionPage;
 import org.olat.selenium.page.repository.ScormPage;
 import org.olat.selenium.page.repository.UserAccess;
 import org.olat.selenium.page.user.UserToolsPage;
@@ -807,6 +809,154 @@ public class AssessmentTest extends Deployments {
 			.selectStatementSegment()
 			.assertOnCourseDetails(testNodeTitle, true);
 	}
+
+	/**
+	 * This tests a course with cascading rules and expert rules
+	 * to calculate if the course is passed and generate a
+	 * certificate. 
+	 * 
+	 * @param loginPage
+	 */
+	@Test
+	@RunAsClient
+	public void certificatesGeneratedWithCascadingRules()
+	throws IOException, URISyntaxException {
+		
+		UserVO author = new UserRestClient(deploymentUrl).createRandomAuthor();
+		UserVO participant1 = new UserRestClient(deploymentUrl).createRandomUser("Ryomou");
+		UserVO participant2 = new UserRestClient(deploymentUrl).createRandomUser("Rei");
+
+		LoginPage loginPage = LoginPage.load(browser, deploymentUrl);
+		loginPage.loginAs(author.getLogin(), author.getPassword());
+		
+		URL zipUrl = JunitTestHelper.class.getResource("file_resources/course_certificates_exrules.zip");
+		File zipFile = new File(zipUrl.toURI());
+		//go the authoring environment to import our course
+		String zipTitle = "Certif - " + UUID.randomUUID();
+		NavigationPage navBar = NavigationPage.load(browser);
+		navBar
+			.openAuthoringEnvironment()
+			.uploadResource(zipTitle, zipFile);
+		
+		// publish the course
+		new RepositoryEditDescriptionPage(browser)
+			.clickToolbarBack();
+		CoursePageFragment course = CoursePageFragment.getCourse(browser)
+				.edit()
+				.autoPublish();
+		
+		// add a participant
+		MembersPage members = course
+			.members();
+		members
+			.importMembers()
+			.setMembers(participant1, participant2)
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
+		members
+			.clickToolbarBack();
+		
+		course
+			.settings()
+			.accessConfiguration()
+			.setUserAccess(UserAccess.registred)
+			.save()
+			.clickToolbarBack();
+		
+		course
+			.changeStatus(RepositoryEntryStatusEnum.published);
+	
+		//log out
+		new UserToolsPage(browser)
+			.logout();
+		
+		// participant log in and go directly to the first test
+		LoginPage participantLoginPage = LoginPage.load(browser, deploymentUrl);
+		
+		participantLoginPage
+			.loginAs(participant1.getLogin(), participant1.getPassword())
+			.resume();
+		
+		//open the course
+		NavigationPage participantNavBar = NavigationPage.load(browser);
+		participantNavBar
+			.openMyCourses()
+			.select(zipTitle);
+		
+		//go to the test
+		CoursePageFragment certificationCourse = new CoursePageFragment(browser);
+		certificationCourse
+			.clickTree()
+			.assertWithTitleSelected("Test 1");
+		//pass the test
+		QTI21Page.getQTI21Page(browser)
+			.passE4()
+			.assertOnCourseAssessmentTestScore(4);
+		
+		OOGraphene.waitingALittleLonger();
+		
+		//open the efficiency statements
+		String certificateTitle = "Certificates" + zipTitle;
+		UserToolsPage participantUserTools = new UserToolsPage(browser);
+		participantUserTools
+			.openUserToolsMenu()
+			.openMyEfficiencyStatement()
+			.assertOnEfficiencyStatmentPage()
+			.assertOnCertificateAndStatements(certificateTitle)
+			.selectStatement(certificateTitle)
+			.selectStatementSegment()
+			.assertOnCourseDetails("CertificatesCert", true)
+			.assertOnCourseDetails("Struktur 1", true)
+			.assertOnCourseDetails("Test 1", true);
+		
+		//log out
+		new UserToolsPage(browser)
+			.logout();
+		
+		
+		// participant 2 log in and go directly to the second test
+		LoginPage participant2LoginPage = LoginPage.load(browser, deploymentUrl);
+		
+		participant2LoginPage
+			.loginAs(participant2.getLogin(), participant2.getPassword())
+			.resume();
+		
+		//open the course
+		NavigationPage participant2NavBar = NavigationPage.load(browser);
+		participant2NavBar
+			.openMyCourses()
+			.select(zipTitle);
+		
+		//go to the test
+		CoursePageFragment certification2Course = new CoursePageFragment(browser);
+		certification2Course
+			.clickTree()
+			.selectWithTitle("Struktur 3")
+			.assertWithTitleSelected("Struktur 3")
+			.assertWithTitle("Test 3")
+			.selectWithTitle("Test 3");
+		//pass the test
+		QTI21Page.getQTI21Page(browser)
+			.passE4()
+			.assertOnCourseAssessmentTestScore(4);
+		
+		OOGraphene.waitingALittleLonger();
+		
+		//open the efficiency statements
+		UserToolsPage participant2UserTools = new UserToolsPage(browser);
+		participant2UserTools
+			.openUserToolsMenu()
+			.openMyEfficiencyStatement()
+			.assertOnEfficiencyStatmentPage()
+			.assertOnCertificateAndStatements(certificateTitle)
+			.selectStatement(certificateTitle)
+			.selectStatementSegment()
+			.assertOnCourseDetails("CertificatesCert", true)
+			.assertOnCourseDetails("Struktur 3", true)
+			.assertOnCourseDetails("Test 3", true);
+	}
 	
 	/**
 	 * An author create a course with an assessment course element with
@@ -2114,107 +2264,4 @@ public class AssessmentTest extends Deployments {
 			.openSolutions()
 			.assertSolution("solution_1.txt");
 	}
-	
-	/**
-	 * This is a degenerated form of task but the case exists.
-	 * An author creates a course (learn path) with a task course
-	 * element. The task is configured to only show the solution,
-	 * and the course element to be passed if the task is done. In
-	 * this case, the participant only need to see the solution to
-	 * get the node done.
-	 * 
-	 * @param participantBrowser Browser of the participant
-	 * @throws IOException
-	 * @throws URISyntaxException
-	 */
-	@Test
-	@RunAsClient
-	public void taskLearnPathSolutionsOnly(@Drone @User WebDriver participantBrowser)
-	throws IOException, URISyntaxException {
-		
-		UserVO author = new UserRestClient(deploymentUrl).createRandomAuthor();
-		UserVO participant = new UserRestClient(deploymentUrl).createRandomUser("kanu");
-		
-		LoginPage authorLoginPage = LoginPage.load(browser, deploymentUrl);
-		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
-		
-		//create a course
-		String courseTitle = "Course-with-auto-task-" + UUID.randomUUID();
-		NavigationPage navBar = NavigationPage.load(browser);
-		navBar
-			.openAuthoringEnvironment()
-			.createCourse(courseTitle, true)
-			.clickToolbarBack();
-
-		//create a course element of type Test with the test that we create above
-		String gtaNodeTitle = "Solution 1";
-		CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser)
-			.edit();
-		courseEditor
-			.createNode("ita")
-			.nodeTitle(gtaNodeTitle);
-		
-		courseEditor
-			.selectTabLearnPath()
-			.setCompletionCriterion(FullyAssessedTrigger.statusDone)
-			.save();
-		
-		GroupTaskConfigurationPage gtaConfig = new GroupTaskConfigurationPage(browser);
-		gtaConfig
-			.selectWorkflow()
-			.enableAssignment(false)
-			.enableSubmission(false)
-			.enableReview(false)
-			.enableGrading(false)
-			.saveWorkflow();
-		
-		URL solutionUrl = JunitTestHelper.class.getResource("file_resources/solution_1.txt");
-		File solutionFile = new File(solutionUrl.toURI());
-		gtaConfig
-			.selectSolution()
-			.uploadSolution("A possible solution", solutionFile);
-		
-		courseEditor
-			.publish()
-			.quickPublish(UserAccess.membersOnly);
-		
-
-		MembersPage membersPage = courseEditor
-			.clickToolbarBack()
-			.members();
-		
-		membersPage
-			.importMembers()
-			.setMembers(participant)
-			.nextUsers()
-			.nextOverview()
-			.nextPermissions()
-			.finish();
-		
-		//Participant log in
-		LoginPage participantLoginPage = LoginPage.load(participantBrowser, deploymentUrl);
-		participantLoginPage
-			.loginAs(participant)
-			.resume();
-		
-		//open the course
-		NavigationPage participantNavBar = NavigationPage.load(participantBrowser);
-		participantNavBar
-			.openMyCourses()
-			.select(courseTitle);
-		
-		//go to the group task
-		CoursePageFragment participantCourse = new CoursePageFragment(participantBrowser);
-		participantCourse
-			.clickTree()
-			.selectWithTitle(gtaNodeTitle);
-		
-		GroupTaskPage participantTask = new GroupTaskPage(participantBrowser);
-		participantTask
-			.openSolutions()
-			.assertSolution("solution_1.txt");
-		// seeing the solution got the job done
-		participantCourse
-			.assertOnLearnPathNodeDone(gtaNodeTitle);
-	}
 }
diff --git a/src/test/java/org/olat/selenium/CourseLearnPathTest.java b/src/test/java/org/olat/selenium/CourseLearnPathTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..adcc2e7b1042927d8c173f18d010d680c443fa96
--- /dev/null
+++ b/src/test/java/org/olat/selenium/CourseLearnPathTest.java
@@ -0,0 +1,295 @@
+/**
+ * <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.RunAsClient;
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.olat.course.learningpath.FullyAssessedTrigger;
+import org.olat.selenium.page.LoginPage;
+import org.olat.selenium.page.NavigationPage;
+import org.olat.selenium.page.User;
+import org.olat.selenium.page.core.MenuTreePageFragment;
+import org.olat.selenium.page.course.CourseEditorPageFragment;
+import org.olat.selenium.page.course.CoursePageFragment;
+import org.olat.selenium.page.course.GroupTaskConfigurationPage;
+import org.olat.selenium.page.course.GroupTaskPage;
+import org.olat.selenium.page.course.MembersPage;
+import org.olat.selenium.page.course.SinglePageConfigurationPage;
+import org.olat.selenium.page.repository.UserAccess;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.rest.UserRestClient;
+import org.olat.user.restapi.UserVO;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * Test specifically features of the course in learn path mode.
+ * 
+ * Initial date: 8 juin 2020<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@RunWith(Arquillian.class)
+public class CourseLearnPathTest extends Deployments {
+	
+	@Drone
+	private WebDriver browser;
+	@ArquillianResource
+	private URL deploymentUrl;
+	
+
+	/**
+	 * This is a course with learn path, three course elements,
+	 * two to confirm, one to visit. The author creates the course
+	 * and a user play it until 100% done.
+	 * 
+	 * @param participantBrowser Browser of the participant
+	 * @throws IOException
+	 * @throws URISyntaxException
+	 */
+	@Test
+	@RunAsClient
+	public void learnPathConfirmationAndVisitedFlow(@Drone @User WebDriver participantBrowser)
+	throws IOException, URISyntaxException {
+		
+		UserVO author = new UserRestClient(deploymentUrl).createRandomAuthor();
+		UserVO participant = new UserRestClient(deploymentUrl).createRandomUser("kanu");
+		
+		LoginPage authorLoginPage = LoginPage.load(browser, deploymentUrl);
+		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
+		
+		//create a course
+		String courseTitle = "Course-with-auto-task-" + UUID.randomUUID();
+		NavigationPage navBar = NavigationPage.load(browser);
+		navBar
+			.openAuthoringEnvironment()
+			.createCourse(courseTitle, true)
+			.clickToolbarBack();
+
+		//create a course element of type single page
+		String firstNodeTitle = "First page";
+		CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser)
+			.edit();
+		courseEditor
+			.createNode("sp")
+			.nodeTitle(firstNodeTitle);
+		
+		String content = "A new single page with some content";
+		SinglePageConfigurationPage spConfiguration = new SinglePageConfigurationPage(browser);
+		spConfiguration
+			.selectConfiguration()
+			.newDefaultPage(content)
+			.assertOnPreview();
+		
+		courseEditor
+			.selectTabLearnPath()
+			.setCompletionCriterion(FullyAssessedTrigger.confirmed)
+			.save();
+		
+		// create a second element, a forum
+		String forumNodeTitle = "Forum discussion";
+		courseEditor
+			.createNode("fo")
+			.nodeTitle(forumNodeTitle)
+			.selectTabLearnPath()
+			.setCompletionCriterion(FullyAssessedTrigger.confirmed)
+			.save();
+		
+		// create a third element, an info message
+		String infosNodeTitle = "Informations";
+		courseEditor
+			.createNode("info")
+			.nodeTitle(infosNodeTitle)
+			.selectTabLearnPath()
+			.setCompletionCriterion(FullyAssessedTrigger.nodeVisited)
+			.save();
+		
+		courseEditor
+			.autoPublish()
+			.publish()
+			.members()
+			.importMembers()
+			.setMembers(participant)
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
+		
+		//Participant log in
+		LoginPage participantLoginPage = LoginPage.load(participantBrowser, deploymentUrl);
+		participantLoginPage
+			.loginAs(participant)
+			.resume();
+		
+		//open the course
+		NavigationPage participantNavBar = NavigationPage.load(participantBrowser);
+		participantNavBar
+			.openMyCourses()
+			.select(courseTitle);
+		
+		//go to the group task
+		CoursePageFragment participantCourse = new CoursePageFragment(participantBrowser);
+		MenuTreePageFragment menuTree = participantCourse
+			.clickTree()
+			.selectWithTitle(firstNodeTitle);
+		participantCourse
+			.assertOnLearnPathNodeReady(firstNodeTitle)
+			.confirmNode()
+			.assertOnLearnPathNodeDone(firstNodeTitle)
+			.assertOnLearnPathNodeInProgress(courseTitle)
+			.assertOnLearnPathNodeReady(forumNodeTitle)
+			.assertOnLearnPathNodeNotAccessible(infosNodeTitle);
+		
+		// confirm second node
+		menuTree
+			.selectWithTitle(forumNodeTitle)
+			.assertWithTitleSelected(forumNodeTitle);
+		participantCourse
+			.confirmNode()
+			.assertOnLearnPathNodeDone(forumNodeTitle)
+			.assertOnLearnPathNodeInProgress(courseTitle)
+			.assertOnLearnPathNodeReady(infosNodeTitle);
+
+		// see the third node
+		menuTree
+			.selectWithTitle(infosNodeTitle)
+			.assertWithTitleSelected(infosNodeTitle);
+		participantCourse
+			.assertOnLearnPathNodeDone(infosNodeTitle)
+			.assertOnLearnPathNodeDone(firstNodeTitle)
+			.assertOnLearnPathNodeDone(forumNodeTitle)
+			.assertOnLearnPathNodeDone(courseTitle)
+			.assertOnLearnPathPercent(100);
+	}
+	
+
+	/**
+	 * This is a degenerated form of task but the case exists.
+	 * An author creates a course (learn path) with a task course
+	 * element. The task is configured to only show the solution,
+	 * and the course element to be passed if the task is done. In
+	 * this case, the participant only need to see the solution to
+	 * get the node done.
+	 * 
+	 * @param participantBrowser Browser of the participant
+	 * @throws IOException
+	 * @throws URISyntaxException
+	 */
+	@Test
+	@RunAsClient
+	public void taskLearnPathSolutionsOnly(@Drone @User WebDriver participantBrowser)
+	throws IOException, URISyntaxException {
+		
+		UserVO author = new UserRestClient(deploymentUrl).createRandomAuthor();
+		UserVO participant = new UserRestClient(deploymentUrl).createRandomUser("kanu");
+		
+		LoginPage authorLoginPage = LoginPage.load(browser, deploymentUrl);
+		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
+		
+		//create a course
+		String courseTitle = "Course-with-auto-task-" + UUID.randomUUID();
+		NavigationPage navBar = NavigationPage.load(browser);
+		navBar
+			.openAuthoringEnvironment()
+			.createCourse(courseTitle, true)
+			.clickToolbarBack();
+
+		//create a course element of type Test with the test that we create above
+		String gtaNodeTitle = "Solution 1";
+		CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser)
+			.edit();
+		courseEditor
+			.createNode("ita")
+			.nodeTitle(gtaNodeTitle);
+		
+		courseEditor
+			.selectTabLearnPath()
+			.setCompletionCriterion(FullyAssessedTrigger.statusDone)
+			.save();
+		
+		GroupTaskConfigurationPage gtaConfig = new GroupTaskConfigurationPage(browser);
+		gtaConfig
+			.selectWorkflow()
+			.enableAssignment(false)
+			.enableSubmission(false)
+			.enableReview(false)
+			.enableGrading(false)
+			.saveWorkflow();
+		
+		URL solutionUrl = JunitTestHelper.class.getResource("file_resources/solution_1.txt");
+		File solutionFile = new File(solutionUrl.toURI());
+		gtaConfig
+			.selectSolution()
+			.uploadSolution("A possible solution", solutionFile);
+		
+		courseEditor
+			.publish()
+			.quickPublish(UserAccess.membersOnly);
+		
+
+		MembersPage membersPage = courseEditor
+			.clickToolbarBack()
+			.members();
+		
+		membersPage
+			.importMembers()
+			.setMembers(participant)
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
+		
+		//Participant log in
+		LoginPage participantLoginPage = LoginPage.load(participantBrowser, deploymentUrl);
+		participantLoginPage
+			.loginAs(participant)
+			.resume();
+		
+		//open the course
+		NavigationPage participantNavBar = NavigationPage.load(participantBrowser);
+		participantNavBar
+			.openMyCourses()
+			.select(courseTitle);
+		
+		//go to the group task
+		CoursePageFragment participantCourse = new CoursePageFragment(participantBrowser);
+		participantCourse
+			.clickTree()
+			.selectWithTitle(gtaNodeTitle);
+		
+		GroupTaskPage participantTask = new GroupTaskPage(participantBrowser);
+		participantTask
+			.openSolutions()
+			.assertSolution("solution_1.txt");
+		// seeing the solution got the job done
+		participantCourse
+			.assertOnLearnPathNodeDone(gtaNodeTitle);
+	}
+
+}
diff --git a/src/test/java/org/olat/selenium/CourseTest.java b/src/test/java/org/olat/selenium/CourseTest.java
index d2d6404c62de57dbf4eb0365950134330bceb890..b107f1c54c669a204355ca7bc49c14bfdddad37f 100644
--- a/src/test/java/org/olat/selenium/CourseTest.java
+++ b/src/test/java/org/olat/selenium/CourseTest.java
@@ -1738,4 +1738,5 @@ public class CourseTest extends Deployments {
 			.uploadResource(zipTitle, zipFile)
 			.assertOnResourceType();
 	}
+	
 }
diff --git a/src/test/java/org/olat/selenium/page/course/CoursePageFragment.java b/src/test/java/org/olat/selenium/page/course/CoursePageFragment.java
index 5700988b382a4be8202b1b59eb77b7d0f1c2c0fb..d229a6416a04bbf223700dfcb385cc265c0fb43f 100644
--- a/src/test/java/org/olat/selenium/page/course/CoursePageFragment.java
+++ b/src/test/java/org/olat/selenium/page/course/CoursePageFragment.java
@@ -93,11 +93,36 @@ public class CoursePageFragment {
 	}
 	
 	public CoursePageFragment assertOnLearnPathNodeDone(String nodeTitle) {
-		By nodeDoneBy = By.xpath("//div[contains(@class,'o_lp_tree')]//span[contains(@class,'o_tree_l1')]/a[i[contains(@class,'o_lp_done')]][span[text()[contains(.,'" + nodeTitle + "')]]]");
+		return assertOnLearnPathNodeStatus(nodeTitle, "o_lp_done");
+	}
+	
+	public CoursePageFragment assertOnLearnPathNodeReady(String nodeTitle) {
+		return assertOnLearnPathNodeStatus(nodeTitle, "o_lp_ready");
+	}
+	
+	public CoursePageFragment assertOnLearnPathNodeInProgress(String nodeTitle) {
+		return assertOnLearnPathNodeStatus(nodeTitle, "o_lp_in_progress");
+	}
+	
+	public CoursePageFragment assertOnLearnPathNodeNotAccessible(String nodeTitle) {
+		return assertOnLearnPathNodeStatus(nodeTitle, "o_lp_not_accessible");
+	}
+	
+	private CoursePageFragment assertOnLearnPathNodeStatus(String nodeTitle, String statusCssClass) {
+		if(nodeTitle.length() > 20) {
+			nodeTitle = nodeTitle.substring(0, 20);
+		}
+		By nodeDoneBy = By.xpath("//div[contains(@class,'o_lp_tree')]//span[contains(@class,'o_tree_l')]/a[i[contains(@class,'" + statusCssClass + "')]][span[text()[contains(.,'" + nodeTitle + "')]]]");
 		OOGraphene.waitElement(nodeDoneBy, browser);
 		return this;
 	}
 	
+	public CoursePageFragment assertOnLearnPathPercent(int percent) {
+		By percentageBy = By.xpath("//span[contains(@class,'o_progress')]//span[contains(@class,'percentage')]//span[text()[contains(.,'" + percent + "%')]]");
+		OOGraphene.waitElement(percentageBy, browser);
+		return this;
+	}
+	
 	/**
 	 * Assert if the password field is displayed.
 	 * @return
@@ -148,6 +173,21 @@ public class CoursePageFragment {
 		return menuTree.selectRoot();
 	}
 	
+	/**
+	 * 
+	 * @return
+	 */
+	public CoursePageFragment confirmNode() {
+		By confirmationBy = By.cssSelector("div.o_course_pagination div.o_confirm a.btn");
+		OOGraphene.waitElement(confirmationBy, browser);
+		browser.findElement(confirmationBy).click();
+		OOGraphene.waitBusy(browser);
+
+		By confirmedBy = By.cssSelector("div.o_course_pagination div.o_confirm a.btn.o_course_pagination_status_done");
+		OOGraphene.waitElement(confirmedBy, browser);
+		return this;
+	}
+	
 	/**
 	 * Open the tools drop-down
 	 * @return
@@ -276,6 +316,11 @@ public class CoursePageFragment {
 		return new BookingPage(browser);
 	}
 	
+	/**
+	 * Set the course status to published.
+	 * 
+	 * @return Itself
+	 */
 	public CoursePageFragment publish() {
 		return changeStatus(RepositoryEntryStatusEnum.published);
 	}
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 56be8baa524eb53632c654bdf74b45c676c4f52c..906042a87b1e7c9e5fd92ee152fb6bc94ee2bd1f 100644
--- a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java
+++ b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java
@@ -117,6 +117,21 @@ public class QTI21Page {
 		return this;
 	}
 	
+	public QTI21Page passE4() {
+		start()
+			.answerSingleChoiceWithParagraph("Correct answer")
+			.saveAnswer()
+			.answerMultipleChoice("Correct answer", "The answer is correct")
+			.saveAnswer()
+			.answerCorrectKPrim("This answer", "Plus answer")
+			.answerIncorrectKPrim("Not answer", "Minus answer")
+			.saveAnswer()
+			.answerGapText("not", "qtiworks_response_oofibc4c14bfe94a41861fe19c70091182_5_1_RESPONSE_1")
+			.saveAnswer()
+			.endTest();
+		return this;
+	}
+	
 	/**
 	 * Check the answer of a single choice.
 	 * @param answer The answer
@@ -807,7 +822,7 @@ public class QTI21Page {
 	
 	public QTI21Page closeTest() {
 		By closeBy = By.cssSelector("a.o_sel_close_test");
-		OOGraphene.waitElement(closeBy, 5, browser);
+		OOGraphene.waitElement(closeBy, browser);
 		browser.findElement(closeBy).click();
 		OOGraphene.waitBusy(browser);
 		confirm();
diff --git a/src/test/java/org/olat/test/file_resources/course_certificates_exrules.zip b/src/test/java/org/olat/test/file_resources/course_certificates_exrules.zip
new file mode 100644
index 0000000000000000000000000000000000000000..988bde8a23373ac1b09c2bf06d3730f68769d507
Binary files /dev/null and b/src/test/java/org/olat/test/file_resources/course_certificates_exrules.zip differ