react-testing-library-如何模拟文件上传到<input type =“ file” />元素?

时间:2020-04-08 15:53:51

标签: react-testing-library

我正在使用user-event尝试进行更多“现实”的用户交互。但是,单击输入后,它将不会触发onChange函数,因为默认情况下,它将仅弹出文件资源管理器供用户上传文件。如何模拟用户上传文件?

我的代码:

// Component
const FileInputComponent = ({ handleFileUpload }) => (
  <div>
    <input type="file" id="testing" accept=".png,.jpg" onChange={handleFileUpload} />
    <label htmlFor="testing">Input File Here</label>
  </div>
);
// Test file
test("Clicking on the label button calls the `handleFileUpload` function", () => {
  const handleFileUploadMockFn = jest.fn();
  const { getByLabelText } = render(<FileInputComponent handleFileUpload={handleFileUploadMockFn} />
  userEvent.click(getByLabelText("Input File Here"));
  expect(handleFileUploadMockFn).toHaveBeenCalledTimes(1);
});

4 个答案:

答案 0 :(得分:2)

我发现了一个有点笨拙的解决方案,我不确定它是否符合测试中的最佳实践,但我会与您分享它可能会有所帮助

 describe('Upload files', () => {
  let file;

  beforeEach(() => {
    file = new File(['(⌐□_□)'], 'chucknorris.png', { type: 'image/png' });
  });

  test('cover photo upload', async () => {
    // render the component
    const { getByTestId } = render(<YourComponent />);

    // get the upload button
    let uploader = getByTestId('photo-uploader');

    // simulate ulpoad event and wait until finish 
    await waitFor(() =>
      fireEvent.change(uploader, {
        target: { files: [file] },
      })
    );
    // get the same uploader from the dom    
    let image = document.getElementById('photo-uploader');
    // check if the file is there
    expect(image.files[0].name).toBe('chucknorris.png');
    expect(image.files.length).toBe(1);
  });
});

答案 1 :(得分:0)

这是我们使用RTL测试文件输入的方式:

describe('input file', () => {
  let rtl: RenderResult;

  beforeEach(() => {
    rtl = render(<MyComponentWithFileInput />);
  });

  test('input file', async () => {
    const file = new File(['(⌐□_□)'], 'file.xml', { type: 'application/xml' });

    // upload the file by updating the value attribute of the input
    // I assume : <input type="file" data-testid="fileInput" />
    fireEvent.change(rtl.getByTestId('fileInput'), {
      target: { files: [file] },
    });

    // here your onChange function should have been called
    expect(handleFileUploadMockFn).toHaveBeenCalledTimes(1);

    // if you have a form which is submitted you should be able to check values :
    expect(onSubmitForm).toHaveBeenCalledWith({
      file: expect.any(Object),
    });
  });
});

这是一般性的想法,显然应该进行更新以匹配您的设置。

答案 2 :(得分:0)

@darthzeren 的回答几乎是正确的,但链接似乎已经过时。 这是 lib 维护者描述的解决方案: https://testing-library.com/docs/ecosystem-user-event/#uploadelement-file--clickinit-changeinit--options

仅引用文档中的示例,以防将来链接失效:

import React from 'react'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'

test('upload file', () => {
  const file = new File(['hello'], 'hello.png', {type: 'image/png'})

  render(
    <div>
      <label htmlFor="file-uploader">Upload file:</label>
      <input id="file-uploader" type="file" />
    </div>,
  )
  const input = screen.getByLabelText(/upload file/i)
  userEvent.upload(input, file)

  expect(input.files[0]).toStrictEqual(file)
  expect(input.files.item(0)).toStrictEqual(file)
  expect(input.files).toHaveLength(1)
})

test('upload multiple files', () => {
  const files = [
    new File(['hello'], 'hello.png', {type: 'image/png'}),
    new File(['there'], 'there.png', {type: 'image/png'}),
  ]

  render(
    <div>
      <label htmlFor="file-uploader">Upload file:</label>
      <input id="file-uploader" type="file" multiple />
    </div>,
  )
  const input = screen.getByLabelText(/upload file/i)
  userEvent.upload(input, files)

  expect(input.files).toHaveLength(2)
  expect(input.files[0]).toStrictEqual(files[0])
  expect(input.files[1]).toStrictEqual(files[1])
})

答案 3 :(得分:-1)

您要测试上传的内容吗? https://github.com/testing-library/user-event#uploadelement-file--clickinit-changeinit-

我只是说

const FileInput= getByLabelText('file-input-label')
userEvent.upload(FileInput, testFile)

它为我模拟了onChange