Skip to content

Commit f8e9fc2

Browse files
committed
Resolve #277 - Correct reports for OpenUrl
1 parent af8e636 commit f8e9fc2

5 files changed

Lines changed: 147 additions & 7 deletions

File tree

CSF.Screenplay.Selenium/NamedUri.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,32 @@ public sealed class NamedUri : IHasName
2727
/// </summary>
2828
public Uri Uri { get; }
2929

30+
/// <summary>
31+
/// Gets a copy of the current named URI, except 'rebased' using the specified base URI.
32+
/// </summary>
33+
/// <remarks>
34+
/// <para>
35+
/// If the current <see cref="Uri"/> is <see cref="UriKind.Absolute"/> then this method has not effect and the named URI which is
36+
/// returned is the unmodified current instance.
37+
/// </para>
38+
/// <para>
39+
/// If the current Uri is not absolute, then the specified base URI is prepended to the current URI, serving as a base.
40+
/// The new URI is then returned from this method. Note that this method will never result in the current instance being
41+
/// mutated, at most it will only return a copy of the current instance, which has the newly-rebased URI.
42+
/// </para>
43+
/// </remarks>
44+
/// <param name="baseUri">A new base URI</param>
45+
/// <returns>A URI which might have been rebased onto the new base URI</returns>
46+
public NamedUri RebaseTo(Uri baseUri)
47+
{
48+
if(baseUri == null) throw new ArgumentNullException(nameof(baseUri));
49+
50+
if (Uri.IsAbsoluteUri) return this;
51+
52+
var rebased = new Uri(baseUri, Uri);
53+
return new NamedUri(rebased, Name);
54+
}
55+
3056
/// <summary>
3157
/// Initializes a new instance of the <see cref="NamedUri"/> class.
3258
/// </summary>
@@ -63,6 +89,6 @@ public NamedUri(string uri, string name = null)
6389
/// </summary>
6490
/// <param name="uri">The URI to convert.</param>
6591
/// <returns>A new <see cref="NamedUri"/> instance.</returns>
66-
public static implicit operator NamedUri(string uri) => uri is null ? null : new NamedUri(new Uri(uri, UriKind.RelativeOrAbsolute));
92+
public static implicit operator NamedUri(string uri) => uri is null ? null : new NamedUri(uri);
6793
}
6894
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
using System;
3+
4+
namespace CSF.Screenplay.Selenium
5+
{
6+
/// <summary>
7+
/// Extension methods for <see cref="NamedUri"/>.
8+
/// </summary>
9+
public static class NamedUriExtensions
10+
{
11+
/// <summary>
12+
/// Gets a copy of the current named URI, except 'rebased' using the specified base URI.
13+
/// </summary>
14+
/// <remarks>
15+
/// <para>
16+
/// If the current <see cref="Uri"/> is <see cref="UriKind.Absolute"/> then this method has not effect and the named URI which is
17+
/// returned is the unmodified current instance.
18+
/// </para>
19+
/// <para>
20+
/// If the current Uri is not absolute, then the specified base URI is prepended to the current URI, serving as a base.
21+
/// The new URI is then returned from this method. Note that this method will never result in the current instance being
22+
/// mutated, at most it will only return a copy of the current instance, which has the newly-rebased URI.
23+
/// </para>
24+
/// </remarks>
25+
/// <param name="namedUri">The named URI to rebase</param>
26+
/// <param name="baseUri">A new base URI</param>
27+
/// <returns>A URI which might have been rebased onto the new base URI</returns>
28+
public static NamedUri RebaseTo(this NamedUri namedUri, string baseUri)
29+
{
30+
if(namedUri == null) throw new ArgumentNullException(nameof(namedUri));
31+
if(baseUri == null) throw new ArgumentNullException(nameof(baseUri));
32+
return namedUri.RebaseTo(new Uri(baseUri, UriKind.Absolute));
33+
}
34+
}
35+
36+
}

CSF.Screenplay.Selenium/Tasks/OpenUrlRespectingBase.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,11 @@ public class OpenUrlRespectingBase : IPerformable, ICanReport
2323
/// <inheritdoc/>
2424
public ValueTask PerformAsAsync(ICanPerform actor, CancellationToken cancellationToken = default)
2525
{
26-
if(uri.Uri.IsAbsoluteUri)
27-
return actor.PerformAsync(new OpenUrl(uri.Uri), cancellationToken);
28-
2926
if(!actor.TryGetAbility<UseABaseUri>(out var ability))
30-
return actor.PerformAsync(new OpenUrl(uri.Uri), cancellationToken);
27+
return actor.PerformAsync(new OpenUrl(uri), cancellationToken);
3128

32-
var absoluteUri = new Uri(ability.BaseUri, uri.Uri);
33-
return actor.PerformAsync(new OpenUrl(absoluteUri), cancellationToken);
29+
var rebased = uri.RebaseTo(ability.BaseUri);
30+
return actor.PerformAsync(new OpenUrl(rebased), cancellationToken);
3431
}
3532

3633
/// <inheritdoc/>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace CSF.Screenplay.Selenium;
2+
3+
[TestFixture, Parallelizable]
4+
public class NamedUriTests
5+
{
6+
[Test]
7+
public void RebaseToShouldReturnARebasedUriIfItIsNotAbsolute()
8+
{
9+
var sut = new NamedUri("test.html", "name");
10+
var rebased = sut.RebaseTo("https://example.com");
11+
Assert.That(rebased.Uri.ToString(), Is.EqualTo("https://example.com/test.html"));
12+
}
13+
14+
[Test]
15+
public void RebaseToShouldNotAlterTheUriIfItIsAbsolute()
16+
{
17+
var sut = new NamedUri("https://foobar.example.com/test.html", "name");
18+
var rebased = sut.RebaseTo("https://example.com");
19+
Assert.That(rebased.Uri.ToString(), Is.EqualTo("https://foobar.example.com/test.html"));
20+
}
21+
22+
[Test]
23+
public void RebaseToShouldReturnAUriWithTheSameName()
24+
{
25+
var sut = new NamedUri("test.html", "name");
26+
var rebased = sut.RebaseTo("https://example.com");
27+
Assert.That(rebased.Name, Is.EqualTo("name"));
28+
}
29+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using CSF.Extensions.WebDriver;
3+
using CSF.Extensions.WebDriver.Factories;
4+
using CSF.Screenplay.Actors;
5+
using CSF.Screenplay.Reporting;
6+
using CSF.Screenplay.Selenium.Actions;
7+
using Microsoft.Extensions.DependencyInjection;
8+
using Moq;
9+
using OpenQA.Selenium;
10+
11+
namespace CSF.Screenplay.Selenium.Tasks;
12+
13+
[TestFixture, Parallelizable]
14+
public class OpenUrlRespectingBaseTests
15+
{
16+
[Test, AutoMoqData]
17+
public async Task TheActionCreatedByThisTaskShouldContainTheCorrectReport(IWebDriver driver, DriverOptions options)
18+
{
19+
var actor = new Actor("Anthony", Guid.NewGuid());
20+
IPerformable? performable = null;
21+
22+
void OnPerform(object? sender, PerformableEventArgs ev) => performable = (IPerformable)ev.Performable;
23+
24+
var namedUri = new NamedUri("test.html", "the test page");
25+
var baseUri = "https://example.com";
26+
actor.IsAbleTo(new UseABaseUri(new Uri(baseUri, UriKind.Absolute)));
27+
actor.IsAbleTo(new BrowseTheWeb(Mock.Of<IGetsWebDriver>(x => x.GetDefaultWebDriver(It.IsAny<Action<DriverOptions>>()) == new WebDriverAndOptions(driver, options))));
28+
var sut = new OpenUrlRespectingBase(namedUri);
29+
var valueFormatterProvider = new ValueFormatterProvider(new ServiceCollection().AddTransient<ToStringFormatter>().BuildServiceProvider(),
30+
new ValueFormatterRegistry { typeof(ToStringFormatter) });
31+
32+
var formatter = new ReportFragmentFormatter(new ReportFormatCreator(), valueFormatterProvider);
33+
34+
actor.EndPerformable += OnPerform;
35+
try
36+
{
37+
await sut.PerformAsAsync(actor);
38+
39+
Assert.Multiple(() =>
40+
{
41+
Assert.That(performable, Is.InstanceOf<OpenUrl>(), "Performable is correct type");
42+
Assert.That(((OpenUrl) performable!).GetReportFragment(actor, formatter).ToString(),
43+
Is.EqualTo("Anthony opens their browser at the test page: https://example.com/test.html"),
44+
"The report is correct");
45+
});
46+
}
47+
finally
48+
{
49+
actor.EndPerformable -= OnPerform;
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)