Magellan supports the creation of custom step definitions via Groovy scripting.
Groovy: Java-syntax-compatible object-oriented programming language for the Java platform.
How to create custom step definitions
You need to create three groovy classes for the followings:
- Project Step Definitions
- UI Step Implementation
- Config Step Implementation
Then place them under the following folder structure “project/common/resources/ext/hercules/” directory as shown below:

Example Custom Groovy Classes
The following example groovy classes were developed for a project called Catapult. If you want to see more custom steps examples please follow For more examples please follow Custom Step Examples
Example Step Definition: I logon as catapult user (\\S+) with password (\\S+)\$
FIRST STEP – Project Step Definitions:
package com.fostermoore.catalyst.catapult.cluster.common.resources.ext.hercules
import com.fostermoore.catalyst.kauri.Log
import com.fostermoore.catalyst.kauri.LogFactory
import com.fostermoore.catalyst.ng.blade.test.Support
import com.fostermoore.catalyst.ng.blade.test.hercules.HerculesFactory
import com.fostermoore.catalyst.ng.io.cucumber.java.en.And
import com.fostermoore.catalyst.ng.io.cucumber.java.en.Given
import com.fostermoore.catalyst.ng.io.cucumber.java.en.When
import com.fostermoore.catalyst.ng.io.cucumber.java.en.Then
import org.apache.commons.lang.StringUtils
import static com.fostermoore.catalyst.ng.blade.test.hercules.HerculesStepUtils.decodeVariables
import static com.fostermoore.catalyst.ng.blade.test.hercules.HerculesStepUtils.getElapsedNanos
class CatapultStepDefinitions {
private CatapultSteps delegate
private static final Log log = LogFactory.getLog(CatapultStepDefinitions.class)
private CatapultSteps delegate() {
switch (StringUtils.defaultIfBlank(System.getProperty(HerculesFactory.IMPLEMENTATION_KEY), HerculesFactory.CONFIG_IMPL).toLowerCase()) {
case HerculesFactory.UI_IMPL:
delegate = (new CatapultSeleniumSteps()) as CatapultSteps
break
default:
delegate = (new CatapultConfigSteps()) as CatapultSteps
}
}
@Given("^I logon as catapult user (\\S+) with password (\\S+)\$")
@Documentation(value="logs the given user on with the given password",link="logonAsCatapult")
public void logon(String username, String password) {
long start = System.nanoTime();
String user = decodeVariables(delegate(), username);
String pwd = decodeVariables(delegate(), password);
delegate().logonAs(user, pwd);
log.debug("[%s] logon as '%s' completed in %s", delegate().getMode(), user, getElapsedNanos(start));
}
@And("^I click catapult button (\\S+)\$")
@Documentation(value="clicks catapult buttons",link="clickCatapultButton")
public void click(String path) {
String button = decodeVariables(delegate(), path)
delegate().clickButtons(button)
}
}
SECOND STEP – Project Specific call:
package com.fostermoore.catalyst.catapult.cluster.common.resources.ext.hercules
import com.fostermoore.catalyst.ng.blade.test.hercules.HerculesSteps
interface CatapultSteps extends HerculesSteps {
void clickButtons(String path);
}
THIRD STEP – Project UI Step Implementation:
Please check the list of UI Selenium API for more information:
package com.fostermoore.catalyst.catapult.cluster.common.resources.ext.hercules
import com.fostermoore.catalyst.cheetah.util.StringUtils
import com.fostermoore.catalyst.kauri.Log
import com.fostermoore.catalyst.kauri.LogFactory
import com.fostermoore.catalyst.ng.blade.test.hercules.HerculesSteps
import com.fostermoore.catalyst.ng.blade.test.hercules.selenium.HerculesSeleniumSteps
import org.openqa.selenium.By
import org.testng.Assert
class CatapultSeleniumSteps extends HerculesSeleniumSteps {
private static final Log log = LogFactory.getLog(CatapultSeleniumSteps.class)
public static String label_name;
public static String label_index;
CatapultSeleniumSteps() {
super()
init()
}
@Override
public void logonAs(String username, String password) {
setApplication(getSecurityApp());
startService(getVariables().getString("logoff.service", "logoff"));
startService(getVariables().getString("logon.service", "logon"));
enterText(getVariables().getString("logon.username.label", "Username"), username, HerculesSteps.ATTRIBUTE_TYPE_TEXT);
enterText(getVariables().getString("logon.password.label", "Password"), password, HerculesSteps.ATTRIBUTE_TYPE_TEXT);
clickButton(getVariables().getString("logon.logon.button", "Logon"));
}
public void clickButtons(String path) {
log.debug("In Catapult Selenium Step logonAs method")
clickButton(path);
}
}
THIRD STEP II – Project Config Step Implementation:
package com.fostermoore.catalyst.catapult.cluster.common.resources.ext.hercules
import com.fostermoore.catalyst.cheetah.util.StringUtils
import com.fostermoore.catalyst.kauri.Log
import com.fostermoore.catalyst.kauri.LogFactory
import com.fostermoore.catalyst.ng.blade.api.ApiHandler
import com.fostermoore.catalyst.ng.blade.api.ApiRequest
import com.fostermoore.catalyst.ng.blade.api.ApiResponse
import com.fostermoore.catalyst.ng.blade.api.command.SmartSaveCommand
import com.fostermoore.catalyst.ng.blade.api.command.StartServiceCommand
import com.fostermoore.catalyst.ng.blade.api.command.UpdateCommand
import com.fostermoore.catalyst.ng.blade.api.command.ViewNodeButtonClickCommand
import com.fostermoore.catalyst.ng.blade.context.ApplicationContext
import com.fostermoore.catalyst.ng.blade.context.Session
import com.fostermoore.catalyst.ng.blade.context.User
import com.fostermoore.catalyst.ng.blade.context.impl.SessionImpl
import com.fostermoore.catalyst.ng.blade.controller.RedirectException
import com.fostermoore.catalyst.ng.blade.model.ViewNode
import com.fostermoore.catalyst.ng.blade.test.config.TestExecutionContext
import com.fostermoore.catalyst.ng.blade.test.hercules.config.HerculesConfigSteps
import org.testng.AssertJUnit
class CatapultConfigSteps extends HerculesConfigSteps {
private static final Log log = LogFactory.getLog(CatapultConfigSteps.class)
@Override
public void logonAs(String username, String password) {
log.debug("In Catapult Config Step logonAs method")
setApplication(getSecurityApp());
AssertJUnit.assertNotNull("Need to specify a username", username);
User user = lookupUserFor(username);
AssertJUnit.assertNotNull(user);
setApplication(getMasterApp());
Session session = ApplicationContext.get().getSession();
if (session instanceof SessionImpl) {
((SessionImpl) session).setUser(user);
} else {
log.error("Failed to logon user as expected Session to be a SessionImpl but was:" +session.getClass());
}
//this forces Kauri Ctx refresh
ApplicationContext.Holder.set(ApplicationContext.get());
//navigate to home service - TODO: is this needed?
startService(getVariables().getString("home.service", "home"));
}
public void clickButtons(String path) {
AssertJUnit.assertTrue("Need to specify a button to click", StringUtils.isNotBlank(path));
ApiRequest apiRequest = new ApiRequest();
AssertJUnit.assertNotNull(TestExecutionContext.Holder.get().getCurrentServiceTransaction());
String vpathExpr = buildVpathExpression(path, ViewNode.TYPE_BUTTON, false);
List<ViewNode> buttons = TestExecutionContext.Holder.get().getCurrentServiceTransaction().getViewTree().select(vpathExpr)
if (buttons == null || buttons.isEmpty()) {
//we have found no buttons
AssertJUnit.fail("Expected to find button: '" + path + "', but didn't");
} else if (buttons.size() > 1) {
//we have found too many buttons, so now try just visible buttons
vpathExpr = buildVpathExpression(path, ViewNode.TYPE_BUTTON, true);
buttons = TestExecutionContext.Holder.get().getCurrentServiceTransaction().getViewTree().select(vpathExpr);
}
AssertJUnit.assertEquals("Expected to find only 1 button: '" + path + "', but found " + buttons.size(), 1, buttons.size());
apiRequest.getCommands().add(new UpdateCommand().setId(TestExecutionContext.Holder.get().getCurrentServiceTransaction().getId()));
apiRequest.getCommands().add(new ViewNodeButtonClickCommand().setVpath(vpathExpr));
apiRequest.getCommands().add(new SmartSaveCommand());
ApiHandler apiHandler = new ApiHandler();
apiRequest.setReturnServiceTransaction(true).setReturnViewTree(true);
try {
ApiResponse response = apiHandler.handle(apiRequest);
AssertJUnit.assertNull("Failed to process request '" + apiRequest + "', error(s):" + response.getError(), response.getError());
TestExecutionContext.Holder.get().setCurrentServiceTransaction(response.getServiceTransaction());
if (ApplicationContext.get().getResponse().getServiceUrl() != null) {
handleRedirect(ApplicationContext.get().getResponse().getServiceUrl());
} else {
//TODO: we should not assume clicking a button, that does not result in a redirect, should always require the service transaction to be validated.
validateServiceTransaction();
}
} catch (RedirectException e) {
handleRedirect(e.getServiceUrl());
}
}
}
Custom step definitions don’t show colors
0

