You need to enable JavaScript to run this app. Angular Jest测试报Cannot read property 'login' of undefined问题求助
优惠活动
大模型
产品
解决方案
定价
更多

Angular Jest测试报Cannot read property 'login' of undefined问题求助

问题排查与修复方案

错误原因列表

    1. 服务注入时机错误:你在异步配置TestBed的流程中,没有等待TestBed编译完成就调用injectMocked注入服务,导致authenticationService为undefined,这是本次报错的直接原因。
    1. 依赖导入缺失:组件使用了Angular响应式表单,但测试模块仅导入了模板驱动表单需要的FormsModule,缺少响应式表单依赖ReactiveFormsModule,会导致表单初始化失败。
    1. Mock服务返回值不符合要求:MockAuthenticationService的login方法没有返回Observable对象,组件调用login后执行订阅操作会抛出异常。
    1. 测试逻辑不成立:测试用例没有触发登录提交操作,直接断言login被调用1次,逻辑本身不成立。
    1. 冗余代码:定义了未使用的authServiceMock变量,可直接删除。

修正后的测试代码

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { of } from 'rxjs';
import { LoginComponent } from './login.component';
import {AuthenticationService} from '../../../services/authentication.service';
import { createComponent, Page, injectMocked } from '@webex/common/test-utils';


const MockAuthenticationService = {
  // 让mock的login返回空的Observable,符合接口要求
  login: jest.fn(() => of({})),
};

class LoginPage extends Page<LoginComponent> {
  constructor(fixture: ComponentFixture<LoginComponent>) {
    super(fixture);
  }
  // 封装页面元素操作方法,方便测试调用
  get usernameInput() { return this.query<HTMLInputElement>('#username'); }
  get passwordInput() { return this.query<HTMLInputElement>('#password'); }
  get submitBtn() { return this.query<HTMLButtonElement>('button[type="submit"]'); }
}

describe('LoginComponent', () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;
  let page: LoginPage;
  let authenticationService: jest.Mocked<AuthenticationService>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ LoginComponent ],
      providers: [
        {
          provide: AuthenticationService,
          useValue: MockAuthenticationService,
        },
      ],
      imports: [
        FormsModule,
        // 新增响应式表单依赖
        ReactiveFormsModule
      ],
      schemas: [NO_ERRORS_SCHEMA],
    })
    // 等待TestBed编译完成
    .compileComponents()
    .then(() => {
      // 编译完成后再注入服务
      authenticationService = injectMocked(AuthenticationService);
    });
  }));

  beforeEach(() => {
    ({ fixture, component, page } = createComponent(LoginComponent, LoginPage));
    fixture.detectChanges();
  });

  it('should call login method when submit valid form', () => {
    // 1. 填充有效表单值
    page.usernameInput.value = 'testUser';
    page.usernameInput.dispatchEvent(new Event('input'));
    page.passwordInput.value = 'testPass';
    page.passwordInput.dispatchEvent(new Event('input'));
    fixture.detectChanges();

    // 2. 触发提交按钮点击
    page.submitBtn.click();
    fixture.detectChanges();

    // 3. 断言login方法被调用,参数正确
    expect(authenticationService.login).toHaveBeenCalledTimes(1);
    expect(authenticationService.login).toHaveBeenCalledWith('testUser', 'testPass');
  });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 07:57:01