Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to correctly use SharedModules with Router while testing angular 2 application?

I'm trying to unit test a (angular 2) component with routerLink and routerLinkActive but all test cases fail with following error message. (Note: I have stubbed the router and other related dependencies. Here's the reference that I used for the same.).

Cannot read property 'subscribe' of undefined

I have also noticed that when routerLink and routerLinkActive are removed from my template, all test cases will run without any errors.

I think the error is caused by either RouterTestingModule or SharedModule(contains component for displaying and validating password input field). So I tried removing or adding them to find which is actually causing the problem. Here's what I observed.

  • I get 'Cannot read property 'subscribe' of undefined' if RouterTestingModule or SharedModule is present.
  • I do not get any error linked to router only if I remove both RouterTestingModule and SharedModules but the elements from the SharedModules would not get loaded in the component and some test cases still fail because of that.

TestBed configuration:

TestBed.configureTestingModule({

            imports: [CoreModule,SharedModule,RouterTestingModule],
            declarations: [ MyComponent,RouterLinkStubDirective,RouterOutletStubComponent ],
            providers: [
                FormBuilder,
                { provide: Router, useClass: RouterStub },
                { provide: ActivatedRoute, userClass: ActivatedRouteStub}
            ],
            schemas: [NO_ERRORS_SCHEMA]
        })
            .overrideComponent(MyComponent, {
                set: {
                    providers: [
                        {provide: AuthModel, useClass: MockAuthModel}    
                    ],
                }
            })
            .compileComponents();
    }));

ActivatedRouterStub:

@Injectable()
export class ActivatedRouteStub {

    // ActivatedRoute.params is Observable
    private subject = new BehaviorSubject(this.testParams);
    params = this.subject.asObservable();

    // Test parameters
    private _testParams: {};
    get testParams() { return this._testParams; }
    set testParams(params: {}) {
        this._testParams = params;
        this.subject.next(params);
    }

    // ActivatedRoute.snapshot.params
    get snapshot() {
        return { params: this.testParams };
    }
}

What changes should I make to solve the issue?

like image 312
Sanju Avatar asked Sep 20 '17 10:09

Sanju


1 Answers

I have managed to solve this issue. I'll list what changes I made to solve the issue.

  1. As I mentioned in the comments, routerLink works only on real router. So we need to include RouterTestingModule (include .withRoutes([{path: 'some/path',component: someComponent}]) if you plan to click on it while testing).

  2. We need not provide Router dependencies separately if we have added RouterTestingModule already. So I removed both Router and ActivatedRoute dependency that I provided. Now, the error changed from Cannot read property 'subscribe' of undefined to Cannot read property 'outlets' of null.

  3. I found out this error occurs when the routerLink is pointing to a null variable. In my case, the property called favoriteUrl that i assigned to routerLink was null because of the isolated testing environment. So I manually assigned a value to the property in beforeEach function and that solved the problem, atleast for me.

Thanks to everyone who tried to help! :-)

References:

https://stackoverflow.com/a/45916133/8558515

https://stackoverflow.com/a/42039920/8558515

like image 122
Sanju Avatar answered Oct 23 '22 20:10

Sanju