From 2b8bc3114c0c7b320910eefdf30441c3649a638f Mon Sep 17 00:00:00 2001
From: Pavel Vostretsov
Date: Sun, 14 Jan 2024 21:07:27 +0500
Subject: [PATCH] playwright playground
---
DbViewer.Tests/DbViewer.Tests.csproj | 1 +
.../FrontTests/AutoFill/PwAutoFill.cs | 60 +++++++++
.../BusinessObjectsChangeValuesTest.cs | 97 +++++++-------
.../FrontTests/BusinessObjectsDeleteTest.cs | 80 ++++++-----
.../FrontTests/BusinessObjectsSearchTests.cs | 91 +++++++------
.../FrontTests/Controls/Accordion.cs | 31 +++++
.../Controls/AccordionFieldValue.cs | 33 +++++
.../FrontTests/Controls/AccordionRow.cs | 25 ++++
.../FrontTests/Controls/AccordionToggle.cs | 16 +++
.../Controls/BusinessObjectFilter.cs | 28 ++++
.../Controls/BusinessObjectGroup.cs | 21 +++
.../FrontTests/Controls/BusinessObjectItem.cs | 16 +++
.../Controls/BusinessObjectTableRow.cs | 24 ++++
.../Controls/ConfirmDeleteObjectModal.cs | 17 +++
.../FrontTests/Controls/FilterModal.cs | 30 +++++
.../Pages/PwBusinessObjectDetailsPage.cs | 25 ++++
.../Pages/PwBusinessObjectTablePage.cs | 51 +++++++
.../FrontTests/Pages/PwBusinessObjectsPage.cs | 32 +++++
.../Playwright/AssertionExtensions.cs | 125 ++++++++++++++++++
.../FrontTests/Playwright/Browser.cs | 113 ++++++++++++++++
.../FrontTests/Playwright/PwButton.cs | 12 ++
.../FrontTests/Playwright/PwCheckbox.cs | 12 ++
.../FrontTests/Playwright/PwControlBase.cs | 17 +++
.../FrontTests/Playwright/PwControlList.cs | 48 +++++++
.../FrontTests/Playwright/PwDatePicker.cs | 12 ++
.../FrontTests/Playwright/PwInput.cs | 12 ++
.../FrontTests/Playwright/PwLabel.cs | 12 ++
.../FrontTests/Playwright/PwLink.cs | 12 ++
.../FrontTests/Playwright/PwPageBase.cs | 17 +++
.../FrontTests/Playwright/PwSelect.cs | 12 ++
DbViewer.Tests/FrontTests/PlaywrightSetup.cs | 66 +++++++++
global.json | 2 +-
32 files changed, 1025 insertions(+), 125 deletions(-)
create mode 100644 DbViewer.Tests/FrontTests/AutoFill/PwAutoFill.cs
create mode 100644 DbViewer.Tests/FrontTests/Controls/Accordion.cs
create mode 100644 DbViewer.Tests/FrontTests/Controls/AccordionFieldValue.cs
create mode 100644 DbViewer.Tests/FrontTests/Controls/AccordionRow.cs
create mode 100644 DbViewer.Tests/FrontTests/Controls/AccordionToggle.cs
create mode 100644 DbViewer.Tests/FrontTests/Controls/BusinessObjectFilter.cs
create mode 100644 DbViewer.Tests/FrontTests/Controls/BusinessObjectGroup.cs
create mode 100644 DbViewer.Tests/FrontTests/Controls/BusinessObjectItem.cs
create mode 100644 DbViewer.Tests/FrontTests/Controls/BusinessObjectTableRow.cs
create mode 100644 DbViewer.Tests/FrontTests/Controls/ConfirmDeleteObjectModal.cs
create mode 100644 DbViewer.Tests/FrontTests/Controls/FilterModal.cs
create mode 100644 DbViewer.Tests/FrontTests/Pages/PwBusinessObjectDetailsPage.cs
create mode 100644 DbViewer.Tests/FrontTests/Pages/PwBusinessObjectTablePage.cs
create mode 100644 DbViewer.Tests/FrontTests/Pages/PwBusinessObjectsPage.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/AssertionExtensions.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/Browser.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/PwButton.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/PwCheckbox.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/PwControlBase.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/PwControlList.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/PwDatePicker.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/PwInput.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/PwLabel.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/PwLink.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/PwPageBase.cs
create mode 100644 DbViewer.Tests/FrontTests/Playwright/PwSelect.cs
create mode 100644 DbViewer.Tests/FrontTests/PlaywrightSetup.cs
diff --git a/DbViewer.Tests/DbViewer.Tests.csproj b/DbViewer.Tests/DbViewer.Tests.csproj
index bc0b37ad..7025c767 100644
--- a/DbViewer.Tests/DbViewer.Tests.csproj
+++ b/DbViewer.Tests/DbViewer.Tests.csproj
@@ -10,6 +10,7 @@
+
diff --git a/DbViewer.Tests/FrontTests/AutoFill/PwAutoFill.cs b/DbViewer.Tests/FrontTests/AutoFill/PwAutoFill.cs
new file mode 100644
index 00000000..643b9add
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/AutoFill/PwAutoFill.cs
@@ -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(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().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()
+ .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);
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/BusinessObjectsChangeValuesTest.cs b/DbViewer.Tests/FrontTests/BusinessObjectsChangeValuesTest.cs
index 0d28ab74..0fbd20e9 100644
--- a/DbViewer.Tests/FrontTests/BusinessObjectsChangeValuesTest.cs
+++ b/DbViewer.Tests/FrontTests/BusinessObjectsChangeValuesTest.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using System.Threading.Tasks;
using Cassandra.Data.Linq;
@@ -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
{
@@ -33,38 +35,42 @@ public BusinessObjectsChangeValuesTest(string documentName)
/// Проверяем, что заданные значения сохраняются
///
[Test]
- public void TestChangeOrganizationName()
+ public async Task TestChangeOrganizationName()
{
var documentId = CreateDocument(documentName);
- using var browser = new BrowserForTests();
- var businessObjectEditingPage = browser.LoginAsSuperUser().SwitchTo(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(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");
}
@@ -74,46 +80,47 @@ public void TestChangeOrganizationName()
/// Проверяем, что заданные значения сохраняются
///
[Test]
- public void TestChangeDocumentDates()
+ public async Task TestChangeDocumentDates()
{
var documentId = CreateDocument(documentName);
- using var browser = new BrowserForTests();
- var businessObjectEditingPage = browser.LoginAsSuperUser().SwitchTo(documentName, $"Id={documentId}");
+ await using var browser = new Browser();
+ var adminBrowser = await browser.LoginAsSuperUser();
+ var businessObjectEditingPage = await adminBrowser.SwitchTo(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));
}
diff --git a/DbViewer.Tests/FrontTests/BusinessObjectsDeleteTest.cs b/DbViewer.Tests/FrontTests/BusinessObjectsDeleteTest.cs
index e1fc132a..e4d0316d 100644
--- a/DbViewer.Tests/FrontTests/BusinessObjectsDeleteTest.cs
+++ b/DbViewer.Tests/FrontTests/BusinessObjectsDeleteTest.cs
@@ -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
{
@@ -16,20 +19,21 @@ public class BusinessObjectsDeleteTest
/// Проверяем, что кнопка с удалением бизнес объекта на странице с таблицей доступна только с SuperUserAccessLevel.God
///
[Test]
- public void DeleteViaSearchPageRequiresGodAccess()
+ public async Task DeleteViaSearchPageRequiresGodAccess()
{
var ftpUser = CreateFtpUser();
- using var browser = new BrowserForTests();
- var businessObjectPage = browser.SwitchTo("FtpUser");
+ await using var browser = new Browser();
+ var businessObjectPage = await browser.SwitchTo("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();
}
///
@@ -39,24 +43,27 @@ public void DeleteViaSearchPageRequiresGodAccess()
///
[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("FtpUser");
+ await using var browser = new Browser();
+
+ var adminBrowser = await browser.LoginAsSuperUser();
+ var businessObjectPage = await adminBrowser.SwitchTo("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);
}
@@ -65,13 +72,13 @@ public void DeleteViaSearchPage(bool confirmDeletion)
/// Проверяем, что кнопка с удалением бизнес объекта на странице с конкретным объектом доступна только с SuperUserAccessLevel.God
///
[Test]
- public void DeleteViaDetailsPageRequiresGodAccess()
+ public async Task DeleteViaDetailsPageRequiresGodAccess()
{
var ftpUser = CreateFtpUser();
- using var browser = new BrowserForTests();
- var detailsPage = browser.SwitchTo("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("FtpUser", $"Id={ftpUser.Id}");
+ await detailsPage.Delete.WaitAbsence();
}
///
@@ -81,27 +88,28 @@ public void DeleteViaDetailsPageRequiresGodAccess()
///
[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("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("FtpUser", $"Id={ftpUser.Id}");
+ await detailsPage.Delete.Click();
+ await ConfirmDeletion(detailsPage.ConfirmDeleteObjectModal, confirmDeletion);
if (confirmDeletion)
- detailsPage.GoTo();
+ detailsPage.GoTo();
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)
diff --git a/DbViewer.Tests/FrontTests/BusinessObjectsSearchTests.cs b/DbViewer.Tests/FrontTests/BusinessObjectsSearchTests.cs
index db4f32b9..73bbc0ea 100644
--- a/DbViewer.Tests/FrontTests/BusinessObjectsSearchTests.cs
+++ b/DbViewer.Tests/FrontTests/BusinessObjectsSearchTests.cs
@@ -1,7 +1,9 @@
-using NUnit.Framework;
+using System.Threading.Tasks;
+
+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
{
@@ -12,46 +14,49 @@ public class BusinessObjectsSearchTests
/// Вводим в строке поиска запрос в R# стиле, проверяем ожидаемое количество и название каждого объекта
///
[Test]
- public void TestSearch()
+ public async Task TestSearch()
{
- using var browser = new BrowserForTests();
+ await using var browser = new Browser();
+
+ var businessObjectsPage = await browser.SwitchTo();
+ await businessObjectsPage.FilterInput.ClearAndInputText("CI");
+ await businessObjectsPage.ObjectGroups.WaitCount(1);
+
+ var pagedObjects = await businessObjectsPage.ObjectGroups.GetItemWithText(x => x.Name, "CQL Paged Objects");
+ await pagedObjects.ObjectsList
+ .Select(x => x.ObjectLink)
+ .WaitText("CqlOrganizationInfo", "CqlUserInfo");
+
+ await businessObjectsPage.FilterInput.ClearAndInputText("DocMe");
+ await businessObjectsPage.ObjectGroups.WaitCount(2);
- var businessObjectsPage = browser.SwitchTo();
- businessObjectsPage.FilterInput.ClearAndInputText("CI");
- businessObjectsPage.ObjectGroups.WaitCount(1);
- businessObjectsPage.ObjectGroups
- .GetItemWithText(x => x.Name.Text, "CQL Paged Objects").ObjectsList
- .Wait(x => x.ObjectLink.Text)
- .That(Is.EqualTo(new[] {"CqlOrganizationInfo", "CqlUserInfo"}));
+ var cqlObjects = await businessObjectsPage.ObjectGroups.GetItemWithText(x => x.Name, "CQL Objects");
+ await cqlObjects.ObjectsList
+ .Select(x => x.ObjectLink)
+ .WaitText(new[] {"DocumentBindingsMeta"});
- businessObjectsPage.FilterInput.ClearAndInputText("DocMe");
- businessObjectsPage.ObjectGroups.WaitCount(2);
- businessObjectsPage.ObjectGroups
- .GetItemWithText(x => x.Name.Text, "CQL Objects").ObjectsList
- .Wait(x => x.ObjectLink.Text)
- .That(Is.EqualTo(new[] {"DocumentBindingsMeta"}));
- businessObjectsPage.ObjectGroups
- .GetItemWithText(x => x.Name.Text, "CQL Paged Objects").ObjectsList
- .Wait(x => x.ObjectLink.Text)
- .That(Is.EqualTo(new[] {"CqlDocumentMeta"}));
+ var cqlPagedObjects = await businessObjectsPage.ObjectGroups.GetItemWithText(x => x.Name, "CQL Paged Objects");
+ await cqlPagedObjects.ObjectsList
+ .Select(x => x.ObjectLink)
+ .WaitText(new[] {"CqlDocumentMeta"});
}
///
/// Проверяем, что у таблицы FtpUser есть плашка indexed
///
[Test]
- public void TestSearchIndexedField()
+ public async Task TestSearchIndexedField()
{
- using var browser = new BrowserForTests();
+ await using var browser = new Browser();
- var businessObjects = browser.SwitchTo();
- businessObjects.FilterInput.ClearAndInputText("UsersTable");
- businessObjects.ObjectGroups.WaitCount(1);
+ var businessObjects = await browser.SwitchTo();
+ await businessObjects.FilterInput.ClearAndInputText("UsersTable");
+ await businessObjects.ObjectGroups.WaitCount(1);
- var objects = businessObjects.ObjectGroups.GetItemWithText(x => x.Name.Text, "Postgres Objects");
- objects.IndexedLabel.WaitPresence();
- objects.ObjectsList.WaitCount(1);
- objects.ObjectsList[0].ObjectLink.WaitText("UsersTable");
+ var objects = await businessObjects.ObjectGroups.GetItemWithText(x => x.Name, "Postgres Objects");
+ await objects.IndexedLabel.WaitPresence();
+ await objects.ObjectsList.WaitCount(1);
+ await objects.ObjectsList[0].ObjectLink.WaitText("UsersTable");
}
///
@@ -59,15 +64,15 @@ public void TestSearchIndexedField()
/// Проверяем что нам выдает ровно одну ссылку
///
[Test]
- public void TestSearchLink()
+ public async Task TestSearchLink()
{
- using var browser = new BrowserForTests();
+ await using var browser = new Browser();
- var businessObjectsPage = browser.SwitchTo();
- businessObjectsPage.FilterInput.ClearAndInputText("DocumentPrintingInfo");
- businessObjectsPage.ObjectGroups.WaitCount(1);
- businessObjectsPage.ObjectGroups[0].ObjectsList.WaitCount(1);
- businessObjectsPage.FindBusinessObjectLink("CQL Objects", "DocumentPrintingInfo").WaitPresence();
+ var businessObjectsPage = await browser.SwitchTo();
+ await businessObjectsPage.FilterInput.ClearAndInputText("DocumentPrintingInfo");
+ await businessObjectsPage.ObjectGroups.WaitCount(1);
+ await businessObjectsPage.ObjectGroups[0].ObjectsList.WaitCount(1);
+ await (await businessObjectsPage.FindBusinessObjectLink("CQL Objects", "DocumentPrintingInfo")).WaitPresence();
}
///
@@ -75,14 +80,14 @@ public void TestSearchLink()
/// Проверяем, что ссылка ведет туда, куда нам нужно
///
[Test]
- public void TestLinkShouldReferToShowTablePage()
+ public async Task TestLinkShouldReferToShowTablePage()
{
- using var browser = new BrowserForTests();
+ await using var browser = new Browser();
- var businessObjectsPage = browser.SwitchTo();
- var link = businessObjectsPage.FindBusinessObjectLink("CQL Objects", "DocumentPrintingInfo");
- var page = link.ClickAndGoTo();
- page.Header.WaitText("DocumentPrintingInfo");
+ var businessObjectsPage = await browser.SwitchTo();
+ var link = await businessObjectsPage.FindBusinessObjectLink("CQL Objects", "DocumentPrintingInfo");
+ var page = await link.ClickAndGoTo();
+ await page.Header.WaitText("DocumentPrintingInfo");
}
}
}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Controls/Accordion.cs b/DbViewer.Tests/FrontTests/Controls/Accordion.cs
new file mode 100644
index 00000000..6a272427
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Controls/Accordion.cs
@@ -0,0 +1,31 @@
+using Microsoft.Playwright;
+
+using SkbKontur.DbViewer.Tests.FrontTests.AutoFill;
+using SkbKontur.DbViewer.Tests.FrontTests.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Controls
+{
+ public class Accordion : PwControlBase
+ {
+ public Accordion(ILocator locator)
+ : base(locator)
+ {
+ }
+
+ public AccordionRow FindField(string id)
+ {
+ var row = new AccordionRow(Locator.GetByTestId(id));
+ PwAutoFill.InitializeControls(row, Locator.Page, row.Locator);
+
+ return row;
+ }
+
+ public AccordionToggle FindAccordionToggle(string id)
+ {
+ var toggle = new AccordionToggle(Locator.GetByTestId(id));
+ PwAutoFill.InitializeControls(toggle, Locator.Page, toggle.Locator);
+
+ return toggle;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Controls/AccordionFieldValue.cs b/DbViewer.Tests/FrontTests/Controls/AccordionFieldValue.cs
new file mode 100644
index 00000000..4fcfa653
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Controls/AccordionFieldValue.cs
@@ -0,0 +1,33 @@
+using Microsoft.Playwright;
+
+using SkbKontur.DbViewer.Tests.FrontTests.AutoFill;
+using SkbKontur.DbViewer.Tests.FrontTests.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Controls
+{
+ public class AccordionFieldValue : PwControlBase
+ {
+ public AccordionFieldValue(ILocator locator)
+ : base(locator)
+ {
+ }
+
+ public PwLink GoToLink { get; set; }
+
+ [Selector("Input")]
+ public PwInput Input { get; set; }
+
+ [Selector("Checkbox")]
+ public PwCheckbox Checkbox { get; set; }
+
+ public PwSelect EnumSelect { get; set; }
+ public PwSelect BooleanSelect { get; set; }
+
+ public PwLink DownloadLink { get; set; }
+
+ public PwDatePicker Date { get; set; }
+ public PwInput Time { get; set; }
+ public PwSelect TimeZoneSelect { get; set; }
+ public PwLabel TimeOffsetLabel { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Controls/AccordionRow.cs b/DbViewer.Tests/FrontTests/Controls/AccordionRow.cs
new file mode 100644
index 00000000..0e38d33d
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Controls/AccordionRow.cs
@@ -0,0 +1,25 @@
+using Microsoft.Playwright;
+
+using SkbKontur.DbViewer.Tests.FrontTests.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Controls
+{
+ public class AccordionRow : PwControlBase
+ {
+ public AccordionRow(ILocator locator)
+ : base(locator)
+ {
+ }
+
+ public PwLabel Key { get; set; }
+
+ public PwLink GoToLink { get; set; }
+
+ public AccordionFieldValue FieldValue { get; set; }
+ public PwLabel Value { get; set; }
+
+ public PwButton Edit { get; set; }
+ public PwButton Save { get; set; }
+ public PwButton Cancel { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Controls/AccordionToggle.cs b/DbViewer.Tests/FrontTests/Controls/AccordionToggle.cs
new file mode 100644
index 00000000..02f94d01
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Controls/AccordionToggle.cs
@@ -0,0 +1,16 @@
+using Microsoft.Playwright;
+
+using SkbKontur.DbViewer.Tests.FrontTests.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Controls
+{
+ public class AccordionToggle : PwControlBase
+ {
+ public AccordionToggle(ILocator locator)
+ : base(locator)
+ {
+ }
+
+ public PwButton ToggleButton { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Controls/BusinessObjectFilter.cs b/DbViewer.Tests/FrontTests/Controls/BusinessObjectFilter.cs
new file mode 100644
index 00000000..8ade8c77
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Controls/BusinessObjectFilter.cs
@@ -0,0 +1,28 @@
+using Microsoft.Playwright;
+
+using SkbKontur.DbViewer.Tests.FrontTests.Pages;
+using SkbKontur.DbViewer.Tests.FrontTests.Playwright;
+
+using SKBKontur.SeleniumTesting.Controls;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Controls
+{
+ public class BusinessObjectFilter : PwControlBase
+ {
+ public BusinessObjectFilter(ILocator locator)
+ : base(locator)
+ {
+ }
+
+ public PwLabel FormCaption { get; set; }
+ public Select OperatorSelect { get; set; }
+ public Select EnumSelect { get; set; }
+ public Select BooleanSelect { get; set; }
+ public PwInput Input { get; set; }
+ public Validation InputValidation { get; set; }
+ public Validation DateTimeValidation { get; set; }
+ public DatePicker Date { get; set; }
+ public PwInput Time { get; set; }
+ public PwInput DateTimeInTicks { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Controls/BusinessObjectGroup.cs b/DbViewer.Tests/FrontTests/Controls/BusinessObjectGroup.cs
new file mode 100644
index 00000000..fffd567e
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Controls/BusinessObjectGroup.cs
@@ -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 ObjectsList { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Controls/BusinessObjectItem.cs b/DbViewer.Tests/FrontTests/Controls/BusinessObjectItem.cs
new file mode 100644
index 00000000..8f7478dc
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Controls/BusinessObjectItem.cs
@@ -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; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Controls/BusinessObjectTableRow.cs b/DbViewer.Tests/FrontTests/Controls/BusinessObjectTableRow.cs
new file mode 100644
index 00000000..63980be1
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Controls/BusinessObjectTableRow.cs
@@ -0,0 +1,24 @@
+using Microsoft.Playwright;
+
+using SkbKontur.DbViewer.Tests.FrontTests.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Controls
+{
+ public class BusinessObjectTableRow : PwControlBase
+ {
+ public BusinessObjectTableRow(ILocator locator)
+ : base(locator)
+ {
+ }
+
+ public PwLink Details { get; set; }
+ public PwLink Delete { get; set; }
+ public PwLabel Id { get; set; }
+ public PwLabel ScopeId { get; set; }
+
+ public PwLabel FindColumn(string tid)
+ {
+ return new PwLabel(Locator.GetByTestId(tid));
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Controls/ConfirmDeleteObjectModal.cs b/DbViewer.Tests/FrontTests/Controls/ConfirmDeleteObjectModal.cs
new file mode 100644
index 00000000..a22c4af1
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Controls/ConfirmDeleteObjectModal.cs
@@ -0,0 +1,17 @@
+using Microsoft.Playwright;
+
+using SkbKontur.DbViewer.Tests.FrontTests.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Controls
+{
+ public class ConfirmDeleteObjectModal : PwControlBase
+ {
+ public ConfirmDeleteObjectModal(ILocator locator)
+ : base(locator)
+ {
+ }
+
+ public PwButton Delete { get; set; }
+ public PwButton Cancel { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Controls/FilterModal.cs b/DbViewer.Tests/FrontTests/Controls/FilterModal.cs
new file mode 100644
index 00000000..39580649
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Controls/FilterModal.cs
@@ -0,0 +1,30 @@
+using System.Threading.Tasks;
+
+using Microsoft.Playwright;
+
+using SkbKontur.DbViewer.Tests.FrontTests.AutoFill;
+using SkbKontur.DbViewer.Tests.FrontTests.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Controls
+{
+ public class FilterModal : PwControlBase
+ {
+ public FilterModal(ILocator locator)
+ : base(locator)
+ {
+ }
+
+ public Task GetFilter(string name)
+ {
+ return ObjectFilters.Where(x => x.Locator.Page.GetByTestId(name)).Single();
+ }
+
+ [Selector("##ObjectFilters ##Filter")]
+ public PwControlList ObjectFilters { get; set; }
+
+ public PwButton Apply { get; set; }
+ public PwLink Clear { get; set; }
+ public PwInput Id { get; set; }
+ public PwInput ScopeId { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Pages/PwBusinessObjectDetailsPage.cs b/DbViewer.Tests/FrontTests/Pages/PwBusinessObjectDetailsPage.cs
new file mode 100644
index 00000000..6981580f
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Pages/PwBusinessObjectDetailsPage.cs
@@ -0,0 +1,25 @@
+using Microsoft.Playwright;
+
+using SkbKontur.DbViewer.Tests.FrontTests.Helpers;
+using SkbKontur.DbViewer.Tests.FrontTests.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Pages
+{
+ [PageRoute("BusinessObjects/{scopeId}/details?{id}")]
+ public class PwBusinessObjectDetailsPage : PwPageBase
+ {
+ public PwBusinessObjectDetailsPage(IPage page)
+ : base(page)
+ {
+ }
+
+ public PwLabel Header { get; set; }
+
+ public PwLink Copy { get; set; }
+ public PwLink Delete { get; set; }
+
+ public Controls.ConfirmDeleteObjectModal ConfirmDeleteObjectModal { get; set; }
+
+ public Controls.Accordion RootAccordion { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Pages/PwBusinessObjectTablePage.cs b/DbViewer.Tests/FrontTests/Pages/PwBusinessObjectTablePage.cs
new file mode 100644
index 00000000..b7b9a3a1
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Pages/PwBusinessObjectTablePage.cs
@@ -0,0 +1,51 @@
+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/{id}")]
+ public class PwBusinessObjectTablePage : PwPageBase
+ {
+ public PwBusinessObjectTablePage(IPage page)
+ : base(page)
+ {
+ }
+
+ public PwLabel Header { get; set; }
+
+ public PwLink GoBack { get; set; }
+ public PwLabel NothingFound { get; set; }
+
+ public PwLabel ItemsCountInfo { get; set; }
+
+ public PwLink OpenFilter { get; set; }
+
+ [Selector("portal=FilterModal")]
+ public Controls.FilterModal FilterModal { get; set; }
+
+ public DownloadLimitModal DownloadLimitModal { get; set; }
+
+ public CountDropdown CountDropdown { get; set; }
+ public PwLink ClearFilter { get; set; }
+ public PwLink FieldSettings { get; set; }
+ public PwLink DownloadLink { get; set; }
+
+ [Selector("Portal:portal ##ColumnSelector")]
+ public ColumnSelector ColumnSelector { get; set; }
+
+ public Controls.ConfirmDeleteObjectModal ConfirmDeleteObjectModal { get; set; }
+
+ public BusinessObjectTableHeader TableHeader { get; set; }
+
+ [Selector("##Body")]
+ [ChildSelector("##Row")]
+ public PwControlList BusinessObjectItems { get; set; }
+
+ public Paging Paging { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Pages/PwBusinessObjectsPage.cs b/DbViewer.Tests/FrontTests/Pages/PwBusinessObjectsPage.cs
new file mode 100644
index 00000000..adca1f70
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Pages/PwBusinessObjectsPage.cs
@@ -0,0 +1,32 @@
+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;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Pages
+{
+ [PageRoute("BusinessObjects")]
+ public class PwBusinessObjectsPage : PwPageBase
+ {
+ public PwBusinessObjectsPage(IPage page)
+ : base(page)
+ {
+ }
+
+ public PwLabel Header { get; set; }
+ public PwLink BackLink { get; set; }
+ public PwInput FilterInput { get; set; }
+
+ [Selector("##ObjectGroups ##ObjectGroup")]
+ public PwControlList ObjectGroups { get; set; }
+
+ public async Task FindBusinessObjectLink(string groupName, string objectName)
+ {
+ var businessObjectsList = (await ObjectGroups.GetItemWithText(x => x.Name, groupName)).ObjectsList;
+ return (await businessObjectsList.GetItemWithText(x => x.ObjectLink, objectName)).ObjectLink;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/AssertionExtensions.cs b/DbViewer.Tests/FrontTests/Playwright/AssertionExtensions.cs
new file mode 100644
index 00000000..10f5ed44
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/AssertionExtensions.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Microsoft.Playwright;
+
+using NUnit.Framework;
+
+using SkbKontur.DbViewer.Tests.FrontTests.AutoFill;
+using SkbKontur.DbViewer.Tests.FrontTests.Pages;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
+{
+ public static class AssertionExtensions
+ {
+ public static Task GetItemWithText(this PwControlList list, Func f, string text)
+ where T : PwControlBase
+ {
+ return list.Where(x => f(x).Locator.GetByText(text)).Single();
+ }
+
+ public static async Task ClickAndGoTo(this PwControlBase control)
+ where T : PwPageBase
+ {
+ await control.Locator.ClickAsync();
+ return PwAutoFill.InitializePage(control.Locator.Page);
+ }
+
+ public static T GoTo(this PwPageBase page)
+ where T : PwPageBase
+ {
+ return PwAutoFill.InitializePage(page.Page);
+ }
+
+ public static Task ClearAndInputText(this PwInput input, string value)
+ {
+ return input.Locator.FillAsync(value);
+ }
+
+ public static async Task ClearAndInputText(this PwDatePicker datePicker, string value)
+ {
+ // await datePicker.Locator.ClickAsync();
+ await datePicker.Locator.GetByTestId("InputLikeText__input").PressSequentiallyAsync(value);
+ }
+
+ public static Task WaitCount(this PwControlList list, int count)
+ where T : PwControlBase
+ {
+ return list.Expect().ToHaveCountAsync(count);
+ }
+
+ public static async Task Single(this PwControlList list)
+ where T : PwControlBase
+ {
+ await list.WaitCount(1);
+ return list[0];
+ }
+
+ public static Task WaitPresence(this PwControlBase control)
+ {
+ return control.Expect().ToBeVisibleAsync();
+ }
+
+ public static Task WaitAbsence(this PwControlBase control)
+ {
+ return control.Expect().Not.ToBeVisibleAsync();
+ }
+
+ public static Task WaitText(this PwControlBase control, string value)
+ {
+ return control.Expect().ToHaveTextAsync(value);
+ }
+
+ public static Task WaitText(this PwControlBase control, params string[] values)
+ {
+ return control.Expect().ToHaveTextAsync(values);
+ }
+
+ public static Task WaitTextContains(this PwControlBase control, string value)
+ {
+ return control.Expect().ToContainTextAsync(value);
+ }
+
+ public static Task SelectValueByText(this PwSelect select, string value)
+ {
+ return select.Locator.SelectOptionAsync(value);
+ }
+
+ public static Task Click(this PwControlBase control)
+ {
+ return control.Locator.ClickAsync();
+ }
+
+ public static async Task LoginAsSuperUser(this Browser browser)
+ {
+ await browser.SwitchToUri(new Uri("Admin", UriKind.Relative));
+ return browser;
+ }
+
+ public static async Task Refresh(this Browser browser, TPage page)
+ where TPage : PwPageBase
+ {
+ await browser.Page.ReloadAsync();
+ return browser.GoTo();
+ }
+
+ public static async Task RefreshUntil(this Browser browser, TPage page, Func> conditionFunc, string cause = null, int timeout = 30000, int waitTimeout = 100)
+ where TPage : PwPageBase
+ {
+ var w = Stopwatch.StartNew();
+ if (await conditionFunc(page))
+ return page;
+ do
+ {
+ page = await browser.Refresh(page);
+ if (await conditionFunc(page))
+ return page;
+ Thread.Sleep(waitTimeout);
+ } while (w.ElapsedMilliseconds < timeout);
+ Assert.Fail(cause ?? $"Не смогли дождаться страницу за {timeout} мс");
+ return default;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/Browser.cs b/DbViewer.Tests/FrontTests/Playwright/Browser.cs
new file mode 100644
index 00000000..dd186afa
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/Browser.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Reflection;
+using System.Threading.Tasks;
+
+using Microsoft.Playwright;
+
+using NUnit.Framework;
+
+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 SwitchToUri(Uri uri)
+ where TPage : PwPageBase
+ {
+ await Page.GotoAsync(MakeAbsolute(uri).ToString());
+ return PwAutoFill.InitializePage(Page);
+ }
+
+ public TPage GoTo()
+ where TPage : PwPageBase
+ {
+ var newPage = PwAutoFill.InitializePage(Page);
+ return newPage;
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ if (context != null)
+ {
+ await context.Tracing.StopAsync(new TracingStopOptions
+ {
+ Path = $"{TestContext.CurrentContext.TestDirectory}/out/{TestContext.CurrentContext.Test.Name}.zip"
+ });
+ }
+
+ if (page != null)
+ await page.CloseAsync();
+
+ if (context != null)
+ {
+ await context.CloseAsync();
+ }
+ }
+
+ private Uri MakeAbsolute(Uri uri)
+ {
+ return uri.IsAbsoluteUri ? uri : new Uri(new Uri(baseUrl), uri);
+ }
+
+ public IPage Page
+ {
+ get
+ {
+ if (page != null)
+ return page;
+
+ context = PlaywrightSetup.Browser.NewContextAsync().GetAwaiter().GetResult();
+ context.Tracing.StartAsync(new TracingStartOptions
+ {
+ Screenshots = true,
+ Snapshots = true,
+ Sources = true,
+ Name = TestContext.CurrentContext.Test.Name
+ }).GetAwaiter().GetResult();
+
+ return page = context.NewPageAsync().GetAwaiter().GetResult();
+ }
+ }
+
+ private const string baseUrl = "http://localhost:5000/";
+
+ private IPage? page;
+ private IBrowserContext? context;
+ }
+
+ public static class AttributeNavigationExtensions
+ {
+ public static ILocatorAssertions Expect(this PwControlBase controlBase)
+ {
+ return Assertions.Expect(controlBase.Locator);
+ }
+
+ public static Task SwitchTo(this Browser browser, params string[] templateParameters)
+ where TPage : PwPageBase
+ {
+ return browser.SwitchToUri(new Uri(GetPageRoute(templateParameters), UriKind.Relative));
+ }
+
+ private static string GetPageRoute(string[] templateParameters)
+ {
+ foreach (var attribute in typeof(TPage).GetCustomAttributes())
+ {
+ 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}");
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/PwButton.cs b/DbViewer.Tests/FrontTests/Playwright/PwButton.cs
new file mode 100644
index 00000000..2796df9a
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/PwButton.cs
@@ -0,0 +1,12 @@
+using Microsoft.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
+{
+ public class PwButton : PwControlBase
+ {
+ public PwButton(ILocator locator)
+ : base(locator)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/PwCheckbox.cs b/DbViewer.Tests/FrontTests/Playwright/PwCheckbox.cs
new file mode 100644
index 00000000..a5906e36
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/PwCheckbox.cs
@@ -0,0 +1,12 @@
+using Microsoft.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
+{
+ public class PwCheckbox : PwControlBase
+ {
+ public PwCheckbox(ILocator locator)
+ : base(locator)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/PwControlBase.cs b/DbViewer.Tests/FrontTests/Playwright/PwControlBase.cs
new file mode 100644
index 00000000..9ab31a04
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/PwControlBase.cs
@@ -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; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/PwControlList.cs b/DbViewer.Tests/FrontTests/Playwright/PwControlList.cs
new file mode 100644
index 00000000..59fdea15
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/PwControlList.cs
@@ -0,0 +1,48 @@
+using System;
+
+using Microsoft.Playwright;
+
+using SkbKontur.DbViewer.Tests.FrontTests.AutoFill;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
+{
+ public class PwControlList : PwControlBase
+ where TControl : PwControlBase
+ {
+ public PwControlList(ILocator locator)
+ : base(locator)
+ {
+ }
+
+ public PwControlList Select(Func selector)
+ where T : PwControlBase
+ {
+ var dummyControl = (TControl)Activator.CreateInstance(typeof(TControl), Locator)!;
+ PwAutoFill.InitializeControls(dummyControl, Locator.Page, Locator);
+
+ return new PwControlList(selector(dummyControl).Locator);
+ }
+
+ public PwControlList Where(Func predicate)
+ {
+ var dummyControl = (TControl)Activator.CreateInstance(typeof(TControl), Locator)!;
+ PwAutoFill.InitializeControls(dummyControl, Locator.Page, null);
+
+ return new PwControlList(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;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/PwDatePicker.cs b/DbViewer.Tests/FrontTests/Playwright/PwDatePicker.cs
new file mode 100644
index 00000000..af82a9fa
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/PwDatePicker.cs
@@ -0,0 +1,12 @@
+using Microsoft.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
+{
+ public class PwDatePicker : PwControlBase
+ {
+ public PwDatePicker(ILocator locator)
+ : base(locator)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/PwInput.cs b/DbViewer.Tests/FrontTests/Playwright/PwInput.cs
new file mode 100644
index 00000000..c539da44
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/PwInput.cs
@@ -0,0 +1,12 @@
+using Microsoft.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
+{
+ public class PwInput : PwControlBase
+ {
+ public PwInput(ILocator locator)
+ : base(locator)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/PwLabel.cs b/DbViewer.Tests/FrontTests/Playwright/PwLabel.cs
new file mode 100644
index 00000000..eb0079a5
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/PwLabel.cs
@@ -0,0 +1,12 @@
+using Microsoft.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
+{
+ public class PwLabel : PwControlBase
+ {
+ public PwLabel(ILocator locator)
+ : base(locator)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/PwLink.cs b/DbViewer.Tests/FrontTests/Playwright/PwLink.cs
new file mode 100644
index 00000000..8881b3a0
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/PwLink.cs
@@ -0,0 +1,12 @@
+using Microsoft.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
+{
+ public class PwLink : PwControlBase
+ {
+ public PwLink(ILocator locator)
+ : base(locator)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/PwPageBase.cs b/DbViewer.Tests/FrontTests/Playwright/PwPageBase.cs
new file mode 100644
index 00000000..373b8621
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/PwPageBase.cs
@@ -0,0 +1,17 @@
+using JetBrains.Annotations;
+
+using Microsoft.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
+{
+ [MeansImplicitUse(ImplicitUseTargetFlags.Members | ImplicitUseTargetFlags.WithInheritors)]
+ public class PwPageBase
+ {
+ public PwPageBase(IPage page)
+ {
+ Page = page;
+ }
+
+ public IPage Page { get; }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/Playwright/PwSelect.cs b/DbViewer.Tests/FrontTests/Playwright/PwSelect.cs
new file mode 100644
index 00000000..8e457e1f
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/Playwright/PwSelect.cs
@@ -0,0 +1,12 @@
+using Microsoft.Playwright;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests.Playwright
+{
+ public class PwSelect : PwControlBase
+ {
+ public PwSelect(ILocator locator)
+ : base(locator)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/DbViewer.Tests/FrontTests/PlaywrightSetup.cs b/DbViewer.Tests/FrontTests/PlaywrightSetup.cs
new file mode 100644
index 00000000..b6bdbf00
--- /dev/null
+++ b/DbViewer.Tests/FrontTests/PlaywrightSetup.cs
@@ -0,0 +1,66 @@
+using System.Threading.Tasks;
+
+using Microsoft.Playwright;
+
+using NUnit.Framework;
+
+namespace SkbKontur.DbViewer.Tests.FrontTests
+{
+ [SetUpFixture]
+ public class PlaywrightSetup
+ {
+ public static IPlaywright Playwright { get; private set; }
+ public static IBrowser Browser { get; private set; }
+
+ [OneTimeSetUp]
+ public async Task SetUp()
+ {
+ Playwright = await Microsoft.Playwright.Playwright.CreateAsync();
+ Playwright.Selectors.SetTestIdAttribute("data-tid");
+// await Playwright.Selectors.RegisterAsync("portal", new SelectorsRegisterOptions
+// {
+// Script = @"
+// // Must evaluate to a selector engine instance.
+// {
+// // Returns the first element matching given selector in the root's subtree.
+// query(root, selector) {
+// console.info(root);
+// console.info(selector);
+// return root.querySelector(selector);
+// },
+//
+// // Returns all elements matching given selector in the root's subtree.
+// queryAll(root, selector) {
+// return Array.from(root.querySelectorAll(selector));
+// }
+// }"
+// });
+
+ await Playwright.Selectors.RegisterAsync("portal", new SelectorsRegisterOptions
+ {
+ Script = @"{
+ query(root, selector) {
+ const portal = root.querySelector(`[data-tid='${selector}']`);
+ const id = portal.getAttribute('data-render-container-id');
+ return document.querySelector(`[data-rendered-container-id='${id}']`);
+ },
+
+ queryAll(root, selector) {
+ const portal = root.querySelector(`[data-tid='${selector}']`);
+ const id = portal.getAttribute('data-render-container-id');
+ return [document.querySelector(`[data-rendered-container-id='${id}']`)];
+ }
+ }"
+ });
+
+ Browser = await Playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions {Headless = false});
+ }
+
+ [OneTimeTearDown]
+ public async Task TearDown()
+ {
+ await Browser.DisposeAsync();
+ Playwright.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/global.json b/global.json
index 447ef432..501e79a8 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "6.0.400",
+ "version": "8.0.100",
"rollForward": "latestFeature"
}
}
\ No newline at end of file