我对角度和茉莉花的单元测试非常陌生,因此我一直在努力使其正确。我正在尝试为登录页面编写一个简单的单元测试。以下是我的代码
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
import {BrowserModule, By} from '@angular/platform-browser';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {Component, DebugElement, Input} from '@angular/core';
import {RouterTestingModule} from '@angular/router/testing';
import {LoaderService} from '@shared/services/loader.service';
import {AuthenticationService} from '@shared/services/authentication.service';
import {HttpClientModule} from '@angular/common/http';
import {CommonService} from '@shared/services/common.service';
import {ExploreService} from '@shared/services/explore.service';
import {TitleService} from '@shared/services/title.service';
import {AppConfig} from '../../app-config.service';
import {ThemeService} from '@shared/services/theme.service';
import {MatDialog, MatFormFieldModule, MatIconModule} from '@angular/material';
import {throwError} from 'rxjs';
@Component({
selector: 'show-errors',
template: '<p>Mock Product Settings Component</p>'
})
class MockShowErrorsComponent {
@Input() public control;
}
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let authService: any;
let common: any;
let explore: any;
let title: any;
let config: any;
let theme: any;
let dialog: any;
let debugElement: DebugElement;
let element: HTMLElement;
let submitSpy: any;
beforeEach(async(() => {
authService = jasmine.createSpyObj('AuthenticationService', [
'login',
'logout'
]);
common = jasmine.createSpyObj('commonService', [
'updateCurrentUrl',
'isMobile',
]);
explore = jasmine.createSpyObj('exploreService', [
'slowCalcMessage',
'cancelSlowMessage',
'getInventoryTotalSummary',
'handleError',
'getMarketData'
]);
title = jasmine.createSpyObj('titleService', [
'getTitle',
'setTitle',
'updateTitle',
'updateSiteName'
]);
config = jasmine.createSpyObj('AppConfigService', [
'load',
'API_ENDPOINT'
]);
theme = jasmine.createSpyObj('ThemeService', [
'getThemeSettings',
'generateColorTheme',
]);
dialog = jasmine.createSpyObj('dialog', [
'open'
]);
TestBed.configureTestingModule({
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
RouterTestingModule.withRoutes([]),
HttpClientModule,
MatIconModule,
MatFormFieldModule,
],
declarations: [
LoginComponent,
MockShowErrorsComponent
],
providers: [
LoaderService,
{provide: AuthenticationService, useValue: authService},
{provide: CommonService, useValue: common},
{provide: ExploreService, useValue: explore},
{provide: TitleService, useValue: title},
{provide: AppConfig, useValue: config},
{provide: ThemeService, useValue: theme},
{provide: MatDialog, useValue: dialog},
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
debugElement = fixture.debugElement;
element = debugElement.nativeElement;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should fail on wrong credentials', () => {
const email = element.querySelector('#defaultForm-email') as HTMLInputElement;
email.value = 'vigneshm@intermx.com';
email.dispatchEvent(new Event('input'));
const password = element.querySelector('#defaultForm-pass') as HTMLInputElement;
password.value = 'agira123';
password.dispatchEvent(new Event('input'));
fixture.detectChanges();
const service = debugElement.injector.get(AuthenticationService);
submitSpy = spyOn(service, 'logout');
debugElement.query(By.css('button.login-btn'))
.triggerEventHandler('click', null);
fixture.detectChanges();
expect(submitSpy).toHaveBeenCalled();
});
});
上面的代码是我对登录屏幕的规格和模拟,我意识到登录页面具有太多的依赖关系,在开始模拟它们时需要简化这些依赖。
真正的问题是,每当我运行此命令时,第二项测试就会失败,并显示TypeError: Cannot set property 'value' of null
。
我不确定为什么在测试时DOM不可用,我应该等待DOM或angular准备好吗?还是其他?
答案 0 :(得分:1)
我在Stackblitz中模拟了您的测试。正如您在Stackblitz中看到的那样,测试现在都通过了。这是我为使其正常工作所做的:
submitSpy = spyOn(service, 'logout')
行,
由于您已经传递了间谍,因此无需进行间谍
再次。因此,我也将最后一行更改为
expect(service.login).toHaveBeenCalled();
测试间谍
已经通过了。fixture.whenStable()
以确保所有内容均已渲染
在测试之前正确进行。我希望这会有所帮助。
答案 1 :(得分:0)
使用vsc并安装simon测试插件。现在,右键单击您要为其编写单元测试的组件。选择选项生成测试。它将生成一个规范文件,其中所有相关性都写在那上面。现在,您将文件的测试用例粘贴到文件上方。
答案 2 :(得分:0)
认为您的问题是const email = element.querySelector('#defaultForm-email') as HTMLInputElement;
以及所有此类element.querySelector
通常,您应该使用fixture.nativeElement.querySelector(className);
或id
。由于TestBed
通常会为您创建一个运行测试的安全环境。
您通常应该使用一些东西
const password: HTMLInputElement = fixture.nativeElement.querySelector('#defaultForm-pass');
password.setValue('value');
答案 3 :(得分:0)
我已修复错误,问题出在模板上。我有一个全局* ngIf语句,用于检查是否存在名为主题设置的变量
<div *ngIf="themeSettings"></div>
在测试中,我忘记了对themeSettings变量进行存根,从而导致永远无法创建测试所需的DOM。在为themeSettings添加存根值后,它又开始工作。
要点:如果模板中包含ngIf,请确保将其存根并在测试中为这些值设置适当的值,并确保在发布之前正确创建了DOM。