Skip to content

Commit

Permalink
Merge pull request #288 from Lombiq/issue/OSOE-647
Browse files Browse the repository at this point in the history
OSOE-647: Context extensions and By helpers.
  • Loading branch information
Piedone authored Jun 18, 2023
2 parents 3b2b659 + 38ec58b commit 14e683f
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 8 deletions.
65 changes: 65 additions & 0 deletions Lombiq.Tests.UI/Extensions/BrowserUITestContextExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Lombiq.Tests.UI.Extensions;
using Lombiq.Tests.UI.Services;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using System.Threading.Tasks;

namespace System.Net;

public static class BrowserUITestContextExtensions
{
/// <summary>
/// Gets all cookies from the browser and converts them into .NET <see cref="Cookie"/> instances in a <see
/// cref="CookieContainer"/>. This can be useful if you want to make web requests using <see cref="HttpClient"/>
/// while using the login and other cookies from the browser.
/// </summary>
public static CookieContainer GetCookieContainer(this UITestContext context)
{
var cookieContainer = new CookieContainer();
foreach (var seleniumCookie in context.Driver.Manage().Cookies.AllCookies)
{
var netCookie = new Cookie
{
Domain = seleniumCookie.Domain,
HttpOnly = seleniumCookie.IsHttpOnly,
Name = seleniumCookie.Name,
Path = seleniumCookie.Path,
Secure = seleniumCookie.Secure,
Value = seleniumCookie.Value,
};

if (seleniumCookie.Expiry.HasValue) netCookie.Expires = seleniumCookie.Expiry.Value;

cookieContainer.Add(netCookie);
}

return cookieContainer;
}

[SuppressMessage(
"Security",
"SCS0004: Certificate Validation has been disabled.",
Justification = "Necessary for local testing.")]
[SuppressMessage(
"Security",
"CA5399: HttpClient is created without enabling CheckCertificateRevocationList.",
Justification = "Necessary for local testing.")]
public static async Task<T> FetchWithBrowserContextAsync<T>(
this UITestContext context,
HttpMethod method,
string address,
Func<HttpResponseMessage, Task<T>> processResponseAsync)
{
using var handler = new HttpClientHandler
{
CookieContainer = context.GetCookieContainer(),
ServerCertificateCustomValidationCallback = (_, _, _, _) => true,
};

using var client = new HttpClient(handler);
using var request = new HttpRequestMessage(method, new Uri(context.GetCurrentUri(), address));
using var response = await client.SendAsync(request);

return await processResponseAsync(response);
}
}
37 changes: 29 additions & 8 deletions Lombiq.Tests.UI/Extensions/NavigationUITestContextExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
using Atata;
using Lombiq.HelpfulLibraries.Common.Utilities;
using Lombiq.Tests.UI.Constants;
using Lombiq.Tests.UI.Helpers;
using Lombiq.Tests.UI.Pages;
using Lombiq.Tests.UI.Services;
using Newtonsoft.Json;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using OrchardCore.ContentFields.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace Lombiq.Tests.UI.Extensions;
Expand Down Expand Up @@ -229,26 +235,41 @@ public static bool WaitForPageLoad(this UITestContext context) =>

public static Task SetTaxonomyFieldByIndexAsync(this UITestContext context, string taxonomyId, int index)
{
var baseSelector = StringHelper.CreateInvariant($".tags[data-taxonomy-content-item-id='{taxonomyId}']");
var baseSelector = ByHelper.Css($".tags[data-taxonomy-content-item-id='{taxonomyId}']");
return SetFieldDropdownByIndexAsync(context, baseSelector, index);
}

public static async Task SetContentPickerByDisplayTextAsync(this UITestContext context, string part, string field, string text)
{
var searchUrl = context.Get(ByHelper.GetContentPickerSelector(part, field)).GetAttribute("data-search-url");
var index = await context.FetchWithBrowserContextAsync(
HttpMethod.Get,
searchUrl,
async response =>
{
var json = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<IList<VueMultiselectItemViewModel>>(json);
return result.IndexOf(result.First(item => item.DisplayText == text));
});

await context.SetContentPickerByIndexAsync(part, field, index);
}

public static Task SetContentPickerByIndexAsync(this UITestContext context, string part, string field, int index)
{
var baseSelector = StringHelper.CreateInvariant($"*[data-part='{part}'][data-field='{field}']");
var baseSelector = ByHelper.GetContentPickerSelector(part, field);
return SetFieldDropdownByIndexAsync(context, baseSelector, index);
}

private static async Task SetFieldDropdownByIndexAsync(UITestContext context, string baseSelector, int index)
private static async Task SetFieldDropdownByIndexAsync(UITestContext context, By baseSelector, int index)
{
var byItem =
By.CssSelector(StringHelper.CreateInvariant(
$"{baseSelector} .multiselect__element:nth-child({index + 1}) .multiselect__option"))
var byItem = baseSelector
.Then(ByHelper.Css($".multiselect__element:nth-child({index + 1}) .multiselect__option"))
.Visible();

while (!context.Exists(byItem.Safely()))
{
await context.ClickReliablyOnAsync(By.CssSelector(baseSelector + " .multiselect__select"));
await context.ClickReliablyOnAsync(baseSelector.Then(By.CssSelector(".multiselect__select")));
}

await context.ClickReliablyOnAsync(byItem);
Expand Down
17 changes: 17 additions & 0 deletions Lombiq.Tests.UI/Helpers/ByHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using Newtonsoft.Json;
using OpenQA.Selenium;
using System;
using System.Globalization;
using System.Runtime.CompilerServices;

namespace Lombiq.Tests.UI.Helpers;

Expand Down Expand Up @@ -31,4 +33,19 @@ public static By Text(string innerText, string element = "*") =>
/// </summary>
public static By TextContains(string innerText, string element = "*") =>
By.XPath($"//{element}[contains(., {JsonConvert.SerializeObject(innerText)})]");

/// <summary>
/// Creates a <see langword="string"/> from an interpolated string with the invariant culture. This prevents culture-
/// sensitive formatting of interpolated values.
/// </summary>
public static By Css(this DefaultInterpolatedStringHandler value) =>
By.CssSelector(string.Create(CultureInfo.InvariantCulture, ref value));

/// <summary>
/// Returns a CSS selector that looks up a content picker field.
/// </summary>
/// <param name="part">The name of the content part.</param>
/// <param name="field">The name of the content picker field.</param>
public static By GetContentPickerSelector(string part, string field) =>
Css($"*[data-part='{part}'][data-field='{field}']");
}
1 change: 1 addition & 0 deletions Lombiq.Tests.UI/Lombiq.Tests.UI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
<PackageReference Include="Microsoft.SqlServer.DACFx" Version="161.6319.0-preview" />
<PackageReference Include="Microsoft.SqlServer.SqlManagementObjects" Version="170.8.0" />
<PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1-preview" />
<PackageReference Include="OrchardCore.ContentFields" Version="1.6.0" />
<PackageReference Include="OrchardCore.Logging.NLog" Version="1.6.0" />
<PackageReference Include="OrchardCore.Abstractions" Version="1.6.0" />
<PackageReference Include="OrchardCore.Recipes.Core" Version="1.6.0" />
Expand Down

0 comments on commit 14e683f

Please sign in to comment.