Подпишитесь на наш ТЕЛЕГРАМ КАНАЛ ПО АВТОМАТИЗАЦИИ ТЕСТИРОВАНИЯ
Даже самые простые интеграционные тесты видеоплеера могут оказаться сложными для автоматизации, особенно когда требуется проверить поведение плеера при сбоях в видеопотоке. Чтобы упростить этот сценарий, в открытом доступе есть инструмент Chaos Stream Proxy. И в этой статье рассмотрим, как можно автоматизировать интеграционное тестирование видеоплеера с помощью Playwright и Chaos Stream Proxy, размещенного в Open Source Cloud. Такие тесты легко интегрируются в CI/CD-процесс — как на GitHub, так и в других пайплайнах.
Управление хаосом в видеоптоке
Chaos Stream Proxy — это прокси-сервер, который располагается между «идеальным» live- или VOD-потоком, и намеренно вносит ошибки в поток в соответствии с заданными параметрами. Например, чтобы вызвать таймаут во втором сегменте видео, в плеер можно передать следующий URL:
https://<chaos-stream-proxy>/api/v2/manifests/hls/proxy-master.m3u8?url=<vodUrl>&timeout=[{i:1}]
В этом случае второй сегмент (индексация начинается с 0) из <vodUrl> не будет загружен.
Самый быстрый способ начать работу — зарегистрировать аккаунт в Open Source Cloud и развернуть собственный экземпляр Chaos Stream Proxy без необходимости создавать для него собственную инфраструктуру.
Читайте также: Как проводить тестирование стримов. Примеры тест-кейсов.
Настройка тестового видеоплеера
В этом примере создадим видеоплеер на основе библиотеки web-player, способный воспроизводить как HLS, так и MPEG-DASH потоки. Сначала инициализируется новый Node-проект:
npm init
Значения, вводимые при инициализации, сейчас не принципиальны. Затем устанавливаем библиотеку web-player-core:
npm install --save @eyevinn/web-player-core
Далее создадим простую HTML-страницу в папке проекта player/index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Web Player Example</title>
<script type="module" src="./index.js"></script>
</head>
<body>
<input
type="text"
name="manifest-url"
id="manifest-input"
placeholder="Paste a Stream URI here..."
/>
<button id="load-button">LOAD</button>
<div id="player"></div>
</body>
</html>
А также JavaScript-файл player/index.js для плеера:
import WebPlayer, { PlayerEvent } from '@eyevinn/web-player-core';
async function main() {
const manifestInput = document.querySelector('#manifest-input');
const loadButton = document.querySelector('#load-button');
const root = document.querySelector('#player');
const video = document.createElement('video');
root.appendChild(video);
const player = new WebPlayer({
video: video
});
player.on(PlayerEvent.ERROR, ({ errorData, fatal }) => {
console.error(JSON.stringify(errorData));
});
async function load() {
console.log('Loading manifest:', manifestInput.value);
await player.load(manifestInput.value, true);
}
loadButton.onclick = async () => {
await load();
};
}
window.onload = main;
Затем используется parcel для сборки web-bundle и запуска встроенного сервера:
npm install --save-dev parcel
В файл package.json в секцию scripts добавляется строка:
"player": "parcel -p 1234 player/index.html --no-cache"
Теперь вы можете запустить команду npm run player и открыть браузер по адресу http://localhost:1234.

Достаточно ввести URL видеопотока, нажать кнопку LOAD — и видео будет воспроизведено.
End-to-end тестирование с Playwright
Теперь можно установить Playwright — фреймворк для написания end-to-end тестов в современных веб-браузерах:
npm install --save-dev @playwright/test
Затем создаем файл конфигурации playwright.config.ts в корневой папке проекта:
import { PlaywrightTestConfig, devices } from '@playwright/test';
const config: PlaywrightTestConfig = {
testDir: "tests/",
use: {
trace: 'on-first-retry',
// Necessary to get the media codecs to play video (default 'chromium' doesn't have them)
channel: 'chrome'
},
webServer: {
command: 'npm run player',
port: 1234,
reuseExistingServer: true,
},
projects: [
{
name: 'setup csp',
testMatch: /global\.setup\.ts/,
teardown: 'cleanup csp'
},
{
name: 'cleanup csp',
testMatch: /global\.teardown\.ts/
},
{
name: 'chromium with csp',
use: {
...devices['Desktop Chrome'],
launchOptions: {
args: ['--disable-web-security']
}
},
dependencies: ['setup csp'],
}
],
};
export default config;
Мы не будем подробно останавливаться на каждой строке. Дополнительная информация доступна в официальной документации на сайте Playwright, а здесь рассмотрим только важные для примера части.
Чтобы запускать веб-приложение видеоплеера, можно использовать уже разработанный плеер, собрать и обслуживать его с помощью Parcel. В конфигурации Playwright мы указываем, что сначала нужно поднять сервер командой npm run player.
Настройка Chaos Stream Proxy
Далее определяем глобальные скрипты установки (setup) и удаления (teardown), которые запускаются перед выполнением любых тестов. В этих скриптах будет запускаться и удаляться экземпляр Chaos Stream Proxy. Для этого необходимо установить клиентскую библиотеку для Open Source Cloud API:
npm install --save-dev @osaas/client-core
Затем рассмотрим скрипт настройки (setup), который размещается в папке tests и называется global.setup.ts:
import { test as setup } from '@playwright/test';
import { Context, createInstance } from '@osaas/client-core';
const delay = ms => new Promise(res => setTimeout(res, ms));
setup('create a chaos stream proxy', async ({}) => {
console.log('Creating Chaos Stream Proxy in Open Source Cloud...');
const ctx = new Context();
try {
const serviceAccessToken = await ctx.getServiceAccessToken(
'eyevinn-chaos-stream-proxy'
);
const instance = await createInstance(
ctx,
'eyevinn-chaos-stream-proxy',
serviceAccessToken,
{
name: 'webplayer'
},
);
await delay(5000);
process.env.CSP_URL = instance.url;
} catch (err) {
console.error('Failed to create Chaos Stream Proxy:', err);
}
});
На этом этапе создаем контекст Open Source Cloud, а затем получаем Service Access Token для сервиса Chaos Stream Proxy. Дадим экземпляру имя webplayer. После этого выдерживаем паузу 5 секунд, чтобы инстанс успел инициализироваться, и URL прокси сохранился в переменной окружения.
Теперь рассмотрим teardown-скрипт в той же папке (global.teardown.ts):
import { test as teardown } from '@playwright/test';
import { Context, removeInstance } from '@osaas/client-core';
teardown('remove chaos stream proxy', async ({}) => {
console.log('Removing Chaos Stream Proxy in Open Source Cloud...');
const ctx = new Context();
try {
const serviceAccessToken = await ctx.getServiceAccessToken(
'eyevinn-chaos-stream-proxy'
);
await removeInstance(
ctx,
'eyevinn-chaos-stream-proxy',
'webplayer',
serviceAccessToken
);
} catch (err) {
console.error('Failed to remove Chaos Stream Proxy:', err);
}
});
В этом случае ожидать полного удаления не требуется.
Написание теста
Теперь, когда все готово для тестов, можно приступать к их написанию. Напомним, что настроена подписка на событие ошибки плеера, и при его возникновении ошибка просто логируется в консоль. На практике такие события обычно отправляются в backend для аналитики.
player.on(PlayerEvent.ERROR, ({ errorData, fatal }) => {
console.error(JSON.stringify(errorData));
});
Итак, в первом тесте надо проверить, что событие действительно обрабатывается и плеер реагирует так, как задумано, — выводит JSON с ошибкой в консоль.
Для этого создаем файл в папке tests, который назовем error-reporting.spec.ts и начнем его со следующих строк:
import { test, expect } from '@playwright/test';
test('emits player error event on segment timeout', async ({ page }) => {
const cspUrl = `${process.env.CSP_URL}/api/v2/manifests/hls/proxy-master.m3u8`;
Как видно, URL Chaos Stream Proxy берется из переменной окружения, заданной в setup-скрипте.
const testVod = 'https://maitv-vod.lab.eyevinn.technology/VINN.mp4/master.m3u8';
const corruptionUrl = `${cspUrl}?url=${testVod}&timeout=[{i:1}]`;
Далее объявляется корректный VOD и формируется «испорченный» вариант — с таймаутом на втором сегменте. Далее загружаем приложение видеоплеера, подставляем URL и нажимаем кнопку загрузки. На этот раз все сделаем с помощью кода:
await page.goto('index.html');
await page.locator('#manifest-input').fill(corruptionUrl);
await page.locator('#load-button').click();
await page.locator('video').waitFor();
Ожидаем появления элемента <video>. Далее перехватываем вывод в консоль, парсим сообщение и проверяем, что ошибка действительно является сетевой:
const msg = await page.waitForEvent('console');
const error = JSON.parse(msg.text());
expect(error.category).toEqual('networkError');
});
Сложим все это вместе и получим вот что:
import { test, expect } from '@playwright/test';
test('emits player error event on segment timeout', async ({ page }) => {
const cspUrl = `${process.env.CSP_URL}/api/v2/manifests/hls/proxy-master.m3u8`;
const testVod = 'https://maitv-vod.lab.eyevinn.technology/VINN.mp4/master.m3u8';
const corruptionUrl = `${cspUrl}?url=${testVod}&timeout=[{i:1}]`;
await page.goto('index.html');
await page.locator('#manifest-input').fill(corruptionUrl);
await page.locator('#load-button').click();
await page.locator('video').waitFor();
const msg = await page.waitForEvent('console');
const error = JSON.parse(msg.text());
expect(error.category).toEqual('networkError');
});
И наконец пришло время реализовать это на практике. Перед запуском теста нужно поставить зависимости Playwright:
npx playwright install --with-deps
Затем можно выполнить тест при помощи команды:
OSC_ACCESS_TOKEN=<osc-personal-access-token> npx playwright test
Где OSC_ACCESS_TOKEN — это персональный токен доступа, который можно найти в настройках Open Source Cloud.
Добавление теста в GitHub
Теперь этот тест можно подключить к CI/CD, например, запускать его для всех pull request’ов в GitHub с помощью workflow:
name: Run integration tests
on: [pull_request]
jobs:
test:
if: "!contains(github.event.pull_request.title, 'WIP!')"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '21.x'
- name: Install dependencies
run: npm ci
- name: Install Playwright
run: npm run test:install
- name: Run Playwright tests
run: npm test
env:
OSC_ACCESS_TOKEN: ${{secrets.OSC_ACCESS_TOKEN}}
При этом в разделе scripts файла package.json должны быть указаны:
"scripts": {
"player": "parcel -p 1234 player/index.html --no-cache",
"test:install": "playwright install --with-deps",
"test": "playwright test"
},
Это был базовый пример того, как можно использовать подобный подход.
Перевод статьи «Automating Video Player Integration Tests using Playwright and Open Source Cloud».