Автоматизация интеграционных тестов видеоплеера с помощью Playwright и Open Source Cloud

Подпишитесь на наш ТЕЛЕГРАМ КАНАЛ ПО АВТОМАТИЗАЦИИ ТЕСТИРОВАНИЯ

Даже самые простые интеграционные тесты видеоплеера могут оказаться сложными для автоматизации, особенно когда требуется проверить поведение плеера при сбоях в видеопотоке. Чтобы упростить этот сценарий, в открытом доступе есть инструмент 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».

🔥 Какой была ваша первая зарплата в QA и как вы искали первую работу? 

Мега обсуждение в нашем телеграм-канале о поиске первой работы. Обмен опытом и мнения.

Читать в телеграм

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *