SkbKontur.Playwright.ReactUI.Controls
4.2.0
Prefix Reserved
dotnet add package SkbKontur.Playwright.ReactUI.Controls --version 4.2.0
NuGet\Install-Package SkbKontur.Playwright.ReactUI.Controls -Version 4.2.0
<PackageReference Include="SkbKontur.Playwright.ReactUI.Controls" Version="4.2.0" />
<PackageVersion Include="SkbKontur.Playwright.ReactUI.Controls" Version="4.2.0" />
<PackageReference Include="SkbKontur.Playwright.ReactUI.Controls" />
paket add SkbKontur.Playwright.ReactUI.Controls --version 4.2.0
#r "nuget: SkbKontur.Playwright.ReactUI.Controls, 4.2.0"
#:package SkbKontur.Playwright.ReactUI.Controls@4.2.0
#addin nuget:?package=SkbKontur.Playwright.ReactUI.Controls&version=4.2.0
#tool nuget:?package=SkbKontur.Playwright.ReactUI.Controls&version=4.2.0
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,Hint,ValidationTooltip - Навигация:
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);
💬 Работа с тултипами и подсказками
Библиотека предоставляет типизированные классы для работы с различными видами всплывающих подсказок.
Hint (подсказка при наведении)
// Получение Hint для любого контрола — автоматически выполняет hover
var hint = await button.GetTooltipAsync<Hint>().ConfigureAwait(false);
// Проверка текста подсказки
await hint.ExpectV2().ToBeVisibleAsync().ConfigureAwait(false);
await hint.ExpectV2().ToHaveTextAsync("Текст подсказки").ConfigureAwait(false);
await hint.ExpectV2().ToContainTextAsync("подсказ").ConfigureAwait(false);
InfoTooltip (информационный тултип)
// Для информационного тултипа нужно предварительно вызвать действие показа (например, hover)
await control.HoverAsync().ConfigureAwait(false);
var tooltip = await control.GetTooltipAsync<InfoTooltip>().ConfigureAwait(false);
await tooltip.ExpectV2().ToHaveTextAsync("Информация").ConfigureAwait(false);
// Закрытие тултипа с крестиком
await tooltip.CloseAsync().ConfigureAwait(false);
ValidationTooltip (валидационный тултип)
// Автоматически выполняет фокусировку контрола для отображения валидации
var validationTooltip = await input.GetTooltipAsync<ValidationTooltip>().ConfigureAwait(false);
await validationTooltip.ExpectV2().ToHaveTextAsync("Поле обязательно").ConfigureAwait(false);
Создание кастомного тултипа
public class MyTooltip : Tooltip
{
public MyTooltip(ControlBase targetControl) : base(targetControl) { }
protected override Task ShowAsync()
=> TargetControl.HoverAsync();
public Button ActionButton
=> ControlFactory.Create<Button>(ContentLocator.GetByTestId("ActionButton"));
}
// Использование
var myTooltip = await button.GetTooltipAsync<MyTooltip>().ConfigureAwait(false);
await myTooltip.ActionButton.ClickAsync().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);
Открытие модального окна из Dropdown или Kebab
// Из Dropdown по тексту
var modal = await dropdown.SelectFirstByTextAndOpenModalAsync<MyModal>("Открыть окно")
.ConfigureAwait(false);
await modal.HeaderText.ExpectV2().ToBeVisibleAsync().ConfigureAwait(false);
// Из Kebab по индексу
var sidePage = await kebab.SelectByIndexAndOpenSidePageAsync<MySidePage>(0)
.ConfigureAwait(false);
await sidePage.HeaderText.ExpectV2().ToBeVisibleAsync().ConfigureAwait(false);
// Из Dropdown по data-tid
var modal = await dropdown.SelectByDataTidAndOpenModalAsync<MyModal>("OpenModalMenuItem")
.ConfigureAwait(false);
await modal.CloseAsync().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 или выше
Запуск с конкретной версией react-ui
# Предустановленные версии
npm run storybook:v4 # @skbkontur/react-ui@4.27.0
npm run storybook:v5 # @skbkontur/react-ui@5.6.12
npm run storybook:v6 # @skbkontur/react-ui@6.0.0
npm run storybook:latest # последняя версия
# Произвольная версия
npm run storybook:custom -- 4.25.0
Запуск в Docker
.\scripts\RunStorybookInDocker.ps1
Требования: Docker
📋 Минимальные требования
- .NET Standard 2.0 / .NET 6+
- Playwright 1.58.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.58.0)
- SkbKontur.Playwright.POM.Abstractions (>= 1.0.3)
- System.Linq.Async (>= 6.0.1)
-
net6.0
- Microsoft.Playwright (>= 1.58.0)
- SkbKontur.Playwright.POM.Abstractions (>= 1.0.3)
- System.Linq.Async (>= 6.0.1)
-
net8.0
- Microsoft.Playwright (>= 1.58.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 | 174 | 4/6/2026 |
| 4.1.1 | 534 | 3/16/2026 |
| 4.1.0 | 171 | 3/16/2026 |
| 4.0.1 | 810 | 1/27/2026 |
| 4.0.0 | 98 | 1/22/2026 |
| 4.0.0-betac761fd74 | 95 | 1/20/2026 |
| 4.0.0-betac1918b74 | 101 | 1/22/2026 |
| 4.0.0-beta4ec7bd11 | 97 | 1/16/2026 |
| 4.0.0-beta2cc952c6 | 272 | 12/16/2025 |