From c475e31c1c586206943010e60716a609363f7d5b Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Thu, 26 Feb 2015 20:39:53 +0100
Subject: [PATCH] OO-349: selenium test for the group's waiting list

---
 .../group/ui/BusinessGroupFormController.java |   2 +
 .../ui/edit/DisplayMemberSwitchForm.java      |   1 +
 .../run/BusinessGroupMainRunController.java   |  12 +-
 .../ui/run/_content/ownersandmembers.html     |  14 +-
 .../token/ui/TokenAccessController.java       |   1 +
 .../org/olat/selenium/AssessmentTest.java     |   2 +-
 .../org/olat/selenium/BusinessGroupTest.java  | 119 ++++++++++++++++-
 .../olat/selenium/page/core/BookingPage.java  | 123 ++++++++++++++++++
 .../selenium/page/course/MembersPage.java     |   2 +-
 .../olat/selenium/page/group/GroupPage.java   | 111 ++++++++++++++--
 .../olat/selenium/page/group/GroupsPage.java  |  60 ++++++++-
 .../page/group/MembersWizardPage.java         |   5 +-
 12 files changed, 416 insertions(+), 36 deletions(-)
 create mode 100644 src/test/java/org/olat/selenium/page/core/BookingPage.java

diff --git a/src/main/java/org/olat/group/ui/BusinessGroupFormController.java b/src/main/java/org/olat/group/ui/BusinessGroupFormController.java
index df58f6dc977..00beddf5d23 100644
--- a/src/main/java/org/olat/group/ui/BusinessGroupFormController.java
+++ b/src/main/java/org/olat/group/ui/BusinessGroupFormController.java
@@ -204,8 +204,10 @@ public class BusinessGroupFormController extends FormBasicController {
 		// Checkboxes
 		enableWaitingList = uifactory.addCheckboxesHorizontal("create.form.enableWaitinglist", null, formLayout, waitingListKeys,
 				waitingListValues);
+		enableWaitingList.setElementCssClass("o_sel_group_edit_waiting_list");
 		enableAutoCloseRanks = uifactory.addCheckboxesHorizontal("create.form.enableAutoCloseRanks", null, formLayout, autoCloseKeys,
 				autoCloseValues);
+		enableAutoCloseRanks.setElementCssClass("o_sel_group_edit_auto_close_ranks");
 
 		// Enable only if specification of min and max members is possible
 		businessGroupMinimumMembers.setVisible(false); // currently the minimum feature is not enabled
diff --git a/src/main/java/org/olat/group/ui/edit/DisplayMemberSwitchForm.java b/src/main/java/org/olat/group/ui/edit/DisplayMemberSwitchForm.java
index eaa56f97f96..1fe9b399955 100644
--- a/src/main/java/org/olat/group/ui/edit/DisplayMemberSwitchForm.java
+++ b/src/main/java/org/olat/group/ui/edit/DisplayMemberSwitchForm.java
@@ -104,6 +104,7 @@ public class DisplayMemberSwitchForm extends FormBasicController {
 		showPartips.select("show_participants", group.isParticipantsVisibleIntern());
 		showPartips.setElementCssClass("o_sel_group_show_participants");
 		showWaitingList.select("show_waiting_list", group.isWaitingListVisibleIntern());
+		showWaitingList.setElementCssClass("o_sel_group_show_waiting_list");
 		openOwners.select("open_owners", group.isOwnersVisiblePublic());
 		openPartips.select("open_participants", group.isParticipantsVisiblePublic());
 		openWaitingList.select("open_waiting_list", group.isWaitingListVisiblePublic());
diff --git a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
index 5d23ab5eeeb..25de909a85e 100644
--- a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
+++ b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
@@ -929,7 +929,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 				bgTree.setTreeModel(trMdl);
 				if (bgEditCntrllr == null) {
 					// change didn't origin by our own edit controller
-					showInfo(translate("grouprun.configurationchanged"));
+					showInfo("grouprun.configurationchanged");
 					bgTree.setSelectedNodeId(trMdl.getRootNode().getIdent());
 					mainPanel.setContent(main);
 				} else {
@@ -1006,6 +1006,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 			gtnChild.setUserObject(ACTIVITY_MENUSELECT_INFORMATION);
 			gtnChild.setAltText(translate("menutree.news.alt"));
 			gtnChild.setIconCssClass("o_icon_news");
+			gtnChild.setCssClass("o_sel_group_news");
 			root.addChild(gtnChild);
 			nodeInformation = gtnChild;
 		}
@@ -1016,6 +1017,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 			gtnChild.setUserObject(ACTIVITY_MENUSELECT_CALENDAR);
 			gtnChild.setAltText(translate("menutree.calendar.alt"));
 			gtnChild.setIconCssClass("o_calendar_icon");
+			gtnChild.setCssClass("o_sel_group_calendar");
 			root.addChild(gtnChild);
 			nodeCal = gtnChild;
 		}
@@ -1027,8 +1029,8 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 			gtnChild.setUserObject(ACTIVITY_MENUSELECT_SHOW_RESOURCES);
 			gtnChild.setAltText(translate("menutree.resources.alt"));
 			gtnChild.setIconCssClass("o_CourseModule_icon");
+			gtnChild.setCssClass("o_sel_group_resources");
 			root.addChild(gtnChild);
-			//fxdiff BAKS-7 Resume function
 			nodeResources = gtnChild;
 		}
 
@@ -1040,8 +1042,8 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 			gtnChild.setUserObject(ACTIVITY_MENUSELECT_MEMBERSLIST);
 			gtnChild.setAltText(translate("menutree.members.alt"));
 			gtnChild.setIconCssClass("o_icon_group");
+			gtnChild.setCssClass("o_sel_group_members");
 			root.addChild(gtnChild);
-			//fxdiff BAKS-7 Resume function
 			nodeGroupOwners = gtnChild;
 		}
 
@@ -1051,8 +1053,8 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 			gtnChild.setUserObject(ACTIVITY_MENUSELECT_CONTACTFORM);
 			gtnChild.setAltText(translate("menutree.contactform.alt"));
 			gtnChild.setIconCssClass("o_co_icon");
+			gtnChild.setCssClass("o_sel_group_contact");
 			root.addChild(gtnChild);
-			//fxdiff BAKS-7 Resume function
 			nodeContact = gtnChild;
 		}
 
@@ -1062,6 +1064,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 			gtnChild.setUserObject(ACTIVITY_MENUSELECT_FOLDER);
 			gtnChild.setAltText(translate("menutree.folder.alt"));
 			gtnChild.setIconCssClass("o_bc_icon");
+			gtnChild.setCssClass("o_sel_group_folder");
 			root.addChild(gtnChild);
 			nodeFolder = gtnChild;
 		}
@@ -1072,6 +1075,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 			gtnChild.setUserObject(ACTIVITY_MENUSELECT_FORUM);
 			gtnChild.setAltText(translate("menutree.forum.alt"));
 			gtnChild.setIconCssClass("o_fo_icon");
+			gtnChild.setCssClass("o_sel_group_forum");
 			root.addChild(gtnChild);
 			nodeForum = gtnChild;
 		}
diff --git a/src/main/java/org/olat/group/ui/run/_content/ownersandmembers.html b/src/main/java/org/olat/group/ui/run/_content/ownersandmembers.html
index 3ab1b88ff06..68ffc79a125 100644
--- a/src/main/java/org/olat/group/ui/run/_content/ownersandmembers.html
+++ b/src/main/java/org/olat/group/ui/run/_content/ownersandmembers.html
@@ -1,11 +1,11 @@
-<h2><i class="o_icon o_icon_group"> </i> $r.translate("userlist.title") </h2>
+<h2><i class="o_icon o_icon_group"> </i> $r.translate("userlist.title")</h2>
 #if ($showOwnerGroups)
 	<h3>$r.translate("userlist.owners.title")</h3>
-	<div class="o_sel_group_coaches">
+	<div id="o_sel_group_coaches">
 		$r.render("owners")
 	</div>
 #else
-    <div class="o_sel_group_coaches_not_visible">
+    <div id="o_sel_group_coaches_not_visible">
     	<h3>$r.translate("userlist.show.no.owners.title")</h3>
 		<div class="o_info">$r.translate("userlist.show.no.owners.text")</div>
 	</div>
@@ -13,11 +13,11 @@
 
 #if ($showPartipsGroups)
 	<h3>$r.translate("userlist.participants.title")</h3>
-	<div class="o_sel_group_participants">
+	<div id="o_sel_group_participants">
 		$r.render("participants")
 	</div>
 #else
-    <div class="o_sel_group_participants_not_visible">
+    <div id="o_sel_group_participants_not_visible">
     	<h3>$r.translate("userlist.show.no.participants.title")</h3>
 		<div class="o_info">$r.translate("userlist.show.no.participants.text")</div>
 	</div>
@@ -26,11 +26,11 @@
 #if ($hasWaitingList)
 	#if ($showWaitingList)
 		<h3>$r.translate("userlist.waitinglist.title")</h3>
-    	<div class="o_sel_group_waiting_list">
+    	<div id="o_sel_group_waiting_list">
 			$r.render("waitingList")
 		</div>
 	#else
-    	<div class="o_sel_group_waiting_list_not_visible">
+    	<div id="o_sel_group_waiting_list_not_visible">
 	    	<h3>$r.translate("userlist.show.no.waitinglist.title")</h3>
 			<div class="o_info">$r.translate("userlist.show.no.waitinglist.text")</div>
 		</div>
diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/token/ui/TokenAccessController.java b/src/main/java/org/olat/resource/accesscontrol/provider/token/ui/TokenAccessController.java
index 46f71a55bc4..633725f07c9 100644
--- a/src/main/java/org/olat/resource/accesscontrol/provider/token/ui/TokenAccessController.java
+++ b/src/main/java/org/olat/resource/accesscontrol/provider/token/ui/TokenAccessController.java
@@ -77,6 +77,7 @@ public class TokenAccessController extends FormBasicController implements FormCo
 		setFormTitle("access.token.title");
 		setFormDescription("access.token.desc");
 		setFormTitleIconCss("o_icon o_icon-fw " + TokenAccessHandler.METHOD_CSS_CLASS + "_icon");
+		formLayout.setElementCssClass("o_sel_accesscontrol_form");
 		
 		String description = link.getOffer().getDescription();
 		if(StringHelper.containsNonWhitespace(description)) {
diff --git a/src/test/java/org/olat/selenium/AssessmentTest.java b/src/test/java/org/olat/selenium/AssessmentTest.java
index cddead01fa7..4e7155d889d 100644
--- a/src/test/java/org/olat/selenium/AssessmentTest.java
+++ b/src/test/java/org/olat/selenium/AssessmentTest.java
@@ -234,7 +234,7 @@ public class AssessmentTest {
 		courseRuntime
 			.members()
 			.addMember()
-			.searchMember(ryomou)
+			.searchMember(ryomou, true)
 			.next().next().next().finish();
 		
 		//Ryomou open the group
diff --git a/src/test/java/org/olat/selenium/BusinessGroupTest.java b/src/test/java/org/olat/selenium/BusinessGroupTest.java
index e320ab21ea4..c2d213b89a1 100644
--- a/src/test/java/org/olat/selenium/BusinessGroupTest.java
+++ b/src/test/java/org/olat/selenium/BusinessGroupTest.java
@@ -38,6 +38,7 @@ import org.junit.runner.RunWith;
 import org.olat.selenium.page.LoginPage;
 import org.olat.selenium.page.NavigationPage;
 import org.olat.selenium.page.Participant;
+import org.olat.selenium.page.Student;
 import org.olat.selenium.page.User;
 import org.olat.selenium.page.core.IMPage;
 import org.olat.selenium.page.group.GroupPage;
@@ -91,8 +92,8 @@ public class BusinessGroupTest {
 			@Drone @Participant WebDriver participantBrowser)
 	throws IOException, URISyntaxException {
 		
-		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
-		UserVO participant = new UserRestClient(deploymentUrl).createRandomUser();
+		UserVO author = new UserRestClient(deploymentUrl).createRandomUser("Selena");
+		UserVO participant = new UserRestClient(deploymentUrl).createRandomUser("Aoi");
 		
 		loginPage
 			.loginAs(author.getLogin(), author.getPassword())
@@ -107,10 +108,10 @@ public class BusinessGroupTest {
 		MembersWizardPage members = group
 			.openAdministration()
 			.openAdminMembers()
-			.setVisibility(true, true)
+			.setVisibility(true, true, false)
 			.addMember();
 		
-		members.searchMember(participant)
+		members.searchMember(participant, false)
 			.next()
 			.next()
 			.next()
@@ -132,6 +133,110 @@ public class BusinessGroupTest {
 		Assert.assertTrue(content.contains(groupName));
 	}
 	
+	/**
+	 * An author creates a group, it opens the tab groups and then "My groups". It
+	 * creates a group, enters a number of participants "1", enable the waiting
+	 * list. In members visibility, it see coaches, participants and waiting
+	 * list visible to members.<br>
+	 * A participant and than a student come, book the group. The first enters
+	 * the group, the second the waiting list.<br>
+	 * The author go in the members list to check if it's in the coach list,
+	 * the participant in the participants list and the student in the waiting
+	 * list.
+	 * 
+	 * Should show group starting page, with menu items Administration and Bookings visible
+	 * 
+	 * @param loginPage
+	 * @param participantBrowser
+	 * @throws IOException
+	 * @throws URISyntaxException
+	 */
+	@Test
+	@RunAsClient
+	public void createGroupWithWaitingList(@InitialPage LoginPage loginPage,
+			@Drone @Participant WebDriver participantBrowser,
+			@Drone @Student WebDriver studentBrowser)
+	throws IOException, URISyntaxException {
+		
+		UserVO author = new UserRestClient(deploymentUrl).createRandomUser("Selena");
+		UserVO participant = new UserRestClient(deploymentUrl).createRandomUser("Ryomou");
+		UserVO student = new UserRestClient(deploymentUrl).createRandomUser("Asuka");
+	
+		loginPage
+			.loginAs(author.getLogin(), author.getPassword())
+			.resume();
+		
+		//go to groups
+		String groupName = "Group-1-" + UUID.randomUUID();
+		GroupPage group = navBar
+			.openGroups(browser)
+			.createGroup(groupName, "A group with a waiting list")
+			.openAdministration()
+			//set waiting list and 1 participant
+			.openEditDetails()
+			.setMaxNumberOfParticipants(1)
+			.setWaitingList()
+			.saveDetails();
+		
+		//add booking ( token one )
+		String token = "secret";
+		String description = "The password is secret";
+		group.openBookingConfig()
+			.openAddDropMenu()
+			.addTokenMethod()
+			.configureTokenMethod(token, description)
+			.assertOnToken(token)
+			.save();
+		
+		//members see members
+		group = GroupPage.getGroup(browser)
+			.openAdminMembers()
+			.setVisibility(true, true, true)
+			.openMembers();
+		
+
+		//participant search published groups
+		LoginPage participantLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl);
+		//tools
+		participantLoginPage
+			.loginAs(participant.getLogin(), participant.getPassword())
+			.resume();
+		//groups
+		NavigationPage participantNavBar = new NavigationPage(participantBrowser);
+		participantNavBar
+				.openGroups(participantBrowser)
+				.publishedGroups()
+				.bookGroup(groupName)
+				.bookToken(token);
+		//are we that we are in the right group?
+		GroupPage.getGroup(participantBrowser)
+			.assertOnInfosPage(groupName);
+		
+		
+		//student search published groups
+		LoginPage studentLoginPage = LoginPage.getLoginPage(studentBrowser, deploymentUrl);
+		//tools
+		studentLoginPage
+			.loginAs(student.getLogin(), student.getPassword())
+			.resume();
+		//groups
+		NavigationPage studentNavBar = new NavigationPage(studentBrowser);
+		studentNavBar
+				.openGroups(studentBrowser)
+				.publishedGroups()
+				.bookGroup(groupName)
+				.bookToken(token);
+		//are we that we are in the right group?
+		GroupPage.getGroup(studentBrowser)
+			.assertOnWaitingList(groupName);
+		
+		group = GroupPage.getGroup(browser)
+				.openMembers()
+				.assertMembersInOwnerList(author)
+				.assertMembersInParticipantList(participant)
+				.assertMembersInWaitingList(student);
+	}
+	
 	/**
 	 * An author create a group, set the visibility to true for owners
 	 * and participants, enable the tools and add 2 users to it. The 2
@@ -169,16 +274,16 @@ public class BusinessGroupTest {
 			.openAdminTools()
 			.enableTools()
 			.openAdminMembers()
-			.setVisibility(true, true);
+			.setVisibility(true, true, false);
 		//add Kanu to the group
 		group
 			.openAdminMembers()
 			.addMember()
-			.searchMember(kanu)
+			.searchMember(kanu, true)
 			.next().next().next().finish();
 		//add Ryomou
 		group.addMember()
-			.searchMember(ryomou)
+			.searchMember(ryomou, true)
 			.next().next().next().finish();
 		
 		//Kanu open the group
diff --git a/src/test/java/org/olat/selenium/page/core/BookingPage.java b/src/test/java/org/olat/selenium/page/core/BookingPage.java
new file mode 100644
index 00000000000..19fd73e7dd4
--- /dev/null
+++ b/src/test/java/org/olat/selenium/page/core/BookingPage.java
@@ -0,0 +1,123 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.selenium.page.core;
+
+import java.util.List;
+
+import org.junit.Assert;
+import org.olat.selenium.page.graphene.OOGraphene;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+
+/**
+ * 
+ * This page drive the booking configuration.
+ * 
+ * Initial date: 24.02.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class BookingPage {
+	
+	private static final By tokenIconBy = By.className("o_ac_token_icon");
+	private static final By addMethodLinksBy = By.cssSelector("fieldset.o_ac_configuration ul.dropdown-menu a");
+	
+	private WebDriver browser;
+	
+	public BookingPage(WebDriver browser) {
+		this.browser = browser;
+	}
+	
+	/**
+	 * Open the dropdown to add an access control method.
+	 * @return This page
+	 */
+	public BookingPage openAddDropMenu() {
+		By addDropMenuBy = By.className("o_sel_accesscontrol_create");
+		browser.findElement(addDropMenuBy).click();
+		return this;
+	}
+	
+	/**
+	 * In the dropdown to add an access control method, choose
+	 * the method by secret token.
+	 * 
+	 * @return This page
+	 */
+	public BookingPage addTokenMethod() {
+		return addMethod(tokenIconBy);
+	}
+	
+	private BookingPage addMethod(By iconBy) {
+		List<WebElement> links = browser.findElements(addMethodLinksBy);
+		WebElement tokenLink = null;
+		for(WebElement link:links) {
+			List<WebElement> icons = link.findElements(iconBy);
+			if(icons.size() > 0) {
+				tokenLink = link;
+			}
+		}
+		Assert.assertNotNull(tokenLink);
+		tokenLink.click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
+	public BookingPage configureTokenMethod(String token, String description) {
+		By descriptionBy = By.cssSelector(".o_sel_accesscontrol_token_form .o_sel_accesscontrol_description textarea");
+		browser.findElement(descriptionBy).sendKeys(description);		
+		By tokenBy = By.cssSelector(".o_sel_accesscontrol_token_form .o_sel_accesscontrol_token input[type='text']");
+		browser.findElement(tokenBy).sendKeys(token);
+
+		By submitBy = By.cssSelector(".o_sel_accesscontrol_token_form button.btn-primary");
+		browser.findElement(submitBy).click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
+	public BookingPage assertOnToken(String token) {
+		boolean found = false;
+		By infosBy = By.className("o_ac_infos");
+		List<WebElement> infos = browser.findElements(infosBy);
+		for(WebElement info:infos) {
+			if(info.getText().contains(token)) {
+				found = true;
+			}
+		}
+		Assert.assertTrue(found);
+		return this;
+	}
+	
+	public void bookToken(String token) {
+		By tokenEntryBy = By.cssSelector(".o_sel_accesscontrol_token_entry input[type='text']");
+		browser.findElement(tokenEntryBy).sendKeys(token);
+		
+		By submitBy = By.cssSelector(".o_sel_accesscontrol_form button.btn-primary");
+		browser.findElement(submitBy).click();
+		OOGraphene.waitBusy(browser);
+	}
+	
+	public void save() {
+		By saveButtonBy = By.cssSelector("form button.btn-primary");
+		browser.findElement(saveButtonBy).click();
+		OOGraphene.waitBusy(browser);
+	}
+}
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 f7cafa5b757..1a3e4980df6 100644
--- a/src/test/java/org/olat/selenium/page/course/MembersPage.java
+++ b/src/test/java/org/olat/selenium/page/course/MembersPage.java
@@ -56,7 +56,7 @@ public class MembersPage {
 	 */
 	public void quickAdd(UserVO user) {
 		addMember()
-			.searchMember(user)
+			.searchMember(user, true)
 			.next().next().next().finish();
 	}
 
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 977eda956c0..1dbef0b6fef 100644
--- a/src/test/java/org/olat/selenium/page/group/GroupPage.java
+++ b/src/test/java/org/olat/selenium/page/group/GroupPage.java
@@ -22,8 +22,10 @@ package org.olat.selenium.page.group;
 import java.util.List;
 
 import org.junit.Assert;
+import org.olat.selenium.page.core.BookingPage;
 import org.olat.selenium.page.core.IMPage;
 import org.olat.selenium.page.graphene.OOGraphene;
+import org.olat.user.restapi.UserVO;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
@@ -37,9 +39,10 @@ import org.openqa.selenium.WebElement;
  */
 public class GroupPage {
 	
-
 	private static final By showOwners = By.className("o_sel_group_show_owners");
 	private static final By toolsBy = By.className("o_sel_collab_tools");
+	private static final By editDetails = By.className("o_sel_group_edit_title");
+	private static final By bookingConfigBy = By.className("o_sel_accesscontrol_create");
 	
 	private WebDriver browser;
 	
@@ -63,6 +66,11 @@ public class GroupPage {
 		return this;
 	}
 	
+	public GroupPage openEditDetails() {
+		openAdminTab(editDetails);
+		return this;
+	}
+	
 	public GroupPage openAdminMembers() {
 		openAdminTab(showOwners);
 		return this;
@@ -73,6 +81,11 @@ public class GroupPage {
 		return this;
 	}
 	
+	public BookingPage openBookingConfig() {
+		openAdminTab(bookingConfigBy);
+		return new BookingPage(browser);
+	}
+	
 	public IMPage openChat() {
 		By chatBy = By.cssSelector("li.o_sel_group_chat a");
 		WebElement chatNode = browser.findElement(chatBy);
@@ -81,20 +94,61 @@ public class GroupPage {
 		return new IMPage(browser);
 	}
 	
-	public GroupPage setVisibility(boolean owners, boolean participants) {
-		By showOwnersBy = By.cssSelector(".o_sel_group_show_owners input[type='checkbox']");
-		WebElement showOwnersEl = browser.findElement(showOwnersBy);
+	public GroupPage openMembers() {
+		By membersBy = By.cssSelector("li.o_sel_group_members a");
+		browser.findElement(membersBy).click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
+	public GroupPage setVisibility(boolean owners, boolean participants, boolean waitingList) {	
 		if(owners) {
-			showOwnersEl.click();
+			By showOwnersBy = By.cssSelector(".o_sel_group_show_owners input[type='checkbox']");
+			browser.findElement(showOwnersBy).click();
+			OOGraphene.waitBusy(browser);
+			OOGraphene.closeBlueMessageWindow(browser);
 		}
-		OOGraphene.waitBusy(browser);
 		
-		By showParticipants = By.cssSelector(".o_sel_group_show_participants input[type='checkbox']");
-		WebElement showParticipantsEl = browser.findElement(showParticipants);
 		if(participants) {
-			showParticipantsEl.click();
+			By showParticipants = By.cssSelector(".o_sel_group_show_participants input[type='checkbox']");
+			browser.findElement(showParticipants).click();
+			OOGraphene.waitBusy(browser);
+			OOGraphene.closeBlueMessageWindow(browser);
+		}
+		
+		if(waitingList) {
+			By showWaitingListBy = By.cssSelector(".o_sel_group_show_waiting_list input[type='checkbox']");
+			browser.findElement(showWaitingListBy).click();
+			OOGraphene.waitBusy(browser);
+			OOGraphene.closeBlueMessageWindow(browser);
 		}
 		
+		OOGraphene.waitBusy(browser);
+		OOGraphene.closeBlueMessageWindow(browser);
+		return this;
+	}
+	
+	public GroupPage setWaitingList() {
+		By waitingListBy = By.cssSelector(".o_sel_group_edit_waiting_list input[type='checkbox']");
+		browser.findElement(waitingListBy).click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
+	public GroupPage setMaxNumberOfParticipants(int max) {
+		By maxBy = By.cssSelector(".o_sel_group_edit_max_members input[type='text']");
+		browser.findElement(maxBy).sendKeys(Integer.toString(max));
+		return this;
+	}
+	
+	/**
+	 * Save the details form.
+	 * @return The group page
+	 */
+	public GroupPage saveDetails() {
+		By submitBy = By.cssSelector(".o_sel_group_edit_group_form button.btn-primary");
+		WebElement submitButton = browser.findElement(submitBy);
+		submitButton.click();
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
@@ -136,4 +190,43 @@ public class GroupPage {
 		}
 		Assert.assertTrue(found);
 	}
+	
+	public GroupPage assertOnInfosPage(String name) {
+		By groupNameBy = By.xpath("//div[@id='o_main_center_content_inner']//p[contains(text(),'" + name+ "')]");
+		List<WebElement> groupNameEls = browser.findElements(groupNameBy);
+		Assert.assertFalse(groupNameEls.isEmpty());
+		return this;
+	}
+	
+	public GroupPage assertOnWaitingList(String name) {
+		//check group name
+		By groupNameBy = By.cssSelector("#o_main_center_content_inner h4");
+		WebElement groupNameEl = browser.findElement(groupNameBy);
+		Assert.assertTrue(groupNameEl.getText().contains(name));
+		//check the warning
+		By warningBy = By.xpath("//div[@id='o_main_center_content_inner']//p[contains(@class,'o_warning')]");
+		List<WebElement> warningEls = browser.findElements(warningBy);
+		Assert.assertFalse(warningEls.isEmpty());
+		return this;
+	}
+	
+	public GroupPage assertMembersInOwnerList(UserVO owner) {
+		return assertMembers(owner, "o_sel_group_coaches");
+	}
+	
+	public GroupPage assertMembersInParticipantList(UserVO owner) {
+		return assertMembers(owner, "o_sel_group_participants");
+	}
+	
+	public GroupPage assertMembersInWaitingList(UserVO owner) {
+		return assertMembers(owner, "o_sel_group_waiting_list");
+	}
+	
+	private GroupPage assertMembers(UserVO member, String cssClass) {
+		String firstName = member.getFirstName();
+		By longBy = By.xpath("//div[@id='" + cssClass + "']//table//tr//td//a[contains(text(),'" + firstName + "')]");
+		List<WebElement> elements = browser.findElements(longBy);
+		Assert.assertFalse(elements.isEmpty());
+		return this;
+	}
 }
diff --git a/src/test/java/org/olat/selenium/page/group/GroupsPage.java b/src/test/java/org/olat/selenium/page/group/GroupsPage.java
index d0bb09fb504..6463c8e4d46 100644
--- a/src/test/java/org/olat/selenium/page/group/GroupsPage.java
+++ b/src/test/java/org/olat/selenium/page/group/GroupsPage.java
@@ -22,6 +22,7 @@ package org.olat.selenium.page.group;
 import java.util.List;
 
 import org.junit.Assert;
+import org.olat.selenium.page.core.BookingPage;
 import org.olat.selenium.page.graphene.OOGraphene;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
@@ -42,6 +43,18 @@ public class GroupsPage {
 		this.browser = browser;
 	}
 	
+	/**
+	 * Select the tab "Published groups"
+	 * 
+	 * @return
+	 */
+	public GroupsPage publishedGroups() {
+		By openGroupsBy = By.className("o_sel_group_open_groups_seg");
+		browser.findElement(openGroupsBy).click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
 	public GroupPage createGroup(String name, String description) {
 		//click create button
 		By createBy = By.className("o_sel_group_create");
@@ -64,12 +77,52 @@ public class GroupsPage {
 		return new GroupPage(browser);
 	}
 	
+	/**
+	 * Click on the book link
+	 * 
+	 * @param name
+	 * @return
+	 */
+	public BookingPage bookGroup(String name) {
+		By rowBy = By.cssSelector("div.o_table_wrapper tr");
+		By colBy = By.cssSelector("td a");	
+		WebElement groupLink = null;
+		List<WebElement> rows = browser.findElements(rowBy);
+		for(WebElement row:rows) {
+			if(row.getText().contains(name)) {
+				// take the last link of the row
+				List<WebElement> links = row.findElements(colBy);
+				if(links.size() > 0) {
+					groupLink = links.get(links.size() - 1);
+				}
+			}
+		}
+		
+		Assert.assertNotNull(groupLink);
+		groupLink.click();
+		OOGraphene.waitBusy(browser);
+		
+		By tokenEntryBy = By.className("o_sel_accesscontrol_token_entry");
+		OOGraphene.waitElement(tokenEntryBy, browser);
+		return new BookingPage(browser);
+	}
+	
 	/**
 	 * Select a group in the list by its name
 	 * @param name
 	 * @return
 	 */
 	public GroupPage selectGroup(String name) {
+		selectGroupInTable(name);
+		
+		//By groupNameBy = By.xpath("//div[contains(@class,'o_tree')]//a/span[contains(text(),'" + name+ "')]");
+		By groupNameBy = By.xpath("//div[@id='o_main_center_content_inner']//p[contains(text(),'" + name+ "')]");
+		OOGraphene.waitElement(groupNameBy, browser);
+		
+		return new GroupPage(browser);
+	}
+	
+	private GroupsPage selectGroupInTable(String name) {
 		By linkBy = By.cssSelector("div.o_table_wrapper td a");
 		
 		WebElement groupLink = null;
@@ -82,10 +135,7 @@ public class GroupsPage {
 		
 		Assert.assertNotNull(groupLink);
 		groupLink.click();
-		
-		By rootTreeNodeBy = By.xpath("//div[contains(@class,'o_tree')]//a/span[contains(text(),'" + name+ "')]");
-		OOGraphene.waitElement(rootTreeNodeBy, browser);
-		
-		return new GroupPage(browser);
+		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 8becdc8070c..debcc2405a4 100644
--- a/src/test/java/org/olat/selenium/page/group/MembersWizardPage.java
+++ b/src/test/java/org/olat/selenium/page/group/MembersWizardPage.java
@@ -71,14 +71,15 @@ public class MembersWizardPage {
 	 * @param user
 	 * @return
 	 */
-	public MembersWizardPage searchMember(UserVO user) {
+	public MembersWizardPage searchMember(UserVO user, boolean admin) {
 		//Search by username
 		By usernameBy = By.cssSelector(".o_sel_usersearch_searchform input[type='text']");
 		OOGraphene.waitElement(usernameBy, browser);
 		
 		List<WebElement> searchFields = browser.findElements(usernameBy);
 		Assert.assertFalse(searchFields.isEmpty());
-		searchFields.get(0).sendKeys(user.getLogin());
+		String search = admin ? user.getLogin() : user.getFirstName();
+		searchFields.get(0).sendKeys(search);
 
 		By searchBy = By.cssSelector(".o_sel_usersearch_searchform a.btn-default");
 		WebElement searchButton = browser.findElement(searchBy);
-- 
GitLab