茉莉花测试,从列表中选择项目

时间:2018-11-27 16:44:59

标签: javascript angular karma-jasmine

我有一个角度应用程序,我需要使用Jasmine对某些方法进行一些单元测试。在这种情况下,我会对选择列表进行单元测试。这样选择列表就不会为空。

方法如下:

 createStatusOptions(listValueoptions: OptionModel[], resources: any): OptionModel[] {
        const processStatusOptions = listValueoptions.map(listValueOption => {
            listValueOption.value = `${caseStatusEnum.inProgress}_${listValueOption.value}`;
            listValueOption.selected = true;
            return listValueOption;
        });

        const caseStatusEnumKeys = Object.keys(caseStatusEnum).filter(key => !isNaN(Number(key)));
        const enumOptions = this.optionService.createOptions(
            new ConfigOptionModel({ source: caseStatusEnumKeys, resources, resourcesModel: enumResourcesModel, isCustomEnum: true, }));

        return [
            this.getEnumOption(enumOptions, caseStatusEnum.submitted, true),
            ...processStatusOptions,
            this.getEnumOption(enumOptions, caseStatusEnum.closed),
        ];
    }

 private getEnumOption(options: OptionModel[], enumType, isSelected = false): OptionModel {
        const option = options.filter(enumOption => enumOption.value === `${enumType}`)[0];
        option.selected = isSelected;
        return option;
    }

我有这样的单元测试:

it('should create status options when there ar list value options are provided', () => {
        optionService.options = [
            {
                value: caseStatusEnum.submitted.toString(),
            },
            {
                value: caseStatusEnum.inProgress.toString(),
            },
            {
                value: caseStatusEnum.closed.toString(),
            },
        ] as OptionModel[];



        // tslint:disable-next-line:max-line-length
        const result = service.createStatusOptions(optionService.options, [[103], [104], [105] ]);
        console.log(result);
       expect(result.length).toBe(2);
        expect(result).toEqual([{ value: '103', selected: true }, { value: '105', selected: false }]);

    });

但是我收到这样的错误:

Services: CaseService > should create status options when there ar list value options are provided
TypeError: Cannot set property 'selected' of undefined
    at <Jasmine>
    at CaseService.getEnumOption (http://localhost:9878/src/app/case/src/services/case.service.ts?:130:9)
    at CaseService.getEnumOption [as createStatusOptions] (http://localhost:9878/src/app/case/src/services/case.service.ts?:109:22)
    at UserContext.<anonymous> (http://localhost:9878/src/app/case/src/services/case.service.spec.ts?:149:32)
    at ZoneDelegate.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/zone.js?:388:1)
    at ProxyZoneSpec.push.../../node_modules/zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/proxy.js?:128:1)
    at ZoneDelegate.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/zone.js?:387:1)
    at Zone.../../node_modules/zone.js/dist/zone.js.Zone.run (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/zone.js?:138:1)
    at runInTestZone (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/jasmine-patch.js?:145:1)
    at UserContext.<anonymous> (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/jasmine-patch.js?:160:1)
    at <Jasmine>

所以我的问题是:如何解决这个问题?

谢谢

如果我这样做:

   console.log(optionService.options);

我得到以下输出:

Array(3)
0: {value: "103", selected: true}
1: {value: "104"}
2: {value: "105", selected: false}
length: 3
__proto__: Array(0)

这是文件:

import { fakeAsync, tick } from '@angular/core/testing';
import { FormServiceMock, MultiFileUploadServiceMock } from 'afw/forms/testing';
import { AfwHttp } from 'afw/generic-services';
import { AfwHttpMock, OptionServiceMock } from 'afw/generic-services/testing';
import { OptionModel, SearchResultModel } from 'afw/models';
import { FeedbackStoreServiceMock } from 'afw/store-services/testing';
import { RouterMock } from 'afw/testing';
import { PagingDataModel, TableSortDataModel } from 'afw/ui-components';
import { caseOwnerEnum, caseStatusEnum, caseTypeEnum, MultiFileUploadResourcesModel } from 'lr/models';
import { Observable, observable } from 'rxjs';
import { CaseTypeInfoModel } from 'support-shared/base/models';
import { CaseTypeInfoStoreServiceMock } from 'support-shared/base/services/case-type-info-store.service.mock';
import { CaseFormComponent } from '../case-base/src/case-form/case-form.component';
import { CaseBaseModel, CaseReferenceModel } from '../models';
import { CaseService } from './case.service';

let service: CaseService;
let afwHttpMock: AfwHttpMock;
// tslint:disable-next-line:prefer-const
let formServiceMock: FormServiceMock;
let multiFileUploadService: MultiFileUploadServiceMock;
let router: RouterMock;
let feedbackStoreService: FeedbackStoreServiceMock;
let optionService: OptionServiceMock;
let caseTypeInfoStoreService: CaseTypeInfoStoreServiceMock;
// tslint:disable-next-line:prefer-const
let component: CaseFormComponent;


fdescribe('Services: CaseService', () => {

    beforeEach(() => {
        afwHttpMock = new AfwHttpMock();
        multiFileUploadService = new MultiFileUploadServiceMock();
        router = new RouterMock();
        feedbackStoreService = new FeedbackStoreServiceMock();
        optionService = new OptionServiceMock();
        caseTypeInfoStoreService = new CaseTypeInfoStoreServiceMock();
        service = new CaseService(afwHttpMock as any, multiFileUploadService as any, router as any,
            feedbackStoreService as any, optionService as any, caseTypeInfoStoreService as any);
    });

    it('should create an instance', () => {
        expect(service).toBeTruthy();
    });

    it('should get case reference details', () => {
        afwHttpMock.setupOnlyResponse({ type: caseTypeEnum.revisionRequest, details: { bsn: 'bsnLabel' } }, 200);
        const d = service.getCaseReferenceDetails('spinnerMessage', { reference: '112314121', type: caseTypeEnum.revisionRequest });
        d.subscribe(r => {
            expect(r.details.length === 1);
            expect(r.details[0].key).toBe('bsn');
            expect(r.details[0].value).toBe('bsnLabel');
            expect((r.details[0] as any).resourceKey).toBe('bsn');
        });
        afwHttpMock.returnSuccessResponse();
    });


    // tslint:disable-next-line:no-identical-functions
    it('should get case reference details with full response', () => {
        afwHttpMock.setupOnlyResponse({ body: { type: caseTypeEnum.revisionRequest, details: [{ key: 'hoi' }] } }, 200);
        const d = service.getCaseReferenceDetailsFullResponse('spinnerMessage', { reference: '100001075', type: caseTypeEnum.revisionRequest });
        // tslint:disable-next-line:no-commented-code
        // tslint:disable-next-line:no-identical-functions
        /*  let result;
         d.subscribe(r => {
             result = r;
         }); */

        d.subscribe(r => {
            expect(r.ok === true);
            expect(r.body.details[0].key).toBe('hoi');
        });

        afwHttpMock.returnSuccessResponse();
        // expect(result.ok === true);
        // expect(result.)

    });


    // tslint:disable-next-line:no-commented-code
    it('shoud get case type info configuration that is used on various views when snapshot exists', () => {
        let result99: Observable<CaseTypeInfoModel[]>;
        result99 = service.getCaseTypeInfo('spinner') as Observable<CaseTypeInfoModel[]>;
        const response = [{ mock: 'mock' } as any];
        service['caseTypeInfoSnapshot'] = response;
        service.getCaseTypeInfo('spinner').subscribe(i => {
            expect(i).toEqual(response);
        });
    });

    // tslint:disable-next-line:no-identical-functions
    it('shoud get case type info configuration that is used on various views when snapshot doesnt exists', () => {
        let result99: Observable<CaseTypeInfoModel[]>;
        const spy = spyOn(caseTypeInfoStoreService, 'addCaseTypeInfoToStore');
        result99 = service.getCaseTypeInfo('spinner') as Observable<CaseTypeInfoModel[]>;
        const response = [{ mock: 'mock' } as any];
        service['caseTypeInfoSnapshot'] = response;
        // caseTypeInfoStoreService..subscribe((result) => { expect(result).toBe(false); });
        result99.subscribe((result) => {
            expect(response).toEqual(response);
        });


        afwHttpMock.setupOnlyResponse(result99, 200);
        afwHttpMock.returnSuccessResponse();
    });

    it('should create status options when no list value options are provided', () => {
        optionService.options = [
            {
                value: caseStatusEnum.submitted.toString(),
            },
            {
                value: caseStatusEnum.inProgress.toString(),
            },
            {
                value: caseStatusEnum.closed.toString(),
            },
        ] as OptionModel[];


        // tslint:disable-next-line:no-commented-code
        //  const spy = spyOn(service, 'createStatusOptions');
        const result = service.createStatusOptions([], {});
        expect(result.length).toBe(2);
        expect(result).toEqual([{ value: '103', selected: true }, { value: '105', selected: false }]);
        // tslint:disable-next-line:no-commented-code
        //  const response = [{ mock: 'mock' } as any];
        // expect(spy).toBe(result);
    });

    it('should create status options when there ar list value options are provided', () => {
        optionService.options = [
            {
                value: caseStatusEnum.submitted.toString(),
            },
            {
                value: caseStatusEnum.inProgress.toString(),
            },
            {
                value: caseStatusEnum.closed.toString(),
            },
        ] as OptionModel[];



        // tslint:disable-next-line:max-line-length
        const result = service.createStatusOptions(optionService.options, 103);
        console.log(optionService.options);
        expect(result.length).toBe(2);
        expect(result).toEqual([{ value: '103', selected: true }, { value: '105', selected: false }]);

    });






    it('should get case reference without details', () => {
        afwHttpMock.setupOnlyResponse({}, 200);
        const spy = spyOn(afwHttpMock, 'post').and.callThrough();
        const model = new CaseReferenceModel({ reference: '112314121', type: caseTypeEnum.revisionRequest });
        const d = service.getCaseReferenceDetails('spinnerMessage', model);
        d.subscribe(r => {
            expect(r).toBeDefined();
        });
        expect(spy).toHaveBeenCalledWith('api/support/cases/get-reference-details', model, 'spinnerMessage');
        afwHttpMock.returnSuccessResponse();
    });

    it('should add case reference without details', () => {
        afwHttpMock.setupOnlyResponse({}, 200);
        const spy = spyOn(afwHttpMock, 'post').and.callThrough();
        const model = new CaseReferenceModel({ reference: '112314121', type: caseTypeEnum.revisionRequest });
        const d = service.addCase('spinnerMessage', model as any);
        d.subscribe(r => {
            expect(r).toBeDefined();
        });
        expect(spy).toHaveBeenCalledWith('api/support/cases', model, 'spinnerMessage');
        afwHttpMock.returnSuccessResponse();
    });

    it('should search for cases', () => {
        const formModel: any = { makeQueryString: () => 'name=test' };
        const pagingModel = new PagingDataModel({ currentPage: 10, itemsPerPage: 20 });
        const sortModel = new TableSortDataModel({ columnName: 'kol', isDescending: false });

        const spy = spyOn(afwHttpMock, 'get').and.callThrough();
        const mockData = [
            new CaseBaseModel({
                id: 100000001,
                type: caseTypeEnum.revisionRequest,
                status: caseStatusEnum.inProgress,
                substatus: 5266,
                verdict: null,
                owner: caseOwnerEnum.caseManager,
                dateSubmitted: '02-02-2009',
                dateClosed: '',
                reference: 'aaa',
            }),
        ];

        const setupResponse = new SearchResultModel<CaseBaseModel>();
        setupResponse.result = mockData;
        setupResponse.totalResultCount = 27;

        afwHttpMock.setupOnlyResponse(setupResponse, 200);
        let response: SearchResultModel<CaseBaseModel>;
        service.search(formModel, sortModel, pagingModel, 'spinnerText').subscribe(result => {
            response = result;
        });
        afwHttpMock.returnOnlyResponse();

        expect(spy).toHaveBeenCalledWith('api/support/cases?name=test&columnName=kol&isDescending=false&currentPage=10&itemsPerPage=20',
            'spinnerText');
        expect(response).toEqual(setupResponse);
        expect(response.result[0].getResourceForStatus).toBeDefined();
    });

    it('should save documents', fakeAsync(() => {
        const spy = spyOn(multiFileUploadService, 'syncFilesWithBackend').and.callThrough();
        const spyRouter = spyOn(router, 'navigate').and.callThrough();
        const spyFeedback = spyOn(feedbackStoreService, 'addSuccessMessageOnMainPortal');
        service.saveDocuments(1, [{} as any], MultiFileUploadResourcesModel.keys, '../', { key: 'da', value: 'fa' });
        expect(spy).toHaveBeenCalledWith('api/support/cases/1/documents', [{}],
            MultiFileUploadResourcesModel.keys.bijlageToevoegenSpinnerTekst,
            MultiFileUploadResourcesModel.keys.bijlageVerwijderenSpinnerTekst
        );
        tick();
        expect(spyRouter).toHaveBeenCalledWith(['../']);
        expect(spyFeedback).toHaveBeenCalled();
    }));

    it('should not save documents if there are no documents in array', fakeAsync(() => {
        const spy = spyOn(multiFileUploadService, 'syncFilesWithBackend').and.callThrough();
        const spyRouter = spyOn(router, 'navigate').and.callThrough();
        const spyFeedback = spyOn(feedbackStoreService, 'addSuccessMessageOnMainPortal');
        service.saveDocuments(1, [], MultiFileUploadResourcesModel.keys, '../', { key: 'da', value: 'fa' });
        expect(spy).not.toHaveBeenCalled();
        tick();
        expect(spyRouter).toHaveBeenCalledWith(['../']);
        expect(spyFeedback).toHaveBeenCalled();
    }));

    it('should save documents and report errors', fakeAsync(() => {
        multiFileUploadService.setResponse([{}, { error: {} }]);
        spyOn(multiFileUploadService, 'makeWarningMessageForUnsyncedFiles').and.returnValue('mock');
        const spyRouter = spyOn(router, 'navigate').and.callThrough();
        const spyFeedback = spyOn(feedbackStoreService, 'addWarningMessageOnMainPortal');
        const spy = spyOn(multiFileUploadService, 'syncFilesWithBackend').and.callThrough();
        service.saveDocuments(1, [{} as any], MultiFileUploadResourcesModel.keys, '../', { key: 'da', value: 'fa' });
        expect(spy).toHaveBeenCalledWith('api/support/cases/1/documents', [{}],
            MultiFileUploadResourcesModel.keys.bijlageToevoegenSpinnerTekst,
            MultiFileUploadResourcesModel.keys.bijlageVerwijderenSpinnerTekst
        );
        tick();
        expect(spyRouter).toHaveBeenCalledWith(['../']);
        expect(spyFeedback).toHaveBeenCalled();
    }));


    it('should get case by id', () => {
        const id = 66208014;
        const setupResponse = new CaseBaseModel({
            id,
            dateSubmitted: '',
            owner: caseOwnerEnum.caseManager,
            reference: 'ksjhkjshdf',
            status: caseStatusEnum.submitted,
            type: caseTypeEnum.revisionRequest,

        });
        afwHttpMock.setupOnlyResponse(setupResponse, 200);
        service.getCase(id, 'spinner').subscribe(r => {
            expect(r).toEqual(setupResponse);
        });
        afwHttpMock.returnSuccessResponse();
    });

    it('edit the case with model', () => {
        const spy = spyOn(service, 'editCase').and.callThrough();

        const caseUpdate = new CaseBaseModel({
            id: 100001075,
            dateSubmitted: '',
            owner: caseOwnerEnum.caseManager,
            reference: 'ksjhkjshdf',
            status: caseStatusEnum.submitted,
            type: caseTypeEnum.revisionRequest,

        });
        service.editCase('spinner', caseUpdate);
        expect(spy).toHaveBeenCalledWith('spinner', caseUpdate);
        expect(caseUpdate.id).toEqual(100001075);
    });
});

1 个答案:

答案 0 :(得分:1)

根据到目前为止的显示,我的猜测是传递给options的{​​{1}}参数是不确定的,这会导致您看到错误。在getEnumOption()中快速进行getEnumOption()验证。

如果您的代码可以正常工作,但仅在测试中失败,那么我会再次猜测您没有正确模拟/ spiedOn console.log(options),因为它设置了可能未定义的options参数。那会在.spec文件中更早完成的-如果您发布整个文件,那么这将帮助其他阅读您的问题的人确定是否是这种情况。

使用Stackblitz更新

我将您所有的代码放入Stackblitz中进行测试。我猜不到它的功能,有很多我无法访问的代码。但是,我确实发现了一些东西。

首先,当您进行测试时,您似乎在对this.optionService.createOptions()预期的收益模拟以及对this.optionService.createOptions()的调用中都使用了相同的变量-这可能与您所使用的变量不同想做。

这是我正在谈论的代码段:

service.createStatusOptions()

当我在Stackblitz中以这种方式调用它时,我遇到了一个可变性问题-您正在更改数组内部对象成员内的数据,这将在访问该变量的任何地方进行更改。为了在Stackblitz中克服这一问题,我制作了两个数据副本,一个用于模拟returnValue,另一个用于调用optionService.options = [ { value: caseStatusEnum.submitted.toString(), }, { value: caseStatusEnum.inProgress.toString(), }, { value: caseStatusEnum.closed.toString(), }, ] as OptionModel[]; // tslint:disable-next-line:max-line-length const result = service.createStatusOptions(optionService.options, [[103], [104], [105] ]); 的完全独立的对象数组。另外,我不熟悉您模拟服务调用的方式,因此我在Stackblitz中用一个简单的Jasmine间谍代替了它。

随时查看我的作品。也许会有所帮助。