I am trying to test a show/hide data component. Without its data (currently undefined), a simple block of text is displayed.
However when i then feed the component with data, the first block should become hidden whilst the second block that consists of the list of data in a table should become visible, however null is being returned (withDataBlock).
Therefore tests errors on the last expect of the test, even though i add fixture.detectChanges()
method beforehand.
component:
import { Component, OnInit, OnChanges, Input, SimpleChanges, OnDestroy, ViewChildren, QueryList } from '@angular/core';
import { Response } from '@angular/http';
import { AccountSearchService } from './../../services/account-search.service';
import { ISearchResult, ISearchResultContentItem, IContentItemStatus } from './../../entities/search.entity';
import { SortByPipe } from './../../pipes/sort.pipe';
import { FilterPipe } from './../../pipes/filter.pipe';
import { CapitalisePipe } from './../../pipes/capitalise.pipe';
import { Subject, Subscription } from 'rxjs';
@Component({
selector: 'app-account-list',
templateUrl: './account-list.component.html',
styleUrls: ['./account-list.component.scss'],
inputs: ['inputSearchTerm']
})
export class AccountListComponent implements OnInit, OnChanges, OnDestroy {
private searchTerm: string = undefined;
private sortByParam: string = "name";
private initialText = "Perform search above to view results below.";
private subs: Subscription = undefined;
private searchResults: ISearchResult = undefined;
private accountsCollection: Array<ISearchResultContentItem> = undefined;
@Input() public set inputSearchTerm(value: string) {
this.searchTerm = value;
}
constructor(
private _accountSearchService: AccountSearchService
) {
}
ngOnInit() {
}
ngOnChanges(changes: SimpleChanges) {
if (!changes.inputSearchTerm.firstChange) {
let curValue = changes.inputSearchTerm.currentValue;
this.subs = this._accountSearchService.SearchAccounts()
.subscribe((response: Response) => {
if (response.status == 200) {
this.searchResults = <ISearchResult>response.json();
this.accountsCollection = <Array<ISearchResultContentItem>>this.searchResults.content;
}
}
)
}
}
ngOnDestroy() {
if (this.subs)
this.subs.unsubscribe();
}
}
HTML:
<section>
<div id="accounts-list" class="accounts-list">
<div id="accountsListNoData" class="row" *ngIf="!accountsCollection">
<div class="col-12">
<p>{{ initialText }}</p>
</div>
</div>
<div id="accountsListWithData" class="row accountsListWithData" *ngIf="accountsCollection">
<div class="col-12">
<div class="row" *ngIf="searchTerm">
<div class="col-6">
<p>You searched for: "{{ searchTerm }}"</p>
</div>
<div class="col-6 text-right" *ngIf="searchResults">
<p>{{ 'Page: ' + (searchResults.page+1) + ' of ' + searchResults.totalPages }}</p>
</div>
</div>
<div class="row" *ngIf="(accountsCollection | filter: searchTerm).length === 0">
<div class="col-12">
<p>No results found</p>
</div>
</div>
<div class="row">
<div class="col-12" *ngIf="(accountsCollection | filter: searchTerm).length > 0">
<div class="table-responsive">
<table id="accountsListTable" class="table">
<thead class="thead-brand">
<tr>
<th scope="col">
<a (click)="sortByParam='id'" title="Sort by Account ID">Account ID</a>
</th>
<th scope="col">
<a (click)="sortByParam='name'" title="Sort by Account Name">Account name</a>
</th>
<th scope="col">
<a href="#" title="Sort by account number">Account number</a>
</th>
<th scope="col">
<a href="#" title="Sort by account sort code">Sort code</a>
</th>
<th scope="col">
<a (click)="sortByParam='balance'" title="Sort by balance">Balance</a>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let account of accountsCollection | filter: searchTerm | sortBy: sortByParam">
<td scope="row">{{ account.id }}</td>
<td>
<strong>{{ account.name | capitalise }}</strong>
</td>
<td [innerHTML]="account.identifiers[0].accountNumber"></td>
<td [innerHTML]="account.identifiers[0].sortCode"></td>
<td [innerHTML]="'£' + account.balance"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
Test:
import { async, ComponentFixture, TestBed, tick } from '@angular/core/testing';
import { AccountListComponent } from './account-list.component';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { SortByPipe } from './../../pipes/sort.pipe';
import { FilterPipe } from './../../pipes/filter.pipe';
import { CapitalisePipe } from './../../pipes/capitalise.pipe';
import { Http, HttpModule } from '@angular/http';
import { AccountSearchService } from '../../services/account-search.service';
import { ISearchResult, IContentItemStatus, IIdentifiers, ISearchResultContentItem } from './../../entities/search.entity';
describe("AccountListComponent", () => {
let component: AccountListComponent;
let fixture: ComponentFixture<AccountListComponent>;
let debEl: DebugElement;
beforeEach(async () => {
TestBed.configureTestingModule({
declarations: [
AccountListComponent, CapitalisePipe, SortByPipe, FilterPipe
],
imports: [HttpModule],
providers: [AccountSearchService]
}).compileComponents()
})
beforeEach(() => {
fixture = TestBed.createComponent(AccountListComponent);
component = fixture.componentInstance;
debEl = fixture.debugElement;
})
it("should initialise the component", () => {
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component).toBeTruthy();
});
})
it("should show accounts-list__noData block without data", () => {
expect((<any>component).searchResults).toBeUndefined;
fixture.detectChanges();
//test initial instruction text
let alEl = debEl.query(By.css(".accounts-list"));
let withoutDataBlock = <HTMLDivElement>alEl.nativeElement.querySelector("p");
expect(withoutDataBlock.textContent).toEqual((<any>component).initialText);
})
it("Show accounts-list__withData block with passed in data", fakeAsync((done) => {
let alEl = debEl.query(By.css(".accounts-list"));
let withDataBlock = <HTMLDivElement>alEl.nativeElement.querySelector("#accountsListWithData");
expect((<any>component).searchTerm).toBeUndefined;
expect(withDataBlock).toBeUndefined;
const testAccounts = <ISearchResult>{
content: <Array<ISearchResultContentItem>>[
{
id: "A02017NU",
name: "1010 SOFTWARE LTD",
balance: "46.91",
currency: "GBP",
status: IContentItemStatus.ACTIVE,
identifiers: <Array<IIdentifiers>>[
{
type: "SCAN",
accountNumber: "00001232",
sortCode: "000000"
}
],
customerId: "C0200098",
externalReference: "Account 1"
}
],
page: 0,
size: 15,
totalPages: 407,
totalSize: 60960944
};
component.inputSearchTerm = "software";
const inputSearchTerm = <SimpleChange> {
currentValue: "software",
firstChange: false,
previousValue: undefined
}
component.ngOnChanges({ inputSearchTerm });
fixture.checkNoChanges();
fixture.detectChanges();
done();
expect((<any>component).searchTerm).toBeDefined;
}))
})
Error:
ERROR: 'Unhandled Promise rejection:', 'Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'ng:///DynamicTestModule/AccountListComponent.ngfactory.js'.', '; Zone:', '<root>', '; Task:', 'Promise.then', '; Value:', DOMException{stack: 'Error: Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'ng:///DynamicTestModule/AccountListComponent.ngfactory.js'.
at http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:2990:1
at XMLHttpRequest.proto.(anonymous function) [as send] (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:1394:1)
at Array.<anonymous> (http://localhost:9876/absolute/Users/victoroyea/Documents/Sites/modulr/modulr/node_modules/source-map-support/browser-source-map-support.js?f894bb45358bceea281c12011b12863c67d3942c:111:263)