LondonAppDev
LondonAppDev

Reputation: 9653

Testing FormData submitted to fetch using jest

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

Answers (2)

xonya
xonya

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

Oscar Barrett
Oscar Barrett

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

Related Questions