-
Notifications
You must be signed in to change notification settings - Fork 41
Adding and configuring an AEM component
This guide will show you how to add an example component, configure it and perform configuration validation using Bobcat. We will use provided SummerBlockbusterHitsPage and SectionHeaderComponent classes. So what's our test scenario? We will find our top parsys, insert a Section Header component there, modify default value and check if the provided value is saved and displayed properly. Let's start from finding our parsys into which Bobcat will insert a component.
Let's go to /cf#/content/geometrixx-media/en/entertainment/summer-blockbuster-hits-and-misses.html page. We can find our parsys there as shown on the image:
As we can see our parsys lays under div element with cq-placeholder-article-content-par_47article_47par1_47_42 class. We should add this parsys to our Page Object now. In order to do this let's add proper declaration of our parsys in the SummerBlockbusterHitsPage class:
@FindBy(xpath = "//div[contains(@class, 'cq-placeholder-article-content-par_47article_47par1_47_42')]/..")
private AemParsys topParsys;The parsys is being found using xpath query where css class which we found before is provided. After defining a getter for this field, we are able to access it from our test classes. Let's create a test class now:
package com.example.test.summer;
import com.cognifide.qa.bb.aem.AemLogin;
import com.cognifide.qa.bb.aem.ui.parsys.AemParsys;
import com.cognifide.qa.bb.junit.Modules;
import com.cognifide.qa.bb.junit.TestRunner;
import com.cognifide.test.GuiceModule;
import com.google.inject.Inject;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
@RunWith(TestRunner.class)
@Modules(GuiceModule.class)
public class AddComponentTest {
@Inject
private SummerBlockbusterHitsPage summerBlockbusterHitsPage;
@Inject
private AemLogin aemLogin;
private AemParsys parsys;
@Before
public void openBlockbusterHitsPage() {
aemLogin.authorLogin();
summerBlockbusterHitsPage.open();
assertTrue(summerBlockbusterHitsPage.isDisplayed());
parsys = summerBlockbusterHitsPage.getTopParsys().clear();
}
@After
public void cleanUp() {
parsys.clear();
}
}We've created @Before and @After annotated methods here. In the openBlockbusterHitsPage() method, we are logging in to the AEM, opening the Summer Blockbuster Hits Page. The following line is responsible for waiting until the page fully renders to be sure that our parsys is visible:
assertTrue(summerBlockbusterHitsPage.isDisplayed());After that we should clear the parsys as it should be always empty. The cleanUp() methods is clearing the parsys after test as well.
Since we have control of the parsys intwo which we want to insert our compnentnt, let's create out test scenario implementation now:
@Test
public void testAddingAndEditingSectionHeader() {
SectionHeaderComponent sectionHeaderComponent = parsys.insertComponent(SectionHeaderComponent.class);
//wait until page reloads after modifying the component
assertTrue(summerBlockbusterHitsPage.isDisplayed());
sectionHeaderComponent = parsys.getFirstComponentOfType(SectionHeaderComponent.class);
assertThat(sectionHeaderComponent , CoreMatchers.notNullValue());
}In the first line we are inserting the Section Header Component into our parsys. Class of this component has the following annotation:
@AemComponent(cssClassName = "section-header", group = "Geometrixx Media", name = "Section Header")It provides information where the component is located in the sidekick so Bobcat can select appropriate component group and component itself to insert it.

The cssClassName property is helpful during component presence verification.
Since we have our component inserted into parsys, we can edit it. In order to do that we need to open a dialog window first. Now, let's edit this component by providing our custom value for Header Text property in the dialog window. We need to obtain AemDialog of this component at first.
AemDialog dialog = sectionHeaderComponent.getDialog();
dialog.open();Now we need to access the Header Text dialog field and edit it. We can use a SectionHeaderComponent#getHeaderText() method. How does it work? In the Section Header Component class, there is a following field defined:
@DialogField(label = "Header Text")
private AemTextField headerText;The @DialogField annotation looks for the dialog field with provided label. Please note that dialog window has to be opened when using it.
The next two lines are responsible for providing a test value and saving it:
title.setValue(TEST_VALUE);
dialog.ok();When we click OK button on the dialog window, the page is being reloaded. We need to wait until it fully reloads and get our component once again:
//wait until page reloads after modifying the component
assertTrue(summerBlockbusterHitsPage.isDisplayed());
sectionHeaderComponent = parsys.getFirstComponentOfType(SectionHeaderComponent.class);The last thing in this test case is an assertion - we are comparing the component's displayed value with our expected value. The SectionHeaderComponent has the following field defined
@FindBy(xpath = "./*/span")
private WebElement sectionText;
...
public String getText() {
return sectionText.getText();
}It holds the value of span element contained by this component. This is the element where our header text value is present
So this simple line in our test method is checking whether our component shows what we expect:
assertThat(sectionHeaderComponent.getText(), is(TEST_VALUE));And this is it! We've written a simple test case which is checking whether adding and configuring is working properly. The entire code can be found below:
package com.cognifide.test.summer;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import com.cognifide.qa.bb.aem.AemLogin;
import com.cognifide.qa.bb.aem.dialog.classic.field.AemTextField;
import com.cognifide.qa.bb.aem.ui.AemDialog;
import com.cognifide.qa.bb.aem.ui.parsys.AemParsys;
import com.cognifide.qa.bb.junit.Modules;
import com.cognifide.qa.bb.junit.TestRunner;
import com.cognifide.test.GuiceModule;
import com.google.inject.Inject;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(TestRunner.class)
@Modules(GuiceModule.class)
public class AddComponentTest {
private static final String TEST_VALUE = "Bobcat test";
@Inject
private SummerBlockbusterHitsPage summerBlockbusterHitsPage;
@Inject
private AemLogin aemLogin;
private AemParsys parsys;
@Before
public void openSiteadminPage() {
aemLogin.authorLogin();
summerBlockbusterHitsPage.open();
assertTrue(summerBlockbusterHitsPage.isDisplayed());
parsys = summerBlockbusterHitsPage.getTopParsys().clear();
}
@Test
public void testAddingAndEditingSectionHeader() {
SectionHeaderComponent sectionHeaderComponent = parsys.insertComponent(SectionHeaderComponent.class);
AemDialog dialog = sectionHeaderComponent.getDialog();
dialog.open();
AemTextField title = sectionHeaderComponent.getHeaderText();
title.setValue(TEST_VALUE);
dialog.ok();
//wait until page reloads after modifying the component
assertTrue(summerBlockbusterHitsPage.isDisplayed());
sectionHeaderComponent = parsys.getFirstComponentOfType(SectionHeaderComponent.class);
assertThat(sectionHeaderComponent.getText(), is(TEST_VALUE));
}
@After
public void cleanUp() {
parsys.clear();
}
}Modified SummerBlockbusterHitsPage class:
package com.cognifide.test.summer;
import org.openqa.selenium.support.FindBy;
import com.cognifide.qa.bb.aem.AbstractPage;
import com.cognifide.qa.bb.aem.ui.parsys.AemParsys;
import com.cognifide.qa.bb.qualifier.Frame;
import com.cognifide.qa.bb.qualifier.PageObject;
/**
* This class represents a page from Geometrixx project.
* <p/>
* Frame annotation determines default frame for all methods in this class.
*/
@PageObject
@Frame("$cq")
public class SummerBlockbusterHitsPage extends AbstractPage {
private static final String PAGE_TITLE = "Summer Blockbuster Hits and Misses";
private static final String URL = "/cf#/content/geometrixx-media/en/entertainment/summer-blockbuster-hits-and-misses.html";
@FindBy(xpath = "//div[contains(@class, 'cq-placeholder-article-content-par_47article_47par1_47_42')]/..")
private AemParsys topParsys;
@FindBy(xpath = "//div[contains(@class, 'cq-element-article-content-par_47image')]/...")
private ImageComponent imageComponent;
@FindBy(className = "cq-element-right-panel-par_47section_95header")
private SectionHeaderComponent sectionHeader;
public ImageComponent getImageComponent() {
return imageComponent;
}
public SectionHeaderComponent getSectionHeader() {
return sectionHeader;
}
public AemParsys getTopParsys() {
return topParsys;
}
@Override
public String getContentPath() {
return URL;
}
@Override
public String getPageTitle() {
return PAGE_TITLE;
}
}- Configuring Bobcat
- Selenium enhancements
- Cucumber enhancements
- Traffic analyzer
- Email support
- Reporting
- Cloud integration
- Mobile integration
- Executing tests on different environments
- Working with multiple threads
- Tips and tricks
- Authoring tutorial - Classic
- AEM Classic Authoring Advanced usage
- Siteadmin
- Sidekick
- Aem Component
- Working with author pages
- Working with Publish pages
- Advanced component interactions
- Working with Context Menu
- Using Aem Content Tree
- Aem Content Finder
- Storing component configurations
- Working with packages
- Jcr Support
- Authoring tutorial - Touch UI
- Adding and editing a component
- Sites management tutorial