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的更多相关文章

  1. Exploring the Angular 1.5 .component() method

    Angular 1.5 introduced the .component() helper method, which is much simpler than the.directive() de ...

  2. Angular(二) - 组件Component

    1. 组件Component示例 2. Component常用的几个选项 3. Component全部的选项 3.1 继承自@Directive装饰器的选项 3.2 @Component自己特有的选项 ...

  3. angular之service、factory预provider区别

    昨晚项目组做了angular分享,刚好有讨论到这个问题.虽然许久不做前端开发,但是兴趣所致.就查阅了下资料,以便后续需要使用 自己的理解:service是new出来的,factory是直接使用就能获得 ...

  4. angular学习(十五)——Provider

    转载请写明来源地址:http://blog.csdn.net/lastsweetop/article/details/60966263 Provider简单介绍 每一个web应用都是由多个对象协作完毕 ...

  5. angular 关于 factory、service、provider的相关用法

    1.factory() Angular里面创建service最简单的方式是使用factory()方法. factory()让我们通过返回一个包含service方法和数据的对象来定义一个service. ...

  6. 【Angular】No component factory found for ×××.

    报错现象: 用modal打开某个组件页面时报错 报错:No component factory found for UpdateAuthWindowComponent. Did you add it ...

  7. [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 ...

  8. [AngularJS] Exploring the Angular 1.5 .component() method

    Angualr 1.4: .directive('counter', function counter() { return { scope: {}, restrict: 'EA', transclu ...

  9. 展示组件(Presentational component)和容器组件(Container component)之间有何不同

    展示组件关心组件看起来是什么.展示专门通过 props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态.(子组件)容器组件则更关心组件 ...

随机推荐

  1. FileChannel的深入理解

    一,官方描写叙述 一个读,写,映射,操作文件的通道. 文件通道有能够被查询和改动的一个当前位置.文件本身包括了一个可悲读写的变长字节序列,而且它的当前的size会被查询.当被写入的字节超过当前文件的大 ...

  2. iOS应用笔记之git的本地使用

    什么是git (1)什么是git >git是一个 "分布式"的版本号控制工具 >git的作者是Linux之父:Linus Benedict Torvalds,当初开发g ...

  3. 火车票问题.以及x轴连续矩形,最大面积问题

    假设火车有10个站点: 1000个座位 api(1)  -> param  : leftStation, rightStation -> result : cnt             ...

  4. 3.1 Broker Configs 官网剖析(博主推荐)

    不多说,直接上干货! 一切来源于官网 http://kafka.apache.org/documentation/ 3.1 Broker Configs 3.1 broker配置 The essent ...

  5. 用Zebra打造Linux下小型路由器

    用Zebra打造Linux下小型路由器 现在的Internet网络相当庞大,不可能在不同的网络之间建立直接的连接,所以这时就必须用路由器为不同网络之间的通信提供路径选择.Linux下搭建路由器价格非常 ...

  6. 交叉编译工具链bash: gcc:no such file or directory

    在进行交叉编译工具链安装时,有三种方法: 1.源码编译,手动安装 2.二进制可执行文件直接安装 3.直接解压工具链,手动修改环境变量 为了方便,我们多用方法3进行安装.但是问题来了,你的工具链制作时有 ...

  7. Scala——构造函数

    Scala的构造函数分为主构造函数和辅助构造函数. 辅助构造函数 辅助构造函数比较容易理解,它们同C++和Java的构造函数十分类似,只有两处不同: 1.辅助构造函数的名称为this,这主要是考虑到在 ...

  8. 今天发现里一个非常好用的Listbox自绘类,带不同文字字体和图片,觉得很有必要记下来

    代码简写 MyListBox.h class CUseListBox : public CListBox { typedef struct _ListBox_Data { CString strApp ...

  9. 【例题 8-1 UVA 120 】Stacks of Flapjacks

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 从大到小安排. 显然想让第i大的数字归位 只要让他翻到最上面,然后再翻回来就ok了 即operate(pos[i]) -> o ...

  10. 计科1111-1114班第一次实验作业(NPC问题——回溯算法、聚类分析)

    实验课安排 地点: 科技楼423 时间:  计科3-4班---15周周一上午.周二下午 计科1-2班---15周周一下午.周二晚上(晚上时间从18:30-21:10) 请各班学委在实验课前飞信通知大家 ...