Перейти к основному содержимому

Написание тестов

Структура теста

describe("Название группы тестов", () => {
it("Описание того, что должно произойти", async ({ browser }) => {
// Тело теста
});
});
  • describe группирует связанные тесты
  • it описывает конкретный тестовый сценарий
  • browser — объект браузера для взаимодействия со страницей

После установки Testplane можно ознакомиться с примером теста в файле testplane-tests/example.testplane.ts.

Пример теста
example.testplane.ts

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);
});
});

Базовый синтаксис

Навигация

Для перемещения по страницам используйте метод browser.url():

await browser.url("https://example.com/");

Для ожидания загрузки страницы используйте browser.openAndWait():

await browser.openAndWait("https://example.com/", {
waitNetworkIdle: true,
timeout: 10000,
});

Команда openAndWait дожидается загрузки страницы и сетевой активности.

Селекторы

Testplane поддерживает различные стратегии поиска элементов. Метод $() возвращает первый найденный элемент, а $$() — массив всех подходящих:

describe("Примеры селекторов", () => {
it("Поиск элементов", async ({ browser }) => {
await browser.url("https://example.com/");

// CSS-селекторы (рекомендуется)
const heading = await browser.$("h1");
const button = await browser.$('[data-testid="submit"]');

// Поиск нескольких элементов
const links = await browser.$$("a");
expect(links.length).toBeGreaterThan(0);
});
});

Типы селекторов

describe("Типы селекторов", () => {
it("CSS-селекторы", async ({ browser }) => {
// Рекомендуется: data-атрибуты (стабильны, не зависят от верстки)
const button = await browser.$('[data-testid="submit-button"]');

// Хорошо: CSS-классы и теги
const logo = await browser.$("a.navbar__brand");
const heading = await browser.$("h1");
});

it("Текстовые селекторы", async ({ browser }) => {
// Поиск по точному тексту
const link = await browser.$("a=Документация");

// Поиск по частичному совпадению
const button = await browser.$("button*=Начать");
});

it("XPath", async ({ browser }) => {
// Поиск по тексту внутри элемента
const element = await browser.$("//button[contains(text(), 'Поиск')]");

// Поиск родительского элемента
const parent = await browser.$("//a[@class='logo']/parent::div");
});
});

Приоритет использования:

  1. Data-атрибуты ([data-testid="..."]) — самый надежный способ
  2. CSS-селекторы (классы, ID, теги) — для стабильных элементов
  3. Текстовые селекторы — когда нет других вариантов
  4. XPath — только для сложных случаев

Избегайте:

  • Сложных CSS-селекторов, зависящих от структуры DOM
  • Селекторов по порядковому номеру (:nth-child)
  • XPath без необходимости (медленнее CSS)

Взаимодействие с элементами

Клик

it("Клик по кнопке", async ({ browser }) => {
await browser.url("https://example.com/");

const button = await browser.$("button");
await button.waitForClickable();
await button.click();

// Проверяем результат
const result = await browser.$(".result");
await expect(result).toBeDisplayed();
});

Ввод текста

it("Ввод текста в поле", async ({ browser }) => {
await browser.url("https://example.com/login");

const input = await browser.$('input[name="email"]');
await input.setValue("user@example.com");

// Проверяем введенное значение
await expect(input).toHaveValue("user@example.com");
});

Работа с формами

it("Работа с чекбоксами и селектами", async ({ browser }) => {
await browser.url("https://example.com/form");

// Чекбокс
const checkbox = await browser.$('input[type="checkbox"]');
await checkbox.click();
await expect(checkbox).toBeSelected();

// Выпадающий список
const select = await browser.$("select");
await select.selectByVisibleText("Option 1");
await expect(select).toHaveValue("1");
});

Assertions

Testplane использует expect API из WebdriverIO для проверки состояния элементов и страниц.

WebdriverIO expect

it("проверки элементов", async ({ browser }) => {
await browser.url("https://example.com/");

const heading = await browser.$("h1");

// Проверка существования и видимости
await expect(heading).toExist();
await expect(heading).toBeDisplayed();

// Проверка текста
await expect(heading).toHaveText("Example Domain");
await expect(heading).toHaveTextContaining("Example");

// Проверка браузера
await expect(browser).toHaveUrl("https://example.com/");
await expect(browser).toHaveTitle("Example Domain");
});

Jest expect

it("проверки значений", async ({ browser }) => {
await browser.url("https://example.com/");

const title = await browser.getTitle();
expect(title).toContain("Example");

const links = await browser.$$("a");
expect(links.length).toBeGreaterThan(0);
});
  • Используйте WebdriverIO expect для проверок элементов ($, $$) и браузера (browser). Он автоматически повторяет проверку до успеха или таймаута.
  • Применяйте Jest expect для проверок простых значений (строк, чисел, массивов), которые не требуют ожидания.

Хуки

Хуки позволяют подготовить окружение перед тестами и очистить его после выполнения.

describe("Работа с хуками", () => {
beforeEach(async ({ browser }) => {
// Выполняется перед каждым тестом
await browser.url("https://example.com/");
});

afterEach(async ({ browser }) => {
// Выполняется после каждого теста
await browser.deleteAllCookies();
});

it("Первый тест", async ({ browser }) => {
// Страница уже открыта благодаря beforeEach
const title = await browser.getTitle();
expect(title).toContain("Example");
});

it("Второй тест", async ({ browser }) => {
// Страница снова открыта, cookies очищены
const heading = await browser.$("h1");
await expect(heading).toExist();
});
});

Ожидания

Явные ожидания необходимы для работы с динамическим контентом:

it("Ожидание элементов", async ({ browser }) => {
await browser.url("https://example.com/");

const button = await browser.$("button");

// Ожидание появления
await button.waitForDisplayed({ timeout: 5000 });

// Ожидание кликабельности
await button.waitForClickable({ timeout: 3000 });

// Ожидание существования
await button.waitForExist({ timeout: 5000 });

await button.click();
});

Кастомные ожидания

it("Кастомное ожидание", async ({ browser }) => {
await browser.url("https://example.com/");

// Ожидание изменения URL
await browser.waitUntil(
async () => {
const url = await browser.getUrl();
return url.includes("success");
},
{
timeout: 5000,
timeoutMsg: "URL не изменился на success",
},
);
});

Визуальное тестирование

Testplane позволяет делать скриншоты элементов и сравнивать их с эталонными изображениями с помощью команды assertView.

При первом запуске теста создаются эталонные скриншоты. При последующих запусках Testplane сравнивает новые скриншоты с эталонами и сообщает о различиях. Если различий нет, тест проходит. Если есть различия, тест падает, а diff-изображение сохраняется для анализа.

it("Визуальная проверка кнопки", async ({ browser }) => {
await browser.url("https://example.com/");

// Скриншот элемента
await browser.assertView("button-default", "button");

// Клик и проверка нового состояния
await browser.$("button").click();
await browser.assertView("button-clicked", "button");
});

Параметры assertView

it("assertView с параметрами", async ({ browser }) => {
await browser.url("https://example.com/");

await browser.assertView("form", ".form", {
// Игнорировать элементы при сравнении
ignoreElements: [".dynamic-date", ".random-id"],

// Допустимое отклонение в пикселях
tolerance: 5,

// Задержка перед скриншотом (для анимаций)
screenshotDelay: 100,

// Отключить анимации
disableAnimation: true,
});
});

Скриншот всего viewport

it("Скриншот viewport", async ({ browser }) => {
await browser.url("https://example.com/");

// Без селектора — скриншот текущего viewport
await browser.assertView("full-page");
});

Работа с JavaScript

Метод execute() выполняет JavaScript-код в контексте страницы:

it("Выполнение JavaScript", async ({ browser }) => {
await browser.url("https://example.com/");

// Работа с localStorage
await browser.execute(() => {
localStorage.setItem("token", "abc123");
});

const token = await browser.execute(() => {
return localStorage.getItem("token");
});
expect(token).toBe("abc123");

// Передача параметров
const sum = await browser.execute((a, b) => a + b, 5, 10);
expect(sum).toBe(15);
});
Ограничения browser.execute

Код в browser.execute() выполняется в браузере, а не в Node.js. Вы не можете использовать Node.js модули (fs, path) или обращаться к файловой системе.

Шаги теста (runStep)

Команда runStep позволяет структурировать тест и улучшить читаемость отчетов:

it("Оформление заказа", async ({ browser }) => {
await browser.runStep("Открыть каталог", async () => {
await browser.url("/catalog");
await browser.$(".products").waitForDisplayed();
});

await browser.runStep("Добавить товар в корзину", async () => {
await browser.$(".product-card button").click();
await expect(browser.$(".cart-count")).toHaveText("1");
});

await browser.runStep("Оформить заказ", async () => {
await browser.url("/checkout");
await browser.$('button[type="submit"]').click();
});
});

Шаги отображаются в HTML-отчете, что упрощает отладку упавших тестов.

Что дальше?

Теперь, когда вы знаете основы написания тестов, изучите: