Extend The Framework to Fit Your Needs

To be sure that you will use BELLATRIX happily and frequently, we developed enormous ways to extend it. We have thus provided you with a wider test execution life cycle with the ability to plug-in everywhere.

Extended Test Execution Life Cycle and Plugins

Have a full control over your test execution.

All test frameworks give you the possibility to execute logic at certain points before or after tests. Typically tests are placed inside test classes. The standard test workflow for MSTest and NUnit is:

1. Execute Assembly Initialize – once for the whole project
2. Execute Class Initialize – once for the test class
3. Execute Test Initialize – executed before each test
4. Execute Test
5. Execute Test Cleanup – executed after each test
6. Execute Class Cleanup – once for the test class
7. Execute Assembly Cleanup – once for the whole project

Why do you need to extend the standard workflow?

Usually, you want to use these primary methods to execute business test-related logic. Sample use cases:

  • Take screenshots of test failure
  • Take videos on test failure
  • Fail tests if not executed under a certain time
  • Log test results in a 3rd party system
  • Control the browser life cycle

In order to meet these requirements and allow you to write custom plugins, BELLATRIX comes with an extended test execution life cycle. When you write a plugin, you can execute logic in various phases of the new life cycle- before TestInitialize, after TestInitialize, before TestCleanup, after TestCleanup and more. For each test, all registered plugins logic is executed. This is how some of the BELLATRIX features work such as video and screenshot on test failure, browser life cycle, and more.

You can easily write your custom plugins. See how it is done.

In BELLATRIX, we have a feature called “execution time under”. Here you specify for the test class the maximal allowed test execution time if some of the tests take longer to run- it fails automatically. This is done through a test workflow plugin.

This is how we specify the maximal allowed time.

 public class MeasuredResponseTimesTests : WebTest

This is part of the plugin.

public class ExecutionTimeUnderTestWorkflowPlugin : TestWorkflowPlugin
    protected override void PostTestInit(object sender, TestWorkflowPluginEventArgs e)
        // get the start time

    protected override void PostTestCleanup(object sender, TestWorkflowPluginEventArgs e)
        // total time = start time - current time
        // IF total time > specified time ===> FAIL TEST

In PostTestInit we start a stopwatch. We get the number placed inside the attribute in the PostTestCleanup method. Then stop the stopwatch and compare the actual and specified times. In case first took longer, we fail the test.
Learn more

Override Globally Element Actions

Change how specific element action is performed.

For example, instead of using our button Click method, use JavaScript to click the button. If you want to change this behaviour for all tests, each BELLATRIX UI element gives you this possibility. You need to initialise the element static delegates- Override{MethodName}Globally.

public static void AssemblyInitialize(TestContext testContext)
    Button.OverrideClickGlobally = (e) =>
        App.JavaScriptService.Execute("arguments[0].click();", e);

Here we change the behaviour of all BELLATRIX UI button elements. Instead of using the default Click method, first we wait for the button to exist and to be clickable. Then instead of using a low-level WebDriver click, the button is clicked through JavaScript.
Learn more

Locally Override Element Actions

Change the UI element action behavior, but only for part of your tests.

In this scenario, you may use BELLATRIX “override element locally” feature. You need to initialize the static delegates- Override{MethodName}Locally. This may be useful to make a temporary fix only for certain page where the default behavior is not working as expected.

  Anchor.OverrideFocusLocally = (e) =>
       App.JavaScriptService.Execute("arguments[0].focus();", anchor);

This call overrides how anchors’ Focus method works only for the currently executing test. After the test is over, the default behavior is restored.

Learn more

Element Action Hooks

Another way to extend BELLATRIX is to use the controls hooks.

This is how the BDD logging and highlighting are implemented. For each control’s method, there are two hooks- one that is called “before the action” and one “after”. For example, the available hooks for the button are:

  • Clicking – an event executed before button click
  • Clicked – an event executed after the button is clicked
  • Hovering – an event executed before button hover
  • Hovered – an event executed after the button is hovered
  • Focusing – an event executed before button focus
  • Focused – an event executed after the button is focused

You need to implement the event handlers for these events and subscribe to them.

public void ClickingEventHandler(object sender, ElementActionEventArgs arg)
    Logger.LogInformation($"Click {arg.Element.ElementName}");

public void HoveringEventHandler(object sender, ElementActionEventArgs arg)
    Logger.LogInformation($"Hover {arg.Element.ElementName}");

These are two sample event handlers for the BELLATRIX button where we log messages before clicking and hovering a button.

Learn more

Common Services Action Hooks

Another way to extend BELLATRIX is to use hooks for its common services.

This is how the failed test analysis works. Here is a list of some common services events you can subscribe to: NavigationService – UrlNotNavigatedEvent, called if the WaitForPartialUrl throws an exception ElementWaitService – OnElementNotFulfillingWaitConditionEvent, called if the Wait method throws an exception.

  • ScrollingToVisible – called before scrolling
  • ScrollingToVisible – called before scrolling
  • ScrolledToVisible – called after scrolling
  • SettingAttribute – called before setting a web attribute
  • AttributeSet – called after setting a value to a web attribute
  • CreatingElement – called before creating the element
  • CreatedElement – called after the creation of the element
  • CreatingElements – called before the creation of nested element
  • CreatedElements – called after the creation of nested element
  • ReturningWrappedElement – called before searching for a native WebDriver element
public static void OnElementNotFound(object sender, ExceptionEventArgs args)
    var exceptionAnalyser = new ExceptionAnalyser();
    throw args.Exception;

This is one of the event handlers we use to call exception analysation engine if an element is not found.
Learn more

Extend Existing UI Elements

You have the ability to add new methods to existing BELLATRIX UI elements. You can add new methods in two ways.

Extension Methods

One way to extend an existing element is to create an extension method for the additional action.

public static class ButtonExtensions
    public static void SubmitButtonWithEnter(this Button button)
        var action = new Actions(button.WrappedDriver);

To use the new method, add a using statement to the extension methods’ namespace.


Click the “proceed to checkout” button via the Enter key instead of clicking on it.
Learn more

Child Elements

The second way of extending an existing element is to create a child element. Inherit the UI control you want to extend.

public class ExtendedButton : Button
    public void SubmitButtonWithEnter()
        var action = new Actions(WrappedDriver);

Next in your tests, use the ExtendedButton instead of the regular Button to have access to these methods.

ExtendedButton proceedToCheckout = 
 App.ElementCreateService.CreateByClassContaining<ExtendedButton>("checkout-button button alt wc-forward");

Learn more

Extend Common Services

Ability to add a new method to BELLATRIX common services.

For example, a new special way of navigating or custom logic for handling dialog alerts.
To extend the BELLATRIX common services you can create an extension method for the additional action.

public static class NavigationServiceExtensions
    public static void NavigateViaJavaScript(this NavigationService navigationService, string url)
        var javaScriptService = new JavaScriptService();
        javaScriptService.Execute($"window.location.href = '{url}';");

To use the new method, add a using statement to the extension methods’ namespace.


Learn more

Add New Find Locators

The ability to avoid code duplication and complex locate expressions by adding a custom find locators.

Here is a sample implementation of the locator for finding all elements starting with ID.
First, we need to create the By locator.

public class ByIdEndingWith : By
    public ByIdEndingWith(string value)
        : base(value)

    public override OpenQA.Selenium.By Convert() => OpenQA.Selenium.By.CssSelector($"[id^='{Value}']");

In the Convert method, we use a standard WebDriver By locator, and in this case we implement our requirements through a little CSS. To ease the usage of the locator, we need to create an extension method of ElementCreateService.

public static TElement CreateByIdStartingWith<TElement>(this ElementCreateService repository, string idStarting)
    where TElement : Element
    repository.Create<TElement, ByIdStartingWith>(new ByIdStartingWith(idStarting));

This is everything after that you can use your new locator as it was originally part of BELLATRIX.
Learn more

Add New Element Wait Methods

Ability to add your custom element wait logic.

Imagine that you want to wait for an element to have a specific style. First, create a new class and inherit the BaseUntil class.

public class UntilHasStyle : BaseUntil
    private readonly string _elementStyle;

    public UntilHasStyle(string elementStyle, int? timeoutInterval = null, int? sleepInterval = null)
        : base(timeoutInterval, sleepInterval)
        _elementStyle = elementStyle;

    public override void WaitUntil<TBy>(TBy by) => WaitUntil(ElementHasStyle(WrappedWebDriver, by), TimeoutInterval, SleepInterval);

    private Func<IWebDriver, bool> ElementHasStyle<TBy>(ISearchContext searchContext, TBy by)
        where TBy : By => driver =>
                                            var element = FindElement(searchContext, by);
                                            return element != null && element.GetAttribute("style").Equals(_elementStyle);
                                        catch (StaleElementReferenceException)
                                            return false;

The important part is located in the ElementHasStyle function. There we find the element and check the current value in the style attribute. The internal WaitUntil will wait until the value changes in the specified time. The next and final step is to create an extension method for all UI elements.

public static TElementType ToHasStyle<TElementType>(this TElementType element, string style, int? timeoutInterval = null, int? sleepInterval = null)
    where TElementType : Element
    var until = new UntilHasStyle(style, timeoutInterval, sleepInterval);
    return element;

After UntilHasStyle is created, it is important to be passed on to the element’s EnsureState method. From now on, the method is available as it was originally part of the framework.
Learn more

Try Now Bellatrix

Build up to 100 tests using full product capabilities.