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
AtataContextattributes - major #398 Global level attributes
- minor
#402 Add
TryGetmethod toUIComponentMetadata - minor
#403 Add
Containsmethod toUIComponentMetadata - minor
#414 Add
Addmethods toUIComponentMetadata - minor
#415 Add
RemoveandRemoveAllmethods toUIComponentMetadata - minor
#416 Add
TargetAllChildrenproperty toMulticastAttribute - minor
#420
ObjectCreator
Changes and Enhancements
- minor
#394 Add parameterless generic
AddScreenshotConsumermethod toAtataContextBuilder - minor
#399 Inherit
UrlAttributefromMulticastAttribute - minor
#400 Inherit
NameAttributefromMulticastAttribute - minor
#401 Inherit
NavigationPageObjectCreatorAttributefromMulticastAttribute - minor
#404 Inherit
TraceLogAttributefromMulticastAttribute - minor
#405 Inherit
WindowTitleAttributefromMulticastAttribute - minor
#406 Inherit
ExtraXPathAttributefromMulticastAttribute - minor
#407 Inherit
GoTemporarilyAttributefromMulticastAttribute - minor
#408 Inherit
IdXPathForLabelAttributefromMulticastAttribute - minor
#409 Inherit
RandomizeCountAttributefromMulticastAttribute - minor
#410 Inherit
RandomizeIncludeAttributefromMulticastAttribute - minor
#411 Inherit
RandomizeExcludeAttributefromMulticastAttribute - minor
#412 Inherit
RandomizeNumberSettingsAttributefromMulticastAttribute - minor
#413 Inherit
RandomizeStringSettingsAttributefromMulticastAttribute - minor
#417 Inherit
TriggerAttributefromMulticastAttribute - minor
#418 Make universal
AttributeUsageofMulticastAttributeand 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):
- Declared
- Parent component
- Assembly
- Global
- 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; }