diff --git a/docs/basic-guides/selectors.mdx b/docs/basic-guides/selectors.mdx
new file mode 100644
index 0000000..df05d98
--- /dev/null
+++ b/docs/basic-guides/selectors.mdx
@@ -0,0 +1,602 @@
+# Селекторы
+
+Testplane предоставляет множество способов для поиска элементов на странице браузера с помощью селекторов. Для этого используются библиотеки `WebDriverIO` и `testing-library`. Селекторы позволяют точно идентифицировать элементы интерфейса, что необходимо для автоматизации тестирования.
+
+## WebDriverIO
+
+WebDriverIO — это Node.js-библиотека для автоматизации браузеров, которая реализует протокол WebDriver (W3C стандарт) В Testplane она используется для управления браузерами и взаимодействия с веб-элементами.
+
+### CSS селекторы
+
+#### По классу
+
+Чтобы найти элемент на странице по классу, используйте селектор `".class-name"`.
+
+```javascript
+// Поиск кнопки с классом "btn-primary"
+const button = await browser.$(".btn-primary");
+await button.click();
+
+// Поиск нескольких элементов
+const menuItems = await browser.$$(".nav-item");
+console.log("Количество пунктов меню: ${menuItems.length}");
+```
+
+Стоит использовать, если:
+
+- класс является стабильным и не генерируется динамически;
+- нужен быстрый и простой способ найти элемент;
+- класс семантически описывает элемент (например, `.error-message`, `.success-banner`);
+- вы работаете с компонентными библиотеками, где классы являются частью API.
+
+#### По id
+
+Чтобы найти элемент по `id`, используйте селектор вида `"#id"`.
+
+```javascript
+// Поиск формы id
+const loginForm = await browser.$("#login-form");
+const isDisplayed = await loginForm.isDisplayed();
+```
+
+Стоит использовать, если:
+
+- вы работаете с критически важными элементами (формы, модальные окна, главные контейнеры);
+- `id` является частью публичного API компонента;
+- нужна максимальная производительность селектора (`id` — самый быстрый селектор).
+
+#### По типу атрибута
+
+Для поиска элемента по атрибуту, используйте селектор вида `input[type="name"]`.
+
+```javascript
+// Поиск всех чекбоксов
+const checkboxes = await browser.$$("input[type="checkbox"]");
+for (const checkbox of checkboxes) {
+ await checkbox.click();
+}
+
+// Поиск email input
+const emailInput = await browser.$("input[type="email"]");
+await emailInput.setValue("test@example.com");
+
+// Поиск скрытых полей
+const hiddenField = await browser.$("input[type="hidden"][name="csrf_token"]");
+const csrfValue = await hiddenField.getValue();
+```
+
+Стоит использовать, если:
+
+- нужно найти все элементы определённого типа (все чекбоксы, все радиокнопки);
+- вы тестируете формы и валидацию;
+- нужно работать с семантическими HTML5 типами (`email`, `tel`, `url`, `date`);
+- вам нужно убедиться, что используется правильный тип поля для `accessibility`;
+- вы тестируете различное поведение для разных типов полей.
+
+#### CSS-селекторы по атрибуту data-testid
+
+Для поиска элементов, которые помечены дял тестирования, используйте селекторы по атрибуту `data-testid`.
+
+```javascript
+// Поиск элемента по data-testid
+const userAvatar = await browser.$("[data-testid="user-avatar"]");
+await userAvatar.waitForDisplayed({ timeout: 5000 });
+
+// Клик по кнопке с data-testid
+const deleteButton = await browser.$("[data-testid="delete-user-btn"]");
+await deleteButton.click();
+
+// Получение текста из элемента
+const errorMessage = await browser.$("[data-testid="error-notification"]");
+const text = await errorMessage.getText();
+expect(text).toContain("Ошибка валидации");
+```
+
+Стоит использовать, если:
+
+- создаёте селекторы специально для тестирования;
+- нужна стабильность селекторов независимо от изменений UI/стилей;
+- работаете в команде, где дизайнеры часто меняют классы и структуру;
+- хотите явно пометить элементы, доступные для тестирования;
+
+#### CSS-комбинированные селекторы
+
+Комбинированные селекторы позволяют находить элементы в определённом контексте.
+
+```javascript
+// Потомок: кнопка внутри модального окна
+const modalButton = await browser.$(".modal .close-button");
+await modalButton.click();
+
+// Прямой потомок: первый уровень вложенности
+const navItem = await browser.$(".navigation > .nav-item");
+
+// Соседний элемент
+const errorLabel = await browser.$("input.invalid + .error-message");
+const errorText = await errorLabel.getText();
+
+// Сложная комбинация
+const activeTab = await browser.$("ul.tabs > li.active > a[href^="#"]");
+```
+
+Стоит использовать, если:
+
+- нужно найти элемент в определённом контексте;
+- работаете с повторяющейся структурой;
+- нужно убедиться в правильной вложенности элементов;
+- простые селекторы слишком неспецифичны;
+- тестируете связанные элементы.
+
+#### CSS-псевдоселекторы
+
+Псевдоселекторы позволяют выбирать элементы на основе их положения или состояния.
+
+```javascript
+// Первый элемент списка
+const firstItem = await browser.$("ul.menu > li:first-child");
+await firstItem.click();
+
+// Последний элемент
+const lastItem = await browser.$(".breadcrumb > li:last-child");
+const currentPage = await lastItem.getText();
+
+// N-ый элемент (третий пункт меню)
+const thirdItem = await browser.$(".menu-item:nth-child(3)");
+
+// Каждый второй элемент (чётные)
+const evenRows = await browser.$$("table tr:nth-child(even)");
+
+// Отключённые элементы
+const disabledButtons = await browser.$$("button:disabled");
+expect(disabledButtons.length).toBe(2);
+
+// Проверенные чекбоксы
+const checkedBoxes = await browser.$$("input[type="checkbox"]:checked");
+```
+
+Стоит использовать, если:
+
+- тестируете позиционирование элементов;
+- проверяете состояния элементов (`disabled`, `checked`, `focus`);
+- работаете с таблицами и нужно выбрать определённую строку или столбец;
+- тестируете паттерны (чётные/нечётные строки для `zebra-striping`);
+- нужно найти элемент по его позиции, когда нет других идентификаторов.
+
+### XPath селекторы
+
+#### По тексту элемента
+
+Чтобы найти элемент по содержащемуся в нем тексту, используйте селектор `//element[text()="text"]`.
+
+```javascript
+// Точное совпадение текста
+const loginButton = await browser.$("//button[text()="Войти в систему"]");
+await loginButton.click();
+
+// Частичное совпадение
+const successMessage = await browser.$("//div[contains(text(), "успешно")]");
+await successMessage.waitForDisplayed();
+
+// Текст с пробелами и переносами
+const heading = await browser.$("//h1[normalize-space()="Добро пожаловать"]");
+
+// Поиск по тексту в дочернем элементе
+const card = await browser.$("//div[@class="card"][.//h3[text()="Premium план"]]");
+
+// Case-insensitive поиск (XPath 2.0)
+const link = await browser.$("//a[contains(translate(text(), "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"), "поиск")]");
+```
+
+Стоит использовать, если:
+
+- текст элемента уникален и стабилен (названия кнопок, заголовки);
+- нет других идентификаторов (нет `data-testid`, `id`, классов);
+- тестируете, что правильный текст отображается в правильном месте;
+- работаете с динамически генерируемым контентом, где единственный стабильный элемент — текст;
+- нужно найти элемент, содержащий определённый текст внутри себя или в дочерних элементах.
+
+#### По атрибутам
+
+Для поиска элемента по атрибуту, используйте селектор вида `//element[@type="atribute"]`.
+
+```javascript
+// Поиск по одному атрибуту
+const nameInput = await browser.$("//input[@name="username"]");
+await nameInput.setValue("john_doe");
+
+// Множественные условия (AND)
+const activeModal = await browser.$("//div[@class="modal" and @data-visible="true"]");
+
+// Условие OR
+const submitBtn = await browser.$("//button[@type="submit" or @class="btn-submit"]");
+
+// Поиск по началу значения атрибута
+const imageJpg = await browser.$("//img[starts-with(@src, "/images/")]");
+
+// Поиск по концу значения атрибута
+const pdfLink = await browser.$("//a[substring(@href, string-length(@href) - 3) = ".pdf"]");
+
+// Поиск по частичному совпадению атрибута
+const dataElement = await browser.$("//div[contains(@data-component, "user-profile")]");
+
+// NOT условие
+const notDisabledButton = await browser.$("//button[not(@disabled)]");
+```
+
+Стоит использовать, если:
+
+- нужны сложные условия поиска (комбинации атрибутов);
+- работаете с динамическими атрибутами (`data`-атрибуты с переменными значениями);
+- нужна гибкость в поиске (частичные совпадения, начало/конец строки);
+- CSS-селекторы не могут выразить нужную логику;
+- нужно найти элемент по отсутствию атрибута.
+
+#### Навигация по DOM
+
+Исползуя XPath, вы можете навигировать по DOM-дереву.
+
+```javascript
+// Прямой родитель
+const parentDiv = await browser.$("//input[@name="email"]/..");
+
+// Предок с условием
+const formContainer = await browser.$("//input[@name="email"]/ancestor::form[@id="registration"]");
+
+// Следующий сиблинг
+const errorLabel = await browser.$("//input[@class="invalid"]/following-sibling::span[@class="error"][1]");
+
+// Предыдущий сиблинг
+const label = await browser.$("//input[@name="password"]/preceding-sibling::label[1]");
+
+// Все потомки
+const allInputs = await browser.$$("//form[@id="checkout"]//input");
+
+// Прямые дети
+const directChildren = await browser.$$("//ul[@class="menu"]/li");
+
+// Поиск «дяди» элемента (родитель -> сиблинг родителя)
+const siblingSection = await browser.$("//h2[text()="Контакты"]/../following-sibling::section[1]");
+```
+
+Стоит использовать, если:
+
+- нужно найти элемент относительно другого известного элемента;
+- структура DOM сложна, но относительные позиции стабильны;
+- тестируете связанные элементы (label и input, ошибка рядом с полем);
+- нужно подняться вверх по DOM-дереву от найденного элемента;
+- работаете с семантической структурой HTML (заголовок и следующая за ним секция).
+
+#### XPath: индексы и позиции
+
+XPath позволяет выбирать элементы по их позиции в наборе результатов.
+
+```javascript
+// Первый элемент в результатах XPath
+const firstButton = await browser.$("(//button[@class="action"])[1]");
+await firstButton.click();
+
+// Последний элемент
+const lastItem = await browser.$("(//li[@class="menu-item"])[last()]");
+
+// Второй элемент
+const secondRow = await browser.$("(//table[@id="results"]//tr)[2]");
+
+// Предпоследний
+const secondToLast = await browser.$("(//div[@class="card"])[last()-1]");
+
+// Диапазон элементов (все кроме первого)
+const allButFirst = await browser.$$("(//li[@class="item"])[position() > 1]");
+
+// Каждый третий элемент
+const everyThird = await browser.$$("//div[@class="grid-item"][position() mod 3 = 0]");
+```
+
+Стоит использовать, если:
+
+- нужен доступ к элементу по его позиции в наборе результатов;
+- тестируете пагинацию или списки с определённым порядком;
+- работаете с таблицами и нужна конкретная строка;
+- нужен первый или последний элемент среди нескольких одинаковых;
+- тестируете сортировку (проверка, что элемент на правильной позиции).
+
+### Селекторы по Link Text
+
+Селекторы по содержащемуся внутри тексту позволяют находить ссылки `()` по их тексту. Используйте `="text"`, чтобы найти элемент с точным текстом и `*="text"` для поиска по частичному совпадению текста.
+
+```javascript
+// Полное совпадение текста ссылки
+const loginLink = await browser.$("=Войти в систему");
+await loginLink.click();
+
+// Частичное совпадение
+const docsLink = await browser.$("*=Документация");
+await docsLink.click();
+```
+
+Стоит использовать, если:
+
+- работаете с навигационными ссылками с уникальным текстом;
+- тестируете меню и навигацию сайта;
+- текст ссылки является частью требований и не должен меняться;
+- нужна простота и читаемость теста;
+- тестируете наличие ссылок с правильным текстом на странице.
+
+### Селекторы по имени тега
+
+Чтобы найти элемент по их HTML-тегу, используйте селектор по имени тега.
+
+```javascript
+// Поиск первой кнопки на странице
+const button = await browser.$("button");
+await button.click();
+
+// Все параграфы
+const paragraphs = await browser.$$("p");
+const textsArray = await Promise.all(paragraphs.map(p => p.getText()));
+
+// Все изображения
+const images = await browser.$$("img");
+for (const img of images) {
+ const alt = await img.getAttribute("alt");
+ expect(alt).not.toBe(""); // проверка accessibility
+}
+
+// Форма
+const form = await browser.$("form");
+await form.waitForDisplayed();
+
+// Таблица
+const table = await browser.$("table");
+const rows = await table.$$("tr");
+```
+
+Стоит использовать, если:
+
+- на странице один элемент данного типа (например, единственная форма);
+- нужно получить все элементы определённого типа для массовой проверки;
+- тестируете семантичность HTML (наличие правильных тегов);
+- работаете с базовой HTML-структурой (`form`, `table`, `ul`);
+- проводите accessibility-аудит (проверка всех `img` на наличие `alt`).
+
+### React селекторы
+
+Для поиска экомпонентов в React-приложении по их имени, используйте react-селекторы, например `react$("MyButton")` найдет компонент `MyButton`, а `react$("Button" { props: { variant: "primary", size: "large"}})` найдет кнопку с определенными параметрами.
+
+```javascript
+// Поиск React-компонента по имени
+const myButton = await browser.react$("MyButton");
+await myButton.click();
+
+// С фильтрацией по параметрами
+const primaryButton = await browser.react$("Button", {
+ props: { variant: "primary", size: "large" },
+});
+
+// С фильтрацией по state
+const openModal = await browser.react$("Modal", {
+ state: { isOpen: true, activeTab: "settings" },
+});
+
+// Все экземпляры компонента
+const allCards = await browser.react$$("ProductCard");
+console.log("Найдено карточек: ${allCards.length}");
+
+// Вложенный поиск
+const form = await browser.react$("CheckoutForm");
+const submitButton = await form.react$("SubmitButton");
+
+// С комплексными параметрами
+const userProfile = await browser.react$("UserProfile", {
+ props: {
+ user: { id: 123, role: "admin" },
+ editable: true,
+ },
+});
+```
+
+Стоит использовать, если:
+
+- работаете с React-приложением и имеете доступ к исходному коду;
+- нужно найти компонент по его параметрам или `state`;
+- тестируете, что компонент рендерится с правильными данными;
+- структура `DOM` может меняться, но API компонента стабилен;
+- нужна глубокая интеграция с React DevTools.
+
+### Shadow DOM селекторы
+
+Shadow DOM селекторы позволяют работать с элементами внутри Shadow DOM — инкапсулированной части DOM-дерева. Например, если у вас есть кастомный элемент `my-custom-element`, вы можете найти кнопку внутри его Shadow DOM с помощью `shadow$("button")`.
+
+```javascript
+// Простой доступ в Shadow DOM
+const customElement = await browser.$("my-custom-element");
+const button = await customElement.shadow$("button");
+await button.click();
+
+// Множественные элементы в Shadow DOM
+const slotElements = await customElement.shadow$$(".slot-item");
+```
+
+Стоит использовать, если:
+
+- работаете с Web Components и Custom Elements;
+- приложение использует Shadow DOM для инкапсуляции стилей;
+- тестируете компоненты из сторонних библиотек (Lit, Stencil, native Web Components);
+- нужен доступ к элементам внутри shadow root;
+- работаете с дизайн-системой на базе Web Components.
+
+## Testing-library
+
+Testing Library — это адаптер популярной философии Testing Library для Testplane. Она предоставляет селекторы, ориентированные на пользовательский опыт (как пользователи находят элементы).
+
+### ByRole
+
+`getByRole` — основной метод в Testing Library, который позволяет находить элементы по их ARIA-ролям. Например, если вы используете метод `screen.getByRole("button", { name: /submit/i })`, то найдете кнопку с текстом, содержащим `submit`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск кнопки
+const submitButton = screen.getByRole("button", { name: /submit/i });
+await userEvent.click(submitButton);
+
+// Поиск текстового поля
+const emailInput = screen.getByRole("textbox", { name: /email/i });
+await userEvent.type(emailInput, "test@example.com");
+
+// Поиск чекбокса
+const agreeCheckbox = screen.getByRole("checkbox", { name: /agree to terms/i });
+await userEvent.click(agreeCheckbox);
+```
+
+Стоит использовать, если:
+
+- для любых интерактивных элементов (кнопки, ссылки, поля ввода);
+- для структурных элементов (`navigation`, `main`, `header`, `footer`);
+- для форм и их элементов (`radio`, `checkbox`, `combobox`);
+- для заголовков и важных текстовых элементов;
+- для списков и таблиц.
+
+### ByLabelText
+
+Для поиска элементов форм по тексту их меток (`label`), используйте метод `getByLabelText`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск по тексту label (полное совпадение)
+const emailInput = screen.getByLabelText("Email Address");
+await userEvent.type(emailInput, "user@example.com");
+
+// Поиск с регулярным выражением (частичное совпадение, case-insensitive)
+const passwordInput = screen.getByLabelText(/password/i);
+await userEvent.type(passwordInput, "secure123");
+```
+
+Стоит использовать, если:
+
+- работаете с формами;
+- нужно найти input, select, textarea по связанной метке;
+- занимаетесь тестированием доступности (наличие `label` обязательно для доступности);
+- метка уникальна и описательна.
+
+### ByPlaceholderText
+
+Чтобы найти поле ввода по тексту `placeholder`, используйте селектор `getByPlaceholderText`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск по placeholder
+const searchInput = screen.getByPlaceholderText("Search...");
+await userEvent.type(searchInput, "testing library");
+
+// С регулярным выражением
+const emailInput = screen.getByPlaceholderText(/enter.*email/i);
+await userEvent.type(emailInput, "test@example.com");
+```
+
+Стоит использовать, если:
+
+- у поля нет `label`, но есть `placeholder`;
+- занимаетесь тестированием legacy-кода, где `placeholder` используется вместо `label`;
+- `placeholder` достаточно описателен и уникален.
+
+### ByText
+
+Чтобы найти текстовый элемент по его содержимому, используйте метод `getByText`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск по точному тексту
+const heading = screen.getByText("Welcome to our application");
+expect(heading).toBeInTheDocument();
+
+// С регулярным выражением (частичное совпадение)
+const errorMessage = screen.getByText(/error.*occurred/i);
+expect(errorMessage).toHaveClass("error");
+```
+
+Стоит использовать, если:
+
+- необходимо найти неинтерактивные текстовые элементов (параграфы, заголовки, уведомления);
+- занимаетесь проверкой отображения текста на странице;
+- текст уникален и является частью требований.
+
+### ByDisplayValue
+
+Для поиска элемента по их текущему значению, используйте метод `getByDisplayValue`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск input с конкретным значением
+const emailInput = screen.getByDisplayValue("user@example.com");
+expect(emailInput).toBeInTheDocument();
+
+// Поиск с регулярным выражением
+const searchInput = screen.getByDisplayValue(/search query/i);
+```
+
+Стоит использовать, если:
+
+- необходимо протестировать предзаполненных форм (edit forms, profile pages);
+- нужно проверить установку корректного значения после действия;
+- необходимо найти элемент по его текущему значению, а не по label.
+
+### ByAltText
+
+Для поиска изображений по тексту `alt`, используйте метод `getByAltText`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск изображения по alt тексту
+const logo = screen.getByAltText("Company Logo");
+expect(logo).toBeInTheDocument();
+expect(logo).toHaveAttribute("src", "/images/logo.png");
+```
+
+Стоит использовать, если:
+
+- нужно работать с изображениями (`
`, ``, ``);
+- необходимо проверить доступность изображений (наличие `alt` обязательно);
+- `alt`-текст достаточно описателен и уникален.
+
+### ByTitle
+
+Чтобы найти элемент по атрибуту title, используйте метод getByTitle.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск элемента по title атрибуту
+const closeButton = screen.getByTitle("Close dialog");
+await userEvent.click(closeButton);
+```
+
+Стоит использовать, если:
+
+- необходимо работать с элементами, которые используют `title` для `tooltips`;
+- нужно протестировать `iframe`-элементы (`title` обязателен для доступности);
+- нужно взаимодействовать с `SVG`-элементами (`title` внутри `SVG` для описания).
+
+### ByTestId
+
+`getByTestId` используется как последний вариант, когда другие методы не подходят. Например, если вы используете `screen.getByTestId("submit-button")`, то найдте элемент с атрибутом `data-testid="submit-button"`
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Базовое использование
+const submitButton = screen.getByTestId("submit-button");
+await userEvent.click(submitButton);
+```
diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/basic-guides/selectors.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/basic-guides/selectors.mdx
new file mode 100644
index 0000000..df05d98
--- /dev/null
+++ b/i18n/ru/docusaurus-plugin-content-docs/current/basic-guides/selectors.mdx
@@ -0,0 +1,602 @@
+# Селекторы
+
+Testplane предоставляет множество способов для поиска элементов на странице браузера с помощью селекторов. Для этого используются библиотеки `WebDriverIO` и `testing-library`. Селекторы позволяют точно идентифицировать элементы интерфейса, что необходимо для автоматизации тестирования.
+
+## WebDriverIO
+
+WebDriverIO — это Node.js-библиотека для автоматизации браузеров, которая реализует протокол WebDriver (W3C стандарт) В Testplane она используется для управления браузерами и взаимодействия с веб-элементами.
+
+### CSS селекторы
+
+#### По классу
+
+Чтобы найти элемент на странице по классу, используйте селектор `".class-name"`.
+
+```javascript
+// Поиск кнопки с классом "btn-primary"
+const button = await browser.$(".btn-primary");
+await button.click();
+
+// Поиск нескольких элементов
+const menuItems = await browser.$$(".nav-item");
+console.log("Количество пунктов меню: ${menuItems.length}");
+```
+
+Стоит использовать, если:
+
+- класс является стабильным и не генерируется динамически;
+- нужен быстрый и простой способ найти элемент;
+- класс семантически описывает элемент (например, `.error-message`, `.success-banner`);
+- вы работаете с компонентными библиотеками, где классы являются частью API.
+
+#### По id
+
+Чтобы найти элемент по `id`, используйте селектор вида `"#id"`.
+
+```javascript
+// Поиск формы id
+const loginForm = await browser.$("#login-form");
+const isDisplayed = await loginForm.isDisplayed();
+```
+
+Стоит использовать, если:
+
+- вы работаете с критически важными элементами (формы, модальные окна, главные контейнеры);
+- `id` является частью публичного API компонента;
+- нужна максимальная производительность селектора (`id` — самый быстрый селектор).
+
+#### По типу атрибута
+
+Для поиска элемента по атрибуту, используйте селектор вида `input[type="name"]`.
+
+```javascript
+// Поиск всех чекбоксов
+const checkboxes = await browser.$$("input[type="checkbox"]");
+for (const checkbox of checkboxes) {
+ await checkbox.click();
+}
+
+// Поиск email input
+const emailInput = await browser.$("input[type="email"]");
+await emailInput.setValue("test@example.com");
+
+// Поиск скрытых полей
+const hiddenField = await browser.$("input[type="hidden"][name="csrf_token"]");
+const csrfValue = await hiddenField.getValue();
+```
+
+Стоит использовать, если:
+
+- нужно найти все элементы определённого типа (все чекбоксы, все радиокнопки);
+- вы тестируете формы и валидацию;
+- нужно работать с семантическими HTML5 типами (`email`, `tel`, `url`, `date`);
+- вам нужно убедиться, что используется правильный тип поля для `accessibility`;
+- вы тестируете различное поведение для разных типов полей.
+
+#### CSS-селекторы по атрибуту data-testid
+
+Для поиска элементов, которые помечены дял тестирования, используйте селекторы по атрибуту `data-testid`.
+
+```javascript
+// Поиск элемента по data-testid
+const userAvatar = await browser.$("[data-testid="user-avatar"]");
+await userAvatar.waitForDisplayed({ timeout: 5000 });
+
+// Клик по кнопке с data-testid
+const deleteButton = await browser.$("[data-testid="delete-user-btn"]");
+await deleteButton.click();
+
+// Получение текста из элемента
+const errorMessage = await browser.$("[data-testid="error-notification"]");
+const text = await errorMessage.getText();
+expect(text).toContain("Ошибка валидации");
+```
+
+Стоит использовать, если:
+
+- создаёте селекторы специально для тестирования;
+- нужна стабильность селекторов независимо от изменений UI/стилей;
+- работаете в команде, где дизайнеры часто меняют классы и структуру;
+- хотите явно пометить элементы, доступные для тестирования;
+
+#### CSS-комбинированные селекторы
+
+Комбинированные селекторы позволяют находить элементы в определённом контексте.
+
+```javascript
+// Потомок: кнопка внутри модального окна
+const modalButton = await browser.$(".modal .close-button");
+await modalButton.click();
+
+// Прямой потомок: первый уровень вложенности
+const navItem = await browser.$(".navigation > .nav-item");
+
+// Соседний элемент
+const errorLabel = await browser.$("input.invalid + .error-message");
+const errorText = await errorLabel.getText();
+
+// Сложная комбинация
+const activeTab = await browser.$("ul.tabs > li.active > a[href^="#"]");
+```
+
+Стоит использовать, если:
+
+- нужно найти элемент в определённом контексте;
+- работаете с повторяющейся структурой;
+- нужно убедиться в правильной вложенности элементов;
+- простые селекторы слишком неспецифичны;
+- тестируете связанные элементы.
+
+#### CSS-псевдоселекторы
+
+Псевдоселекторы позволяют выбирать элементы на основе их положения или состояния.
+
+```javascript
+// Первый элемент списка
+const firstItem = await browser.$("ul.menu > li:first-child");
+await firstItem.click();
+
+// Последний элемент
+const lastItem = await browser.$(".breadcrumb > li:last-child");
+const currentPage = await lastItem.getText();
+
+// N-ый элемент (третий пункт меню)
+const thirdItem = await browser.$(".menu-item:nth-child(3)");
+
+// Каждый второй элемент (чётные)
+const evenRows = await browser.$$("table tr:nth-child(even)");
+
+// Отключённые элементы
+const disabledButtons = await browser.$$("button:disabled");
+expect(disabledButtons.length).toBe(2);
+
+// Проверенные чекбоксы
+const checkedBoxes = await browser.$$("input[type="checkbox"]:checked");
+```
+
+Стоит использовать, если:
+
+- тестируете позиционирование элементов;
+- проверяете состояния элементов (`disabled`, `checked`, `focus`);
+- работаете с таблицами и нужно выбрать определённую строку или столбец;
+- тестируете паттерны (чётные/нечётные строки для `zebra-striping`);
+- нужно найти элемент по его позиции, когда нет других идентификаторов.
+
+### XPath селекторы
+
+#### По тексту элемента
+
+Чтобы найти элемент по содержащемуся в нем тексту, используйте селектор `//element[text()="text"]`.
+
+```javascript
+// Точное совпадение текста
+const loginButton = await browser.$("//button[text()="Войти в систему"]");
+await loginButton.click();
+
+// Частичное совпадение
+const successMessage = await browser.$("//div[contains(text(), "успешно")]");
+await successMessage.waitForDisplayed();
+
+// Текст с пробелами и переносами
+const heading = await browser.$("//h1[normalize-space()="Добро пожаловать"]");
+
+// Поиск по тексту в дочернем элементе
+const card = await browser.$("//div[@class="card"][.//h3[text()="Premium план"]]");
+
+// Case-insensitive поиск (XPath 2.0)
+const link = await browser.$("//a[contains(translate(text(), "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"), "поиск")]");
+```
+
+Стоит использовать, если:
+
+- текст элемента уникален и стабилен (названия кнопок, заголовки);
+- нет других идентификаторов (нет `data-testid`, `id`, классов);
+- тестируете, что правильный текст отображается в правильном месте;
+- работаете с динамически генерируемым контентом, где единственный стабильный элемент — текст;
+- нужно найти элемент, содержащий определённый текст внутри себя или в дочерних элементах.
+
+#### По атрибутам
+
+Для поиска элемента по атрибуту, используйте селектор вида `//element[@type="atribute"]`.
+
+```javascript
+// Поиск по одному атрибуту
+const nameInput = await browser.$("//input[@name="username"]");
+await nameInput.setValue("john_doe");
+
+// Множественные условия (AND)
+const activeModal = await browser.$("//div[@class="modal" and @data-visible="true"]");
+
+// Условие OR
+const submitBtn = await browser.$("//button[@type="submit" or @class="btn-submit"]");
+
+// Поиск по началу значения атрибута
+const imageJpg = await browser.$("//img[starts-with(@src, "/images/")]");
+
+// Поиск по концу значения атрибута
+const pdfLink = await browser.$("//a[substring(@href, string-length(@href) - 3) = ".pdf"]");
+
+// Поиск по частичному совпадению атрибута
+const dataElement = await browser.$("//div[contains(@data-component, "user-profile")]");
+
+// NOT условие
+const notDisabledButton = await browser.$("//button[not(@disabled)]");
+```
+
+Стоит использовать, если:
+
+- нужны сложные условия поиска (комбинации атрибутов);
+- работаете с динамическими атрибутами (`data`-атрибуты с переменными значениями);
+- нужна гибкость в поиске (частичные совпадения, начало/конец строки);
+- CSS-селекторы не могут выразить нужную логику;
+- нужно найти элемент по отсутствию атрибута.
+
+#### Навигация по DOM
+
+Исползуя XPath, вы можете навигировать по DOM-дереву.
+
+```javascript
+// Прямой родитель
+const parentDiv = await browser.$("//input[@name="email"]/..");
+
+// Предок с условием
+const formContainer = await browser.$("//input[@name="email"]/ancestor::form[@id="registration"]");
+
+// Следующий сиблинг
+const errorLabel = await browser.$("//input[@class="invalid"]/following-sibling::span[@class="error"][1]");
+
+// Предыдущий сиблинг
+const label = await browser.$("//input[@name="password"]/preceding-sibling::label[1]");
+
+// Все потомки
+const allInputs = await browser.$$("//form[@id="checkout"]//input");
+
+// Прямые дети
+const directChildren = await browser.$$("//ul[@class="menu"]/li");
+
+// Поиск «дяди» элемента (родитель -> сиблинг родителя)
+const siblingSection = await browser.$("//h2[text()="Контакты"]/../following-sibling::section[1]");
+```
+
+Стоит использовать, если:
+
+- нужно найти элемент относительно другого известного элемента;
+- структура DOM сложна, но относительные позиции стабильны;
+- тестируете связанные элементы (label и input, ошибка рядом с полем);
+- нужно подняться вверх по DOM-дереву от найденного элемента;
+- работаете с семантической структурой HTML (заголовок и следующая за ним секция).
+
+#### XPath: индексы и позиции
+
+XPath позволяет выбирать элементы по их позиции в наборе результатов.
+
+```javascript
+// Первый элемент в результатах XPath
+const firstButton = await browser.$("(//button[@class="action"])[1]");
+await firstButton.click();
+
+// Последний элемент
+const lastItem = await browser.$("(//li[@class="menu-item"])[last()]");
+
+// Второй элемент
+const secondRow = await browser.$("(//table[@id="results"]//tr)[2]");
+
+// Предпоследний
+const secondToLast = await browser.$("(//div[@class="card"])[last()-1]");
+
+// Диапазон элементов (все кроме первого)
+const allButFirst = await browser.$$("(//li[@class="item"])[position() > 1]");
+
+// Каждый третий элемент
+const everyThird = await browser.$$("//div[@class="grid-item"][position() mod 3 = 0]");
+```
+
+Стоит использовать, если:
+
+- нужен доступ к элементу по его позиции в наборе результатов;
+- тестируете пагинацию или списки с определённым порядком;
+- работаете с таблицами и нужна конкретная строка;
+- нужен первый или последний элемент среди нескольких одинаковых;
+- тестируете сортировку (проверка, что элемент на правильной позиции).
+
+### Селекторы по Link Text
+
+Селекторы по содержащемуся внутри тексту позволяют находить ссылки `()` по их тексту. Используйте `="text"`, чтобы найти элемент с точным текстом и `*="text"` для поиска по частичному совпадению текста.
+
+```javascript
+// Полное совпадение текста ссылки
+const loginLink = await browser.$("=Войти в систему");
+await loginLink.click();
+
+// Частичное совпадение
+const docsLink = await browser.$("*=Документация");
+await docsLink.click();
+```
+
+Стоит использовать, если:
+
+- работаете с навигационными ссылками с уникальным текстом;
+- тестируете меню и навигацию сайта;
+- текст ссылки является частью требований и не должен меняться;
+- нужна простота и читаемость теста;
+- тестируете наличие ссылок с правильным текстом на странице.
+
+### Селекторы по имени тега
+
+Чтобы найти элемент по их HTML-тегу, используйте селектор по имени тега.
+
+```javascript
+// Поиск первой кнопки на странице
+const button = await browser.$("button");
+await button.click();
+
+// Все параграфы
+const paragraphs = await browser.$$("p");
+const textsArray = await Promise.all(paragraphs.map(p => p.getText()));
+
+// Все изображения
+const images = await browser.$$("img");
+for (const img of images) {
+ const alt = await img.getAttribute("alt");
+ expect(alt).not.toBe(""); // проверка accessibility
+}
+
+// Форма
+const form = await browser.$("form");
+await form.waitForDisplayed();
+
+// Таблица
+const table = await browser.$("table");
+const rows = await table.$$("tr");
+```
+
+Стоит использовать, если:
+
+- на странице один элемент данного типа (например, единственная форма);
+- нужно получить все элементы определённого типа для массовой проверки;
+- тестируете семантичность HTML (наличие правильных тегов);
+- работаете с базовой HTML-структурой (`form`, `table`, `ul`);
+- проводите accessibility-аудит (проверка всех `img` на наличие `alt`).
+
+### React селекторы
+
+Для поиска экомпонентов в React-приложении по их имени, используйте react-селекторы, например `react$("MyButton")` найдет компонент `MyButton`, а `react$("Button" { props: { variant: "primary", size: "large"}})` найдет кнопку с определенными параметрами.
+
+```javascript
+// Поиск React-компонента по имени
+const myButton = await browser.react$("MyButton");
+await myButton.click();
+
+// С фильтрацией по параметрами
+const primaryButton = await browser.react$("Button", {
+ props: { variant: "primary", size: "large" },
+});
+
+// С фильтрацией по state
+const openModal = await browser.react$("Modal", {
+ state: { isOpen: true, activeTab: "settings" },
+});
+
+// Все экземпляры компонента
+const allCards = await browser.react$$("ProductCard");
+console.log("Найдено карточек: ${allCards.length}");
+
+// Вложенный поиск
+const form = await browser.react$("CheckoutForm");
+const submitButton = await form.react$("SubmitButton");
+
+// С комплексными параметрами
+const userProfile = await browser.react$("UserProfile", {
+ props: {
+ user: { id: 123, role: "admin" },
+ editable: true,
+ },
+});
+```
+
+Стоит использовать, если:
+
+- работаете с React-приложением и имеете доступ к исходному коду;
+- нужно найти компонент по его параметрам или `state`;
+- тестируете, что компонент рендерится с правильными данными;
+- структура `DOM` может меняться, но API компонента стабилен;
+- нужна глубокая интеграция с React DevTools.
+
+### Shadow DOM селекторы
+
+Shadow DOM селекторы позволяют работать с элементами внутри Shadow DOM — инкапсулированной части DOM-дерева. Например, если у вас есть кастомный элемент `my-custom-element`, вы можете найти кнопку внутри его Shadow DOM с помощью `shadow$("button")`.
+
+```javascript
+// Простой доступ в Shadow DOM
+const customElement = await browser.$("my-custom-element");
+const button = await customElement.shadow$("button");
+await button.click();
+
+// Множественные элементы в Shadow DOM
+const slotElements = await customElement.shadow$$(".slot-item");
+```
+
+Стоит использовать, если:
+
+- работаете с Web Components и Custom Elements;
+- приложение использует Shadow DOM для инкапсуляции стилей;
+- тестируете компоненты из сторонних библиотек (Lit, Stencil, native Web Components);
+- нужен доступ к элементам внутри shadow root;
+- работаете с дизайн-системой на базе Web Components.
+
+## Testing-library
+
+Testing Library — это адаптер популярной философии Testing Library для Testplane. Она предоставляет селекторы, ориентированные на пользовательский опыт (как пользователи находят элементы).
+
+### ByRole
+
+`getByRole` — основной метод в Testing Library, который позволяет находить элементы по их ARIA-ролям. Например, если вы используете метод `screen.getByRole("button", { name: /submit/i })`, то найдете кнопку с текстом, содержащим `submit`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск кнопки
+const submitButton = screen.getByRole("button", { name: /submit/i });
+await userEvent.click(submitButton);
+
+// Поиск текстового поля
+const emailInput = screen.getByRole("textbox", { name: /email/i });
+await userEvent.type(emailInput, "test@example.com");
+
+// Поиск чекбокса
+const agreeCheckbox = screen.getByRole("checkbox", { name: /agree to terms/i });
+await userEvent.click(agreeCheckbox);
+```
+
+Стоит использовать, если:
+
+- для любых интерактивных элементов (кнопки, ссылки, поля ввода);
+- для структурных элементов (`navigation`, `main`, `header`, `footer`);
+- для форм и их элементов (`radio`, `checkbox`, `combobox`);
+- для заголовков и важных текстовых элементов;
+- для списков и таблиц.
+
+### ByLabelText
+
+Для поиска элементов форм по тексту их меток (`label`), используйте метод `getByLabelText`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск по тексту label (полное совпадение)
+const emailInput = screen.getByLabelText("Email Address");
+await userEvent.type(emailInput, "user@example.com");
+
+// Поиск с регулярным выражением (частичное совпадение, case-insensitive)
+const passwordInput = screen.getByLabelText(/password/i);
+await userEvent.type(passwordInput, "secure123");
+```
+
+Стоит использовать, если:
+
+- работаете с формами;
+- нужно найти input, select, textarea по связанной метке;
+- занимаетесь тестированием доступности (наличие `label` обязательно для доступности);
+- метка уникальна и описательна.
+
+### ByPlaceholderText
+
+Чтобы найти поле ввода по тексту `placeholder`, используйте селектор `getByPlaceholderText`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск по placeholder
+const searchInput = screen.getByPlaceholderText("Search...");
+await userEvent.type(searchInput, "testing library");
+
+// С регулярным выражением
+const emailInput = screen.getByPlaceholderText(/enter.*email/i);
+await userEvent.type(emailInput, "test@example.com");
+```
+
+Стоит использовать, если:
+
+- у поля нет `label`, но есть `placeholder`;
+- занимаетесь тестированием legacy-кода, где `placeholder` используется вместо `label`;
+- `placeholder` достаточно описателен и уникален.
+
+### ByText
+
+Чтобы найти текстовый элемент по его содержимому, используйте метод `getByText`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск по точному тексту
+const heading = screen.getByText("Welcome to our application");
+expect(heading).toBeInTheDocument();
+
+// С регулярным выражением (частичное совпадение)
+const errorMessage = screen.getByText(/error.*occurred/i);
+expect(errorMessage).toHaveClass("error");
+```
+
+Стоит использовать, если:
+
+- необходимо найти неинтерактивные текстовые элементов (параграфы, заголовки, уведомления);
+- занимаетесь проверкой отображения текста на странице;
+- текст уникален и является частью требований.
+
+### ByDisplayValue
+
+Для поиска элемента по их текущему значению, используйте метод `getByDisplayValue`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск input с конкретным значением
+const emailInput = screen.getByDisplayValue("user@example.com");
+expect(emailInput).toBeInTheDocument();
+
+// Поиск с регулярным выражением
+const searchInput = screen.getByDisplayValue(/search query/i);
+```
+
+Стоит использовать, если:
+
+- необходимо протестировать предзаполненных форм (edit forms, profile pages);
+- нужно проверить установку корректного значения после действия;
+- необходимо найти элемент по его текущему значению, а не по label.
+
+### ByAltText
+
+Для поиска изображений по тексту `alt`, используйте метод `getByAltText`.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск изображения по alt тексту
+const logo = screen.getByAltText("Company Logo");
+expect(logo).toBeInTheDocument();
+expect(logo).toHaveAttribute("src", "/images/logo.png");
+```
+
+Стоит использовать, если:
+
+- нужно работать с изображениями (`
`, ``, ``);
+- необходимо проверить доступность изображений (наличие `alt` обязательно);
+- `alt`-текст достаточно описателен и уникален.
+
+### ByTitle
+
+Чтобы найти элемент по атрибуту title, используйте метод getByTitle.
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Поиск элемента по title атрибуту
+const closeButton = screen.getByTitle("Close dialog");
+await userEvent.click(closeButton);
+```
+
+Стоит использовать, если:
+
+- необходимо работать с элементами, которые используют `title` для `tooltips`;
+- нужно протестировать `iframe`-элементы (`title` обязателен для доступности);
+- нужно взаимодействовать с `SVG`-элементами (`title` внутри `SVG` для описания).
+
+### ByTestId
+
+`getByTestId` используется как последний вариант, когда другие методы не подходят. Например, если вы используете `screen.getByTestId("submit-button")`, то найдте элемент с атрибутом `data-testid="submit-button"`
+
+```javascript
+import { screen } from "@testing-library/dom";
+import userEvent from "@testing-library/user-event";
+
+// Базовое использование
+const submitButton = screen.getByTestId("submit-button");
+await userEvent.click(submitButton);
+```
diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/index.mdx
index de25099..035e2ea 100644
--- a/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/index.mdx
+++ b/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/index.mdx
@@ -4,36 +4,59 @@ sidebar_position: 1
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
+import Admonition from "@theme/Admonition";
-# Установка {#install}
+# Установка и настройка
-Запустите установщик testplane с помощью `npm`.
+## Системные требования
+
+Чтобы начать работу с testplane, установите `Node.js` версии 18.0 и выше.
+
+## Установка {#install}
+
+Для запуска установщика testplane, с помощью `npm` выполните следующую команду:
```bash
npm init testplane@latest YOUR_PROJECT_PATH
```
-Если вы не хотите использовать дефолты при инициализации проекта, а настроить его с помощью визарда, укажите опцию `-v`.
+Чтобы настроить проект, а не использовать дефолты при его инициализации, укажите опцию `-v`.
+
+После выполнения команды установки, в директории проекта появится следующий набор файлов и папок:
+
+```bash
+node_modules
+testplane-tests
+ example.testplane.ts
+ ts.config.json
+package-lock.json
+package.json
+testplane.config.ts
+```
## Настройка {#setup}
-После выполнения команды, указанной выше, в корне проекта сгенерится файл `testplane.config.ts` с базовой настройкой.
+В файле `testplane.config.ts` содержится базовый набор настроек для запуска тестов:
```typescript
export default {
- // https://testplane.io/ru/docs/v8/basic-guides/managing-browsers/
gridUrl: "local",
baseUrl: "http://localhost",
pageLoadTimeout: 0,
httpTimeout: 60000,
testTimeout: 90000,
resetCursor: false,
+
+ // В параметре sets содержится информация о директории, в которой находятся тесты
+ // и перечень браузеров, в которых они будут запускаться:
sets: {
desktop: {
files: ["testplane-tests/**/*.testplane.(t|j)s"],
browsers: ["chrome", "firefox"],
},
},
+
+ // В поле `browsers` описана конфигурация используемых браузеров:
browsers: {
chrome: {
headless: true,
@@ -48,9 +71,9 @@ export default {
},
},
},
+
plugins: {
"html-reporter/testplane": {
- // https://github.com/gemini-testing/html-reporter
enabled: true,
path: "testplane-report",
defaultView: "all",
@@ -60,39 +83,10 @@ export default {
};
```
-Вы можете загрузить браузеры, описанные в конфиге, отдельно от запуска самого Testplane:
+Чтобы загрузить браузеры, описанные в конфиге, отдельно от запуска самого Testplane, выполните команду:
```bash
npx testplane install-deps
```
Без предварительного запуска команды, недостающие браузеры будут автоматически загружены с первым запуском Testplane.
-
-## Создание теста {#test_creation}
-
-Перейдите в файл `tests/example.testplane.js` с тестом. В нем вы можете посмотреть пример теста или написать свой. Например,
-
-```javascript
-describe("github", async function () {
- it("should find testplane", async function ({ browser }) {
- await browser.url("https://github.com/gemini-testing/testplane");
- const elem = await browser.$("#readme h1");
-
- await expect(elem).toHaveText("Testplane");
- });
-});
-```
-
-## Запуск теста {#test_running}
-
-Теперь вы можете запустить тесты:
-
-```bash
-npx testplane
-```
-
-или запустить gui-режим и запустить тест через интерфейс в браузере
-
-```bash
-npx testplane gui
-```
diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/running-tests.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/running-tests.mdx
index 2461ca2..1283c37 100644
--- a/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/running-tests.mdx
+++ b/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/running-tests.mdx
@@ -2,54 +2,174 @@
sidebar_position: 3
---
-# Запуск тестов
+# Запуск и отладка
-Используйте команду `npx testplane` для запуска всех тестов в вашем проекте.
+## Запуск тестов
-## Запуск конкретного файла
+Для запуска тестов используйте команду:
-Если вы хотите запустить всю группу тестов, которые находятся в конкретном файле, то укажите путь к этому файлу в качестве входного параметра для testplane:
+```bash
+npx testplane
+```
+
+Также тесты можно запускать в `gui`-режиме, для этого выполните команду:
```bash
-testplane src/features/Reviews/Reviews.test/MyReview/MyReview.a11y@touch-phone.testplane.js
+npx testplane gui
```
-## Опция `--grep`
+### Запуск конкретного теста
+
+У вас имеется набор тестов и вам нужно запустить только один из них.
+
+```javascript
+const assert = require("assert");
+
+describe("tests", () => {
+ it("Проверка отображения главной страницы", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+ const title = await browser.getTitle();
+ assert.ok(title.includes("Testplane"));
+ });
+
+ it("Проверка наличия логотипа на главной странице", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+ const logo = await browser.$("a.navbar__brand");
+ const isDisplayed = await logo.isDisplayed();
+ assert.strictEqual(isDisplayed, true);
+ });
+
+ it("Проверка навигационного меню", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+ const menuItems = await browser.$$("nav.navbar a.navbar__item");
+ assert.ok(menuItems.length > 0);
+ });
+
+ it("Проверка наличия поля поиска", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+ const searchButton = await browser.$("button.DocSearch");
+ const isExisting = await searchButton.isExisting();
+ assert.strictEqual(isExisting, true);
+ });
+});
+```
-Если же вы хотите запустить конкретный тест, то воспользуйтесь опцией `--grep`, указав в качестве ее значения полное имя теста:
+В таком случае выполните команду:
```bash
-testplane --grep "Доступность Оставление отзыва"
+testplane --grep "Проверка наличия поля поиска"
```
-## Директива `.only`
+В кавычках вам необходимо передать содержимое скобок ключевого слова `it`.
-Ещё вы можете воспользоваться директивой `.only` для набора тестов `describe` и конкретного теста `it`, аналогично тому как это реализовано в `mocha` (см. раздел [exlusive tests](https://mochajs.org/#exclusive-tests)):
+### Запуск тестов в конкретных браузерах
-Например:
+По умолчанию тесты запускаются в тех браузерах, которые указаны в файле `testplane.config.ts`.
```javascript
-describe.only("Доступность", function () {
- // набор тестов...
-});
+browsers: ["chrome", "firefox"];
+```
+
+При выполнении команды `npx testplane` тесты запустятся в браузерах Google Chrome и Mozila Firefox.
+
+```bash
+# Запуск во всех браузерах (по умолчанию)
+testplane
+```
+
+Чтобы выполнить тесты в конкретном браузере, используйте команду:
+
+```bash
+# Запуск только в Chrome
+testplane --browser chrome
```
-или
+Также вы можете указать конкретный браузер для работы в теле теста.
```javascript
-it.only("Оставление отзыва", async function () {
- // код теста...
+// tests/browser-specific.test.js
+describe("Browser specific tests", () => {
+ it("should work in all browsers", async ({ browser }) => {
+ await browser.url("https://example.com");
+ });
+
+ // Пропустить тест в Safari
+ testplane.skip.in("safari", "Feature not supported in Safari");
+ it("should work only in Chrome and Firefox", async ({ browser }) => {
+ await browser.url("https://example.com");
+ // ... тело теста
+ });
+
+ // Запустить только в Chrome
+ testplane.only.in("chrome");
+ it("should work only in Chrome", async ({ browser }) => {
+ await browser.url("https://example.com");
+ // ... тело теста
+ });
});
```
-## Запуск тестов несколько раз {#running_tests_multiple_times}
-Иногда может быть полезным запустить один и тот же тест несколько раз — например, для проверки стабильности. Плагин [@testplane/test-repeater][testplane-test-repeater] позволяет запустить тесты заданное количество раз.
+### Запуск теста из конкретного файла
-После установки и включения плагина вы можете запустить тесты нужное количество раз, используя следующую команду:
+Чтобы запустить тесты из конкретного файла, выполните команду:
```bash
-npx testplane --test-repeater-repeat 5 --grep 'Имя теста'
+# Запуск конкретного файла
+testplane ../testplane-tests/example.testplane.ts
+```
+
+Где `../testplane-tests/example.testplane.ts` это путь к файлу с тестами.
+
+### Режим пользовательского интерфейса
+
+В Testplane вы можете работать с тестами в UI формате с помощью Testplane UI.
+
+
+
+О процессах установки и настройки Testplane UI вы можете прочитать в разделе [UI.](..//html-reporter//overview.mdx)
+
+## Отладка
+
+### Отладка в gui-формате
+
+Отслеживать процесс выполнения тестов очень легко, если запустить их в `gui`-режиме. В подобном формате работы html-reporter продемонстрирует, какие тесты были успешно выполнены, а в каких присутствуют ошибки и какого они характера.
+
+Тут скриншот из gui testplane
+
+### Browser.debug()
+
+В Testplane имеется встроенный инструмент для отладки — `browser.debug`.
+
+```javascript
+it("отладка с паузой", async ({ browser }) => {
+ // Открываем тестируемую страницу
+ await browser.url("/page");
+
+ // browser.debug() останавливает выполнение теста
+ // и открывает интерактивную консоль (REPL - Read-Eval-Print Loop)
+ await browser.debug();
+
+ // После вызова debug() тест приостанавливается
+ // В консоли можно вводить команды WebdriverIO в реальном времени:
+
+ // Примеры команд, которые можно вводить в REPL:
+ // > await browser.$('.button').click() - кликнуть по кнопке
+ // > await browser.getTitle() - получить заголовок страницы
+ // > await browser.$$('.items') - найти все элементы
+ // > .exit - выйти из режима отладки
+
+ // Этот код выполнится только после выхода из debug()
+ await browser.$(".button").click();
+});
```
-[testplane-test-repeater]: ../../plugins/testplane-test-repeater
+### Отладка через Testplane UI
+
+Наиболее удобным способом для работы с отладкой тестов является UI режим, в нем вы можете в реальном времени наблюдать выполнения тестов.
+
+
+
+И находить нестабильные тесты, медленные тесты или другие проблемы с помощью опций «сортировка» и «группировка».
+
+
diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/writing-tests.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/writing-tests.mdx
index 9b4bed9..8446aa6 100644
--- a/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/writing-tests.mdx
+++ b/i18n/ru/docusaurus-plugin-content-docs/current/quickstart/writing-tests.mdx
@@ -5,4 +5,558 @@ draft: true
# Написание тестов
-
+## Структура теста
+
+Блок `describe` предназначен для группировки связанных тестов.
+
+```javascript
+describe("Название группы тестов", () => {
+ it("описание того, что должно произойти", async ({ browser }) => {
+ // Тело теста
+ });
+});
+```
+
+В блоке `it` описываются тестовые сценарии.
+
+```javascript
+it("описание того, что должно произойти", async ({ browser }) => {
+ // Тело теста
+});
+```
+
+После установки testplane, вы можете ознакомиться с примером теста, для этого перейдите в папку `testplane-tests` и откройте файл `example.testplane.ts`.
+
+```javascript
+describe("test examples", () => {
+ it("docs search test", async ({ browser }) => {
+ await browser.openAndWait("https://testplane.io/");
+
+ // Find by tag name
+ const navBar = await browser.$("nav");
+
+ // Find by aria-label
+ await navBar.$("aria/Search").click();
+
+ // Find by placeholder
+ const fileSearchInput = await browser.findByPlaceholderText("Search docs");
+ await fileSearchInput.waitForDisplayed();
+ await fileSearchInput.setValue("config");
+
+ // Find by id
+ const fileSearchResults = await browser.$("#docsearch-list");
+
+ // Find by role
+ const fileSearchResultsItems = await fileSearchResults.findAllByRole("option");
+
+ await expect(fileSearchResultsItems.length).toBeGreaterThan(1);
+ });
+});
+```
+
+## Базовый синтаксис
+
+### Навигация
+
+Для перемещения по страницам используйте метод:
+
+```javascript
+await browser.url("https://testplane.io/ru/");
+```
+
+Если на странице имеются элементы, которые отображаются с задержкой, для корректного выполнения тестов укажите явное ожидание:
+
+```javascript
+await browser.url("https://testplane.io/ru/");
+await browser.$("h1").waitForExist({ timeout: 5000 });
+const title = await browser.$("h1").getText();
+```
+
+Либо используйте команду:
+
+```javascript
+await browser.openAndWait("https://testplane.io/ru/");
+```
+
+Команда `await browser.openAndWait()` по умолчанию дожидается загрузки всех необходимых элементов на странице.
+
+### Селекторы
+
+Testplane поддерживает различные стратегии поиска элементов: `CSS` селекторы (самые распространенные), текстовые селекторы (по содержимому), `XPath` для сложных запросов. Метод `$()` возвращает первый найденный элемент, а `$$()` — массив всех подходящих элементов:
+
+```javascript
+const assert = require("assert");
+
+describe("tests", () => {
+ it("Проверка отображения главной страницы", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+ const title = await browser.getTitle();
+ assert.ok(title.includes("Testplane"));
+ });
+
+ it("Проверка наличия логотипа на главной странице", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+ const logo = await browser.$("a.navbar__brand");
+ const isDisplayed = await logo.isDisplayed();
+ assert.strictEqual(isDisplayed, true);
+ });
+
+ it("Проверка навигационного меню", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+ const menuItems = await browser.$$("nav.navbar a.navbar__item");
+ assert.ok(menuItems.length > 0);
+ });
+
+ it("Проверка наличия поля поиска", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+ const searchButton = await browser.$("button.DocSearch");
+ const isExisting = await searchButton.isExisting();
+ assert.strictEqual(isExisting, true);
+ });
+});
+```
+
+### Взаимодействия с элементами
+
+После знакомства с селекторами и нахождения элемента можно выполнить различные действия: клик, ввод текста, двойной клик.
+
+```javascript
+const assert = require("assert");
+
+describe("tests, () => {
+
+ it("Пример клика - открытие поиска", async ({browser}) => {
+ await browser.url("https://testplane.io/ru/");
+
+ // Клик по кнопке поиска
+ const searchButton = await browser.$("button.DocSearch");
+ await searchButton.waitForClickable({timeout: 5000});
+ await searchButton.click();
+ await browser.pause(1000);
+
+ // Проверяем, что модальное окно поиска появилось
+ const searchModal = await browser.$(".DocSearch-Modal");
+ const isDisplayed = await searchModal.isDisplayed();
+ assert.strictEqual(isDisplayed, true);
+ });
+
+ it("Пример ввода текста - поиск по документации", async ({browser}) => {
+ await browser.url("https://testplane.io/ru/");
+
+ // Открываем поиск
+ const searchButton = await browser.$("button.DocSearch");
+ await searchButton.waitForClickable({timeout: 5000});
+ await searchButton.click();
+ await browser.pause(500);
+
+ // Вводим текст в поле поиска
+ const searchInput = await browser.$("input.DocSearch-Input");
+ await searchInput.waitForDisplayed({timeout: 5000});
+ await searchInput.setValue("browser");
+ await browser.pause(1000);
+
+ // Проверяем, что текст введен
+ const inputValue = await searchInput.getValue();
+ assert.strictEqual(inputValue, "browser");
+ });
+
+ it("Пример двойного клика - выделение текста заголовка", async ({browser}) => {
+ await browser.url("https://testplane.io/ru/");
+
+ // Находим заголовок на главной странице
+ const heading = await browser.$("h1");
+ await heading.waitForDisplayed({timeout: 5000});
+ await heading.scrollIntoView();
+ await browser.pause(500);
+
+ // Двойной клик по заголовку
+ await heading.doubleClick();
+ await browser.pause(500);
+
+ // Проверяем, что элемент существует и отображается
+ const isDisplayed = await heading.isDisplayed();
+ assert.strictEqual(isDisplayed, true);
+ });
+});
+```
+
+### Assertions
+
+Testplane задействует `expect API` из `WebdriverIO` для проверки состояния элементов и страниц — это позволяет формулировать утверждения (`assertions`) о том, какими должны быть свойства элементов или страницы в целом.
+
+```javascript
+const assert = require("assert");
+
+describe("tests", () => {
+ it("WebdriverIO assert - проверка URL", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+
+ // WebdriverIO expect для browser
+ await expect(browser).toHaveUrl("https://testplane.io/ru/");
+ });
+
+ it("WebdriverIO assert - проверка существования элемента", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+
+ const logo = await browser.$("a.navbar__brand");
+
+ // WebdriverIO expect для элемента
+ await expect(logo).toExist();
+ });
+
+ it("WebdriverIO assert - проверка видимости элемента", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+
+ const searchButton = await browser.$("button.DocSearch");
+
+ // WebdriverIO expect
+ await expect(searchButton).toBeDisplayed();
+ });
+
+ // Примеры с Jest ассертами
+ it("Jest assert - проверка заголовка страницы", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+
+ const title = await browser.getTitle();
+
+ // Jest expect
+ expect(title).toContain("Testplane");
+ });
+
+ it("Jest assert - проверка количества элементов", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+
+ const menuItems = await browser.$$("nav.navbar a.navbar__item");
+
+ // Jest expect
+ expect(menuItems.length).toBeGreaterThan(0);
+ });
+
+ it("Jest assert - проверка атрибута элемента", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+
+ const docsLink = await browser.$("a[href='/ru/docs/v8/']");
+ const href = await docsLink.getAttribute("href");
+
+ // Jest expect
+ expect(href).toBe("/ru/docs/v8/");
+ });
+
+ it("Jest assert - проверка URL с регулярным выражением", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+
+ const currentUrl = await browser.getUrl();
+
+ // Jest expect с regex
+ expect(currentUrl).toMatch(/testplane\.io/);
+ });
+});
+```
+
+### Хуки
+
+Хуки — это специальные функции, которые автоматически выполняются в определенные моменты жизненного цикла тестов. Они позволяют подготовить окружение перед тестами и очистить его после выполнения. По умолчанию доступны два вида хуков — `beforeEach` и `afterEach`, первый выполняется перед каждым тестом, а второй после.
+
+```javascript
+const assert = require("assert");
+
+describe("Примеры работы с хуками", () => {
+ // beforeEach - выполняется перед каждым тестом
+ beforeEach(async ({ browser }) => {
+ console.log("--- Выполняется BEFOREEACH - перед каждым тестом ---");
+ await browser.url("https://testplane.io/ru/");
+ await browser.pause(500);
+ });
+
+ // afterEach - выполняется после каждого теста
+ afterEach(async ({ browser }) => {
+ console.log("--- Выполняется AFTEREACH - после каждого теста ---");
+ const currentUrl = await browser.getUrl();
+ console.log("Текущий URL:", currentUrl);
+ // Можно делать скриншоты, очищать данные и т.д.
+ });
+
+ it("Тест 1 - проверка заголовка", async ({ browser }) => {
+ const title = await browser.getTitle();
+ assert.ok(title.includes("Testplane"));
+ });
+
+ it("Тест 2 - проверка логотипа", async ({ browser }) => {
+ const logo = await browser.$("a.navbar__brand");
+ const isDisplayed = await logo.isDisplayed();
+ assert.strictEqual(isDisplayed, true);
+ });
+
+ it("Тест 3 - проверка поиска", async ({ browser }) => {
+ const searchButton = await browser.$("button.DocSearch");
+ const isExisting = await searchButton.isExisting();
+ assert.strictEqual(isExisting, true);
+ });
+});
+
+describe("Пример вложенных describe с хуками", () => {
+ beforeEach(async ({ browser }) => {
+ console.log("--- OUTER BEFOREEACH ---");
+ await browser.url("https://testplane.io/ru/");
+ });
+
+ afterEach(async ({ browser }) => {
+ console.log("--- OUTER AFTEREACH ---");
+ });
+
+ it("Внешний тест", async ({ browser }) => {
+ const title = await browser.getTitle();
+ assert.ok(title.length > 0);
+ });
+
+ describe("Внутренний блок тестов", () => {
+ beforeEach(async ({ browser }) => {
+ console.log("--- INNER BEFOREEACH ---");
+ // Сначала выполнится outer beforeEach, потом этот
+ await browser.url("https://testplane.io/ru/docs/v8/");
+ });
+
+ afterEach(async ({ browser }) => {
+ console.log("--- INNER AFTEREACH ---");
+ // Сначала выполнится этот afterEach, потом outer
+ });
+
+ it("Внутренний тест 1", async ({ browser }) => {
+ const currentUrl = await browser.getUrl();
+ assert.ok(currentUrl.includes("docs"));
+ });
+
+ it("Внутренний тест 2", async ({ browser }) => {
+ const heading = await browser.$("h1");
+ const isDisplayed = await heading.isDisplayed();
+ assert.strictEqual(isDisplayed, true);
+ });
+ });
+});
+```
+
+### Ожидания
+
+Явные ожидания необходимы для работы с динамическим контентом, который загружается или изменяется асинхронно. Testplane автоматически ждет появления элементов, но для сложных сценариев можно использовать специальные методы ожидания.
+
+```javascript
+const assert = require("assert");
+
+describe("Примеры ожиданий в Testplane", () => {
+ it("Ожидание появления и кликабельности элемента", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+
+ // Ожидаем, что кнопка поиска появится на странице
+ const searchButton = await browser.$("button.DocSearch");
+ await searchButton.waitForDisplayed({
+ timeout: 5000,
+ timeoutMsg: "Кнопка поиска не появилась в течение 5 секунд",
+ });
+
+ // Ожидаем, что элемент станет кликабельным
+ await searchButton.waitForClickable({
+ timeout: 3000,
+ timeoutMsg: "Кнопка поиска не стала кликабельной",
+ });
+
+ await searchButton.click();
+
+ // Ожидаем появления модального окна поиска
+ const searchModal = await browser.$(".DocSearch-Modal");
+ await searchModal.waitForDisplayed({ timeout: 3000 });
+
+ const isDisplayed = await searchModal.isDisplayed();
+ assert.strictEqual(isDisplayed, true);
+ });
+
+ it("Ожидание изменения текста элемента", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+
+ const heading = await browser.$("h1");
+
+ // Ожидаем, что элемент будет существовать
+ await heading.waitForExist({
+ timeout: 5000,
+ timeoutMsg: "Заголовок не найден на странице",
+ });
+
+ // Ожидаем, что у элемента будет определенный текст
+ await heading.waitUntil(
+ async function () {
+ const text = await this.getText();
+ return text.length > 0;
+ },
+ {
+ timeout: 5000,
+ timeoutMsg: "Текст заголовка не появился",
+ },
+ );
+
+ const text = await heading.getText();
+ assert.ok(text.length > 0);
+ });
+
+ it("Ожидание с использованием browser.waitUntil для проверки URL", async ({ browser }) => {
+ await browser.url("https://testplane.io/ru/");
+
+ const docsLink = await browser.$("a[href='/ru/docs/v8/']");
+ await docsLink.waitForExist({ timeout: 5000 });
+
+ // Используем JavaScript click для надежности
+ await browser.execute(el => el.click(), docsLink);
+
+ // Ожидаем изменения URL с помощью browser.waitUntil
+ await browser.waitUntil(
+ async () => {
+ const currentUrl = await browser.getUrl();
+ return currentUrl.includes("docs");
+ },
+ {
+ timeout: 5000,
+ timeoutMsg: "URL не изменился на страницу документации",
+ },
+ );
+
+ const finalUrl = await browser.getUrl();
+ assert.ok(finalUrl.includes("docs"));
+ });
+});
+```
+
+### Работа с формами
+
+Testplane предоставляет специальные методы для работы с различными элементами форм. Чекбоксы и радио-кнопки управляются через клик. Для выпадающих списков `(