承诺的角度单元测试 [英] Angular unit testing for the promises

查看:11
本文介绍了承诺的角度单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为以下方法编写测试用例: 下面是添加产品的组件代码

组件:

import { HttpClient } from '@angular/common/http';
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { Observable } from 'rxjs';
import { Constants } from '../../../../../../utils/constants';
import { FileUploadService } from '../../../services/file-upload.service';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { ManagePackageService } from '../../../services/manage-package.service';
import { DomSanitizer } from '@angular/platform-browser';
import { Package } from '../../../models/package.model';
import { ProductPackageMapping } from '../../../models/product-package-mapping.model';
import { Product } from '../../../models/product.model';
import { NotificationAlertService } from '../../../../shared/services/notification-alert.service';
import { ManageProductService } from '../../../services/manage-product.service';
import { DocumentDTO } from '../../../models/document-dto';
import { saveAs } from 'file-saver';
import { ConfirmationDialogService } from '../../../../shared/services/confirmation-dialog.service';

@Component({
  selector: 'app-add-product',
  templateUrl: './add-product.component.html',
  styleUrls: ['./add-product.component.scss']
})

export class AddProductComponent implements OnInit {
  productDetailForm: FormGroup;
  addTitle: boolean = true;
  isView: boolean = true;
  submitted: boolean = false;
  status: boolean = true;
  check: boolean = false;
  changevar: string;
  @Input() id: Number;
  @Output() changeIndicator = new EventEmitter<string>();
  @Input() list: ProductPackageMapping;
  @Output() dataLoaded = new EventEmitter<string>();
  fileToUpload: File | null = null;
  fileArray: Array<any> = [];
  productData: any = [];
  productDataTemp: any[];
  fData = new FormData();
  packagePlan: Array<any> = [];
  productDto = new Product();
  packageDto = new Package();
  productPackageMappingDto = new ProductPackageMapping();
  documentDto: Array<any> = [];
  isDocId: boolean = false;
  productForm: FormGroup;
  activeStatus: boolean = true;
  requiredFileType: string;
  public NAME_MAX_LENGTH = 50;
  isValidFormSubmitted: boolean;
  @Input() allRolesFromParent: Product[] = [];
  selectedFiles?: FileList;
  message: string[] = [];
  fileInfos?: Observable<any>;
  documentList: Array<any> = [];
  ppm: any;
  fileUrl: any;
  constructor(private http: HttpClient,
    private formBuilder: FormBuilder,
    private uploadService: FileUploadService,
    private manageProduct: ManageProductService,
    private managePackageService: ManagePackageService,
    private sanitizer: DomSanitizer,
    private notifyService: NotificationAlertService,
    private confirmationDialogService: ConfirmationDialogService
  
  ) { }

  ngOnInit(): void {
    this.createForm();
    this.fileInfos = this.uploadService.getFiles();
    this.fData = new FormData();
    this.subscriptionPackages()
  }

  closeModal() {
    this.status = true;
    this.check = false;
    this.changevar = 'cancel';
    this.changeIndicator.emit(this.changevar);
    this.productForm.reset();
    this.fData.delete('ppm');
    this.fData.delete('file');
    this.emit();
  }

  closeEditModel() {
    this.status = true;
    this.documentList = [];
    this.changevar = "cancel";
    this.changeIndicator.emit(this.changevar);
    this.addTitle = true;
    this.productForm.reset();
    this.fData.delete("ppm");
    this.fData.delete("file");
    this.emit();
  }

  
  onChangeSwitch(event) {
    if (event.target.checked == true) {
      this.activeStatus = true;
    } else {
      this.activeStatus = false;
    }
  }


  createForm() {
    this.productForm = new FormGroup({
      name: new FormControl(this.productDto.name, [
        Validators.required,
        Validators.maxLength(this.NAME_MAX_LENGTH),
        Validators.pattern(Constants.NO_WHITE_SPACE_PATTERN),
      ]),
      url: new FormControl(this.productDto.demoURL, Validators.required),
      version: new FormControl(this.productDto.productVersion, Validators.required),
      projectType: new FormControl(this.productDto.projectType, Validators.required),
      plansName: new FormControl(this.packageDto.id, Validators.required),
      desc: new FormControl(this.productDto.productDescription, Validators.required),
      active: new FormControl(this.productDto.active, Validators.required),
      documents: this.formBuilder.array([]),
    });
  }


  ngOnChanges() {
    this.productData = this.list;
    if (this.id) {
      this.addTitle = false;
      this.productDataTemp = this.productData.filter((vl) => (this.id == vl.id));
      this.productDataTemp.forEach(obj => {
        this.productDto.ppmId = obj.ppmId;
        this.productDto.id = obj.id;
        this.productDto.name = obj.name;
        this.productDto.demoURL = obj.demoURL;
        this.productDto.productDescription = obj.productDescription;
        this.productDto.projectType = obj.type;
        this.productDto.active = obj.active;
        this.productDto.productVersion = obj.version;
        this.packageDto.id = obj.pkgInfo.id;
        this.documentList = obj.listDocuments
      })
      this.createForm();
    } else {
      this.productDto = new Product();
      this.packageDto = new Package();
      this.documentDto = [];
      this.documentList = [];
    }
    this.documentList.length == 0 ? this.isDocId = false : this.isDocId = true;
  }

  get f() {
    return this.productForm.controls;
  }

  choosePackages(e) {
    

  }

  subscriptionPackages() {
    this.managePackageService.getPackages().subscribe(
      (response) => {
        this.packagePlan = response;
      },
      (httpErrorRes) => {
      }
    );
  }

  get documentsFormArray(): FormArray {
    return this.f['documents'] as FormArray;
  }

  addDocument() {
    if (this.documentsFormArray.length < 5) {
      this.documentsFormArray.push(this.formBuilder.group({
        id: new FormControl(''),
        docName: new FormControl('', Validators.required),
        docType: new FormControl('', Validators.required),
        attachment: new FormControl('', Validators.required)
      }))
    }
  }

  deleteRow(i: number) {

    if (this.id) {
      delete this.fileArray[i];
      this.documentsFormArray.removeAt(i);
      this.fileArray.splice(i, 1);
    }
    else {
      delete this.documentsFormArray[i];
      this.documentsFormArray.removeAt(i);
      this.fileArray.splice(i, 1);
    }
  }

  getFiles(fileArray) {
    this.fileArray.forEach(files => {
      this.fData.append("file", files);
    })
  }

  selectFiles(event): void {
    this.selectedFiles = event.target.files;
  }

  onFormSubmit() {
    this.submitted = true;
    if (this.fileArray.length > 0) {
      this.getFiles(this.fileArray);
    }
    if (this.productForm.value.id === null) {
      this.productDto.id = null;
    }
    this.productDto.name = this.productForm.value.name;
    this.productDto.demoURL = this.productForm.value.url;
    this.productDto.productVersion = this.productForm.value.version;
    this.productDto.projectType = this.productForm.value.projectType;
    this.productDto.productDescription = this.productForm.value.desc;
    this.productDto.active = this.productForm.value.active;
    this.packageDto.id = this.productForm.value.plansName;
    if (this.documentsFormArray && this.documentsFormArray.value && this.documentsFormArray.value.length > 0) {
      this.documentsFormArray.value.forEach(element => {
        this.documentDto.push(element);
      });
    }

    this.productPackageMappingDto.id = this.productDto.ppmId ? this.productDto.ppmId : null;
    this.productPackageMappingDto.products = this.productDto;
    this.productPackageMappingDto.packages = this.packageDto;
    this.productPackageMappingDto.document = this.documentDto;
    this.ppm = new Blob([JSON.stringify(this.productPackageMappingDto)], { type: "application/json" });
    this.fData.has("file") ? true : this.fData.append("file", '');
    this.fData.append("ppm", this.ppm);
    this.confirmationDialogService.confirm('Are you sure ?', 'Do you really want to Activate/ Deactivate Package ?')
      .then((confirmed) => {
        if (confirmed) {
          this.manageProduct.createProduct(this.fData).subscribe(
            (response) => {
              this.notifyService.showSuccess("Data saved successfully !!", "Success")
              this.closeModal();
              this.fData.delete("ppm");
              this.fData.delete("file");
              this.productDto = new Product();
              this.packageDto = new Package();
              this.documentDto = [];
              this.documentList = [];
              this.fileArray = [];
              this.emit();
            },
            (httpErrorRes) => {
              this.fData.delete("ppm");
              this.fData.delete("file");
              this.notifyService.showError(httpErrorRes.error, "Error");
            }
          );
        }
        else {
          this.fData.delete("ppm");
          this.fData.delete("file");
        }
      })

  }


  upload(event: any) {
    let files = event.target.files[0];
    this.fileArray.push(files);
  }

  downloadFile(fileData: DocumentDTO): void {
    this.manageProduct.download(fileData.fileName)
      .subscribe(blob => saveAs(blob, fileData.fileName));
  }


  emit() {
    this.dataLoaded.emit('AddProductComponent')
  }
}

以下是上述组件的规范文件

COMPONENT.SPEC.TS

import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NgSelectModule } from '@ng-select/ng-select';
import { TranslateModule } from '@ngx-translate/core';
import { ToastrModule } from 'ngx-toastr';
import { Observable, of, throwError } from 'rxjs';
import { AppConfig } from '../../../../../app.config';
import { ConfirmationDialogService } from '../../../../configurations/services/confirmation-dialog.service';
import { NotificationAlertService } from '../../../../shared/services/notification-alert.service';
import { DocumentDTO } from '../../../models/document-dto';
import { ManagePackageService } from '../../../services/manage-package.service';
import { ManageProductService } from '../../../services/manage-product.service';
import { AddProductComponent } from './add-product.component';

describe('AddProductComponent', () => {
  let component: AddProductComponent;
  let fixture: ComponentFixture<AddProductComponent>;
  let packageServiceStub = jasmine.createSpyObj('ManagePackageService', ['getPackages']);
  let confirmationDialougeStub = jasmine.createSpyObj('ConfirmationDialogService', ['confirm']);
  let manageProductStub = jasmine.createSpyObj('ManageProductService', ['createProduct','download']);
  let notificationStub = jasmine.createSpyObj('NotificationAlertService', ['showSuccess', 'showError']);
  let fileData = new DocumentDTO()

  class MockUserService {
    getPackages() {
      return [{'name':'basic', 'id':1}, {'name':'advance', 'id':2}, {'name':'premium', 'id':3}];
    } 
  }

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [HttpClientTestingModule,ReactiveFormsModule,FormsModule,ToastrModule.forRoot(),
        TranslateModule.forRoot(), NgSelectModule],
      declarations: [ AddProductComponent ],
      providers :[AppConfig,
        { provide: ManageProductService, useValue: manageProductStub },
        { provide: ManagePackageService, useValue: packageServiceStub }]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(AddProductComponent);
    component = fixture.componentInstance;
    const mockpackageResponse = []; 
    packageServiceStub.getPackages.and.returnValue(of(mockpackageResponse));

    component.activeStatus  = true;
    component.productDataTemp = [{'ppmId': 2, 'id': 2, 'name': 'ttvrtv', 'productDescription': 'vttvt', 'projectType': null}]
    component.productData = [{'ppmId': 1, 'id': 1, 'name': 'tvrtv', 'productDescription': 'vtvt', 'projectType': null},
    {'ppmId': 2, 'id': 2, 'name': 'ttvrtv', 'productDescription': 'vttvt', 'projectType': null}]
    component.id  = 2;
    component.fileArray = ['dfdfdf','dfdsdf']
    component.packagePlan = [{'name':'basic', 'id':1}, {'name':'advance', 'id':2}, {'name':'premium', 'id':3}];
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should create closeModal()', () => {
    const eventTrue = {
      target: {
        checked: true,
     }
    };
    const eventFalse = {
      target: {
        checked: false,
     }
    };
    component.closeModal();
    component.closeEditModel();
    component.onChangeSwitch(eventTrue)
    component.onChangeSwitch(eventFalse)
  });

  // it('should create ngOnChanges', () => {
  //   component.ngOnChanges();
  // });

  it('should create choosePackages', () => {
    const event = {};
    component.choosePackages(event);
  });

  it('should create subscriptionPackages()', () => {
    component.subscriptionPackages();
    expect(component.packagePlan).toBeTruthy();
  });

//   it('should handle error subscriptionPackages', () => {
//     spyOn(window, 'alert');
//     packageServiceStub.getPackages.and.returnValue(throwError({ error: 'some error'}));
//     component.subscriptionPackages();
// });

  it('should create addDocument()', () => {
    component.addDocument();
  });

  it('should create deleteRow(i: number)', () => {
    component.id  = 1;
    component.deleteRow(1);
  });

  it('should create deleteRow(i: number) nullity check', () => {
    component.id  = null;
    component.deleteRow(null);
  });

  it('should create selectFiles', () => {
    const eventSelectFiles = {
      target: {
        files: 'ss',
     }
    };
    component.selectFiles(eventSelectFiles);
  });

  it('should create onFormSubmit length>0', () => {
    component.fileArray.length = 2;
    component.onFormSubmit();
  });

  it('should create onFormSubmit nullity check', () => {
    component.productForm.value.id = null
    component.onFormSubmit();
  });

//   it('should create onFormSubmit else part', (done) => {
//     const confirmationResponse = {}; // Keep is as your response
//     let spy = spyOn( confirmationDialougeStub,'confirm').and.returnValue(Promise.resolve(true));
//   //   fixture.whenStable().then(confirmed => {
//   //     fixture.detectChanges();
//   //     component.onFormSubmit();
//   //  })

//   spy.calls.mostRecent().returnValue.then(() => {
//     fixture.detectChanges();
//     //component.onFormSubmit();
//     done();
// });
//   });

// it('should create onFormSubmit else part', () => {
//   confirmationDialougeStub.confirm.and.returnValue({
//     closePromise : {
//       then : function(callback) {
//         callback({value: true});
//       }
//     }
//   });
 
// });

  it('should create upload download', () => {
    const eventFile = {
      target: {
        files: true,
     }
    };
    component.upload(eventFile);
  });

});

问题:-我有一些关于茉莉的以下建议,并试图找到实现同样目标的方法。

  1. 我想不出如何覆盖或测试承诺的回报

    this.confirmationDialogService.confirm(‘Are您确定吗?’,‘您真的要激活/停用包吗?’) .然后((已确认)=>;{

在代码覆盖中,上面的代码行没有被覆盖,我不知道哪里出了问题,我尝试了这么多方法,并引用了Stackoverflow本身的许多帖子,但这些方法对我的用例都不起作用。

  1. 如何为具有foreach()filter()map()

    的方法编写测试用例
  2. 如何编写具有可观察、可订阅和可承诺的方法的测试用例

请建议最佳实践。

推荐答案

您的组件很长,我将向您展示如何使用PromisesObservables覆盖以下行。

this.confirmationDialogService.confirm('Are you sure ?', 'Do you really want to Activate/ Deactivate Package ?')
      .then((confirmed) => {
        if (confirmed) {
          this.manageProduct.createProduct(this.fData).subscribe(

进行以下更改:

// dialog is spelt wrong here
let confirmationDialogStub = jasmine.createSpyObj('ConfirmationDialogService', ['confirm']);
....
providers: [
 ...
 // provide the mock for confiramtion dialog service
 { provide: ConfirmationDialogService, usevalue: confirmationDialogStub },
 { provide: ManageProductService, useValue: manageProductStub },
 { provide: ManagePackageService, useValue: packageServiceStub }
],

// fakeAsync because we need tick (wait for promises to resolve before asserting)
it('does abc', fakeAsync(() => {
  // mock the value for confirmation with a promise
  confirmationDialogStub.confirm.and.returnValue(Promise.resovle(true));
  manageProductStub.createProduct.and.returnValue(of({/* mock however you wish */}));
  // call the method
  component.onFormSubmit();
  // wait for all promises to resolve with tick
  tick();
  // do your assertions
}));

对于forEachfiltermap,请确保模拟数组。数组在那里。

话虽如此,我强烈建议您查看以下资源,它们将对您有很大帮助。

https://testing-angular.com/ ^一本写得很好的电子书。

https://www.pluralsight.com/courses/unit-testing-angular ^一个关于角度单元测试的非常好的类。

这篇关于承诺的角度单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆