测试用例未在ViewContainerRef中检测到更新

时间:2019-01-29 19:23:06

标签: angular6

我的html使用ng-template。该模板用于创建缩略图。

 <ng-template #thumbnailTemplate let-option="option">

      <div id="{{option.divId}}"> <!-- top level div of thumbnail. This will have ids thumbnail-1, thumbnail-2 etc.-->
        <img id="{{option.imgId}}" src="{{option.imgSrc}}"> <!-- this will have width, height=80-->
        <a href="#" id="{{option.closeId}}" (click)="deleteThumbnail(option)"></a> <!-- the X button is created using CSS. This will have ids close-button-1, close-button-2. They'll also containn reference to the parent div id (thumbnail-1, thumbnail-2 ) -->
      </div>
    </ng-template>

input元素中选择文件后,将创建缩略图。 FileReader发送load事件,并调用我的事件处理程序,该事件处理程序应通过在容器中添加视图来创建缩略图

handleReaderLoaded(event:FileReaderProgressEvent) {
    console.log("got load event of file reader ",event);
    let thumbnailTemplateViewRef:EmbeddedViewRef<any>;

    let imageString = event.target.result;//this will be like data:image/png;base64,ZGQ=ZGF0YTppbWFnZS9wbmc7YmFzZTY0LFpHUT0=

    console.log("result from file load: ",imageString);
    console.log("consecutive generator is ",this.consecutiveIdGenerator);
    //create new ids for div, img and a in the template
    ++this.consecutiveIdGenerator;
    let divId = "thumbnail-"+(this.consecutiveIdGenerator);
    console.log("div id "+divId);

    let imgId = "img-"+(this.consecutiveIdGenerator);
    console.log("img id "+imgId);


    let closeId = "close-button-"+(this.consecutiveIdGenerator);

    console.log("close Id is "+closeId);
    console.log("thumbnail container length was "+this.thumbnailContainerRef.length);

    //TODOM - define context as a class so that it can be used in new question and question details
    thumbnailTemplateViewRef = this.thumbnailContainerRef.createEmbeddedView(this.thumbnailTemplateRef,{option:{divId:divId,
        imgId:imgId,
        closeId:closeId,
        imgSrc:imageString}});

    //store the reference of the view in context of the template. This will be used later to retrive the index of the view when deleting the thumbnail
    thumbnailTemplateViewRef.context.option.viewRefId = thumbnailTemplateViewRef;
    console.log("thumbnail container length is "+this.thumbnailContainerRef.length);
  }

现在,我想测试handleReaderLoaded并检查它是否通过在其中添加thumbnailContainerRef来更新thumbnailTemplateViewRef

我写的规范是

fit('should upload image if user selects an image', () => {
    let newPracticeQuestionComponent = component;
    expect(newPracticeQuestionComponent.currentImageAttachmentCount).toBe(0);
    expect(newPracticeQuestionComponent.thumbnailContainerRef.length).toBe(0);

    let file1 = new File(["foo1"], "foo1.txt");

    let reader = newPracticeQuestionComponent.handleFileSelect([file1]);//the callback for FileReader load method is assigned in this function. The callback is handleReaderLoaded
fixture.detectChanges();
    expect(newPracticeQuestionComponent.currentImageAttachmentCount).toBe(1);
    expect(newPracticeQuestionComponent.thumbnailContainerRef.length).toBe(1);
    done(); //wait
console.log('done here');
  });

我的测试用例失败,因为expect(newPracticeQuestionComponent.thumbnailContainerRef.length).toBe(1);的结果为0。

我在做什么错?

1 个答案:

答案 0 :(得分:0)

似乎,我不正确理解done的目的。我以为如果我使用done,该脚本将自动等待,但不会等待(如以下跟踪所示)

reading file->在handleFileSelect中 context.js:1972 done here->在handleFileSelect中 context.js:1972 got load event of file reader ProgressEvent {isTrusted: true, lengthComputable: true, loaded: 4, total: 4, type: "load", …}->位于回调handleReaderLoaded中。因此规范在调用回调之前完成。

done充当Jasmine中的检查点。当Jasmine看到某个规范使用done时,它知道除非调用了包含done的代码段,否则它无法继续进行下一步(例如运行下一个规范)。

我重新编写了规范,并使用done如下创建了检查点

it('should upload image if user selects an image', (done) => {
    let newPracticeQuestionComponent = component;
    expect(newPracticeQuestionComponent.currentImageAttachmentCount).toBe(0);
    expect(newPracticeQuestionComponent.thumbnailContainerRef.length).toBe(0);

    let imageThumbnailDiv = fixture.debugElement.query(By.css("#thumbnail-1"));
    let imageThumbnailImg = fixture.debugElement.query(By.css('#img-1'));
    let imageThumbnailClose = fixture.debugElement.query(By.css('#close-button-1'));

//there should not be any HTML code which contains thumbnail
    expect(imageThumbnailDiv).toBeFalsy();
    expect(imageThumbnailImg).toBeFalsy();
    expect(imageThumbnailClose).toBeFalsy();

    let file1 = new File(["foo1"], "foo1.txt");
    let reader = newPracticeQuestionComponent.handleFileSelect([file1]);
//file upload is async. so give time for `load` event of FileReader to be triggered and handled
    setTimeout(function() {
      console.log("in timeout");

      fixture.detectChanges();//without this, the view will not be updated with model
      expect(newPracticeQuestionComponent.currentImageAttachmentCount).toBe(1);
      expect(newPracticeQuestionComponent.thumbnailContainerRef.length).toBe(1);
//the html for thumbnail should be created now
      let imageThumbnailDiv2 = fixture.debugElement.query(By.css("#thumbnail-1"));
      let imageThumbnailImg2= fixture.debugElement.query(By.css('#img-1'));
      let imageThumbnailClose2 = fixture.debugElement.query(By.css('#close-button-1'));

      expect(imageThumbnailDiv2).toBeTruthy();
      expect(imageThumbnailImg2).toBeTruthy();
      expect(imageThumbnailClose2).toBeTruthy();
      done();//without done, jasmine will finish this test spec without checking the assertions in the timeout
    }, 2000);


    //if done is not use, jasmine will just finish the current spec without checking any assertions

  });