Как юнит-тест можно активировать методом защиты angular2 с помощью жасмина?

Извините за вопрос такого типа. Но я не могу найти ни одного блога или учебных пособий для YouTube по написанию тестирования файла защиты canActivate. Ни в официальной документации нет ничего упомянутого.

Любая помощь будет высоко ценится.

3 ответа

Решение

Так как никто не ответил на мой вопрос, поэтому я вставляю свой фрагмент кода для справки, чтобы помочь людям, которые могут получить эту ситуацию.

sampleLoggedIn.guard.ts

import {Injectable} from '@angular/core';
import {Router, CanActivate} from '@angular/router';
import {StorageService} from '../storage.service';

@Injectable()
export class LoggedInGuard implements CanActivate {
    constructor(private router: Router, private storageService: StorageService) {
    }

    /**Overriding canActivate to guard routes
     *
     * This method returns true if the user is not logged in
     * @returns {boolean}
     */
    canActivate() {
        if (this.storageService.isLoggedIn) {
            return true;
        } else {
            this.router.navigate(['home']);
            return false;
        }
    }
}

sampleLoggedIn.guard.spec.ts

import {TestBed, async} from '@angular/core/testing';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';
import {CommonModule} from '@angular/common';
import 'rxjs/Rx';
import 'rxjs/add/observable/throw';
import {Router} from '@angular/router';
import 'rxjs/add/operator/map';
import {LoggedInGuard} from './loggedin.guard';
import {StorageService} from '../storage.service';
import {CookieService} from 'angular2-cookie/core';

describe('Logged in guard should', () => {
    let loggedInGuard: LoggedInGuard;
    let storageService: StorageService;
    let router = {
        navigate: jasmine.createSpy('navigate')
    };

    // async beforeEach
    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [FormsModule, CommonModule, HttpModule],
            providers: [LoggedInGuard, StorageService, CookieService,
                {provide: Router, useValue: router}
            ]
        })
            .compileComponents(); // compile template and css
    }));

    // synchronous beforeEach
    beforeEach(() => {
        loggedInGuard = TestBed.get(LoggedInGuard);
        storageService = TestBed.get(StorageService);
    });

    it('be able to hit route when user is logged in', () => {
        storageService.isLoggedIn = true;
        expect(loggedInGuard.canActivate()).toBe(true);
    });

    it('not be able to hit route when user is not logged in', () => {
        storageService.isLoggedIn = false;
        expect(loggedInGuard.canActivate()).toBe(false);
    });
});

Этот вопрос довольно старый - но так как я сам пытался найти подробную документацию для модульного тестирования, я просто хотел изложить здесь свой подход. В общем, если есть зависимости в моей охране / сервисе / компоненте / что бы я ни думал, все они должны быть высмеяны, а не настоящие сервисы. Поскольку эти услуги не то, что мы хотим проверить в нашем модульном тесте для охранника - мы просто хотим проверить охранника. Итак, вот общий пример того, как я сделал бы это для охранника, возвращающего наблюдаемое:

import { MyGuard } from './path/to/your/guard';
import { TestBed } from '@angular/core/testing';
import { finalize } from 'rxjs/operators';

describe('MyGuard Test', () => {
    const createMockRoute = (id: string) => {
    return {
      params: { id: id }
    } as any;
  };

  const createMockRouteState = () => null;
  let guard: MyGuard;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        MyGuard,
      ]
    });

    guard = TestBed.get(MyGuard);
  });

  it('should not be able to activate invalid route', done => {
    const route = createMockRoute(null);
    const state = createMockRouteState();
    const res$ = guard.canActivate(route, state);
    res$.pipe(finalize(done)).subscribe(res => expect(res).toBeFalsy());
  });
});

и это то, что я бы сделал в вашем конкретном случае (должен работать с angular 6, canActivate также должен принимать 2 параметра):

import { LoggedInGuard } from './loggedin.guard';
import { TestBed } from '@angular/core/testing';
import { Router } from '@angular/router';
import { StorageService } from '../storage.service';

describe('LoggedInGuard', () => {
  let guard: LoggedInGuard;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        LoggedInGuard,
        { provide: Router, useClass: { navigate: () => null } },
        { provide: StorageService, useClass: { } }
      ]
    });

    guard = TestBed.get(LoggedInGuard);
  });

  it('should not be able to activate when logged out', () => {
    const storageService = TestBed.get(StorageService);
    storageService.isLoggedIn = false;
    const res = guard.canActivate(null, null);
    expect(res).toBeFalsy();
  });

  it('should be able to activate when logged in', () => {
    const storageService = TestBed.get(StorageService);
    storageService.isLoggedIn = true;
    const res = guard.canActivate(null, null);
    expect(res).toBeTruthy();
  });
});

Если ваш Guard асинхронный, его можно протестировать с помощью асинхронного тестирования:

      import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed, waitForAsync } from '@angular/core/testing';
import { Observable, of } from 'rxjs';

describe('MyGuard', () => {
  let guard: MyGuard;
  let service: MyAsyncService;

  // async beforeEach
  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule,
      ],
      providers: [
        MyGuard,
        MyAsyncService,
      ],
    });
  }));

  // synchronous beforeEach
  beforeEach(() => {
    guard = TestBed.inject(MyGuard);
    service = TestBed.inject(MyAsyncService);
  });

  it('should allow if service reports as allowed', (done) => {
    service.canFoo = (): Observable<boolean> => of(true);

    guard.canActivate(null, null).subscribe({
      next: (allowed: boolean) => {
        expect(allowed).toBeTrue();
        done();
      },
      error: err => {
        fail(err);
      },
    });
  });

  it('should reject if service reports as not allowed', () => {
    service.canFoo = (): Observable<boolean> => of(false);

    guard.canActivate(null, null).subscribe({
      next: (allowed: boolean) => {
        expect(allowed).toBeFalse();
        done();
      },
      error: err => {
        fail(err);
      },
    });
  });
});
Другие вопросы по тегам