[Angular] Test Container component with async provider
The main idea for testing contianer component is to make sure it setup everythings correctlly. Call the onInit() lifecycle first, then the variables have the right value. Methods will be called with the right params.
Container component:
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormArray, FormGroup } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/forkJoin';
import { Product, Item } from '../../models/product.interface';
import { StockInventoryService } from '../../services/stock-inventory.service';
@Component({
selector: 'stock-inventory',
styleUrls: ['stock-inventory.component.scss'],
template: `
<div class="stock-inventory">
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<stock-branch
[parent]="form">
</stock-branch>
<stock-selector
[parent]="form"
[products]="products"
(added)="addStock($event)">
</stock-selector>
<stock-products
[parent]="form"
[map]="productsMap"
(remove)="removeStock($event, i)">
</stock-products>
<div class="stock-inventory__buttons">
<button
type="submit"
[disabled]="form.invalid">
Order stock
</button>
</div>
<pre>{{ form.value | json }}</pre>
</form>
</div>
`
})
export class StockInventoryComponent implements OnInit {
products: Product[];
productsMap: Map<number, Product>;
form = this.fb.group({
store: this.fb.group({
branch: '',
code: ''
}),
selector: this.createStock({}),
stock: this.fb.array([])
});
constructor(
private fb: FormBuilder,
private stockService: StockInventoryService
) {}
ngOnInit() {
const cart = this.stockService.getCartItems();
const products = this.stockService.getProducts();
Observable
.forkJoin(cart, products)
.subscribe(([cart, products]: [Item[], Product[]]) => {
const mapInfo = products.map<[number, Product]>(product => [product.id, product]);
this.products = products;
this.productsMap = new Map<number, Product>(mapInfo);
cart.forEach(item => this.addStock(item));
});
}
createStock(stock) {
return this.fb.group({
product_id: (parseInt(stock.product_id, 10) || ''),
quantity: (stock.quantity || 10)
});
}
addStock(stock) {
const control = this.form.get('stock') as FormArray;
control.push(this.createStock(stock));
}
removeStock({ group, index }: { group: FormGroup, index: number }) {
const control = this.form.get('stock') as FormArray;
control.removeAt(index);
}
onSubmit() {
console.log('Submit:', this.form.value);
}
}
Service:
import { Injectable } from '@angular/core';
import { Http, Response, URLSearchParams } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import { Product, Item } from '../models/product.interface';
@Injectable()
export class StockInventoryService {
constructor(private http: Http) {}
getCartItems(): Observable<Item[]> {
return this.http
.get('/api/cart')
.map((response: Response) => response.json())
.catch((error: any) => Observable.throw(error.json()));
}
getProducts(): Observable<Product[]> {
return this.http
.get('/api/products')
.map((response: Response) => response.json())
.catch((error: any) => Observable.throw(error.json()));
}
}
Test:
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
import { DebugElement } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { StockInventoryComponent } from './stock-inventory.component';
import { StockBranchComponent } from '../../components/stock-branch/stock-branch.component';
import { StockCounterComponent } from '../../components/stock-counter/stock-counter.component';
import { StockProductsComponent } from '../../components/stock-products/stock-products.component';
import { StockSelectorComponent } from '../../components/stock-selector/stock-selector.component';
import { StockInventoryService } from '../../services/stock-inventory.service';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
const products = [{ id: , price: , name: 'Test' }, { id: , price: , name: 'Another test'}];
const items = [{ product_id: , quantity: }, { product_id: , quantity: }];
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
class MockStockInventoryService {
getProducts() {
return Observable.of(products);
}
getCartItems() {
return Observable.of(items);
}
}
describe('StockInventoryComponent', () => {
let component: StockInventoryComponent;
let fixture: ComponentFixture<StockInventoryComponent>;
let el: DebugElement;
let service: StockInventoryService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
ReactiveFormsModule
],
declarations: [
StockBranchComponent,
StockCounterComponent,
StockProductsComponent,
StockSelectorComponent,
StockInventoryComponent
],
providers: [
{provide: StockInventoryService, useClass: MockStockInventoryService }
]
})
fixture = TestBed.createComponent(StockInventoryComponent)
component = fixture.componentInstance;
el = fixture.debugElement;
service = el.injector.get(StockInventoryService)
})
it('should call through tow service funs when init', () => {
spyOn(service, 'getCartItems').and.callThrough();
spyOn(service, 'getProducts').and.callThrough();
component.ngOnInit();
expect(service.getCartItems).toHaveBeenCalled();
expect(service.getProducts).toHaveBeenCalled();
})
it('should store the response into products', () => {
component.ngOnInit();
expect(component.products).toEqual(products)
})
it('should set producetsMap', () => {
component.ngOnInit();
expect(component.productsMap.get()).toEqual(products[]);
expect(component.productsMap.get()).toEqual(products[]);
})
it('should call addStock with the right param', () => {
spyOn(component, 'addStock');
component.ngOnInit();
expect(component.addStock).toHaveBeenCalledWith(items[]);
expect(component.addStock).toHaveBeenCalledWith(items[]);
})
});
[Angular] Test Container component with async provider的更多相关文章
- Exploring the Angular 1.5 .component() method
Angular 1.5 introduced the .component() helper method, which is much simpler than the.directive() de ...
- Angular(二) - 组件Component
1. 组件Component示例 2. Component常用的几个选项 3. Component全部的选项 3.1 继承自@Directive装饰器的选项 3.2 @Component自己特有的选项 ...
- angular之service、factory预provider区别
昨晚项目组做了angular分享,刚好有讨论到这个问题.虽然许久不做前端开发,但是兴趣所致.就查阅了下资料,以便后续需要使用 自己的理解:service是new出来的,factory是直接使用就能获得 ...
- angular学习(十五)——Provider
转载请写明来源地址:http://blog.csdn.net/lastsweetop/article/details/60966263 Provider简单介绍 每一个web应用都是由多个对象协作完毕 ...
- angular 关于 factory、service、provider的相关用法
1.factory() Angular里面创建service最简单的方式是使用factory()方法. factory()让我们通过返回一个包含service方法和数据的对象来定义一个service. ...
- 【Angular】No component factory found for ×××.
报错现象: 用modal打开某个组件页面时报错 报错:No component factory found for UpdateAuthWindowComponent. Did you add it ...
- [Angular 2] Exposing component properties to the template
Showing you how you can expose properties on your Controller to access them using #refs inside of yo ...
- [AngularJS] Exploring the Angular 1.5 .component() method
Angualr 1.4: .directive('counter', function counter() { return { scope: {}, restrict: 'EA', transclu ...
- 展示组件(Presentational component)和容器组件(Container component)之间有何不同
展示组件关心组件看起来是什么.展示专门通过 props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态.(子组件)容器组件则更关心组件 ...
随机推荐
- C语言之文件操作06——写数据到文本文件遇0停止
//文件 /* =============================================================== 题目:输入10个篮球运动员的身高数据(cm)保存至D盘文 ...
- thinkphp事务处理以及无效时的解决方案(整理)
thinkphp事务处理以及无效时的解决方案(整理) 一.总结 一句话总结:要程序里面支持事务,首先连接的数据库和数据表必须支持事务 mysql 1.InnoDB和MyISAM对事务的支持怎么样? I ...
- Java学习笔记三.2
5.继承 //Java中所有对象都显式/隐式的继承子Object类 class fu{ fu(){ System.out.println("fu..."+getNum()); sh ...
- Monkey服务器命令
- position(static-relative-absolute-fixed),margin(top-right-bottom-left),top-right-bottom-left
最近写css遇到一些问题,所以准备写下来捋一下思路. 1.position=satic下看margin的使用.(top-right-bottom-left在这种case下无效) 1-1)margin ...
- SQLITE数据表主键设置Id自增方法
SQLITE数据表主键设置Id自增方法 标签: sqliteintegerinsertnulltableapi 2010-01-12 08:39 35135人阅读 评论(8) 收藏 举报 分类: S ...
- Mining Station on the Sea (hdu 2448 SPFA+KM)
Mining Station on the Sea Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav ...
- Solr 倒排索引
正排索引(正向索引):正排表是以文档的ID为关键字,表中记录文档中每个字的位置信息,查找时扫描表中每个文档中字的信息直到找出所有包含查询关键字的文档. 正排表结构如图1所示,这种组织方法在建立索引的 ...
- menuconfig_kconfig
这一节的主要内容: Menuconfig的操作 Kconfig和.config文件 Linux内核配置裁剪实验 linux编译器通过.config文件确认哪些代码编译进内核,哪些被裁减掉 menuco ...
- jQuery快速入门知识重点
1.jquery中attr与prop的区别 attr:是通过setAttribute 和 getAttribute来设置的使用的是DOM属性节点 prop:是通过document.getEle ...