Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for IWebElement natively #81

Merged
merged 10 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0"/>
<PackageReference Include="NUnit" Version="3.13.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0"/>
<PackageReference Include="Selenium.WebDriver" Version="4.18.1" />
<PackageReference Include="Selenium.WebDriver" Version="4.21.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<PackageReference Include="NUnit" Version="3.13.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0"/>
<PackageReference Include="coverlet.collector" Version="3.1.0"/>
<PackageReference Include="Selenium.WebDriver" Version="4.18.1" />
<PackageReference Include="Selenium.WebDriver" Version="4.21.0" />
<PackageReference Include="RichardSzalay.MockHttp" Version="7.0.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ internal class CreateSnapshotFromWebDriverIn
public DiffingOptionsIn? DiffingOptions { get; set; }
[JsonProperty("ignoreRegions")]
public RegionIn[] IgnoreRegions { get; }
[JsonProperty("ignoreElements")]
public ElementIn[]? IgnoreElements { get; }
[JsonProperty("jobId")]
public string JobId { get; }
[JsonProperty("name")]
Expand All @@ -30,6 +32,8 @@ internal class CreateSnapshotFromWebDriverIn

[JsonProperty("clipSelector")]
public string? ClipSelector { get; set; }
[JsonProperty("clipElement")]
public string? ClipElement { get; set; }
[JsonProperty("fullPageConfig")]
public FullPageConfigIn? FullPageConfig { get; set; }

Expand All @@ -43,21 +47,25 @@ public CreateSnapshotFromWebDriverIn(
RegionIn[] regions,
bool captureDom,
string? clipSelector,
string? clipElement,
string? suiteName,
string? testName,
ElementIn[]? ignoredElements,
FullPageConfigIn? fullPageConfig,
DiffingOptionsIn? diffingOptions
)
{
BuildUuid = buildUuid;
DiffingMethod = diffingMethod;
IgnoreRegions = regions;
IgnoreElements = ignoredElements;
JobId = jobId;
Name = name;
SessionMetadata = sessionMetadata;
SessionId = sessionId;
CaptureDom = captureDom;
ClipSelector = clipSelector;
ClipElement = clipElement;
SuiteName = suiteName;
TestName = testName;
FullPageConfig = fullPageConfig;
Expand Down
29 changes: 29 additions & 0 deletions visual-dotnet/SauceLabs.Visual/GraphQL/ElementIn.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Newtonsoft.Json;
using OpenQA.Selenium;
using SauceLabs.Visual.Models;
using SauceLabs.Visual.Utils;

namespace SauceLabs.Visual.GraphQL
{
internal class ElementIn
{
[JsonProperty("name")]
public string? Name { get; }
[JsonProperty("id")]
public string Id { get; }

[JsonProperty("diffingOptions")]
public DiffingOptionsIn? DiffingOptions { get; }

public ElementIn(IWebElement element, DiffingOptionsIn opts) : this(element, null, opts)
{
}

public ElementIn(IWebElement element, string? name = null, DiffingOptionsIn? diffingOptions = null)
{
Id = element.GetElementId();
Name = name;
DiffingOptions = diffingOptions;
}
}
}
14 changes: 13 additions & 1 deletion visual-dotnet/SauceLabs.Visual/Models/SelectiveRegion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,19 @@ internal RegionIn ToRegionIn()
return new RegionIn(Element, diffingOptions);
}

throw new VisualClientException("No Element nor Region has been passed");
throw new VisualClientException("No Region has been passed");
}


internal ElementIn ToElementIn()
{
if (Element == null)
{
throw new VisualClientException("No Element has been passed");
}

var diffingOptions = DiffingOptionsInHelper.CreateFromEnableOnlyDisable(EnableOnly, DisableOnly);
return new ElementIn(Element, null, diffingOptions);
}
}
}
21 changes: 21 additions & 0 deletions visual-dotnet/SauceLabs.Visual/Utils/IWebElementExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Reflection;
using OpenQA.Selenium;

namespace SauceLabs.Visual.Utils
{
internal static class IWebElementExtension
{
internal static string GetElementId(this IWebElement element)
{
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
var field = element.GetType().GetField("elementId", bindingFlags);
var id = (string?)field?.GetValue(element);

if (id == null)
{
throw new VisualClientException("Unable to retrieve Id from WebElement");
}
return id;
}
}
}
34 changes: 34 additions & 0 deletions visual-dotnet/SauceLabs.Visual/Utils/IgnoredRegions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Linq;
using OpenQA.Selenium;
using SauceLabs.Visual.GraphQL;
using SauceLabs.Visual.Models;

namespace SauceLabs.Visual.Utils
{
internal class IgnoredRegions
{
internal RegionIn[] RegionsIn;

Check warning on line 11 in visual-dotnet/SauceLabs.Visual/Utils/IgnoredRegions.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field 'RegionsIn' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

Check warning on line 11 in visual-dotnet/SauceLabs.Visual/Utils/IgnoredRegions.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field 'RegionsIn' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
internal ElementIn[] ElementsIn;

Check warning on line 12 in visual-dotnet/SauceLabs.Visual/Utils/IgnoredRegions.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field 'ElementsIn' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

Check warning on line 12 in visual-dotnet/SauceLabs.Visual/Utils/IgnoredRegions.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field 'ElementsIn' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.


internal static IgnoredRegions SplitIgnoredRegions(SelectiveRegion[]? regions, IgnoreRegion[]? ignoreRegions, IWebElement[]? ignoreElements)
{
var emptyRegions = regions?.Any(r => r.Region == null && r.Element == null);
if (emptyRegions != null && emptyRegions != false)
{
throw new VisualClientException("Some ignore regions have Element nor Region");
}

var ignoredRegions = new List<RegionIn>();
ignoredRegions.AddRange(ignoreRegions?.Select(r => new RegionIn(r)) ?? new List<RegionIn>());
ignoredRegions.AddRange(regions?.Where(r => r.Region != null).Select(r => r.ToRegionIn()) ?? new List<RegionIn>());

var ignoredElements = new List<ElementIn>();
ignoredElements.AddRange(ignoreElements?.Select(elem => new ElementIn(elem)) ?? new List<ElementIn>());
ignoredElements.AddRange(regions?.Where(r => r.Element != null).Select(r => r.ToElementIn()) ?? new List<ElementIn>());

return new IgnoredRegions { RegionsIn = ignoredRegions.ToArray(), ElementsIn = ignoredElements.ToArray() };
}
}
}
1 change: 1 addition & 0 deletions visual-dotnet/SauceLabs.Visual/VisualCheckOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class VisualCheckOptions
public bool? FullPage { get; set; }
public FullPageConfig? FullPageConfig { get; set; }
public string? ClipSelector { get; set; }
public IWebElement? ClipElement { get; set; }

/// <summary>
/// <c>DiffingOptions</c> set which kind of changes should be considered.
Expand Down
9 changes: 4 additions & 5 deletions visual-dotnet/SauceLabs.Visual/VisualClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
/// <param name="region">the Sauce Labs region to connect to</param>
/// <param name="username">the Sauce Labs username</param>
/// <param name="accessKey">the Sauce Labs access key</param>
private VisualClient(WebDriver wd, Region region, string username, string accessKey)

Check warning on line 95 in visual-dotnet/SauceLabs.Visual/VisualClient.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Build' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 95 in visual-dotnet/SauceLabs.Visual/VisualClient.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Build' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
{
if (StringUtils.IsNullOrEmpty(username) || StringUtils.IsNullOrEmpty(accessKey))
{
Expand Down Expand Up @@ -141,10 +141,7 @@

private async Task<string> VisualCheckAsync(string name, VisualCheckOptions options)
{
var ignored = new List<RegionIn>();
ignored.AddRange(options.IgnoreRegions?.Select(r => new RegionIn(r)) ?? new List<RegionIn>());
ignored.AddRange(options.IgnoreElements?.Select(r => new RegionIn(r)) ?? new List<RegionIn>());
ignored.AddRange(options.Regions?.Select(r => r.ToRegionIn()) ?? new List<RegionIn>());
var ignoredRegions = IgnoredRegions.SplitIgnoredRegions(options.Regions, options.IgnoreRegions, options.IgnoreElements);

FullPageConfigIn? fullPageConfigIn = null;
if (options.FullPage == true)
Expand All @@ -157,11 +154,13 @@
name: name,
jobId: _jobId,
diffingMethod: options.DiffingMethod ?? DiffingMethod.Simple,
regions: ignored.ToArray(),
regions: ignoredRegions.RegionsIn,
ignoredElements: ignoredRegions.ElementsIn,
sessionId: _sessionId,
sessionMetadata: _sessionMetadataBlob ?? "",
captureDom: options.CaptureDom ?? CaptureDom,
clipSelector: options.ClipSelector,
clipElement: options.ClipElement?.GetElementId(),
suiteName: options.SuiteName,
testName: options.TestName,
fullPageConfig: fullPageConfigIn,
Expand Down