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

Added IWebDriverManager<T> & extension method to fire DOM events #3

Merged
merged 11 commits into from
Apr 21, 2023
Merged
22 changes: 22 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
root = True

# Default settings
[*]
insert_final_newline = true
indent_style = space
indent_size = 4

# Xml project files
[*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
indent_size = 2

# Xml files
[*.{xml,stylecop,resx,ruleset}]
indent_size = 2

# Xml config files
[*.{props,targets,config,nuspec}]
indent_size = 2

[*.yml]
indent_size = 2
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased](https://github.com/maik-hasler/SeleniumSharper/compare/v1.1.0...HEAD)

## [v1.1.0](https://github.com/maik-hasler/SeleniumSharper/releases/tag/v1.1.0)
**Published:** 21th April 2023
### Added
- `IWebDriverManager<TOptions>` and first implementation for Chrome to automatically install driver binaries
- Helper classes related to `IWebDriverManager<TOptions>`
- Enum and extension method to fire JavaScript event
### Changed
- Upgrade dependencies: Selenium.WebDriver, Selenium.Support etc.
### Removed
- Custom result classes

## [v1.0.0](https://github.com/maik-hasler/SeleniumSharper/releases/tag/v1.0.0)
**Published:** 19th April 2023
### Added
- `WebElementsConditionBuilder<TSearchContext, TSearchResult>` to build wait conditions for a `ReadOnlyCollection<IWebElement>`
- `WebElementConditionBuilder<TSearchContext, TSearchResult>` to build wait conditions for a `IWebElement`
- `ClassConditionBuilder<TSearchContext, TSearchResult>` to build wait conditions for a `IEquatable<string>`
- Custom result classes `WebElementsVisibilityResult` and `WebElementVisibilityResult`
### Changed
- Changed `Waiter<T>` to `ContextualWait<TSearchContext>`, which supports more generic method chaining
### Removed
- Collection of commonly used selenium wait conditions

## [v1.0.0-preview.0](https://github.com/maik-hasler/SeleniumSharper/releases/tag/v1.0.0-preview.0)
**Published:** 18th April 2023
<br />
**Disclaimer:** This is a pre-release. It was published in order to verify, that the nuget.yml workflow works fine.
### Added
- `Waiter<T>` to wait for a specified condition to be satisfied
- Collection of commonly used selenium wait conditions
- Extension method to create a `Waiter<T>` object from an `ISearchContext`
- Various `IJavaScriptExecutor` extension methods
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using OpenQA.Selenium;

namespace SeleniumSharper;
namespace SeleniumSharper.Conditions;

public class ClassConditionBuilder<TSearchContext, TSearchResult>
public class StringConditionBuilder<TSearchContext, TSearchResult>
where TSearchContext : ISearchContext
where TSearchResult : IEquatable<string>
{
private readonly ContextualWait<TSearchContext> _contextualWait;

private readonly Func<TSearchContext, string> _action;

public ClassConditionBuilder(ContextualWait<TSearchContext> fluentWait, Func<TSearchContext, string> action)
public StringConditionBuilder(ContextualWait<TSearchContext> fluentWait, Func<TSearchContext, string> action)
{
_contextualWait = fluentWait;
_action = action;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using OpenQA.Selenium;

namespace SeleniumSharper;
namespace SeleniumSharper.Conditions;

public class WebElementConditionBuilder<TSearchContext, TSearchResult>
where TSearchContext : ISearchContext
Expand All @@ -16,32 +16,24 @@ public WebElementConditionBuilder(ContextualWait<TSearchContext> fluentWait, Fun
_action = action;
}

public WebElementVisibilityResult IsVisible()
public IWebElement? IsVisible()
{
IWebElement? webElement = null;

try
{
IWebElement? webElement = null;

var isDisplayed = _contextualWait.Wait.Until(ctx =>
_contextualWait.Wait.Until(ctx =>
{
webElement = _action.Invoke(ctx);

return webElement.Displayed;
});

return new WebElementVisibilityResult
{
WebElement = webElement,
IsVisible = isDisplayed
};
return webElement;
}
catch (WebDriverTimeoutException)
{
return new WebElementVisibilityResult
{
WebElement = null,
IsVisible = false
};
return null;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using OpenQA.Selenium;
using SeleniumSharper.Models;
using System.Collections.ObjectModel;

namespace SeleniumSharper;
namespace SeleniumSharper.Conditions;

public sealed class WebElementsConditionBuilder<TSearchContext, TSearchResult>
where TSearchContext : ISearchContext
Expand All @@ -18,32 +17,24 @@ public WebElementsConditionBuilder(ContextualWait<TSearchContext> fluentWait, Fu
_action = action;
}

public WebElementsVisibilityResult AreVisible()
public ReadOnlyCollection<IWebElement>? AreVisible()
{
ReadOnlyCollection<IWebElement>? webElements = null;

try
{
ReadOnlyCollection<IWebElement>? webElements = null;

var areDisplayed = _contextualWait.Wait.Until(ctx =>
_contextualWait.Wait.Until(ctx =>
{
webElements = _action.Invoke(ctx);

return webElements.All(e => e.Displayed);
});

return new WebElementsVisibilityResult
{
WebElements = webElements,
AreDisplayed = areDisplayed
};
return webElements;
}
catch (WebDriverTimeoutException)
{
return new WebElementsVisibilityResult
{
WebElements = null,
AreDisplayed = false
};
return null;
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/ContextualWait.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using SeleniumSharper.Conditions;

namespace SeleniumSharper;

Expand Down Expand Up @@ -27,8 +28,8 @@ public WebElementConditionBuilder<TSearchContext, IWebElement> Until(Func<TSearc
return new WebElementConditionBuilder<TSearchContext, IWebElement>(this, action);
}

public ClassConditionBuilder<TSearchContext, string> Until(Func<TSearchContext, string> action)
public StringConditionBuilder<TSearchContext, string> Until(Func<TSearchContext, string> action)
{
return new ClassConditionBuilder<TSearchContext, string>(this, action);
return new StringConditionBuilder<TSearchContext, string>(this, action);
}
}
11 changes: 11 additions & 0 deletions src/DomEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace SeleniumSharper;

public enum DomEvent
{
Click,
DoubleClick,
MouseDown,
MouseUp,
KeyDown,
KeyUp
}
7 changes: 7 additions & 0 deletions src/JavaScriptExecutorExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,11 @@ public static void Click(this IJavaScriptExecutor executor, IWebElement elementT
{
executor.ExecuteScript("arguments[0].click();", elementToBeClicked);
}

public static void DispatchEvent(this IJavaScriptExecutor executor, IWebElement webElement, DomEvent domEvent)
{
var domEventName = domEvent.ToString().ToLower();

executor.ExecuteScript("[0].dispatchEvent(new Event('[1]'));", webElement, domEventName);
}
}
101 changes: 101 additions & 0 deletions src/Managers/ChromeDriverManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using SeleniumSharper.Managers.Interfaces;
using SeleniumSharper.Managers.Services;
using System.Runtime.InteropServices;

namespace SeleniumSharper.Managers;

public sealed class ChromeDriverManager : IWebDriverManager<ChromeOptions>
{
public IWebDriver Setup()
{
var driverPath = InstallBinary();

var chromeDriverService = ChromeDriverService.CreateDefaultService(driverPath);

return new ChromeDriver(chromeDriverService);
}

public IWebDriver Setup(ChromeOptions chromeOptions)
{
var driverPath = InstallBinary();

var chromeDriverService = ChromeDriverService.CreateDefaultService(driverPath);

return new ChromeDriver(chromeDriverService, chromeOptions);
}

private static string GetBinaryName()
{
var suffix = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : string.Empty;

return $"chromedriver{suffix}";
}

private static Uri GetDownloadUrl(string version, string fileName)
{
var url = $"https://chromedriver.storage.googleapis.com/{version}/{fileName}";

return new Uri(url);
}

private static string GetFileName()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
var architectureExtension = RuntimeInformation.ProcessArchitecture == Architecture.Arm64 ? "_arm64" : "64";

return $"chromedriver_mac{architectureExtension}.zip";
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return "chromedriver_linux64.zip";
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return "chromedriver_win32.zip";
}

throw new PlatformNotSupportedException();
}

private static string GetLatestVersion()
{
var url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE";

using var httpClient = new HttpClient();

var response = httpClient.GetStringAsync(url).Result;

return response.Trim();
}

private static string GetBinaryPath(string version)
{
var architecture = Environment.Is64BitOperatingSystem ? "64" : "32";

return Path.Combine(
Directory.GetCurrentDirectory(),
"Binaries",
"Chrome",
version,
architecture,
GetBinaryName());
}

private static string InstallBinary()
{
var version = GetLatestVersion();

var fileName = GetFileName();

var downloadUrl = GetDownloadUrl(version, fileName);

var binaryPath = GetBinaryPath(version);

return WebDriverManagerUtils.InstallBinary(fileName, downloadUrl, binaryPath, GetBinaryName());
}
}
11 changes: 11 additions & 0 deletions src/Managers/Interfaces/IWebDriverManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using OpenQA.Selenium;

namespace SeleniumSharper.Managers.Interfaces;

public interface IWebDriverManager<TOptions>
where TOptions : DriverOptions
{
public IWebDriver Setup();

public IWebDriver Setup(TOptions options);
}
Loading