Angular 4:测试是否已调用window.location.href

时间:2017-07-03 08:23:24

标签: angular testing

我有一个AuthGuard服务负责检测用户是否已登录。如果没有登录,我会将用户重定向到我们的oauth提供商网址。

import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';

import { environment } from './../../environments/environment';
import { Session } from './../core/security/session.service';

@Injectable()
export class AuthGuard implements CanActivate {
  /**
   * Class constructor.
   * @constructor
   *
   * @param {Session} - Instance of session.
   */
  constructor(private session: Session) {}

  /**
   * Method to implements from CanActivate interface.
   * Check if a user is authenticated.
   *
   * @return {boolean}
   */
  canActivate(): boolean {
    if (this.session.isActive()) {
      return true;
    }

    this.redirectToProvider();
    return false;
  }

  /**
   * Redirect to Identity unauthorized url.
   */
  private redirectToProvider() {
    const unauthorizeUrl = environment.api.identity.unauthorizeUrl;
    window.location.href = unauthorizeUrl;
  }
}

我想知道当Session不存在时是否调用window.location.href。这是我到目前为止所做的:

import { TestBed, async, inject } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';

import { AuthGuard } from './auth-guard.service';
import { Session } from './../core/security/session.service';

describe('AuthGuard', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        AuthGuard,
        Session
      ],
      imports: [RouterTestingModule]
    });
  });

  describe('.canActivate', () => {
    describe('active session', () => {
      it('returns true',
        async(inject([AuthGuard, Session], (guard, session) => {
          session.set({ name: 'user' });

          expect(guard.canActivate()).toBeTruthy();
        })
      ));
    });

    describe('no session', () => {
      it('redirects the user',
        async(inject([AuthGuard, Session], (guard, session) => {
          spyOn(window.location, 'href');
          session.destroy();

          expect(guard.canActivate()).toBeFalsy();
          expect(window.location.href).toHaveBeenCalled();
        })
      ));
    });
  })
});

但是它给了我以下错误:

Failed: <spyOn> : href is not declared writable or has no setter

有没有办法模拟窗口对象来实现这一点,还是我需要依赖一些特殊的类来处理这样的重定向,以便我可以在测试中注入它们?

1 个答案:

答案 0 :(得分:1)

您可以注入environment.dev.ts作为注入令牌。 Angular在@ angular / common中还有一个window DI令牌,您可以直接与DOCUMENT一起使用。

document.location.href

将其添加到import { InjectionToken } from '@angular/core'; export const WindowToken = new InjectionToken('Window'); export function windowProvider() { return window; }

app.module.ts

并将其注入服务中

providers: [
    ...
    { provide: WindowToken, useFactory: windowProvider }
  ]

在您的spec文件中,模拟window对象并对其进行测试。我创建了一个具有两个测试服务的工作示例(一个依赖于另一个)。该服务是使用Angular的Static Injector创建的:

constructor(@Inject(WindowToken) private window: Window, private session: Session)