Its been a while I am struggling with this. New to Unit testing.. I am trying to mock a unit test case for -
fetchFooter() {
client.items().type('footer_link')
.depthParameter(10)
.toObservable()
.subscribe((response) => {
this.setState({
resFooter: response.items,
resFooterLinked: response.linkedItems,
});
});
}
Where client is
import { DeliveryClient } from '@kentico/kontent-delivery';
const client = new DeliveryClient({
projectId: <projectKey>,
enableAdvancedLogging: false,
});
This is what I have written till now, but doesn't seem to work.
const sample = {
items: {},
linkedItems: {}
};//this is my response object
describe("testing client", () => {
const mockClient = {
items: jest.fn().mockReturnThis(),
type: jest.fn().mockReturnThis(),
depthParameter: jest.fn().mockReturnThis(),
toObservable: jest.fn().mockReturnThis(),
subscribe: jest.fn().mockReturnThis(),
};
const mockProps = {
client: mockClient,
};
const component = mount(
<Footer mockProps={mockProps} resFooter={true} resFooterLinked={true} />
);
describe("Component", () => {
describe("#componentDidMount", () => {
it("should mount the component and set state correctly", () => {
const mockedResponse = sample;
mockClient.subscribe.mockImplementationOnce((handler) => handler(sample));
// tslint:disable-next-line: no-string-literal
component["setState"] = jest.fn();
component.instance().fetchFooter();
expect(
mockClient.items().type().depthParameter().toObservable().subscribe
).toBeCalledWith("footer_link");
// tslint:disable-next-line: no-string-literal
expect(component["setState"]).toBeCalledWith(sample);
});
});
});
});
I am getting an error as -
expect(jest.fn()).toBeCalledWith(...expected)
Expected: "footer_link"
Number of calls: 0
Maybe I am missing some basics here. I searched for a solution for this, but unfortunately didn't find one which can work for me. Can anyone help with this? Thanks in advance
As the reference states, mockReturnThis
is a shortcut for:
jest.fn(function () {
return this;
});
It only makes functions chainable and doesn't pass arguments to next function in a chain. subscribe
isn't expected to be called with footer_link
, it's type
that is called with this argument.
It's unnecessary to make mocked subscribe
call a handler, this doesn't guarantee that setState
has been called inside it. Also, setState
is called not with sample
but another object.
It's unnecessary to call expect(mockClient.items()...)
chain in a test, this just increases call count. Call assertions don't allow to determine the order in which methods have been called, this can be secured by hand.
Since mocked client object should be accessible in config
module mock, the variable needs to be lifted to module scope, this allows to mock client
in component module.
The chain can be fully tested like:
// module scope
jest.mock('../../config', () => ({
__esModule: true,
default: mockClient
});
const mockClient = {
items: jest.fn(),
type: jest.fn(),
...
};
...
// describe scope
let clientCalls;
beforeEach(() => {
clientCalls = [];
mockClient.items.mockImplementation(function () { clientCalls.push(1); return this });
mockClient.type.mockImplementation(function () { clientCalls.push(2); return this });
...
});
...
// test scope
component.instance().fetchFooter();
expect(clientCalls).toEqual([1,2,3,4,5]);
expect(mockClient.items).toBeCalledWith();
expect(mockClient.type).toBeCalledWith("footer_link");
...
expect(mockClient.subscribe).toBeCalledWith(expect.any(Function));
let [handler] = mockClient.subscribe.mock.calls[0];
expect(component["setState"]).not.toBeCalled();
handler();
expect(component["setState"]).toBeCalledWith({ resFooter:..., resFooterLinked:...});