Create test for component ( router Mock)

Hi!
I’m trying to create a test for my component. My goal is to create mock of the router so I can check if it navigates to right destianation.

import {inject, bindable, customElement} from 'aurelia-framework';
import {Router, activationStrategy} from 'aurelia-router';

@customElement('navbar')
export class NavigationBarMenu {

@bindable changedValue;
private router;

static inject = [Router];
constructor(router){
this.router = router;
}

currentRoute() {
return this.router.currentInstruction == null ? '#' : this.router.currentInstruction.config.name;
}

DropdownChanged(changedVal) {
this.router.navigate(changedVal);
}

newArchiveJob() {
this.router.navigate('newArchiveJob');
}

newRestoreJob() {
this.router.navigate('restore-step1');
}

 newMoveJob() {
  this.router.navigate('newMoveJob');
  }

}

Thats my View-Model. its simple navigation.
Can you tell me if there is a way that I can create some simple router in jest test file?

1 Like

Aurelia element is just plain JS class, one thing you can do is to test it as a plain JS class without using StageComponent helper.

import {NavigationBarMenu} from '../src/navigation-bar-menu';

describe('NavigationBarMenu', function() {
  it('...', function() {
    const routerMock = {
      currentInstuction: ...
      navigate: (...) => {...} // write your assertions here.
    };

    // when use the class outside of aurelia context,
    // all decorators `inject` `customElement` are ignored.
    // you just feed the constructor with mocks.
    const menu = new NavigationBarMenu(routerMock);

    menu.newArchiveJob();
  });
});

If you use StageComponent to test it in Aurelia context, there should be some API to modify DI container (to replace Router injection with a mock up version), but I don’t know the API. cc @bigopon

1 Like

Thank you for your help. Based on your response I came up with this:

          it('Navigate call on New Job', done => {
            component.create(bootstrap).then(() => {
            const routerMock = {
            currentInstuction: '',
             navigate: jest.fn((val) => {})
           };
  
          const menu = new NavigationBarMenu(routerMock);
          menu.newArchiveJob();
          expect(routerMock.navigate).toBeCalled();
          expect(routerMock.navigate).toBeCalledWith('newArchiveJob');
          routerMock.navigate.mockRestore(); 
         done();
        });
1 Like

Very curious what @bigopon and others have to share. In the past when using StageComponent and needing to modify behavior of an injected dependency, or replace the injected dependency entirely, I’ve used two rather long winded approaches that I would love to see a more elegant solution shared for:

  1. Make the main configure() function dynamic, so that it can be consumed by the stage component and when doing so alternate implementations are setup in Container (also, setRoot() is not called).
  2. Leverage beforeBind() to replace or alter dependencies before the remainder of the lifecycle kicks off
1 Like

Here is an example how i bootstrap differently for my tests:

And how it looks like in a test without StageComponent

You can do the same thing. The idea is to construct an Aurelia instance, give it the root container if desired, and bootstrap the test app with it, on a host you choose. So for what you want to do, you can do:

const rootContainer = new Container();
const mockRouter = {
  navigate() { /* say hello */ }
}
const appHost = document.createElement('app');
document.body.appendChild(appHost);
rootContainer.registerInstance(Router, mockRouter);

aurelia.use.standardConfiguration();
await aurelia.start();
await aurelia.setRoot('app', appHost);