【问题标题】:ngOnInit and MediaChange testing with Karma使用 Karma 进行 ngOnInit 和 MediaChange 测试
【发布时间】:2019-04-01 02:50:58
【问题描述】:

我正在尝试测试 ngOnInit 方法中的代码。该代码监视屏幕大小的变化,以使导航栏缩小到移动设备或保持在顶部栏。我已经尝试了大约一个星期,并且在测试时不断收到一系列不同的错误。我省略了 comp.component.ts 的一些代码,因为不需要其他代码。我不断收到subscribe is not a methodCan't resolve all parameters for MediaChange: (?, ?, ?, ?)。关于如何为此编写测试的任何建议或您可能建议查看的任何资源来帮助我解决这个问题。

comp.component.ts

import { Component, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { MediaChange, ObservableMedia } from '@angular/flex-layout';

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

export class NavigationComponent implements OnInit {
    isOpen: Boolean;
    watcher: Subscription;
    activeMediaQuery = "";
    media: ObservableMedia;

    constructor() {
        this.isOpen = false;
    }

    ngOnInit(): void {
        this.watcher = this.media.subscribe((change: MediaChange) => {
            this.activeMediaQuery = change ? `'${change.mqAlias}' = (${change.mediaQuery})` : '';
            this.isOpen = false;
        });
    }

    navPressed(event, path): void {
        this.navClick.emit(path);
        if ( this.checkSize() ) this.toggle();
    }

    checkSize(): Boolean {
        return this.activeMediaQuery.includes('xs') || this.activeMediaQuery.includes('sm');
    }
}

comp.component.spec.ts

import { Component } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DebugElement } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatButtonModule, MatToolbarModule, MatIconModule } from '@angular/material';
import { CompComponent } from './comp.component';
import { Subscription } from 'rxjs';
import { MediaChange, ObservableMedia } from '@angular/flex-layout';


@Component({
    selector: 'app-test-component-wrapper',
    template: '<app-navigation [navItems]="clickables" (navClick)="handleNavClick($event)"></app-navigation>'
})

class TestWrapperComponent {
    clickables = [
        { path: '/login', label: 'Login', onClick() {} }
    ];
}

describe('app testing', () => {
    let component: CompComponent;
    let fixture: ComponentFixture<TestWrapperComponent>;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [
                MatButtonModule,
                MatToolbarModule,
                MatIconModule,
                BrowserAnimationsModule
            ],
            declarations: [
                TestWrapperComponent,
                NavigationComponent
            ],
            providers: [
                ObservableMedia,
                MediaChange,
                Subscription
            ]
        }).compileComponents();
        fixture = TestBed.createComponent(TestWrapperComponent);
    }));

    it('should create and have Login label', () => {
        // EDIT START
        spyOn(ObservableMedia, 'prototype');
        // EDIT END
        expect(fixture).toBeTruthy();
        fixture.detectChanges();
        fixture.whenStable().then(() => {
            component = fixture.debugElement.children[0].componentInstance;
            expect(component.navItems[0].label).toBe('Login');
        });
    });
});

编辑:使用我添加的代码在代码中添加了“编辑”注释。我现在收到了resolve all parameters for MediaChange: (?, ?, ?, ?) 错误,我认为这是上述订阅错误的进展。

【问题讨论】:

    标签: javascript angular typescript jasmine karma-jasmine


    【解决方案1】:

    一些观察:

    • 需要将来自 flex-layout 的 ObservableMedia 注入到您的组件中才能工作。详情here
    • 您没有在原始组件中提供 MediaChange 或 Subscription,因此也不需要在 TestBed 中提供。

    在下面的堆栈闪电战中,我必须做出一些假设。如果其中有任何错误,请告诉我,或者继续更新 stackblitz:

    • 在规范中导入了 CompComponent,但在 comp.component.ts 中定义了 NavigationComponent。在这两个中,我选择使用 NavigationComponent。
    • 上面的代码中缺少 navClick,所以我认为它是来自组件的 @Output(因为您发出了指向它的路径)。
    • 上面的代码中也缺少 navItems,但由于您正在测试它,我认为它很重要,并猜测它是您组件的输入(同样,只是您使用它的方式)。
    • 你没有包含你的模板,所以我很简单地模拟了它。
    • toggle 是从 navPressed 中调用的,但不存在,所以我将它创建为一个空函数。

    这里是堆栈闪电战:https://stackblitz.com/edit/stackoverflow-q-53024049?file=app%2Fmy.component.spec.ts

    修复您的问题:我进行了上述更改,并使用以下内容模拟了传入的 ObservableMedia 对象:

    let mockFlex = jasmine.createSpyObj({
      subscribe: ({mqAlias: 'xs', mediaQuery: ''}),
      isActive: true,
      });
    

    我还将提供者数组更改为以下内容:

    providers: [
        { provide: ObservableMedia, useValue: mockFlex }
    ]
    

    查看 stackblitz 以了解所有详细信息。如您所见,现在测试通过了。

    【讨论】:

    • 对不起,我试图重命名一些东西并清理我的帖子代码,但显然做得很糟糕,在我离开之前匆忙发布......教训学会了不要这样做再说一遍。对于那个很抱歉。我会仔细研究你的东西,看看我是否还有其他问题。感谢您的回复,非常感谢。
    • 这就像一个魅力,非常有帮助,我对注入部分感到困惑,因为它没有注入的装饰器。我还有一些关于 Angular 和测试的阅读。非常感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 2013-05-16
    • 2015-09-16
    • 2020-12-07
    • 1970-01-01
    • 2019-05-01
    • 1970-01-01
    相关资源
    最近更新 更多