简体   繁体   English

在 Angular/Jasmine 中扩展其他两个组件的测试组件

[英]Testing component extending two other components in Angular / Jasmine

I have three components that are extending each other TileComponent -> CollectionElementComponent -> SelectableItemComponent.我有三个相互扩展的组件 TileComponent -> CollectionElementComponent -> SelectableItemComponent。 Now, I am trying to write some unit tests for the TileComponent class using Jasmine 3.4.0 and Angular 8. However, the test (should create component) fails, because the mocked selectableService is not properly injected in the extended extended component:现在,我正在尝试使用 Jasmine 3.4.0 和 Angular 8 为 TileComponent 类编写一些单元测试。但是,测试(应该创建组件)失败,因为模拟的 selectableService 没有正确注入扩展扩展组件中:

Failed: Uncaught (in promise): TypeError: Cannot read property 'pipe' of undefined
TypeError: Cannot read property 'pipe' of undefined
    at TileComponent.ngOnInit (http://localhost:9876/_karma_webpack_/src/app/shared/components/selectable/selectable-item.component.ts:26:14)
    at TileComponent.ngOnInit (http://localhost:9876/_karma_webpack_/src/app/collection/view/elements/collection-element/collection-element.component.ts:32:15)
    at TileComponent.ngOnInit (http://localhost:9876/_karma_webpack_/src/app/collection/view/elements/tile/tile.component.ts:65:15)

With selectable-item.component.ts:26:14 referring to this call (also see the code snippet further down): this.selectableService.onDeselectAllSelectedItems.pipe(...)使用selectable-item.component.ts:26:14引用此调用(另请参阅下面的代码片段): this.selectableService.onDeselectAllSelectedItems.pipe(...)

I init the testing component like this:我像这样初始化测试组件:

beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [
                TileComponent,
            ],
            providers: [
                { provide: SelectableService, useClass: MockSelectableService },
            ],
            schemas: [CUSTOM_ELEMENTS_SCHEMA],
        })
            .compileComponents()
            .then(() => {
                fixture = TestBed.createComponent(TileComponent);
                component = fixture.componentInstance;
                fixture.detectChanges();
            });
    }));

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


  ...

@Injectable()
class MockSelectableService {
    onDeselectAllSelectedItems = new EventEmitter<void>();
}

This way of injecting the service into the component worked for other component tests, so I am not entirely sure why it fails here.这种将服务注入组件的方式适用于其他组件测试,所以我不完全确定为什么它在这里失败。 I have tried pretty much everything already, using ng-mocks and MockComponent() in the declarations for the two parent components, trying to mock both parents and injecting them using { provide: ComponentName, useClass: MockComponentName} .我已经尝试了几乎所有方法,在两个父组件的声明中使用ng-mocksMockComponent() ,尝试模拟两个父组件并使用{ provide: ComponentName, useClass: MockComponentName}注入它们。 Also tried to override the ngOnInit methods using component.ngOnInit = () => {} in the beforeEach method or CollectionElementComponent.prototype.ngOnInit = () => {} etc. All of them result in the same error.还尝试使用 beforeEach 方法中的component.ngOnInit = () => {}CollectionElementComponent.prototype.ngOnInit = () => {}等覆盖 ngOnInit 方法。所有这些都会导致相同的错误。

The affected components look like this:受影响的组件如下所示:

export class SelectableItemComponent implements OnInit {
      constructor(
          public selectableService: SelectableService
      ) { }

      ngOnInit() {
          this.selectableService.onDeselectAllSelectedItems
              .pipe(takeUntil(this.componentDestroyed$))
              .subscribe(this.deselectItem.bind(this));
      }
}

This class is extended by the CollectionElementComponent:这个类由 CollectionElementComponent 扩展:

export class CollectionElementComponent extends SelectableItemComponent implements OnInit {
          constructor(
             public selectableService: SelectableService,
          ) {
             super(selectableService);
          }

          ngOnInit() {
             super.ngOnInit();
             // some other stuff
          }
}

And last, the TileComponent extending the CollectionElementComponent最后,TileComponent 扩展了 CollectionElementComponent

export class TileComponent extends CollectionElementComponent implements OnInit {
              constructor(
                 public selectableService: SelectableService,
              ) {
                 super(selectableService);
              }

              ngOnInit() {
                 super.ngOnInit();
                 // some other stuff
              }
    }

Any help or tips are highly appreciated, since I am really out of ideas... Thanks for the support!非常感谢任何帮助或提示,因为我真的没有想法......感谢您的支持!

If you are using ng-mocks you could use MockBuilder or MockProvider too:如果您使用ng-mocks,您也可以使用MockBuilderMockProvider

beforeEach(() => MockBuilder(
  TileComponent,
  [
    CollectionElementComponent,
    SelectableItemComponent,
    SelectableService,
  ],
));

it('test', () => {
  // mocking the prop of SelectableService 
  const selectedItems$ = new EventEmitter();
  MockInstance(
    SelectableService,
    'onDeselectAllSelectedItems',
    selectedItems$,
  );

  const fixture = MockRender(TileComponent);
  // should work properly now
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM