Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/417.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 角度异步管道在单元测试中未正确更新_Javascript_Angular_Unit Testing_Jasmine - Fatal编程技术网

Javascript 角度异步管道在单元测试中未正确更新

Javascript 角度异步管道在单元测试中未正确更新,javascript,angular,unit-testing,jasmine,Javascript,Angular,Unit Testing,Jasmine,在编写单元测试时,通过HTML中的async管道呈现更新可观察对象时,我面临一个问题 我的想法是,我不仅要测试组件,还要测试子组件是否都被渲染并具有正确的输入 这是出现问题的最小示例: <ng-container *ngFor="let plan of plans$ | async"> <child-component [plan]="plan"></child-component> </ng-containe

在编写单元测试时,通过HTML中的
async
管道呈现更新可观察对象时,我面临一个问题

我的想法是,我不仅要测试组件,还要测试子组件是否都被渲染并具有正确的输入

这是出现问题的最小示例:

<ng-container *ngFor="let plan of plans$ | async">
  <child-component [plan]="plan"></child-component>
</ng-container>

Visible plans: {{ plans$ | async | json }}

可见计划:{{plans$| async | json}
组件的最小示例:

export class RecommendationsComponent implements OnInit {
  public plans$: Observable<Plan[]>;

  constructor(private readonly _store: Store<State>) {
    this.plans$ = this._store.pipe(select(selectRecommendationsPayload));
  }

  public ngOnInit(): void {
    this.getRecommendations(); // Action dispatch, state is filled with data
  }
}
导出类建议组件实现OnInit{
公共计划:可见;
构造函数(私有只读存储:存储){
this.plans$=this.\u store.pipe(select(selectRecommendationsPayload));
}
public ngOnInit():void{
this.getRecommensions();//动作分派,状态为数据填充
}
}
此模块/组件的单元测试:

describe('Recommendations', () => {
  let component: RecommendationsComponent;
  let fixture: ComponentFixture<RecommendationsComponent>;
  let store: Store<any>;
  let mockStore: MockStore<any>;
  let actions$: ReplaySubject<any> = new ReplaySubject<any>();

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [RecommendationsComponent],
      imports: [RouterTestingModule.withRoutes([]), HttpClientTestingModule],
      providers: [
        MockStore,
        provideMockStore({ initialState: initialStateMock }),
        provideMockActions(() => actions$),
      ],
    });

    store = TestBed.inject(Store);
    mockStore = TestBed.inject(MockStore);

    fixture = TestBed.createComponent(RecommendationsComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should successfully retrieve and handle plans', () => {
    recommendationsService.getRecommendations = jasmine.createSpy().and.returnValue(of(plans)); // Mock BE response with non-empty data

    component.plans$.subscribe(plans => {
      console.log(plans);
      console.log(fixture.debugElement);
      // A few expect() based on state and HTML...
      // This fires since all logic starts on ngOnInit() lifecycle
    });
  });
});
description('建议',()=>{
let组件:推荐组件;
let夹具:组件夹具;
让店:店;
让mockStore:mockStore;
让操作$:ReplaySubject=新建ReplaySubject();
beforeach(异步()=>{
等待TestBed.configureTestingModule({
声明:[建议组件],
导入:[RouterTestingModule.withRoutes([]),HttpClientTestingModule],
供应商:[
模拟商店,
provideMockStore({initialState:initialStateMock}),
provideMockActions(()=>actions$),
],
});
store=TestBed.inject(store);
mockStore=TestBed.inject(mockStore);
fixture=TestBed.createComponent(推荐组件);
组件=fixture.componentInstance;
fixture.detectChanges();
});
它('应成功检索和处理计划',()=>{
recommendationsService.getRecommendations=jasmine.createSpy().and.returnValue(of(plan));//使用非空数据模拟BE响应
component.plans$.subscribe(计划=>{
控制台日志(计划);
console.log(fixture.debugElement);
//一些基于状态和HTML的expect()。。。
//这是因为所有逻辑都在ngOnInit()生命周期上启动
});
});
});
而真正的代码和
console.log(计划)显示正确的数据,由于某种原因,HTML中的
计划$| async
始终具有默认状态。这个问题只与HTML有关

我的尝试:

  • 添加
    fixture.detectChanges()
    -在
    beforeach()
    it
    测试用例中,几乎每隔一行就添加这一行(到了如此极端的程度),但没有任何更改
  • 硬编码为
    component.plans$=of([{name:'name'}如有])
    it
    测试用例中(我想知道这是否与Store/MockStore有关,但即使是硬编码的值在HTML中也似乎不起作用)
  • 使用
    fixture.whenRenderingDone()。然后(async()=>{
    })在整个测试用例中(可能在出现
    console.log()
    行时HTML没有呈现)
  • 与第三个类似,我也尝试了使用
    setTimeout()
    ,理由相同
  • 我的其他想法也是:

  • 我在
    声明
    导入
    等方面遗漏了什么
  • MockStore/Store无法正确触发对
    异步
    管道的更改(尽管它们适用于
    订阅()

  • 如果缺少什么,请告诉我。提前谢谢。

    我感到奇怪的是,你对
    store
    mockStore
    都有控制权

    我想你应该只用一个。我对mockStore没有太多经验,所以我会尝试实际的商店。尝试执行集成测试,如图所示。通过集成测试,我们有实际的存储,而不是模拟存储

    describe('Recommendations', () => {
      let component: RecommendationsComponent;
      let fixture: ComponentFixture<RecommendationsComponent>;
      let store: Store<any>;
      let actions$: ReplaySubject<any> = new ReplaySubject<any>();
    
      beforeEach(async () => {
        await TestBed.configureTestingModule({
          declarations: [RecommendationsComponent],
          imports: [
             RouterTestingModule.withRoutes([]), 
             HttpClientTestingModule,
             StoreModule.forRoot({
               // Pay attention here, make sure this is provided in a way
               // where your selectors will work (make sure the structure is
               // good)
               recommendations: recommendationsReducer,
             })
          ],
        });
    
        store = TestBed.inject(Store);
        // load the recommendations into the store by dispatching
        store.dispatch(new loadRecommendations([]));
        fixture = TestBed.createComponent(RecommendationsComponent);
        component = fixture.componentInstance;
        // see your state here, make sure the selector works
        store.subscribe(state => console.log(state));
        // any time you want to change plans, do another dispatch
        store.dispatch(new loadRecommendations([/* add stuff here */]));
        // the following above should make plans$ emit every time
        fixture.detectChanges();
      });
      
    
     // !! -- The rest is up to you from now on but what I presented above
     // should help in getting new plans$ with the async pipe !!-
    
      it('should successfully retrieve and handle plans', () => {
        recommendationsService.getRecommendations = jasmine.createSpy().and.returnValue(of(plans)); // Mock BE response with non-empty data
    
        component.plans$.subscribe(plans => {
          console.log(plans);
          console.log(fixture.debugElement);
          // A few expect() based on state and HTML...
          // This fires since all logic starts on ngOnInit() lifecycle
        });
      });
    });
    
    description('建议',()=>{
    let组件:推荐组件;
    let夹具:组件夹具;
    让店:店;
    让操作$:ReplaySubject=新建ReplaySubject();
    beforeach(异步()=>{
    等待TestBed.configureTestingModule({
    声明:[建议组件],
    进口:[
    RouterTestingModule.withRoutes([]),
    HttpClientTestingModule,
    StoreModule.forRoot({
    //注意这里,确保以适当的方式提供
    //选择器工作的位置(确保结构正确
    //好的)
    建议:建议减速器,
    })
    ],
    });
    store=TestBed.inject(store);
    //通过调度将建议加载到存储中
    存储、发送(新装载建议([]);
    fixture=TestBed.createComponent(推荐组件);
    组件=fixture.componentInstance;
    //在此处查看您的状态,确保选择器工作正常
    订阅(state=>console.log(state));
    //任何时候你想改变计划,再做一次调度
    store.dispatch(新加载建议([/*在此处添加内容*/]);
    //下面的内容每次都应该制定$emit计划
    fixture.detectChanges();
    });
    //!!--从现在起,剩下的由您决定,但我在上面介绍了什么
    //应该有助于通过异步管道获得新计划-
    它('应成功检索和处理计划',()=>{
    recommendationsService.getRecommendations=jasmine.createSpy().and.returnValue(of(plan));//使用非空数据模拟BE响应
    component.plans$.subscribe(计划=>{
    控制台日志(计划);
    console.log(fixture.debugElement);
    //一些基于状态和HTML的expect()。。。
    //这是因为所有逻辑都在ngOnInit()生命周期上启动
    });
    });
    });
    
    Hmm,似乎对我不起作用(
    错误:NgModule'DynamicTestModule'的提供程序无效-只允许提供程序和类型的实例
    )。我使用了两个不同的商店,因为在某些情况下,效果或动作都不会被触发。我可能走错方向了。谢谢你的代码和链接,我将尝试更新和测试,看看是否我的c