Skip to content

Commit

Permalink
playwright playground
Browse files Browse the repository at this point in the history
  • Loading branch information
fakefeik committed Jan 15, 2024
1 parent 008fe98 commit 577a3fc
Show file tree
Hide file tree
Showing 17 changed files with 436 additions and 9 deletions.
1 change: 1 addition & 0 deletions DbViewer.Tests/DbViewer.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.2.0" />
<PackageReference Include="Kontur.ReactUI.SeleniumTesting" Version="3.6.0" />
<PackageReference Include="Microsoft.Playwright" Version="1.40.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
Expand Down
60 changes: 60 additions & 0 deletions DbViewer.Tests/FrontTests/AutoFill/PwAutoFill.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Linq;
using System.Reflection;

using Microsoft.Playwright;

using SkbKontur.DbViewer.Tests.FrontTests.Playwright;

namespace SkbKontur.DbViewer.Tests.FrontTests.AutoFill
{
public class PwAutoFill
{
public static TPage InitializePage<TPage>(IPage page)
where TPage : PwPageBase
{
var newPage = (TPage)Activator.CreateInstance(typeof(TPage), page)!;
InitializeControls(newPage, newPage.Page, null);
return newPage;
}

public static void InitializeControls(object instance, IPage page, ILocator? parent)
{
var properties = instance
.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.CanWrite && typeof(PwControlBase).IsAssignableFrom(p.PropertyType) && !p.GetCustomAttributes<SkipAutoFillAttribute>().Any());

foreach (var property in properties)
{
var locator = LocatorForProperty(property, page, parent);
var value = Activator.CreateInstance(property.PropertyType, locator)!;
InitializeControls(value, page, locator);
property.SetValue(instance, value);
}
}

public static ILocator LocatorForProperty(PropertyInfo property, IPage page, ILocator? parent)
{
var selector = property
.GetCustomAttributes<SelectorAttribute>()
.Select(x => x.Selector.ToString())
.FirstOrDefault();

if (string.IsNullOrEmpty(selector))
return GetByTestId(page, parent, property.Name);

var selectors = selector.Split(" ", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
return selectors
.Aggregate(
parent,
(current, s) => s.StartsWith("##")
? GetByTestId(page, current, s[2..])
: GetLocator(page, current, s)
)!;
}

private static ILocator GetByTestId(IPage page, ILocator? parent, string tid) => parent == null ? page.GetByTestId(tid) : parent.GetByTestId(tid);
private static ILocator GetLocator(IPage page, ILocator? parent, string loc) => parent == null ? page.Locator(loc) : parent.Locator(loc);
}
}
38 changes: 31 additions & 7 deletions DbViewer.Tests/FrontTests/BusinessObjectsSearchTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
using NUnit.Framework;
using System.Threading.Tasks;

using Microsoft.Playwright;

using NUnit.Framework;

using SkbKontur.DbViewer.Tests.FrontTests.Helpers;
using SkbKontur.DbViewer.Tests.FrontTests.Pages;
using SkbKontur.DbViewer.Tests.FrontTests.Playwright;

namespace SkbKontur.DbViewer.Tests.FrontTests
{
Expand Down Expand Up @@ -75,14 +80,33 @@ public void TestSearchLink()
/// Проверяем, что ссылка ведет туда, куда нам нужно
/// </summary>
[Test]
public void TestLinkShouldReferToShowTablePage()
public async Task TestLinkShouldReferToShowTablePage()
{
using var browser = new BrowserForTests();
await using var browser = new Browser();

var businessObjectsPage = browser.SwitchTo<BusinessObjectsPage>();
var link = businessObjectsPage.FindBusinessObjectLink("CQL Objects", "DocumentPrintingInfo");
var page = link.ClickAndGoTo<BusinessObjectTablePage>();
page.Header.WaitText("DocumentPrintingInfo");
var businessObjectsPage = await browser.SwitchTo<PwBusinessObjectsPage>();
var loc = businessObjectsPage.ObjectGroups.Locator.Filter(new LocatorFilterOptions
{
Has = businessObjectsPage.ObjectGroups.Locator.Page.Locator("css=body").GetByTestId("Name").GetByText("CQL Objects")
});
var el = await loc.AllAsync();

var group0 = businessObjectsPage.ObjectGroups[0];
await group0.Name.Expect().ToHaveTextAsync("Business Array Objects");
await group0.IndexedLabel.Expect().Not.ToBeVisibleAsync();

var group1 = businessObjectsPage.ObjectGroups[1];
await group1.Name.Expect().ToHaveTextAsync("CQL Objects");
await group1.IndexedLabel.Expect().ToHaveTextAsync("indexed");

var group2 = businessObjectsPage.ObjectGroups[2];
await group2.Name.Expect().ToHaveTextAsync("CQL Paged Objects");
await group2.IndexedLabel.Expect().ToHaveTextAsync("indexed");

var link = await businessObjectsPage.FindBusinessObjectLink("CQL Objects", "DocumentPrintingInfo");
await link.Locator.ClickAsync();
// var page = link.ClickAndGoTo<BusinessObjectTablePage>();
// page.Header.WaitText("DocumentPrintingInfo");
}
}
}
21 changes: 21 additions & 0 deletions DbViewer.Tests/FrontTests/Controls/BusinessObjectGroup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Microsoft.Playwright;

using SkbKontur.DbViewer.Tests.FrontTests.AutoFill;
using SkbKontur.DbViewer.Tests.FrontTests.Playwright;

namespace SkbKontur.DbViewer.Tests.FrontTests.Controls
{
public class BusinessObjectGroup : PwControlBase
{
public BusinessObjectGroup(ILocator locator)
: base(locator)
{
}

public PwLabel Name { get; set; }
public PwLabel IndexedLabel { get; set; }

[Selector("##ObjectsList ##ObjectItem")]
public PwControlList<BusinessObjectItem> ObjectsList { get; set; }
}
}
16 changes: 16 additions & 0 deletions DbViewer.Tests/FrontTests/Controls/BusinessObjectItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Microsoft.Playwright;

using SkbKontur.DbViewer.Tests.FrontTests.Playwright;

namespace SkbKontur.DbViewer.Tests.FrontTests.Controls
{
public class BusinessObjectItem : PwControlBase
{
public BusinessObjectItem(ILocator locator)
: base(locator)
{
}

public PwLink ObjectLink { get; set; }
}
}
37 changes: 37 additions & 0 deletions DbViewer.Tests/FrontTests/Pages/PwBusinessObjectsPage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Threading.Tasks;

using Microsoft.Playwright;

using SkbKontur.DbViewer.Tests.FrontTests.AutoFill;
using SkbKontur.DbViewer.Tests.FrontTests.Helpers;
using SkbKontur.DbViewer.Tests.FrontTests.Playwright;

using SKBKontur.SeleniumTesting.Controls;

namespace SkbKontur.DbViewer.Tests.FrontTests.Pages
{
[PageRoute("BusinessObjects")]
public class PwBusinessObjectsPage : PwPageBase
{
public PwBusinessObjectsPage(IPage page)
: base(page)
{
}

[Selector("##ObjectGroups ##ObjectGroup")]
public PwControlList<Controls.BusinessObjectGroup> ObjectGroups { get; set; }

public async Task<PwLink> FindBusinessObjectLink(string groupName, string objectName)
{
var groups = ObjectGroups.Where(x => x.Name.Locator.GetByText(groupName));
await groups.Locator.HighlightAsync();
await groups.Expect().ToHaveCountAsync(1);

var objects = groups[0].ObjectsList.Where(x => x.ObjectLink.Locator.GetByText(objectName));
await objects.Locator.HighlightAsync();
await objects.Expect().ToHaveCountAsync(1);

return objects[0].ObjectLink;
}
}
}
82 changes: 82 additions & 0 deletions DbViewer.Tests/FrontTests/Playwright/Browser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using System.Reflection;
using System.Threading.Tasks;

using Microsoft.Playwright;

using SkbKontur.DbViewer.Tests.FrontTests.AutoFill;
using SkbKontur.DbViewer.Tests.FrontTests.Helpers;

namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
{
public class Browser : IAsyncDisposable
{
public async Task<TPage> SwitchToUri<TPage>(Uri uri)
where TPage : PwPageBase
{
await Page.GotoAsync(MakeAbsolute(uri).ToString());
return PwAutoFill.InitializePage<TPage>(Page);
}

public ValueTask DisposeAsync()
{
return page != null
? new ValueTask(page.CloseAsync())
: ValueTask.CompletedTask;
}

private Uri MakeAbsolute(Uri uri)
{
return uri.IsAbsoluteUri ? uri : new Uri(new Uri(baseUrl), uri);
}

public IPage Page
{
get
{
if (page != null)
return page;

return page = PlaywrightSetup.Browser.NewPageAsync().GetAwaiter().GetResult();
}
}

private const string baseUrl = "http://localhost:5000/";

private IPage? page;
}

public static class AttributeNavigationExtensions
{
public static ILocatorAssertions Expect(this PwControlBase controlBase)
{
return Assertions.Expect(controlBase.Locator);
}

public static Task<TPage> SwitchTo<TPage>(this Browser browser, params string[] templateParameters)
where TPage : PwPageBase
{
return browser.SwitchToUri<TPage>(new Uri(GetPageRoute<TPage>(templateParameters), UriKind.Relative));
}

private static string GetPageRoute<TPage>(string[] templateParameters)
{
foreach (var attribute in typeof(TPage).GetCustomAttributes<PageRouteAttribute>())
{
var route = attribute.Route;
if (templateParameters.Length == 0 && !route.Contains("{id}") && !route.Contains("{scopeId}"))
return route;
if (templateParameters.Length == 1 && route.Contains("{id}") && !route.Contains("{scopeId}"))
return route.Replace("{id}", templateParameters[0]);
if (templateParameters.Length == 2 && route.Contains("{id}") && route.Contains("{scopeId}"))
return route.Replace("{scopeId}", templateParameters[0]).Replace("{id}", templateParameters[1]);
if (templateParameters.Length == 3 && route.Contains("{scopeId}") && route.Contains("{id}") && route.Contains("{versionId}"))
return route
.Replace("{scopeId}", templateParameters[0])
.Replace("{id}", templateParameters[1])
.Replace("{versionId}", templateParameters[2]);
}
throw new InvalidOperationException($"Corresponding PageRoute attribute with {templateParameters.Length} arguments not found for {typeof(TPage).Name}");
}
}
}
17 changes: 17 additions & 0 deletions DbViewer.Tests/FrontTests/Playwright/PwControlBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using JetBrains.Annotations;

using Microsoft.Playwright;

namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
{
[MeansImplicitUse(ImplicitUseTargetFlags.Members | ImplicitUseTargetFlags.WithInheritors)]
public class PwControlBase
{
public PwControlBase(ILocator locator)
{
Locator = locator;
}

public ILocator Locator { get; }
}
}
46 changes: 46 additions & 0 deletions DbViewer.Tests/FrontTests/Playwright/PwControlList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Linq.Expressions;

using Microsoft.Playwright;

using SkbKontur.DbViewer.Tests.FrontTests.AutoFill;

namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
{
public class PwControlList<TControl> : PwControlBase
where TControl : PwControlBase
{
public PwControlList(ILocator locator)
: base(locator)
{
}

public PwControlList<T> Select<T>(Expression<Func<TControl, T>> selector)
where T : PwControlBase
{
return new PwControlList<T>(Locator);
}

public PwControlList<TControl> Where(Func<TControl, ILocator> predicate)
{
var dummyControl = (TControl)Activator.CreateInstance(typeof(TControl), new object?[] {null})!;
PwAutoFill.InitializeControls(dummyControl, Locator.Page, null);

return new PwControlList<TControl>(Locator.Filter(new LocatorFilterOptions
{
Has = predicate(dummyControl)
}));
}

public TControl this[int index]
{
get
{
var controlLocator = Locator.Nth(index);
var control = (TControl)Activator.CreateInstance(typeof(TControl), controlLocator)!;
PwAutoFill.InitializeControls(control, Locator.Page, controlLocator);
return control;
}
}
}
}
12 changes: 12 additions & 0 deletions DbViewer.Tests/FrontTests/Playwright/PwLabel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.Playwright;

namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
{
public class PwLabel : PwControlBase
{
public PwLabel(ILocator locator)
: base(locator)
{
}
}
}
12 changes: 12 additions & 0 deletions DbViewer.Tests/FrontTests/Playwright/PwLink.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.Playwright;

namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
{
public class PwLink : PwControlBase
{
public PwLink(ILocator locator)
: base(locator)
{
}
}
}
Loading

0 comments on commit 577a3fc

Please sign in to comment.