【问题标题】:react-testing-library - how to simulate file upload to a <input type="file" /> element?react-testing-library - 如何模拟文件上传到 <input type="file" /> 元素?
【发布时间】:2020-07-21 02:38:22
【问题描述】:

我正在使用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);
});

【问题讨论】:

    标签: react-testing-library


    【解决方案1】:

    输入元素 -

    <input type="file" data-testid="fileDropzone"/>
    

    首先渲染元素,然后通过getByTestId获取输入文件上传元素。

    其次,定义一个假文件。

    const fakeFile = new File(['hello'], 'hello.png', { type: 'image/png' });
    

    然后,导入 userEvent。并上传文件,一定要在act()里面说唱。

    import userEvent from '@testing-library/user-event';
    

    测试期望,这里是最终代码。

    it('Upload Files', async () => {
      const { getByTestId } = render(<FileUplaodComponent/>);
      const fakeFile = new File(['hello'], 'hello.png', { type: 'image/png' });
      const inputFile = getByTestId(/fileDropzone/i);
      await act(async () => {
           await waitFor(() => {
                userEvent.upload(inputFile, fakeFile);
           });
       });
      expect(inputFile.files[0]).toStrictEqual(inputFile);
     });
    

    【讨论】:

      【解决方案2】:

      @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】:

        我找到了一个有点老套的解决方案,我不确定它是否符合测试中的最佳实践,但我会与你分享它可能会有所帮助

         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);
          });
        });
        

        【讨论】:

          【解决方案4】:

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

          我只是说

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

          它为我模拟了 onChange

          【讨论】:

            【解决方案5】:

            这就是我们使用 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),
                });
              });
            });
            

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

            【讨论】:

              猜你喜欢
              • 2018-07-16
              • 2019-01-24
              • 2021-11-26
              • 1970-01-01
              • 1970-01-01
              • 2016-05-25
              • 2019-08-22
              • 2016-01-08
              • 2021-01-13
              相关资源
              最近更新 更多