zoukankan      html  css  js  c++  java
  • [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]);
      })
    });
  • 相关阅读:
    用js获取当前页面的url
    innerHTML 和 innertext 以及 outerHTML
    scrollWidth,clientWidth与offsetWidth的区别
    top、postop、scrolltop、offsetTop、scrollHeight、offsetHeight、clientHeight
    两个文字向上滚动案列
    mysql 经典案例
    学习笔记11
    顺时针打印矩阵
    重建二叉树
    镜像二叉树
  • 原文地址:https://www.cnblogs.com/Answer1215/p/6833399.html
Copyright © 2011-2022 走看看