Attributes
A way to configure page object components.
General
Atata attributes can divided into the categories:
- Attributes of control search - basically, element locators,
like
[FindById]
,[FindByName]
,[FindByXPath]
, etc. - Trigger attributes - a functionality that is automatically executed in response to certain events on a particular component. For example, when a click on button occurs it may be defined that a wait should be executed.
- Behavior attributes - change the way how particular actions are executed.
For example, specify the click behavior for a specific button by adding
[ClickUsingScript]
to perform the click using JavaScript, instead of defaultIWebElement.Click()
way. - Settings attributes - set settings for control finding, culture, value format, etc.
Attribute Levels
There are 5 attributes levels (ordered by priority from lowest to highest level):
- Declared
- Parent component
- Assembly
- Global
- Component
Replacable attributes (FindAttribute
’s, behaviors, etc.) at lower level can override similar attributes at higher levels.
Declared Level
Declared attributes are located on control properties.
[FindById("post-title")]
public TextInput<_> Title { get; private set; }
Parent Component Level
Parent pomponent attributes are located on a parent component, which can be a page object class or a wrapping control.
[FindById("post-title", TargetName = nameof(Title))]
public class SomePage : Page<_>
{
public TextInput<_> Title { get; private set; }
}
[FindByName(TargetType = typeof(TextInput<>))]
public class UserDetailsSection<TOwner> : Control<TOwner>
where TOwner : PageObject<TOwner>
{
public TextInput<_> FirstName { get; private set; }
public TextInput<_> LastName { get; private set; }
}
Assembly Level
Assembly attributes are spread across all components in the assembly where its is defined.
[assembly: Culture("en-US")]
[assembly: FindByName(TermCase.Pascal, TargetType = typeof(Input<,>))]
Global Level
Global attributes are spread across all components in scope of a certain AtataContext
or all contexts if an attribute is added to AtataContext.GlobalConfiguration
.
Global attributes can be added though AtataContextBuilder.Attributes
property
or specified in JSON config file (see JSON Schema).
AtataContext.Configure()
.Attributes.Global.Add(
new ClicksUsingScriptAttribute())
.Build();
AtataContext.GlobalConfiguration
.Attributes.Global.Add(
new FindByIdAttribute
{
TargetTypes = new[] { typeof(Button<>), typeof(TextInput<>) }
});
Component Level
Component-level attributes are defined on a class of component and don’t have any target property set.
[Url("some-page")]
public class SomePage : Page<_>
{
}
[ControlDefinition("div", ContainingClass = "some-class")]
public class SomeControl<TOwner> : Control<_>
where TOwner : PageObject<TOwner>
{
}
MulticastAttribute
Almost all Atata attributes, except of few special ones, are inherited from a base MulticastAttribute
.
MulticastAttribute
can be applied to a component at any level (declared, parent component, assembly, global and component).
Properties
public string[] TargetNames { get; set; }
public string TargetName { get; set; }
public Type[] TargetTypes { get; set; }
public Type TargetType { get; set; }
public string[] TargetTags { get; set; }
public string TargetTag { get; set; }
public Type[] TargetParentTypes { get; set; }
public Type TargetParentType { get; set; }
public string[] ExcludeTargetNames { get; set; }
public string ExcludeTargetName { get; set; }
public Type[] ExcludeTargetTypes { get; set; }
public Type ExcludeTargetType { get; set; }
public string[] ExcludeTargetTags { get; set; }
public string ExcludeTargetTag { get; set; }
public Type[] ExcludeTargetParentTypes { get; set; }
public Type ExcludeTargetParentType { get; set; }
public bool TargetSelf { get; set; }
public bool TargetSelfAndChildren { get; set; }
public bool TargetAnyType { get; set; }
public bool TargetAllChildren { get; set; }
public bool TargetChildren { get; set; }
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.
It can be done using targeting mechanics of MulticastAttribute
.
[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; }
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 FindAttribute
s 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 WaitForAngularAttribute());
Adds WaitForAngularAttribute
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 WaitForAngularAttribute
{
TargetType = typeof(Page<>)
});
Adds WaitForAngularAttribute
trigger to all page classes that are located in “SomeProduct.SomeAtataComponentsLibrary” library (project).