From 495be63ad3468d17ada18a911ecb9f25c5235d4f Mon Sep 17 00:00:00 2001 From: Avan Date: Tue, 12 Nov 2024 21:05:53 +0800 Subject: [PATCH] refactor: use Promise.allSettled (#6779) * refactor: use Promise.allSettled * fix: console.error test * refactor: use Promise.all * test: add test case * chore: adjust code order * chore: adjust code order * fix: only return successful data * test: verify the successfully uploaded file --- .../image-uploader/image-uploader.tsx | 30 ++++---- .../tests/image-uploader.test.tsx | 77 +++++++++++++++---- 2 files changed, 79 insertions(+), 28 deletions(-) diff --git a/src/components/image-uploader/image-uploader.tsx b/src/components/image-uploader/image-uploader.tsx index 109bc0814e..5dada6834d 100644 --- a/src/components/image-uploader/image-uploader.tsx +++ b/src/components/image-uploader/image-uploader.tsx @@ -1,22 +1,22 @@ -import React, { forwardRef, useRef, useState, useImperativeHandle } from 'react' +import { useIsomorphicLayoutEffect, useSize, useUnmount } from 'ahooks' +import { AddOutline, CloseOutline } from 'antd-mobile-icons' import type { - ReactNode, - InputHTMLAttributes, CSSProperties, + InputHTMLAttributes, ReactElement, + ReactNode, } from 'react' -import { AddOutline, CloseOutline } from 'antd-mobile-icons' -import { mergeProps } from '../../utils/with-default-props' -import ImageViewer, { ImageViewerShowHandler } from '../image-viewer' -import PreviewItem from './preview-item' -import { usePropsValue } from '../../utils/use-props-value' -import { useIsomorphicLayoutEffect, useUnmount, useSize } from 'ahooks' -import Space from '../space' -import { NativeProps, withNativeProps } from '../../utils/native-props' +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' import { measureCSSLength } from '../../utils/measure-css-length' +import { NativeProps, withNativeProps } from '../../utils/native-props' +import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' import { useConfig } from '../config-provider' -import type { ImageProps } from '../image' import Grid, { GridProps } from '../grid' +import type { ImageProps } from '../image' +import ImageViewer, { ImageViewerShowHandler } from '../image-viewer' +import Space from '../space' +import PreviewItem from './preview-item' export type TaskStatus = 'pending' | 'fail' | 'success' @@ -225,11 +225,11 @@ export const ImageUploader = forwardRef( return task }) }) - throw e + console.error(e) } }) - ).catch(error => console.error(error)) - setValue(prev => prev.concat(newVal)) + ) + setValue(prev => prev.concat(newVal).filter(Boolean)) } const imageViewerHandlerRef = useRef(null) diff --git a/src/components/image-uploader/tests/image-uploader.test.tsx b/src/components/image-uploader/tests/image-uploader.test.tsx index 0d9c23322a..a0690a6825 100644 --- a/src/components/image-uploader/tests/image-uploader.test.tsx +++ b/src/components/image-uploader/tests/image-uploader.test.tsx @@ -1,14 +1,14 @@ import React, { createRef, forwardRef, useState } from 'react' import { + act, + cleanup, + fireEvent, render, + screen, + sleep, testA11y, - fireEvent, - waitFor, userEvent, - sleep, - screen, - cleanup, - act, + waitFor, waitForElementToBeRemoved, } from 'testing' import ImageUploader, { ImageUploadItem, ImageUploaderRef } from '..' @@ -65,19 +65,26 @@ describe('ImageUploader', () => { }) const App = forwardRef((props, ref) => { - const [fileList, setFileList] = useState([ - { - url: demoSrc, - }, - ]) + const { onChange: propsOnChange, defaultFileList, ...restProps } = props + const [fileList, setFileList] = useState( + defaultFileList || [ + { + url: demoSrc, + }, + ] + ) + const onChange = (newFileList: ImageUploadItem[]) => { + setFileList(newFileList) + propsOnChange?.(newFileList) + } return ( ) }) @@ -389,4 +396,48 @@ describe('ImageUploader', () => { expect(ref.current).toBeDefined() expect(ref.current?.nativeElement).toBeDefined() }) + + test('get all upload url', async () => { + function mockUploadWithFailure(failOnCount: number) { + let count = 0 + return async (file: File) => { + count++ + if (count === failOnCount + 1) { + throw new Error('Fail to upload') + } + return { + url: URL.createObjectURL(file), + extra: { + fileName: file.name, + }, + } + } + } + + const fn = jest.fn() + const FAIL_INDEX = 1 + const mockUpload = mockUploadWithFailure(FAIL_INDEX) + + render( + + ) + + const fileNameList = ['one.png', 'two.png', 'three.png'] + + mockInputFile( + fileNameList.map(name => new File([name], name, { type: 'image/png' })) + ) + + await act(async () => { + jest.runAllTimers() + }) + + expect(fn.mock.lastCall[0].length).toBe(2) + + const successFileNames = fileNameList.filter((_, i) => i !== FAIL_INDEX) + const mockInputSuccessFileNames = fn.mock.lastCall[0].map( + (item: ImageUploadItem) => item.extra.fileName + ) + expect(successFileNames).toEqual(mockInputSuccessFileNames) + }) })