I want to write a simple unit test to check if button is disable when certain value is null or empty.
Below is my spec file:
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();
});
});
Test failed:
Expected undefined to be 'disabled'.
I have searched internet to find debugElement functions to get properties of element but could not find exact solution.
This is a reference similar SO Question
UPDATE:
Below is HTML of component
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>
At the end of the html there is textarea and button which I am testing to be disabled when textarea is empty.
In component class variable name is comment which should be empty for button to be disabled. This is assertion of my test.
Below is Component class:
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
}
)*/
}
}
nativeElement() returns DOM tree whereas debugElement returns a JS object (debugElement tree). debugElement is a Angular's method. . nativeElement() is Browser specific API that returns or give access to DOM tree.
DebugElement is an Angular class that contains all kinds of references and methods relevant to investigate an element as well as component fixture.debugElement.query(By.css('#shan')) will return.
You can create a component fixture with TestBed. createComponent . Fixtures have access to a debugElement , which will give you access to the internals of the component fixture. Change detection isn't done automatically, so you'll call detectChanges on a fixture to tell Angular to run change detection.
You need to update the view after setting the component.comment = ''
.
Add fixture.detectChanges()
call before querying for your element and making the assertions.
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);
}
});
It's worth noting that you can inspect the DebugElement
without accessing the nativeElement
.
here is a slight modification of the code. Try this out
expect(addCommentBtn.nativeElement.attributes).toContain['disabled'];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With