diff --git a/src/main/java/org/olat/portfolio/ui/EPOverviewController.java b/src/main/java/org/olat/portfolio/ui/EPOverviewController.java
index 178491c7367f6eea4a100a75e2f6e0faba1fd17f..b74349761113c3917776c1d4973cdd390435f0fe 100644
--- a/src/main/java/org/olat/portfolio/ui/EPOverviewController.java
+++ b/src/main/java/org/olat/portfolio/ui/EPOverviewController.java
@@ -56,12 +56,16 @@ public class EPOverviewController extends BasicController {
 		
 		segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this);
 		myArtefactLink = LinkFactory.createLink("myartefacts.menu.title", mainVC, this);
+		myArtefactLink.setElementCssClass("o_sel_ep_my_artfeacts");
 		segmentView.addSegment(myArtefactLink, true);
 		myMapLink = LinkFactory.createLink("mymaps.menu.title", mainVC, this);
+		myMapLink.setElementCssClass("o_sel_ep_my_maps");
 		segmentView.addSegment(myMapLink, false);
 		myTaskLink = LinkFactory.createLink("mystructuredmaps.menu.title", mainVC, this);
+		myTaskLink.setElementCssClass("o_sel_ep_my_tasks");
 		segmentView.addSegment(myTaskLink, false);
 		publicMapLink = LinkFactory.createLink("othermaps.menu.title", mainVC, this);
+		publicMapLink.setElementCssClass("o_sel_ep_public_maps");
 		segmentView.addSegment(publicMapLink, false);
 		
 		doOpenMyArtefacts(ureq);
diff --git a/src/main/java/org/olat/portfolio/ui/artefacts/collect/ArtefactWizzardStepsController.java b/src/main/java/org/olat/portfolio/ui/artefacts/collect/ArtefactWizzardStepsController.java
index ea14c77fd577d2d23c12598974a2d091eef05077..9e48cc7ac7ea8c2594b522743b165e46c534705b 100755
--- a/src/main/java/org/olat/portfolio/ui/artefacts/collect/ArtefactWizzardStepsController.java
+++ b/src/main/java/org/olat/portfolio/ui/artefacts/collect/ArtefactWizzardStepsController.java
@@ -134,7 +134,7 @@ public class ArtefactWizzardStepsController extends BasicController {
 	private void initCollectLinkVelocity() {
 		addLink = LinkFactory.createCustomLink("add.to.eportfolio", "add.to.eportfolio", "", Link.LINK_CUSTOM_CSS + Link.NONTRANSLATED,
 				null, this);
-		addLink.setCustomEnabledLinkCSS("b_eportfolio_add");
+		addLink.setCustomEnabledLinkCSS("o_eportfolio_add");
 		addLink.setIconLeftCSS("o_icon o_icon-lg o_icon_eportfolio_add");
 		addLink.setTooltip(translate("add.to.eportfolio"));
 		addLink.setTranslator(getTranslator());
@@ -143,7 +143,7 @@ public class ArtefactWizzardStepsController extends BasicController {
 		if (existingArtefacts!=null){
 			int amount = existingArtefacts.size();
 			addLink.setIconLeftCSS("o_icon o_icon-lg o_icon_eportfolio_add");
-			addLink.setCustomEnabledLinkCSS("b_eportfolio_add_again");
+			addLink.setCustomEnabledLinkCSS("o_eportfolio_add_again");
 			addLink.setTooltip(translate("add.to.eportfolio.again", String.valueOf(amount)));	
 		}
 		putInitialPanel(addLink);
diff --git a/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCollectStepForm01.java b/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCollectStepForm01.java
index 0fb0534265c28d874deb91601289299fd1319d13..381b10ec269a8c73e4c5d27ebf23f49d8bd1fe52 100644
--- a/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCollectStepForm01.java
+++ b/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCollectStepForm01.java
@@ -84,6 +84,7 @@ public class EPCollectStepForm01 extends StepFormBasicController {
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 
 		tagListElement = uifactory.addTextBoxListElement("artefact.tags", null, "tag.input.hint", getTagMapToDisplay(), formLayout, getTranslator());
+		tagListElement.setElementCssClass("o_sel_ep_tagsinput");
 		Map<String, String> allUsersTags = ePFMgr.getUsersMostUsedTags(getIdentity(), 50);
 		tagListElement.setAutoCompleteContent(allUsersTags);
 		tagListElement.setAllowDuplicates(false);
diff --git a/src/main/java/org/olat/portfolio/ui/structel/EPMapViewController.java b/src/main/java/org/olat/portfolio/ui/structel/EPMapViewController.java
index 186b1d3453412ccb07785c0db12aa6887c0b6b0f..740900e9d0e7db6bcedcbc279fc763f17da881fb 100644
--- a/src/main/java/org/olat/portfolio/ui/structel/EPMapViewController.java
+++ b/src/main/java/org/olat/portfolio/ui/structel/EPMapViewController.java
@@ -142,6 +142,7 @@ public class EPMapViewController extends BasicController implements Activateable
 		mainVc.remove(mainVc.getComponent("map.editButton"));
 		if(secCallback.canEditStructure()) {
 			editButton = LinkFactory.createButton("map.editButton", mainVc, this);
+			editButton.setElementCssClass("o_sel_ep_edit_map");
 			editButton.setIconLeftCSS("o_icon o_icon-fw o_icon_edit");
 			if(Boolean.FALSE.equals(editMode)) {
 				editButton.setCustomDisplayText(translate("map.editButton.on"));
diff --git a/src/main/java/org/olat/portfolio/ui/structel/EPMultipleMapController.java b/src/main/java/org/olat/portfolio/ui/structel/EPMultipleMapController.java
index 7e5ab62fae0a24ea20ac86fb604431957de30489..35fef4d2a85f9e46a63bb38b53c71f912debce12 100644
--- a/src/main/java/org/olat/portfolio/ui/structel/EPMultipleMapController.java
+++ b/src/main/java/org/olat/portfolio/ui/structel/EPMultipleMapController.java
@@ -228,6 +228,7 @@ public class EPMultipleMapController extends BasicController implements Activate
 				Link vLink = LinkFactory.createCustomLink(VIEW_LINK_PREFIX + i, "viewMap" + map.getResourceableId(), "view.map",
 						Link.LINK, vC, this);
 				vLink.setUserObject(map);
+				vLink.setElementCssClass("o_sel_ep_open_map");
 				vLink.setIconRightCSS("o_icon o_icon-fw o_icon_start");
 				
 				//can always try to delete your own map, but exercise only if the course was deleted
diff --git a/src/test/java/org/olat/selenium/PortfolioTest.java b/src/test/java/org/olat/selenium/PortfolioTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7ded966101eacdf60ac7af12704378d17e786be
--- /dev/null
+++ b/src/test/java/org/olat/selenium/PortfolioTest.java
@@ -0,0 +1,161 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.selenium;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.UUID;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.graphene.page.InitialPage;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.olat.selenium.page.LoginPage;
+import org.olat.selenium.page.NavigationPage;
+import org.olat.selenium.page.course.CourseEditorPageFragment;
+import org.olat.selenium.page.course.CoursePageFragment;
+import org.olat.selenium.page.forum.ForumPage;
+import org.olat.selenium.page.graphene.OOGraphene;
+import org.olat.selenium.page.portfolio.ArtefactWizardPage;
+import org.olat.selenium.page.portfolio.PortfolioPage;
+import org.olat.selenium.page.repository.AuthoringEnvPage.ResourceType;
+import org.olat.selenium.page.user.UserToolsPage;
+import org.olat.test.ArquillianDeployments;
+import org.olat.test.rest.UserRestClient;
+import org.olat.user.restapi.UserVO;
+import org.openqa.selenium.WebDriver;
+
+
+@RunWith(Arquillian.class)
+public class PortfolioTest {
+	
+	@Deployment(testable = false)
+	public static WebArchive createDeployment() {
+		return ArquillianDeployments.createDeployment();
+	}
+
+	@Drone
+	private WebDriver browser;
+	@ArquillianResource
+	private URL deploymentUrl;
+
+	@Page
+	private UserToolsPage userTools;
+	@Page
+	private NavigationPage navBar;
+
+	/**
+	 * Create a course with a forum, publish it.
+	 * Create a map.
+	 * Post in the forum, collect the artefact, bind it to the map.
+	 * Check the map and the artefact.
+	 * 
+	 * @param loginPage
+	 * @throws IOException
+	 * @throws URISyntaxException
+	 */
+	@Test
+	@RunAsClient
+	public void collectForumArtfect(@InitialPage LoginPage loginPage)
+	throws IOException, URISyntaxException {
+		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
+		loginPage
+			.loginAs(author.getLogin(), author.getPassword())
+			.resume();
+		
+		//open the portfolio
+		PortfolioPage portfolio = userTools
+				.openUserToolsMenu()
+				.openPortfolio();
+		
+		//create a map
+		String mapTitle = "Map-Forum-" + UUID.randomUUID();
+		String pageTitle = "Page-Forum-" + UUID.randomUUID();
+		String structureElementTitle = "Struct-Forum-" + UUID.randomUUID();
+		portfolio
+			.openMyMaps()
+			.createMap(mapTitle, "Hello forum")
+			.openEditor()
+			.selectMapInEditor(mapTitle)
+			.selectFirstPageInEditor()
+			.setPage(pageTitle, "With a little description")
+			.createStructureElement(structureElementTitle, "Structure description");
+		
+		
+		String courseTitle = "Collect-Forum-" + UUID.randomUUID();
+		String forumTitle = ("Forum-" + UUID.randomUUID()).substring(0, 24);
+		//go to authoring, create a course with a forum
+		navBar
+			.openAuthoringEnvironment()
+			.openCreateDropDown()
+			.clickCreate(ResourceType.course)
+			.fillCreateForm(courseTitle)
+			.clickToolbarBack()
+			.edit();
+		
+		//open course editor
+		CourseEditorPageFragment courseEditor = CourseEditorPageFragment.getEditor(browser);
+		courseEditor
+			.createNode("fo")
+			.nodeTitle(forumTitle)
+			.publish()
+			.quickPublish();
+		
+		navBar.backToTheTop();
+		
+		CoursePageFragment course = CoursePageFragment.getCourse(browser);
+		course
+			.clickTree()
+			.selectWithTitle(forumTitle);
+		
+		String threadTitle = "Very interessant thread";
+		ForumPage forum = ForumPage.getForumPage(browser);
+		ArtefactWizardPage artefactWizard = forum
+			.createThread(threadTitle, "With a lot of content")
+			.addAsArtfeact();
+		
+		artefactWizard
+			.next()
+			.tags("Forum", "Thread", "Miscellanous")
+			.next()
+			.selectMap(mapTitle, pageTitle, structureElementTitle)
+			.finish();
+
+		OOGraphene.closeBlueMessageWindow(browser);
+		
+		//open the portfolio
+		portfolio = userTools
+			.openUserToolsMenu()
+			.openPortfolio()
+			.openMyMaps()
+			.openMap(mapTitle)
+			.selectStructureInTOC(structureElementTitle);
+		
+		portfolio.assertArtefact(threadTitle);
+	}
+
+}
diff --git a/src/test/java/org/olat/selenium/page/forum/ForumPage.java b/src/test/java/org/olat/selenium/page/forum/ForumPage.java
new file mode 100644
index 0000000000000000000000000000000000000000..18d96f3590aeca0ae29083916f657a55b61edd4c
--- /dev/null
+++ b/src/test/java/org/olat/selenium/page/forum/ForumPage.java
@@ -0,0 +1,102 @@
+/**
+ * <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.forum;
+
+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.olat.selenium.page.portfolio.ArtefactWizardPage;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+
+/**
+ * Drive the forum
+ * 
+ * 
+ * Initial date: 01.07.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ForumPage {
+	
+	@Drone
+	private WebDriver browser;
+
+	/**
+	 * Get the forum from a course element.
+	 * 
+	 * @param browser
+	 * @return
+	 */
+	public static ForumPage getForumPage(WebDriver browser) {
+		By forumBy = By.cssSelector("div.o_course_run div.o_forum");
+		List<WebElement> forumEl = browser.findElements(forumBy);
+		Assert.assertFalse(forumEl.isEmpty());
+	
+		By mainBy = By.cssSelector("div.o_course_run");
+		WebElement main = browser.findElement(mainBy);
+		return Graphene.createPageFragment(ForumPage.class, main);
+	}
+	
+	/**
+	 * Create a new thread
+	 * 
+	 * @param title
+	 * @param content
+	 * @return
+	 */
+	public ForumPage createThread(String title, String content) {
+		By newThreadBy = By.className("o_sel_forum_thread_new");
+		WebElement newThreadButton = browser.findElement(newThreadBy);
+		newThreadButton.click();
+		OOGraphene.waitBusy();
+		
+		//fill the form
+		By titleBy = By.cssSelector("div.o_content form input[type='text']");
+		WebElement titleEl = browser.findElement(titleBy);
+		titleEl.sendKeys(title);
+		
+		OOGraphene.tinymce(content, browser);
+		
+		//save
+		By saveBy = By.cssSelector("div.o_content form button.btn-primary");
+		WebElement saveButton = browser.findElement(saveBy);
+		saveButton.click();
+		OOGraphene.waitBusy();
+		return this;
+	}
+	
+	/**
+	 * Add the thread to my artefacts
+	 * 
+	 */
+	public ArtefactWizardPage addAsArtfeact() {
+		By addAsArtefactBy = By.className("o_eportfolio_add");
+		WebElement addAsArtefactButton = browser.findElement(addAsArtefactBy);
+		addAsArtefactButton.click();
+		OOGraphene.waitBusy();
+		return ArtefactWizardPage.getWizard(browser);
+	}
+
+}
diff --git a/src/test/java/org/olat/selenium/page/portfolio/ArtefactWizardPage.java b/src/test/java/org/olat/selenium/page/portfolio/ArtefactWizardPage.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a694d4b1608229ae4099b6052ab818918f7c8d6
--- /dev/null
+++ b/src/test/java/org/olat/selenium/page/portfolio/ArtefactWizardPage.java
@@ -0,0 +1,105 @@
+/**
+ * <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.portfolio;
+
+import java.util.List;
+
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.graphene.Graphene;
+import org.jcodec.common.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 wizard to add artefacts
+ * 
+ * 
+ * Initial date: 01.07.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ArtefactWizardPage {
+	
+	public static final By nextBy = By.className("o_wizard_button_next");
+	public static final By finishBy = By.className("o_wizard_button_finish");
+	
+	@Drone
+	private WebDriver browser;
+	
+	public static ArtefactWizardPage getWizard(WebDriver browser) {
+		By modalBy = By.className("modal-content");
+		WebElement modal = browser.findElement(modalBy);
+		return Graphene.createPageFragment(ArtefactWizardPage.class, modal);
+	}
+	
+	public ArtefactWizardPage next() {
+		WebElement next = browser.findElement(nextBy);
+		Assert.assertTrue(next.isDisplayed());
+		Assert.assertTrue(next.isEnabled());
+		next.click();
+		OOGraphene.waitBusy();
+		OOGraphene.closeBlueMessageWindow(browser);
+		return this;
+	}
+	
+	public ArtefactWizardPage finish() {
+		WebElement finish = browser.findElement(finishBy);
+		Assert.assertTrue(finish.isDisplayed());
+		Assert.assertTrue(finish.isEnabled());
+		finish.click();
+		OOGraphene.waitBusy();
+		OOGraphene.closeBlueMessageWindow(browser);
+		return this;
+	}
+	
+	public ArtefactWizardPage tags(String... tags) {
+		By tagBy = By.cssSelector("div.o_sel_artefact_add_wizard div.bootstrap-tagsinput>input");
+		WebElement tagEl = browser.findElement(tagBy);
+		if(tags != null && tags.length > 0 && tags[0] != null) {
+			for(String tag:tags) {
+				tagEl.sendKeys(tag);
+			}
+		}
+		return this;
+	}
+	
+	public ArtefactWizardPage selectMap(String mapTitle, String pageTitle, String structureTitle) {
+		select(mapTitle, By.cssSelector("a.o_tree_l1"));
+		select(pageTitle, By.cssSelector("a.o_tree_l2"));
+		select(structureTitle, By.cssSelector("a.o_tree_l3"));
+		return this;
+	}
+	
+	private void select(String title, By selector) {
+		WebElement linkToClick = null;
+		List<WebElement> links = browser.findElements(selector);
+		for(WebElement link:links) {
+			if(link.getText().contains(title)) {
+				linkToClick = link;
+			}
+		}
+		Assert.assertNotNull(linkToClick);
+		linkToClick.click();
+		OOGraphene.waitBusy();
+	}
+
+}
diff --git a/src/test/java/org/olat/selenium/page/portfolio/PortfolioPage.java b/src/test/java/org/olat/selenium/page/portfolio/PortfolioPage.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e5a16dbd767faa2a9aefad1ff548a199321c944
--- /dev/null
+++ b/src/test/java/org/olat/selenium/page/portfolio/PortfolioPage.java
@@ -0,0 +1,248 @@
+/**
+ * <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.portfolio;
+
+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.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+
+/**
+ * Drive the portfolio map age, view and editor
+ * 
+ * 
+ * Initial date: 01.07.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class PortfolioPage {
+	
+	@Drone
+	private WebDriver browser;
+	
+	/**
+	 * Open the segment view at "My maps"
+	 * 
+	 * @return
+	 */
+	public PortfolioPage openMyMaps() {
+		By myMapsBy = By.className("o_sel_ep_my_maps");
+		WebElement myMapsLink = browser.findElement(myMapsBy);
+		Assert.assertTrue(myMapsLink.isDisplayed());
+		myMapsLink.click();
+		OOGraphene.waitBusy();
+		return this;
+	}
+	
+	/**
+	 * Create a map (type default) with the specified title.
+	 * @param title
+	 * @param description
+	 * @return
+	 */
+	public PortfolioPage createMap(String title, String description) {
+		//open sub menu
+		By createMapBy = By.className("o_sel_create_map");
+		WebElement createMapLink = browser.findElement(createMapBy);
+		Assert.assertTrue(createMapLink.isDisplayed());
+		createMapLink.click();
+		
+		//create default map
+		By createDefaultMapBy = By.className("o_sel_create_default_map");
+		OOGraphene.waitElement(createDefaultMapBy);
+		WebElement createDefaultMapLink = browser.findElement(createDefaultMapBy);
+		Assert.assertTrue(createDefaultMapLink.isDisplayed());
+		createDefaultMapLink.click();
+		OOGraphene.waitBusy();
+		
+		//title
+		By titleBy = By.xpath("//div[contains(@class,'o_sel_add_map_window')]//form//input[@type='text']");
+		WebElement titleEl = browser.findElement(titleBy);
+		titleEl.sendKeys(title);
+		
+		//description
+		OOGraphene.tinymce(description, browser);
+		
+		//ok
+		By saveBy = By.xpath("(//div[contains(@class,'o_sel_add_map_window')]//form//button)[last()]");
+		WebElement saveButton = browser.findElement(saveBy);
+		Assert.assertTrue(saveButton.isDisplayed());
+		saveButton.click();
+		OOGraphene.waitElement(By.className("o_eportfolio_map"));
+		return this;
+	}
+	
+	/**
+	 * Open the editor from the map
+	 * 
+	 * @return
+	 */
+	public PortfolioPage openEditor() {
+		By editorBy = By.className("o_sel_ep_edit_map");
+		WebElement editorButton = browser.findElement(editorBy);
+		Assert.assertTrue(editorButton.isDisplayed());
+		editorButton.click();
+		OOGraphene.waitBusy();
+		return this;
+	}
+	
+	public PortfolioPage openMap(String mapTitle) {
+		By mapBy = By.cssSelector("div.o_eportfolio_maps div.o_map-default");
+		By headingBy = By.cssSelector("div.panel-heading h4");
+		By openBy = By.className("o_sel_ep_open_map");
+		
+		List<WebElement> mapEls = browser.findElements(mapBy);
+		WebElement mapEl = null;
+		for(WebElement el:mapEls) {
+			WebElement headingEl = el.findElement(headingBy);
+			if(headingEl.getText().contains(mapTitle)) {
+				mapEl = el;
+			}
+		}
+		Assert.assertNotNull(mapEl);
+		WebElement openLink = mapEl.findElement(openBy);
+		openLink.click();
+		OOGraphene.waitBusy();	
+		return this;
+	}
+	
+	/**
+	 * Select and click the map node in the TOC
+	 * of the editor.
+	 * 
+	 * @param mapTitle
+	 * @return
+	 */
+	public PortfolioPage selectMapInEditor(String mapTitle) {
+		By mapNodeBy = By.cssSelector("div.o_ep_toc_editor a.o_tree_level_label_open.o_tree_l1");
+		WebElement selectedNode = null;
+		List<WebElement> level1Nodes = browser.findElements(mapNodeBy);
+		for(WebElement level1Node:level1Nodes) {
+			if(level1Node.getText().contains(mapTitle)) {
+				selectedNode = level1Node;
+			}
+		}
+		Assert.assertNotNull(selectedNode);
+		selectedNode.click();
+		OOGraphene.waitBusy();
+		return this;
+	}
+	
+	public PortfolioPage selectStructureInTOC(String structureElementTitle) {
+		WebElement selectedStructLink = null;
+		By structBy = By.cssSelector("li.level2.type_struct>a");
+		List<WebElement> structLinkEls = browser.findElements(structBy);
+		for(WebElement el:structLinkEls) {
+			if(el.getText().contains(structureElementTitle)) {
+				selectedStructLink = el;
+			}
+		}
+		Assert.assertNotNull(selectedStructLink);
+		selectedStructLink.click();
+		OOGraphene.waitBusy();
+		return this;
+	}
+	
+	/**
+	 * Find and click the first page in the TOC of the
+	 * editor.
+	 * 
+	 * @return
+	 */
+	public PortfolioPage selectFirstPageInEditor() {
+		By pageNodeBy = By.cssSelector("div.o_ep_toc_editor a.o_tree_level_label_leaf.o_tree_l2");
+		List<WebElement> level2Nodes = browser.findElements(pageNodeBy);
+		Assert.assertFalse(level2Nodes.isEmpty());
+		level2Nodes.get(0).click();
+		OOGraphene.waitBusy();
+		return this;
+	}
+	
+	public PortfolioPage assertArtefact(String artefactTitle) {
+		By artefactBy = By.cssSelector(".b_artefact h3");
+		List<WebElement> artefactEls = browser.findElements(artefactBy);
+		Assert.assertFalse(artefactEls.isEmpty());
+		WebElement artefactEl = null;
+		for(WebElement el:artefactEls) {
+			if(el.getText().contains(artefactTitle)) {
+				artefactEl = el;
+			}
+		}
+		Assert.assertNotNull(artefactEl);	
+		return this;
+	}
+	
+	/**
+	 * Set title and description of a page
+	 * 
+	 * @param name
+	 * @param description
+	 * @return
+	 */
+	public PortfolioPage setPage(String name, String description) {
+		return fillElementForm(name, description);
+	}
+	
+	/**
+	 * Create a structure element and set its title
+	 * and description.
+	 * 
+	 * @param title
+	 * @param description
+	 * @return
+	 */
+	public PortfolioPage createStructureElement(String title, String description) {
+		By newStructureBy = By.cssSelector("div.o_ep_toc_editor a.o_eportfolio_add_link.o_ep_struct_icon");
+		WebElement newStructureButton = browser.findElement(newStructureBy);
+		newStructureButton.click();
+		OOGraphene.waitBusy();
+		
+		//fill the form
+		return fillElementForm(title, description);
+	}
+	
+	/**
+	 * Fill the standard form for portfolio element.
+	 * 
+	 * @param name
+	 * @param description
+	 * @return
+	 */
+	private PortfolioPage fillElementForm(String name, String description) {
+		//title
+		By nameBy = By.cssSelector("form div.o_ep_struct_editor input[type='text']");
+		WebElement nameEl = browser.findElement(nameBy);
+		nameEl.clear();
+		nameEl.sendKeys(name);
+		
+		//description
+		OOGraphene.tinymce(description, browser);
+		
+		By saveBy = By.cssSelector("form div.o_ep_struct_editor button.btn-primary");
+		WebElement saveButton = browser.findElement(saveBy);
+		saveButton.click();
+		OOGraphene.waitBusy();
+		return this;
+	}
+}
diff --git a/src/test/java/org/olat/selenium/page/user/UserToolsPage.java b/src/test/java/org/olat/selenium/page/user/UserToolsPage.java
index 9f5acd92583960d37a51c3c42b02744f1d182eb4..d1dc77e9f426f06d87ea3975abf41f75599b54e5 100644
--- a/src/test/java/org/olat/selenium/page/user/UserToolsPage.java
+++ b/src/test/java/org/olat/selenium/page/user/UserToolsPage.java
@@ -25,6 +25,7 @@ import org.jboss.arquillian.graphene.page.Page;
 import org.jcodec.common.Assert;
 import org.olat.selenium.page.LoginPage;
 import org.olat.selenium.page.graphene.OOGraphene;
+import org.olat.selenium.page.portfolio.PortfolioPage;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
@@ -100,6 +101,17 @@ public class UserToolsPage {
 		return userSettings;
 	}
 	
+	public PortfolioPage openPortfolio() {
+		By linkBy = By.className("o_sel_user_tools-Portfolio");
+		WebElement passwordLink = browser.findElement(linkBy);
+		Assert.assertTrue(passwordLink.isDisplayed());
+		passwordLink.click();
+		OOGraphene.waitBusy();
+		
+		WebElement main = browser.findElement(By.id("o_main"));
+		return Graphene.createPageFragment(PortfolioPage.class, main);
+	}
+	
 	/**
 	 * Log out and wait until the login form appears
 	 */