1

I'm creating a simple unit test for a service that has a dependency. It is a simple service that I am starting on to help to get my head around the best process and structure.

The unit test I have created works but TypeScript throws an error.

Argument of type '{ order_id: string; user: string; }' is not assignable to parameter of type 'Expected<Observable<any>>'.
Object literal may only specify known properties, and 'order_id' does not exist in type 'Expected<Observable<any>>'.

The service executes the method sendBody on the injected service which makes a HTTP post request. I understand an Observable should be returned here but I would have thought the mock service should have resolved this TypeScript type error.

Is there a better way to inject and mock dependencies when testing services only?

Service

export class ReturnOrderService {

    constructor(private _ReturnOrderResource: ReturnOrderResource) { }

    updateOrderStatus(orderId: string, user: string) {
        let body = {};

        if (orderId !== undefined && user !== undefined) {
            body["order_id"] = orderId;
            body["user"] = user;
        }

        return this._ReturnOrderResource.sendBody(body);
    }

}

Spec

const MockReturnOrderResource = {
sendBody: function(body) {
    return body;
  }
}

describe('ReturnsComponent', () => {

  beforeEach(() => {
    TestBed.configureTestingModule({ providers: [
       ReturnOrderService,
       { provide: ReturnOrderResource, useValue: MockReturnOrderResource }
      ] });
  });

  it('#updateOrderStatus should create an object literal from arguments',
    async(inject([ReturnOrderService], (service: ReturnOrderService) => {
      expect(service.updateOrderStatus("10006886","Mr Bungle")).toEqual({ order_id: '10006886', user: 'Mr Bungle' });
  })));

});
2
  • what does _ReturnOrderResource.sendBody return? Can you add that code as well? Commented Jun 16, 2017 at 10:14
  • @sabithpocker it is passed through a few different services but essentially just makes a POST request using the Angular 2 Http class and Request method : angular.io/api/http/Http#request. So an Observable is expected to be returned Commented Jun 16, 2017 at 10:18

2 Answers 2

1

If it must return an Observable, then return an Observable !

Try this :

const MockReturnOrderResource = {
    sendBody: (any: any) => Observable.of(any);
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, trichetriche. I did try something similar (and now the above) but continued to get the same type error. All though the test itself passes in each case which is odd.
You error is that somewhere, you expected a parameter of type Expected<Observable<any>> but you provided a custom object. I suggest you find this error and you should be able to suppress this error.
Thanks again for your help. I was able to find a solution using a different method to get the injected service and create a test against that. I've included the answer within this thread
1

I've worked through a solution for this using a different approach. While it may not resolve the type error I was experiencing, it allows me to spyOn the injected service which is exactly what I was after.

After injecting the service I get the service using TestBed.get() and assign this to a variable.

I can then spyOn the injected service and test against the argument(s) the method was called with.

The updated spec below.

const MockReturnOrderResource = {
  sendBody: function(body) {
    return body;
  }
}

describe('ReturnsComponent', () => {
  let _ReturnOrderResource;

  beforeEach(() => {
    TestBed.configureTestingModule({ providers: [
       ReturnOrderService,
       { provide: ReturnOrderResource, useValue: MockReturnOrderResource }
      ] });
    _ReturnOrderResource = TestBed.get(ReturnOrderResource);
  });

  it('#updateOrderStatus should pass an object literal as an argument',
    async(inject([ReturnOrderService], (service: ReturnOrderService) => {
    spyOn(service, "updateOrderStatus").and.callThrough();
    spyOn(_ReturnOrderResource, "sendBody").and.callThrough();
    service.updateOrderStatus("10006886","Mr Bungle");
    expect(_ReturnOrderResource.sendBody).toHaveBeenCalledWith({ order_id: '10006886', user: 'Mr Bungle' })
  })));

});

For further reading around this solution: https://angular.io/guide/testing#testbedget

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.