[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 状态而不是数据的状态.(子组件)容器组件则更关心组件 ...
随机推荐
- CCNP路由实验之十五 NAT(网络地址转换)
CCNP路由实验之十五 NAT(网络地址转换) 众所周知,要让自己的电脑连上Internet,必须要到运营商(ISP)申请一个上网账号,依据此账号申请自己的宽频业务(拨号上网.商业固定IP等等) ...
- scrollBarStyle- listview滑动条调整
今天在解决问题的时候,需要设置listview滚动条,使listview的内容不能被滚动条覆盖 后来发现网上提到一个 ScrollView 属性.ScrollView中ScrollBar的style ...
- Objective-C基础笔记(9)Foundation常用类NSArray
NSArray用来存储对象的有序列表,它是不可变的 NSArray不能存储C语言中的基本数据类型,如int.float.enum.struct,也不能存储nil,nil代表数组元素的结束 // // ...
- JS数组排序技巧汇总(冒泡、sort、快速、希尔等排序)
本文实例总结了JS数组排序技巧.分享给大家供大家参考,具体如下: 1.冒泡排序 var temp = 0; for (var i = 0; i < array.length; i++) { fo ...
- ListCtrl添加右键菜单(在对话框类中)
在对话框类中如何添加NM_RCLICK消息: ListCtrl控件右键单击选择属性 在右侧属性栏中选择控件事件 在控件事件中找到NM_RCLICK并添加 完成,写代码
- PatentTips - Method to manage memory in a platform with virtual machines
BACKGROUND INFORMATION Various mechanisms exist for managing memory in a virtual machine environment ...
- Linux中删除文件,磁盘空间未释放问题追踪
在客户使用我们产品后,发现一个问题:在删除了文件后.磁盘空间却没有释放.是有进程在打开这个文件,还是其它情况?我们一起来看看一下两个场景 一. 场景一:进程打开此文件 当一个文件正在被一个进程使用时. ...
- [Javascript AST] 0. Introduction: Write a simple BabelJS plugin
To write a simple Babel plugin, we can use http://astexplorer.net/ to help us. The plugin we want to ...
- spring 通过编程来获取属性文件
配置可以读取属性: <beans profile="dev"> <context:property-placeholder ignore-resource-not ...
- valueof(), intvalue(0 parseint() 这三个方法怎么用
valueOf(int i) 返回一个表示指定的 int 值的 Integer 实例.valueOf(String s) 返回保存指定的 String 的值的 Integer 对象.valueOf(S ...