Back to Repositories

Testing ResizeManager Component Observation Workflow in video.js

This test suite validates the ResizeManager component in video.js, focusing on resize observation and event handling functionality. It ensures proper initialization, fallback behavior, and event triggering mechanisms for player resizing.

Test Coverage Overview

The test suite covers essential ResizeManager functionality including ResizeObserver implementation and iframe fallback mechanisms.

  • Tests ResizeObserver availability and fallback iframe creation
  • Validates observer lifecycle methods (observe, unobserve, disconnect)
  • Verifies playerresize event triggering
  • Tests proper cleanup and disposal

Implementation Analysis

The testing approach uses QUnit framework with sinon for time manipulation and mocking.

Implementation focuses on two main patterns:
  • Mock ResizeObserver class implementation for controlled testing
  • Clock manipulation for timing-dependent operations
Tests utilize beforeEach/afterEach hooks for consistent setup and cleanup.

Technical Details

Testing infrastructure includes:

  • QUnit as the primary testing framework
  • Sinon.js for fake timers and mocking
  • TestHelpers utility for player instance creation
  • ES modules for component imports
  • Custom ResizeObserver mock implementation

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Proper test isolation through setup/teardown hooks
  • Comprehensive mock object implementation
  • Explicit state verification
  • Clear test case organization
  • Effective cleanup of resources
  • Atomic test cases with single responsibility

videojs/videoJs

test/unit/resize-manager.test.js

            
/* eslint-env qunit */
import ResizeManager from '../../src/js/resize-manager.js';
import TestHelpers from './test-helpers.js';
import sinon from 'sinon';

QUnit.module('ResizeManager', {
  beforeEach() {
    this.clock = sinon.useFakeTimers();
    this.player = TestHelpers.makePlayer();
  },
  afterEach() {
    this.player.dispose();
    this.clock.restore();
  }
});

QUnit.test('ResizeManager creates an iframe if ResizeObserver is not available', function(assert) {
  const rm = new ResizeManager(this.player, {ResizeObserver: null});

  assert.equal(rm.el().tagName.toLowerCase(), 'iframe', 'we got an iframe');
  assert.equal(rm.el().getAttribute('tabIndex'), '-1', 'TabIndex is set to -1');
  assert.equal(rm.el().getAttribute('aria-hidden'), 'true', 'aria-hidden property is set');

  rm.dispose();
});

QUnit.test('ResizeManager uses the ResizeObserver, if given', function(assert) {
  let roCreated = false;
  let observeCalled = false;
  let unobserveCalled = false;
  let disconnectCalled = false;
  let sameEl = false;

  class MyResizeObserver {
    constructor(fn) {
      roCreated = true;
    }

    observe(el) {
      observeCalled = true;
      this.el = el;
    }

    unobserve(el) {
      unobserveCalled = true;
      sameEl = this.el === el;
    }

    disconnect() {
      disconnectCalled = true;
    }
  }

  const rm = new ResizeManager(this.player, {ResizeObserver: MyResizeObserver});

  assert.ok(roCreated, 'we intantiated the RO that was passed');
  assert.ok(observeCalled, 'we observed the RO');
  assert.equal(rm.resizeObserver_.el, this.player.el(), 'we observed the player el');

  rm.dispose();

  assert.ok(unobserveCalled, 'we unobserve when disposed');
  assert.ok(sameEl, 'we unobserve the same el as we observed');
  assert.ok(disconnectCalled, 'we disconnected when disposed');
});

QUnit.test('ResizeManager triggers `playerresize` when the observer method is called', function(assert) {
  let observer;

  class MyResizeObserver {
    constructor(fn) {
      observer = fn;
    }

    observe(el) {
      this.el = el;
    }

    unobserve(el) {
    }

    disconnect() {
    }
  }

  let playerresizeCalled = 0;
  const rm = new ResizeManager(this.player, {ResizeObserver: MyResizeObserver});

  this.player.one('playerresize', function() {
    playerresizeCalled++;
  });
  observer();

  this.clock.tick(100);

  assert.equal(playerresizeCalled, 1, 'playerresize was triggered');

  rm.dispose();
});