Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Mock ActivatedRoute using Snapshot and ParamMap

I'm using this, from here:

constructor(private heroService: HeroService,
    private activatedRoute: ActivatedRoute) {
}

ngOnInit() {
    const heroId = this.activatedRoute.snapshot.paramMap.get('id');
    this.heroService.getHeroById(heroId).subscribe((hero: Hero) => {
        ...
    });
}

Now I have a unit test that needs to mock this ActivatedRoute. I've already check some answers here in stackoverflow but without luck.

Notice that I'm using snapshot.paramMap so many solutions do not work at all. For example, this, this, and this do not work.

I think the near valid answer could be:

{
    provide: ActivatedRoute,
    useValue: {paramMap: Observable.of(convertToParamMap({id: 1}))}
}

But does not work either.

The error showing is:

Error: Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'ng:///HeroesModule/HeroDetailComponent_Host.ngfactory.js'.
    error properties: Object({ INDEX_SIZE_ERR: 1, DOMSTRING_SIZE_ERR: 2, HIERARCHY_REQUEST_ERR: 3, WRONG_DOCUMENT_ERR: 4, INVALID_CHARACTER_ERR: 5, NO_DATA_ALLOWED_ERR: 6, NO_MODIFICATION_ALLOWED_ERR: 7, NOT_FOUND_ERR: 8, NOT_SUPPORTED_ERR: 9, INUSE_ATTRIBUTE_ERR: 10, INVALID_STATE_ERR: 11, SYNTAX_ERR: 12, INVALID_MODIFICATION_ERR: 13, NAMESPACE_ERR: 14, INVALID_ACCESS_ERR: 15, VALIDATION_ERR: 16, TYPE_MISMATCH_ERR: 17, SECURITY_ERR: 18, NETWORK_ERR: 19, ABORT_ERR: 20, URL_MISMATCH_ERR: 21, QUOTA_EXCEEDED_ERR: 22, TIMEOUT_ERR: 23, INVALID_NODE_TYPE_ERR: 24, DATA_CLONE_ERR: 25, code: 19 })

This is because I'm doing a request that responses with status 500 because paramMap is undefined so there is no id on the request.

... any ideas?

Thanks and BR

like image 710
ismaestro Avatar asked Apr 19 '18 09:04

ismaestro


People also ask

How to mock ActivatedRoute in angular unit test?

It is pretty straightforward to mock the ActivatedRoute in the User component test file. All we have to do is to edit the providers list as follows: beforeEach(async(() => { TestBed. configureTestingModule({ declarations: [ UserComponent ], imports: [ RouterTestingModule, HttpClientTestingModule // ...

What is ActivatedRoute snapshot angular?

ActivatedRouteSnapshotlinkContains the information about a route associated with a component loaded in an outlet at a particular moment in time. ActivatedRouteSnapshot can also be used to traverse the router state tree.

How do you test ActivatedRoute?

Test Cases for ActivatedRoute it('getDataByNameAndID test case ', () => {route.snapshot.params.id = '2';route.snapshot.params.name = 'testParamChanged';fixture = TestBed. createComponent(MyComponent);component = fixture. componentInstance;fixture. detectChanges();expect(component.name).

What is Parammap in angular?

ParamMaplinkA map that provides access to the required and optional parameters specific to a route. The map supports retrieving a single value with get() or multiple values with getAll() .


2 Answers

Add snapshot to the useValue like:

{
          provide: ActivatedRoute,
          useValue: {
            snapshot: {
              paramMap: convertToParamMap({
                id: '1'
              })
            }
          }
        }
like image 199
Ibrahim El_Khatib Avatar answered Nov 10 '22 21:11

Ibrahim El_Khatib


In recent Angular versions, a project's aot setting is on by default (for better compile-time type checking). If this is the case with your project, then you probably need to at least stub out all the properties of ActivatedRoute and ActivatedRouteSnapshot. Something like this:

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Type } from '@angular/core';
import { Location } from '@angular/common';
import { MockPlatformLocation } from '@angular/common/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { ActivatedRoute, ActivatedRouteSnapshot, Params, ParamMap, convertToParamMap } from '@angular/router';
import { of, BehaviorSubject } from 'rxjs';

import { HeroDetailComponent } from './hero-detail.component';
import { Hero } from '../hero';


export class MockActivatedRouteSnapshot implements ActivatedRouteSnapshot {
  private innerTestParams?: Params;

  constructor(params?: Params) {
    if (params) {
      this.testParams = params;
    } else {
      this.testParams = null;
    }
  }

  private get testParams() {
    return this.innerTestParams;
  }

  private set testParams(params: Params) {
    this.innerTestParams = params;
  }

  get paramMap() {
    return convertToParamMap(this.testParams);
  }

  get queryParamMap() {
    return this.paramMap;
  }

  get url() {
    return null;
  }

  get fragment() {
    return null;
  }

  get data() {
    return null;
  }

  get outlet() {
    return null;
  }

  get params() {
    return this.innerTestParams;
  }

  get queryParams() {
    return this.innerTestParams;
  }

  get component() {
    return null;
  }

  get routeConfig() {
    return null;
  }

  get root() {
    return null;
  }

  get parent() {
    return null;
  }

  get firstChild() {
    return null;
  }

  get children() {
    return null;
  }

  get pathFromRoot() {
    return null;
  }
}


export class MockActivatedRoute implements ActivatedRoute {
  private innerTestParams?: Params;
  private subject?: BehaviorSubject<Params> = new BehaviorSubject(this.testParams);
  private paramMapSubject?: BehaviorSubject<ParamMap> = new BehaviorSubject(convertToParamMap(this.testParams));

  constructor(params?: Params) {
    if (params) {
      this.testParams = params;
    } else {
      this.testParams = null;
    }
  }

  private get testParams() {
    return this.innerTestParams;
  }

  private set testParams(params: Params) {
    this.innerTestParams = params;
    this.subject.next(params);
    this.paramMapSubject.next(convertToParamMap(params));
  }

  get snapshot() {
    return new MockActivatedRouteSnapshot(this.testParams);
  }

  get params() {
    return this.subject.asObservable();
  }

  get queryParams() {
    return this.params;
  }

  get paramMap() {
    return this.paramMapSubject.asObservable();
  }

  get queryParamMap() {
    return this.paramMap;
  }

  get url() {
    return null;
  }

  get fragment() {
    return null;
  }

  get data() {
    return null;
  }

  get outlet() {
    return null;
  }

  get component() {
    return null;
  }

  get routeConfig() {
    return null;
  }

  get root() {
    return null;
  }

  get parent() {
    return null;
  }

  get firstChild() {
    return null;
  }

  get children() {
    return null;
  }

  get pathFromRoot() {
    return null;
  }
}


describe('HeroDetailComponent', () => {
  let component: HeroDetailComponent;
  let fixture: ComponentFixture<HeroDetailComponent>;
  let httpMock: HttpTestingController;
  let routeMock: MockActivatedRoute;
  let initialMockParams: Params;
  let locationMock: MockPlatformLocation;

  beforeEach(async(() => {
    initialMockParams = {id: 11};
    routeMock = new MockActivatedRoute(initialMockParams);
    locationMock = new MockPlatformLocation;
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule
      ],
      declarations: [ HeroDetailComponent ],
      providers: [
        {
          provide: ActivatedRoute, useValue: routeMock,
        },
        {
          provide: Location, useValue: locationMock,
        }
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(HeroDetailComponent);
    component = fixture.componentInstance;
    httpMock = TestBed.inject<HttpTestingController>(HttpTestingController as Type<HttpTestingController>);
    fixture.detectChanges();
  });

  afterEach(() => {
    httpMock.verify();
  });

  it('should be created', () => {
    fixture.detectChanges();

    expect(component).toBeTruthy();

    const dummyHero: Hero = { id: 11, name: 'dummyHero' };
    const req = httpMock.expectOne('api/details/11');
    req.flush(dummyHero);
  });
});
like image 41
Stephen G Tuggy Avatar answered Nov 10 '22 19:11

Stephen G Tuggy