Привет, Testplane 9!
Встречайте Testplane 9: в этой версии заметно улучшились визуальные проверки, стала удобнее работа с глобальными объектами и появилось несколько полезных улучшений во всем фреймворке.
Переход на Testplane 9
Руководство по миграции находится здесь. Ниже — обзор новых возможностей.
Полностью новый assertView
Главное изменение в Testplane 9 — полностью переработанная логика работы assertView.
Она лучше справляется с реальными интерфейсами: длинными страницами, скроллируемыми контейнерами, sticky-заголовками, fixed-оверлеями, шторками, модальными окнами, псевдоэлементами, тенями, обводками и другими случаями, из-за которых визуальные проверки часто становятся нестабильными.
Длинные скриншоты и контейнеры со скроллом
assertView теперь гораздо лучше работает с элементами, которые не помещаются в один вьюпорт.
Команда может автоматически определить, какой элемент нужно скроллить, найти неподвижные элементы и корректно обработать элементы с нестабильной высотой.
Код теста
Testplane:
it("should capture a screenshot with assertView", async ({ browser }) => {
await browser.url("file:///page.html");
await browser.assertView("visual-engine-comparison", "[data-testid=list-container]");
});
Playwright:
test("should capture a scrollable drawer list with toHaveScreenshot", async ({ page }) => {
await page.goto("file:///page.html");
await expect(page.locator("[data-testid=list-container]")).toHaveScreenshot(
"visual-engine-comparison.png",
);
});
- Testplane v9
- Testplane v8
- Playwright



Избегание мешающих элементов
В Testplane v9 assertView умеет скроллить элемент так, чтобы в итоговый скриншот не попадали наложения и нежелательные элементы.
Код теста
Testplane:
it("should capture a screenshot of review item", async ({ browser }) => {
await browser.url("file:///page.html");
await browser.$(".Review.Review_hasReactions.ReviewViewer-Review").scrollIntoView();
await browser.assertView(
"visual-engine-comparison",
".Review.Review_hasReactions.ReviewViewer-Review",
);
});
Playwright:
test("should capture a screenshot of review item", async ({ page }) => {
await page.goto("file:///page.html");
const el = await page.locator(".Review.Review_hasReactions.ReviewViewer-Review").first();
await el.scrollIntoViewIfNeeded();
await expect(el).toHaveScreenshot("review.png");
});
| Testplane v9 | Testplane v8 | Playwright |
|---|---|---|
![]() | ![]() |
Sticky- и fixed-элементы
Новая механика assertView вычисляет безопасную область до и во время съемки, поэтому sticky-заголовки, fixed-футеры и оверлеи не попадают в итоговый скриншот.
Код теста
Testplane:
it("captures a card with fixed page chrome around it", async ({ browser }) => {
await browser.url("file:///page.html");
await browser.assertView("analytics-card", "[data-testid=analytics-card]");
});
Playwright:
test("captures a card with fixed page chrome around it", async ({ page }) => {
await page.goto("file:///page.html");
await expect(page.locator("[data-testid=analytics-card]")).toHaveScreenshot(
"analytics-card.png",
);
});
| Testplane v9 | Testplane v8 | Playwright |
|---|---|---|
![]() | ![]() | ![]() |
Элементы с нестабильной высотой и lazy-load-контентом
В Testplane 9 assertView умеет работать с контентом, который подгружается при скролле, и заранее прогружать всю нужную область.
Если даже после такой прогрузки высота элемента меняется в процессе снятия скриншота, assertView постарается сделать скриншот без видимых разрывов.
Код и сравнение скриншотов
it("should capture a full page screenshot with assertView", async ({browser}) => {
await browser.url("https://sp.yandex.ru/s7");
await browser.execute(() => {
document.querySelectorAll('.DialElement_root__CftHX h1').forEach(h1 => {
h1.style.display = 'none';
});
});
await browser.assertView("visual-engine-comparison", "#__next");
});
Примечание: изображения ниже сильно сжаты из-за большого исходного размера.
Кликните на изображение, чтобы открыть его в новой вкладке.
| Testplane v9 | Testplane v8 | Playwright |
|---|---|---|
![]() | ![]() | ![]() |
Подавление hover-эффектов
В команде assertView появилась опция disableHover, которая подавляет hover-эффекты во время снятия скриншота.
По умолчанию она включается автоматически, когда для того, чтобы снять скриншот элемента целиком, нужен скролл.
Примечание: на скриншоте Testplane v8 прямоугольниками выделены области, где видны hover-эффекты. В Testplane v9 их нет.
| Testplane v9 | Testplane v8 | Playwright |
|---|---|---|
![]() | ![]() | ![]() |
Поддержка псевдоэлементов
Обновленный assertView умеет снимать псевдоэлементы, например ::before и ::after.
В Testplane v8 для этого приходилось писать кастомную команду, которая сначала рисовала прямоугольник примерно поверх элемента, а затем снимала скриншот этой области.
В Testplane v9 assertView работает с псевдоэлементами наравне с обычными элементами.
| Testplane v9 | Testplane v8 | Playwright |
|---|---|---|
![]() | ![]() | TypeError: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined |
Другие заметные улучшения
В Testplane 9 есть и другие изменения, которые делают визуальное тестирование удобнее и стабильнее:
- Значение
toleranceпо умолчанию теперь3.0, а не2.3, как в Testplane v8. То есть по умолчанию проверкиassertViewстали немного менее строгими. - Поддержка симуляторов iOS 26+ с новым Safari.
- Опция
cropMarginsдля обрезки скриншотов. Она полезна для обрезки скроллбаров в окружениях, где их нельзя скрыть. - Улучшенная отладка скриншотов: подробный лог и пошаговые скриншоты.
Асинхронный конфиг и lifecycle-хуки
Конфиг Testplane теперь может быть асинхронной функцией. Это позволяет, например, загружать секреты, обращаться к внешним сервисам, готовить временные тестовые данные или вычислять настройки браузеров перед запуском.
import type { ConfigInput } from "testplane";
export default async (): Promise<ConfigInput> => {
const baseUrl = await getPreviewUrl();
return {
baseUrl,
browsers: {
chrome: {
desiredCapabilities: { browserName: "chrome" },
},
},
};
};
prepareEnvironment тоже может быть асинхронным:
import type { ConfigInput } from "testplane";
const config: ConfigInput = {
prepareEnvironment: async () => {
process.env.AUTH_TOKEN = await createTestToken();
},
browsers: {
chrome: {
desiredCapabilities: { browserName: "chrome" },
},
},
};
export default config;
Некоторые lifecycle-события теперь тоже умеют ждать асинхронные обработчики, включая CLI и NEW_BROWSER.
const fs = require("node:fs/promises");
module.exports = testplane => {
testplane.on(testplane.events.CLI, async cli => {
const environments = JSON.parse(await fs.readFile("./test-envs.json", "utf8"));
cli.option("--env <name>", `Environment: ${environments.join(", ")}`);
});
};
Testplane больше не засоряет глобальный namespace
Исторически тесты Testplane опирались на глобальные объекты вроде it, describe, beforeEach, afterEach, testplane.* и hermione.*. В Testplane 9 эти хелперы явно экспортируются из пакета и по умолчанию не добавляются в глобальное пространство, чтобы не конфликтовать с другими test runner'ами:
import { describe, it, beforeEach } from "testplane";
describe("profile", () => {
beforeEach(async ({ browser }) => {
await browser.url("/profile");
});
it("shows user name", async ({ browser }) => {
await expect(browser.$("[data-testid=user-name]")).toHaveText("Alice");
});
});
Но можно и вернуть всё как было: достаточно установить пакет @testplane/globals.
Удаление automationProtocol: "devtools" и изменения в браузерных настройках по умолчанию
Testplane 9 использует WebDriver как единственный automationProtocol. Старый режим automationProtocol: "devtools" удален, локальный запуск браузеров можно делать с помощью gridUrl: "local".
Примечание: CDP-протокол и все, что с ним связано, по-прежнему можно использовать. Это изменение касается только опции automationProtocol.
Прекращение поддержки Node 18 и 20
Testplane 9 необходима Node 22 или новее для работы (мы рекомендуем v22.12+).












