You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 6单元测试:如何Stub未定义的videojs?

解决Angular 6 Jasmine测试中videojs is not defined的问题

你遇到的核心问题是:Jasmine测试环境并没有加载Video.js库,而你的组件直接引用了全局的videojs变量,导致测试时触发未定义错误。咱们可以通过全局模拟videojs函数的方式快速解决,不用尝试把它当成Angular可注入服务(它本来就不是)。

方法一:全局模拟videojs Spy函数

修改你的单元测试代码,在测试初始化阶段给window对象挂载一个模拟的videojs间谍函数,这样组件调用videojs时就会使用这个模拟实现,不会报错:

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { TestDetailsComponent } from './test-details.component';

fdescribe('TestDetailsComponent', () => {
  let component: TestDetailsComponent;
  let fixture: ComponentFixture<TestDetailsComponent>;
  // 声明videojs的spy变量,方便后续验证调用
  let videojsSpy: jasmine.Spy;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [TestDetailsComponent],
      schemas: [CUSTOM_ELEMENTS_SCHEMA]
      // 移除无效的providers配置,因为videojs不是Angular注入token
    }).compileComponents();
  }));

  beforeEach(() => {
    // 在window对象上模拟全局videojs变量
    videojsSpy = jasmine.createSpy('videojs').and.returnValue({
      // 可根据测试需求,模拟player的方法,比如play()、pause()等
    });
    (window as any).videojs = videojsSpy;

    fixture = TestBed.createComponent(TestDetailsComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
    // 额外验证:确保videojs按预期参数被调用
    expect(videojsSpy).toHaveBeenCalledWith(
      jasmine.any(Element),
      { controls: true, autoplay: false, preload: 'auto' }
    );
  });
});

关键修改说明

  • 删掉了providers数组里的{ provide: videojs, useValue: {} }:videojs是全局变量,不是Angular的依赖注入token,这么配置完全无效
  • 在beforeEach中给window挂载模拟的videojs:让组件能找到全局的videojs变量,避免未定义错误
  • 新增调用验证:通过spy可以确认videojs是否按预期参数被调用,让测试更严谨

进阶优化建议(可选)

如果想提升组件的可测试性和可维护性,建议把Video.js的调用封装成Angular服务,避免直接依赖全局变量。比如:

1. 封装Video.js服务

import { Injectable } from '@angular/core';
declare const videojs: any;

@Injectable({ providedIn: 'root' })
export class VideoJsService {
  createPlayer(element: HTMLElement, options: any) {
    return videojs(element, options);
  }
}

2. 组件中注入服务替代全局调用

import { AfterViewInit, Component } from '@angular/core';
import { VideoJsService } from './video-js.service';

@Component({
  selector: 'test-details',
  templateUrl: './test-details.component.html'
})
export class TestDetailsComponent implements AfterViewInit {
  public videoJSplayer: any;

  constructor(private videoJsService: VideoJsService) {}

  ngAfterViewInit(): void {
    this.initVideo();
  }

  public initVideo(): void {
    this.videoJSplayer = this.videoJsService.createPlayer(
      document.getElementById('video_player_id'),
      { controls: true, autoplay: false, preload: 'auto' }
    );
  }
}

3. 测试时Mock服务

// 在TestBed的providers中配置mock服务
providers: [
  { 
    provide: VideoJsService, 
    useValue: { createPlayer: jasmine.createSpy('createPlayer').and.returnValue({}) } 
  }
]

这种方式更符合Angular的依赖注入规范,后续测试和维护都会更轻松。

内容的提问来源于stack exchange,提问作者AngularM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:46:59