【问题标题】:Angular+Jasmine: Cannot spy on ActivatedRoute.queryParamsAngular+Jasmine:无法监视 ActivatedRoute.queryParams
【发布时间】:2018-08-12 06:49:03
【问题描述】:

我如何监视预期会返回诸如 ActivatedRoute.queryParams 之类的 Observable 的存根 Angular Service 方法。这是我失败的规范:

import { TestBed, ComponentFixture } from "@angular/core/testing";
import { RivalChartComponent } from "./rival-chart-component";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { ActivatedRoute, RouterModule, Router } from "@angular/router";
import { appRoutes } from "../app.routes";
import { Observable } from 'rxjs/Observable';

import 'rxjs/add/observable/of';

describe('RivalChartComponent', () => {

    let component: RivalChartComponent;
    let fixture: ComponentFixture<RivalChartComponent>;

    beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [
                RivalChartComponent
            ],
            imports: [FormsModule, ReactiveFormsModule],
            providers: [
                {provide: ActivatedRoute, useValue: {queryParams: Observable.of({tags:'all'})}},
                {provide: Router, useValue: {}}
            ]
        });
        fixture = TestBed.createComponent(RivalChartComponent);
        component = fixture.componentInstance;
    });

    it('should init selectedTags as empty string when no query parameter is set', () => {
        spyOn(fixture.debugElement.injector.get(ActivatedRoute), 'queryParams').and.returnValue(Observable.of({tags:null}));
        component.ngOnInit();
        expect(component.selectedTags.value).toEqual('')
    });

});

这里是对应的源代码:

import { Component, OnInit } from '@angular/core';
import { Rival } from '../domain/rival';
import { Route, ActivatedRoute, Router } from '@angular/router';
import { FormGroup, FormControl } from '@angular/forms';
import { CompairValidators } from '../validators/CompairValidators';

@Component({
    moduleId: module.id,
    selector: 'cp-rival-chart',
    templateUrl: 'rival-chart.html'

})
export class RivalChartComponent implements OnInit {

    rivals: Array<Rival> = [];
    selectedTags: FormControl;

    constructor(private route: ActivatedRoute, private router: Router) {
        this.selectedTags = new FormControl('', CompairValidators.trimmedArrayMinLengthValidator(3,1));
    }

    ngOnInit() {
        this.updateInputFromQueryParams();
    }

    updateInputFromQueryParams() {
        this.route.queryParams.subscribe((params) => {
            this.selectedTags.patchValue(this.createInputTagsFromUrlTags(params.tags));
        });
    }

    createInputTagsFromUrlTags(tags: String): string {
        if (!tags) {
            return '';
        }
        const tagsArray = tags.split('+');
        const cleanedTags = tagsArray
            .filter((tag) => tag && tag.trim());
        return '#' + cleanedTags.join(' #');
    }

}

该代码预计将从ActivatedRoute 服务给出的名为tags 的查询参数初始化selectedTags FormControl。当没有给出查询参数时,它应该用空字符串初始化 selectedTags。为了测试它,我想监视 ActivatedRoutes.queryParams 方法并为键标签返回一个空字符串,但不幸的是它不起作用。相反,最初传递的 ActivatedRoute 存根的 Observable 被调用,它返回键标签的字符串“全部”。因此,我的测试失败并显示以下消息:

预期 '#all' 等于 ''。

您可能会想,为什么 ActivatedRoute 存根不直接返回空字符串。那是因为我的规范中实际上还有其他测试,我没有在此处添加以专注于我的主要问题。

--- 更新---

原来ActivatedRoute.queryParams 不能在 jasmine 中以常规方式被窥探,因为它不是函数而是属性。解决这个问题的一种方法是提供一个用于注入的对象,其中包含具有所需值的属性queryParams。以下是在我的初始代码中应用的更新,以使测试工作:

  let activatedRoute: jasmine.SpyObj<ActivatedRoute>;

  beforeEach(() => {
    const activatedRouteSpy = {
      queryParams: of({ tags: null }),
      ...jasmine.createSpyObj("ActivatedRoute", [""]),
    };
    TestBed.configureTestingModule({
      declarations: [RivalChartComponent, RivalCardComponent, SortRivalsByVotesPipe, SpinnerComponent],
      imports: [FormsModule, ReactiveFormsModule, MatProgressSpinnerModule],
      providers: [
        {
          provide: ActivatedRoute,
          useValue: activatedRouteSpy,
        },
        ...
      ],
    });
    fixture = TestBed.createComponent(RivalChartComponent);
    component = fixture.componentInstance;
    activatedRoute = TestBed.get(ActivatedRoute);
  });

  it("should init selectedTags as empty string when no query parameter is set", () => {
    component.ngOnInit();
    expect(component.selectedTags.value).toEqual("");
  });

【问题讨论】:

  • 您也可以添加RouterTestingModule
  • @ErnestoLuis 你会怎么做?您可以提供任何示例或伪代码吗?提醒一下:这里的问题是伪造ActivatedRoute.queryParams 的行为(实际实现),以便参数tags 将返回null。

标签: angular testing jasmine


【解决方案1】:

您的测试应该在async 测试区域内执行以处理ObservablePromise。有几种方法可以做到这一点

这是一个带有 async 关键字的示例:

it('should init selectedTags as empty string when no query parameter is set', async(() => {
        spyOn(fixture.debugElement.injector.get(ActivatedRoute), 'queryParams').and.returnValue(Observable.of({tags:null}));
        component.ngOnInit();
        expect(component.selectedTags.value).toEqual('')
    }));

【讨论】:

  • 不幸的是,只是将我的测试包装在异步测试区域中并没有成功。仍然得到相同的结果。由于我通过调用 Observable.of({tags:null}) 创建的 Observable 是同步的,因此这并不让我感到惊讶。它立即发出指定的值。我还是想知道怎么了……
猜你喜欢
  • 2017-08-15
  • 2019-03-31
  • 2013-11-07
  • 2018-05-10
  • 2013-01-09
  • 2022-09-30
  • 1970-01-01
  • 2018-04-20
相关资源
最近更新 更多