Skip to content

Commit

Permalink
- #682 Add DomAttributes property to UIComponent<TOwner>;
Browse files Browse the repository at this point in the history
- #683 Add `DomProperties` property to `UIComponent<TOwner>`;
- #684 Add `DomClasses` property to `UIComponent<TOwner>`;
- #685 Make `UIComponent<TOwner>.Attributes` obsolete and replace its usage with `DomAttributes` and `DomProperties`
  • Loading branch information
YevgeniyShunevych committed Oct 12, 2022
1 parent a949b2f commit b8dd57d
Show file tree
Hide file tree
Showing 23 changed files with 267 additions and 36 deletions.
Expand Up @@ -18,6 +18,6 @@ public class GetsContentFromAttributeAttribute : ContentGetBehaviorAttribute
public string AttributeName { get; }

public override string Execute<TOwner>(IUIComponent<TOwner> component) =>
component.Attributes[AttributeName];
component.DomAttributes[AttributeName];
}
}
@@ -1,12 +1,12 @@
namespace Atata
{
/// <summary>
/// Represents the behavior for control value getting from <c>value</c> attribute.
/// Represents the behavior for control value getting from <c>value</c> DOM property.
/// </summary>
public class GetsValueFromValueAttribute : ValueGetBehaviorAttribute
{
/// <inheritdoc/>
public override string Execute<TOwner>(IUIComponent<TOwner> component) =>
component.Attributes.Value;
component.DomProperties.Value;
}
}
5 changes: 3 additions & 2 deletions src/Atata/Components/Fields/Content/Label`2.cs
Expand Up @@ -12,8 +12,9 @@ public class Label<TValue, TOwner> : Content<TValue, TOwner>
where TOwner : PageObject<TOwner>
{
/// <summary>
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> of the <c>for</c> attribute.
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> of the <c>for</c> DOM attribute.
/// </summary>
public ValueProvider<string, TOwner> For => Attributes.For;
public ValueProvider<string, TOwner> For =>
DomAttributes["for"];
}
}
2 changes: 1 addition & 1 deletion src/Atata/Components/Fields/EditableField`2.cs
Expand Up @@ -40,7 +40,7 @@ protected EditableField()
public new FieldVerificationProvider<TValue, EditableField<TValue, TOwner>, TOwner> WaitTo => Should.Using<WaitingVerificationStrategy>();

protected virtual bool GetIsReadOnly() =>
Attributes.ReadOnly;
DomProperties.ReadOnly.Value == true;

/// <summary>
/// Converts the value to string for <see cref="SetValue(TValue)"/> method.
Expand Down
16 changes: 16 additions & 0 deletions src/Atata/Components/IUIComponent`1.cs
Expand Up @@ -91,8 +91,24 @@ public interface IUIComponent<TOwner>
/// <summary>
/// Gets the <see cref="UIComponentAttributeProvider{TOwner}"/> instance that provides an access to the scope element's attributes.
/// </summary>
[Obsolete("Use DomProperties, DomAttributes or DomClasses instead.")] // Obsolete since v2.3.0.
UIComponentAttributeProvider<TOwner> Attributes { get; }

/// <summary>
/// Gets the <see cref="UIComponentAttributeProvider{TOwner}"/> instance that provides an access to the scope element's DOM attributes.
/// </summary>
UIComponentDomAttributesProvider<TOwner> DomAttributes { get; }

/// <summary>
/// Gets the <see cref="UIComponentAttributeProvider{TOwner}"/> instance that provides an access to the scope element's DOM properties.
/// </summary>
UIComponentDomPropertiesProvider<TOwner> DomProperties { get; }

/// <summary>
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> instance that provides a list of the scope element's DOM classes.
/// </summary>
ValueProvider<IEnumerable<string>, TOwner> DomClasses { get; }

/// <summary>
/// Gets the <see cref="UIComponentCssProvider{TOwner}"/> instance that provides an access to the scope element's CSS properties.
/// </summary>
Expand Down
8 changes: 5 additions & 3 deletions src/Atata/Components/ImageInput`1.cs
Expand Up @@ -11,13 +11,15 @@ public class ImageInput<TOwner> : Control<TOwner>
where TOwner : PageObject<TOwner>
{
/// <summary>
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> of the <c>src</c> attribute.
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> of the <c>src</c> DOM property.
/// </summary>
public ValueProvider<string, TOwner> Source => Attributes.Src;
public ValueProvider<string, TOwner> Source =>
DomProperties["src"];

/// <summary>
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> of the <c>alt</c> attribute.
/// </summary>
public ValueProvider<string, TOwner> Alt => Attributes.Alt;
public ValueProvider<string, TOwner> Alt =>
DomProperties["alt"];
}
}
4 changes: 2 additions & 2 deletions src/Atata/Components/Image`1.cs
Expand Up @@ -10,10 +10,10 @@ public class Image<TOwner> : Control<TOwner>
where TOwner : PageObject<TOwner>
{
/// <summary>
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> of the <c>src</c> attribute.
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> of the <c>src</c> DOM property.
/// </summary>
public ValueProvider<string, TOwner> Source =>
Attributes.Src;
DomProperties["src"];

/// <summary>
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> of the value indicating whether the image file is loaded.
Expand Down
2 changes: 1 addition & 1 deletion src/Atata/Components/LabelList`1.cs
Expand Up @@ -16,7 +16,7 @@ public class LabelList<TOwner> : AssociatedControlList<Label<TOwner>, TOwner>
/// <returns>The <see cref="Label{TOwner}"/> control.</returns>
protected override Label<TOwner> CreateAssociatedControl(Control<TOwner> control)
{
string id = control.Attributes.Id;
string id = control.DomProperties.Id;
return Component.Find<Label<TOwner>>(control.ComponentName, new FindByAttributeAttribute("for", id));
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/Atata/Components/UIComponentAttributeProvider`1.cs
Expand Up @@ -7,55 +7,77 @@ namespace Atata
/// Allows to access the component scope element's attribute values.
/// </summary>
/// <typeparam name="TOwner">The type of the owner page object.</typeparam>
[Obsolete("Use UIComponentDomAttributesProvider<TOwner> or UIComponentDomPropertiesProvider<TOwner> class instead.")] // Obsolete since v2.3.0.
public class UIComponentAttributeProvider<TOwner> : UIComponentPart<TOwner>
where TOwner : PageObject<TOwner>
{
private const string AttributeProviderNameFormat = "{0} attribute";

[Obsolete("Use {component}.DomProperties.Id instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Id => Get<string>(nameof(Id));

[Obsolete("Use {component}.DomProperties.Name instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Name => Get<string>(nameof(Name));

[Obsolete("Use {component}.DomProperties.Value instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Value => Get<string>(nameof(Value));

[Obsolete("Use {component}.DomProperties.Title instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Title => Get<string>(nameof(Title));

[Obsolete("Use Href or HrefAttribue of Link<TOwner> class instead. Alternatively use {component}.DomProperties[\"href\"] or {component}.DomAttributes[\"href\"] instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Href => Get<string>(nameof(Href));

[Obsolete("Use For of Label<TValue, TOwner> class instead. Alternatively use {component}.DomAttributes[\"for\"] instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> For => Get<string>(nameof(For));

[Obsolete("Use {component}.DomProperties[\"type\"] instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Type => Get<string>(nameof(Type));

[Obsolete("Use {component}.DomProperties.Style instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Style => Get<string>(nameof(Style));

[Obsolete("Use Alt of Image<TOwner>/ImageInput<TOwner> class instead. Alternatively use {component}.DomProperties[\"alt\"] instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Alt => Get<string>(nameof(Alt));

[Obsolete("Use Placeholder of Input<TValue, TOwner>/TextArea<TOwner> class instead. Alternatively use {component}.DomProperties[\"placeholder\"] instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Placeholder => Get<string>(nameof(Placeholder));

[Obsolete("Use {component}.DomProperties[\"target\"] instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Target => Get<string>(nameof(Target));

[Obsolete("Use Pattern of Input<TValue, TOwner> class instead. Alternatively use {component}.DomProperties[\"pattern\"] instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Pattern => Get<string>(nameof(Pattern));

[Obsolete("Use Accept of FileInput<TOwner> class instead. Alternatively use {component}.DomProperties[\"accept\"] instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Accept => Get<string>(nameof(Accept));

[Obsolete("Use Source or SourceAttribue of Image<TOwner>/ImageInput<TOwner> class instead. Alternatively use {component}.DomProperties[\"src\"] or {component}.DomAttributes[\"src\"] instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> Src => Get<string>(nameof(Src));

[Obsolete("Use {component}.DomProperties.TextContent instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> TextContent => Component.CreateValueProvider(
AttributeProviderNameFormat.FormatWith("textContent"),
() => GetValue("textContent")?.Trim());

[Obsolete("Use {component}.DomProperties.InnerHtml instead.")] // Obsolete since v2.3.0.
public ValueProvider<string, TOwner> InnerHtml => Component.CreateValueProvider(
AttributeProviderNameFormat.FormatWith("innerHTML"),
() => GetValue("innerHTML")?.Trim());

[Obsolete("Use {component}.DomProperties.Get<bool?>(\"disabled\") instead.")] // Obsolete since v2.3.0.
public ValueProvider<bool, TOwner> Disabled => Get<bool>(nameof(Disabled));

[Obsolete("Use {component}.DomProperties.ReadOnly instead.")] // Obsolete since v2.3.0.
public ValueProvider<bool, TOwner> ReadOnly => Get<bool>(nameof(ReadOnly));

[Obsolete("Use {component}.DomProperties.Get<bool?>(\"checked\") instead.")] // Obsolete since v2.3.0.
public ValueProvider<bool, TOwner> Checked => Get<bool>(nameof(Checked));

[Obsolete("Use {component}.DomProperties.Required instead.")] // Obsolete since v2.3.0.
public ValueProvider<bool, TOwner> Required => Get<bool>(nameof(Required));

[Obsolete("Use {component}.DomClasses instead.")] // Obsolete since v2.3.0.
public ValueProvider<IEnumerable<string>, TOwner> Class => Component.CreateValueProvider<IEnumerable<string>>(
"class attribute",
() => GetValue("class").Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries));
Expand Down
71 changes: 71 additions & 0 deletions src/Atata/Components/UIComponentDomAttributesProvider`1.cs
@@ -0,0 +1,71 @@
namespace Atata
{
/// <summary>
/// Allows to access the component scope element's DOM attribute values.
/// </summary>
/// <typeparam name="TOwner">The type of the owner page object.</typeparam>
public sealed class UIComponentDomAttributesProvider<TOwner> : UIComponentPart<TOwner>
where TOwner : PageObject<TOwner>
{
private const string AttributeProviderNameFormat = "\"{0}\" DOM attribute";

public UIComponentDomAttributesProvider(IUIComponent<TOwner> component)
{
Component = component.CheckNotNull(nameof(component));
ComponentPartName = "DOM attributes";
}

/// <summary>
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> instance for the value of the specified control's scope element attribute.
/// </summary>
/// <param name="attributeName">The name of the attribute.</param>
/// <returns>The <see cref="ValueProvider{TValue, TOwner}"/> instance for the attribute's current value.</returns>
public ValueProvider<string, TOwner> this[string attributeName] =>
Get<string>(attributeName);

/// <summary>
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> instance for the value of the specified control's scope element attribute.
/// </summary>
/// <typeparam name="TValue">The type of the attribute value.</typeparam>
/// <param name="attributeName">The name of the attribute.</param>
/// <returns>The <see cref="ValueProvider{TValue, TOwner}"/> instance for the attribute's current value.</returns>
public ValueProvider<TValue, TOwner> Get<TValue>(string attributeName)
{
attributeName.CheckNotNullOrWhitespace(nameof(attributeName));

return Component.CreateValueProvider(
AttributeProviderNameFormat.FormatWith(attributeName),
() => GetValue<TValue>(attributeName));
}

/// <summary>
/// Gets the value of the specified control's scope element attribute.
/// </summary>
/// <param name="attributeName">The name of the attribute.</param>
/// <returns>The attribute's current value.
/// Returns <see langword="null"/> if the value is not set.</returns>
public string GetValue(string attributeName)
{
attributeName.CheckNotNullOrWhitespace(nameof(attributeName));

return Component.Scope.GetDomAttribute(attributeName);
}

/// <summary>
/// Gets the value of the specified control's scope element attribute.
/// </summary>
/// <typeparam name="TValue">The type of the attribute value.</typeparam>
/// <param name="attributeName">The name of the attribute.</param>
/// <returns>The attribute's current value.
/// Returns <see langword="null"/> if the value is not set.</returns>
public TValue GetValue<TValue>(string attributeName)
{
string valueAsString = GetValue(attributeName);

if (string.IsNullOrEmpty(valueAsString) && typeof(TValue) == typeof(bool))
return default;

return TermResolver.FromString<TValue>(valueAsString);
}
}
}
100 changes: 100 additions & 0 deletions src/Atata/Components/UIComponentDomPropertiesProvider`1.cs
@@ -0,0 +1,100 @@
namespace Atata
{
/// <summary>
/// Allows to access the component scope element's DOM property values.
/// </summary>
/// <typeparam name="TOwner">The type of the owner page object.</typeparam>
public sealed class UIComponentDomPropertiesProvider<TOwner> : UIComponentPart<TOwner>
where TOwner : PageObject<TOwner>
{
private const string ItemProviderNameFormat = "\"{0}\" DOM property";

public UIComponentDomPropertiesProvider(IUIComponent<TOwner> component)
{
Component = component.CheckNotNull(nameof(component));
ComponentPartName = "DOM properties";
}

public ValueProvider<string, TOwner> Id =>
Get<string>("id");

public ValueProvider<string, TOwner> Name =>
Get<string>("name");

public ValueProvider<string, TOwner> Value =>
Get<string>("value");

public ValueProvider<string, TOwner> Title =>
Get<string>("title");

public ValueProvider<string, TOwner> Style =>
Get<string>("style");

public ValueProvider<bool?, TOwner> ReadOnly =>
Get<bool?>("readOnly");

public ValueProvider<bool?, TOwner> Required =>
Get<bool?>("required");

public ValueProvider<string, TOwner> TextContent => Component.CreateValueProvider(
ItemProviderNameFormat.FormatWith("textContent"),
() => GetValue("textContent")?.Trim());

public ValueProvider<string, TOwner> InnerHtml => Component.CreateValueProvider(
ItemProviderNameFormat.FormatWith("innerHTML"),
() => GetValue("innerHTML")?.Trim());

/// <summary>
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> instance for the value of the specified control's scope element property.
/// </summary>
/// <param name="propertyName">The name of the property.</param>
/// <returns>The <see cref="ValueProvider{TValue, TOwner}"/> instance for the property's current value.</returns>
public ValueProvider<string, TOwner> this[string propertyName] =>
Get<string>(propertyName);

/// <summary>
/// Gets the <see cref="ValueProvider{TValue, TOwner}"/> instance for the value of the specified control's scope element property.
/// </summary>
/// <typeparam name="TValue">The type of the property value.</typeparam>
/// <param name="propertyName">The name of the property.</param>
/// <returns>The <see cref="ValueProvider{TValue, TOwner}"/> instance for the property's current value.</returns>
public ValueProvider<TValue, TOwner> Get<TValue>(string propertyName)
{
propertyName.CheckNotNullOrWhitespace(nameof(propertyName));

return Component.CreateValueProvider(
ItemProviderNameFormat.FormatWith(propertyName),
() => GetValue<TValue>(propertyName));
}

/// <summary>
/// Gets the value of the specified control's scope element property.
/// </summary>
/// <param name="propertyName">The name of the property.</param>
/// <returns>The property's current value.
/// Returns <see langword="null"/> if the value is not set.</returns>
public string GetValue(string propertyName)
{
propertyName.CheckNotNullOrWhitespace(nameof(propertyName));

return Component.Scope.GetDomProperty(propertyName);
}

/// <summary>
/// Gets the value of the specified control's scope property attribute.
/// </summary>
/// <typeparam name="TValue">The type of the property value.</typeparam>
/// <param name="propertyName">The name of the property.</param>
/// <returns>The property's current value.
/// Returns <see langword="null"/> if the value is not set.</returns>
public TValue GetValue<TValue>(string propertyName)
{
string valueAsString = GetValue(propertyName);

if (string.IsNullOrEmpty(valueAsString) && typeof(TValue) == typeof(bool))
return default;

return TermResolver.FromString<TValue>(valueAsString);
}
}
}

0 comments on commit b8dd57d

Please sign in to comment.