Atata 1.8.0 is Released

October 30, 2020 by Yevgeniy Shunevych


Atata 1.8.0 is released with a new script executor and significant enhancement of the attributes system.

Changelog

New Features

  • major #391 Script executor
  • major #392 Support attributes declared at property level that target control’s children
  • major #397 AtataContext attributes
  • major #398 Global level attributes
  • minor #402 Add TryGet method to UIComponentMetadata
  • minor #403 Add Contains method to UIComponentMetadata
  • minor #414 Add Add methods to UIComponentMetadata
  • minor #415 Add Remove and RemoveAll methods to UIComponentMetadata
  • minor #416 Add TargetAllChildren property to MulticastAttribute
  • minor #420 ObjectCreator

Changes and Enhancements

  • minor #394 Add parameterless generic AddScreenshotConsumer method to AtataContextBuilder
  • minor #399 Inherit UrlAttribute from MulticastAttribute
  • minor #400 Inherit NameAttribute from MulticastAttribute
  • minor #401 Inherit NavigationPageObjectCreatorAttribute from MulticastAttribute
  • minor #404 Inherit TraceLogAttribute from MulticastAttribute
  • minor #405 Inherit WindowTitleAttribute from MulticastAttribute
  • minor #406 Inherit ExtraXPathAttribute from MulticastAttribute
  • minor #407 Inherit GoTemporarilyAttribute from MulticastAttribute
  • minor #408 Inherit IdXPathForLabelAttribute from MulticastAttribute
  • minor #409 Inherit RandomizeCountAttribute from MulticastAttribute
  • minor #410 Inherit RandomizeIncludeAttribute from MulticastAttribute
  • minor #411 Inherit RandomizeExcludeAttribute from MulticastAttribute
  • minor #412 Inherit RandomizeNumberSettingsAttribute from MulticastAttribute
  • minor #413 Inherit RandomizeStringSettingsAttribute from MulticastAttribute
  • minor #417 Inherit TriggerAttribute from MulticastAttribute
  • minor #418 Make universal AttributeUsage of MulticastAttribute and inheritors
  • minor #419 Update attributes that implement IFindItemAttribute

Fixes

  • fix #393 Fail to log message containing “{“ character
  • fix #395 Incorrect order of layered attributes

Script Executor

Idea

The purpose of this feature is a simplification of JavaScript execution. Currently to execute script you should write the code like Driver.ExecuteScript("...") (inside page object) or AtataContext.Current.Driver.ExecuteScript("...") (everywhere else).

There is also a need to simplify passing target element to the script, for example: Driver.ExecuteScript("arguments[0].click();", SomeComponent.Scope);

It would be better to be able to write the same action with: SomeComponent.Script.ExecuteAgainst("arguments[0].click();");

Implementation

UIComponentScriptExecutor<TOwner> is implemented as a part of UIComponent<TOwner>. It provides a set of methods for script execution, like:

component.Script.Execute("<some script>");
component.Script.ExecuteAgainst("arguments[0].click();");
component.Script.ExecuteAgainst("arguments[0].value = arguments[1];", "some value");

To execute a script inside a page object or a control:

Script.Execute("...");

Additionally, a set of ready to use script-executing methods are implemented: SetValue, SetValueAndDispatchChangeEvent, Click, Focus, ScrollIntoView.

Complete list of methods can be found in UIComponentScriptExecutor<TOwner> source file.

Verification

Verification of values returned by the script is also supported:

component.Script.ExecuteAgainst("return arguments[0].value;").Should.Equal("some_value")

AtataContext Attributes

This is the functionality to add extra attributes to components via AtataContext. These added attributes has higher order level and can override the attributes of the same kind (and at the same level) declared in a regular manner, for example FindAttributes or behavior attributes.

This feature can be quite useful in testing multi-language applications or applications that have some HTML differences on different environments/version/editions. So you might need to configure the page objects in a bit different way depending on testing environment.

Examples

Apply to Control

AtataContext.GlobalConfiguration
    .Attributes.Component(typeof(Button<>)).Add(
        new FindByIdAttribute());

Sets all buttons to be found by id attribute.

Apply to Several Controls

AtataContext.GlobalConfiguration
    .Attributes.Global.Add(
        new FindByIdAttribute
        {
            TargetTypes = new[] { typeof(Button<>), typeof(TextInput<>) }
        });

Sets all buttons and text inputs to be found by id attribute.

Apply to Page Object

AtataContext.GlobalConfiguration
    .Attributes.Component<SomePage>().Add(
        new WaitForAngularJSAjaxAttribute());

Adds WaitForAngularJSAjaxAttribute trigger to SomePage.

Apply to Control Property of Page Object

AtataContext.GlobalConfiguration
    .Attributes.Component<SomePage>()
        .Property(x => x.Save).Add(new FindByContentAttribute("Save"))
        .Property(x => x.Cancel).Add(new FindByContentAttribute("Cancel"));

Apply to Components Within Assembly

AtataContext.GlobalConfiguration
    .Attributes.Assembly("SomeProduct.SomeAtataComponentsLibrary").Add(
        new WaitForAngularJSAjaxAttribute
        {
            TargetType = typeof(Page<>)
        });

Adds WaitForAngularJSAjaxAttribute trigger to all page classes that are located in “SomeProduct.SomeAtataComponentsLibrary” library (project).

Global Level Attributes

Enable a feature of global level attributes used by UIComponentMetadata.

As a result, we have 5 attributes levels (ordered by priority):

  1. Declared
  2. Parent component
  3. Assembly
  4. Global
  5. Component

Replacable (FindAttribute’s, behaviors, etc.) attributes from higher level can override similar attributes from lower levels.

Consolidate All Attributes to Be MulticastAttribute

Almost all Atata attributes that were not inherited from MulticastAttribute are updated to inherit it. Including triggers. This gives much richer possibilities to apply attributes at different levels, and they also can be added thru AtataContext attributes system.

Support Attributes Declared at Property Level That Target Control’s Children

Example #1

Assume that we have a control class that contains Select button property:

[ControlDefinition(ContainingClass = "some-class")]
public class SomeControl<TOwner> : Control<TOwner>
    where TOwner : PageObject<TOwner>
{
    [FindFirst]
    public TextInput<TOwner> Input { get; private set; }

    [FindByContent("Select...")]
    public Button<TOwner> Select { get; private set; }
}

In most cases this button has text “Select…” that is used to identify the control. Regularly this control can be defined this way in page objects:

public SomeControl<_> Control1 { get; private set; }

Let’s also assume that in some particular page the text of this button can be different, for example “…”. So we need to change the locator of that button from [FindByContent("Select...")] to [FindByContent("...")] only for that page.

Now we can do this using targeting mechanics of Atata MulticastAttributes.

[FindByContent("...", TargetName = nameof(SomeControl<_>.Select))]
public SomeControl<_> Control1 { get; private set; }

Example #2

Another example is to change the settings of ItemsControl items.

The following ItemsControl has all descendant elements as items:

[FindById("some-id")]
public ItemsControl<Control<_>, _> ItemsControlOfDescendantsAsControls { get; private set; }

But this one has only child elements as items:

[FindById("some-id")]
[FindSettings(OuterXPath = "./", TargetName = "Items")]
public ItemsControl<Control<_>, _> ItemsControlOfChildrenAsControls { get; private set; }