Angular2 how to Mock Activated Route Params subscribed
Asked Answered
M

2

6

I have a components that gets a value from the params property of a ActivatedRoute.

The components looks like:

......
  constructor(public userRegistration: UserRegistrationService, public userLogin: UserLoginService,
              public router: Router, public route: ActivatedRoute) {
  }

  ngOnInit() {
    this.verificationCode = new FormControl('', [Validators.required]);
    this.confirmationCodeForm = new FormGroup({verificationCode: this.verificationCode});

    //****************************** 
    this.sub = this.route.params.subscribe(params => {
      this.email = params['userId'];
    });
   //******************************
    this.errorMessage = null;
  }
 ......

The test provides an ActivatedRoute as "useValue" that mocks the class. The test looks like:

describe('ConfirmRegistrationComponent', () => {
  let component: ConfirmRegistrationComponent;
  let fixture: ComponentFixture<ConfirmRegistrationComponent>;
  let userRegistrationService: UserRegistrationService;
  let userLoginService: UserLoginService;
  let router: Router;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ReactiveFormsModule, FormsModule, RouterTestingModule, HttpClientModule],
      declarations: [ConfirmRegistrationComponent],
      providers: [UserRegistrationService, UserLoginService, {

        provide: ActivatedRoute,
        useValue: {'params': Observable.from([{userId: 1}])}

      }, ImageService, UserService, CognitoUtil,
        {
          provide: Router, useClass: class {
            navigate = jasmine.createSpy('navigate');
          }
        }]
    }).compileComponents();

    fixture = TestBed.createComponent(ConfirmRegistrationComponent);
    component = fixture.componentInstance;
    userRegistrationService = TestBed.get(UserRegistrationService);
    userLoginService = TestBed.get(UserLoginService);
    spyOn(userLoginService, 'isAuthenticated').and.callFake(function () {

    });
    router = TestBed.get(Router);
    fixture.detectChanges();
    component.ngOnInit();
  }));

  it('should create', () => {
  });
});

When I run the test, I get the next error:

Failed: Cannot read property 'subscribe' of undefined
TypeError: Cannot read property 'subscribe' of undefined
    at new RouterLinkWithHref node_modules/@angular/router/esm5/router.js:6099:1)

Could you help me please? Thanks!

Misalliance answered 14/6, 2018 at 4:10 Comment(0)
C
8

When using the RouterTestingModule, you should not put a Router provider in the providers collection (either import RouterTestingModule or provide Router, but not both).

Additionally, I don't know if this will help, but I had a related problem in Angular 6 where I had to use this syntax:

providers: [
    { provide: ActivatedRoute, useValue: {
            paramMap: of( convertToParamMap( { userId: 1 } ) )
        }
    }
],

convertToParamMap is in @angular/Router

Chlamys answered 14/6, 2018 at 6:8 Comment(5)
Thank you for your answer @Beartums, but it's still not working.Misalliance
@AleGallagher, right. I thought that would b a longshot. The other suggestion is that this is an error with the router module. I see you are providing a router class even though you have imported the RouterTestingModule. I believe that means that RouterTestingModule is not being used. Can you try deleting the provided router class (don't have a router at all in the 'provides' collection, but still import the routerTestingModule). That should allow the RTM to deal wuth the RouterLinkWithHref message and you can spy on the router later.Chlamys
Thanks @Chlamys ! It works deleting the provider Router class and leaving the use value of ActivatedRoute with : useValue: {'params': Observable.from([{userId: 1}])}. With your suggestion of using paramMap: of( convertToParamMap( { userId: 1 } ) ) the test return an error. Thanks a lot!Misalliance
Great. Glad It worked out. Thanks for the input and I'll change the answer to match the actual problem, Sorry for the wild goose chase with the parammap.Chlamys
Worked like a charm for me, with a Router subscription in component, not needed to call Router on specs, only this instance of ActivatedRoute. Curious.Marriott
S
1

The solution worked for me was the following (Angular 7 + Jest):

const mockActivatedRoute = {
  snapshot: {
    paramMap: {
      get() { return '1'; }
    }
  }
};

And just use it in providers:

      providers: [
        { provide: ActivatedRoute, useValue: mockActivatedRoute },
      ],
Sarcophagus answered 13/5, 2019 at 14:11 Comment(1)
Your solution is a StubVulcanism

© 2022 - 2024 — McMap. All rights reserved.