From 667e7a7a39fd13a7ba735c3cfbe266dd5b37f5a8 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Thu, 22 Jun 2017 13:41:27 +0200
Subject: [PATCH] OO-2836: update to selenium 3.4, migrate the tests to pass
 with chrome, add css class mostly in wizards, remove some fieldset in
 fieldset, add some label around checkbox

---
 TESTING.README.LATEST                         |   9 +-
 pom.xml                                       |  24 +--
 .../admin/user/UserSearchFlexiController.java |   2 +
 .../user/groups/GroupSearchController.java    |   1 +
 .../org/olat/admin/user/imp/ImportStep00.java |   3 +-
 .../org/olat/admin/user/imp/ImportStep01.java |   2 +
 .../imp/SendMailConfirmationController.java   |   1 +
 .../info/ui/InfoDisplayController.java        |  23 ++-
 .../info/ui/SendMailStepController.java       |   1 +
 .../commons/info/ui/_content/display.html     |  26 ++-
 .../core/gui/components/tree/MenuTree.java    |   7 +-
 .../closablewrapper/_content/index.html       |   1 -
 .../wizard/StepsMainRunController.java        |  10 +
 .../generic/wizard/_content/stepslayout.html  |   1 -
 .../control/guistack/GuiStackNiceImpl.java    |   5 +
 .../gui/control/winmgr/ScrollTopCommand.java  |  47 +++++
 .../bulk/ChooseColumnsStepForm.java           |   1 +
 .../bulk/ChooseColumnsStepSkipForm.java       |   1 +
 .../course/assessment/bulk/DataStepForm.java  |   2 +
 .../assessment/bulk/ScheduleStepForm.java     |   2 +
 .../assessment/bulk/_content/select_node.html |   4 +-
 .../assessment/bulk/_content/validation.html  |   4 +-
 .../olat/course/editor/PublishStep00a.java    |   3 +-
 .../editor/PublishStep01AccessForm.java       |  12 +-
 .../editor/_content/nothingtopublish.html     |   8 +-
 .../olat/course/editor/_content/publish.html  |   3 +-
 .../editor/_content/publish_update.html       |   6 +-
 .../ImportMemberByUsernamesController.java    |   1 +
 ...ortMemberOverviewIdentitiesController.java |   1 +
 ...mportMemberPermissionChoiceController.java |   2 +-
 .../BusinessGroupModuleAdminController.java   |   8 +
 .../org/olat/group/ui/_content/bg_admin.html  |  24 +--
 .../group/ui/main/_content/edit_member.html   |   2 +
 .../ui/wizard/BGMailTemplateController.java   |   1 +
 .../_content/multiple_choices.html            |   4 +-
 .../ui/wizard/MemberMailController.java       |   1 +
 .../MembersOverviewIdentitiesController.java  |   1 +
 .../org/olat/selenium/AssessmentTest.java     |  61 ++++--
 .../org/olat/selenium/BusinessGroupTest.java  |  28 +--
 .../java/org/olat/selenium/CourseTest.java    |  78 ++++----
 .../org/olat/selenium/PortfolioV2Test.java    |  21 ++-
 src/test/java/org/olat/selenium/UserTest.java |  12 +-
 .../olat/selenium/page/NavigationPage.java    |   8 +-
 .../page/core/AdministrationPage.java         |  26 ++-
 .../olat/selenium/page/core/CalendarPage.java |  17 +-
 .../olat/selenium/page/core/FolderPage.java   |   2 +-
 .../org/olat/selenium/page/core/IMPage.java   |  40 ++--
 .../course/AssessmentCEConfigurationPage.java |   4 +-
 .../page/course/AssessmentToolPage.java       |   4 +-
 .../page/course/BulkAssessmentPage.java       |  37 ++--
 .../page/course/CourseEditorPageFragment.java |  30 ++-
 .../page/course/CoursePageFragment.java       |  24 ++-
 .../page/course/CourseWizardPage.java         |  47 ++---
 .../page/course/EasyConditionConfigPage.java  |   6 +-
 .../selenium/page/course/GroupTaskPage.java   |  24 ++-
 .../page/course/GroupTaskToCoachPage.java     |  29 +--
 .../page/course/InfoMessageCEPage.java        |  21 ++-
 .../selenium/page/course/MembersPage.java     |   9 +-
 .../page/course/PublisherPageFragment.java    |  58 +++---
 .../olat/selenium/page/forum/ForumPage.java   |   4 +-
 .../selenium/page/graphene/BusyPredicate.java |   8 +-
 ...dicate.java => BusyScrollToPredicate.java} |  44 ++---
 .../graphene/CloseAlertInfoPredicate.java     |   7 +-
 .../graphene/NavBarTransitionPredicate.java   |   8 +-
 .../selenium/page/graphene/OOGraphene.java    | 175 ++++++++++++------
 .../page/graphene/ScrollToPredicate.java      |   8 +-
 .../graphene/TinyMCELoadedByIdPredicate.java  |   8 +-
 .../page/graphene/TinyMCELoadedPredicate.java |   8 +-
 .../page/graphene/TransitionPredicate.java    |   8 +-
 .../olat/selenium/page/group/GroupPage.java   |   7 +-
 .../page/group/MembersWizardPage.java         |  66 +++----
 .../portfolio/BinderMemberWizardPage.java     |  20 +-
 .../selenium/page/portfolio/BinderPage.java   |   2 +-
 .../page/portfolio/BinderPublicationPage.java |   6 +-
 .../selenium/page/portfolio/EntryPage.java    |   2 +-
 .../page/qti/QTI21KprimEditorPage.java        |   3 +-
 .../selenium/page/qti/QTI21LobEditorPage.java |   2 +-
 .../page/qti/QTI21MatchEditorPage.java        |   3 +-
 .../qti/QTI21MultipleChoiceEditorPage.java    |  11 +-
 .../org/olat/selenium/page/qti/QTI21Page.java |   4 +-
 .../page/qti/QTI21SingleChoiceEditorPage.java |   3 +-
 .../page/repository/AuthoringEnvPage.java     |   3 +-
 .../selenium/page/repository/FeedPage.java    |   3 +-
 .../selenium/page/user/ImportUserPage.java    |  34 ++--
 .../selenium/page/user/UserAdminPage.java     |   2 +
 .../user/UserPreferencesPageFragment.java     |   6 +-
 src/test/resources/arquillian.xml             |  14 +-
 87 files changed, 793 insertions(+), 516 deletions(-)
 create mode 100644 src/main/java/org/olat/core/gui/control/winmgr/ScrollTopCommand.java
 rename src/test/java/org/olat/selenium/page/graphene/{InViewportPredicate.java => BusyScrollToPredicate.java} (50%)

diff --git a/TESTING.README.LATEST b/TESTING.README.LATEST
index e00e1f7ca2d..a06a6ffd7ae 100644
--- a/TESTING.README.LATEST
+++ b/TESTING.README.LATEST
@@ -74,15 +74,14 @@ junit and integration tests in OpenOLAT 8
 
 * Execute selenium functional integration tests
 -----------------------------------------------
-- selenium integration tests which started the whole web application in Tomcat (execution time ca. 10m)
+- selenium integration tests which started the whole web application in Tomcat (execution time ca. 30 - 45m)
   - MySQL
 	mvn clean verify -DskipTests=true -Dwith-mysql -Ptomcat
   - PostgreSQL
-	mvn clean verify -DskipTests=true -Dwith-postgresql -Ptomcat
+	mvn clean verify -DskipTests=true -Dwith-postgresql -Dtest.env.db.postgresql.pass=serial -Ptomcat
 
-The Selenium tests can be run with different browser but with some limitations:
-- Chrome/Safari cannot do an upload (tests which need an upload are ignored)
-- Firefox works until version 42.
+The Selenium tests can be run with Chrome browser. It need to be installed the standard way on
+Mac or Linux and the test process will download the WebDriver and found the browser.
 
 * Execute a single selenium functional integration test in Eclipse
 ------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 78c7940ea68..236cb4c1056 100644
--- a/pom.xml
+++ b/pom.xml
@@ -70,8 +70,8 @@
 		<org.postgresql.version>42.0.0</org.postgresql.version>
 		<org.infinispan.version>8.2.5.Final</org.infinispan.version>
 		<lucene.version>4.8.0</lucene.version>
-		<version.selenium>2.53.1</version.selenium>
-		<version.drone>2.0.1.Final</version.drone>
+		<version.selenium>3.4.0</version.selenium>
+		<version.drone>2.1.2</version.drone>
 		<activemq.version>5.11.1</activemq.version>
 		<qtiworks.version>1.0.4</qtiworks.version>
 
@@ -1414,7 +1414,9 @@
 					<artifactId>maven-war-plugin</artifactId>
 					<version>3.0.0</version>
 					<configuration>
+						<!--
 						<attachClasses>true</attachClasses>
+						-->
 						<directory>src/main/java</directory>
 						<archive>
 							<manifest>
@@ -2535,11 +2537,19 @@
 			<artifactId>arquillian-drone-impl</artifactId>
 			<scope>test</scope>
 		</dependency>
+		<!-- 
 		<dependency>
 			<groupId>org.jboss.arquillian.extension</groupId>
 			<artifactId>arquillian-drone-selenium-server</artifactId>
 			<scope>test</scope>
 		</dependency>
+		-->
+		<dependency>
+			<groupId>com.google.guava</groupId>
+			<artifactId>guava</artifactId>
+			<version>21.0</version>
+			<scope>test</scope>
+		</dependency>
 		<dependency>
             <groupId>org.jboss.arquillian.extension</groupId>
             <artifactId>arquillian-drone-webdriver-depchain</artifactId>
@@ -2559,20 +2569,12 @@
 					<groupId>com.opera</groupId>
 					<artifactId>operadriver</artifactId>
             	</exclusion>
-            	<exclusion>
-					<groupId>org.jboss.arquillian.extension</groupId>
-					<artifactId>arquillian-phantom-driver</artifactId>
-            	</exclusion>
-            	<exclusion>
-					<groupId>org.seleniumhq.selenium</groupId>
-					<artifactId>selenium-chrome-driver</artifactId>
-            	</exclusion>
             </exclusions>
         </dependency>
 		<dependency>
 			<groupId>org.jboss.arquillian.graphene</groupId>
 			<artifactId>graphene-webdriver</artifactId>
-			<version>2.1.0.Final</version>
+			<version>2.2.1</version>
 			<type>pom</type>
 			<scope>test</scope>
 		</dependency>
diff --git a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
index 87060249840..8347e7a6968 100644
--- a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
+++ b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
@@ -51,6 +51,7 @@ import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.ajax.autocompletion.FlexiAutoCompleterController;
 import org.olat.core.gui.control.generic.ajax.autocompletion.ListProvider;
+import org.olat.core.gui.control.winmgr.ScrollTopCommand;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Roles;
@@ -345,6 +346,7 @@ public class UserSearchFlexiController extends FlexiAutoCompleterController {
 			}
 		} else if(searchButton == source) {
 			if(validateForm(ureq)) {
+				getWindowControl().getWindowBackOffice().sendCommandTo(new ScrollTopCommand());
 				doSearch();
 			}
 		} else if (tableEl == source) {
diff --git a/src/main/java/org/olat/admin/user/groups/GroupSearchController.java b/src/main/java/org/olat/admin/user/groups/GroupSearchController.java
index 636e28258dc..b32adf86490 100644
--- a/src/main/java/org/olat/admin/user/groups/GroupSearchController.java
+++ b/src/main/java/org/olat/admin/user/groups/GroupSearchController.java
@@ -117,6 +117,7 @@ public class GroupSearchController extends StepFormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		setFormDescription("group.search.description");
+		formLayout.setElementCssClass("o_sel_groups_search");
 
 		search = uifactory.addTextElement("search.field", "search.field", 100, "", formLayout);
 		
diff --git a/src/main/java/org/olat/admin/user/imp/ImportStep00.java b/src/main/java/org/olat/admin/user/imp/ImportStep00.java
index 07b01ba2d23..0005b9bf3ff 100644
--- a/src/main/java/org/olat/admin/user/imp/ImportStep00.java
+++ b/src/main/java/org/olat/admin/user/imp/ImportStep00.java
@@ -411,8 +411,9 @@ class ImportStep00 extends BasicStep {
 		@Override
 		protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 			setFormTitle("title");
+			formLayout.setElementCssClass("o_sel_import_users_data");
 
-			FormLayoutContainer textContainer = FormLayoutContainer.createCustomFormLayout("index", getTranslator(), this.velocity_root + "/step0.html");
+			FormLayoutContainer textContainer = FormLayoutContainer.createCustomFormLayout("index", getTranslator(), velocity_root + "/step0.html");
 			formLayout.add(textContainer);
 			textContainer.contextPut("canCreateOLATPassword", canCreateOLATPassword);
 
diff --git a/src/main/java/org/olat/admin/user/imp/ImportStep01.java b/src/main/java/org/olat/admin/user/imp/ImportStep01.java
index 437e5361fd9..57d6baf708c 100644
--- a/src/main/java/org/olat/admin/user/imp/ImportStep01.java
+++ b/src/main/java/org/olat/admin/user/imp/ImportStep01.java
@@ -134,6 +134,8 @@ class ImportStep01 extends BasicStep {
 
 		@Override
 		protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+			formLayout.setElementCssClass("o_sel_import_users_overview");
+			
 			FormLayoutContainer formLayoutVertical = FormLayoutContainer.createVerticalFormLayout("vertical", getTranslator());
 			formLayout.add(formLayoutVertical);
 
diff --git a/src/main/java/org/olat/admin/user/imp/SendMailConfirmationController.java b/src/main/java/org/olat/admin/user/imp/SendMailConfirmationController.java
index d94f46d4bc9..5211ce10a86 100644
--- a/src/main/java/org/olat/admin/user/imp/SendMailConfirmationController.java
+++ b/src/main/java/org/olat/admin/user/imp/SendMailConfirmationController.java
@@ -52,6 +52,7 @@ public class SendMailConfirmationController extends StepFormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		setFormDescription("step3.send.mail.description");
+		formLayout.setElementCssClass("o_sel_users_import_contact");
 		
 		@SuppressWarnings("unchecked")
 		List<Long> ownGroups = (List<Long>) getFromRunContext("ownerGroups");
diff --git a/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java b/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java
index ee786cb3bf6..efb93bb8932 100644
--- a/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java
+++ b/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java
@@ -124,7 +124,7 @@ public class InfoDisplayController extends FormBasicController {
 		initForm(ureq);	
 		
 		// now load with configuration
-		loadMessages(ureq);		
+		loadMessages();		
 	}
 	
 	public InfoDisplayController(UserRequest ureq, WindowControl wControl, ModuleConfiguration config,
@@ -166,7 +166,7 @@ public class InfoDisplayController extends FormBasicController {
 		}
 		
 		// now load with configuration
-		loadMessages(ureq);
+		loadMessages();
 	}
 	
 	private int getConfigValue(ModuleConfiguration config, String key, int def) {
@@ -201,7 +201,7 @@ public class InfoDisplayController extends FormBasicController {
 	 * This is the main method which push the messages in the layout container,
 	 * and clean-up old links.
 	 */
-	protected void loadMessages(UserRequest ureq) {
+	protected void loadMessages() {
 		//first clear the current message if any
 		for(Long key:previousDisplayKeys) {
 			flc.contextRemove("info.date." + key);
@@ -216,7 +216,7 @@ public class InfoDisplayController extends FormBasicController {
 		deleteLinks.clear();
 
 		List<InfoMessage> msgs = infoMessageManager.loadInfoMessageByResource(ores, resSubPath, businessPath, after, null, 0, maxResults);
-		List<InfoMessageForDisplay> infoDisplays = new ArrayList<InfoMessageForDisplay>(msgs.size());
+		List<InfoMessageForDisplay> infoDisplays = new ArrayList<>(msgs.size());
 		for(InfoMessage info:msgs) {
 			previousDisplayKeys.add(info.getKey());
 			infoDisplays.add(createInfoMessageForDisplay(info));
@@ -313,8 +313,7 @@ public class InfoDisplayController extends FormBasicController {
 				getWindowControl().pop();
 			} else if (event == Event.CHANGED_EVENT) {
 				getWindowControl().pop();
-				loadMessages(ureq);
-				flc.setDirty(true);//update the view
+				loadMessages();
 			}	else if (event == Event.DONE_EVENT){
 				showError("failed");
 			}
@@ -326,7 +325,7 @@ public class InfoDisplayController extends FormBasicController {
 						LoggingResourceable.wrap(msgToDelete.getOLATResourceable(), OlatResourceableType.infoMessage));
 				
 				infoMessageManager.deleteInfoMessage(msgToDelete);
-				loadMessages(ureq);
+				loadMessages();
 			}
 			confirmDelete.setUserObject(null);
 			
@@ -335,7 +334,7 @@ public class InfoDisplayController extends FormBasicController {
 			lockEntry = null;
 		} else if (source == editController) {
 			if(event == Event.DONE_EVENT) {
-				loadMessages(ureq);
+				loadMessages();
 			}
 			editDialogBox.deactivate();
 			removeAsListenerAndDispose(editController);
@@ -371,11 +370,11 @@ public class InfoDisplayController extends FormBasicController {
 		} else if(source == oldMsgsLink) {
 			maxResults = -1;
 			after = null;
-			loadMessages(ureq);
+			loadMessages();
 		}  else if(source == newMsgsLink) {
 			maxResults = maxResultsConfig;
 			after = afterConfig;
-			loadMessages(ureq);
+			loadMessages();
 		} else {
 			super.formInnerEvent(ureq, source, event);
 		}
@@ -391,7 +390,7 @@ public class InfoDisplayController extends FormBasicController {
 				showWarning("already.deleted");
 				CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(lockEntry);
 				lockEntry = null;
-				loadMessages(ureq);
+				loadMessages();
 			} else {
 				String title = StringHelper.escapeHtml(msg.getTitle());
 				String confirmDeleteText = translate("edit.confirm_delete", new String[]{ title });
@@ -414,7 +413,7 @@ public class InfoDisplayController extends FormBasicController {
 				showWarning("already.deleted");
 				CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(lockEntry);
 				lockEntry = null;
-				loadMessages(ureq);
+				loadMessages();
 			} else {
 				removeAsListenerAndDispose(editController);
 				removeAsListenerAndDispose(editDialogBox);
diff --git a/src/main/java/org/olat/commons/info/ui/SendMailStepController.java b/src/main/java/org/olat/commons/info/ui/SendMailStepController.java
index 718ba20d63c..d503830da8d 100644
--- a/src/main/java/org/olat/commons/info/ui/SendMailStepController.java
+++ b/src/main/java/org/olat/commons/info/ui/SendMailStepController.java
@@ -65,6 +65,7 @@ public class SendMailStepController extends StepFormBasicController {
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		formLayout.setElementCssClass("o_sel_info_contact");
 		setFormTitle("wizard.step1.title");
 		setFormDescription("wizard.step1.form_description");
 		sendSelection = uifactory.addCheckboxesVertical("wizard.step1.send_option", formLayout, sendOptionKeys, sendOptionValues, 1);
diff --git a/src/main/java/org/olat/commons/info/ui/_content/display.html b/src/main/java/org/olat/commons/info/ui/_content/display.html
index 4ccf7ba59bd..07f554e7046 100644
--- a/src/main/java/org/olat/commons/info/ui/_content/display.html
+++ b/src/main/java/org/olat/commons/info/ui/_content/display.html
@@ -1,8 +1,6 @@
 #if($infos.isEmpty())
 	<div class="o_important">
-		<p>
-		$r.translate("display.no_messages")
-		</p>
+		<p>$r.translate("display.no_messages")</p>
 		#if($r.available("new_message"))
 		<div class="o_button_group">
 			$r.render("new_message")
@@ -19,9 +17,7 @@
 	#end	
 #end
 
-
-<div class="o_infomsg o_block_with_datecomp clearfix">
-	
+<div class="clearfix"><div class="o_infomsg o_block_with_datecomp">
 	#foreach($info in $infos)
 		<div class="o_msg o_block_large clearfix">
 			<div class="o_head">
@@ -51,12 +47,12 @@
 			#end
 		</div>
 	#end
-	<div class="pull-right clearfix">
-		#if($r.available("display.old_messages"))
-			$r.render("display.old_messages")
-		#end
-		#if($r.available("display.new_messages"))
-			$r.render("display.new_messages")
-		#end
-	</div>
-</div>
\ No newline at end of file
+</div></div>
+<div class="o_button_group">
+	#if($r.available("display.old_messages"))
+		$r.render("display.old_messages")
+	#end
+	#if($r.available("display.new_messages"))
+		$r.render("display.new_messages")
+	#end
+</div>
diff --git a/src/main/java/org/olat/core/gui/components/tree/MenuTree.java b/src/main/java/org/olat/core/gui/components/tree/MenuTree.java
index 323f8f5c765..22661d76377 100644
--- a/src/main/java/org/olat/core/gui/components/tree/MenuTree.java
+++ b/src/main/java/org/olat/core/gui/components/tree/MenuTree.java
@@ -41,7 +41,7 @@ import org.olat.core.gui.components.ComponentRenderer;
 import org.olat.core.gui.components.Window;
 import org.olat.core.gui.components.tree.InsertionPoint.Position;
 import org.olat.core.gui.control.JSAndCSSAdder;
-import org.olat.core.gui.control.winmgr.JSCommand;
+import org.olat.core.gui.control.winmgr.ScrollTopCommand;
 import org.olat.core.gui.render.ValidationResult;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.nodes.INode;
@@ -172,10 +172,7 @@ public class MenuTree extends AbstractComponent {
 	private void scrollTop(UserRequest ureq) {
 		Window window = Windows.getWindows(ureq).getWindow(ureq);
 		if(window != null) {
-			StringBuilder sb = new StringBuilder();
-			sb.append("try{ o_scrollToElement('#o_top'); }catch(e){}");
-			JSCommand jsCommand = new JSCommand(sb.toString());
-			window.getWindowBackOffice().sendCommandTo(jsCommand);
+			window.getWindowBackOffice().sendCommandTo(new ScrollTopCommand());
 		}
 	}
 
diff --git a/src/main/java/org/olat/core/gui/control/generic/closablewrapper/_content/index.html b/src/main/java/org/olat/core/gui/control/generic/closablewrapper/_content/index.html
index ea636d31e23..7e52b91713d 100644
--- a/src/main/java/org/olat/core/gui/control/generic/closablewrapper/_content/index.html
+++ b/src/main/java/org/olat/core/gui/control/generic/closablewrapper/_content/index.html
@@ -20,7 +20,6 @@
 jQuery(function() {
 	jQuery('#$r.getId("o_closablewapper_") > .modal-backdrop')
 		.css('height', 0).css('height', jQuery('#$r.getId("o_closablewapper_")')[0].scrollHeight);
-	o_scrollToElement('#$r.getId("o_closablewapper_")');
 });
 /* ]]> */
 </script>
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/gui/control/generic/wizard/StepsMainRunController.java b/src/main/java/org/olat/core/gui/control/generic/wizard/StepsMainRunController.java
index e74b492f53c..b7416da9b50 100644
--- a/src/main/java/org/olat/core/gui/control/generic/wizard/StepsMainRunController.java
+++ b/src/main/java/org/olat/core/gui/control/generic/wizard/StepsMainRunController.java
@@ -42,6 +42,8 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.creator.ControllerCreator;
+import org.olat.core.gui.control.winmgr.JSCommand;
+import org.olat.core.gui.control.winmgr.ScrollTopCommand;
 import org.olat.core.logging.AssertException;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.event.GenericEventListener;
@@ -208,12 +210,18 @@ public class StepsMainRunController extends FormBasicController implements Gener
 		} else if (source == nextButton) {
 			// submit and let current unsaved step do its work
 			flc.getRootForm().submitAndNext(ureq);
+			//getWindowControl().getWindowBackOffice()
+			//	.sendCommandTo(new JSCommand("try { o_scrollToElement('.o_wizard.modal.show.in'); } catch(e){ }"));
+			getWindowControl().getWindowBackOffice()
+				.sendCommandTo(new ScrollTopCommand());
 			// the current step decides whether to proceed to the next step or
 			// not.
 		} else if (source == finishButton) {
 			// submit and let last unsaved step do its work
 			finishCycle = true;
 			flc.getRootForm().submitAndFinish(ureq);
+			getWindowControl().getWindowBackOffice()
+				.sendCommandTo(new ScrollTopCommand());
 			// the current step decides whether to proceed or not
 			// an end step will fire FINISH
 			// a intermediate step will fire NEXT .. but NEXT && FINISHCYCLE
@@ -221,6 +229,8 @@ public class StepsMainRunController extends FormBasicController implements Gener
 		} else if (source == prevButton) {
 			lastEvent = StepsEvent.ACTIVATE_PREVIOUS;
 			doAfterDispatch = true;
+			getWindowControl().getWindowBackOffice()
+				.sendCommandTo(new JSCommand("try { o_scrollToElement('.o_wizard.modal.show.in'); } catch(e){ }"));
 		} else if (whichTitleClickedIndex >= 0) {
 			// handle a step title link
 			// remove all steps until the clicked one
diff --git a/src/main/java/org/olat/core/gui/control/generic/wizard/_content/stepslayout.html b/src/main/java/org/olat/core/gui/control/generic/wizard/_content/stepslayout.html
index 883e32f9d28..141d1cb7c26 100644
--- a/src/main/java/org/olat/core/gui/control/generic/wizard/_content/stepslayout.html
+++ b/src/main/java/org/olat/core/gui/control/generic/wizard/_content/stepslayout.html
@@ -43,7 +43,6 @@
 jQuery(function() {
 	jQuery('.o_wizard.modal.show.in > .modal-backdrop')
 		.css('height', 0).css('height', jQuery('.o_wizard.modal.show.in')[0].scrollHeight);
-	o_scrollToElement('.o_wizard.modal.show.in');
 });
 /* ]]> */
 </script>
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java b/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java
index f589ca46ef2..40fd4df6d22 100644
--- a/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java
+++ b/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java
@@ -37,6 +37,7 @@ import org.olat.core.gui.control.WindowBackOffice;
 import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings;
 import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings.CalloutOrientation;
 import org.olat.core.gui.control.util.ZIndexWrapper;
+import org.olat.core.gui.control.winmgr.ScrollTopCommand;
 import org.olat.core.gui.render.ValidationResult;
 import org.olat.core.util.Util;
 
@@ -83,10 +84,14 @@ public class GuiStackNiceImpl implements GuiStack {
 	 * @param title the title of the modal dialog, can be null
 	 * @param content the component to push as modal dialog
 	 */
+	@Override
 	public void pushModalDialog(Component content) {
+		wbo.sendCommandTo(new ScrollTopCommand());
+		
 		// wrap the component into a modal foreground dialog with alpha-blended-background
 		final Panel guiMsgPlace = new Panel("guimsgplace_for_modaldialog");
 		VelocityContainer inset = new VelocityContainer("inset", VELOCITY_ROOT + "/modalDialog.html", null, null) {
+			@Override
 			public void validate(UserRequest ureq, ValidationResult vr) {
 				super.validate(ureq, vr);
 				// just before rendering, we need to tell the windowbackoffice that we are a favorite for accepting gui-messages.
diff --git a/src/main/java/org/olat/core/gui/control/winmgr/ScrollTopCommand.java b/src/main/java/org/olat/core/gui/control/winmgr/ScrollTopCommand.java
new file mode 100644
index 00000000000..b796a4a11e0
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/control/winmgr/ScrollTopCommand.java
@@ -0,0 +1,47 @@
+/**
+ * <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.core.gui.control.winmgr;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.olat.core.logging.AssertException;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, https://www.frentix.com
+ *
+ */
+public class ScrollTopCommand extends Command {
+
+	/**
+	 * Create a command that executes arbitrary JS code
+	 * @param javaScriptCode
+	 */
+	public ScrollTopCommand() {
+		super(1); // do not change this command id, it is in js also
+		JSONObject subjo = new JSONObject();
+		try {
+			subjo.put("e", "try { o_scrollToElement('#o_top'); } catch(e){ }");
+		} catch (JSONException e) {
+			throw new AssertException("json exception:", e);
+		}
+		setSubJSON(subjo);		
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/bulk/ChooseColumnsStepForm.java b/src/main/java/org/olat/course/assessment/bulk/ChooseColumnsStepForm.java
index 9fb4f9adfb5..8ca3fc47f1f 100644
--- a/src/main/java/org/olat/course/assessment/bulk/ChooseColumnsStepForm.java
+++ b/src/main/java/org/olat/course/assessment/bulk/ChooseColumnsStepForm.java
@@ -98,6 +98,7 @@ public class ChooseColumnsStepForm extends StepFormBasicController {
 		otherValues[otherValues.length - 1] = translate("column.dontuse");
 
 		FormLayoutContainer choosersCont = FormLayoutContainer.createDefaultFormLayout("choosers", getTranslator());
+		choosersCont.setElementCssClass("o_sel_bulk_assessment_columns");
 		choosersCont.setRootForm(mainForm);
 		formLayout.add(choosersCont);
 
diff --git a/src/main/java/org/olat/course/assessment/bulk/ChooseColumnsStepSkipForm.java b/src/main/java/org/olat/course/assessment/bulk/ChooseColumnsStepSkipForm.java
index 130c7799f8b..81e867f26c8 100644
--- a/src/main/java/org/olat/course/assessment/bulk/ChooseColumnsStepSkipForm.java
+++ b/src/main/java/org/olat/course/assessment/bulk/ChooseColumnsStepSkipForm.java
@@ -45,6 +45,7 @@ public class ChooseColumnsStepSkipForm extends StepFormBasicController {
 	
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		formLayout.setElementCssClass("o_sel_bulk_assessment_columns");
 		setFormTitle("chooseColumns.title");
 		setFormDescription("chooseColumns.skip.description");
 	}
diff --git a/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java b/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java
index 6545ff20a9b..9d74870fe85 100644
--- a/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java
+++ b/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java
@@ -102,6 +102,8 @@ public class DataStepForm extends StepFormBasicController {
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		formLayout.setElementCssClass("o_sel_bulk_assessment_data");
+		
 		// hide data input field in case the element does not have any score, passed or comment field enabled
 		BulkAssessmentSettings settings = new BulkAssessmentSettings(courseNode);
 		boolean onlyReturnFiles = (!settings.isHasScore() && !settings.isHasPassed() && !settings.isHasUserComment());
diff --git a/src/main/java/org/olat/course/assessment/bulk/ScheduleStepForm.java b/src/main/java/org/olat/course/assessment/bulk/ScheduleStepForm.java
index c736a0cd7a4..e893e680107 100644
--- a/src/main/java/org/olat/course/assessment/bulk/ScheduleStepForm.java
+++ b/src/main/java/org/olat/course/assessment/bulk/ScheduleStepForm.java
@@ -57,6 +57,8 @@ public class ScheduleStepForm extends StepFormBasicController {
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		formLayout.setElementCssClass("o_sel_bulk_assessment_schedule");
+		
 		setFormTitle("schedule.title");
 		setFormDescription("schedule.description");
 		setFormContextHelp("Using Course Tools#bulkassessment_schedule");
diff --git a/src/main/java/org/olat/course/assessment/bulk/_content/select_node.html b/src/main/java/org/olat/course/assessment/bulk/_content/select_node.html
index b568dae7a73..c2492481d49 100644
--- a/src/main/java/org/olat/course/assessment/bulk/_content/select_node.html
+++ b/src/main/java/org/olat/course/assessment/bulk/_content/select_node.html
@@ -1,4 +1,6 @@
+<div class="o_sel_bulk_assessment_nodes">
 $r.contextHelpWithWrapper("Using Course Tools#bulkassessment_node")
 <h4>$r.translate("choose.node.title")</h4>
 <p class="o_info">$r.translate("choose.node.desc")</p>
-$r.render("nodeList")
\ No newline at end of file
+$r.render("nodeList")
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/assessment/bulk/_content/validation.html b/src/main/java/org/olat/course/assessment/bulk/_content/validation.html
index fec642e2e04..d13e7dde2f7 100644
--- a/src/main/java/org/olat/course/assessment/bulk/_content/validation.html
+++ b/src/main/java/org/olat/course/assessment/bulk/_content/validation.html
@@ -1,3 +1,4 @@
+<div class="o_sel_bulk_assessment_validation">
 #if ($hasNoItems) 
 	<p class="o_warning">
 		$r.translate("validation.error")
@@ -50,4 +51,5 @@
 		$r.render("notFoundList")
 	</fieldset>
 	#end
-#end
\ No newline at end of file
+#end
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/editor/PublishStep00a.java b/src/main/java/org/olat/course/editor/PublishStep00a.java
index 3824e28ad39..3e2a39d50e5 100644
--- a/src/main/java/org/olat/course/editor/PublishStep00a.java
+++ b/src/main/java/org/olat/course/editor/PublishStep00a.java
@@ -88,7 +88,8 @@ class PublishStep00a extends BasicStep implements Step {
 
 		@Override
 		protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-			//
+			formLayout.setElementCssClass("o_sel_publish_update");
+			
 			if(containsRunContextKey("STEP00.warningMessage")) {
 				uifactory.addStaticTextElement("warnings", null,(String)getFromRunContext("STEP00.warningMessage"), formLayout);
 			} else {
diff --git a/src/main/java/org/olat/course/editor/PublishStep01AccessForm.java b/src/main/java/org/olat/course/editor/PublishStep01AccessForm.java
index 10c81febbdb..212c7f52281 100644
--- a/src/main/java/org/olat/course/editor/PublishStep01AccessForm.java
+++ b/src/main/java/org/olat/course/editor/PublishStep01AccessForm.java
@@ -105,15 +105,15 @@ public class PublishStep01AccessForm extends StepFormBasicController {
 	private String[] publishedKeys;
 	
 	
-	private List<FormLink> addMethods = new ArrayList<FormLink>();
-	private List<OfferAccess> offerAccess = new ArrayList<OfferAccess>();
+	private List<FormLink> addMethods = new ArrayList<>();
+	private List<OfferAccess> offerAccess = new ArrayList<>();
 	private final String displayName;
 	
 	private CloseableModalController cmc;
 	private FormLayoutContainer confControllerContainer;
 	private AbstractConfigurationMethodController newMethodCtrl, editMethodCtrl;
 	
-	private final List<AccessInfo> confControllers = new ArrayList<AccessInfo>();
+	private final List<AccessInfo> confControllers = new ArrayList<>();
 	
 	private int button_id;
 	private final boolean emptyConfigGrantsFullAccess;
@@ -134,7 +134,7 @@ public class PublishStep01AccessForm extends StepFormBasicController {
 	private AccessControlModule acModule;
 	
 	public PublishStep01AccessForm(UserRequest ureq, WindowControl control, Form rootForm, StepsRunContext runContext) {
-		super(ureq, control, rootForm, runContext, LAYOUT_VERTICAL, null);
+		super(ureq, control, rootForm, runContext, LAYOUT_BAREBONE, null);
 		Translator translator = Util.createPackageTranslator(
 				Util.createPackageTranslator(RepositoryService.class, AuthoringEntryPublishController.class, getLocale()),
 				Util.createPackageTranslator(ChooseNodeController.class, AccessConfigurationController.class, getLocale()), getLocale());
@@ -288,7 +288,7 @@ public class PublishStep01AccessForm extends StepFormBasicController {
 		accessLayout.setFormTitle(translate("accesscontrol.title"));
 		
 		HelpTooltip acMethodsLabelHelp = new HelpTooltip("acMethodsLabelHelp", "Legen Sie fest unter welchen Bedingungen Benutzer diese Ressource buchen können.", "Course Settings#_buchungsmethode", getLocale());
-		((FormLayoutContainer)accessLayout).put("acMethodsLabelHelp", acMethodsLabelHelp);
+		accessLayout.put("acMethodsLabelHelp", acMethodsLabelHelp);
 
 		if(editable) {
 			List<AccessMethod> methods = acService.getAvailableMethods(getIdentity(), ureq.getUserSession().getRoles());
@@ -305,7 +305,7 @@ public class PublishStep01AccessForm extends StepFormBasicController {
 				addMethods.add(add);
 				accessLayout.add(add.getName(), add);
 			}
-			((FormLayoutContainer)accessLayout).contextPut("methods", addMethods);
+			accessLayout.contextPut("methods", addMethods);
 		}
 		
 		String confPage = velocity_root + "/configuration_list.html";
diff --git a/src/main/java/org/olat/course/editor/_content/nothingtopublish.html b/src/main/java/org/olat/course/editor/_content/nothingtopublish.html
index 823aa50f562..8ad9aba4763 100644
--- a/src/main/java/org/olat/course/editor/_content/nothingtopublish.html
+++ b/src/main/java/org/olat/course/editor/_content/nothingtopublish.html
@@ -1,4 +1,4 @@
-<h4>$r.translate("publish.header")</h4>
-<p>
-	$r.translate("pbl.nothing")
-</p>
\ No newline at end of file
+<div class="o_sel_publish_nodes">
+	<h4>$r.translate("publish.header")</h4>
+	<p>$r.translate("pbl.nothing")</p>
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/editor/_content/publish.html b/src/main/java/org/olat/course/editor/_content/publish.html
index 7c775e18660..be0963226a3 100644
--- a/src/main/java/org/olat/course/editor/_content/publish.html
+++ b/src/main/java/org/olat/course/editor/_content/publish.html
@@ -1,4 +1,4 @@
-<h4>$r.translate("publish.header")</h4>
+<div class="o_sel_publish_nodes"><h4>$r.translate("publish.header")</h4>
 <div class="o_important">
 	<h5>$r.translate("pbl.intro.warning.header")</h5>
 	$r.translate("pbl.intro.warning")
@@ -12,4 +12,5 @@ $r.render("seltree")
 <div class="o_togglecheck">
 	<input type="checkbox" checked="checked" disabled="disabled" />$r.render("checkall")
 	<input type="checkbox" disabled="disabled" />$r.render("uncheckall")
+</div>
 </div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/editor/_content/publish_update.html b/src/main/java/org/olat/course/editor/_content/publish_update.html
index c85f36b604d..60f5c4020c4 100644
--- a/src/main/java/org/olat/course/editor/_content/publish_update.html
+++ b/src/main/java/org/olat/course/editor/_content/publish_update.html
@@ -1,7 +1,9 @@
+<div class="o_sel_publish_update">
 <h4>$r.translate("publish.step.update.title")</h4>
 #if($r.available("updateNotes"))
 	<div class='o_info'>$r.translate("publish.update.description")</div>
 	$r.render("updateNotes")
 #else
-	$r.translate("publish.update.nothing")
-#end
\ No newline at end of file
+	<div class='o_info'>$r.translate("publish.update.nothing")</div>
+#end
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/wizard/ImportMemberByUsernamesController.java b/src/main/java/org/olat/course/member/wizard/ImportMemberByUsernamesController.java
index 52a82e93697..bda5c3cdaab 100644
--- a/src/main/java/org/olat/course/member/wizard/ImportMemberByUsernamesController.java
+++ b/src/main/java/org/olat/course/member/wizard/ImportMemberByUsernamesController.java
@@ -61,6 +61,7 @@ public class ImportMemberByUsernamesController extends StepFormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		idata = uifactory.addTextAreaElement("addusers", "form.addusers", -1, 15, 40, true, " ", formLayout);
+		idata.setElementCssClass("o_sel_user_import");
 		idata.setExampleKey ("form.names.example", null);
 	}
 
diff --git a/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewIdentitiesController.java b/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewIdentitiesController.java
index 90d8973787b..d85d5e951e5 100644
--- a/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewIdentitiesController.java
+++ b/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewIdentitiesController.java
@@ -96,6 +96,7 @@ public class ImportMemberOverviewIdentitiesController extends StepFormBasicContr
 	
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		formLayout.setElementCssClass("o_sel_user_import_overview");
 		if(notfounds != null && !notfounds.isEmpty()) {
 			String page = velocity_root + "/warn_notfound.html";
 			FormLayoutContainer warnLayout = FormLayoutContainer.createCustomFormLayout("warnNotFounds", getTranslator(), page);
diff --git a/src/main/java/org/olat/course/member/wizard/ImportMemberPermissionChoiceController.java b/src/main/java/org/olat/course/member/wizard/ImportMemberPermissionChoiceController.java
index d0a7b56c666..db52f11c279 100644
--- a/src/main/java/org/olat/course/member/wizard/ImportMemberPermissionChoiceController.java
+++ b/src/main/java/org/olat/course/member/wizard/ImportMemberPermissionChoiceController.java
@@ -42,7 +42,7 @@ public class ImportMemberPermissionChoiceController extends StepFormBasicControl
 	public ImportMemberPermissionChoiceController(UserRequest ureq, WindowControl wControl,
 			RepositoryEntry repoEntry, BusinessGroup group, boolean overrideManaged,
 			Form rootForm, StepsRunContext runContext) {
-		super(ureq, wControl, rootForm, runContext, LAYOUT_VERTICAL, null);
+		super(ureq, wControl, rootForm, runContext, LAYOUT_BAREBONE, null);
 		
 		permissionCtrl = new EditMembershipController(ureq, getWindowControl(), null, repoEntry, group, overrideManaged, rootForm);
 		listenTo(permissionCtrl);
diff --git a/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java b/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java
index 84b8d875a56..236f78c94d8 100644
--- a/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java
+++ b/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java
@@ -84,6 +84,8 @@ public class BusinessGroupModuleAdminController extends FormBasicController impl
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		FormLayoutContainer optionsContainer = FormLayoutContainer.createDefaultFormLayout("options", getTranslator());
+		optionsContainer.setFormTitle(translate("module.admin.title"));
+		optionsContainer.setFormDescription(translate("module.admin.desc"));
 		formLayout.add(optionsContainer);
 		String[] values = new String[]{
 				translate("user.allow.create"),
@@ -95,6 +97,8 @@ public class BusinessGroupModuleAdminController extends FormBasicController impl
 		allowEl.addActionListener(FormEvent.ONCHANGE);
 
 		FormLayoutContainer resourceAssignmentContainer = FormLayoutContainer.createDefaultFormLayout("resourceAssignment", getTranslator());
+		resourceAssignmentContainer.setFormTitle(translate("module.resource.title"));
+		resourceAssignmentContainer.setFormDescription(translate("module.resource.desc"));
 		formLayout.add(resourceAssignmentContainer);
 		
 		String[] courseValues = new String[]{ translate("module.resource.courses.grant") };
@@ -108,6 +112,8 @@ public class BusinessGroupModuleAdminController extends FormBasicController impl
 		assignGroupsEl.addActionListener(FormEvent.ONCHANGE);
 		
 		FormLayoutContainer privacyOptionsContainer = FormLayoutContainer.createDefaultFormLayout("privacy_options", getTranslator());
+		privacyOptionsContainer.setFormTitle(translate("module.privacy.title"));
+		privacyOptionsContainer.setFormDescription(translate("module.privacy.desc"));
 		formLayout.add(privacyOptionsContainer);
 		String[] enrollmentValues = new String[]{
 				translate("enrolment.email.users"),
@@ -152,6 +158,8 @@ public class BusinessGroupModuleAdminController extends FormBasicController impl
 		allowLeavingGroupsEl.addActionListener(FormEvent.ONCHANGE);
 				
 		FormLayoutContainer dedupCont = FormLayoutContainer.createDefaultFormLayout("dedup", getTranslator());
+		dedupCont.setFormTitle(translate("dedup.members"));
+		dedupCont.setFormDescription(translate("dedup.members.desc"));
 		formLayout.add(dedupCont);
 		dedupLink = uifactory.addFormLink("dedup.members", dedupCont, Link.BUTTON);
 	}
diff --git a/src/main/java/org/olat/group/ui/_content/bg_admin.html b/src/main/java/org/olat/group/ui/_content/bg_admin.html
index a8feba1615a..72de8c89eaf 100644
--- a/src/main/java/org/olat/group/ui/_content/bg_admin.html
+++ b/src/main/java/org/olat/group/ui/_content/bg_admin.html
@@ -1,22 +1,6 @@
 <div class="o_form clearfix">
-	<fieldset>
-		<legend>$r.translate("module.admin.title")</legend>
-		<div class="o_desc">$r.translate("module.admin.desc")</div>
-		$r.render("options")
-	</fieldset>
-	<fieldset>
-		<legend>$r.translate("module.resource.title")</legend>
-		<div class="o_desc">$r.translate("module.resource.desc")</div>
-		$r.render("resourceAssignment")
-	</fieldset>
-	<fieldset>
-		<legend>$r.translate("module.privacy.title")</legend>
-		<div class="o_desc">$r.translate("module.privacy.desc")</div>
-		$r.render("privacy_options")
-	</fieldset>
-	<fieldset>
-		<legend>$r.translate("dedup.members")</legend>
-		<div class="o_desc">$r.translate("dedup.members.desc")</div>
-		$r.render("dedup")
-	</fieldset>
+$r.render("options")
+$r.render("resourceAssignment")
+$r.render("privacy_options")
+$r.render("dedup")
 </div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/_content/edit_member.html b/src/main/java/org/olat/group/ui/main/_content/edit_member.html
index e1ae7b03c7f..3a892843de8 100644
--- a/src/main/java/org/olat/group/ui/main/_content/edit_member.html
+++ b/src/main/java/org/olat/group/ui/main/_content/edit_member.html
@@ -1,3 +1,4 @@
+<div class="o_sel_edit_permissions">
 #if($r.available("repoRights"))
 	<fieldset>
 		<legend>$editTitle</legend>
@@ -10,6 +11,7 @@
 		$r.render("groupList")
 	</fieldset>
 #end
+</div>
 #if($r.available("buttonLayout"))
 	<div class="o_button_group">$r.render("buttonLayout")</div>
 #end
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/wizard/BGMailTemplateController.java b/src/main/java/org/olat/group/ui/wizard/BGMailTemplateController.java
index d50acff65f7..5a5aad96b55 100644
--- a/src/main/java/org/olat/group/ui/wizard/BGMailTemplateController.java
+++ b/src/main/java/org/olat/group/ui/wizard/BGMailTemplateController.java
@@ -156,6 +156,7 @@ public class BGMailTemplateController extends FormBasicController {
 	
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		formLayout.setElementCssClass("o_sel_contact_form");
 		if(!mandatoryEmail) {
 			sendMail = uifactory.addCheckboxesVertical("sendmail", "", formLayout, new String[]{"xx"}, new String[]{translate("mailtemplateform.sendMailSwitchElem")}, 1);
 			sendMail.select("xx", true);
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/multiple_choices.html b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/multiple_choices.html
index 18358d4d08a..779f6701364 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/multiple_choices.html
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/multiple_choices.html
@@ -20,8 +20,8 @@
 		#end
 	</div>
 	<div class="col-sm-1">
-		<input type="checkbox" id="oo_correct-${foreach.count}s" name="correct" value="${choice.getIdentifierString()}" #if($restrictedEdit) disabled #end #if(${choice.isCorrect()}) checked #end/>
-		$f.appendFlexiFormDirtyForCheckbox("oo_correct-${foreach.count}")
+		<label for="oo_correct-${foreach.count}"><input type="checkbox" id="oo_correct-${foreach.count}" name="correct" value="${choice.getIdentifierString()}" #if($restrictedEdit) disabled #end #if(${choice.isCorrect()}) checked #end/>
+		$f.appendFlexiFormDirtyForCheckbox("oo_correct-${foreach.count}")</label>
 	</div>
 	<div class="col-sm-10">
 		$r.render(${choice.getAnswer().getComponent().getComponentName()})
diff --git a/src/main/java/org/olat/modules/portfolio/ui/wizard/MemberMailController.java b/src/main/java/org/olat/modules/portfolio/ui/wizard/MemberMailController.java
index e8df5e53bb2..03ec015d518 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/wizard/MemberMailController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/wizard/MemberMailController.java
@@ -83,6 +83,7 @@ public class MemberMailController extends StepFormBasicController {
 	
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		formLayout.setElementCssClass("o_sel_contact_form");
 		sendMailEl = uifactory.addCheckboxesVertical("sendmail", "", formLayout, new String[]{"xx"}, new String[]{translate("mail.sendMail")}, 1);
 		sendMailEl.setElementCssClass("o_pf_sel_send_mail");
 		sendMailEl.select("xx", true);
diff --git a/src/main/java/org/olat/modules/portfolio/ui/wizard/MembersOverviewIdentitiesController.java b/src/main/java/org/olat/modules/portfolio/ui/wizard/MembersOverviewIdentitiesController.java
index 104e74b5e05..d20cdb84447 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/wizard/MembersOverviewIdentitiesController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/wizard/MembersOverviewIdentitiesController.java
@@ -91,6 +91,7 @@ public class MembersOverviewIdentitiesController extends StepFormBasicController
 	
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		formLayout.setElementCssClass("o_sel_user_import_overview");
 		if(notfounds != null && !notfounds.isEmpty()) {
 			String page = velocity_root + "/warn_notfound.html";
 			FormLayoutContainer warnLayout = FormLayoutContainer.createCustomFormLayout("warnNotFounds", getTranslator(), page);
diff --git a/src/test/java/org/olat/selenium/AssessmentTest.java b/src/test/java/org/olat/selenium/AssessmentTest.java
index b8235fc47fb..fe5fb84938d 100644
--- a/src/test/java/org/olat/selenium/AssessmentTest.java
+++ b/src/test/java/org/olat/selenium/AssessmentTest.java
@@ -245,7 +245,10 @@ public class AssessmentTest {
 			.members()
 			.addMember()
 			.searchMember(ryomou, true)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
 		
 		//Ryomou open the course
 		LoginPage ryomouLoginPage = LoginPage.getLoginPage(ryomouBrowser, deploymentUrl);
@@ -377,7 +380,10 @@ public class AssessmentTest {
 			.members()
 			.addMember()
 			.searchMember(ryomou, true)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
 		
 		//Ryomou open the course
 		LoginPage ryomouLoginPage = LoginPage.getLoginPage(ryomouBrowser, deploymentUrl);
@@ -619,7 +625,11 @@ public class AssessmentTest {
 		members
 			.addMember()
 			.searchMember(rei, true)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
+		
 		// return to course
 		courseRuntime = members
 				.clickToolbarBack()
@@ -709,7 +719,11 @@ public class AssessmentTest {
 		members
 			.addMember()
 			.searchMember(rei, true)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
+		
 		// return to course
 		courseRuntime = members
 				.clickToolbarBack()
@@ -810,7 +824,10 @@ public class AssessmentTest {
 		members
 			.addMember()
 			.searchMember(ryomou, true)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
 		
 		//efficiency statement is default on
 		//go to the assessment to to set the points
@@ -901,12 +918,14 @@ public class AssessmentTest {
 		
 		URL task1Url = JunitTestHelper.class.getResource("file_resources/task_1_a.txt");
 		File task1File = new File(task1Url.toURI());
-		gtaConfig.uploadTask("Task 1", task1File);
+		String taskName1 = "Task-1";
+		gtaConfig.uploadTask(taskName1, task1File);
 		
 		URL task2Url = JunitTestHelper.class.getResource("file_resources/task_1_b.txt");
 		File task2File = new File(task2Url.toURI());
+		String taskName2 = "Task-2-b";
 		gtaConfig
-			.uploadTask("Task 2 B", task2File)
+			.uploadTask(taskName2, task2File)
 			.saveTasks()
 			.selectSolution();
 		
@@ -931,13 +950,17 @@ public class AssessmentTest {
 		groupPage
 			.addMember()
 			.searchMember(kanu, true)
-			.next().next().next()
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
 			.finish();
 		
 		groupPage
 			.addMember()
 			.searchMember(ryomou, true)
-			.next().next().next()
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
 			.finish();
 		
 		groupPage.close();
@@ -970,7 +993,7 @@ public class AssessmentTest {
 		GroupTaskPage ryomouTask = new GroupTaskPage(ryomouBrowser);
 		ryomouTask
 			.assertAssignmentAvailable()
-			.selectTask(1)
+			.selectTask(taskName2)
 			.assertSubmissionAvailable();
 		
 		//Participant 2 log in
@@ -997,7 +1020,7 @@ public class AssessmentTest {
 		String submittedText = "This is my solution";
 		GroupTaskPage kanuTask = new GroupTaskPage(kanuBrowser);
 		kanuTask
-			.assertTask("Task 2 B")
+			.assertTask(taskName2)
 			.assertSubmissionAvailable()
 			.submitFile(submit1File)
 			.submitText(submittedFilename, submittedText)
@@ -1109,7 +1132,10 @@ public class AssessmentTest {
 		membersPage
 			.importMembers()
 			.setMembers(kanu, ryomou)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
 		
 		//go to the course
 		CoursePageFragment coursePage = membersPage
@@ -1256,7 +1282,10 @@ public class AssessmentTest {
 		members
 			.importMembers()
 			.setMembers(ryomou, kanu)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
 		
 		BulkAssessmentData[] data = new BulkAssessmentData[] {
 			new BulkAssessmentData(ryomou, 8.0f, null, "Well done"),
@@ -1268,9 +1297,9 @@ public class AssessmentTest {
 			.assessmentTool()
 			.bulk()
 			.data(data)
-			.next()
-			.next()
-			.next()
+			.nextData()
+			.nextColumns()
+			.nextValidation()
 			.finish();
 		
 		//Ryomou login
diff --git a/src/test/java/org/olat/selenium/BusinessGroupTest.java b/src/test/java/org/olat/selenium/BusinessGroupTest.java
index e32f2771982..1e1e815b7b8 100644
--- a/src/test/java/org/olat/selenium/BusinessGroupTest.java
+++ b/src/test/java/org/olat/selenium/BusinessGroupTest.java
@@ -150,9 +150,9 @@ public class BusinessGroupTest {
 			.addMember();
 		
 		members.searchMember(participant, false)
-			.next()
-			.next()
-			.next()
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
 			.finish();
 		
 		LoginPage participantLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl);
@@ -431,16 +431,16 @@ public class BusinessGroupTest {
 		group.openAdminMembers()
 			.addMember()
 			.searchMember(participant, false)
-			.next()
-			.next()
-			.next()
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
 			.finish();
 		
 		group.addMember()
 			.searchMember(rei, false)
-			.next()
-			.next()
-			.next()
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
 			.finish();
 		
 		//participant login
@@ -513,11 +513,17 @@ public class BusinessGroupTest {
 			.openAdminMembers()
 			.addMember()
 			.searchMember(kanu, true)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
 		//add Ryomou
 		group.addMember()
 			.searchMember(ryomou, true)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
 		
 		//Kanu open the group
 		LoginPage kanuLoginPage = LoginPage.getLoginPage(kanuBrowser, deploymentUrl);
diff --git a/src/test/java/org/olat/selenium/CourseTest.java b/src/test/java/org/olat/selenium/CourseTest.java
index 60ffff96abf..de264c6ca78 100644
--- a/src/test/java/org/olat/selenium/CourseTest.java
+++ b/src/test/java/org/olat/selenium/CourseTest.java
@@ -153,11 +153,11 @@ public class CourseTest {
 		//publish
 		publisher
 			.assertOnPublisher()
-			.next()
+			.nextSelectNodes()
 			.selectAccess(UserAccess.guest)
-			.next()
+			.nextAccess()
 			.selectCatalog(false)
-			.next() // -> no problem found
+			.nextCatalog() // -> no problem found
 			.finish();
 		
 		//back to the course
@@ -251,9 +251,10 @@ public class CourseTest {
 		
 		courseWizard
 			.selectAllCourseElements()
-			.next()
-			.next()
+			.nextNodes()
+			.nextCatalog()
 			.finish();
+		//OOGraphene.closeErrorBox(browser);//STMP error
 		
 		RepositoryEditDescriptionPage editDescription = new RepositoryEditDescriptionPage(browser);
 		//from description editor, back to details and launch the course
@@ -308,7 +309,7 @@ public class CourseTest {
 			.assertOnNavigationPage()
 			.openAuthoringEnvironment();
 		
-		String title = "Concurrent-Edit-" + UUID.randomUUID().toString();
+		String title = "Coedit-" + UUID.randomUUID();
 		//create course
 		authoringEnv
 			.openCreateDropDown()
@@ -322,10 +323,10 @@ public class CourseTest {
 		members
 			.addMember()
 			.searchMember(coAuthor, true)
-			.next()
-			.next()
+			.nextUsers()
+			.nextOverview()
 			.selectRepositoryEntryRole(true, false, false)
-			.next()
+			.nextPermissions()
 			.finish();
 		//open the editor
 		CoursePageFragment coursePage = members
@@ -348,7 +349,7 @@ public class CourseTest {
 		//try to edit
 		CoursePageFragment coAuthorCourse = new CoursePageFragment(coAuthorBrowser);
 		coAuthorCourse
-			.edit()
+			.tryToEdit()
 			.assertOnWarning();
 		
 		//retry in list
@@ -371,7 +372,7 @@ public class CourseTest {
 		
 		//author try
 		coursePage
-			.edit()
+			.tryToEdit()
 			.assertOnWarning();
 		
 		//co-author close the editor
@@ -1073,12 +1074,12 @@ public class CourseTest {
 			.edit();
 		courseEditor
 			.publish()
-			.next()
+			.nextSelectNodes()
 			.selectAccess(UserAccess.guest)
-			.next()
+			.nextAccess()
 			.selectCatalog(true)
 			.selectCategory(node1, node2_2)
-			.next() // -> no problem found
+			//.nextCatalog() // -> no problem found
 			.finish();
 		
 		//User logs in, go to "My courses", navigate the catalog and start
@@ -1175,9 +1176,10 @@ public class CourseTest {
 		int numOfMessages = infoMsgConfig.countMessages();
 		Assert.assertEquals(3, numOfMessages);
 		
-		//old messages
-		infoMsgConfig.oldMessages();
-		int numOfOldMessages = infoMsgConfig.countMessages();
+		// count old messages
+		int numOfOldMessages = infoMsgConfig
+				.oldMessages()
+				.countMessages();
 		Assert.assertEquals(4, numOfOldMessages);
 		
 		//new messages
@@ -1186,7 +1188,8 @@ public class CourseTest {
 		Assert.assertEquals(3, numOfNewMessages);
 		
 		//edit
-		infoMsgConfig.oldMessages();
+		infoMsgConfig
+			.oldMessages();
 		infoMsgConfig
 			.editMessage("Information 2")
 			.setMessage("The latest information", "A very important info")
@@ -1317,7 +1320,7 @@ public class CourseTest {
 	 */
 	@Test
 	@RunAsClient
-	public void courseWithCalendar_alt(@InitialPage LoginPage loginPage)
+	public void createCourseWithCalendar_alt(@InitialPage LoginPage loginPage)
 	throws IOException, URISyntaxException {
 		
 		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
@@ -1505,7 +1508,7 @@ public class CourseTest {
 		cal.add(Calendar.DATE, 20);
 		Date validTo = cal.getTime();
 		
-		String title = "Remind-me-" + UUID.randomUUID().toString();
+		String title = "Remind-me-" + UUID.randomUUID();
 		//create course
 		authoringEnv
 			.openCreateDropDown()
@@ -1764,7 +1767,6 @@ public class CourseTest {
 			.getCourseForumPage(kanuBrowser)
 			.openThread("The best anime ever");
 
-		
 		//First user go to the course
 		LoginPage reiLoginPage = LoginPage.getLoginPage(reiBrowser, deploymentUrl);
 		reiLoginPage
@@ -1870,12 +1872,12 @@ public class CourseTest {
 		//publish the course
 		courseEditor
 			.publish()
-			.next()
+			.nextSelectNodes()
 			.selectAccess(UserAccess.guest)
-			.next()
+			.nextAccess()
 			.selectCatalog(true)
 			.selectCategory(null, node1)
-			.next() // -> no problem found
+			.nextCatalog() // -> no problem found
 			.finish();
 		//back in course
 		courseEditor.clickToolbarBack();
@@ -2007,10 +2009,16 @@ public class CourseTest {
 			.selectTabVisibility()
 			.setAssessmentCondition(1)
 			.save();
-
+		
+		OOGraphene.scrollTop(browser);
 		courseEditor
 			.publish()
-			.quickPublish(UserAccess.membersOnly);
+			.nextSelectNodes()
+			.selectAccess(UserAccess.membersOnly)
+			.nextAccess()
+			.selectCatalog(false)
+			.nextCatalog() // -> no problem found
+			.finish();
 		courseEditor
 			.clickToolbarBack();
 		
@@ -2021,10 +2029,10 @@ public class CourseTest {
 		members
 			.addMember()
 			.searchMember(rei, true)
-			.next()
-			.next()
+			.nextUsers()
+			.nextOverview()
 			.selectGroupAsParticipant(groupName)
-			.next()
+			.nextPermissions()
 			.finish();
 		
 		//participant search the course
@@ -2140,18 +2148,18 @@ public class CourseTest {
 			.selectMembers()
 			.addMember()
 			.searchMember(rei, true)
-			.next()
-			.next()
+			.nextUsers()
+			.nextOverview()
 			.selectGroupAsParticipant(groupName)
-			.next()
+			.nextPermissions()
 			.finish();
 		members
 			.addMember()
 			.searchMember(participant, true)
-			.next()
-			.next()
+			.nextUsers()
+			.nextOverview()
 			.selectGroupAsParticipant(groupName)
-			.next()
+			.nextPermissions()
 			.finish();
 		members
 			.clickToolbarBack();
diff --git a/src/test/java/org/olat/selenium/PortfolioV2Test.java b/src/test/java/org/olat/selenium/PortfolioV2Test.java
index ec19e8f5236..b548b0d8410 100644
--- a/src/test/java/org/olat/selenium/PortfolioV2Test.java
+++ b/src/test/java/org/olat/selenium/PortfolioV2Test.java
@@ -192,7 +192,10 @@ public class PortfolioV2Test {
 		membersPage
 			.importMembers()
 			.setMembers(ryomou)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
 		
 		//Participant log in
 		LoginPage ryomouLoginPage = LoginPage.getLoginPage(ryomouBrowser, deploymentUrl);
@@ -472,7 +475,10 @@ public class PortfolioV2Test {
 		members
 			.addMember()
 			.searchMember(ryomou, true)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
 		
 		//efficiency statement is default on
 		//go to the assessment to to set the points
@@ -689,7 +695,10 @@ public class PortfolioV2Test {
 		membersPage
 			.importMembers()
 			.setMembers(rei)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
 		
 		//Participant log in
 		LoginPage reiLoginPage = LoginPage.getLoginPage(reiBrowser, deploymentUrl);
@@ -728,10 +737,10 @@ public class PortfolioV2Test {
 			.openAccessMenu()
 			.addMember()
 			.searchMember(author, false)
-			.next()
-			.next()
+			.nextUsers()
+			.nextOverview()
 			.fillAccessRights(binderTitle, Boolean.TRUE)
-			.next()
+			.nextPermissions()
 			.deSelectEmail()
 			.finish();
 		
diff --git a/src/test/java/org/olat/selenium/UserTest.java b/src/test/java/org/olat/selenium/UserTest.java
index 9275bf4cdb0..67533c7dc6b 100644
--- a/src/test/java/org/olat/selenium/UserTest.java
+++ b/src/test/java/org/olat/selenium/UserTest.java
@@ -740,10 +740,10 @@ public class UserTest {
 		importWizard.append(username2, "vampire01", "Mizore", "Shirayuki", csv);
 		importWizard
 			.fill(csv.toString())
-			.next() // -> preview
+			.nextData() // -> preview
 			.assertGreen(2)
-			.next() // -> groups
-			.next() // -> emails
+			.nextOverview() // -> groups
+			.nextGroups() // -> emails
 			.finish();
 		
 		OOGraphene.waitAndCloseBlueMessageWindow(browser);
@@ -796,13 +796,13 @@ public class UserTest {
 		user1 = importWizard.append(user1, "Aono", "openolat2", csv);
 		importWizard
 			.fill(csv.toString())
-			.next() // -> preview
+			.nextData() // -> preview
 			.assertGreen(1)
 			.assertWarn(1)
 			.updatePasswords()
 			.updateUsers()
-			.next() // -> groups
-			.next() // -> emails
+			.nextOverview() // -> groups
+			.nextGroups() // -> emails
 			.finish();
 		
 		OOGraphene.waitAndCloseBlueMessageWindow(browser);
diff --git a/src/test/java/org/olat/selenium/page/NavigationPage.java b/src/test/java/org/olat/selenium/page/NavigationPage.java
index 64594768a18..829ad25fc19 100644
--- a/src/test/java/org/olat/selenium/page/NavigationPage.java
+++ b/src/test/java/org/olat/selenium/page/NavigationPage.java
@@ -128,11 +128,15 @@ public class NavigationPage {
 		if(links.isEmpty() || !links.get(0).isDisplayed()) {
 			//try to open the more menu
 			openMoreMenu();
-			links = browser.findElements(linkBy);
 		}
 
 		OOGraphene.waitElement(linkBy, browser);
-		browser.findElement(linkBy).click();
+		try {
+			browser.findElement(linkBy).click();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
 		OOGraphene.waitBusy(browser);
 		OOGraphene.waitingTransition(browser);
 	}
diff --git a/src/test/java/org/olat/selenium/page/core/AdministrationPage.java b/src/test/java/org/olat/selenium/page/core/AdministrationPage.java
index 39ba3a7bc70..02363a69a6b 100644
--- a/src/test/java/org/olat/selenium/page/core/AdministrationPage.java
+++ b/src/test/java/org/olat/selenium/page/core/AdministrationPage.java
@@ -101,19 +101,29 @@ public class AdministrationPage {
 	}
 	
 	public AdministrationPage setGroupConfirmationForUser(boolean mandatory) {
-		By membershipConfirmationBy = By.cssSelector("input[name='mandatory.membership'][value='users']");
-		OOGraphene.waitElement(membershipConfirmationBy, 5, browser);
-		WebElement membershipConfirmationEl = browser.findElement(membershipConfirmationBy);
-		OOGraphene.check(membershipConfirmationEl, new Boolean(mandatory));
+		By userConfirmationBy = By.xpath("//label[input[@name='mandatory.membership' and @value='users']]");
+		By userConfirmationCheckBy = By.xpath("//label/input[@name='mandatory.membership' and @value='users']");
+		
+		OOGraphene.waitElement(userConfirmationBy, browser);
+		OOGraphene.scrollTo(userConfirmationBy, browser);
+		
+		WebElement userConfirmationEl = browser.findElement(userConfirmationBy);
+		WebElement userConfirmationCheckEl = browser.findElement(userConfirmationCheckBy);
+		OOGraphene.check(userConfirmationEl, userConfirmationCheckEl, new Boolean(mandatory));
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
 	
 	public AdministrationPage setGroupConfirmationForAuthor(boolean mandatory) {
-		By membershipConfirmationBy = By.cssSelector("input[name='mandatory.membership'][value='authors']");
-		OOGraphene.waitElement(membershipConfirmationBy, 5, browser);
-		WebElement membershipConfirmationEl = browser.findElement(membershipConfirmationBy);
-		OOGraphene.check(membershipConfirmationEl, new Boolean(mandatory));
+		By authorConfirmationBy = By.xpath("//label[input[@name='mandatory.membership' and @value='authors']]");
+		By authorConfirmationCheckBy = By.xpath("//label/input[@name='mandatory.membership' and @value='authors']");
+		
+		OOGraphene.waitElement(authorConfirmationBy, 5, browser);
+		OOGraphene.scrollTo(authorConfirmationBy, browser);
+		
+		WebElement authorConfirmationEl = browser.findElement(authorConfirmationBy);
+		WebElement authorConfirmationCheckEl = browser.findElement(authorConfirmationCheckBy);
+		OOGraphene.check(authorConfirmationEl, authorConfirmationCheckEl, new Boolean(mandatory));
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
diff --git a/src/test/java/org/olat/selenium/page/core/CalendarPage.java b/src/test/java/org/olat/selenium/page/core/CalendarPage.java
index 0fbf4b5aaf9..7151b7bb006 100644
--- a/src/test/java/org/olat/selenium/page/core/CalendarPage.java
+++ b/src/test/java/org/olat/selenium/page/core/CalendarPage.java
@@ -118,9 +118,13 @@ public class CalendarPage {
 	}
 	
 	public CalendarPage setAllDay(boolean allDay) {
-		By locationBy = By.cssSelector("fieldset.o_sel_cal_entry_form div.o_sel_cal_all_day input[type='checkbox']");
+		By locationBy = By.xpath("//fieldset[contains(@class,'o_sel_cal_entry_form')]//div[contains(@class,'o_sel_cal_all_day')]//input[@type='checkbox']");
+		By labelLocationBy = By.xpath("//fieldset[contains(@class,'o_sel_cal_entry_form')]//div[contains(@class,'o_sel_cal_all_day')]//label[input[@type='checkbox']]");
+		
 		WebElement allDayEl = browser.findElement(locationBy);
-		OOGraphene.check(allDayEl, new Boolean(allDay));
+		WebElement allDayLabelEl = browser.findElement(labelLocationBy);
+		OOGraphene.scrollTo(labelLocationBy, browser);
+		OOGraphene.check(allDayLabelEl, allDayEl, new Boolean(allDay));
 		
 		if(!allDay) {
 			By hourBy = By.xpath("//fieldset[contains(@class,'o_sel_cal_entry_form')]//div[contains(@class,'o_sel_cal_begin')]//input[contains(@id,'o_dch_')]");
@@ -174,11 +178,7 @@ public class CalendarPage {
 	public CalendarPage save() {
 		By saveBy = By.cssSelector("fieldset.o_sel_cal_entry_form button.btn.btn-primary span");
 		OOGraphene.waitElement(saveBy, 5, browser);
-		
-		WebElement saveEl = browser.findElement(saveBy);
-		OOGraphene.moveTo(saveEl, browser)
-			.click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.clickAndWait(saveBy, browser);//TODO sel
 		return this;
 	}
 	
@@ -201,8 +201,7 @@ public class CalendarPage {
 	public CalendarPage delete() {
 		By deleteBy = By.cssSelector("fieldset.o_sel_cal_entry_form a.btn.o_sel_cal_delete");
 		OOGraphene.waitElement(deleteBy, 5, browser);
-		browser.findElement(deleteBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.clickAndWait(deleteBy, browser);
 		return this;
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/core/FolderPage.java b/src/test/java/org/olat/selenium/page/core/FolderPage.java
index e12aea7f27c..8627d61f1ae 100644
--- a/src/test/java/org/olat/selenium/page/core/FolderPage.java
+++ b/src/test/java/org/olat/selenium/page/core/FolderPage.java
@@ -101,7 +101,7 @@ public class FolderPage {
 		OOGraphene.tinymce(content, browser);
 		
 		By saveAndCloseButton = By.cssSelector("#o_button_saveclose a.btn");
-		browser.findElement(saveAndCloseButton).click();
+		OOGraphene.clickAndWait(saveAndCloseButton, browser);
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
diff --git a/src/test/java/org/olat/selenium/page/core/IMPage.java b/src/test/java/org/olat/selenium/page/core/IMPage.java
index 3116596ac37..df0bd09488c 100644
--- a/src/test/java/org/olat/selenium/page/core/IMPage.java
+++ b/src/test/java/org/olat/selenium/page/core/IMPage.java
@@ -21,6 +21,7 @@ package org.olat.selenium.page.core;
 
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
 
 import org.jboss.arquillian.graphene.Graphene;
 import org.olat.selenium.page.graphene.OOGraphene;
@@ -28,8 +29,6 @@ import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 
-import com.google.common.base.Predicate;
-
 /**
  * Drive the chat / instant messaging from OpenOLAT
  * 
@@ -84,31 +83,22 @@ public class IMPage {
 	 * @param message
 	 * @return
 	 */
-	public IMPage assertOnMessage(String message) {
-		Graphene.waitModel().withTimeout(10, TimeUnit.SECONDS).until(new MessagePredicate(message));
-		return this;
-	}
-	
-	private static class MessagePredicate implements Predicate<WebDriver> {
+	public IMPage assertOnMessage(final String message) {
+		final By historyBy = By.cssSelector(".o_im_chat_history .o_im_body");
 		
-		private static final By historyBy = By.cssSelector(".o_im_chat_history .o_im_body");
-		
-		private final String message;
-		
-		public MessagePredicate(String message) {
-			this.message = message;
-		}
-
-		@Override
-		public boolean apply(WebDriver browser) {
-			boolean found = false;
-			List<WebElement> history = browser.findElements(historyBy);
-			for(WebElement m:history) {
-				if(m.getText().contains(message)) {
-					found = true;
+		Graphene.waitModel().withTimeout(10, TimeUnit.SECONDS).until(new Function<WebDriver,Boolean>(){
+			@Override
+			public Boolean apply(WebDriver browser) {
+				boolean found = false;
+				List<WebElement> history = browser.findElements(historyBy);
+				for(WebElement m:history) {
+					if(m.getText().contains(message)) {
+						found = true;
+					}
 				}
+				return found;
 			}
-			return found;
-		}
+		});
+		return this;
 	}
 }
diff --git a/src/test/java/org/olat/selenium/page/course/AssessmentCEConfigurationPage.java b/src/test/java/org/olat/selenium/page/course/AssessmentCEConfigurationPage.java
index 91038ad31c3..73da8fdc44c 100644
--- a/src/test/java/org/olat/selenium/page/course/AssessmentCEConfigurationPage.java
+++ b/src/test/java/org/olat/selenium/page/course/AssessmentCEConfigurationPage.java
@@ -77,9 +77,7 @@ public class AssessmentCEConfigurationPage {
 		cutValEl.sendKeys(Float.toString(cutVal));
 		
 		By saveBy = By.cssSelector(".o_sel_course_ms_form button.btn.btn-primary");
-		browser.findElement(saveBy).click();
-		OOGraphene.waitBusy(browser);
-		
+		OOGraphene.click(saveBy, browser);
 		return this;
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/course/AssessmentToolPage.java b/src/test/java/org/olat/selenium/page/course/AssessmentToolPage.java
index 2ab27745c05..57e6c528fdb 100644
--- a/src/test/java/org/olat/selenium/page/course/AssessmentToolPage.java
+++ b/src/test/java/org/olat/selenium/page/course/AssessmentToolPage.java
@@ -71,8 +71,7 @@ public class AssessmentToolPage {
 	 */
 	public AssessmentToolPage selectUser(UserVO user) {
 		By userLinksBy = By.xpath("//div[contains(@class,'o_table_flexi')]//table//tr//td//a[text()[contains(.,'" + user.getFirstName() + "')]]");
-		WebElement userLink = browser.findElement(userLinksBy);
-		userLink.click();
+		browser.findElement(userLinksBy).click();
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
@@ -160,6 +159,7 @@ public class AssessmentToolPage {
 		By newBy = By.cssSelector("a.o_sel_assessment_tool_new_bulk_assessment");
 		browser.findElement(newBy).click();
 		OOGraphene.waitBusy(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_bulk_assessment_data"), browser);
 		return new BulkAssessmentPage(browser);
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/course/BulkAssessmentPage.java b/src/test/java/org/olat/selenium/page/course/BulkAssessmentPage.java
index 35d89457111..51dc3b99697 100644
--- a/src/test/java/org/olat/selenium/page/course/BulkAssessmentPage.java
+++ b/src/test/java/org/olat/selenium/page/course/BulkAssessmentPage.java
@@ -19,7 +19,6 @@
  */
 package org.olat.selenium.page.course;
 
-import org.junit.Assert;
 import org.olat.selenium.page.graphene.OOGraphene;
 import org.olat.user.restapi.UserVO;
 import org.openqa.selenium.By;
@@ -67,22 +66,36 @@ public class BulkAssessmentPage {
 		return this;
 	}
 	
-	public BulkAssessmentPage next() {
-		WebElement next = browser.findElement(nextBy);
-		Assert.assertTrue(next.isDisplayed());
-		Assert.assertTrue(next.isEnabled());
-		next.click();
-		OOGraphene.waitBusy(browser);
+	public BulkAssessmentPage nextNodes() {
+		OOGraphene.nextStep(browser);
 		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_bulk_assessment_data"), browser);
+		return this;
+	}
+	
+	public BulkAssessmentPage nextData() {
+		OOGraphene.nextStep(browser);
+		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_bulk_assessment_columns"), browser);
+		return this;
+	}
+	
+	public BulkAssessmentPage nextColumns() {
+		OOGraphene.nextStep(browser);
+		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("div.o_sel_bulk_assessment_validation"), browser);
+		return this;
+	}
+	
+	public BulkAssessmentPage nextValidation() {
+		OOGraphene.nextStep(browser);
+		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_bulk_assessment_schedule"), browser);
 		return this;
 	}
 	
 	public BulkAssessmentPage finish() {
-		WebElement finish = browser.findElement(finishBy);
-		Assert.assertTrue(finish.isDisplayed());
-		Assert.assertTrue(finish.isEnabled());
-		finish.click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.finishStep(browser);
 		OOGraphene.waitAndCloseBlueMessageWindow(browser);
 		return this;
 	}
diff --git a/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java b/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java
index 86ad1dd77e5..909fcf06b1a 100644
--- a/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java
+++ b/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java
@@ -22,7 +22,6 @@ package org.olat.selenium.page.course;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.jboss.arquillian.graphene.Graphene;
 import org.junit.Assert;
 import org.olat.selenium.page.graphene.OOGraphene;
 import org.openqa.selenium.By;
@@ -218,16 +217,12 @@ public class CourseEditorPageFragment {
 	public CourseEditorPageFragment createNode(String nodeAlias) {
 		OOGraphene.waitElement(createNodeButton, 5, browser);
 		browser.findElement(createNodeButton).click();
-		OOGraphene.waitElement(createNodeModalBy, browser);
 		
 		//modal
-		WebElement createNodeModal = browser.findElement(createNodeModalBy);
-		
-		//create the node
-		By node = By.className("o_sel_course_editor_node-" + nodeAlias);
-		WebElement createNodeLink = createNodeModal.findElement(node);
-		Assert.assertTrue(createNodeLink.isDisplayed());
-		createNodeLink.click();
+		OOGraphene.waitBusyAndScrollTop(browser);
+		OOGraphene.waitModalDialog(browser);
+		By node = By.xpath("//div[@id='o_course_editor_choose_nodetype']//a[contains(@class,'o_sel_course_editor_node-" + nodeAlias + "')]");
+		browser.findElement(node).click();
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
@@ -239,8 +234,9 @@ public class CourseEditorPageFragment {
 	 * @return
 	 */
 	public CourseEditorPageFragment nodeTitle(String title) {
-		By shortTitle = By.cssSelector("div.o_sel_node_editor_shorttitle input");
-		WebElement shortTitleEl = browser.findElement(shortTitle);
+		By shortTitleBy = By.cssSelector("div.o_sel_node_editor_shorttitle input[type='text']");
+		OOGraphene.waitElement(shortTitleBy, 5, browser);
+		WebElement shortTitleEl = browser.findElement(shortTitleBy);
 		shortTitleEl.clear();
 		shortTitleEl.sendKeys(title);
 		
@@ -250,9 +246,10 @@ public class CourseEditorPageFragment {
 		titleEl.sendKeys(title);
 		
 		By saveButton = By.cssSelector("button.o_sel_node_editor_submit");
+		OOGraphene.scrollTo(saveButton, browser);
 		browser.findElement(saveButton).click();
 		OOGraphene.waitBusy(browser);
-		
+
 		return this;
 	}
 	
@@ -283,6 +280,7 @@ public class CourseEditorPageFragment {
 		By changeNodeLinkBy = By.cssSelector("a.o_sel_course_editor_move_node");
 		browser.findElement(changeNodeLinkBy).click();
 		OOGraphene.waitBusy(browser);
+		OOGraphene.waitModalDialog(browser);
 		
 		By targetNodeBy = By.xpath("//div[contains(@class,'o_tree_insert_tool')]//a[contains(@title,'" + targetNodeTitle + "')]");
 		browser.findElement(targetNodeBy).click();
@@ -535,11 +533,9 @@ public class CourseEditorPageFragment {
 		WebElement publishButton = browser.findElement(publishButtonBy);
 		Assert.assertTrue(publishButton.isDisplayed());
 		publishButton.click();
-		
-		By modalBy = By.className("modal");
-		OOGraphene.waitElement(modalBy, browser);
-		WebElement modal = browser.findElement(By.className("modal"));
-		return Graphene.createPageFragment(PublisherPageFragment.class, modal);
+		OOGraphene.waitBusy(browser);
+		OOGraphene.waitElement(By.cssSelector("div.o_sel_publish_nodes"), 5, browser);
+		return new PublisherPageFragment(browser);
 	}
 	
 	/**
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 477bfd3df61..764b5188c5b 100644
--- a/src/test/java/org/olat/selenium/page/course/CoursePageFragment.java
+++ b/src/test/java/org/olat/selenium/page/course/CoursePageFragment.java
@@ -57,7 +57,7 @@ public class CoursePageFragment {
 	public static final By treeContainerBy = By.id("o_main_left_content");
 	public static final By efficiencyStatementsBy = By.className("o_sel_course_options_certificates");
 	
-	private WebDriver browser;
+	private final WebDriver browser;
 	
 	public CoursePageFragment(WebDriver browser) {
 		this.browser = browser;
@@ -183,10 +183,28 @@ public class CoursePageFragment {
 	}
 	
 	/**
-	 * Click the editor link in the tools drop-down
-	 * @return
+	 * Click the editor link in the tools drop-down and
+	 * wait the edit mode.
+	 * 
+	 * @return Itself
 	 */
 	public CourseEditorPageFragment edit() {
+		if(!browser.findElement(toolsMenu).isDisplayed()) {
+			openToolsMenu();
+		}
+		browser.findElement(editCourseBy).click();
+		OOGraphene.waitBusy(browser);
+		OOGraphene.waitElement(By.xpath("//div[contains(@class,'o_edit_mode')]"), 5, browser);
+		OOGraphene.closeBlueMessageWindow(browser);
+		return new CourseEditorPageFragment(browser);
+	}
+	
+	/**
+	 * Try to edit the course but don't wait the edit mode.
+	 * 
+	 * @return Itself
+	 */
+	public CourseEditorPageFragment tryToEdit() {
 		if(!browser.findElement(toolsMenu).isDisplayed()) {
 			openToolsMenu();
 		}
diff --git a/src/test/java/org/olat/selenium/page/course/CourseWizardPage.java b/src/test/java/org/olat/selenium/page/course/CourseWizardPage.java
index e3c35c36ef5..e4e4c910531 100644
--- a/src/test/java/org/olat/selenium/page/course/CourseWizardPage.java
+++ b/src/test/java/org/olat/selenium/page/course/CourseWizardPage.java
@@ -21,8 +21,6 @@ package org.olat.selenium.page.course;
 
 import java.util.List;
 
-import org.jboss.arquillian.drone.api.annotation.Drone;
-import org.jboss.arquillian.graphene.Graphene;
 import org.junit.Assert;
 import org.olat.selenium.page.graphene.OOGraphene;
 import org.openqa.selenium.By;
@@ -39,29 +37,37 @@ import org.openqa.selenium.WebElement;
  */
 public class CourseWizardPage {
 	
-	public static final By nextBy = By.className("o_wizard_button_next");
-	public static final By finishBy = By.className("o_wizard_button_finish");
+	private final WebDriver browser;
 	
-	@Drone
-	private WebDriver browser;
+	public CourseWizardPage(WebDriver browser) {
+		this.browser = browser;
+	}
 	
 	public static CourseWizardPage getWizard(WebDriver browser) {
-		By modalBy = By.className("modal-content");
-		WebElement modal = browser.findElement(modalBy);
-		return Graphene.createPageFragment(CourseWizardPage.class, modal);
+		return new CourseWizardPage(browser);
 	}
 	
 	/**
-	 * Next
-	 * @return this
+	 * Click next on the step which selects the course elements.
+	 * 
+	 * @return Itself
+	 */
+	public CourseWizardPage nextNodes() {
+		OOGraphene.nextStep(browser);
+		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("div.o_sel_catalog_chooser_tree"), 5, browser);
+		return this;
+	}
+	
+	/**
+	 * Click next the step which selects a catalog entry.
+	 * 
+	 * @return Itself
 	 */
-	public CourseWizardPage next() {
-		WebElement next = browser.findElement(nextBy);
-		Assert.assertTrue(next.isDisplayed());
-		Assert.assertTrue(next.isEnabled());
-		next.click();
-		OOGraphene.waitBusy(browser);
+	public CourseWizardPage nextCatalog() {
+		OOGraphene.nextStep(browser);
 		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_repositoryentry_access"), 5, browser);
 		return this;
 	}
 	
@@ -70,12 +76,7 @@ public class CourseWizardPage {
 	 * @return this
 	 */
 	public CourseWizardPage finish() {
-		WebElement finish = browser.findElement(finishBy);
-		Assert.assertTrue(finish.isDisplayed());
-		Assert.assertTrue(finish.isEnabled());
-		finish.click();
-		OOGraphene.waitBusy(browser);
-		OOGraphene.waitAndCloseBlueMessageWindow(browser);
+		OOGraphene.finishStep(browser);
 		return this;
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/course/EasyConditionConfigPage.java b/src/test/java/org/olat/selenium/page/course/EasyConditionConfigPage.java
index 3f0fb75f827..6f9f0dead70 100644
--- a/src/test/java/org/olat/selenium/page/course/EasyConditionConfigPage.java
+++ b/src/test/java/org/olat/selenium/page/course/EasyConditionConfigPage.java
@@ -56,7 +56,8 @@ public class EasyConditionConfigPage {
 	public EasyConditionConfigPage createBusinessGroup(String name) {
 		By createBy = By.cssSelector("a.o_sel_condition_create_groups");
 		browser.findElement(createBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.waitModalDialog(browser);
+		OOGraphene.waitBusyAndScrollTop(browser);
 		
 		//fill the form
 		By nameBy = By.cssSelector(".o_sel_group_edit_title input[type='text']");
@@ -94,5 +95,4 @@ public class EasyConditionConfigPage {
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
-
-}
+}
\ No newline at end of file
diff --git a/src/test/java/org/olat/selenium/page/course/GroupTaskPage.java b/src/test/java/org/olat/selenium/page/course/GroupTaskPage.java
index 1811add270f..d4ab680132c 100644
--- a/src/test/java/org/olat/selenium/page/course/GroupTaskPage.java
+++ b/src/test/java/org/olat/selenium/page/course/GroupTaskPage.java
@@ -51,6 +51,7 @@ public class GroupTaskPage {
 	
 	public GroupTaskPage assertAssignmentAvailable() {
 		By assignmentBy = By.id("o_step_assignement_content");
+		OOGraphene.waitElement(assignmentBy, browser);
 		List<WebElement> assignementEls = browser.findElements(assignmentBy);
 		Assert.assertEquals(1, assignementEls.size());
 		return this;
@@ -58,6 +59,7 @@ public class GroupTaskPage {
 	
 	public GroupTaskPage assertTask(String taskName) {
 		By selectLinkBy = By.xpath("//div[@id='o_step_assignement_content']//h5//span[contains(text(),'" + taskName + "')]");
+		OOGraphene.waitElement(selectLinkBy, browser);
 		List<WebElement> selectLinkEls = browser.findElements(selectLinkBy);
 		Assert.assertFalse(selectLinkEls.isEmpty());
 		return this;
@@ -65,6 +67,7 @@ public class GroupTaskPage {
 	
 	public GroupTaskPage assertSubmissionAvailable() {
 		By assignmentBy = By.id("o_step_submit_content");
+		OOGraphene.waitElement(assignmentBy, browser);
 		List<WebElement> assignementEls = browser.findElements(assignmentBy);
 		Assert.assertEquals(1, assignementEls.size());
 		return this;
@@ -79,6 +82,13 @@ public class GroupTaskPage {
 		return this;
 	}
 	
+	public GroupTaskPage selectTask(String name) {
+		By taskBy = By.xpath("//div[@id='o_step_assignement_content']//table//tr[td[contains(text(),'" + name + "')]]/td//a[contains(@href,'select')]");
+		OOGraphene.clickAndWait(taskBy, browser);
+		OOGraphene.waitAndCloseBlueMessageWindow(browser);
+		return this;
+	}
+	
 	public GroupTaskPage submitFile(File file) {
 		return uploadFile("o_step_submit_content", file);
 	}
@@ -89,8 +99,7 @@ public class GroupTaskPage {
 	
 	private GroupTaskPage uploadFile(String stepId, File file) {
 		By uploadButtonBy = By.cssSelector("#" + stepId + " .o_sel_course_gta_submit_file");
-		browser.findElement(uploadButtonBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.clickAndWait(uploadButtonBy, browser);
 		OOGraphene.waitModalDialog(browser);
 		
 		By inputBy = By.cssSelector(".o_fileinput input[type='file']");
@@ -105,8 +114,7 @@ public class GroupTaskPage {
 	
 	public GroupTaskPage submitText(String filename, String text) {
 		By uploadButtonBy = By.cssSelector("#o_step_submit_content .o_sel_course_gta_create_doc");
-		browser.findElement(uploadButtonBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.clickAndWait(uploadButtonBy, browser);
 		OOGraphene.waitModalDialog(browser);
 		
 		By filenameBy = By.cssSelector(".o_sel_course_gta_doc_filename input[type='text']");
@@ -124,8 +132,7 @@ public class GroupTaskPage {
 	
 	public GroupTaskPage submitDocuments() {
 		By submitBy = By.cssSelector("#o_step_submit_content .o_sel_course_gta_submit_docs");
-		browser.findElement(submitBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.clickAndWait(submitBy, browser);
 		
 		//confirm
 		confirmDialog();
@@ -136,7 +143,6 @@ public class GroupTaskPage {
 	public GroupTaskPage submitRevision() {
 		By submitBy = By.cssSelector("#o_step_revision_content .o_sel_course_gta_submit_revisions");
 		browser.findElement(submitBy).click();
-		OOGraphene.waitBusy(browser);
 		return confirmDialog();
 	}
 	
@@ -144,8 +150,10 @@ public class GroupTaskPage {
 	 * Confirm a yes / no dialog box
 	 */
 	private GroupTaskPage confirmDialog() {
+		OOGraphene.waitModalDialog(browser);
+		OOGraphene.waitBusyAndScrollTop(browser);
+		
 		By confirmButtonBy = By.cssSelector("div.modal-dialog div.modal-footer a");
-		OOGraphene.waitElement(confirmButtonBy, 5, browser);
 		browser.findElement(confirmButtonBy).click();
 		OOGraphene.waitBusy(browser);
 		return this;
diff --git a/src/test/java/org/olat/selenium/page/course/GroupTaskToCoachPage.java b/src/test/java/org/olat/selenium/page/course/GroupTaskToCoachPage.java
index 6ddb522856e..42296371ce4 100644
--- a/src/test/java/org/olat/selenium/page/course/GroupTaskToCoachPage.java
+++ b/src/test/java/org/olat/selenium/page/course/GroupTaskToCoachPage.java
@@ -85,8 +85,8 @@ public class GroupTaskToCoachPage {
 	
 	public GroupTaskToCoachPage reviewed() {
 		By reviewBy = By.cssSelector("#o_step_review_content .o_sel_course_gta_reviewed");
-		browser.findElement(reviewBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.waitElement(reviewBy, browser);
+		OOGraphene.clickAndWait(reviewBy, browser);
 		confirm();
 		OOGraphene.waitAndCloseBlueMessageWindow(browser);
 		return this;
@@ -94,19 +94,19 @@ public class GroupTaskToCoachPage {
 	
 	public GroupTaskToCoachPage needRevision() {
 		By reviewBy = By.cssSelector("#o_step_review_content .o_sel_course_gta_need_revision");
-		browser.findElement(reviewBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.clickAndWait(reviewBy, browser);
 		return confirm();
 	}
 	
 	public GroupTaskToCoachPage closeRevisions() {
 		By closeRevisionBy = By.cssSelector("#o_step_revision_content .o_sel_course_gta_close_revision");
-		browser.findElement(closeRevisionBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.clickAndWait(closeRevisionBy, browser);
 		return confirm();
 	}
 	
 	public GroupTaskToCoachPage confirm() {
+		OOGraphene.waitBusyAndScrollTop(browser);
+		OOGraphene.waitModalDialog(browser);
 		WebElement yesLink = browser.findElement(By.xpath("//div[contains(@class,'modal-dialog')]//a[contains(@href,'link_0')]"));
 		yesLink.click();
 		OOGraphene.waitBusy(browser);
@@ -115,8 +115,7 @@ public class GroupTaskToCoachPage {
 	
 	public GroupTaskToCoachPage uploadCorrection(File correctionFile) {
 		By uploadButtonBy = By.cssSelector("#o_step_review_content .o_sel_course_gta_submit_file");
-		browser.findElement(uploadButtonBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.clickAndWait(uploadButtonBy, browser);
 		
 		By inputBy = By.cssSelector(".o_fileinput input[type='file']");
 		OOGraphene.uploadFile(inputBy, correctionFile, browser);
@@ -158,7 +157,7 @@ public class GroupTaskToCoachPage {
 		}
 		
 		By saveAndCloseBy = By.cssSelector(".o_sel_assessment_form button.o_sel_assessment_form_save_and_close");
-		browser.findElement(saveAndCloseBy).click();
+		OOGraphene.click(saveAndCloseBy, browser);
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
@@ -190,15 +189,19 @@ public class GroupTaskToCoachPage {
 		By groupAssessmentPopupBy = By.cssSelector(".modal-body .o_sel_course_gta_group_assessment_form");
 		OOGraphene.waitElement(groupAssessmentPopupBy, 5, browser);
 		
-		By applyToAllBy = By.cssSelector(".o_sel_course_gta_group_assessment_form .o_sel_course_gta_apply_to_all input[type='checkbox']");
+		By applyToAllBy = By.xpath("//div[contains(@class,'o_sel_course_gta_group_assessment_form')]//div[contains(@class,'o_sel_course_gta_apply_to_all')]//label[input[@type='checkbox']]");
+		By applyToAllCheckBy = By.xpath("//div[contains(@class,'o_sel_course_gta_group_assessment_form')]//div[contains(@class,'o_sel_course_gta_apply_to_all')]//input[@type='checkbox']");
 		WebElement applyToAllEl = browser.findElement(applyToAllBy);
-		OOGraphene.check(applyToAllEl, Boolean.TRUE);
+		WebElement applyToAllCheckEl = browser.findElement(applyToAllCheckBy);
+		OOGraphene.check(applyToAllEl, applyToAllCheckEl, Boolean.TRUE);
 		OOGraphene.waitBusy(browser);
 		
 		if(passed != null) {
-			By passedBy = By.cssSelector(".o_sel_course_gta_group_assessment_form .o_sel_course_gta_group_passed input[type='checkbox']");
+			By passedBy = By.xpath("//div[contains(@class,'o_sel_course_gta_group_assessment_form')]//div[contains(@class,'o_sel_course_gta_group_passed')]//label[input[@type='checkbox']]");
+			By passedCheckBy = By.xpath("//div[contains(@class,'o_sel_course_gta_group_assessment_form')]//div[contains(@class,'o_sel_course_gta_group_passed')]//input[@type='checkbox']");
 			WebElement passedEl = browser.findElement(passedBy);
-			OOGraphene.check(passedEl, Boolean.TRUE);
+			WebElement passedCheckEl = browser.findElement(passedCheckBy);
+			OOGraphene.check(passedEl, passedCheckEl, Boolean.TRUE);
 			OOGraphene.waitBusy(browser);
 		}
 		
diff --git a/src/test/java/org/olat/selenium/page/course/InfoMessageCEPage.java b/src/test/java/org/olat/selenium/page/course/InfoMessageCEPage.java
index 96d27ffe252..315b394fa69 100644
--- a/src/test/java/org/olat/selenium/page/course/InfoMessageCEPage.java
+++ b/src/test/java/org/olat/selenium/page/course/InfoMessageCEPage.java
@@ -84,9 +84,8 @@ public class InfoMessageCEPage {
 	 * @return This page
 	 */
 	public InfoMessageCEPage next() {
-		By nextBy = By.className("o_wizard_button_next");
-		browser.findElement(nextBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.nextStep(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_info_contact"), browser);
 		return this;
 	}
 	
@@ -96,9 +95,7 @@ public class InfoMessageCEPage {
 	 * @return This page
 	 */
 	public InfoMessageCEPage finish() {
-		By finishBy = By.className("o_wizard_button_finish");
-		browser.findElement(finishBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.finishStep(browser);
 		return this;
 	}
 	
@@ -142,6 +139,7 @@ public class InfoMessageCEPage {
 		Assert.assertFalse(editEls.isEmpty());
 		editEls.get(0).click();
 		OOGraphene.waitBusy(browser);
+		OOGraphene.waitModalDialog(browser);
 		return this;
 	}
 	
@@ -206,14 +204,23 @@ public class InfoMessageCEPage {
 		return this;
 	}
 	
+	public InfoMessageCEPage scrollToMessage(String title) {
+		By titleBy = By.xpath("//div[contains(@class,'o_msg')]//div//h3[contains(text(),'" + title + "')]");
+		OOGraphene.scrollTo(titleBy, browser);
+		return this;
+	}
+	
 	/**
 	 * Click the old messages button. Raise an error if the button is not there.
 	 * 
 	 * @return This page
 	 */
 	public InfoMessageCEPage oldMessages() {
-		By oldMessagesBy = By.className("o_sel_course_info_old_msgs");
+		By oldMessagesBy = By.cssSelector("a.o_sel_course_info_old_msgs");
+		OOGraphene.waitElement(oldMessagesBy, browser);
+		OOGraphene.waitingTooLong();// I don't know why
 		browser.findElement(oldMessagesBy).click();
+		OOGraphene.scrollTop(browser);
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
diff --git a/src/test/java/org/olat/selenium/page/course/MembersPage.java b/src/test/java/org/olat/selenium/page/course/MembersPage.java
index ec9c653b2d1..3b3b3bde24b 100644
--- a/src/test/java/org/olat/selenium/page/course/MembersPage.java
+++ b/src/test/java/org/olat/selenium/page/course/MembersPage.java
@@ -52,6 +52,8 @@ public class MembersPage {
 		By addMemberBy = By.className("o_sel_course_add_member");
 		browser.findElement(addMemberBy).click();
 		OOGraphene.waitBusy(browser);
+		OOGraphene.waitModalWizard(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_usersearch_searchform"), 5, browser);
 		return new MembersWizardPage(browser);
 	}
 	
@@ -59,6 +61,8 @@ public class MembersPage {
 		By importMembersBy = By.className("o_sel_course_import_members");
 		browser.findElement(importMembersBy).click();
 		OOGraphene.waitBusy(browser);
+		OOGraphene.waitModalWizard(browser);
+		OOGraphene.waitElement(By.cssSelector("div.o_sel_user_import textarea.form-control"), 5, browser);
 		return new MembersWizardPage(browser);
 	}
 	
@@ -129,7 +133,10 @@ public class MembersPage {
 	public void quickAdd(UserVO user) {
 		addMember()
 			.searchMember(user, true)
-			.next().next().next().finish();
+			.nextUsers()
+			.nextOverview()
+			.nextPermissions()
+			.finish();
 	}
 	
 	/**
diff --git a/src/test/java/org/olat/selenium/page/course/PublisherPageFragment.java b/src/test/java/org/olat/selenium/page/course/PublisherPageFragment.java
index d3f3827a4cb..4459a72f254 100644
--- a/src/test/java/org/olat/selenium/page/course/PublisherPageFragment.java
+++ b/src/test/java/org/olat/selenium/page/course/PublisherPageFragment.java
@@ -21,14 +21,12 @@ package org.olat.selenium.page.course;
 
 import java.util.List;
 
-import org.jboss.arquillian.drone.api.annotation.Drone;
 import org.junit.Assert;
 import org.olat.selenium.page.graphene.OOGraphene;
 import org.olat.selenium.page.repository.RepositoryAccessPage.UserAccess;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
-import org.openqa.selenium.support.FindBy;
 import org.openqa.selenium.support.ui.Select;
 
 /**
@@ -47,17 +45,18 @@ public class PublisherPageFragment {
 	public static final By selectAccessBy = By.cssSelector("div.o_sel_course_publish_wizard select");
 	public static final By selectCatalogYesNoBy = By.cssSelector("div.o_sel_course_publish_wizard select");
 	
-	@Drone
-	private WebDriver browser;
+	private final WebDriver browser;
 	
-	@FindBy(className="o_sel_course_publish_wizard")
-	private WebElement publishBody;
+	public PublisherPageFragment(WebDriver browser) {
+		this.browser = browser;
+	}
 	
 	public PublisherPageFragment assertOnPublisher() {
-		Assert.assertTrue(publishBody.isDisplayed());
+		OOGraphene.waitModalWizard(browser);
+		By publishWizardBy = By.className("o_sel_course_publish_wizard");
+		OOGraphene.waitElement(publishWizardBy, 5, browser);
 		return this;
 	}
-	
 
 	public void quickPublish() {
 		quickPublish(UserAccess.guest);
@@ -65,21 +64,29 @@ public class PublisherPageFragment {
 	
 	public void quickPublish(UserAccess access) {
 		assertOnPublisher()
-			.next()
+			.nextSelectNodes()
 			.selectAccess(access)
-			.next()
+			.nextAccess()
 			.selectCatalog(false)
-			.next() // -> no problem found
+			.nextCatalog() // -> no problem found
 			.finish();
 	}
 	
-	public PublisherPageFragment next() {
-		WebElement next = browser.findElement(nextBy);
-		Assert.assertTrue(next.isDisplayed());
-		Assert.assertTrue(next.isEnabled());
-		next.click();
-		OOGraphene.waitBusy(browser);
-		OOGraphene.closeBlueMessageWindow(browser);
+	public PublisherPageFragment nextSelectNodes() {
+		OOGraphene.nextStep(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_repositoryentry_access"), 5, browser);
+		return this;
+	}
+	
+	public PublisherPageFragment nextAccess() {
+		OOGraphene.nextStep(browser);
+		OOGraphene.waitElement(By.cssSelector("div.o_course_editor_publish"), 5, browser);
+		return this;
+	}
+	
+	public PublisherPageFragment nextCatalog() {
+		OOGraphene.nextStep(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_publish_update"), 5, browser);
 		return this;
 	}
 	
@@ -95,15 +102,19 @@ public class PublisherPageFragment {
 	
 	public PublisherPageFragment selectAccess(UserAccess access) {
 		if(access == UserAccess.none) {
-			By userSwitch = By.cssSelector("#o_cousersSwitch input[type='radio'][value='n']");
-			browser.findElement(userSwitch).click();
+			By labelSwitchBy = By.xpath("//div[@id='o_cousersSwitch']//label[input[@name='usersSwitch'][@type='radio'][@value='n']]");
+			browser.findElement(labelSwitchBy).click();
 			OOGraphene.waitBusy(browser);
 		} else {
-			By userSwitch = By.cssSelector("#o_cousersSwitch input[type='radio'][value='y']");
-			browser.findElement(userSwitch).click();
+			By labelSwitchBy = By.xpath("//div[@id='o_cousersSwitch']//label[input[@name='usersSwitch'][@type='radio'][@value='y']]");
+			browser.findElement(labelSwitchBy).click();
 			OOGraphene.waitBusy(browser);
 			
-			By publishForUserBy = By.cssSelector("#o_fiopublishedForUsers_SELBOX");
+			By accessConfigurationBy = By.cssSelector("fieldset.o_ac_configuration");
+			OOGraphene.waitElement(accessConfigurationBy, 5, browser);
+			
+			By publishForUserBy = By.id("o_fiopublishedForUsers_SELBOX");
+			OOGraphene.scrollTo(publishForUserBy, browser);
 			WebElement publishForUserEl = browser.findElement(publishForUserBy);
 			Select publishForUserSelect = new Select(publishForUserEl);
 			switch(access) {
@@ -118,6 +129,7 @@ public class PublisherPageFragment {
 	}
 	
 	public PublisherPageFragment selectCatalog(boolean access) {
+		OOGraphene.waitElement(selectCatalogYesNoBy, 5, browser);
 		WebElement select = browser.findElement(selectCatalogYesNoBy);
 		new Select(select).selectByValue(access ? "yes" : "no");
 		return this;
diff --git a/src/test/java/org/olat/selenium/page/forum/ForumPage.java b/src/test/java/org/olat/selenium/page/forum/ForumPage.java
index 1cd22698d4e..19846100f6b 100644
--- a/src/test/java/org/olat/selenium/page/forum/ForumPage.java
+++ b/src/test/java/org/olat/selenium/page/forum/ForumPage.java
@@ -118,7 +118,7 @@ public class ForumPage {
 		
 		//save
 		By saveBy = By.cssSelector("div.modal-content form button.btn-primary");
-		browser.findElement(saveBy).click();
+		OOGraphene.click(saveBy, browser);
 		OOGraphene.waitBusy(browser);
 		By messageTitleBy = By.xpath("//div[contains(@class,'o_forum_message')][//h4[contains(text(),'" + title + "')]]");
 		OOGraphene.waitElement(messageTitleBy, 5, browser);
@@ -214,7 +214,7 @@ public class ForumPage {
 		OOGraphene.tinymce(reply, browser);
 		
 		By saveBy = By.cssSelector("fieldset.o_sel_forum_message_form button.btn-primary");
-		browser.findElement(saveBy).click();
+		OOGraphene.click(saveBy, browser);
 		return this;
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/graphene/BusyPredicate.java b/src/test/java/org/olat/selenium/page/graphene/BusyPredicate.java
index e84e63822de..7852f6f58f7 100644
--- a/src/test/java/org/olat/selenium/page/graphene/BusyPredicate.java
+++ b/src/test/java/org/olat/selenium/page/graphene/BusyPredicate.java
@@ -19,11 +19,11 @@
  */
 package org.olat.selenium.page.graphene;
 
+import java.util.function.Function;
+
 import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebDriver;
 
-import com.google.common.base.Predicate;
-
 /**
  * 
  * Predicate which test the busy flag used to lock the
@@ -33,10 +33,10 @@ import com.google.common.base.Predicate;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class BusyPredicate implements Predicate<WebDriver> {
+public class BusyPredicate implements Function<WebDriver,Boolean> {
 	
 	@Override
-	public boolean apply(WebDriver driver) {
+	public Boolean apply(WebDriver driver) {
         Object busy = ((JavascriptExecutor)driver)
         		.executeScript("return (typeof window.o_info === 'undefined') || window.o_info.linkbusy");
         return Boolean.FALSE.equals(busy);
diff --git a/src/test/java/org/olat/selenium/page/graphene/InViewportPredicate.java b/src/test/java/org/olat/selenium/page/graphene/BusyScrollToPredicate.java
similarity index 50%
rename from src/test/java/org/olat/selenium/page/graphene/InViewportPredicate.java
rename to src/test/java/org/olat/selenium/page/graphene/BusyScrollToPredicate.java
index 6826b6a042c..67bde4b2324 100644
--- a/src/test/java/org/olat/selenium/page/graphene/InViewportPredicate.java
+++ b/src/test/java/org/olat/selenium/page/graphene/BusyScrollToPredicate.java
@@ -19,43 +19,31 @@
  */
 package org.olat.selenium.page.graphene;
 
-import org.openqa.selenium.By;
+import java.util.function.Function;
+
 import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
-
-import com.google.common.base.Predicate;
 
 /**
- * Experimental predicate which check if an element is
- * in the viewport.
  * 
- * Initial date: 7 mars 2017<br>
+ * Observe the scrolling flag of the o_scrollToElement method.
+ * 
+ * Initial date: 23.05.2016<br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class InViewportPredicate implements Predicate<WebDriver> {
-	
-	private final By by;
-	
-	public InViewportPredicate(By by) {
-		this.by = by;
-	}
+public class BusyScrollToPredicate implements Function<WebDriver,Boolean> {
 	
+	private int count = 0;
+
 	@Override
-	public boolean apply(WebDriver driver) {
-		WebElement element = driver.findElement(by);
-		StringBuilder sb = new StringBuilder();
-		sb.append("var rect = arguments[0].getBoundingClientRect();")
-		  .append(" console.log(rect); return (")
-		  .append("  rect.top >= 0 &&")
-		  .append("  rect.left >= 0 &&")
-		  .append("  rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&")
-		  .append("  rect.right <= (window.innerWidth || document.documentElement.clientWidth)")
-		  .append(" );");
-		
-        Object busy = ((JavascriptExecutor)driver)
-        		.executeScript(sb.toString(), element);
-        return Boolean.TRUE.equals(busy);
+	public Boolean apply(WebDriver driver) {
+        Number y = (Number)((JavascriptExecutor)driver).executeScript("return (((typeof window.o_info === 'undefined') || window.o_info.linkbusy) ? -1 : window.pageYOffset);");
+        if(y.intValue() != 0) {
+        	count = 0;
+        } else if(y.intValue() == 0) {
+        	count++;
+        }
+        return count > 2;
     }
 }
diff --git a/src/test/java/org/olat/selenium/page/graphene/CloseAlertInfoPredicate.java b/src/test/java/org/olat/selenium/page/graphene/CloseAlertInfoPredicate.java
index 96612f51c32..75dac60aa88 100644
--- a/src/test/java/org/olat/selenium/page/graphene/CloseAlertInfoPredicate.java
+++ b/src/test/java/org/olat/selenium/page/graphene/CloseAlertInfoPredicate.java
@@ -20,13 +20,12 @@
 package org.olat.selenium.page.graphene;
 
 import java.util.List;
+import java.util.function.Function;
 
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 
-import com.google.common.base.Predicate;
-
 /**
  * 
  * Predicate which test if the alert disappear
@@ -35,12 +34,12 @@ import com.google.common.base.Predicate;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class CloseAlertInfoPredicate implements Predicate<WebDriver> {
+public class CloseAlertInfoPredicate implements Function<WebDriver,Boolean> {
 	
 	private static final By alertBy = By.cssSelector("div.o_alert_info");
 	
 	@Override
-	public boolean apply(WebDriver driver) {
+	public Boolean apply(WebDriver driver) {
 		List<WebElement> closeButtons = driver.findElements(alertBy);
         return closeButtons.isEmpty();
     }
diff --git a/src/test/java/org/olat/selenium/page/graphene/NavBarTransitionPredicate.java b/src/test/java/org/olat/selenium/page/graphene/NavBarTransitionPredicate.java
index c651855493c..5669cb022bc 100644
--- a/src/test/java/org/olat/selenium/page/graphene/NavBarTransitionPredicate.java
+++ b/src/test/java/org/olat/selenium/page/graphene/NavBarTransitionPredicate.java
@@ -19,11 +19,11 @@
  */
 package org.olat.selenium.page.graphene;
 
+import java.util.function.Function;
+
 import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebDriver;
 
-import com.google.common.base.Predicate;
-
 /**
  * Observe the boolean flag which is set at the beginning and 
  * the end of the transition of the off canvas navigation bar.
@@ -32,10 +32,10 @@ import com.google.common.base.Predicate;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class NavBarTransitionPredicate implements Predicate<WebDriver> {
+public class NavBarTransitionPredicate implements Function<WebDriver,Boolean> {
 	
 	@Override
-	public boolean apply(WebDriver driver) {
+	public Boolean apply(WebDriver driver) {
         Object busy = ((JavascriptExecutor)driver)
         		.executeScript("return (window.OPOL.navbar.offcanvasTransitioning)");
         return Boolean.FALSE.equals(busy);
diff --git a/src/test/java/org/olat/selenium/page/graphene/OOGraphene.java b/src/test/java/org/olat/selenium/page/graphene/OOGraphene.java
index 06e0e2e6b2a..572fe4cbf2b 100644
--- a/src/test/java/org/olat/selenium/page/graphene/OOGraphene.java
+++ b/src/test/java/org/olat/selenium/page/graphene/OOGraphene.java
@@ -35,7 +35,6 @@ import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.TimeoutException;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
-import org.openqa.selenium.interactions.Actions;
 
 /**
  * 
@@ -45,15 +44,27 @@ import org.openqa.selenium.interactions.Actions;
  */
 public class OOGraphene {
 
-	private static final long poolingDuration = 50;//ms
-	private static final long waitTinyDuration = 15;//seconds
+	private static final long poolingDuration = 100;//ms
+	private static final long waitTinyDuration = 50;//seconds
+	private static final long defaultTimeout = 5;//seconds
 
-	private static final By closeBlueBoxButtonBy = By.cssSelector("div.o_alert_info div.o_sel_info_message a.o_alert_close.o_sel_info_close i.o_icon_close");
+	private static final By closeBlueBoxButtonBy = By.cssSelector("div.o_alert_info div.o_sel_info_message a.o_alert_close.o_sel_info_close");
+	//private static final By closeBlueBoxButtonBy = By.cssSelector("div.o_alert_info div.o_sel_info_message a.o_alert_close.o_sel_info_close i.o_icon_close");
 	private static final By closeModalDialogButtonBy = By.cssSelector("div.modal-dialog div.modal-header button.close");
 	
+	public static final By wizardNextBy = By.xpath("//div[contains(@class,'modal-footer')]//a[contains(@class,'o_wizard_button_next')]");
+	public static final By wizardFinishBy = By.xpath("//div[contains(@class,'modal-footer')]//a[contains(@class,'o_wizard_button_finish') and not(contains(@class,'o_disabled'))]");
+	
 	public static void waitModalDialog(WebDriver browser) {
 		By modalBy = By.cssSelector("div.modal-dialog div.modal-body");
-		waitElement(modalBy, 5, browser);
+		Graphene.waitModel(browser).withTimeout(5, TimeUnit.SECONDS)
+			.pollingEvery(200, TimeUnit.MILLISECONDS).until().element(modalBy).is().visible();
+	}
+	
+	public static void waitModalWizard(WebDriver browser) {
+		By modalBy = By.cssSelector("div.modal-dialog div.modal-body");
+		Graphene.waitModel(browser).withTimeout(defaultTimeout, TimeUnit.SECONDS)
+			.pollingEvery(200, TimeUnit.MILLISECONDS).until().element(modalBy).is().visible();
 	}
 	
 	public static void waitCallout(WebDriver browser) {
@@ -62,7 +73,8 @@ public class OOGraphene {
 	}
 	
 	public static void waitBusy(WebDriver browser) {
-		Graphene.waitModel(browser).pollingEvery(poolingDuration, TimeUnit.MILLISECONDS).until(new BusyPredicate());
+		Graphene.waitModel(browser).withTimeout(defaultTimeout, TimeUnit.SECONDS)
+			.pollingEvery(poolingDuration, TimeUnit.MILLISECONDS).until(new BusyPredicate());
 	}
 	
 	public static void waitBusy(WebDriver browser, int timeoutInSeconds) {
@@ -70,8 +82,13 @@ public class OOGraphene {
 			.pollingEvery(poolingDuration, TimeUnit.MILLISECONDS).until(new BusyPredicate());
 	}
 	
+	/**
+	 * 
+	 * @param element
+	 * @param browser
+	 */
 	public static void waitElement(By element, WebDriver browser) {
-		Graphene.waitModel(browser)
+		Graphene.waitModel(browser).withTimeout(5, TimeUnit.SECONDS)
 			.pollingEvery(poolingDuration, TimeUnit.MILLISECONDS).until().element(element).is().visible();
 	}
 	
@@ -88,7 +105,7 @@ public class OOGraphene {
 	}
 	
 	/**
-	 * Wait until the element is present.
+	 * Wait until the element is not present.
 	 * 
 	 * @param element The selector of the element
 	 * @param timeoutInSeconds The timeout in seconds
@@ -111,72 +128,79 @@ public class OOGraphene {
 			.pollingEvery(poolingDuration, TimeUnit.MILLISECONDS).until().element(element).is().not().visible();
 	}
 	
-	/**
-	 * Wait until the element is visible.
-	 * 
-	 * @param element The element to be visible
-	 * @param browser The web driver
-	 */
-	public static void waitElement(WebElement element, WebDriver browser) {
-		Graphene.waitModel(browser)
-			.pollingEvery(poolingDuration, TimeUnit.MILLISECONDS).until().element(element).is().visible();
+	public static void waitGui(WebDriver browser) {
+		Graphene.waitGui(browser);
 	}
 	
-	/**
-	 * Wait until the element is visible.
-	 * 
-	 * @param element The element
-	 * @param timeoutInSeconds The timeout in seconds
-	 * @param browser The web driver
-	 */
-	public static void waitElement(WebElement element, int timeoutInSeconds, WebDriver browser) {
-		Graphene.waitModel(browser).withTimeout(timeoutInSeconds, TimeUnit.SECONDS)
-			.pollingEvery(poolingDuration, TimeUnit.MILLISECONDS).until().element(element).is().visible();
+	public static void nextStep(WebDriver browser) {
+		clickAndWait(wizardNextBy, browser);
+	}
+	
+	public static void finishStep(WebDriver browser) {
+		clickAndWait(wizardFinishBy, browser);
+		OOGraphene.closeBlueMessageWindow(browser);
 	}
 	
 	/**
-	 * Wait until the element is present.
+	 * Verify the location of the button, scroll
+	 * if needed and click. There is no wait of
+	 * any sort. 
 	 * 
-	 * @param element The selector of the element
-	 * @param browser The web driver
+	 * @param buttonBy The selector
+	 * @param browser The browser
 	 */
-	public static void waitElementPresent(By element, WebDriver browser) {
-		Graphene.waitModel(browser)
-			.pollingEvery(poolingDuration, TimeUnit.MILLISECONDS).until().element(element).is().present();
+	public static void click(By buttonBy, WebDriver browser) {
+		WebElement buttonEl = browser.findElement(buttonBy);
+		boolean move = buttonEl.getLocation().getY() > 681;
+		if(move) {
+			scrollTo(buttonBy, browser);
+		}
+		browser.findElement(buttonBy).click();
 	}
 	
 	/**
-	 * Wait until the element is present.
+	 * Check the location of the button. If it's below the visible
+	 * window, it scrolls to the button, waits a little longer and
+	 * click it. After it wait until the window scroll to the top
+	 * and/or make a classic waitBusy
 	 * 
-	 * @param element The selector of the element
-	 * @param timeoutInSeconds The timeout in seconds
-	 * @param browser The web driver
+	 * @param buttonBy
+	 * @param browser
 	 */
-	public static void waitElementPresent(By element, int timeoutInSeconds, WebDriver browser) {
-		Graphene.waitModel(browser).withTimeout(timeoutInSeconds, TimeUnit.SECONDS)
-			.pollingEvery(poolingDuration, TimeUnit.MILLISECONDS).until().element(element).is().present();
+	public static void clickAndWait(By buttonBy, WebDriver browser) {
+		WebElement buttonEl = browser.findElement(buttonBy);
+		boolean move = buttonEl.getLocation().getY() > 669;
+		if(move) {
+			scrollTo(buttonBy, browser);
+		}
+		browser.findElement(buttonBy).click();
+		if(move) {
+			OOGraphene.waitBusyAndScrollTop(browser);
+		} else {
+			OOGraphene.waitBusy(browser);
+		}
 	}
 	
 	/**
-	 * The method is very, very experimental and not reliable. Only for research purpose.
-	 * 
+	 * Scroll to the element and wait a little longer.
 	 * @param by
 	 * @param browser
 	 */
-	public static void waitElementInViewport(By by, WebDriver browser) {
-		Graphene.waitModel(browser).withTimeout(5, TimeUnit.SECONDS)
-			.pollingEvery(poolingDuration, TimeUnit.MILLISECONDS)
-			.until(new InViewportPredicate(by));
+	public static void scrollTo(By by, WebDriver browser) {
+		WebElement el = browser.findElement(by);
+		((JavascriptExecutor)browser).executeScript("return arguments[0].scrollIntoView({behavior:\"instant\", block: \"end\"});", el);
+		OOGraphene.waitingALittleLonger();
 	}
 	
-	public static void waitGui(WebDriver browser) {
-		Graphene.waitGui(browser);
-	}
-	
-	public static WebElement moveTo(WebElement element, WebDriver browser) {
-		Actions actions = new Actions(browser);
-		actions.moveToElement(element).perform();
-		return element;
+	/**
+	 * Scroll to the top anchor.
+	 * 
+	 * @param browser
+	 */
+	public static void scrollTop(WebDriver browser) {
+		WebElement el = browser.findElement(By.id("o_top"));
+		((JavascriptExecutor)browser).executeScript("return arguments[0].scrollIntoView({behavior:\"instant\", block: \"end\"});", el);
+		OOGraphene.waitingALittleLonger();
 	}
 	
 	// top.tinymce.get('o_fi1000000416').setContent('<p>Hacked</p>');
@@ -220,6 +244,21 @@ public class OOGraphene {
 		}
 	}
 	
+	public static final void check(WebElement labelEl, WebElement checkboxEl, Boolean val) {
+		if(val == null) return;
+		
+		String checked = checkboxEl.getAttribute("checked");
+		if(Boolean.TRUE.equals(val)) {
+			if(checked == null) {
+				labelEl.click();
+			}
+		} else {
+			if(checked != null) {
+				labelEl.click();
+			}
+		}
+	}
+	
 	public static final void textarea(WebElement textareaEl, String content, WebDriver browser) {
 		String id = textareaEl.getAttribute("id");
 		((JavascriptExecutor)browser).executeScript("document.getElementById('" + id + "').value = '" + content + "'");
@@ -293,18 +332,36 @@ public class OOGraphene {
 		}
 	}
 	
+	/**
+	 * Wait 5 seconds. Only use it if you lose all hopes.
+	 */
+	public static final void waitingTooLong() {
+		try {
+			Thread.sleep(5000);
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+	}
+	
 	public static final void uploadFile(By inputBy, File file, WebDriver browser) {
 		WebElement input = browser.findElement(inputBy);
 		input.sendKeys(file.getAbsolutePath());
 	}
 	
-	public static final void waitScrollTop(WebDriver browser) {
+	/**
+	 * This take longer than the standard busy wait because it waits the
+	 * window is stabilized.
+	 * 
+	 * @param browser
+	 */
+	public static final void waitBusyAndScrollTop(WebDriver browser) {
 		try {
-			Graphene.waitModel(browser).ignoring(TimeoutException.class).pollingEvery(poolingDuration, TimeUnit.MILLISECONDS)
-				.until(new ScrollToPredicate());
-			waitingALittleBit();
+			Graphene.waitModel(browser)
+				.ignoring(TimeoutException.class)
+				.pollingEvery(poolingDuration, TimeUnit.MILLISECONDS)
+				.until(new BusyScrollToPredicate());
 		} catch (Exception e) {
-			//e.printStackTrace();
+			e.printStackTrace();
 		}
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/graphene/ScrollToPredicate.java b/src/test/java/org/olat/selenium/page/graphene/ScrollToPredicate.java
index 683e082d602..208f6fc9f0b 100644
--- a/src/test/java/org/olat/selenium/page/graphene/ScrollToPredicate.java
+++ b/src/test/java/org/olat/selenium/page/graphene/ScrollToPredicate.java
@@ -19,11 +19,11 @@
  */
 package org.olat.selenium.page.graphene;
 
+import java.util.function.Function;
+
 import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebDriver;
 
-import com.google.common.base.Predicate;
-
 /**
  * 
  * Observe the scrolling flag of the o_scrollToElement method.
@@ -32,12 +32,12 @@ import com.google.common.base.Predicate;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class ScrollToPredicate implements Predicate<WebDriver> {
+public class ScrollToPredicate implements Function<WebDriver,Boolean> {
 	
 	private boolean started = false;
 	
 	@Override
-	public boolean apply(WebDriver driver) {
+	public Boolean apply(WebDriver driver) {
         Object busy = ((JavascriptExecutor)driver)
         		.executeScript("return (window.o_info.scrolling)");
         if(started) {
diff --git a/src/test/java/org/olat/selenium/page/graphene/TinyMCELoadedByIdPredicate.java b/src/test/java/org/olat/selenium/page/graphene/TinyMCELoadedByIdPredicate.java
index a8871d9eb31..6ff6c24df86 100644
--- a/src/test/java/org/olat/selenium/page/graphene/TinyMCELoadedByIdPredicate.java
+++ b/src/test/java/org/olat/selenium/page/graphene/TinyMCELoadedByIdPredicate.java
@@ -19,11 +19,11 @@
  */
 package org.olat.selenium.page.graphene;
 
+import java.util.function.Function;
+
 import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebDriver;
 
-import com.google.common.base.Predicate;
-
 /**
  * Predicate which test if TinyMCE is fully loaded and specifically
  * the tiny with the specified id.
@@ -32,7 +32,7 @@ import com.google.common.base.Predicate;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class TinyMCELoadedByIdPredicate implements Predicate<WebDriver> {
+public class TinyMCELoadedByIdPredicate implements Function<WebDriver,Boolean> {
 	
 	private final String id;
 	
@@ -41,7 +41,7 @@ public class TinyMCELoadedByIdPredicate implements Predicate<WebDriver> {
 	}
 	
 	@Override
-	public boolean apply(WebDriver driver) {
+	public Boolean apply(WebDriver driver) {
         Object active = ((JavascriptExecutor)driver)
         		.executeScript("return top != null && top.tinymce != null && top.tinymce.activeEditor != null "
         				+ " && top.tinymce.activeEditor.initialized && top.tinymce.editors[0].initialized "
diff --git a/src/test/java/org/olat/selenium/page/graphene/TinyMCELoadedPredicate.java b/src/test/java/org/olat/selenium/page/graphene/TinyMCELoadedPredicate.java
index dcc430a5111..f76c7e419e1 100644
--- a/src/test/java/org/olat/selenium/page/graphene/TinyMCELoadedPredicate.java
+++ b/src/test/java/org/olat/selenium/page/graphene/TinyMCELoadedPredicate.java
@@ -19,11 +19,11 @@
  */
 package org.olat.selenium.page.graphene;
 
+import java.util.function.Function;
+
 import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebDriver;
 
-import com.google.common.base.Predicate;
-
 /**
  * 
  * Predicate which test if TinyMCE is fully loaded
@@ -32,10 +32,10 @@ import com.google.common.base.Predicate;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class TinyMCELoadedPredicate implements Predicate<WebDriver> {
+public class TinyMCELoadedPredicate implements Function<WebDriver, Boolean> {
 	
 	@Override
-	public boolean apply(WebDriver driver) {
+	public Boolean apply(WebDriver driver) {
         Object active = ((JavascriptExecutor)driver)
         		.executeScript("return top != null && top.tinymce != null && top.tinymce.activeEditor != null "
         				+ " && top.tinymce.activeEditor.initialized && top.tinymce.editors[0].initialized "
diff --git a/src/test/java/org/olat/selenium/page/graphene/TransitionPredicate.java b/src/test/java/org/olat/selenium/page/graphene/TransitionPredicate.java
index 4de6f599e43..7f76c7b73fe 100644
--- a/src/test/java/org/olat/selenium/page/graphene/TransitionPredicate.java
+++ b/src/test/java/org/olat/selenium/page/graphene/TransitionPredicate.java
@@ -19,11 +19,11 @@
  */
 package org.olat.selenium.page.graphene;
 
+import java.util.function.Function;
+
 import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebDriver;
 
-import com.google.common.base.Predicate;
-
 /**
  * Check the navigation bar states, but it's not enough. It needs
  * a wait after that (100ms seems to make the thing)
@@ -32,10 +32,10 @@ import com.google.common.base.Predicate;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class TransitionPredicate implements Predicate<WebDriver> {
+public class TransitionPredicate implements Function<WebDriver,Boolean> {
 	
 	@Override
-	public boolean apply(WebDriver driver) {
+	public Boolean apply(WebDriver driver) {
         Object busy = ((JavascriptExecutor)driver)
         		.executeScript("return (window.OPOL.navbar.state.sitesDirty || window.OPOL.navbar.state.tabsDirty || window.OPOL.navbar.state.toolsDirty)");
         return Boolean.FALSE.equals(busy);
diff --git a/src/test/java/org/olat/selenium/page/group/GroupPage.java b/src/test/java/org/olat/selenium/page/group/GroupPage.java
index d1f4c08d5c2..a8fd278704a 100644
--- a/src/test/java/org/olat/selenium/page/group/GroupPage.java
+++ b/src/test/java/org/olat/selenium/page/group/GroupPage.java
@@ -224,8 +224,11 @@ public class GroupPage {
 	}
 	
 	public GroupPage setWaitingList() {
-		By waitingListBy = By.cssSelector(".o_sel_group_edit_waiting_list input[type='checkbox']");
-		browser.findElement(waitingListBy).click();
+		By waitingListBy = By.xpath("//div[contains(@class,'o_sel_group_edit_waiting_list')]//label[input[@type='checkbox']]");
+		By waitingListCheckBy = By.xpath("//div[contains(@class,'o_sel_group_edit_waiting_list')]//input[@type='checkbox']");
+		WebElement waitingListEl = browser.findElement(waitingListBy);
+		WebElement waitingListCheckEl = browser.findElement(waitingListCheckBy);
+		OOGraphene.check(waitingListEl, waitingListCheckEl, Boolean.TRUE);
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
diff --git a/src/test/java/org/olat/selenium/page/group/MembersWizardPage.java b/src/test/java/org/olat/selenium/page/group/MembersWizardPage.java
index 6161c0b017d..2e0a7609c22 100644
--- a/src/test/java/org/olat/selenium/page/group/MembersWizardPage.java
+++ b/src/test/java/org/olat/selenium/page/group/MembersWizardPage.java
@@ -36,9 +36,6 @@ import org.openqa.selenium.WebElement;
  *
  */
 public class MembersWizardPage {
-
-	public static final By nextBy = By.className("o_wizard_button_next");
-	public static final By finishBy = By.className("o_wizard_button_finish");
 	
 	private WebDriver browser;
 	
@@ -46,23 +43,36 @@ public class MembersWizardPage {
 		this.browser = browser;
 	}
 	
-	public MembersWizardPage next() {
-		WebElement next = browser.findElement(nextBy);
-		Assert.assertTrue(next.isDisplayed());
-		Assert.assertTrue(next.isEnabled());
-		next.click();
-		OOGraphene.waitBusy(browser);
+	public MembersWizardPage nextUsers() {
+		OOGraphene.nextStep(browser);
 		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_user_import_overview"), 5, browser);
 		return this;
 	}
 	
-	public MembersWizardPage finish() {
-		WebElement finish = browser.findElement(finishBy);
-		Assert.assertTrue(finish.isDisplayed());
-		Assert.assertTrue(finish.isEnabled());
-		finish.click();
-		OOGraphene.waitBusy(browser);
+	public MembersWizardPage nextOverview() {
+		OOGraphene.nextStep(browser);
+		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("div.o_sel_edit_permissions"), 5, browser);
+		return this;
+	}
+	
+	public MembersWizardPage nextPermissions() {
+		OOGraphene.nextStep(browser);
 		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_contact_form"), browser);
+		return this;
+	}
+	
+	public MembersWizardPage finish() {
+		try {
+			By contactFormBy = By.cssSelector("fieldset.o_sel_contact_form");
+			OOGraphene.waitElement(contactFormBy, 5, browser);
+			OOGraphene.waitBusyAndScrollTop(browser);
+			OOGraphene.finishStep(browser);
+		} catch (Exception e) {
+			OOGraphene.finishStep(browser);
+		}
 		return this;
 	}
 	
@@ -82,19 +92,11 @@ public class MembersWizardPage {
 		searchFields.get(0).sendKeys(search);
 
 		By searchBy = By.cssSelector(".o_sel_usersearch_searchform a.btn-default");
-		WebElement searchButton = browser.findElement(searchBy);
-		searchButton.click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.clickAndWait(searchBy, browser);
 		
-		//check
-		By checkAllBy = By.cssSelector("div.modal div.o_table_wrapper input[type='checkbox']");
-		OOGraphene.waitElement(checkAllBy, 5, browser);
-		List<WebElement> checkAll = browser.findElements(checkAllBy);
-		Assert.assertFalse(checkAll.isEmpty());
-		for(WebElement check:checkAll) {
-			check.click();
-			OOGraphene.waitBusy(browser);
-		}
+		By selectAll = By.xpath("//div[contains(@class,'modal')]//div[contains(@class,'o_table_checkall')]/label/a[i[contains(@class,'o_icon_check_on')]]");
+		OOGraphene.waitElement(selectAll, 5, browser);
+		browser.findElement(selectAll).click();
 		return this;
 	}
 	
@@ -115,29 +117,29 @@ public class MembersWizardPage {
 			By ownerBy = By.cssSelector("label input[name='repoRights'][type='checkbox'][value='owner']");
 			WebElement ownerEl = browser.findElement(ownerBy);
 			OOGraphene.check(ownerEl, new Boolean(owner));
-			OOGraphene.waitBusy(browser);
+			OOGraphene.waitBusyAndScrollTop(browser);
 		}
 		
 		if(coach) {
 			By coachBy = By.cssSelector("label input[name='repoRights'][type='checkbox'][value='tutor']");
 			WebElement coachEl = browser.findElement(coachBy);
 			OOGraphene.check(coachEl, new Boolean(coach));
-			OOGraphene.waitBusy(browser);
+			OOGraphene.waitBusyAndScrollTop(browser);
 		}
 		
 		if(participant) {
 			By participantBy = By.cssSelector("label input[name='repoRights'][type='checkbox'][value='participant']");
 			WebElement participantEl = browser.findElement(participantBy);
 			OOGraphene.check(participantEl, new Boolean(participant));
-			OOGraphene.waitBusy(browser);
+			OOGraphene.waitBusyAndScrollTop(browser);
 		}
 		return this;
 	}
 	
 	public MembersWizardPage selectGroupAsParticipant(String groupName) {
 		By rolesBy = By.xpath("//div[contains(@class,'o_table_wrapper')]//table//tr[td[text()='" + groupName + "']]//label[contains(@class,'o_sel_role_participant')]/input");
-		List<WebElement> roleEls = browser.findElements(rolesBy);
-		roleEls.get(0).click();
+		OOGraphene.waitElement(rolesBy, 5, browser);
+		browser.findElement(rolesBy).click();
 		return this;
 	}
 }
diff --git a/src/test/java/org/olat/selenium/page/portfolio/BinderMemberWizardPage.java b/src/test/java/org/olat/selenium/page/portfolio/BinderMemberWizardPage.java
index 29cdd2e0a11..bebe79cc489 100644
--- a/src/test/java/org/olat/selenium/page/portfolio/BinderMemberWizardPage.java
+++ b/src/test/java/org/olat/selenium/page/portfolio/BinderMemberWizardPage.java
@@ -59,8 +59,24 @@ public class BinderMemberWizardPage {
 		return this;
 	}
 	
-	public BinderMemberWizardPage next() {
-		delegate.next();
+	public BinderMemberWizardPage nextUsers() {
+		OOGraphene.nextStep(browser);
+		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_user_import_overview"), browser);
+		return this;
+	}
+	
+	public BinderMemberWizardPage nextOverview() {
+		OOGraphene.nextStep(browser);
+		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("div.o_portfolio_rights"), browser);
+		return this;
+	}
+	
+	public BinderMemberWizardPage nextPermissions() {
+		OOGraphene.nextStep(browser);
+		OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_contact_form"), browser);
 		return this;
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/portfolio/BinderPage.java b/src/test/java/org/olat/selenium/page/portfolio/BinderPage.java
index 0df94928a04..ec5df8d6b5f 100644
--- a/src/test/java/org/olat/selenium/page/portfolio/BinderPage.java
+++ b/src/test/java/org/olat/selenium/page/portfolio/BinderPage.java
@@ -348,7 +348,7 @@ public class BinderPage {
 	protected void confirm() {
 		By confirmButtonBy = By.xpath("//div[contains(@class,'modal-dialo')]//div[contains(@class,'modal-footer')]/a[contains(@onclick,'link_0')]");
 		OOGraphene.waitElement(confirmButtonBy, 5, browser);
-		OOGraphene.waitScrollTop(browser);
+		OOGraphene.waitBusyAndScrollTop(browser);
 		browser.findElement(confirmButtonBy).click();
 		OOGraphene.waitBusy(browser);
 	}
diff --git a/src/test/java/org/olat/selenium/page/portfolio/BinderPublicationPage.java b/src/test/java/org/olat/selenium/page/portfolio/BinderPublicationPage.java
index 1459245b3aa..61cc9523f54 100644
--- a/src/test/java/org/olat/selenium/page/portfolio/BinderPublicationPage.java
+++ b/src/test/java/org/olat/selenium/page/portfolio/BinderPublicationPage.java
@@ -60,6 +60,7 @@ public class BinderPublicationPage {
 		OOGraphene.waitModalDialog(browser);
 		
 		By emailBy = By.cssSelector(".o_sel_pf_invitation_mail input[type='text']");
+		OOGraphene.waitElement(emailBy, browser);
 		browser.findElement(emailBy).sendKeys(email);
 		
 		//save
@@ -81,8 +82,11 @@ public class BinderPublicationPage {
 	
 	public BinderPublicationPage fillAccessRights(String name, Boolean check) {
 		By checkBy = By.xpath("//div[contains(@class,'o_portfolio_rights')]//table//tr[td[contains(text(),'" + name + "')]]/td//input[@type='checkbox']");
+		By labelCheckBy = By.xpath("//div[contains(@class,'o_portfolio_rights')]//table//tr[td[contains(text(),'" + name + "')]]/td//label[input[@type='checkbox']]");
 		WebElement checkEl = browser.findElement(checkBy);
-		OOGraphene.check(checkEl, check);
+		WebElement labelCheckEl = browser.findElement(labelCheckBy);
+		OOGraphene.scrollTo(labelCheckBy, browser);
+		OOGraphene.check(labelCheckEl, checkEl, check);
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
diff --git a/src/test/java/org/olat/selenium/page/portfolio/EntryPage.java b/src/test/java/org/olat/selenium/page/portfolio/EntryPage.java
index be0470c9e4f..6ea7a5d2755 100644
--- a/src/test/java/org/olat/selenium/page/portfolio/EntryPage.java
+++ b/src/test/java/org/olat/selenium/page/portfolio/EntryPage.java
@@ -223,7 +223,7 @@ public class EntryPage {
 	private void confirm() {
 		By confirmButtonBy = By.xpath("//div[contains(@class,'modal-dialo')]//div[contains(@class,'modal-footer')]/a[contains(@onclick,'link_0')]");
 		OOGraphene.waitElement(confirmButtonBy, 5, browser);
-		OOGraphene.waitScrollTop(browser);
+		OOGraphene.waitBusyAndScrollTop(browser);
 		browser.findElement(confirmButtonBy).click();
 		OOGraphene.waitBusy(browser);
 	}
diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21KprimEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21KprimEditorPage.java
index 9f3514b83d1..65fcfd985ed 100644
--- a/src/test/java/org/olat/selenium/page/qti/QTI21KprimEditorPage.java
+++ b/src/test/java/org/olat/selenium/page/qti/QTI21KprimEditorPage.java
@@ -62,8 +62,7 @@ public class QTI21KprimEditorPage extends QTI21AssessmentItemEditorPage {
 	
 	public QTI21KprimEditorPage save() {
 		By saveBy = By.cssSelector("fieldset.o_sel_choices_save button.btn.btn-primary");
-		browser.findElement(saveBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.click(saveBy, browser);
 		return this;
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java
index 200162a800a..6c6820e9876 100644
--- a/src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java
+++ b/src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java
@@ -52,7 +52,7 @@ public class QTI21LobEditorPage extends QTI21AssessmentItemEditorPage {
 	
 	public QTI21LobEditorPage save() {
 		By saveBy = By.cssSelector("div.o_sel_lob_save button.btn.btn-primary");
-		browser.findElement(saveBy).click();
+		OOGraphene.click(saveBy, browser);
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21MatchEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21MatchEditorPage.java
index 759580c71d5..11b02f452ec 100644
--- a/src/test/java/org/olat/selenium/page/qti/QTI21MatchEditorPage.java
+++ b/src/test/java/org/olat/selenium/page/qti/QTI21MatchEditorPage.java
@@ -86,8 +86,7 @@ public class QTI21MatchEditorPage extends QTI21AssessmentItemEditorPage {
 	
 	public QTI21MatchEditorPage save() {
 		By saveBy = By.cssSelector("div.o_sel_match_save button.btn.btn-primary");
-		browser.findElement(saveBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.click(saveBy, browser);
 		return this;
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21MultipleChoiceEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21MultipleChoiceEditorPage.java
index d5297490822..e191a816cb5 100644
--- a/src/test/java/org/olat/selenium/page/qti/QTI21MultipleChoiceEditorPage.java
+++ b/src/test/java/org/olat/selenium/page/qti/QTI21MultipleChoiceEditorPage.java
@@ -22,6 +22,7 @@ package org.olat.selenium.page.qti;
 import org.olat.selenium.page.graphene.OOGraphene;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
 
 /**
  * 
@@ -51,8 +52,11 @@ public class QTI21MultipleChoiceEditorPage extends QTI21AssessmentItemEditorPage
 	}
 	
 	public QTI21MultipleChoiceEditorPage setCorrect(int position) {
-		By correctBy = By.xpath("//div[contains(@class,'o_sel_choice_" + position + "')]//input[contains(@id,'oo_correct-')]");
-		browser.findElement(correctBy).click();
+		By correctBy = By.xpath("//div[contains(@class,'o_sel_choice_" + position + "')]//label[input[contains(@id,'oo_correct-')]]");
+		By correctCheckBy = By.xpath("//div[contains(@class,'o_sel_choice_" + position + "')]//input[contains(@id,'oo_correct-')]");
+		WebElement correctEl = browser.findElement(correctBy);
+		WebElement correctCheckEl = browser.findElement(correctCheckBy);
+		OOGraphene.check(correctEl, correctCheckEl, true);
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
@@ -65,8 +69,7 @@ public class QTI21MultipleChoiceEditorPage extends QTI21AssessmentItemEditorPage
 	
 	public QTI21MultipleChoiceEditorPage save() {
 		By saveBy = By.cssSelector("fieldset.o_sel_choices_save button.btn.btn-primary");
-		browser.findElement(saveBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.click(saveBy, browser);
 		return this;
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java
index f5125df057f..54f7ca6d059 100644
--- a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java
+++ b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java
@@ -294,8 +294,7 @@ public class QTI21Page {
 	
 	public QTI21Page endTest() {
 		By endBy = By.cssSelector("a.o_sel_end_testpart");
-		browser.findElement(endBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.clickAndWait(endBy, browser);
 		confirm();
 		return this;
 	}
@@ -443,6 +442,7 @@ public class QTI21Page {
 	 * Yes in a dialog box controller.
 	 */
 	private void confirm() {
+		OOGraphene.waitBusyAndScrollTop(browser);
 		// confirm
 		By confirmButtonBy = By.cssSelector("div.modal-dialog div.modal-footer a");
 		OOGraphene.waitElement(confirmButtonBy, 5, browser);
diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21SingleChoiceEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21SingleChoiceEditorPage.java
index f518c83876d..81a56b119d2 100644
--- a/src/test/java/org/olat/selenium/page/qti/QTI21SingleChoiceEditorPage.java
+++ b/src/test/java/org/olat/selenium/page/qti/QTI21SingleChoiceEditorPage.java
@@ -64,8 +64,7 @@ public class QTI21SingleChoiceEditorPage extends QTI21AssessmentItemEditorPage {
 	
 	public QTI21SingleChoiceEditorPage save() {
 		By saveBy = By.cssSelector("fieldset.o_sel_choices_save button.btn.btn-primary");
-		browser.findElement(saveBy).click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.click(saveBy, browser);
 		return this;
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/repository/AuthoringEnvPage.java b/src/test/java/org/olat/selenium/page/repository/AuthoringEnvPage.java
index d8f124d1a2f..7f8851e05e8 100644
--- a/src/test/java/org/olat/selenium/page/repository/AuthoringEnvPage.java
+++ b/src/test/java/org/olat/selenium/page/repository/AuthoringEnvPage.java
@@ -152,7 +152,7 @@ public class AuthoringEnvPage {
 		By createBy = By.cssSelector("div.modal.o_sel_author_create_popup .o_sel_author_create_wizard");
 		browser.findElement(createBy).click();
 		OOGraphene.waitBusy(browser);
-		return CourseWizardPage.getWizard(browser);
+		return new CourseWizardPage(browser);
 	}
 	
 	/**
@@ -210,6 +210,7 @@ public class AuthoringEnvPage {
 	
 	public void selectResource(String title) {
 		By selectBy = By.xpath("//div[contains(@class,'o_coursetable')]//a[contains(text(),'" + title + "')]");
+		OOGraphene.waitElement(selectBy, browser);
 		browser.findElement(selectBy).click();
 		OOGraphene.waitBusy(browser);
 	}
diff --git a/src/test/java/org/olat/selenium/page/repository/FeedPage.java b/src/test/java/org/olat/selenium/page/repository/FeedPage.java
index eddf29d0cc6..66a706b403d 100644
--- a/src/test/java/org/olat/selenium/page/repository/FeedPage.java
+++ b/src/test/java/org/olat/selenium/page/repository/FeedPage.java
@@ -168,8 +168,7 @@ public class FeedPage {
 	 */
 	public MediaPage addAsMedia() {
 		By addAsMediaBy = By.cssSelector(".o_post .o_portfolio_collector");
-		WebElement addAsmediaButton = browser.findElement(addAsMediaBy);
-		addAsmediaButton.click();
+		browser.findElement(addAsMediaBy).click();
 		OOGraphene.waitBusy(browser);
 		return new MediaPage(browser);
 	}
diff --git a/src/test/java/org/olat/selenium/page/user/ImportUserPage.java b/src/test/java/org/olat/selenium/page/user/ImportUserPage.java
index c089c52ae9f..ac77367275c 100644
--- a/src/test/java/org/olat/selenium/page/user/ImportUserPage.java
+++ b/src/test/java/org/olat/selenium/page/user/ImportUserPage.java
@@ -157,17 +157,25 @@ public class ImportUserPage {
 		return this;
 		
 	}
+
+	public ImportUserPage nextData() {
+		OOGraphene.nextStep(browser);
+		//OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_import_users_overview"), browser);
+		return this;
+	}
 	
-	/**
-	 * Next
-	 * @return this
-	 */
-	public ImportUserPage next() {
-		WebElement next = browser.findElement(nextBy);
-		Assert.assertTrue(next.isDisplayed());
-		Assert.assertTrue(next.isEnabled());
-		next.click();
-		OOGraphene.waitBusy(browser);
+	public ImportUserPage nextOverview() {
+		OOGraphene.nextStep(browser);
+		//OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_groups_search"), browser);
+		return this;
+	}
+	
+	public ImportUserPage nextGroups() {
+		OOGraphene.nextStep(browser);
+		//OOGraphene.closeBlueMessageWindow(browser);
+		OOGraphene.waitElement(By.cssSelector("fieldset.o_sel_users_import_contact"), browser);
 		return this;
 	}
 	
@@ -176,11 +184,7 @@ public class ImportUserPage {
 	 * @return this
 	 */
 	public ImportUserPage finish() {
-		WebElement finish = browser.findElement(finishBy);
-		Assert.assertTrue(finish.isDisplayed());
-		Assert.assertTrue(finish.isEnabled());
-		finish.click();
-		OOGraphene.waitBusy(browser);
+		OOGraphene.finishStep(browser);
 		OOGraphene.closeBlueMessageWindow(browser);
 		return this;
 	}
diff --git a/src/test/java/org/olat/selenium/page/user/UserAdminPage.java b/src/test/java/org/olat/selenium/page/user/UserAdminPage.java
index 510b2bbc66f..160a7685df9 100644
--- a/src/test/java/org/olat/selenium/page/user/UserAdminPage.java
+++ b/src/test/java/org/olat/selenium/page/user/UserAdminPage.java
@@ -137,6 +137,8 @@ public class UserAdminPage {
 		By importBy = By.cssSelector("a.o_sel_id_start_import_user_button.btn-primary");
 		browser.findElement(importBy).click();
 		OOGraphene.waitBusy(browser);
+		By dataBy = By.cssSelector("fieldset.o_sel_import_users_data");
+		OOGraphene.waitElement(dataBy, browser);
 		return new ImportUserPage(browser);
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/user/UserPreferencesPageFragment.java b/src/test/java/org/olat/selenium/page/user/UserPreferencesPageFragment.java
index ed4619cc2e0..45c187b8050 100644
--- a/src/test/java/org/olat/selenium/page/user/UserPreferencesPageFragment.java
+++ b/src/test/java/org/olat/selenium/page/user/UserPreferencesPageFragment.java
@@ -93,7 +93,7 @@ public class UserPreferencesPageFragment {
 		By saveSystemSettingsButton = By.cssSelector("div.o_sel_home_settings_gui_buttons.form-inline button[type='button']");
 		browser.findElement(saveSystemSettingsButton).click();
 		OOGraphene.waitBusy(browser);
-		OOGraphene.waitScrollTop(browser);//wait scroll top
+		OOGraphene.waitBusyAndScrollTop(browser);//wait scroll top
 		OOGraphene.waitAndCloseBlueMessageWindow(browser);
 		return this;
 	}
@@ -110,7 +110,7 @@ public class UserPreferencesPageFragment {
 		By saveSystemSettingsButton = By.cssSelector("div.o_sel_home_settings_gui_buttons.form-inline button[type='button']");
 		browser.findElement(saveSystemSettingsButton).click();
 		OOGraphene.waitBusy(browser);
-		OOGraphene.waitScrollTop(browser);
+		OOGraphene.waitBusyAndScrollTop(browser);
 		OOGraphene.waitAndCloseBlueMessageWindow(browser);
 		return this;
 	}
@@ -123,7 +123,7 @@ public class UserPreferencesPageFragment {
 		WebElement saveButton = browser.findElement(saveSystemPrefsButton);
 		saveButton.click();
 		OOGraphene.waitBusy(browser);
-		OOGraphene.waitScrollTop(browser);
+		OOGraphene.waitBusyAndScrollTop(browser);
 		OOGraphene.waitAndCloseBlueMessageWindow(browser);
 		return this;
 	}
diff --git a/src/test/resources/arquillian.xml b/src/test/resources/arquillian.xml
index 5ed8d03af92..7a01481e7b1 100644
--- a/src/test/resources/arquillian.xml
+++ b/src/test/resources/arquillian.xml
@@ -4,6 +4,8 @@
         http://jboss.org/schema/arquillian
         http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
 
+	<defaultProtocol type="Servlet 3.0" />
+	
 	<engine>
 		<property name="deploymentExportPath">target/arquillianDeployments</property>
 	</engine>
@@ -13,15 +15,23 @@
             <property name="workDir">target/arquillianDeployments</property>
 			<property name="catalinaHome">target/arq-apache-tomcat-8.0.24</property>
 			<property name="catalinaBase">target/arq-apache-tomcat-8.0.24</property>
-			<property name="javaVmArguments">-XX:MaxPermSize=128m -Xmx512m -Xms256m -Djava.awt.headless=true</property>
+			<property name="javaVmArguments">-Xmx512m -Xms256m -Djava.awt.headless=true</property>
 			<!-- debugging arguments for javaVm: -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y -->
         </configuration>
     </container>
    
 	<extension qualifier="webdriver">
-		<property name="browser">firefox</property>
+		<property name="browser">chrome</property>
 		<property name="dimensions">1024x800</property>
+		<!-- 
+		<property name="downloadBinaries">no</property>
+		<property name="chromeDriverBinary">target/drone/e3f9380ecadad5a28982e841b1b31f90/chromedriver</property>
+		<property name="firefoxDriverBinary">target/drone/30f3fdc84d76c53de2916008a889d26f/geckodriver</property>
+		-->
 		<property name="firefoxUserPreferences">src/test/profile/firefox/prefs.js</property>
+		<property name="chromeExperimentalOption">{
+			"prefs":{"credentials_enable_service": false, "profile.password_manager_enabled": false }
+		}</property>
 	</extension>
 
 </arquillian>
-- 
GitLab