如何使用 useDropZone 在 enzyme 和 jest 中为组件编写测试用例?

发布于 2025-01-16 07:34:21 字数 831 浏览 5 评论 0原文

如何为这样的组件编写测试用例?模拟onChange或onClick函数不添加任何文件。

import React from 'react';
import {useDropzone} from 'react-dropzone';

function Basic(props) {
  const {acceptedFiles, getRootProps, getInputProps} = useDropzone();
  
  const files = acceptedFiles.map(file => (
    <li key={file.path}>
      {file.path} - {file.size} bytes
    </li>
  ));

  return (
    <section className="container">
      <div data-testid="dropDiv" {...getRootProps({className: 'dropzone'})}>
        <input data-testid="dropInput" {...getInputProps()} />
        <p>Drag 'n' drop some files here, or click to select files</p>
      </div>
      <aside>
        <h4>Files</h4>
        <ul>{files}</ul>
      </aside>
    </section>
  );
}

How to write test case for a component like this? Simulation of onChange or onClick function does not add any files.

import React from 'react';
import {useDropzone} from 'react-dropzone';

function Basic(props) {
  const {acceptedFiles, getRootProps, getInputProps} = useDropzone();
  
  const files = acceptedFiles.map(file => (
    <li key={file.path}>
      {file.path} - {file.size} bytes
    </li>
  ));

  return (
    <section className="container">
      <div data-testid="dropDiv" {...getRootProps({className: 'dropzone'})}>
        <input data-testid="dropInput" {...getInputProps()} />
        <p>Drag 'n' drop some files here, or click to select files</p>
      </div>
      <aside>
        <h4>Files</h4>
        <ul>{files}</ul>
      </aside>
    </section>
  );
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

行雁书 2025-01-23 07:34:21

测试组件的行为。 官方文档底部有一个关于测试的示例。建议将 react-testing-library 用于 react-拖放区

您可以创建模拟文件并模拟放置区域上的 drop 事件。然后断言组件渲染什么。

例如

index.tsx:

import React from 'react';
import { useDropzone, FileWithPath } from 'react-dropzone';

export function Basic(props) {
  const { acceptedFiles, getRootProps, getInputProps } = useDropzone();

  const files = acceptedFiles.map((file: FileWithPath) => (
    <li key={file.path}>
      {file.path} - {file.size} bytes
    </li>
  ));

  return (
    <section className="container">
      <div {...getRootProps({ className: 'dropzone' })}>
        <input {...getInputProps()} />
        <p>Drag 'n' drop some files here, or click to select files</p>
      </div>
      <aside>
        <h4>Files</h4>
        <ul>{files}</ul>
      </aside>
    </section>
  );
}

index.test.tsx:

import { act, fireEvent, waitFor, render } from '@testing-library/react';
import React from 'react';
import { Basic } from './';

async function flushPromises(rerender, ui) {
  await act(() => waitFor(() => rerender(ui)));
}

function dispatchEvt(node, type, data) {
  const event = new Event(type, { bubbles: true });
  Object.assign(event, data);
  fireEvent(node, event);
}

function mockData(files) {
  return {
    dataTransfer: {
      files,
      items: files.map((file) => ({
        kind: 'file',
        type: file.type,
        getAsFile: () => file,
      })),
      types: ['Files'],
    },
  };
}

describe('71585833', () => {
  test('should pass', async () => {
    const file = new File([JSON.stringify({ ping: true })], 'ping.json', { type: 'application/json' });
    const data = mockData([file]);
    const { container, rerender } = render(<Basic />);
    const dropzone = container.querySelector('div');
    dispatchEvt(dropzone, 'drop', data);
    await flushPromises(rerender, <Basic />);

    expect(container.querySelectorAll('li')).toHaveLength(1);
    expect(container.querySelectorAll('li')[0].textContent).toEqual('ping.json - 13 bytes');
  });
});

测试结果:

 PASS  stackoverflow/71585833/index.test.tsx (9.766 s)
  71585833
    ✓ should pass (41 ms)

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------|---------|----------|---------|---------|-------------------
All files  |     100 |      100 |     100 |     100 |                   
 index.tsx |     100 |      100 |     100 |     100 |                   
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        10.794 s

Testing the behavior of the component. There is an example about testing at the bottom of the official doc. The react-testing-library is recommended to use for react-dropzone.

You can create mock files and simulate the drop event on the drop zone. Then assert what does the component render.

E.g.

index.tsx:

import React from 'react';
import { useDropzone, FileWithPath } from 'react-dropzone';

export function Basic(props) {
  const { acceptedFiles, getRootProps, getInputProps } = useDropzone();

  const files = acceptedFiles.map((file: FileWithPath) => (
    <li key={file.path}>
      {file.path} - {file.size} bytes
    </li>
  ));

  return (
    <section className="container">
      <div {...getRootProps({ className: 'dropzone' })}>
        <input {...getInputProps()} />
        <p>Drag 'n' drop some files here, or click to select files</p>
      </div>
      <aside>
        <h4>Files</h4>
        <ul>{files}</ul>
      </aside>
    </section>
  );
}

index.test.tsx:

import { act, fireEvent, waitFor, render } from '@testing-library/react';
import React from 'react';
import { Basic } from './';

async function flushPromises(rerender, ui) {
  await act(() => waitFor(() => rerender(ui)));
}

function dispatchEvt(node, type, data) {
  const event = new Event(type, { bubbles: true });
  Object.assign(event, data);
  fireEvent(node, event);
}

function mockData(files) {
  return {
    dataTransfer: {
      files,
      items: files.map((file) => ({
        kind: 'file',
        type: file.type,
        getAsFile: () => file,
      })),
      types: ['Files'],
    },
  };
}

describe('71585833', () => {
  test('should pass', async () => {
    const file = new File([JSON.stringify({ ping: true })], 'ping.json', { type: 'application/json' });
    const data = mockData([file]);
    const { container, rerender } = render(<Basic />);
    const dropzone = container.querySelector('div');
    dispatchEvt(dropzone, 'drop', data);
    await flushPromises(rerender, <Basic />);

    expect(container.querySelectorAll('li')).toHaveLength(1);
    expect(container.querySelectorAll('li')[0].textContent).toEqual('ping.json - 13 bytes');
  });
});

Test result:

 PASS  stackoverflow/71585833/index.test.tsx (9.766 s)
  71585833
    ✓ should pass (41 ms)

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------|---------|----------|---------|---------|-------------------
All files  |     100 |      100 |     100 |     100 |                   
 index.tsx |     100 |      100 |     100 |     100 |                   
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        10.794 s
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文