Сохранение скриншотов с временными метками

Protractor, будучи инструментом для end-to-end тестирования Angular и других веб-приложений, предоставляет возможности для взаимодействия с браузером и получения данных о состоянии страницы. Одной из часто используемых техник является сохранение скриншотов, особенно с временными метками, что облегчает диагностику и сопоставление с событиями тестирования.


Подключение необходимых модулей

Для работы с файлами и генерации скриншотов используются стандартные модули Node.js:

const fs = require('fs');
const path = require('path');

Protractor предоставляет метод browser.takeScreenshot(), который возвращает строку в формате base64, представляющую текущее состояние страницы. Для удобства хранения рекомендуется создавать отдельную папку для скриншотов, например screenshots.


Генерация временной метки

Временная метка позволяет уникально идентифицировать каждый скриншот. Обычно используют формат YYYY-MM-DD_HH-MM-SS, чтобы было легко сортировать файлы:

function getTimestamp() {
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, '0');
    const day = String(now.getDate()).padStart(2, '0');
    const hours = String(now.getHours()).padStart(2, '0');
    const minutes = String(now.getMinutes()).padStart(2, '0');
    const seconds = String(now.getSeconds()).padStart(2, '0');
    return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;
}

Такой подход исключает коллизии имен файлов даже при быстром последовательном выполнении тестов.


Сохранение скриншота

Метод browser.takeScreenshot() возвращает промис, который разрешается в base64-строку. Для записи в файл используется fs.writeFileSync:

async function saveScreenshot(filenamePrefix = 'screenshot') {
    const timestamp = getTimestamp();
    const screenshotPath = path.join('screenshots', `${filenamePrefix}_${timestamp}.png`);
    const pngBase64 = await browser.takeScreenshot();
    fs.writeFileSync(screenshotPath, pngBase64, { encoding: 'base64' });
    console.log(`Скриншот сохранён: ${screenshotPath}`);
}

Ключевые моменты:

  • Используется асинхронная функция, так как browser.takeScreenshot() возвращает промис.
  • filenamePrefix позволяет различать скриншоты по сценарию, например login_page или checkout_error.
  • Сохраняется в формате PNG, что обеспечивает совместимость с большинством инструментов просмотра и анализа.

Интеграция с Protractor тестами

Скриншоты обычно сохраняют:

  1. После выполнения определённого шага.
  2. В случае ошибки или падения теста.

Пример интеграции с тестом Jasmine:

describe('Тестирование страницы логина', () => {
    it('Должен отображать форму входа', async () => {
        await browser.get('https://example.com/login');
        await saveScreenshot('login_page');
        const loginForm = element(by.id('loginForm'));
        expect(await loginForm.isPresent()).toBe(true);
    });

    afterEach(async function() {
        if (this.currentTest.state === 'failed') {
            await saveScreenshot('error');
        }
    });
});

Особенности реализации:

  • afterEach позволяет автоматически сохранять скриншоты только при ошибках, экономя место на диске.
  • Префиксы файлов могут быть динамическими, включая имя теста или шага, что облегчает поиск конкретного события.

Создание папки для скриншотов

Чтобы избежать ошибок записи, необходимо проверять существование папки:

function ensureDirectoryExistence(dirPath) {
    if (!fs.existsSync(dirPath)) {
        fs.mkdirSync(dirPath, { recursive: true });
    }
}

// Вызов перед сохранением скриншота
ensureDirectoryExistence('screenshots');

Использование recursive: true гарантирует создание вложенных директорий при необходимости.


Варианты улучшения и автоматизации

  1. Интеграция с отчетами: можно сохранять путь к скриншоту в HTML или Allure отчете.
  2. Разделение по дате: создавать подкаталоги screenshots/YYYY-MM-DD для удобной организации.
  3. Автоматическое сжатие PNG: для экономии места на диске при большом количестве тестов.
  4. Скриншоты отдельных элементов: вместо всей страницы использовать element.takeScreenshot() (доступно через WebDriver API), что уменьшает размер файла и акцентирует внимание на проблемной области.

Пример структуры проекта

project/
│
├─ e2e/
│  ├─ tests/
│  │  └─ login.spec.js
│  ├─ helpers/
│  │  └─ screenshotHelper.js
│  └─ screenshots/
│     └─ 2026-01-07_login_page_14-23-45.png
│
└─ protractor.conf.js

helpers/screenshotHelper.js может содержать функции getTimestamp, ensureDirectoryExistence и saveScreenshot для повторного использования в разных тестах.


Примечания по надежности

  • Скриншоты лучше делать после await browser.sleep(1000) или ожидания элемента, чтобы страница успела полностью загрузиться.
  • Base64-конвертация и запись в файл — синхронная операция (writeFileSync) может блокировать поток, но для тестов это допустимо. Для крупных наборов тестов можно использовать асинхронную запись fs.promises.writeFile.
  • Временные метки должны формироваться локально в местном часовом поясе, чтобы совпадали с логами тестов.

Система скриншотов с временными метками повышает прозрачность тестирования, позволяет быстро идентифицировать проблемы и обеспечивает надёжное хранение визуальных доказательств работы приложения.