Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I Mock an Angular 2 route?

I have the following code...

export class LoginComponent {
    userName: string;
    password: string;
    rememberMe: boolean = false;
    constructor( private auth: AuthenticationService,
                 private router: Router) {
      ...
    }
    ...
}

I am trying to Unit test but my first attempt failed....

beforeEach(() => {
        router = new Router();
        component = new LoginComponent(authService, router);
});

Because it needs the params for the Router constructor. Here I saw...

beforeEach(() => addProviders([
    APP_ROUTER_PROVIDERS, // must be first
    {provide: APP_BASE_HREF, useValue: '/'}, // must be second
    {provide: ActivatedRoute, useClass: Mock},
    {provide: Router, useClass: Mock}
]));

But I don't seem to have APP_ROUTER_PROVIDERS or Mock anywhere in my dependencies, so I think it might be stale (or I need dependencies).

How do I mock this out? It doesn't even matter for the test I am working on.

like image 840
Jackie Avatar asked Nov 28 '16 21:11

Jackie


3 Answers

For a simple case you could just create your own mock and provide it by value, for example:

describe('whatever', () => {
  let mockRouter: any;
  ...

  beforeEach(async(() => {
    // create your own mock 
    mockRouter = jasmine.createSpyObj('Router', ['navigate']);

    ...

    TestBed.configureTestingModule({
      declarations: [LoginComponent],
      providers: [
        // provide it by value
        { provide: Router, useValue: mockRouter },
        ...
      ],
    }).compileComponents();
  }));

  ...

}); 

This uses the test bed's dependency injection, rather than trying to "new-up" the class under test.

For an example in context, see e.g. one of my projects on GitHub.

like image 122
jonrsharpe Avatar answered Sep 23 '22 02:09

jonrsharpe


Here is a working example of loading query string parameters for each test. Works on Angular 2.3.

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        MyViewerComponent,
        ...
      ],
      imports: [
        HttpModule,
        FormsModule,
        RouterModule,
        ...  
      ],
      providers: [
        {provide: ActivatedRoute, useValue: {queryParams: {test: 111}}},
        {provide: MyService, useClass: MyMockService}
      ]
    })
      .compileComponents();
  }));
like image 36
David Dehghan Avatar answered Sep 26 '22 02:09

David Dehghan


I accepted the above answer because it appears to be correct, however, I actually implemented it differently...

describe("Login Component", () => {
    let component: LoginComponent;
    let authService: AuthenticationService;
    let router: Router;

    describe("Testing the subscription happens", () => {
        beforeEach(() => {
            TestBed.configureTestingModule({imports: [RouterTestingModule]});
            router = TestBed.get(Router);
            authService = new AuthenticationService();
            authService.notifications = new Subject();
            authService.notifications.subscribe = jasmine.createSpy("SpyToTestNotifications");
        });
        it("Make sure we try to subscribe to the auth event", () => {
            component = new LoginComponent(authService, router);
            expect(authService.notifications.subscribe).toHaveBeenCalled();
        })
    });
});

As you can see this only requires 2 lines in the beforeEach...

TestBed.configureTestingModule({imports: [RouterTestingModule]});
router = TestBed.get(Router);

However, per @jonrsharpe this does a lot of things so you can't guarantee what other side effects might happen. But it is quick, it is dirty and it does seem to "work"

like image 44
Jackie Avatar answered Sep 26 '22 02:09

Jackie