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
相关产品推荐
相关产品推荐

