8

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.

Community
  • 1
  • 1
Jackie
  • 17,579
  • 26
  • 116
  • 227

3 Answers3

8

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.

jonrsharpe
  • 99,167
  • 19
  • 183
  • 334
  • How does this differ from the way that the actual project does it (I posted before I looked). It seems there we only need... `TestBed.configureTestingModule({imports: [RouterTestingModule]});` and `router = TestBed.get(Router);`? I haven't tested it yet though so I am not sure it works. – Jackie Nov 28 '16 at 21:12
  • @Jackie What do you mean *"the actual project"*? – jonrsharpe Nov 28 '16 at 21:13
  • https://github.com/angular/angular/blob/master/modules/%40angular/router/test/router.spec.ts – Jackie Nov 28 '16 at 21:13
  • @Jackie well they're testing the Router itself, you're testing *something that uses it*. Have you looked at the example I linked and tried this out? – jonrsharpe Nov 28 '16 at 21:14
  • I will try to look a little more and see if I get it. Sorry this stuff seems so esoteric to me. In my case I don't care about the side effects LOL but what I think you are saying is this does some extra stuff I don't need. – Jackie Nov 28 '16 at 21:21
3

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();
  }));
David Dehghan
  • 14,410
  • 2
  • 84
  • 85
2

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"

Jackie
  • 17,579
  • 26
  • 116
  • 227