Перенос набора тестов Playwright с Applitools Eyes на Delta-QA
Набор тестов Playwright, написанный для Applitools Eyes, работает в Delta-QA после двух изменений: импорта и переменных окружения. Его eyes.open, check, close, BatchInfo, addBrowser и регионы остаются на месте.
Установите и замените импорт
Eyes API в @delta-qa/vision сохраняет имена и смысл Applitools Eyes для Playwright. Требуются Node.js 22 или новее и @playwright/test 1.62 или новее.
Vision SDK сначала доступен в раннем доступе: свяжитесь с нами, чтобы использовать его в своём наборе тестов. Запросить доступ к Vision
| Applitools | Delta-QA |
|---|---|
import { test } from "@applitools/eyes-playwright/fixture"; | import { test } from "@delta-qa/vision/eyes/fixture"; |
import type { EyesFixture } from "@applitools/eyes-playwright/fixture"; | import type { EyesFixture } from "@delta-qa/vision/eyes/fixture"; |
import { Eyes, Target, … } from "@applitools/eyes-playwright"; | import { Eyes, Target, … } from "@delta-qa/vision/eyes"; |
eyesConfig в playwright.config остаётся как есть. С фикстурой в тесте меняется только импорт:
// import { test } from "@applitools/eyes-playwright/fixture";
import { test } from "@delta-qa/vision/eyes/fixture";
test("checkout", async ({ page, eyes }) => {
await page.goto("https://shop.example/cart");
await eyes.check("Cart", { fully: true });
}); // opened before the test, closed by the fixtureЗадайте переменные окружения
| Переменная | Читается для |
|---|---|
DELTAQA_API_KEY | API-ключ вашего рабочего пространства Delta-QA (dqa_…) с ролью «Can edit», созданный в Settings → Workspace → API keys. Сохраните его в секрете вашего CI. |
APPLITOOLS_API_KEY | Читается, если DELTAQA_API_KEY не задана: оставьте переменную, но укажите в ней ключ Delta-QA. |
DELTAQA_SERVER_URL | Ваш сервер Delta-QA для установки On-Premise; если переменная не задана — облако Delta-QA. APPLITOOLS_SERVER_URL никогда не читается. |
APPLITOOLS_BATCH_ID | Тестируемая версия — коммит. id пакета, заданный в коде, имеет приоритет. |
APPLITOOLS_BRANCH | Ветка. setBranchName в коде имеет приоритет. |
APPLITOOLS_PARENT_BRANCHAPPLITOOLS_BASELINE_BRANCH | Базовая ветка, эталон которой используется, пока у ветки нет своего. APPLITOOLS_BASELINE_BRANCH имеет приоритет над APPLITOOLS_PARENT_BRANCH; код — над обеими. |
Формы _NAME переменных ветки (APPLITOOLS_BRANCH_NAME, APPLITOOLS_PARENT_BRANCH_NAME, APPLITOOLS_BASELINE_BRANCH_NAME) тоже читаются. Пустая переменная считается незаданной. Без ключа открытие теста завершается ошибкой, в которой названа переменная, которую нужно задать.
Эти переменные Applitools не читаются и не вызывают предупреждения: APPLITOOLS_SERVER_URL, APPLITOOLS_BATCH_NAME, APPLITOOLS_DONT_CLOSE_BATCHES, APPLITOOLS_SHOW_LOGS.
Настройте CI
SDK не читает ни git, ни переменные вашего CI: строки ниже берут из них ветку, базовую ветку и коммит и записывают их в три переменные Applitools.
GitHub Actions
При push github.head_ref пуст: веткой тогда служит github.ref_name. В pull request github.sha — это merge-коммит, который создаёт GitHub, а не запушенный коммит: head-коммит имеет приоритет.
env:
APPLITOOLS_BRANCH: ${{ github.head_ref || github.ref_name }}
APPLITOOLS_PARENT_BRANCH: ${{ github.base_ref || github.event.repository.default_branch }}
APPLITOOLS_BATCH_ID: ${{ github.event.pull_request.head.sha || github.sha }}GitLab CI
В пайплайне merge request CI_MERGE_REQUEST_TARGET_BRANCH_NAME — целевая ветка; в пайплайне ветки она пуста.
script:
- export APPLITOOLS_BRANCH="${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME:-$CI_COMMIT_REF_NAME}"
- export APPLITOOLS_PARENT_BRANCH="${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-$CI_DEFAULT_BRANCH}"
- export APPLITOOLS_BATCH_ID="$CI_COMMIT_SHA"
- npx playwright testBitbucket Pipelines
BITBUCKET_PR_DESTINATION_BRANCH задаётся только в пайплайне pull request.
script:
- export APPLITOOLS_BRANCH="$BITBUCKET_BRANCH"
- export APPLITOOLS_PARENT_BRANCH="$BITBUCKET_PR_DESTINATION_BRANCH"
- export APPLITOOLS_BATCH_ID="$BITBUCKET_COMMIT"
- npx playwright testAzure Pipelines
Переменные System.PullRequest задаются только в сборке pull request, в виде refs/heads/… для Azure Repos. Build.SourceBranchName сохраняет только последний сегмент имени ветки (feature/cart даёт cart), поэтому ветка читается из полного ref.
- script: |
branch="${SYSTEM_PULLREQUEST_SOURCEBRANCH:-$BUILD_SOURCEBRANCH}"
base="${SYSTEM_PULLREQUEST_TARGETBRANCH:-}"
export APPLITOOLS_BRANCH="${branch#refs/heads/}"
export APPLITOOLS_PARENT_BRANCH="${base#refs/heads/}"
export APPLITOOLS_BATCH_ID="${SYSTEM_PULLREQUEST_SOURCECOMMITID:-$BUILD_SOURCEVERSION}"
npx playwright testБазовая ветка, совпадающая с веткой, не используется: на ветке по умолчанию эти строки не дают базовой ветки.
Закрывайте в teardown, никогда в теле теста
С фикстурой eyes закрывается в teardown теста. Без неё вызывайте eyes.close() в afterEach, а runner.getAllTestResults() — в afterAll.
Никогда не закрывайте в теле теста: ожидание вердикта расходует время теста — по умолчанию 30 секунд в Playwright Test, — а шаг, упавший до close(), оставляет тест открытым. У teardown собственный таймаут.
import { test } from "@playwright/test";
import { Eyes, Target, VisualGridRunner } from "@delta-qa/vision/eyes";
const runner = new VisualGridRunner();
let eyes: Eyes;
test.beforeEach(async ({ page }) => {
eyes = new Eyes(runner);
await eyes.open(page, "Shop", test.info().title);
});
test("checkout", async ({ page }) => {
await page.goto("https://shop.example/cart");
await eyes.check("Cart", Target.window().fully());
});
test.afterEach(async () => {
await eyes.close(); // throws DiffsFoundError when a difference awaits a judgment
});
test.afterAll(async () => {
await runner.getAllTestResults();
});Каждая настройка Applitools и во что она превращается
Принимается любая настройка Applitools Eyes: набор тестов компилируется и выполняется. Каждая либо применяется Delta-QA, либо принимается без эффекта, с предупреждением. Нескольких вызовов нет.
Применяются
| Настройка | В Delta-QA |
|---|---|
appName | Приложение теста; вместе с именем теста оно идентифицирует тест. В eyesConfig, если не задано, — My App, как в фикстуре Applitools. |
testName | Имя теста, его ключ: изменённое имя — это новый тест. В eyesConfig это может быть и функция от теста; без него — путь заголовков теста без файла (describe > test), как в фикстуре Applitools. |
apiKeysetApiKey | Ключ вместо DELTAQA_API_KEY или APPLITOOLS_API_KEY — ключ Delta-QA. Он никогда не появляется ни в сообщении, ни в логе, ни в ссылке. |
branchName | Ветка запуска; без неё — APPLITOOLS_BRANCH, затем APPLITOOLS_BRANCH_NAME. |
parentBranchNamebaselineBranchName | Базовая ветка: baselineBranchName раньше parentBranchName; без них — их переменные в том же порядке. |
batch | Его id — тестируемая версия, то есть коммит; без него — APPLITOOLS_BATCH_ID; без обоих — одна версия на процесс (см. отличия ниже). |
saveNewTests | Становятся ли страницы нового теста его эталоном; если не задано — true. |
viewportSize | Размер, который задаётся странице при открытии теста. |
browsersInfoaddBrowser(width, height) | Каждый размер — это окружение, для Chrome или без имени браузера. Язык, часовой пояс, тема и плотность экрана берутся из браузера теста. |
fullyfully(true) | Вся страница — то, что Delta-QA проверяет в любом случае. |
withNamename | Имя проверки. |
Target.window | Страница теста. |
Target.regionCheckSettings.regioncheckRegioncheckRegionBycheckRegionByElementcheckElementcheckElementBy | Единственная сравниваемая часть страницы: первый элемент, на который указывает локатор, селектор или хэндл элемента, как в Applitools; побеждает последний заданный регион. Игнорируемые регионы внутри него исключаются. |
ignoreRegionsignoreRegionignoreignores | Каждый элемент, на который указывает регион — локатор, селектор, { selector, type }, хэндл элемента, — исключается из сравнения: каждый элемент локатора, как в Applitools. Также форма { region } и ключ ignoreRegions в объектной форме. |
eyesConfig.failTestsOnDiff | Что роняет вердикт, отличный от PASSED, в фикстуре: 'afterEach' роняет тест в его teardown; 'afterAll' роняет воркер после завершения его тестов; false ничего не роняет, но вердикт всё равно ожидается. Без него — 'afterAll', если задана переменная CI, и 'afterEach' в остальных случаях, как это решает код фикстуры Applitools. |
eyesConfig.afterAll | Вызывается после завершения тестов воркера, с результатом каждого. |
Вызовы
| Вызов | В Delta-QA |
|---|---|
open(page, appName, testName, viewportSize?) | Тест идентифицируется по приложению и имени: изменённое имя — это новый тест. Размер viewport задаётся странице. |
check(name?, Target.window())checkWindow(tag?) | Проверяет страницу в текущем виде в каждом окружении. Проверка без имени сопоставляется по адресу своей страницы; две проверки с одинаковым именем допускаются. Возвращает MatchResult без вердикта, как check в Applitools: вердикт приходит при закрытии. |
close(throwErr = true) | Ожидает вердикт: DiffsFoundError при различии, требующем решения, NewTestError при новом тесте, требующем решения (saveNewTests(false)), TestFailedError при различии, признанном багом, или при сбое. Сообщение содержит ссылку на версию в Delta-QA. |
closeAsync()runner.getAllTestResults(throwErr = true) | closeAsync() закрывает без ожидания; runner ждёт каждый вердикт, закрывает оставшийся открытым тест и выбрасывает ошибку для теста, который не прошёл, — ошибка closeAsync() сохраняется для него. |
abort()abortIfNotClosed()abortAsync() | Закрывает, не дожидаясь вердикта, и ничего не роняет: результаты помечаются как прерванные, без результата; null, если открытого теста нет. Delta-QA всё равно сравнивает запуски, и версия показывает их результат. |
Принимаются без эффекта
Настройка, которую Delta-QA не применяет, не роняет тест: тест выполняется без неё. При первом использовании в процессе выдаётся предупреждение Node.js с её именем и кодом DELTAQA_IGNORED_SETTING; последующие использования проходят молча, а node --disable-warning=DELTAQA_IGNORED_SETTING отключает такие предупреждения. Пустое значение — setX(process.env.VARIABLE) вне CI — считается незаданной настройкой и не вызывает предупреждения. Ниже приведены имена в том виде, в каком их выдаёт предупреждение.
Настройки сравнения
Уровни совпадения, регионы по уровню совпадения, плавающие регионы и смещения настраивают сравнение Applitools. Delta-QA сравнивает страницу так, как это сделал бы человеческий глаз, без уровня допуска, который нужно настраивать: каждое различие показывается, и человек оценивает его в Delta-QA.
matchLeveldefaultMatchSettingsenablePatternsignoreDisplacementsignoreCaretuseDomsendDomCheckSettings.matchLevelCheckSettings.layoutCheckSettings.exactCheckSettings.strictCheckSettings.contentCheckSettings.ignoreColorsCheckSettings.dynamicCheckSettings.enablePatternsCheckSettings.ignoreDisplacementsCheckSettings.ignoreCaretCheckSettings.ignoreMismatchCheckSettings.useDomCheckSettings.sendDomCheckSettings.layoutRegionCheckSettings.layoutRegionsCheckSettings.strictRegionCheckSettings.strictRegionsCheckSettings.contentRegionCheckSettings.contentRegionsCheckSettings.floatingCheckSettings.floatingsCheckSettings.floatingRegionCheckSettings.floatingRegionsCheckSettings.dynamicRegionCheckSettings.dynamicRegions
Настройки снимка
Склейка, прокрутка, обрезка, ожидания и отладочные снимки определяют снимок Applitools. Delta-QA проверяет всю страницу в том виде, в каком её оставил тест в момент вызова check: чтобы дождаться контента или загрузить ленивую секцию, сделайте это в тесте, до проверки.
hideCarethideScrollbarsforceFullPageScreenshotstitchModestitchOverlapscrollRootElementcutrotationwaitBeforeScreenshotswaitBeforeCapturematchTimeoutsaveDebugScreenshotsdebugScreenshotsPathdebugScreenshotsPrefixfully(false)CheckSettings.fully(false)CheckSettings.scrollRootElementCheckSettings.stitchModeCheckSettings.timeoutCheckSettings.waitBeforeCaptureCheckSettings.lazyLoadCheckSettings.useSystemScreenshot
Браузеры, устройства и окружения
Delta-QA рендерит в Chromium: учитывается размер, переданный в addBrowser, а не названный браузер, поэтому два браузера одного размера — это одно окружение. Устройство из грида Applitools (DeviceName, IosDeviceName, эмуляция, мультиустройства) не добавляет окружения. Язык, часовой пояс, тема и плотность экрана берутся из браузера теста, а метки окружений ничего не меняют. ClassicRunner и VisualGridRunner ведут себя одинаково.
addBrowser(chrome-one-version-back)addBrowser(chrome-two-versions-back)addBrowser(firefox)addBrowser(firefox-one-version-back)addBrowser(firefox-two-versions-back)addBrowser(safari)addBrowser(safari-one-version-back)addBrowser(safari-two-versions-back)addBrowser(edgechromium)addBrowser(edgechromium-one-version-back)addBrowser(edgechromium-two-versions-back)addBrowser(edgelegacy)addBrowser(ie)addBrowser(ie10)addBrowser(device)addDeviceEmulationaddMultiDeviceTargetmobileOptionscaptureStatusBarlayoutBreakpointsCheckSettings.layoutBreakpointsenvironmentNameenvNamebaselineEnvNamedeviceInfohostApphostAppInfohostOShostOSInfoscaleRatioCheckSettings.densityMetricseyesConfig.type
Грид рендеринга Applitools
Опции рендеринга, хуки, загрузка ресурсов, кеши и параллелизм грида Applitools не имеют аналогов: страница проверяется в том виде, в каком её оставил тест. Скрипт, который вы запускали в хуке, запускается в тесте, до проверки.
visualGridOptionsCheckSettings.ufgOptionCheckSettings.ufgOptionsCheckSettings.visualGridOptionCheckSettings.visualGridOptionsCheckSettings.variationGroupIdCheckSettings.hookCheckSettings.beforeRenderScreenshotHookCheckSettings.webHookdisableBrowserFetchingCheckSettings.disableBrowserFetchingdisableNMLUrlCacheautProxybypassCSPskipRootHtmlResourceconcurrentSessionsRunnerOptions.testConcurrencyRunnerOptions.fetchConcurrencyRunnerOptions.removeDuplicateTests
Пакеты, эталоны и результаты
Версия несёт коммит: у неё нет ни имени, ни последовательности, ни свойств, ни уведомлений, и закрывать её не нужно. Эталон меняется, только когда человек оценивает различие в Delta-QA; тест без эталона — «Новый». Проверки сопоставляются по имени, иначе по адресу своей страницы. isDisabled: тест, который должен выполняться без проверки, не открывает Eyes.
BatchInfo.nameBatchInfo.sequenceNameBatchInfo.startedAtBatchInfo.notifyOnCompletionBatchInfo.propertiesBatchInfo.buildIddontCloseBatchesBatchClosepropertiesremoveSessionsaveDiffssaveFailedTestsignoreBaselinedisplayNamesessionTypeCheckSettings.pageIdisDisabled
Git
SDK не читает git: передайте базовую ветку через parentBranchName или baselineBranchName, а коммит — через id пакета или APPLITOOLS_BATCH_ID.
compareWithParentBranchignoreGitMergeBasegitMergeBaseTimestamplatestCommitInfo
Сервер, подключение и логи
Они относятся к серверу Applitools, подключению к нему и его логам. Сервер Delta-QA читается из DELTAQA_SERVER_URL; SDK не пишет логов Applitools и не генерирует событий Applitools.
serverUrlproxyagentIdhttpVersionconnectionTimeoutEyes.onEyes.setLogHandlerEyes.addSessionEventHandlereyesConfig.logConfigRunnerOptions.maskLog
Функции вне Delta-QA
Delta-QA не проверяет доступность, не читает Figma и не имеет проверки на естественном языке; у страницы Playwright нет web view.
accessibilityValidationCheckSettings.accessibilityRegionCheckSettings.accessibilityRegionsfigmaBaselinesfigmaOptionsnlpOptionsTarget.webviewCheckSettings.webview
Регионы без элемента
Delta-QA находит элементы, которые отличаются. У региона, заданного координатами ({ x, y, width, height }, { left, top, width, height }), нет аналога: страница сравнивается без него — целиком, если это Target.region. Зона — это сам элемент, без отступов; regionId именует регион в дашборде Applitools. С Target.frame или Target.shadow страница сравнивается целиком, а регион, заданный затем селектором, роняет проверку с TypeError: зона — это элемент самой страницы.
CheckSettings.ignoreRegions(coordinates)Target.region(coordinates)CodedRegion.paddingCodedRegion.regionIdTarget.frameTarget.shadowCheckSettings.frameCheckSettings.shadow
Неизвестный ключ в объектной форме конфигурации или проверки вызывает предупреждение со своим именем (CheckSettings.<key> в проверке).
Отсутствуют: что не компилируется
Это не настройки: они возвращают данные, которых у Delta-QA нет, или проверяют изображение, а не страницу. Набор тестов, который их использует, не компилируется — вместо того чтобы получить выдуманное значение.
| Отсутствует | Почему |
|---|---|
eyes.locateeyes.extractTexteyes.extractTextRegions | Они возвращают регионы или текст, которые Applitools считывает со своего снимка. |
eyes.checkImageTarget.imageTarget.bufferTarget.base64Target.pathTarget.url | Delta-QA проверяет страницы, а не изображения. |
eyes.getLoggereyes.logger | Лог Applitools. |
eyes.run | В фикстуре Applitools — её проверка на естественном языке. |
Отличия от Applitools
Осознанные решения Delta-QA, о которых стоит знать до первого запуска.
| Ситуация | Delta-QA |
|---|---|
| Сопоставление проверки с эталоном | По имени проверки, если каждое имя уникально в тесте; иначе по порядку, по имени, а при его отсутствии — по адресу страницы: добавленная или удалённая проверка не сдвигает остальные. |
| Изменение, принятое на ветке | Эталоны не сливаются автоматически из одной ветки в другую. Когда то же различие появляется на другой ветке, Delta-QA предлагает «Already intended on … — apply?». |
| Принятие различия | «Ожидаемо» действует на отмеченные вами ветки. |
Нет ни APPLITOOLS_BATCH_ID, ни id пакета | Одна версия на процесс: каждый воркер Playwright Test — отдельный процесс, поэтому несколько воркеров дают несколько версий — и с фикстурой тоже. Задайте в APPLITOOLS_BATCH_ID коммит вашего CI, чтобы получить одну общую версию. |
| Игнорируемый регион, которому не соответствует ни один элемент | Исключается, и проверка отправляется без него, как в Applitools, — а предупреждение Node.js с кодом DELTAQA_IGNORED_REGION называет его, один раз на регион и процесс (node --disable-warning=DELTAQA_IGNORED_REGION его отключает). Проверяемый регион, которому ничего не соответствует, роняет проверку с ZoneNotFoundError, как в Applitools. |
runner.getAllTestResults() и тест, оставшийся открытым | Тест закрывается, и выносится его вердикт; Applitools его прерывает. |
Фикстура: eyesConfig на верхнем уровне playwright.config и в проекте | Конфигурация проекта заменяет верхнеуровневую — так Playwright Test передаёт опцию; test.use добавляет свои ключи к конфигурации проекта. Фикстура Applitools объединяет обе по ключам. |
Фикстура: type: 'classic' с browsersInfo | Каждый размер — это окружение, как с ClassicRunner вне фикстуры; фикстура Applitools отбрасывает размеры. type вызывает предупреждение. |
Фикстура: expect(page).toHaveScreenshot() | Собственный метод Playwright Test: expect — тот, что из @playwright/test. Фикстура Applitools превращает его в проверку Eyes. |
| Тест, оставшийся без проверки 30 минут | Delta-QA закрывает его; затем close() читает его вердикт. |
Данные, которые вы отправляете
То, что отправляет SDK, — страницы, которые проверяют ваши тесты, и файлы, которые они используют, — служит только для их сравнения. Ответственность за тестирование на персональных данных production лежит на вас: запускайте набор тестов на тестовых данных.
Vision SDK: проверки Delta-QA в ваших тестах Playwright
Applitools, Applitools Eyes и Eyes являются товарными знаками Applitools Ltd. Delta-QA не связана с Applitools, не одобрена и не спонсируется ею.
Запустите свой набор тестов Eyes в Delta-QA
Чтобы использовать Vision, свяжитесь с нами: сначала он доступен в раннем доступе. Расскажите, какие тесты вы хотите проверять, и мы откроем вам доступ.