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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SkbKontur.Playwright.ReactUI.Controls" Version="4.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SkbKontur.Playwright.ReactUI.Controls" Version="4.2.0" />
                    
Directory.Packages.props
<PackageReference Include="SkbKontur.Playwright.ReactUI.Controls" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SkbKontur.Playwright.ReactUI.Controls --version 4.2.0
                    
#r "nuget: SkbKontur.Playwright.ReactUI.Controls, 4.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SkbKontur.Playwright.ReactUI.Controls@4.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SkbKontur.Playwright.ReactUI.Controls&version=4.2.0
                    
Install as a Cake Addin
#tool nuget:?package=SkbKontur.Playwright.ReactUI.Controls&version=4.2.0
                    
Install as a Cake Tool

Playwright.ReactUI.Controls

Библиотека для автоматизированного тестирования компонентов @skbkontur/react-ui с помощью Playwright.NET.

📋 Содержание

🚀 Быстрый старт

Инициализация контрола

// Создание экземпляра 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 UI
  • IPageFactory - фабрика для создания Page Objects
  • IAutofillDependenciesFactory - фабрика для предоставления дополнительных зависимостей
  • 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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