From 19dbb27eccf16b168a9461dbd9b5641365563338 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Wed, 2 Dec 2015 18:06:01 +0100
Subject: [PATCH] OO-1770: selenium test of forum course element with guests

---
 .../org/olat/course/nodes/FOCourseNode.java   |   3 +-
 .../course/nodes/fo/SettingsController.java   |   3 +
 .../olat/modules/fo/ui/ForumController.java   |   9 +-
 .../modules/fo/ui/MessageEditController.java  |   1 +
 .../modules/fo/ui/MessageListController.java  |  23 +++-
 .../org/olat/selenium/BusinessGroupTest.java  |   2 +-
 .../java/org/olat/selenium/CourseTest.java    | 125 +++++++++++++++++-
 .../java/org/olat/selenium/PortfolioTest.java |   2 +-
 .../org/olat/selenium/page/LoginPage.java     |  10 ++
 .../olat/selenium/page/NavigationPage.java    |   7 +
 .../selenium/page/course/ForumCEPage.java     |  76 +++++++++++
 .../olat/selenium/page/forum/ForumPage.java   |  61 ++++++++-
 .../selenium/page/repository/CatalogPage.java |  68 ++++++++++
 13 files changed, 368 insertions(+), 22 deletions(-)
 create mode 100644 src/test/java/org/olat/selenium/page/course/ForumCEPage.java
 create mode 100644 src/test/java/org/olat/selenium/page/repository/CatalogPage.java

diff --git a/src/main/java/org/olat/course/nodes/FOCourseNode.java b/src/main/java/org/olat/course/nodes/FOCourseNode.java
index 8f6df7f35a6..ace3839fe25 100644
--- a/src/main/java/org/olat/course/nodes/FOCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/FOCourseNode.java
@@ -154,8 +154,7 @@ public class FOCourseNode extends AbstractAccessableCourseNode {
 		boolean guestPostAllowed = false;
 		if(ureq.getUserSession().getRoles().isGuestOnly()) {
 			String config = getModuleConfiguration().getStringValue(FOCourseNodeEditController.GUEST_POST_ALLOWED);
-			guestPostAllowed = CoreSpringFactory.getImpl(ForumModule.class).isAnonymousPostingWithPseudonymEnabled()
-					&& "true".equals(config);
+			guestPostAllowed = "true".equals(config);
 		} else {
 			String config = getModuleConfiguration().getStringValue(FOCourseNodeEditController.PSEUDONYM_POST_ALLOWED);
 			pseudonymPostAllowed = CoreSpringFactory.getImpl(ForumModule.class).isAnonymousPostingWithPseudonymEnabled()
diff --git a/src/main/java/org/olat/course/nodes/fo/SettingsController.java b/src/main/java/org/olat/course/nodes/fo/SettingsController.java
index 600f4f2bd95..026b2cf24b0 100644
--- a/src/main/java/org/olat/course/nodes/fo/SettingsController.java
+++ b/src/main/java/org/olat/course/nodes/fo/SettingsController.java
@@ -58,11 +58,13 @@ public class SettingsController extends FormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		setFormTitle("settings.title");
+		formLayout.setElementCssClass("o_sel_course_forum_settings");
 		
 		if(forumModule.isAnonymousPostingWithPseudonymEnabled()) {
 			String[] allowPseudonymValues = new String[] { translate("allow.pseudonym.post") };
 			allowPseudonymEl = uifactory.addCheckboxesHorizontal("allow.pseudonym", formLayout,
 					allowKeys, allowPseudonymValues);
+			allowPseudonymEl.setElementCssClass("o_sel_course_forum_allow_pseudo");
 			allowPseudonymEl.setLabel(null, null);
 			allowPseudonymEl.addActionListener(FormEvent.ONCHANGE);
 			
@@ -74,6 +76,7 @@ public class SettingsController extends FormBasicController {
 		String[] allowGuestValues = new String[] { translate("allow.guest.post") };
 		allowGuestEl = uifactory.addCheckboxesHorizontal("allow.guest", formLayout,
 				allowKeys, allowGuestValues);
+		allowGuestEl.setElementCssClass("o_sel_course_forum_allow_guest");
 		allowGuestEl.setLabel(null, null);
 		allowGuestEl.addActionListener(FormEvent.ONCHANGE);
 		if("true".equals(foNode.getModuleConfiguration().getStringValue(FOCourseNodeEditController.GUEST_POST_ALLOWED))) {
diff --git a/src/main/java/org/olat/modules/fo/ui/ForumController.java b/src/main/java/org/olat/modules/fo/ui/ForumController.java
index e32bc7198a3..a1a51ae8122 100644
--- a/src/main/java/org/olat/modules/fo/ui/ForumController.java
+++ b/src/main/java/org/olat/modules/fo/ui/ForumController.java
@@ -189,10 +189,7 @@ public class ForumController extends BasicController implements GenericEventList
 	@Override
 	public void event(Event event) {
 		if(event instanceof ForumChangedEvent) {
-			ForumChangedEvent fce = (ForumChangedEvent)event;
-			if(fce.getMessageKey() == null) {
-				reloadThreadList = true;
-			}
+			reloadThreadList = true;
 		}
 	}
 
@@ -280,7 +277,7 @@ public class ForumController extends BasicController implements GenericEventList
 		viewCtrl = new MessageListController(ureq, bbwControl, forum, focallback);
 		viewCtrl.loadThread(ureq, thread);
 		viewCtrl.scrollTo(scrollTo);
-		viewCtrl.doShowMarked();
+		viewCtrl.doShowMarked(ureq);
 		listenTo(viewCtrl);
 		putContent(viewCtrl);
 		addToHistory(ureq, viewCtrl);
@@ -297,7 +294,7 @@ public class ForumController extends BasicController implements GenericEventList
 		viewCtrl = new MessageListController(ureq, bbwControl, forum, focallback);
 		viewCtrl.loadThread(ureq, thread);
 		viewCtrl.scrollTo(scrollTo);
-		viewCtrl.doShowNew();
+		viewCtrl.doShowNew(ureq);
 		listenTo(viewCtrl);
 		putContent(viewCtrl);
 		addToHistory(ureq, viewCtrl);
diff --git a/src/main/java/org/olat/modules/fo/ui/MessageEditController.java b/src/main/java/org/olat/modules/fo/ui/MessageEditController.java
index 79edbd24797..ac6f1a2521d 100644
--- a/src/main/java/org/olat/modules/fo/ui/MessageEditController.java
+++ b/src/main/java/org/olat/modules/fo/ui/MessageEditController.java
@@ -196,6 +196,7 @@ public class MessageEditController extends FormBasicController {
 				usePseudonymEl.select(enableKeys[0], true);
 			}
 			pseudonymEl = uifactory.addTextElement("pseudonym", "pseudonym", 128, message.getPseudonym(), formLayout);
+			pseudonymEl.setElementCssClass("o_sel_forum_message_alias");
 
 			if(guestOnly) {
 				usePseudonymEl.setVisible(false);
diff --git a/src/main/java/org/olat/modules/fo/ui/MessageListController.java b/src/main/java/org/olat/modules/fo/ui/MessageListController.java
index 31f377a30d8..b73faa6d1f5 100644
--- a/src/main/java/org/olat/modules/fo/ui/MessageListController.java
+++ b/src/main/java/org/olat/modules/fo/ui/MessageListController.java
@@ -650,9 +650,9 @@ public class MessageListController extends BasicController implements GenericEve
 		}  else if (oneButton == source) {
 			doShowOne(ureq);
 		}  else if (markedButton == source) {
-			doShowMarked();		
+			doShowMarked(ureq);		
 		}  else if (newButton == source) {
-			doShowNew();		
+			doShowNew(ureq);		
 		} else if(stickyButton == source || removeStickyButton == source) {
 			doToogleSticky();
 		} else if (source instanceof Link) {
@@ -736,7 +736,7 @@ public class MessageListController extends BasicController implements GenericEve
 		} else if(messageTableCtrl == source) {
 			if(event instanceof SelectMessageEvent) {
 				SelectMessageEvent sme = (SelectMessageEvent)event;
-				doSelectTheOne(sme.getMessageKey());
+				doSelectTheOne(ureq, sme.getMessageKey());
 			}
 		} else if(moveCtrl == source) {
 			if(event instanceof SelectMessageEvent) {
@@ -1072,7 +1072,10 @@ public class MessageListController extends BasicController implements GenericEve
 		}
 	}
 	
-	private void doSelectTheOne(Long messageKey) {
+	private void doSelectTheOne(UserRequest ureq, Long messageKey) {
+		if(reloadList) {
+			reloadModel(ureq, null);
+		}
 		updateButtons(oneButton);
 		mainVC.contextPut("mode", "one");
 		mainVC.contextPut("threadMode", Boolean.FALSE);
@@ -1090,7 +1093,11 @@ public class MessageListController extends BasicController implements GenericEve
 		}
 	}
 	
-	protected void doShowMarked() {
+	protected void doShowMarked(UserRequest ureq) {
+		if(reloadList) {
+			reloadModel(ureq, null);
+		}
+		
 		updateButtons(markedButton);
 		mainVC.contextPut("threadMode", Boolean.FALSE);
 		mainVC.contextPut("mode", "marked");
@@ -1111,7 +1118,11 @@ public class MessageListController extends BasicController implements GenericEve
 		mainVC.contextPut("messages", views);
 	}
 	
-	protected void doShowNew() {
+	protected void doShowNew(UserRequest ureq) {
+		if(reloadList) {
+			reloadModel(ureq, null);
+		}
+		
 		updateButtons(newButton);
 		mainVC.contextPut("threadMode", Boolean.FALSE);
 		mainVC.contextPut("mode", "new");
diff --git a/src/test/java/org/olat/selenium/BusinessGroupTest.java b/src/test/java/org/olat/selenium/BusinessGroupTest.java
index f1344d294ae..395967af295 100644
--- a/src/test/java/org/olat/selenium/BusinessGroupTest.java
+++ b/src/test/java/org/olat/selenium/BusinessGroupTest.java
@@ -206,7 +206,7 @@ public class BusinessGroupTest {
 		String threadBodyMarker = UUID.randomUUID().toString();
 		group
 			.openForum()
-			.createThread("New thread in a group", "Very interessant discussion in a group" + threadBodyMarker)
+			.createThread("New thread in a group", "Very interessant discussion in a group" + threadBodyMarker, null)
 			.assertMessageBody(threadBodyMarker);
 		
 		//check chat @see other selenium test dedicated to this one
diff --git a/src/test/java/org/olat/selenium/CourseTest.java b/src/test/java/org/olat/selenium/CourseTest.java
index db823a6002d..06567945c8b 100644
--- a/src/test/java/org/olat/selenium/CourseTest.java
+++ b/src/test/java/org/olat/selenium/CourseTest.java
@@ -51,6 +51,7 @@ import org.olat.selenium.page.course.AssessmentCEConfigurationPage;
 import org.olat.selenium.page.course.CourseEditorPageFragment;
 import org.olat.selenium.page.course.CoursePageFragment;
 import org.olat.selenium.page.course.CourseWizardPage;
+import org.olat.selenium.page.course.ForumCEPage;
 import org.olat.selenium.page.course.InfoMessageCEPage;
 import org.olat.selenium.page.course.MembersPage;
 import org.olat.selenium.page.course.PublisherPageFragment;
@@ -1146,7 +1147,7 @@ public class CourseTest {
 	 */
 	@Test
 	@RunAsClient
-	public void forum_concurrent(@InitialPage LoginPage loginPage,
+	public void forumConcurrent(@InitialPage LoginPage loginPage,
 			@Drone @Participant WebDriver kanuBrowser,
 			@Drone @Student WebDriver reiBrowser)
 	throws IOException, URISyntaxException {
@@ -1182,7 +1183,7 @@ public class CourseTest {
 		ForumPage authorForum = ForumPage
 			.getCourseForumPage(browser);
 		authorForum
-			.createThread("The best anime ever", "What is the best anime ever?");
+			.createThread("The best anime ever", "What is the best anime ever?", null);
 		
 		//First user go to the course
 		LoginPage kanuLoginPage = LoginPage.getLoginPage(kanuBrowser, deploymentUrl);
@@ -1259,6 +1260,126 @@ public class CourseTest {
 			.waitMessageBody(reiReply);
 	}
 	
+
+	/**
+	 * An administrator create a category in catalog. It creates a new course
+	 * with a forum open to guests. it publish the course in the
+	 * catalog.<br>
+	 * The guest find the course, create a new thread. The administrator reply
+	 * to the message, the guest to its reply.<br>
+	 * The administrator checks the last message in its new messages, click
+	 * back, use the list of users to see the messages of the guest. It clicks
+	 * back to the threads list and checks the thread has 3 messages.
+	 * 
+	 * @param loginPage
+	 * @param guestBrowser
+	 * @throws IOException
+	 * @throws URISyntaxException
+	 */
+	@Test
+	@RunAsClient
+	public void forumWithGuest(@InitialPage LoginPage loginPage,
+			@Drone @User WebDriver guestBrowser)
+	throws IOException, URISyntaxException {
+		loginPage
+			.loginAs("administrator", "openolat")
+			.resume();
+		
+		String node1 = "Forums " + UUID.randomUUID();
+		navBar
+			.openCatalogAdministration()
+			.addCatalogNode(node1, "First level of the catalog");
+		
+		//create a course
+		String courseTitle = "Guest FO " + UUID.randomUUID();
+		navBar
+			.openAuthoringEnvironment()
+			.createCourse(courseTitle)
+			.clickToolbarBack();
+		
+		//go the authoring environment to create a forum
+		String foTitle = "GFO - " + UUID.randomUUID();
+		CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser)
+			.edit();
+		courseEditor
+			.createNode("fo")
+			.nodeTitle(foTitle);
+		//configure for guest
+		ForumCEPage forumConfig = new ForumCEPage(browser);
+		forumConfig
+			.selectConfiguration()
+			.allowGuest();
+		
+		//publish the course
+		courseEditor
+			.publish()
+			.next()
+			.selectAccess(Access.guests)
+			.next()
+			.selectCatalog(true)
+			.selectCategory(null, node1)
+			.next() // -> no problem found
+			.finish();
+		//back in course
+		courseEditor.clickToolbarBack();
+		
+		// guest go to the catalog and find the course
+		LoginPage guestLogin = LoginPage.getLoginPage(guestBrowser, deploymentUrl);
+		guestLogin
+			.asGuest();
+
+		NavigationPage guestNavBar = new NavigationPage(guestBrowser);
+		guestNavBar
+			.openCatalog()
+			.selectCatalogEntry(node1)
+			.select(courseTitle)
+			.start();
+		
+		//go to the forum
+		new CoursePageFragment(guestBrowser)
+			.clickTree()
+			.selectWithTitle(foTitle.substring(0, 20));
+		
+		String guestAlias = "Guest-" + UUID.randomUUID();
+		ForumPage guestForum = ForumPage
+			.getCourseForumPage(guestBrowser)
+			.createThread("Your favorite author", "Name your favorite author", guestAlias);
+		
+		System.out.println();
+		
+		// admin go to the forum
+		new CoursePageFragment(browser)
+			.clickTree()
+			.selectWithTitle(foTitle.substring(0, 20));
+		//admin reply to the thread of guest
+		ForumPage adminForum = ForumPage
+			.getCourseForumPage(browser)
+			.openThread("Your favorite author")
+			.assertOnGuestPseudonym(guestAlias)
+			.newMessages()
+			.assertOnGuestPseudonym(guestAlias)
+			.replyToMessage("Your favorite author", "Huxley is my favorite author", "My favorite author is Huxley");
+		
+		//guest refresh the view and reply to admin
+		guestForum
+			.flatView()
+			.assertMessageBody("Huxley")
+			.replyToMessage("Huxley is my favorite author", " I prefer Orwell", "Orwell is my favorite author");
+
+		//admin see its new messages, see the list of users, select the guest and its messages
+		OOGraphene.waitingALittleLonger();//JMS message need to be delivered
+		adminForum
+			.newMessages()
+			.assertMessageBody("Orwell")
+			.clickBack()
+			.userFilter()
+			.selectFilteredUser(guestAlias)
+			.assertMessageBody("Orwell")
+			.clickBack()
+			.clickBack()
+			.assertThreadListOnNumber("Your favorite author", 3);
+	}
+	
 	/**
 	 * An author creates a course with 4 course elements. A folder
 	 * which is visible to group, a forum which is visible to coaches,
diff --git a/src/test/java/org/olat/selenium/PortfolioTest.java b/src/test/java/org/olat/selenium/PortfolioTest.java
index 5e05ac36417..769e530ada0 100644
--- a/src/test/java/org/olat/selenium/PortfolioTest.java
+++ b/src/test/java/org/olat/selenium/PortfolioTest.java
@@ -144,7 +144,7 @@ public class PortfolioTest {
 		String threadTitle = "Very interessant thread";
 		ForumPage forum = ForumPage.getCourseForumPage(browser);
 		ArtefactWizardPage artefactWizard = forum
-			.createThread(threadTitle, "With a lot of content")
+			.createThread(threadTitle, "With a lot of content", null)
 			.addAsArtfeact();
 		
 		artefactWizard
diff --git a/src/test/java/org/olat/selenium/page/LoginPage.java b/src/test/java/org/olat/selenium/page/LoginPage.java
index 57941387ce8..5ef4e7e17be 100644
--- a/src/test/java/org/olat/selenium/page/LoginPage.java
+++ b/src/test/java/org/olat/selenium/page/LoginPage.java
@@ -106,6 +106,16 @@ public class LoginPage {
 		return this;
 	}
 	
+	/**
+	 * Enter OpenOLAT as guest
+	 */
+	public void asGuest() {
+		By guestLinkBy = By.xpath("//a[contains(@href,'menu.guest')]");
+		WebElement guestLink = browser.findElement(guestLinkBy);
+		Graphene.guardHttp(guestLink).click();
+		OOGraphene.waitElement(authXPath, browser);
+	}
+	
 	/**
 	 * Login and accept the disclaimer if there is one.
 	 * 
diff --git a/src/test/java/org/olat/selenium/page/NavigationPage.java b/src/test/java/org/olat/selenium/page/NavigationPage.java
index 43e0cb0acc2..b6899ac60e4 100644
--- a/src/test/java/org/olat/selenium/page/NavigationPage.java
+++ b/src/test/java/org/olat/selenium/page/NavigationPage.java
@@ -30,6 +30,7 @@ import org.olat.selenium.page.graphene.OOGraphene;
 import org.olat.selenium.page.group.GroupsPage;
 import org.olat.selenium.page.repository.AuthoringEnvPage;
 import org.olat.selenium.page.repository.CatalogAdminPage;
+import org.olat.selenium.page.repository.CatalogPage;
 import org.olat.selenium.page.user.PortalPage;
 import org.olat.selenium.page.user.UserAdminPage;
 import org.openqa.selenium.By;
@@ -56,6 +57,7 @@ public class NavigationPage {
 	private By myCoursesBy = By.cssSelector("li.o_site_repository > a");
 	private By userManagementBy = By.cssSelector("li.o_site_useradmin > a");
 	private By administrationBy = By.cssSelector("li.o_site_admin > a");
+	private By catalogBy = By.cssSelector("li.o_site_catalog > a");
 	private By catalogAdministrationBy = By.cssSelector("li.o_site_catalog_admin > a");
 	private	By groupsBy = By.cssSelector("li.o_site_groups > a");
 	
@@ -113,6 +115,11 @@ public class NavigationPage {
 		return new CatalogAdminPage(browser);
 	}
 	
+	public CatalogPage openCatalog() {
+		navigate(catalogBy);
+		return new CatalogPage(browser);
+	}
+	
 	public GroupsPage openGroups(WebDriver currentBrowser) {
 		navigate(groupsBy);
 		return new GroupsPage(currentBrowser);
diff --git a/src/test/java/org/olat/selenium/page/course/ForumCEPage.java b/src/test/java/org/olat/selenium/page/course/ForumCEPage.java
new file mode 100644
index 00000000000..28927ea654d
--- /dev/null
+++ b/src/test/java/org/olat/selenium/page/course/ForumCEPage.java
@@ -0,0 +1,76 @@
+/**
+ * <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.course;
+
+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;
+
+/**
+ * Drive the configuration of the forum's course element.
+ * 
+ * Initial date: 01.12.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ForumCEPage {
+
+	private WebDriver browser;
+	
+	public ForumCEPage(WebDriver browser) {
+		this.browser = browser;
+	}
+	
+	public ForumCEPage selectConfiguration() {
+		By configBy = By.className("o_sel_course_forum_settings");
+		return selectTab(configBy);
+	}
+	
+	public ForumCEPage allowGuest() {
+		By allowBy = By.cssSelector("div.o_sel_course_forum_allow_guest label input[type='checkbox']");
+		browser.findElement(allowBy).click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
+	private ForumCEPage selectTab(By tabBy) {
+		List<WebElement> tabLinks = browser.findElements(CourseEditorPageFragment.navBarNodeConfiguration);
+
+		boolean found = false;
+		a_a:
+		for(WebElement tabLink:tabLinks) {
+			tabLink.click();
+			OOGraphene.waitBusy(browser);
+			List<WebElement> chooseRepoEntry = browser.findElements(tabBy);
+			if(chooseRepoEntry.size() > 0) {
+				found = true;
+				break a_a;
+			}
+		}
+
+		Assert.assertTrue("Found the tab", found);
+		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 fe1fce2d2b8..df9c1bf2fea 100644
--- a/src/test/java/org/olat/selenium/page/forum/ForumPage.java
+++ b/src/test/java/org/olat/selenium/page/forum/ForumPage.java
@@ -68,6 +68,27 @@ public class ForumPage {
 		return new ForumPage(browser);
 	}
 	
+	public ForumPage clickBack() {
+		By backBy = By.cssSelector("a.o_link_back");
+		browser.findElement(backBy).click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
+	public ForumPage userFilter() {
+		By userFilterBy = By.cssSelector("a.o_sel_forum_filter");
+		browser.findElement(userFilterBy).click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
+	public ForumPage selectFilteredUser(String lastName) {
+		By userFilterBy = By.xpath("//table//td//a[text()[contains(.,'" + lastName + "')]]");
+		browser.findElement(userFilterBy).click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
 	/**
 	 * Create a new thread
 	 * 
@@ -75,16 +96,20 @@ public class ForumPage {
 	 * @param content
 	 * @return
 	 */
-	public ForumPage createThread(String title, String content) {
+	public ForumPage createThread(String title, String content, String alias) {
 		By newThreadBy = By.className("o_sel_forum_thread_new");
 		WebElement newThreadButton = browser.findElement(newThreadBy);
 		newThreadButton.click();
 		OOGraphene.waitBusy(browser);
 		
 		//fill the form
-		By titleBy = By.cssSelector("div.modal-content form input[type='text']");
-		WebElement titleEl = browser.findElement(titleBy);
-		titleEl.sendKeys(title);
+		By titleBy = By.cssSelector("div.modal-content form div.o_sel_forum_message_title input[type='text']");
+		browser.findElement(titleBy).sendKeys(title);
+		
+		if(alias != null) {
+			By aliasBy = By.cssSelector("div.modal-content form div.o_sel_forum_message_alias input[type='text']");
+			browser.findElement(aliasBy).sendKeys(alias);
+		}
 		
 		OOGraphene.tinymce(content, browser);
 		
@@ -96,6 +121,13 @@ public class ForumPage {
 		return this;
 	}
 	
+	public ForumPage assertThreadListOnNumber(String thread, int number) {
+		By threadBy = By.xpath("//table[contains(@class,'table')]//tr[td[text()='" + number + "']]//a[text()='" + thread + "']");
+		browser.findElement(threadBy).click();
+		
+		return this;
+	}
+	
 	public ForumPage openThread(String title) {
 		By threadBy = By.xpath("//table[contains(@class,'table')]//tr//a[text()='" + title + "']");
 		browser.findElement(threadBy).click();
@@ -117,6 +149,20 @@ public class ForumPage {
 		return this;
 	}
 	
+	public ForumPage newMessages() {
+		By newBy = By.cssSelector("a.o_forum_new_messages");
+		browser.findElement(newBy).click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
+	public ForumPage assertOnNewMessages() {
+		By messageBodyBy = By.cssSelector("div.o_forum div.o_forum_message_new");
+		List<WebElement> messages = browser.findElements(messageBodyBy);
+		Assert.assertFalse(messages.isEmpty());
+		return this;
+	}
+	
 	public ForumPage assertMessageBody(String text) {
 		By messageBodyBy = By.className("o_forum_message_body");
 		List<WebElement> messages = browser.findElements(messageBodyBy);
@@ -130,6 +176,13 @@ public class ForumPage {
 		return this;
 	}
 	
+	public ForumPage assertOnGuestPseudonym(String alias) {
+		By authorBy = By.xpath("//div[contains(@class,'o_author')][contains(text(),'" + alias + "')]");
+		List<WebElement> authorEls = browser.findElements(authorBy);
+		Assert.assertFalse(authorEls.isEmpty());
+		return this;
+	}
+	
 	public ForumPage waitMessageBody(String text) {
 		By messageBy = By.xpath("//div[contains(@class,'o_forum_message_body')][//p[contains(text(),'" + text + "')]]");
 		OOGraphene.waitElement(messageBy, 10, browser);
diff --git a/src/test/java/org/olat/selenium/page/repository/CatalogPage.java b/src/test/java/org/olat/selenium/page/repository/CatalogPage.java
new file mode 100644
index 00000000000..a53a8f6d54f
--- /dev/null
+++ b/src/test/java/org/olat/selenium/page/repository/CatalogPage.java
@@ -0,0 +1,68 @@
+/**
+ * <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.repository;
+
+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;
+
+/**
+ * Drive the catalog tab.
+ * 
+ * Initial date: 01.12.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CatalogPage {
+	
+	private WebDriver browser;
+	
+	public CatalogPage(WebDriver browser) {
+		this.browser = browser;
+	}
+	
+	public CatalogPage selectCatalogEntry(String title) {
+		By titleBy = By.xpath("//div[contains(@class,'o_sublevel')]//div[contains(@class,'o_meta')]//h4[contains(@class,'o_title')]//a[span[text()[contains(.,'" + title + "')]]]");
+		List<WebElement> titleLinks = browser.findElements(titleBy);
+		Assert.assertFalse(titleLinks.isEmpty());
+		titleLinks.get(0).click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
+	public CatalogPage select(String title) {
+		By titleLinkBy = By.xpath("//h4[contains(@class,'o_title')]//a[span[text()[contains(.,'" + title + "')]]]");
+		browser.findElement(titleLinkBy).click();
+		OOGraphene.waitBusy(browser);
+		return this;
+	}
+	
+	public void start() {
+		By startBy = By.className("o_start");
+		WebElement startLink = browser.findElement(startBy);
+		startLink.click();
+		OOGraphene.waitBusy(browser);
+	}
+
+}
-- 
GitLab