MatDialog注入导致角度测试失败

时间:2018-07-05 16:12:48

标签: angular typescript karma-jasmine

我目前正在为使用MatDialog打开模式的服务构建单元测试。每种模态都在其各自的组件文件中定义。我设法为组件创建了单元测试,没有出现问题,但是服务测试抛出了以下错误:

× should successfully create an alert popup with default config
  Chrome 67.0.3396 (Windows 10 0.0.0)
Failed: this.dialog.open is not a function
    at <Jasmine>
    at PopupService.alert (dist/dev/app/shared/ui/popup/popup.service.js:9:7503)
    at UserContext.eval (dist/dev/app/shared/ui/popup/popup.service.spec.js:19:26)
    at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:388:26)
    at AsyncTestZoneSpec.onInvoke (node_modules/zone.js/dist/async-test.js:106:39)
    at ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/proxy.js:125:39)
    at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:387:32)
    at Zone.runGuarded (node_modules/zone.js/dist/zone.js:151:47)
    at runInTestZone (node_modules/zone.js/dist/async-test.js:234:29)
    at UserContext.<anonymous> (node_modules/zone.js/dist/async-test.js:168:17)
    at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:388:26)
    at ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/proxy.js:128:39)
    at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:387:32)
    at Zone.run (node_modules/zone.js/dist/zone.js:138:43)
    at runInTestZone (node_modules/zone.js/dist/jasmine-patch.js:142:34)
    at UserContext.<anonymous> (node_modules/zone.js/dist/jasmine-patch.js:158:20)
    at <Jasmine>
    at ZoneDelegate.invokeTask (node_modules/zone.js/dist/zone.js:421:31)
    at Zone.runTask (node_modules/zone.js/dist/zone.js:188:47)
    at drainMicroTaskQueue (node_modules/zone.js/dist/zone.js:595:35)

正在运行测试本身,但是(在服务中)调用MatDialog.open()时会引发此错误。当应用程序在开发中运行时,不会引发此错误。

以下是与该问题相关的代码段:

服务的测试用例:

import { inject, TestBed, async } from "@angular/core/testing";
import { PopupService } from "./popup.service";
import { MatDialogModule, MatDialog } from "@angular/material";
import { Injectable } from "@angular/core";
import { PopupAlertComponent } from './popup.component';

export function main() {

    describe('Service: PopupService', () => {

        let dialog: MatDialog,
                popupService: PopupService;

        beforeEach(() => {
            TestBed.configureTestingModule({
                providers: [
                    { provide: MatDialog, useValue: {} } //This is a workaround: otherwise a NullInjectorError is thrown
                ]
            });

            dialog = TestBed.get(MatDialog);
            popupService = new PopupService(dialog);

        });

        /*********************
         * CONFIRM           *
         ********************/
        it('should successfully create an confirm popup with default config',
            async(() => {
                popupService.confirm("test", "this is a test", "Ok", "Cancel");
            }));

        it('should successfully create an confirm popup with custom config',
            async(() => {
                let config = { disableClose: false, width: '850px' };
                popupService.confirm("test", "this is a test", "Ok", "Cancel", config);
            }));
    });
}

模态服务:

    import { Injectable } from "@angular/core";
    import { MatDialog, MatDialogRef } from "@angular/material";
    import {
        PopupAlertComponent, PopupConfirmComponent, PopupInputComponent,
        PopupBillerListComponent, PopupListComponent
    } from "./popup.component";

    export class KeyValuePair {
        id: number;
        name: string;
    }

    export class ListObject {
        id: number;
        name: string;
        imageUrl: string;
    }

    /**
     * Class used to generate popups through the app, by calling one of the functions. (alert, input, confirm..)
     */
    @Injectable()
    export class PopupService {

        /*
        Base config for popups, passed in through mdDialog config options.
        Can be temporarily modified on a specific popup, if necessary.
         */
        config = {
            disableClose: true,
            width: '330px'
        };

        constructor(public dialog: MatDialog) {

        }

        /**
         * Base popup function that sets the popup text to specified strings, or allow the default values specified in the popup.component.
         * @param popupRef
         * @param {boolean} hasButtons
         * @param {string} title
         * @param {string} message
         * @param {string} okText
         * @param {string} cancelText
         * @returns {Observable<any>}
         */
        popup(popupRef: any, hasButtons: boolean, title: string, message: string, okText: string, cancelText: string) {
            if (title !== "")
                popupRef.componentInstance.title = title;
            if (message !== "")
                popupRef.componentInstance.message = message;
            if (hasButtons) {
                if (okText !== "")
                    popupRef.componentInstance.okText = okText;
                if (cancelText !== "")
                    popupRef.componentInstance.cancelText = cancelText;
            }

            return popupRef.afterClosed();
        }

        /**
         * Input popup function with input popup specific features
         * @param {string} title
         * @param {string} message
         * @param {string} okText
         * @param {string} cancelText
         * @param {object} config (optional)
         * @returns {Observable<any>}
         */
        input(title: string, message: string, okText: string, cancelText: string, config?: {}) {
            let popupRef: MatDialogRef<PopupInputComponent>;

            popupRef = this.dialog.open(PopupInputComponent, config ? config : this.config);

            return this.popup(popupRef, true, title, message, okText, cancelText);
        }
    }

模式部分:

import { Component } from "@angular/core";
import { MatDialogRef } from "@angular/material";
import { PopupService, KeyValuePair } from "./popup.service";

/**
 * Input Popup
 * Popup that will be used in cases where a single input popup is required
 */
@Component({
    moduleId : module.id,
    selector: 'tp-input-popup',
    template: `
        <div class="body">
            <mat-dialog-content>
                <h4><p class="text-center">{{title | translate}}</p></h4>
                <hr>
            </mat-dialog-content>
            <mat-dialog-actions align="end">
                <div class="group">
                    <input #input
                           id="input"
                           type="tel"
                           [ngClass]="input.validity.valid ? 'used' : false"
                           required>
                    <span class="highlight"></span>
                    <span class="bar"></span>
                    <label>{{message | translate}}</label>
                </div>
                <div class="button-position">
                    <button mat-button type="button" class="button" (click)="popup.close(false)">
                        <span><b>{{cancelText | translate}}</b></span>
                    </button>
                    <button mat-raised-button type="button" class="button" (click)="popup.close(input.value)">
                        <span><b>{{okText | translate}}</b></span>
                    </button>
                </div>
            </mat-dialog-actions>
        </div>
    `,
    styleUrls  : ['popup.component.css']
})
export class PopupInputComponent {
    title: string      = "Input";
    message: string    = "Enter your data here:";
    okText: string     = "Ok";
    cancelText: string = "Cancel";

    constructor(public popup: MatDialogRef<PopupInputComponent>) {
    }
}

有多个函数(例如输入),每个函数都调用不同的模式,但是为了简洁起见,我仅包含其中一个。如果需要,我可以在问题的代码片段中包含其他模式类型。

我在搜索过程中发现了其他问题,这些问题看起来很相似,但是没有一个问题可以解决Karma中的这一特定错误。

0 个答案:

没有答案