Skip to main content
net6.0net8.0.NETStandard2.0

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° для взаимодСйствия с ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ @skbkontur/react-ui ΠΏΡ€ΠΈ тСстировании с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Playwright"

Published
Aug 28, 2026
1mo ago
Total Downloads
16.2K
16,247

Install

dotnet add package SkbKontur.Playwright.ReactUI.Controls --version 4.3.0-beta435b1021
ProductVersions
.NET
net6.0net8.0
.NET Standard
netstandard2.0

README

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/[email protected]
npm run storybook:v5    # @skbkontur/[email protected]
npm run storybook:v6    # @skbkontur/[email protected]
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 с прСдлоТСниями ΠΏΠΎ ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡŽ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ.

Changes from Previous Version

No structural changes between v4.2.0 and v4.3.0-beta435b1021.

Adoption Assessment

A verified publisher signal is available. Assess fit from the package's supported frameworks, license and dependency graph rather than popularity alone.

This version is marked prerelease. Validate its API and upgrade path before production use.Compatibility metadata lists 3 target frameworks; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.