• [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: 1, price: 10, name: 'Test' }, { id: 2, price: 100, name: 'Another test'}];
    const items = [{ product_id: 1, quantity: 10 }, { product_id: 2, quantity: 5 }];
    
    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(1)).toEqual(products[0]);
        expect(component.productsMap.get(2)).toEqual(products[1]);
      })
    
      it('should call addStock with the right param', () => {
        spyOn(component, 'addStock');
        component.ngOnInit();
        expect(component.addStock).toHaveBeenCalledWith(items[0]);
        expect(component.addStock).toHaveBeenCalledWith(items[1]);
      })
    });
  • 相关阅读:
    maven第三章 maven使用入门
    各个软件产生的原因
    maven的pom.xml深入理解
    批量同步订单信息(包括状态)到订单中心心得
    数据库连接超时和go away、如何检测数据库的最大连接数
    记录错误日志的技巧
    架构思想总结同步和事务的具体应用
    业务逻辑复杂性处理
    日志系统总结
    php捕获异常的处理
  • 原文地址:https://www.cnblogs.com/Answer1215/p/6833399.html
Copyright © 2020-2023  润新知