Skip to content

Commit

Permalink
playwright playground
Browse files Browse the repository at this point in the history
  • Loading branch information
fakefeik committed Jan 17, 2024
1 parent 6b3d502 commit 2596311
Show file tree
Hide file tree
Showing 33 changed files with 1,028 additions and 125 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ jobs:
- name: Pack dotnet
run: dotnet pack --no-build --configuration Release ./DbViewer.sln

- name: Install Playwright
run: pwsh ./DbViewer.Tests/bin/Release/net6.0/playwright.ps1 install chromium

- name: Build front
run: yarn --cwd db-viewer-ui build

Expand Down
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);
}
}
97 changes: 52 additions & 45 deletions DbViewer.Tests/FrontTests/BusinessObjectsChangeValuesTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Threading.Tasks;

using Cassandra.Data.Linq;

Expand All @@ -16,6 +17,7 @@
using SkbKontur.DbViewer.TestApi.Impl.Document;
using SkbKontur.DbViewer.Tests.FrontTests.Helpers;
using SkbKontur.DbViewer.Tests.FrontTests.Pages;
using SkbKontur.DbViewer.Tests.FrontTests.Playwright;

namespace SkbKontur.DbViewer.Tests.FrontTests
{
Expand All @@ -33,38 +35,42 @@ public BusinessObjectsChangeValuesTest(string documentName)
/// Проверяем, что заданные значения сохраняются
/// </summary>
[Test]
public void TestChangeOrganizationName()
public async Task TestChangeOrganizationName()
{
var documentId = CreateDocument(documentName);

using var browser = new BrowserForTests();
var businessObjectEditingPage = browser.LoginAsSuperUser().SwitchTo<BusinessObjectDetailsPage>(documentName, $"Id={documentId}");
await using var browser = new Browser();

var filledNumberRow = businessObjectEditingPage.RootAccordion.FindField("DocumentNumber");
filledNumberRow.FieldValue.WaitText("123");
filledNumberRow.Edit.Click();
filledNumberRow.FieldValue.Input.ClearAndInputText("2qwe123QWE2");
filledNumberRow.Save.Click();
filledNumberRow.FieldValue.WaitText("2qwe123QWE2");
var adminBrowser = await browser.LoginAsSuperUser();
var businessObjectEditingPage = await adminBrowser.SwitchTo<PwBusinessObjectDetailsPage>(documentName, $"Id={documentId}");

browser.WebDriver.Navigate().Refresh();
var filledNumberRow = businessObjectEditingPage.RootAccordion.FindField("DocumentNumber");
await filledNumberRow.FieldValue.WaitText("123");
await filledNumberRow.Edit.Click();
await filledNumberRow.FieldValue.Input.ClearAndInputText("2qwe123QWE2");
await filledNumberRow.Key.Click();
await Task.Delay(1000);
await filledNumberRow.Save.Click();
await filledNumberRow.FieldValue.WaitText("2qwe123QWE2");

await businessObjectEditingPage.Page.ReloadAsync();
filledNumberRow = businessObjectEditingPage.RootAccordion.FindField("DocumentNumber");
filledNumberRow.FieldValue.WaitText("2qwe123QWE2");
await filledNumberRow.FieldValue.WaitText("2qwe123QWE2");

GetDocument(documentName, documentId).DocumentNumber.Should().Be("2qwe123QWE2");

businessObjectEditingPage.RootAccordion.FindAccordionToggle("DocumentContent").ToggleButton.Click();
await businessObjectEditingPage.RootAccordion.FindAccordionToggle("DocumentContent").ToggleButton.Click();
var unfilledNumberRow = businessObjectEditingPage.RootAccordion.FindField("DocumentContent_OrdersNumber");
unfilledNumberRow.FieldValue.WaitText("null");
unfilledNumberRow.Edit.Click();
unfilledNumberRow.FieldValue.Input.ClearAndInputText("123");
unfilledNumberRow.Save.Click();
unfilledNumberRow.FieldValue.WaitText("123");

browser.WebDriver.Navigate().Refresh();
businessObjectEditingPage.RootAccordion.FindAccordionToggle("DocumentContent").ToggleButton.Click();
await unfilledNumberRow.FieldValue.WaitText("null");
await unfilledNumberRow.Edit.Click();
await unfilledNumberRow.FieldValue.Input.ClearAndInputText("123");
await unfilledNumberRow.Save.Click();
await unfilledNumberRow.FieldValue.WaitText("123");

await businessObjectEditingPage.Page.ReloadAsync();
await businessObjectEditingPage.RootAccordion.FindAccordionToggle("DocumentContent").ToggleButton.Click();
unfilledNumberRow = businessObjectEditingPage.RootAccordion.FindField("DocumentContent_OrdersNumber");
unfilledNumberRow.FieldValue.WaitText("123");
await unfilledNumberRow.FieldValue.WaitText("123");

GetDocument(documentName, documentId).DocumentContent.OrdersNumber.Should().Be("123");
}
Expand All @@ -74,46 +80,47 @@ public void TestChangeOrganizationName()
/// Проверяем, что заданные значения сохраняются
/// </summary>
[Test]
public void TestChangeDocumentDates()
public async Task TestChangeDocumentDates()
{
var documentId = CreateDocument(documentName);

using var browser = new BrowserForTests();
var businessObjectEditingPage = browser.LoginAsSuperUser().SwitchTo<BusinessObjectDetailsPage>(documentName, $"Id={documentId}");
await using var browser = new Browser();
var adminBrowser = await browser.LoginAsSuperUser();
var businessObjectEditingPage = await adminBrowser.SwitchTo<PwBusinessObjectDetailsPage>(documentName, $"Id={documentId}");

var filledDateRow = businessObjectEditingPage.RootAccordion.FindField("DocumentDate");
filledDateRow.FieldValue.WaitTextContains("2014-12-11");
filledDateRow.Edit.Click();
await filledDateRow.FieldValue.WaitTextContains("2014-12-11");
await filledDateRow.Edit.Click();

var expectedOffset = documentName == "CqlDocument" ? TimeSpan.Zero : DateTimeOffset.Now.Offset;
var expectedOffsetStr = $"+{expectedOffset:hh':'mm}";
filledDateRow.FieldValue.Date.ClearAndInputText("13.12.2014");
filledDateRow.FieldValue.Time.ClearAndInputText("10:18:13.567");
filledDateRow.FieldValue.TimeOffsetLabel.WaitText(expectedOffsetStr);
filledDateRow.Save.Click();
await filledDateRow.FieldValue.Date.ClearAndInputText("13.12.2014");
await filledDateRow.FieldValue.Time.ClearAndInputText("10:18:13.567");
await filledDateRow.FieldValue.TimeOffsetLabel.WaitText(expectedOffsetStr);
await filledDateRow.Save.Click();
var expectedStr = $"2014-12-13T10:18:13.567{expectedOffsetStr}";
filledDateRow.FieldValue.WaitTextContains(expectedStr);
await filledDateRow.FieldValue.WaitTextContains(expectedStr);

browser.WebDriver.Navigate().Refresh();
await businessObjectEditingPage.Page.ReloadAsync();
filledDateRow = businessObjectEditingPage.RootAccordion.FindField("DocumentDate");
filledDateRow.FieldValue.WaitTextContains(expectedStr);
await filledDateRow.FieldValue.WaitTextContains(expectedStr);

GetDocument(documentName, documentId).DocumentDate.Should().Be(new DateTimeOffset(2014, 12, 13, 10, 18, 13, 567, expectedOffset));

businessObjectEditingPage.RootAccordion.FindAccordionToggle("DocumentContent").ToggleButton.Click();
await businessObjectEditingPage.RootAccordion.FindAccordionToggle("DocumentContent").ToggleButton.Click();
var unfilledDateRow = businessObjectEditingPage.RootAccordion.FindField("DocumentContent_DeliveryDate");
unfilledDateRow.FieldValue.WaitText("null");
unfilledDateRow.Edit.Click();
unfilledDateRow.FieldValue.Date.ClearAndInputText("14.12.2014");
unfilledDateRow.FieldValue.Time.ClearAndInputText("20:19");
unfilledDateRow.FieldValue.TimeZoneSelect.SelectValueByText("UTC");
unfilledDateRow.Save.Click();
unfilledDateRow.FieldValue.WaitText("2014-12-14T20:19:00Z");

browser.WebDriver.Navigate().Refresh();
businessObjectEditingPage.RootAccordion.FindAccordionToggle("DocumentContent").ToggleButton.Click();
await unfilledDateRow.FieldValue.WaitText("null");
await unfilledDateRow.Edit.Click();
await unfilledDateRow.FieldValue.Date.ClearAndInputText("14.12.2014");
await unfilledDateRow.FieldValue.Time.ClearAndInputText("20:19");
await unfilledDateRow.FieldValue.TimeZoneSelect.SelectValueByText("UTC");
await unfilledDateRow.Save.Click();
await unfilledDateRow.FieldValue.WaitText("2014-12-14T20:19:00Z");

await businessObjectEditingPage.Page.ReloadAsync();
await businessObjectEditingPage.RootAccordion.FindAccordionToggle("DocumentContent").ToggleButton.Click();
unfilledDateRow = businessObjectEditingPage.RootAccordion.FindField("DocumentContent_DeliveryDate");
unfilledDateRow.FieldValue.WaitText("2014-12-14T20:19:00Z");
await unfilledDateRow.FieldValue.WaitText("2014-12-14T20:19:00Z");

GetDocument(documentName, documentId).DocumentContent.DeliveryDate.Should().Be(new DateTime(2014, 12, 14, 20, 19, 00, 00, DateTimeKind.Utc));
}
Expand Down
80 changes: 44 additions & 36 deletions DbViewer.Tests/FrontTests/BusinessObjectsDeleteTest.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using NUnit.Framework;

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

using ConfirmDeleteObjectModal = SkbKontur.DbViewer.Tests.FrontTests.Controls.ConfirmDeleteObjectModal;

namespace SkbKontur.DbViewer.Tests.FrontTests
{
Expand All @@ -16,20 +19,21 @@ public class BusinessObjectsDeleteTest
/// Проверяем, что кнопка с удалением бизнес объекта на странице с таблицей доступна только с SuperUserAccessLevel.God
/// </summary>
[Test]
public void DeleteViaSearchPageRequiresGodAccess()
public async Task DeleteViaSearchPageRequiresGodAccess()
{
var ftpUser = CreateFtpUser();

using var browser = new BrowserForTests();
var businessObjectPage = browser.SwitchTo<BusinessObjectTablePage>("FtpUser");
await using var browser = new Browser();
var businessObjectPage = await browser.SwitchTo<PwBusinessObjectTablePage>("FtpUser");

businessObjectPage.OpenFilter.Click();
businessObjectPage.FilterModal.GetFilter("Login").Input.ClearAndInputText(ftpUser.Login);
businessObjectPage.FilterModal.Apply.Click();
await businessObjectPage.OpenFilter.Click();
var filter = await businessObjectPage.FilterModal.GetFilter("Login");
await filter.Input.ClearAndInputText(ftpUser.Login);
await businessObjectPage.FilterModal.Apply.Click();

businessObjectPage = browser.RefreshUntil(businessObjectPage, x => x.BusinessObjectItems.IsPresent.Get());
businessObjectPage.BusinessObjectItems.WaitCount(1);
businessObjectPage.BusinessObjectItems[0].Delete.IsPresent.Wait().That(Is.False, "Delete link should only be present for gods");
businessObjectPage = await browser.RefreshUntil(businessObjectPage, x => x.BusinessObjectItems.Locator.IsVisibleAsync());
await businessObjectPage.BusinessObjectItems.WaitCount(1);
await businessObjectPage.BusinessObjectItems[0].Delete.WaitAbsence();
}

/// <summary>
Expand All @@ -39,24 +43,27 @@ public void DeleteViaSearchPageRequiresGodAccess()
/// <param name="confirmDeletion"></param>
[TestCase(true)]
[TestCase(false)]
public void DeleteViaSearchPage(bool confirmDeletion)
public async Task DeleteViaSearchPage(bool confirmDeletion)
{
var ftpUser = CreateFtpUser();

using var browser = new BrowserForTests();
var businessObjectPage = browser.LoginAsSuperUser().SwitchTo<BusinessObjectTablePage>("FtpUser");
await using var browser = new Browser();

var adminBrowser = await browser.LoginAsSuperUser();
var businessObjectPage = await adminBrowser.SwitchTo<PwBusinessObjectTablePage>("FtpUser");

businessObjectPage.OpenFilter.Click();
businessObjectPage.FilterModal.GetFilter("Login").Input.ClearAndInputText(ftpUser.Login);
businessObjectPage.FilterModal.Apply.Click();
await businessObjectPage.OpenFilter.Click();
var filter = await businessObjectPage.FilterModal.GetFilter("Login");
await filter.Input.ClearAndInputText(ftpUser.Login);
await businessObjectPage.FilterModal.Apply.Click();

businessObjectPage = browser.RefreshUntil(businessObjectPage, x => x.BusinessObjectItems.IsPresent.Get());
businessObjectPage.BusinessObjectItems.WaitCount(1);
businessObjectPage.BusinessObjectItems[0].Delete.Click();
ConfirmDeletion(businessObjectPage.ConfirmDeleteObjectModal, confirmDeletion);
businessObjectPage = await browser.RefreshUntil(businessObjectPage, x => x.BusinessObjectItems.Locator.IsVisibleAsync());
await businessObjectPage.BusinessObjectItems.WaitCount(1);
await businessObjectPage.BusinessObjectItems[0].Delete.Click();
await ConfirmDeletion(businessObjectPage.ConfirmDeleteObjectModal, confirmDeletion);

if (confirmDeletion)
businessObjectPage.BusinessObjectItems.WaitAbsence();
await businessObjectPage.BusinessObjectItems.WaitAbsence();

AssertFtpUserExistence(ftpUser.Id, confirmDeletion);
}
Expand All @@ -65,13 +72,13 @@ public void DeleteViaSearchPage(bool confirmDeletion)
/// Проверяем, что кнопка с удалением бизнес объекта на странице с конкретным объектом доступна только с SuperUserAccessLevel.God
/// </summary>
[Test]
public void DeleteViaDetailsPageRequiresGodAccess()
public async Task DeleteViaDetailsPageRequiresGodAccess()
{
var ftpUser = CreateFtpUser();

using var browser = new BrowserForTests();
var detailsPage = browser.SwitchTo<BusinessObjectDetailsPage>("FtpUser", $"Id={ftpUser.Id}");
detailsPage.Delete.IsPresent.Wait().That(Is.False, "Delete link should only be present for gods");
await using var browser = new Browser();
var detailsPage = await browser.SwitchTo<PwBusinessObjectDetailsPage>("FtpUser", $"Id={ftpUser.Id}");
await detailsPage.Delete.WaitAbsence();
}

/// <summary>
Expand All @@ -81,27 +88,28 @@ public void DeleteViaDetailsPageRequiresGodAccess()
/// <param name="confirmDeletion"></param>
[TestCase(true)]
[TestCase(false)]
public void DeleteViaDetailsPage(bool confirmDeletion)
public async Task DeleteViaDetailsPage(bool confirmDeletion)
{
var ftpUser = CreateFtpUser();

using var browser = new BrowserForTests();
var detailsPage = browser.LoginAsSuperUser().SwitchTo<BusinessObjectDetailsPage>("FtpUser", $"Id={ftpUser.Id}");
detailsPage.Delete.Click();
ConfirmDeletion(detailsPage.ConfirmDeleteObjectModal, confirmDeletion);
await using var browser = new Browser();

var adminBrowser = await browser.LoginAsSuperUser();
var detailsPage = await adminBrowser.SwitchTo<PwBusinessObjectDetailsPage>("FtpUser", $"Id={ftpUser.Id}");
await detailsPage.Delete.Click();
await ConfirmDeletion(detailsPage.ConfirmDeleteObjectModal, confirmDeletion);

if (confirmDeletion)
detailsPage.GoTo<BusinessObjectTablePage>();
detailsPage.GoTo<PwBusinessObjectTablePage>();

AssertFtpUserExistence(ftpUser.Id, confirmDeletion);
}

private static void ConfirmDeletion(ConfirmDeleteObjectModal modal, bool confirmDeletion)
private static Task ConfirmDeletion(ConfirmDeleteObjectModal modal, bool confirmDeletion)
{
if (confirmDeletion)
modal.Delete.Click();
else
modal.Cancel.Click();
return confirmDeletion
? modal.Delete.Click()
: modal.Cancel.Click();
}

private static void AssertFtpUserExistence(Guid userId, bool deletionConfirmed)
Expand Down
Loading

0 comments on commit 2596311

Please sign in to comment.