Back to Repositories

Testing SeekToLive Component Behavior in Video.js

This test suite validates the SeekToLive functionality in Video.js, focusing on live streaming behavior and UI controls. The tests ensure proper handling of live edge detection, UI state management, and live window display conditions.

Test Coverage Overview

The test suite provides comprehensive coverage of the SeekToLive component functionality in Video.js.

Key areas tested include:
  • Live UI state transitions between at-live and behind-live states
  • Display behavior based on live UI enablement
  • Duration change handling for live streams
  • Edge case handling for disabled live UI scenarios

Implementation Analysis

The testing approach uses QUnit framework with sinon for time manipulation and mocking. Tests utilize beforeEach/afterEach hooks for consistent setup and cleanup, with mock implementations of player methods to simulate live streaming scenarios.

Key patterns include:
  • Time-based testing using sinon clock
  • DOM computation checks for display states
  • Class presence validation for UI states

Technical Details

Testing infrastructure includes:
  • QUnit as the primary testing framework
  • Sinon.js for time manipulation and stubs
  • TestHelpers utility for player instance creation
  • Custom DOM utilities for style computation
  • Time range creation utilities for seekable range simulation

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices through isolation of test cases and thorough setup/teardown procedures.

Notable practices include:
  • Proper test isolation using beforeEach/afterEach hooks
  • Consistent state verification
  • Comprehensive edge case coverage
  • Clean mock setup and restoration

videojs/videoJs

test/unit/seek-to-live.test.js

            
/* eslint-env qunit */
import TestHelpers from './test-helpers.js';
import sinon from 'sinon';
import { computedStyle } from '../../src/js/utils/dom.js';
import { createTimeRange } from '../../src/js/utils/time.js';

QUnit.module('SeekToLive', {
  beforeEach() {
    this.clock = sinon.useFakeTimers();
    this.player = TestHelpers.makePlayer();
    this.seekToLive = this.player.controlBar.seekToLive;
    this.getComputedDisplay = () => {
      return computedStyle(this.seekToLive.el(), 'display');
    };

    this.mockLiveui = () => {
      this.player.paused = () => false;
      this.player.hasStarted = () => true;
      this.player.options_.liveui = true;
      this.player.seekable = () => createTimeRange(0, 45);
      this.player.currentTime = () => this.player.liveTracker.liveCurrentTime();
      this.player.duration(Infinity);
    };
  },
  afterEach() {
    this.player.dispose();
    this.clock.restore();
  }
});

QUnit.test('liveui enabled, can switch between at and behind live edge ', function(assert) {
  this.mockLiveui();

  assert.notEqual(this.getComputedDisplay(), 'none', 'is not hidden');
  assert.ok(this.seekToLive.hasClass('vjs-at-live-edge'), 'has at live edge class');

  this.player.currentTime = () => 0;
  this.player.seekable = () => createTimeRange(0, 38);
  this.clock.tick(30);

  assert.notOk(this.seekToLive.hasClass('vjs-at-live-edge'), 'does not have at live edge class');
});

QUnit.test('liveui enabled can show/hide on durationchange', function(assert) {
  // start out non-live
  assert.equal(this.getComputedDisplay(), 'none', 'is hidden');
  assert.notOk(this.seekToLive.hasClass('vjs-at-live-edge'), 'does not have at live edge class');

  // switch to live
  this.mockLiveui();

  assert.notEqual(this.getComputedDisplay(), 'none', 'is not hidden');
  assert.ok(this.seekToLive.hasClass('vjs-at-live-edge'), 'has at live edge class');

  // switch to non-live
  this.player.duration(20);

  assert.equal(this.getComputedDisplay(), 'none', 'is hidden');
  assert.notOk(this.seekToLive.hasClass('vjs-at-live-edge'), 'does not have at live edge class');

  // back to live again.
  this.mockLiveui();

  assert.notEqual(this.getComputedDisplay(), 'none', 'is not hidden');
  assert.ok(this.seekToLive.hasClass('vjs-at-live-edge'), 'has at live edge class');
});

QUnit.test('liveui disabled live window is never shown', function(assert) {
  assert.equal(this.getComputedDisplay(), 'none', 'is hidden');
  assert.notOk(this.seekToLive.hasClass('vjs-at-live-edge'), 'does not have at live edge class');

  this.player.paused = () => false;
  this.player.hasStarted = () => true;
  this.player.currentTime = () => this.player.liveTracker.liveCurrentTime();

  // liveui false, seekable range is good though
  this.player.options_.liveui = false;
  this.player.duration(Infinity);

  assert.equal(this.getComputedDisplay(), 'none', 'is hidden');
  assert.notOk(this.seekToLive.hasClass('vjs-at-live-edge'), 'does not have at live edge class');

  this.player.duration(10);

  // liveui false
  this.player.options_.liveui = false;
  this.player.seekable = () => createTimeRange(0, 19);
  this.player.duration(Infinity);

  assert.equal(this.getComputedDisplay(), 'none', 'is hidden');
  assert.notOk(this.seekToLive.hasClass('vjs-at-live-edge'), 'does not have at live edge class');
});