Reputation: 9653
I'm using Jest to test calling an API in my React app.
The code I'm testing is:
const createItem = (data) => {
let formData = buildForm(data);
return fetch(URL, {
method: 'POST',
body: formData
});
};
I want to confirm that the buildForm
function correctly converts the data
to a FormData
object.
My test looks like this:
it('creates item using api', () => {
let data = {name: 'test name'};
return createItem(data)
.then(() => {
let expForm = new FormData();
expForm.append('name', data.name);
expect(global.fetch).toHaveBeenCalledWith(URL, {
method: 'POST',
body: expForm
});
});
});
The problem is, this test passes regardless what fields I append to expForm
in my test. It seems like toHaveBeenCalledWith
doesn't actually compare the values of body
and just checks that it is a FormData
object.
How can I test the values passed into the body
FormData object?
Upvotes: 14
Views: 13777
Reputation: 2484
To do this directly inside the matcher you can use expect.extend
to add your own matcher to Jest.
beforeAll(() => {
expect.extend({
toBeFormDataWith(received, expectedProperties) {
const pass = received instanceof FormData;
const receivedObject = pass ? Object.fromEntries(received.entries()) : {};
expect(receivedObject).toMatchObject(expectedProperties);
return {
message: () => `expected ${received} to be FormData`,
pass
};
}
});
});
Then your test simplifies to:
expect(fetch).toHaveBeenCalledWith(
'/my-url',
expect.objectContaining({
body: expect.toBeFormDataWith({ expected_key: 'expected_value' })
})
);
Upvotes: 0
Reputation: 3265
You can convert the FormData entries into an object for easy comparison.
expect(global.fetch).toHaveBeenCalledWith(
URL,
expect.objectContaining({ method: 'POST', body: expect.any(FormData) })
);
const formData = Array.from(global.fetch.calls[0][1].body.entries())
.reduce((acc, f) => ({ ...acc, [f[0]]: f[1] }), {});
expect(formData).toMatchObject(data);
Upvotes: 18