SkbKontur.Playwright.ReactUI.Controls
4.1.1
Prefix Reserved
See the version list below for details.
dotnet add package SkbKontur.Playwright.ReactUI.Controls --version 4.1.1
NuGet\Install-Package SkbKontur.Playwright.ReactUI.Controls -Version 4.1.1
<PackageReference Include="SkbKontur.Playwright.ReactUI.Controls" Version="4.1.1" />
<PackageVersion Include="SkbKontur.Playwright.ReactUI.Controls" Version="4.1.1" />
<PackageReference Include="SkbKontur.Playwright.ReactUI.Controls" />
paket add SkbKontur.Playwright.ReactUI.Controls --version 4.1.1
#r "nuget: SkbKontur.Playwright.ReactUI.Controls, 4.1.1"
#:package SkbKontur.Playwright.ReactUI.Controls@4.1.1
#addin nuget:?package=SkbKontur.Playwright.ReactUI.Controls&version=4.1.1
#tool nuget:?package=SkbKontur.Playwright.ReactUI.Controls&version=4.1.1
Playwright.ReactUI.Controls
Библиотека для автоматизированного тестирования компонентов @skbkontur/react-ui с помощью Playwright.NET.
📋 Содержание
- Быстрый старт
- Основные возможности
- Работа с модальными окнами и боковыми панелями
- Создание пользовательских компонентов
- Автоматическая инициализация контролов
- Расширения и утилиты
- Dependency Injection
- Запуск Storybook
- Требования
- История изменений
🚀 Быстрый старт
Инициализация контрола
// Создание экземпляра Input по data-tid
var input = new Input(page.GetByTestId("InputId"));
Взаимодействие с контролом
// Заполнение поля ввода
await input.FillAsync("newValue").ConfigureAwait(false);
// Очистка поля
await input.ClearAsync().ConfigureAwait(false);
// Установка фокуса
await input.FocusAsync().ConfigureAwait(false);
Проверка состояния
// Проверка значения
await input.ExpectV2().ToHaveValueAsync("newValue").ConfigureAwait(false);
// Проверка видимости
await input.ExpectV2().ToBeVisibleAsync().ConfigureAwait(false);
// Проверка состояния ошибки
await input.ExpectV2().ToHaveErrorAsync().ConfigureAwait(false);
🎯 Основные возможности
Поддержка всех компонентов React UI
Библиотека предоставляет готовые классы для работы со всеми основными компонентами:
- Ввод данных:
Input,Textarea,DateInput,DatePicker,CurrencyInput,FxInput - Выбор значений:
Select,Combobox,Autocomplete,Dropdown,DropdownMenu - Множественный выбор:
Checkbox,Radio,RadioGroup,Toggle,TokenInput - Действия:
Button,Link,Kebab - Оверлеи:
Modal,SidePage,Tooltip - Навигация:
Tabs,Paging - Индикаторы:
Loader,Spinner - Другое:
FileUploader,Label
Fluent API для проверок
await button.ExpectV2()
.ToBeVisibleAsync()
.ConfigureAwait(false);
await input.ExpectV2()
.ToHaveValueAsync("expected")
.ConfigureAwait(false);
await select.ExpectV2()
.ToBeDisabledAsync()
.ConfigureAwait(false);
🪟 Работа с модальными окнами и боковыми панелями
Открытие модального окна
// Определение класса модального окна
public class MyModal : ModalBase
{
public MyModal(ILocator rootLocator) : base(rootLocator)
{
HeaderText = ControlFactory.Create<Label>(
RootLocator.GetByTestId("ModalHeader__root")
);
}
public Label HeaderText { get; }
public override async Task CloseAsync()
{
// Реализация закрытия модального окна
await Cross.ClickAsync().ConfigureAwait(false);
}
}
// Использование
var modal = await button.ClickAndOpenModalAsync<MyModal>().ConfigureAwait(false);
await modal.HeaderText.ExpectV2().ToHaveTextAsync("Заголовок").ConfigureAwait(false);
await modal.CloseByCrossAsync().ConfigureAwait(false);
Открытие боковой панели
// Определение класса боковой панели
public class MySidePage : SidePageBase
{
public MySidePage(ILocator rootLocator) : base(rootLocator)
{
Content = ControlFactory.Create<Label>(
RootLocator.GetByTestId("SidePageBody__root")
);
}
public Label Content { get; }
public override async Task CloseAsync()
{
await Cross.ClickAsync().ConfigureAwait(false);
}
}
// Использование
var sidePage = await link.ClickAndOpenSidePageAsync<MySidePage>().ConfigureAwait(false);
await sidePage.IsOpenedAsync(); // true
await sidePage.CloseByCrossAsync().ConfigureAwait(false);
Открытие модального окна из Tooltip, Dropdown или Kebab
// Из Tooltip
var tooltip = await button.GetTooltipAsync(TooltipType.Simple).ConfigureAwait(false);
var tooltipButton = tooltip.GetContent().Locator("button");
var modal = await tooltipButton.ClickAndOpenModalAsync<MyModal>().ConfigureAwait(false);
// Из Dropdown
var menuItem = await dropdown.GetMenuItemAsync("Открыть окно").ConfigureAwait(false);
var modal = await menuItem.ClickAndOpenModalAsync<MyModal>(
page.GetByTestId("MyModal")
).ConfigureAwait(false);
// Из Kebab
var menuItem = await kebab.GetMenuItemAsync(0).ConfigureAwait(false);
var modal = await menuItem.ClickAndOpenModalAsync<MyModal>(
page.GetByTestId("MyModal")
).ConfigureAwait(false);
🏗️ Создание пользовательских компонентов
Простой компонент
public class Header : ControlBase
{
public Header(ILocator rootLocator)
: base(rootLocator)
{
SomeInput = new Input(rootLocator.GetByTestId("InputId"));
Logo = new Label(rootLocator.GetByTestId("Logo"));
}
public Input SomeInput { get; }
public Label Logo { get; }
}
Компонент с Assertions
public class HeaderAssertions : ControlBaseAssertionsV2
{
private readonly Header header;
public HeaderAssertions(Header header)
: base(header)
{
this.header = header;
}
public async Task ToBeVisibleAsync()
=> await header.RootLocator.Expect()
.ToBeVisibleAsync()
.ConfigureAwait(false);
public async Task ToHaveLogoAsync()
=> await header.Logo.ExpectV2()
.ToBeVisibleAsync()
.ConfigureAwait(false);
}
// Добавление в класс Header
public new HeaderAssertions ExpectV2() => new(this);
🔄 Автоматическая инициализация контролов
Используйте атрибут [AutoFillControls] для автоматической инициализации контролов в PageObjects и PageElements.
PageObject с автозаполнением
[AutoFillControls]
public class TestPage : PageBase
{
public TestPage(IPage page)
: base(page)
{
}
// Контрол инициализируется с data-tid="Compound"
public Compound Compound { get; init; }
// Контрол инициализируется с data-tid="LinkId"
[RootByTid("LinkId")]
public Link Link { get; init; }
// Контрол инициализируется с локатором "LocatorId" (css/xpath)
[RootByLocator("LocatorId")]
public Input Input { get; init; }
}
Составной компонент (PageElement)
[AutoFillControls]
public class Compound : CompoundControlBase
{
public Compound(ILocator rootLocator)
: base(rootLocator)
{
// Контрол инициализируется вручную
ManualButton = new Button(rootLocator.GetByText("ButtonId"));
}
// Пропускаем автозаполнение для контролов, инициализированных в конструкторе
[SkipAutoFillControl]
public Button ManualButton { get; init; }
// Автоматическая инициализация с data-tid="Title"
public Label Title { get; init; }
// Список контролов: Root определяет контейнер, Child - элементы
[RootByTid("RootList")]
[ChildByLocator("ChildItem")]
public ControlList<Label> List { get; init; }
}
Доступные атрибуты
RootByTid- поиск контрола поdata-tidатрибутуRootByLocator- поиск контрола по CSS/XPath селекторуChildByTid- поиск элементов списка поdata-tid(только дляControlList)ChildByLocator- поиск элементов списка по селектору (только дляControlList)SkipAutoFillControl- пропуск автоматической инициализации
🛠️ Расширения и утилиты
Дополнительные методы для контролов
// Добавление текста к существующему в Input
await input.AppendTextAsync("newValue").ConfigureAwait(false);
// Ожидание видимости компонента
await input.WaitToBeVisibleAsync().ConfigureAwait(false);
// Ожидание значения в Input
await input.WaitToHaveValueAsync("TODO").ConfigureAwait(false);
Работа со списками
var list = new ControlList<MenuItem>(
rootLocator,
locator => locator.Locator("[data-tid='MenuItem__root']"),
locator => new MenuItem(locator)
);
// Получение всех элементов
var items = await list.GetItemsAsync().ConfigureAwait(false);
// Фильтрация списка
var filtered = list.Filter(new LocatorFilterOptions { HasText = "Search" });
// Поиск элемента по условию
var item = await list.GetFirstItemAsync(
async x => await x.GetTextAsync().ConfigureAwait(false) == "Target"
).ConfigureAwait(false);
🔧 Dependency Injection
Библиотека поддерживает базовый Dependency Injection через интерфейсы:
IReactUIControlFactory- фабрика для создания контролов React UIIPageFactory- фабрика для создания Page ObjectsIAutofillDependenciesFactory- фабрика для предоставления дополнительных зависимостейIAutoControlsSetter- интерфейс для кастомизации автоматического создания контролов
📚 Запуск Storybook
Для запуска тестов необходим Storybook. Его можно запустить локально или в Docker-контейнере.
Локальный запуск
Вариант 1: Скрипт PowerShell
.\scripts\RunLocalStorybook.ps1
Вариант 2: Вручную
npm i
npm run build-storybook
npm run storybook
Требования: Node.js 18.19.0 или выше
Запуск в Docker
.\scripts\RunStorybookInDocker.ps1
Требования: Docker
📋 Минимальные требования
- .NET Standard 2.0 / .NET 6+
- Playwright 1.51.0+
- @skbkontur/react-ui 4.25.2+ (рекомендуется использовать последние версии)
📝 История изменений
Все изменения документируются в CHANGELOG.md.
📄 Лицензия
MIT License
🤝 Вклад в проект
Приветствуются merge request'ы и issue с предложениями по улучшению библиотеки.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Playwright (>= 1.51.0)
- SkbKontur.Playwright.POM.Abstractions (>= 1.0.3)
- System.Linq.Async (>= 6.0.1)
-
net6.0
- Microsoft.Playwright (>= 1.51.0)
- SkbKontur.Playwright.POM.Abstractions (>= 1.0.3)
- System.Linq.Async (>= 6.0.1)
-
net8.0
- Microsoft.Playwright (>= 1.51.0)
- SkbKontur.Playwright.POM.Abstractions (>= 1.0.3)
- System.Linq.Async (>= 6.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.2.0 | 234 | 4/6/2026 |
| 4.1.1 | 599 | 3/16/2026 |
| 4.1.0 | 182 | 3/16/2026 |
| 4.0.1 | 917 | 1/27/2026 |
| 4.0.0 | 101 | 1/22/2026 |
| 4.0.0-betac761fd74 | 98 | 1/20/2026 |
| 4.0.0-betac1918b74 | 105 | 1/22/2026 |
| 4.0.0-beta4ec7bd11 | 100 | 1/16/2026 |
| 4.0.0-beta2cc952c6 | 274 | 12/16/2025 |