Skip to content

Commit

Permalink
Add Support for IWebElement natively (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
FriggaHel authored Jul 2, 2024
1 parent f3af5ab commit 7f29bed
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 8 deletions.
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 @@ -141,10 +141,7 @@ public Task<string> VisualCheck(string name, VisualCheckOptions? options = null,

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 @@ private async Task<string> VisualCheckAsync(string name, VisualCheckOptions opti
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

0 comments on commit 7f29bed

Please sign in to comment.