How to mock ValidationController and inject into component


#1

How do you easily mock a ValidationController?

Got a custom element - looks like this:

@inject(NewInstance.of(ValidationController))
export class MyCustomThing {
  constructor(controller) {
     this.controller = controller;  
     ...
  }

  async save() {
    const result = await this.controller.validate();
    ...
  }
}

Want to write a test - eg:

it('save', async () => {
    await myComp.viewModel.save();
    expect(controller.validate).toHaveBeenCalled();
});

Struggling to do all the boilerplate stuff needed by aurelia-testing. Tried this (more or less from the documentation example at https://aurelia.io/docs/testing/components#testing-custom-component-with-a-real-view-model) - no luck:

import {StageComponent} from 'aurelia-testing';
import {bootstrap} from 'aurelia-bootstrapper';
import {ValidationController} from 'aurelia-validation';

describe('MyCustomThing ', () => {
  let component;
  let controller = {
    validate: jest.fn()
  };

  beforeEach(() => {
    component = StageComponent.withResources('my-custom-thing')
      .inView('<my-custom-thing></my-custom-thing>');

    component.bootstrap(aurelia => {
      aurelia.use.standardConfiguration().plugin('aurelia-validation');
      aurelia.container.registerInstance(ValidationController, controller);
    });
  });

  afterEach(() => {
    component.dispose();
  });

  it('save', async () => {
    await component.create(bootstrap);
    await component.viewModel.save();
    expect(controller.validate).toHaveBeenCalled();
  });
});

No luck.

Expected mock function to have been called, but it was not called.

The mock is not the one in the test staged component. It is still an instance of a real ValidationController so the mock one never gets called.

Tried every other possible combination I can thing of to get the mock ValidationController into the test subject - no luck. Probably missing something really obvious. Any ideas?

Also failing to simply mock ValidationController as there are multiple exports from ‘aurelia-validation’ - ie, this won’t work:

 jest.mock('aurelia-validation');

Anyone know how to do that?


#2

Hmm. I think the NewInstance.of is is causing the problem:

@inject(NewInstance.of(ValidationController))
export class MyCustomThing {

If I remove that, and just do:

@inject(ValidationController)
export class MyCustomThing {

I get the mock into the test subject. However, the mock is crap because I have only mocked on of the many methods - validate. Test now errors with:

	TypeError: controller.registerBinding is not a function
	Error: Cannot call ComponentTester.dispose() before ComponentTester.create()

I am on the right track, I think. But still stuck with how to easily mock the ValidationController. I can do this and it works:

  let mockController = {
    validate: jest.fn().mockReturnValue({valid: true}),
    registerBinding: jest.fn(),
    resetBinding: jest.fn(),
    unregisterBinding: jest.fn(),
    reset: jest.fn()
  };

And then how to deal with injecting a mock when using NewInstance.of in the code.

Looks like this bug was closed without actually fixing the problem of mocking.

https://github.com/aurelia/dependency-injection/issues/137