ΠΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ° Π΄Π»Ρ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ Ρ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°ΠΌΠΈ @skbkontur/react-ui ΠΏΡΠΈ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠΈ Ρ ΠΏΠΎΠΌΠΎΡΡΡ Playwright"
Install
| Product | Versions |
|---|---|
| .NET | |
| .NET Standard |
README
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/[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
Adoption Assessment
A verified publisher signal is available. Assess fit from the package's supported frameworks, license and dependency graph rather than popularity alone.
Related Guides & Workflows
Learn how to evaluate, integrate, or audit this package in your .NET project.