如何在角度单元测试中使用 debugeElement 访问 nativeElement 属性
Posted
技术标签:
【中文标题】如何在角度单元测试中使用 debugeElement 访问 nativeElement 属性【英文标题】:How to access nativeElement attribute using debugeElement in angular unit test 【发布时间】:2018-09-29 19:02:13 【问题描述】:我想编写一个简单的单元测试来检查当某个值为空或为空时按钮是否被禁用。
以下是我的规范文件:
test.spec.ts
import async, ComponentFixture, TestBed from '@angular/core/testing';
import 'reflect-metadata';
import Component,
DebugElement,
ViewChild
from "@angular/core";
import By from "@angular/platform-browser";
import FormsModule from '@angular/forms';
import HttpClientModule, HttpClient from '@angular/common/http';
import ListCommentsComponent from './list-comments.component';
import CommentsDataService from '../../services/comments/comments-data.service'
describe('ListCommentsComponent', () =>
let component: ListCommentsComponent;
let fixture: ComponentFixture<ListCommentsComponent>;
let debugElement:DebugElement;
let htmlElement:HTMLElement;
let addCommentBtn:DebugElement;
beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [ FormsModule, HttpClientModule],
declarations: [ ListCommentsComponent ],
providers:[provide: CommentsDataService],
// providers:[HttpClientModule, HttpClient]
)
.compileComponents();
));
beforeEach(() =>
fixture = TestBed.createComponent(ListCommentsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
);
fit('should be disabled when comment is empty', () =>
component.comment = '';
addCommentBtn = fixture.debugElement.query(By.css('button.addCommentBtn'));
expect(addCommentBtn.nativeElement.getAttribute('disabled')).toBeTruthy();
);
);
测试失败:
预期未定义为“禁用”。
我在网上搜索了 debugElement 函数来获取元素的属性,但找不到确切的解决方案。
这是一个类似SO Question的参考
更新:
下面是组件的 HTML
HTML
<div class="container">
<!--<h1 id="hello"></h1>-->
<div class="row listCommentsContainer">
<div class="col-lg-8 col-sm-8" *ngFor="let commentData of commentsData| async ; let i = index">
<ol style="list-style: none;">
<li class="listComments">
<div style="display: block">
<div style="display:inline-block;">
<a class="avatar">
<img style="" src="commentData.profile_image">
</a>
</div>
<a class="commentPostByUserName">
<span class="commentPostByUserName" style="">commentData.first_name</span>
</a>
<div class="commentTime">commentData.time_stamp</div>
</div>
<div class="commentTextDisplay">commentData.object</div>
<br>
<!-- Reply Link -->
<div class="addReplyContainer" >
<a class="addReplyLink" (click)="showReplyTextArea($event,i )">Reply</a>
</div>
<!-- Add Reply -->
<div [attr.commentId] = "commentData.target_id" *ngIf = "selectedindex == i "
class="addReplyContainer replyTextAreaContainer" >
<textarea [(ngModel)]="reply" style="width:100%"
class="replyText commentText addReplyTextarea form-control"></textarea>
<button [attr.commentId]="commentData.id" [disabled] = "!reply || reply.length>500" class="btn btn-success addCommentBtn" (click)="addReply(commentData.target_id)">Add</button>
</div>
<!-- -----Add Reply end------ -->
<!-- List Replies -->
<div class="replies col-lg-8 col-sm-8" *ngFor="let reply of commentData.comment">
<ol style="list-style: none;">
<li class="listComments listReplies">
<div style="display: block">
<div style="display:inline-block;">
<a class="avatar">
<img style="" src="reply.profile_image">
</a>
</div>
<a class="commentPostByUserName">
<span class="commentPostByUserName" style="">reply.first_name</span>
</a>
</div>
<div class="commentTextDisplay replyTextDisplay">reply.object</div>
</li>
</ol>
</div>
<!-- -------list reply end-------- -->
</li>
</ol>
</div>
</div>
<!-- Add Comment-->
<div class="row">
<div class="addCommentContainer col-lg-6 col-sm-12">
<textarea maxlength="500"
[(ngModel)]="comment" class="commentText form-control"
placeholder="Add Comment">
</textarea>
<button #addCommentBtn [disabled] = "!comment || comment.length>500" (click)="addComment()" class="btn addCommentBtn btn-success">Add</button>
</div>
</div>
<!-- Add Comment end-->
</div>
在 html 的末尾有 textarea 和 button,我正在测试当 textarea 为空时将其禁用。
在组件类中,变量名是注释,如果按钮被禁用,注释应该是空的。 这是我测试的断言。
下面是组件类:
import Component, OnInit, ElementRef, ViewChild, Renderer2 from '@angular/core';
import CommentsDataService from "../../services/comments/comments-data.service";
import Observable from 'rxjs/Observable';
import mergeMap from 'rxjs/operators';
import IComment from "../../comments";
import ICommentType from "../../commentType";
declare let jQuery: any;
@Component(
selector: 'app-list-comments',
templateUrl: './list-comments.component.html',
styleUrls: ['./list-comments.component.css'],
providers:[CommentsDataService]
)
export class ListCommentsComponent implements OnInit
constructor(private commentsDataService:CommentsDataService, private el: ElementRef)
commentsData :any; // Comment Data received from service.
comment:string; // Comment text; declaration.
reply:string;
commentObj:any;
commentArrayObj:any;
public selectedindex;
getComments; // Declaration of function.
saveComment;
getUser;
/**
* This Function is triggered to
* call save function and append
* new comment.
* Append new comment
*
*/
addComment()
this.comment = this.comment.trim();
let commentObj;
let comment = this.comment;
commentObj =
"root_id":"1",
"target_id": "1",
"object": this.comment,
"time_stamp":'2 secs ago',
"profile_image":"/../../assets/images/no-user.png",
"first_name" : "john",
;
//let commentObj = this.commentObj; //Put this.commentObj to push it into this.commentData
if( typeof this.comment == "undefined" || this.comment === '' || this.comment == null || this.comment == '\n' || this.comment.length>500 )
return false;
else
this.commentsData.push( commentObj );
this.comment = ''; // Empty comment Textarea.
return comment;
/**
*
* Function triggered when
* reply link is clicked
* @param event
* @param index
*/
showReplyTextArea(event, index);
showReplyTextArea(event, index)
this.selectedindex = index;
console.log( this.selectedindex);
/**
* Append Reply to list.
* @param event
* @param target_id
*/
addReply(target_id)
let commentData = this.commentsData; //creating local variable
let reply = this.reply; //creating local variable
if(reply == "" || reply === '/n' || reply.length <=0 || reply.length > 500 )
return false;
else
this.commentObj =
root_id:1,
target_id: target_id,
object: reply,
profile_image:"/../../assets/images/no-user.png",
actor:1,
first_name : "john"
;
let commentObj = this.commentObj;
this.commentArrayObj =[
root_id:1,
target_id: target_id,
object: reply,
actor:"user:123",
time_stamp: "2 min ago",
first_name : "john",
profile_image:"/../../assets/images/no-user.png"
];
let commentArrayObj1 = this.commentArrayObj;
console.log('commentObj');
console.log(commentObj);
jQuery.each(this.commentsData, function (index, value)
if(value.target_id == target_id)
if(! ('comment' in commentData[index]))
commentData[index]['comment'] = commentArrayObj1;
else
commentData[index].comment.push(commentObj);
)
this.reply = ''; // Empty textarea after posting reply.
ngOnInit()
this.commentsData = this.commentsDataService.getComments();
//Service call for Comments listing.
/* this.commentsDataService.getComments().subscribe(comments=>
this.commentsData = comments
)*/
【问题讨论】:
请用您正在测试的组件更新问题 @TomaszKula 完成。 【参考方案1】:您需要在设置component.comment = ''
后更新视图。
在查询您的元素并做出断言之前添加 fixture.detectChanges()
调用。
fit('should be disabled when comment is empty', () =>
component.comment = '';
fixture.detectChanges() // <-- add this to update the view
addCommentBtn = fixture.debugElement.query(By.css('button.addCommentBtn'));
// this asserts that button matches <button disabled>Hello</button>
expect(addCommentBtn.nativeElement.getAttribute('disabled')).toEqual('');
// this asserts that button matches <button>Hello</button>
expect(addCommentBtn.nativeElement.getAttribute('disabled')).toEqual(null);
);
值得注意的是,您可以在不访问nativeElement
的情况下检查DebugElement
。
【讨论】:
Tomasz,我已经在 beforeach 块中添加了这个。感谢您的答复。但这种改变没有效果。仍然让 Expected '' 被'禁用'。 将其添加到 before 块中为时过早。将评论设置为''
后,您必须更新视图。除非这是默认值。
是的,我添加了它,但仍然出现错误。 " 预期 ' ' 会被'禁用'"
如果我检查任何其他属性(如 id)的测试,它通过了。
太棒了,感谢您的时间和分享知识。干杯!!【参考方案2】:
这里是对代码的轻微修改。试试这个
expect(addCommentBtn.nativeElement.attributes).toContain['disabled'];
【讨论】:
debugElement.properties 在我的单元测试用例中为空,有什么解决方案吗?示例 html 代码是 "另一个对我有用的细微变化
const disabledEl = fixture.debugElement.query(By.css('.disabled-el'));
expect(Object.keys(disabledEl.attributes)).toContain('disabled');
不确定这是否与我的 angular 版本或 jasmine/karma 有关,但它有效。
【讨论】:
以上是关于如何在角度单元测试中使用 debugeElement 访问 nativeElement 属性的主要内容,如果未能解决你的问题,请参考以下文章