【问题标题】:Testing component extending two other components in Angular / Jasmine在 Angular / Jasmine 中扩展其他两个组件的测试组件
【发布时间】:2020-03-20 13:52:56
【问题描述】:

我有三个相互扩展的组件 TileComponent -> CollectionElementComponent -> SelectableItemComponent。现在,我正在尝试使用 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)

selectable-item.component.ts:26:14 指代此调用(另请参阅下面的代码 sn-p):this.selectableService.onDeselectAllSelectedItems.pipe(...)

我这样初始化测试组件:

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>();
}

这种将服务注入组件的方式适用于其他组件测试,所以我不完全确定它为什么会在这里失败。我已经尝试了几乎所有东西,在两个父组件的声明中使用ng-mocksMockComponent(),尝试模拟父母并使用{ provide: ComponentName, useClass: MockComponentName} 注入它们。还尝试在 beforeEach 方法中使用 component.ngOnInit = () =&gt; {}CollectionElementComponent.prototype.ngOnInit = () =&gt; {} 等覆盖 ngOnInit 方法。所有这些都会导致相同的错误。

受影响的组件如下所示:

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

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

这个类由 CollectionElementComponent 扩展:

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

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

最后,TileComponent 扩展了 CollectionElementComponent

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

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

非常感谢任何帮助或提示,因为我真的没有想法...... 感谢支持!

【问题讨论】:

  • 错误提示onDeselectAllSelectedItems未定义。这意味着 selectableService 已定义 并且依赖注入似乎有效。 MockSelectableService 是否有属性 onDeselectAllSelectedItems
  • 感谢@rveerd。是的,MockSelectableService 确实具有onDeselectAllSelectedItems 属性(参见上面的代码)。我是从原SelectableService复制过来的,所以应该是一模一样的。
  • 尝试调试测试以了解this.selectableService 是什么以及它具有哪些属性?
  • 无法真正让调试正常运行,但这是另一个问题。幸运的是,问题现在自己解决了,我不知道为什么。重新启动 VSCode,现在它可以工作了。无论如何感谢您的支持!

标签: angular jasmine karma-jasmine


【解决方案1】:

如果您使用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
});

【讨论】:

    猜你喜欢
    • 2019-07-03
    • 1970-01-01
    • 2018-08-01
    • 2020-12-15
    • 2018-10-02
    • 2017-09-15
    • 1970-01-01
    • 2018-04-05
    • 2017-12-02
    相关资源
    最近更新 更多