mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-11-30 02:59:04 +08:00
refactor: Upload use batch start (#29474)
* chore: Update Upload version * useMergedStatus * fix file list parser * fix list replacement * bump rc-upload * add Upload.LIST_IGNORE * support LIST_IGNORE * fix uploadList batch test * test: fix batch case test case changed * test: Finish test case * fix: Not change uid if exist * use proxy * fix proxy * fix ts * part test case check * more test back * back of test all * update test case * more unmount * adjust test cae * add unmount
This commit is contained in:
parent
5d22b0ef7a
commit
79f8fece4b
@ -1,5 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import RcUpload from 'rc-upload';
|
import RcUpload, { UploadProps as RcUploadProps } from 'rc-upload';
|
||||||
|
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Dragger from './Dragger';
|
import Dragger from './Dragger';
|
||||||
import UploadList from './UploadList';
|
import UploadList from './UploadList';
|
||||||
@ -13,19 +14,19 @@ import {
|
|||||||
UploadType,
|
UploadType,
|
||||||
UploadListType,
|
UploadListType,
|
||||||
} from './interface';
|
} from './interface';
|
||||||
import { T, fileToObject, getFileItem, removeFileItem } from './utils';
|
import { T, wrapFile, getFileItem, removeFileItem } from './utils';
|
||||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||||
import defaultLocale from '../locale/default';
|
import defaultLocale from '../locale/default';
|
||||||
import { ConfigContext } from '../config-provider';
|
import { ConfigContext } from '../config-provider';
|
||||||
import devWarning from '../_util/devWarning';
|
import devWarning from '../_util/devWarning';
|
||||||
import useForceUpdate from '../_util/hooks/useForceUpdate';
|
|
||||||
import useFreshState from './useFreshState';
|
const LIST_IGNORE = `__LIST_IGNORE_${Date.now()}__`;
|
||||||
|
|
||||||
export { UploadProps };
|
export { UploadProps };
|
||||||
|
|
||||||
const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (props, ref) => {
|
const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (props, ref) => {
|
||||||
const {
|
const {
|
||||||
fileList: fileListProp,
|
fileList,
|
||||||
defaultFileList,
|
defaultFileList,
|
||||||
onRemove,
|
onRemove,
|
||||||
showUploadList,
|
showUploadList,
|
||||||
@ -48,14 +49,11 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
maxCount,
|
maxCount,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [dragState, setDragState] = React.useState<string>('drop');
|
const [mergedFileList, setMergedFileList] = useMergedState(defaultFileList || [], {
|
||||||
const forceUpdate = useForceUpdate();
|
value: fileList,
|
||||||
|
});
|
||||||
|
|
||||||
// Refresh always use fresh data
|
const [dragState, setDragState] = React.useState<string>('drop');
|
||||||
const [getFileList, setFileList] = useFreshState<UploadFile<any>[]>(
|
|
||||||
fileListProp || defaultFileList || [],
|
|
||||||
fileListProp,
|
|
||||||
);
|
|
||||||
|
|
||||||
const upload = React.useRef<any>();
|
const upload = React.useRef<any>();
|
||||||
|
|
||||||
@ -77,13 +75,19 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
|
|
||||||
(fileListProp || []).forEach((file, index) => {
|
(fileList || []).forEach((file, index) => {
|
||||||
file.uid = file.uid ?? `__AUTO__${timestamp}_${index}__`;
|
if (!file.uid) {
|
||||||
|
file.uid = `__AUTO__${timestamp}_${index}__`;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}, [fileListProp]);
|
}, [fileList]);
|
||||||
|
|
||||||
const onInternalChange = (info: UploadChangeParam) => {
|
const onInternalChange = (
|
||||||
let cloneList = [...info.fileList];
|
file: UploadFile,
|
||||||
|
changedFileList: UploadFile[],
|
||||||
|
event?: { percent: number },
|
||||||
|
) => {
|
||||||
|
let cloneList = [...changedFileList];
|
||||||
|
|
||||||
// Cut to match count
|
// Cut to match count
|
||||||
if (maxCount === 1) {
|
if (maxCount === 1) {
|
||||||
@ -92,19 +96,47 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
cloneList = cloneList.slice(0, maxCount);
|
cloneList = cloneList.slice(0, maxCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
setFileList(cloneList);
|
setMergedFileList(cloneList);
|
||||||
|
|
||||||
onChange?.({
|
const changeInfo: UploadChangeParam = {
|
||||||
...info,
|
file,
|
||||||
fileList: cloneList,
|
fileList: cloneList,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
changeInfo.event = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange?.(changeInfo);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onBatchStart: RcUploadProps['onBatchStart'] = batchFileInfoList => {
|
||||||
|
// Skip file which marked as `LIST_IGNORE`, these file will not add to file list
|
||||||
|
const filteredFileInfoList = batchFileInfoList.filter(info => !(info.file as any)[LIST_IGNORE]);
|
||||||
|
|
||||||
|
// Nothing to do since no file need upload
|
||||||
|
if (!filteredFileInfoList.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectFileList = filteredFileInfoList.map(info => wrapFile(info.file));
|
||||||
|
|
||||||
|
// Concat new files with prev files
|
||||||
|
const newFileList = [...mergedFileList];
|
||||||
|
objectFileList.forEach(fileObj => {
|
||||||
|
if (newFileList.every(existFile => existFile.uid !== fileObj.uid)) {
|
||||||
|
newFileList.push(fileObj);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onInternalChange(filteredFileInfoList[0]?.file, newFileList);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onStart = (file: RcFile) => {
|
const onStart = (file: RcFile) => {
|
||||||
const targetItem = fileToObject(file);
|
const targetItem = wrapFile(file);
|
||||||
targetItem.status = 'uploading';
|
targetItem.status = 'uploading';
|
||||||
|
|
||||||
const nextFileList = getFileList().concat();
|
const nextFileList = [...mergedFileList];
|
||||||
|
|
||||||
const fileIndex = nextFileList.findIndex(({ uid }: UploadFile) => uid === targetItem.uid);
|
const fileIndex = nextFileList.findIndex(({ uid }: UploadFile) => uid === targetItem.uid);
|
||||||
if (fileIndex === -1) {
|
if (fileIndex === -1) {
|
||||||
@ -113,10 +145,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
nextFileList[fileIndex] = targetItem;
|
nextFileList[fileIndex] = targetItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
onInternalChange({
|
onInternalChange(targetItem, nextFileList);
|
||||||
file: targetItem,
|
|
||||||
fileList: nextFileList,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSuccess = (response: any, file: UploadFile, xhr: any) => {
|
const onSuccess = (response: any, file: UploadFile, xhr: any) => {
|
||||||
@ -127,7 +156,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
}
|
}
|
||||||
const targetItem = getFileItem(file, getFileList());
|
const targetItem = getFileItem(file, mergedFileList);
|
||||||
// removed
|
// removed
|
||||||
if (!targetItem) {
|
if (!targetItem) {
|
||||||
return;
|
return;
|
||||||
@ -135,28 +164,21 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
targetItem.status = 'done';
|
targetItem.status = 'done';
|
||||||
targetItem.response = response;
|
targetItem.response = response;
|
||||||
targetItem.xhr = xhr;
|
targetItem.xhr = xhr;
|
||||||
onInternalChange({
|
onInternalChange(wrapFile(targetItem), [...mergedFileList]);
|
||||||
file: { ...targetItem },
|
|
||||||
fileList: getFileList().concat(),
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onProgress = (e: { percent: number }, file: UploadFile) => {
|
const onProgress = (e: { percent: number }, file: UploadFile) => {
|
||||||
const targetItem = getFileItem(file, getFileList());
|
const targetItem = getFileItem(file, mergedFileList);
|
||||||
// removed
|
// removed
|
||||||
if (!targetItem) {
|
if (!targetItem) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
targetItem.percent = e.percent;
|
targetItem.percent = e.percent;
|
||||||
onInternalChange({
|
onInternalChange(wrapFile(targetItem), [...mergedFileList], e);
|
||||||
event: e,
|
|
||||||
file: { ...targetItem },
|
|
||||||
fileList: getFileList().concat(),
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onError = (error: Error, response: any, file: UploadFile) => {
|
const onError = (error: Error, response: any, file: UploadFile) => {
|
||||||
const targetItem = getFileItem(file, getFileList());
|
const targetItem = getFileItem(file, mergedFileList);
|
||||||
// removed
|
// removed
|
||||||
if (!targetItem) {
|
if (!targetItem) {
|
||||||
return;
|
return;
|
||||||
@ -164,10 +186,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
targetItem.error = error;
|
targetItem.error = error;
|
||||||
targetItem.response = response;
|
targetItem.response = response;
|
||||||
targetItem.status = 'error';
|
targetItem.status = 'error';
|
||||||
onInternalChange({
|
onInternalChange(wrapFile(targetItem), [...mergedFileList]);
|
||||||
file: { ...targetItem },
|
|
||||||
fileList: getFileList().concat(),
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemove = (file: UploadFile) => {
|
const handleRemove = (file: UploadFile) => {
|
||||||
@ -178,12 +197,12 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileList = getFileList();
|
const removedFileList = removeFileItem(file, mergedFileList);
|
||||||
const removedFileList = removeFileItem(file, fileList);
|
|
||||||
|
|
||||||
if (removedFileList) {
|
if (removedFileList) {
|
||||||
currentFile = { ...file, status: 'removed' };
|
currentFile = wrapFile(file);
|
||||||
fileList?.forEach(item => {
|
currentFile.status = 'removed';
|
||||||
|
mergedFileList?.forEach(item => {
|
||||||
const matchKey = currentFile.uid !== undefined ? 'uid' : 'name';
|
const matchKey = currentFile.uid !== undefined ? 'uid' : 'name';
|
||||||
if (item[matchKey] === currentFile[matchKey]) {
|
if (item[matchKey] === currentFile[matchKey]) {
|
||||||
item.status = 'removed';
|
item.status = 'removed';
|
||||||
@ -191,10 +210,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
});
|
});
|
||||||
upload.current?.abort(currentFile);
|
upload.current?.abort(currentFile);
|
||||||
|
|
||||||
onInternalChange({
|
onInternalChange(currentFile, removedFileList);
|
||||||
file: currentFile,
|
|
||||||
fileList: removedFileList,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -203,43 +219,47 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
setDragState(e.type);
|
setDragState(e.type);
|
||||||
};
|
};
|
||||||
|
|
||||||
const beforeUpload = (file: RcFile, fileListArgs: RcFile[]) => {
|
const mergedBeforeUpload = async (file: RcFile, fileListArgs: RcFile[]) => {
|
||||||
const { beforeUpload: beforeUploadProp } = props;
|
const { beforeUpload, transformFile } = props;
|
||||||
if (!beforeUploadProp) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const result = beforeUploadProp(file, fileListArgs);
|
|
||||||
if (result === false) {
|
|
||||||
// Get unique file list
|
|
||||||
const uniqueList: UploadFile<any>[] = [];
|
|
||||||
getFileList()
|
|
||||||
.concat(fileListArgs.map(fileToObject))
|
|
||||||
.forEach(f => {
|
|
||||||
if (uniqueList.every(uf => uf.uid !== f.uid)) {
|
|
||||||
uniqueList.push(f);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
onInternalChange({
|
let parsedFile: File | Blob | string = file;
|
||||||
file,
|
if (beforeUpload) {
|
||||||
fileList: uniqueList,
|
const result = await beforeUpload(file, fileListArgs);
|
||||||
});
|
|
||||||
return false;
|
if (result === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hack for LIST_IGNORE, we add additional info to remove from the list
|
||||||
|
delete (file as any)[LIST_IGNORE];
|
||||||
|
if ((result as any) === LIST_IGNORE) {
|
||||||
|
Object.defineProperty(file, LIST_IGNORE, {
|
||||||
|
value: true,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof result === 'object' && result) {
|
||||||
|
parsedFile = result as File;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (result && (result as PromiseLike<any>).then) {
|
|
||||||
return result;
|
if (transformFile) {
|
||||||
|
parsedFile = await transformFile(parsedFile as any);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
return parsedFile as RcFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Test needs
|
// Test needs
|
||||||
React.useImperativeHandle(ref, () => ({
|
React.useImperativeHandle(ref, () => ({
|
||||||
onStart,
|
onStart,
|
||||||
onSuccess,
|
onSuccess,
|
||||||
onProgress,
|
onProgress,
|
||||||
onError,
|
onError,
|
||||||
fileList: getFileList(),
|
fileList: mergedFileList,
|
||||||
upload: upload.current,
|
upload: upload.current,
|
||||||
forceUpdate,
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||||
@ -247,13 +267,14 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
const prefixCls = getPrefixCls('upload', customizePrefixCls);
|
const prefixCls = getPrefixCls('upload', customizePrefixCls);
|
||||||
|
|
||||||
const rcUploadProps = {
|
const rcUploadProps = {
|
||||||
|
onBatchStart,
|
||||||
onStart,
|
onStart,
|
||||||
onError,
|
onError,
|
||||||
onProgress,
|
onProgress,
|
||||||
onSuccess,
|
onSuccess,
|
||||||
...props,
|
...props,
|
||||||
prefixCls,
|
prefixCls,
|
||||||
beforeUpload,
|
beforeUpload: mergedBeforeUpload,
|
||||||
onChange: undefined,
|
onChange: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -277,7 +298,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
return (
|
return (
|
||||||
<UploadList
|
<UploadList
|
||||||
listType={listType}
|
listType={listType}
|
||||||
items={getFileList(true)}
|
items={mergedFileList}
|
||||||
previewFile={previewFile}
|
previewFile={previewFile}
|
||||||
onPreview={onPreview}
|
onPreview={onPreview}
|
||||||
onDownload={onDownload}
|
onDownload={onDownload}
|
||||||
@ -306,7 +327,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
prefixCls,
|
prefixCls,
|
||||||
{
|
{
|
||||||
[`${prefixCls}-drag`]: true,
|
[`${prefixCls}-drag`]: true,
|
||||||
[`${prefixCls}-drag-uploading`]: getFileList().some(file => file.status === 'uploading'),
|
[`${prefixCls}-drag-uploading`]: mergedFileList.some(file => file.status === 'uploading'),
|
||||||
[`${prefixCls}-drag-hover`]: dragState === 'dragover',
|
[`${prefixCls}-drag-hover`]: dragState === 'dragover',
|
||||||
[`${prefixCls}-disabled`]: disabled,
|
[`${prefixCls}-disabled`]: disabled,
|
||||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||||
@ -365,12 +386,15 @@ interface CompoundedComponent
|
|||||||
React.PropsWithChildren<UploadProps> & React.RefAttributes<any>
|
React.PropsWithChildren<UploadProps> & React.RefAttributes<any>
|
||||||
> {
|
> {
|
||||||
Dragger: typeof Dragger;
|
Dragger: typeof Dragger;
|
||||||
|
LIST_IGNORE: {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Upload = React.forwardRef<unknown, UploadProps>(InternalUpload) as CompoundedComponent;
|
const Upload = React.forwardRef<unknown, UploadProps>(InternalUpload) as CompoundedComponent;
|
||||||
|
|
||||||
Upload.Dragger = Dragger;
|
Upload.Dragger = Dragger;
|
||||||
|
|
||||||
|
Upload.LIST_IGNORE = LIST_IGNORE;
|
||||||
|
|
||||||
Upload.displayName = 'Upload';
|
Upload.displayName = 'Upload';
|
||||||
|
|
||||||
Upload.defaultProps = {
|
Upload.defaultProps = {
|
||||||
|
@ -5,7 +5,7 @@ import { act } from 'react-dom/test-utils';
|
|||||||
import produce from 'immer';
|
import produce from 'immer';
|
||||||
import Upload from '..';
|
import Upload from '..';
|
||||||
import Form from '../../form';
|
import Form from '../../form';
|
||||||
import { T, fileToObject, getFileItem, removeFileItem } from '../utils';
|
import { T, wrapFile, getFileItem, removeFileItem } from '../utils';
|
||||||
import { setup, teardown } from './mock';
|
import { setup, teardown } from './mock';
|
||||||
import { resetWarned } from '../../_util/devWarning';
|
import { resetWarned } from '../../_util/devWarning';
|
||||||
import mountTest from '../../../tests/shared/mountTest';
|
import mountTest from '../../../tests/shared/mountTest';
|
||||||
@ -291,11 +291,29 @@ describe('Upload', () => {
|
|||||||
expect(res).toBe(true);
|
expect(res).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to copy file instance', () => {
|
describe('wrapFile', () => {
|
||||||
const file = new File([], 'aaa.zip');
|
it('should be able to copy file instance when Proxy not support', () => {
|
||||||
const copiedFile = fileToObject(file);
|
const file = new File([], 'aaa.zip');
|
||||||
['uid', 'lastModified', 'lastModifiedDate', 'name', 'size', 'type'].forEach(key => {
|
|
||||||
expect(key in copiedFile).toBe(true);
|
const OriginProxy = global.Proxy;
|
||||||
|
global.Proxy = undefined;
|
||||||
|
|
||||||
|
const copiedFile = wrapFile(file);
|
||||||
|
['uid', 'lastModified', 'lastModifiedDate', 'name', 'size', 'type'].forEach(key => {
|
||||||
|
expect(key in copiedFile).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
global.Proxy = OriginProxy;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Proxy support', () => {
|
||||||
|
const file = new File([], 'aaa.zip');
|
||||||
|
|
||||||
|
const copiedFile = wrapFile(file);
|
||||||
|
console.log(Object.keys(copiedFile));
|
||||||
|
['uid', 'lastModified', 'lastModifiedDate', 'name', 'size', 'type'].forEach(key => {
|
||||||
|
expect(key in copiedFile).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -617,15 +635,20 @@ describe('Upload', () => {
|
|||||||
|
|
||||||
switch (callTimes) {
|
switch (callTimes) {
|
||||||
case 1:
|
case 1:
|
||||||
|
expect(file.status).toBe(undefined);
|
||||||
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
case 3:
|
||||||
|
console.log('===>', file.status);
|
||||||
expect(file).toEqual(expect.objectContaining({ status: 'uploading', percent: 0 }));
|
expect(file).toEqual(expect.objectContaining({ status: 'uploading', percent: 0 }));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 4:
|
||||||
expect(file).toEqual(expect.objectContaining({ status: 'uploading', percent: 100 }));
|
expect(file).toEqual(expect.objectContaining({ status: 'uploading', percent: 100 }));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 5:
|
||||||
expect(file).toEqual(expect.objectContaining({ status: 'done', percent: 100 }));
|
expect(file).toEqual(expect.objectContaining({ status: 'done', percent: 100 }));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -104,6 +104,7 @@ describe('Upload List', () => {
|
|||||||
expect(linkNode.prop('href')).toBe(file.url);
|
expect(linkNode.prop('href')).toBe(file.url);
|
||||||
expect(imgNode.prop('src')).toBe(file.thumbUrl);
|
expect(imgNode.prop('src')).toBe(file.thumbUrl);
|
||||||
});
|
});
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
// https://github.com/ant-design/ant-design/issues/7269
|
// https://github.com/ant-design/ant-design/issues/7269
|
||||||
@ -145,6 +146,8 @@ describe('Upload List', () => {
|
|||||||
// console.log(wrapper.html());
|
// console.log(wrapper.html());
|
||||||
|
|
||||||
expect(wrapper.find('.ant-upload-list-text-container').hostNodes().length).toBe(1);
|
expect(wrapper.find('.ant-upload-list-text-container').hostNodes().length).toBe(1);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be uploading when upload a file', done => {
|
it('should be uploading when upload a file', done => {
|
||||||
@ -157,6 +160,7 @@ describe('Upload List', () => {
|
|||||||
}
|
}
|
||||||
if (file.status === 'done') {
|
if (file.status === 'done') {
|
||||||
expect(wrapper.render()).toMatchSnapshot();
|
expect(wrapper.render()).toMatchSnapshot();
|
||||||
|
wrapper.unmount();
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,8 +185,9 @@ describe('Upload List', () => {
|
|||||||
it('handle error', done => {
|
it('handle error', done => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
const onChange = ({ file }) => {
|
const onChange = ({ file }) => {
|
||||||
if (file.status !== 'uploading') {
|
if (file.status === 'error') {
|
||||||
expect(wrapper.render()).toMatchSnapshot();
|
expect(wrapper.render()).toMatchSnapshot();
|
||||||
|
wrapper.unmount();
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -202,7 +207,7 @@ describe('Upload List', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does concat filelist when beforeUpload returns false', () => {
|
it('does concat fileList when beforeUpload returns false', async () => {
|
||||||
const handleChange = jest.fn();
|
const handleChange = jest.fn();
|
||||||
const ref = React.createRef();
|
const ref = React.createRef();
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
@ -222,11 +227,17 @@ describe('Upload List', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await sleep();
|
||||||
|
|
||||||
expect(ref.current.fileList.length).toBe(fileList.length + 1);
|
expect(ref.current.fileList.length).toBe(fileList.length + 1);
|
||||||
expect(handleChange.mock.calls[0][0].fileList).toHaveLength(3);
|
expect(handleChange.mock.calls[0][0].fileList).toHaveLength(3);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('In the case of listType=picture, the error status does not show the download.', () => {
|
it('In the case of listType=picture, the error status does not show the download.', () => {
|
||||||
|
global.testName =
|
||||||
|
'In the case of listType=picture, the error status does not show the download.';
|
||||||
const file = { status: 'error', uid: 'file' };
|
const file = { status: 'error', uid: 'file' };
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
<Upload listType="picture" fileList={[file]} showUploadList={{ showDownloadIcon: true }}>
|
<Upload listType="picture" fileList={[file]} showUploadList={{ showDownloadIcon: true }}>
|
||||||
@ -238,9 +249,13 @@ describe('Upload List', () => {
|
|||||||
wrapper.find('.ant-upload-list-item-error').simulate('mouseenter');
|
wrapper.find('.ant-upload-list-item-error').simulate('mouseenter');
|
||||||
|
|
||||||
expect(wrapper.find('div.ant-upload-list-item i.anticon-download').length).toBe(0);
|
expect(wrapper.find('div.ant-upload-list-item i.anticon-download').length).toBe(0);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('In the case of listType=picture-card, the error status does not show the download.', () => {
|
it('In the case of listType=picture-card, the error status does not show the download.', () => {
|
||||||
|
global.testName =
|
||||||
|
'In the case of listType=picture-card, the error status does not show the download.';
|
||||||
const file = { status: 'error', uid: 'file' };
|
const file = { status: 'error', uid: 'file' };
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
<Upload listType="picture-card" fileList={[file]} showUploadList={{ showDownloadIcon: true }}>
|
<Upload listType="picture-card" fileList={[file]} showUploadList={{ showDownloadIcon: true }}>
|
||||||
@ -248,6 +263,8 @@ describe('Upload List', () => {
|
|||||||
</Upload>,
|
</Upload>,
|
||||||
);
|
);
|
||||||
expect(wrapper.find('div.ant-upload-list-item i.anticon-download').length).toBe(0);
|
expect(wrapper.find('div.ant-upload-list-item i.anticon-download').length).toBe(0);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('In the case of listType=text, the error status does not show the download.', () => {
|
it('In the case of listType=text, the error status does not show the download.', () => {
|
||||||
@ -258,6 +275,8 @@ describe('Upload List', () => {
|
|||||||
</Upload>,
|
</Upload>,
|
||||||
);
|
);
|
||||||
expect(wrapper.find('div.ant-upload-list-item i.anticon-download').length).toBe(0);
|
expect(wrapper.find('div.ant-upload-list-item i.anticon-download').length).toBe(0);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support onPreview', () => {
|
it('should support onPreview', () => {
|
||||||
@ -271,6 +290,8 @@ describe('Upload List', () => {
|
|||||||
expect(handlePreview).toHaveBeenCalledWith(fileList[0]);
|
expect(handlePreview).toHaveBeenCalledWith(fileList[0]);
|
||||||
wrapper.find('.anticon-eye').at(1).simulate('click');
|
wrapper.find('.anticon-eye').at(1).simulate('click');
|
||||||
expect(handlePreview).toHaveBeenCalledWith(fileList[1]);
|
expect(handlePreview).toHaveBeenCalledWith(fileList[1]);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support onRemove', async () => {
|
it('should support onRemove', async () => {
|
||||||
@ -292,6 +313,8 @@ describe('Upload List', () => {
|
|||||||
expect(handleRemove).toHaveBeenCalledWith(fileList[1]);
|
expect(handleRemove).toHaveBeenCalledWith(fileList[1]);
|
||||||
await sleep();
|
await sleep();
|
||||||
expect(handleChange.mock.calls.length).toBe(2);
|
expect(handleChange.mock.calls.length).toBe(2);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support onDownload', async () => {
|
it('should support onDownload', async () => {
|
||||||
@ -316,6 +339,8 @@ describe('Upload List', () => {
|
|||||||
</Upload>,
|
</Upload>,
|
||||||
);
|
);
|
||||||
wrapper.find('.anticon-download').at(0).simulate('click');
|
wrapper.find('.anticon-download').at(0).simulate('click');
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support no onDownload', async () => {
|
it('should support no onDownload', async () => {
|
||||||
@ -338,6 +363,8 @@ describe('Upload List', () => {
|
|||||||
</Upload>,
|
</Upload>,
|
||||||
);
|
);
|
||||||
wrapper.find('.anticon-download').at(0).simulate('click');
|
wrapper.find('.anticon-download').at(0).simulate('click');
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should generate thumbUrl from file', () => {
|
describe('should generate thumbUrl from file', () => {
|
||||||
@ -360,7 +387,7 @@ describe('Upload List', () => {
|
|||||||
delete newFile.thumbUrl;
|
delete newFile.thumbUrl;
|
||||||
newFileList.push(newFile);
|
newFileList.push(newFile);
|
||||||
const ref = React.createRef();
|
const ref = React.createRef();
|
||||||
mount(
|
const wrapper = mount(
|
||||||
<Upload
|
<Upload
|
||||||
ref={ref}
|
ref={ref}
|
||||||
listType="picture-card"
|
listType="picture-card"
|
||||||
@ -370,7 +397,7 @@ describe('Upload List', () => {
|
|||||||
<button type="button">upload</button>
|
<button type="button">upload</button>
|
||||||
</Upload>,
|
</Upload>,
|
||||||
);
|
);
|
||||||
ref.current.forceUpdate();
|
wrapper.update();
|
||||||
await sleep();
|
await sleep();
|
||||||
|
|
||||||
expect(ref.current.fileList[2].thumbUrl).not.toBe(undefined);
|
expect(ref.current.fileList[2].thumbUrl).not.toBe(undefined);
|
||||||
@ -383,6 +410,8 @@ describe('Upload List', () => {
|
|||||||
} else {
|
} else {
|
||||||
expect(offsetY === 0).toBeTruthy();
|
expect(offsetY === 0).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -462,6 +491,8 @@ describe('Upload List', () => {
|
|||||||
</Upload>,
|
</Upload>,
|
||||||
);
|
);
|
||||||
expect(wrapper.render()).toMatchSnapshot();
|
expect(wrapper.render()).toMatchSnapshot();
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support showRemoveIcon and showPreviewIcon', () => {
|
it('should support showRemoveIcon and showPreviewIcon', () => {
|
||||||
@ -493,6 +524,8 @@ describe('Upload List', () => {
|
|||||||
</Upload>,
|
</Upload>,
|
||||||
);
|
);
|
||||||
expect(wrapper.render()).toMatchSnapshot();
|
expect(wrapper.render()).toMatchSnapshot();
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support custom onClick in custom icon', async () => {
|
it('should support custom onClick in custom icon', async () => {
|
||||||
@ -525,6 +558,8 @@ describe('Upload List', () => {
|
|||||||
expect(myClick).toHaveBeenCalled();
|
expect(myClick).toHaveBeenCalled();
|
||||||
await sleep();
|
await sleep();
|
||||||
expect(handleChange.mock.calls.length).toBe(2);
|
expect(handleChange.mock.calls.length).toBe(2);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support removeIcon and downloadIcon', () => {
|
it('should support removeIcon and downloadIcon', () => {
|
||||||
@ -574,6 +609,9 @@ describe('Upload List', () => {
|
|||||||
</Upload>,
|
</Upload>,
|
||||||
);
|
);
|
||||||
expect(wrapper2.render()).toMatchSnapshot();
|
expect(wrapper2.render()).toMatchSnapshot();
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
|
wrapper2.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
// https://github.com/ant-design/ant-design/issues/7762
|
// https://github.com/ant-design/ant-design/issues/7762
|
||||||
@ -626,19 +664,22 @@ describe('Upload List', () => {
|
|||||||
wrapper.find(Form).simulate('submit');
|
wrapper.find(Form).simulate('submit');
|
||||||
await sleep();
|
await sleep();
|
||||||
expect(formRef.getFieldError(['file'])).toEqual([]);
|
expect(formRef.getFieldError(['file'])).toEqual([]);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('return when prop onPreview not exists', () => {
|
it('return when prop onPreview not exists', () => {
|
||||||
const ref = React.createRef();
|
const ref = React.createRef();
|
||||||
mount(<UploadList ref={ref} />);
|
const wrapper = mount(<UploadList ref={ref} />);
|
||||||
expect(ref.current.handlePreview()).toBe(undefined);
|
expect(ref.current.handlePreview()).toBe(undefined);
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('return when prop onDownload not exists', () => {
|
it('return when prop onDownload not exists', () => {
|
||||||
const file = new File([''], 'test.txt', { type: 'text/plain' });
|
const file = new File([''], 'test.txt', { type: 'text/plain' });
|
||||||
const items = [{ uid: 'upload-list-item', url: '' }];
|
const items = [{ uid: 'upload-list-item', url: '' }];
|
||||||
const ref = React.createRef();
|
const ref = React.createRef();
|
||||||
mount(
|
const wrapper = mount(
|
||||||
<UploadList
|
<UploadList
|
||||||
ref={ref}
|
ref={ref}
|
||||||
items={items}
|
items={items}
|
||||||
@ -647,6 +688,7 @@ describe('Upload List', () => {
|
|||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
expect(ref.current.handleDownload(file)).toBe(undefined);
|
expect(ref.current.handleDownload(file)).toBe(undefined);
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('previewFile should work correctly', async () => {
|
it('previewFile should work correctly', async () => {
|
||||||
@ -655,7 +697,9 @@ describe('Upload List', () => {
|
|||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
<UploadList listType="picture-card" items={items} locale={{ previewFile: '' }} />,
|
<UploadList listType="picture-card" items={items} locale={{ previewFile: '' }} />,
|
||||||
);
|
);
|
||||||
return wrapper.props().previewFile(file);
|
expect(wrapper.props().previewFile(file)).toBeTruthy();
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('downloadFile should work correctly', async () => {
|
it('downloadFile should work correctly', async () => {
|
||||||
@ -670,7 +714,11 @@ describe('Upload List', () => {
|
|||||||
showUploadList={{ showDownloadIcon: true }}
|
showUploadList={{ showDownloadIcon: true }}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
return wrapper.props().onDownload(file);
|
|
||||||
|
// Not throw
|
||||||
|
wrapper.props().onDownload(file);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('extname should work correctly when url not exists', () => {
|
it('extname should work correctly when url not exists', () => {
|
||||||
@ -679,6 +727,7 @@ describe('Upload List', () => {
|
|||||||
<UploadList listType="picture-card" items={items} locale={{ previewFile: '' }} />,
|
<UploadList listType="picture-card" items={items} locale={{ previewFile: '' }} />,
|
||||||
);
|
);
|
||||||
expect(wrapper.find('.ant-upload-list-item-thumbnail').length).toBe(1);
|
expect(wrapper.find('.ant-upload-list-item-thumbnail').length).toBe(1);
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('extname should work correctly when url exists', done => {
|
it('extname should work correctly when url exists', done => {
|
||||||
@ -688,6 +737,7 @@ describe('Upload List', () => {
|
|||||||
listType="picture"
|
listType="picture"
|
||||||
onDownload={file => {
|
onDownload={file => {
|
||||||
expect(file.url).toBe('/example');
|
expect(file.url).toBe('/example');
|
||||||
|
wrapper.unmount();
|
||||||
done();
|
done();
|
||||||
}}
|
}}
|
||||||
items={items}
|
items={items}
|
||||||
@ -705,6 +755,8 @@ describe('Upload List', () => {
|
|||||||
);
|
);
|
||||||
expect(wrapper.find('.ant-upload-list-item-thumbnail').length).toBe(1);
|
expect(wrapper.find('.ant-upload-list-item-thumbnail').length).toBe(1);
|
||||||
expect(wrapper.find('.ant-upload-list-item-thumbnail').text()).toBe('uploading');
|
expect(wrapper.find('.ant-upload-list-item-thumbnail').text()).toBe('uploading');
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('onPreview should be called, when url exists', () => {
|
it('onPreview should be called, when url exists', () => {
|
||||||
@ -725,6 +777,8 @@ describe('Upload List', () => {
|
|||||||
wrapper.setProps({ items: [{ thumbUrl: 'thumbUrl', uid: 'upload-list-item' }] });
|
wrapper.setProps({ items: [{ thumbUrl: 'thumbUrl', uid: 'upload-list-item' }] });
|
||||||
wrapper.find('.ant-upload-list-item-name').simulate('click');
|
wrapper.find('.ant-upload-list-item-name').simulate('click');
|
||||||
expect(onPreview).toHaveBeenCalled();
|
expect(onPreview).toHaveBeenCalled();
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('upload image file should be converted to the base64', async () => {
|
it('upload image file should be converted to the base64', async () => {
|
||||||
@ -735,12 +789,14 @@ describe('Upload List', () => {
|
|||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
<UploadList listType="picture-card" items={fileList} locale={{ uploading: 'uploading' }} />,
|
<UploadList listType="picture-card" items={fileList} locale={{ uploading: 'uploading' }} />,
|
||||||
);
|
);
|
||||||
return wrapper
|
await wrapper
|
||||||
.props()
|
.props()
|
||||||
.previewFile(mockFile)
|
.previewFile(mockFile)
|
||||||
.then(dataUrl => {
|
.then(dataUrl => {
|
||||||
expect(dataUrl).toEqual('data:image/png;base64,');
|
expect(dataUrl).toEqual('data:image/png;base64,');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("upload non image file shouldn't be converted to the base64", async () => {
|
it("upload non image file shouldn't be converted to the base64", async () => {
|
||||||
@ -751,12 +807,14 @@ describe('Upload List', () => {
|
|||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
<UploadList listType="picture-card" items={fileList} locale={{ uploading: 'uploading' }} />,
|
<UploadList listType="picture-card" items={fileList} locale={{ uploading: 'uploading' }} />,
|
||||||
);
|
);
|
||||||
return wrapper
|
await wrapper
|
||||||
.props()
|
.props()
|
||||||
.previewFile(mockFile)
|
.previewFile(mockFile)
|
||||||
.then(dataUrl => {
|
.then(dataUrl => {
|
||||||
expect(dataUrl).toBe('');
|
expect(dataUrl).toBe('');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('customize previewFile support', () => {
|
describe('customize previewFile support', () => {
|
||||||
@ -775,12 +833,14 @@ describe('Upload List', () => {
|
|||||||
<button type="button">button</button>
|
<button type="button">button</button>
|
||||||
</Upload>,
|
</Upload>,
|
||||||
);
|
);
|
||||||
ref.current.forceUpdate();
|
wrapper.update();
|
||||||
expect(previewFile).toHaveBeenCalledWith(file.originFileObj);
|
expect(previewFile).toHaveBeenCalledWith(file.originFileObj);
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|
||||||
expect(wrapper.find('.ant-upload-list-item-thumbnail img').prop('src')).toBe(mockThumbnail);
|
expect(wrapper.find('.ant-upload-list-item-thumbnail img').prop('src')).toBe(mockThumbnail);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
test('File', () => new File([], 'xxx.png'));
|
test('File', () => new File([], 'xxx.png'));
|
||||||
@ -808,6 +868,8 @@ describe('Upload List', () => {
|
|||||||
);
|
);
|
||||||
const imgNode = wrapper.find('.ant-upload-list-item-thumbnail img');
|
const imgNode = wrapper.find('.ant-upload-list-item-thumbnail img');
|
||||||
expect(imgNode.length).toBe(2);
|
expect(imgNode.length).toBe(2);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
it('should render <img /> when custom imageUrl return true', () => {
|
it('should render <img /> when custom imageUrl return true', () => {
|
||||||
const isImageUrl = jest.fn(() => true);
|
const isImageUrl = jest.fn(() => true);
|
||||||
@ -819,6 +881,8 @@ describe('Upload List', () => {
|
|||||||
const imgNode = wrapper.find('.ant-upload-list-item-thumbnail img');
|
const imgNode = wrapper.find('.ant-upload-list-item-thumbnail img');
|
||||||
expect(isImageUrl).toHaveBeenCalled();
|
expect(isImageUrl).toHaveBeenCalled();
|
||||||
expect(imgNode.length).toBe(3);
|
expect(imgNode.length).toBe(3);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
it('should not render <img /> when custom imageUrl return false', () => {
|
it('should not render <img /> when custom imageUrl return false', () => {
|
||||||
const isImageUrl = jest.fn(() => false);
|
const isImageUrl = jest.fn(() => false);
|
||||||
@ -830,6 +894,8 @@ describe('Upload List', () => {
|
|||||||
const imgNode = wrapper.find('.ant-upload-list-item-thumbnail img');
|
const imgNode = wrapper.find('.ant-upload-list-item-thumbnail img');
|
||||||
expect(isImageUrl).toHaveBeenCalled();
|
expect(isImageUrl).toHaveBeenCalled();
|
||||||
expect(imgNode.length).toBe(0);
|
expect(imgNode.length).toBe(0);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -897,9 +963,13 @@ describe('Upload List', () => {
|
|||||||
});
|
});
|
||||||
const afterImgNode = wrapper.find('.ant-upload-list-item-thumbnail img');
|
const afterImgNode = wrapper.find('.ant-upload-list-item-thumbnail img');
|
||||||
expect(afterImgNode.length).toBeTruthy();
|
expect(afterImgNode.length).toBeTruthy();
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not render <img /> when upload non-image file without thumbUrl in onChange', done => {
|
it('should not render <img /> when upload non-image file without thumbUrl in onChange', done => {
|
||||||
|
global.testName =
|
||||||
|
'should not render <img /> when upload non-image file without thumbUrl in onChange';
|
||||||
let wrapper;
|
let wrapper;
|
||||||
const onChange = async ({ fileList: files }) => {
|
const onChange = async ({ fileList: files }) => {
|
||||||
wrapper.setProps({ fileList: files });
|
wrapper.setProps({ fileList: files });
|
||||||
@ -907,6 +977,7 @@ describe('Upload List', () => {
|
|||||||
await sleep();
|
await sleep();
|
||||||
const imgNode = wrapper.find('.ant-upload-list-item-thumbnail img');
|
const imgNode = wrapper.find('.ant-upload-list-item-thumbnail img');
|
||||||
expect(imgNode.length).toBe(0);
|
expect(imgNode.length).toBe(0);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
wrapper = mount(
|
wrapper = mount(
|
||||||
@ -927,14 +998,17 @@ describe('Upload List', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('[deprecated] should support transformFile', done => {
|
it('[deprecated] should support transformFile', done => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
const handleTransformFile = jest.fn();
|
const handleTransformFile = jest.fn();
|
||||||
const onChange = ({ file }) => {
|
const onChange = ({ file }) => {
|
||||||
if (file.status === 'done') {
|
if (file.status === 'done') {
|
||||||
expect(handleTransformFile).toHaveBeenCalled();
|
expect(handleTransformFile).toHaveBeenCalled();
|
||||||
|
wrapper.unmount();
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const wrapper = mount(
|
wrapper = mount(
|
||||||
<Upload
|
<Upload
|
||||||
action="http://jsonplaceholder.typicode.com/posts/"
|
action="http://jsonplaceholder.typicode.com/posts/"
|
||||||
transformFile={handleTransformFile}
|
transformFile={handleTransformFile}
|
||||||
@ -972,6 +1046,8 @@ describe('Upload List', () => {
|
|||||||
expect(wrapper.exists('.ant-upload-list button.trigger')).toBe(true);
|
expect(wrapper.exists('.ant-upload-list button.trigger')).toBe(true);
|
||||||
wrapper.setProps({ showUploadList: false });
|
wrapper.setProps({ showUploadList: false });
|
||||||
expect(wrapper.exists('.ant-upload-list button.trigger')).toBe(false);
|
expect(wrapper.exists('.ant-upload-list button.trigger')).toBe(false);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
// https://github.com/ant-design/ant-design/issues/26536
|
// https://github.com/ant-design/ant-design/issues/26536
|
||||||
@ -998,7 +1074,7 @@ describe('Upload List', () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
mount(<MyUpload />);
|
const wrapper = mount(<MyUpload />);
|
||||||
|
|
||||||
// Mock async update in a frame
|
// Mock async update in a frame
|
||||||
const files = ['light', 'bamboo', 'little'];
|
const files = ['light', 'bamboo', 'little'];
|
||||||
@ -1018,6 +1094,8 @@ describe('Upload List', () => {
|
|||||||
jest.runAllTimers();
|
jest.runAllTimers();
|
||||||
expect(uploadRef.current.fileList).toHaveLength(files.length);
|
expect(uploadRef.current.fileList).toHaveLength(files.length);
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
|
|
||||||
jest.useRealTimers();
|
jest.useRealTimers();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1035,5 +1113,7 @@ describe('Upload List', () => {
|
|||||||
};
|
};
|
||||||
const wrapper = mount(<UploadList locale={{}} items={fileList} itemRender={itemRender} />);
|
const wrapper = mount(<UploadList locale={{}} items={fileList} itemRender={itemRender} />);
|
||||||
expect(wrapper.render()).toMatchSnapshot();
|
expect(wrapper.render()).toMatchSnapshot();
|
||||||
|
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,11 +7,11 @@ title:
|
|||||||
|
|
||||||
## zh-CN
|
## zh-CN
|
||||||
|
|
||||||
`beforeUpload` 返回 `false` 或 `Promise.reject` 时,只用于拦截上传行为,不会阻止文件进入上传列表([原因](https://github.com/ant-design/ant-design/issues/15561#issuecomment-475108235))。如果需要阻止列表展现,可以参照此例配合 `onChange` 进行实现。
|
`beforeUpload` 返回 `false` 或 `Promise.reject` 时,只用于拦截上传行为,不会阻止文件进入上传列表([原因](https://github.com/ant-design/ant-design/issues/15561#issuecomment-475108235))。如果需要阻止列表展现,可以通过返回 `Upload.LIST_IGNORE` 实现。
|
||||||
|
|
||||||
## en-US
|
## en-US
|
||||||
|
|
||||||
`beforeUpload` only prevent upload behavior when return false or reject promise, the prevented file would still show in file list. Here is the example you can keep prevented files out of list by using `onChange`.
|
`beforeUpload` only prevent upload behavior when return false or reject promise, the prevented file would still show in file list. Here is the example you can keep prevented files out of list by return `UPLOAD.LIST_IGNORE`.
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
@ -19,19 +19,15 @@ import { Upload, Button, message } from 'antd';
|
|||||||
import { UploadOutlined } from '@ant-design/icons';
|
import { UploadOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
const Uploader = () => {
|
const Uploader = () => {
|
||||||
const [fileList, updateFileList] = useState([]);
|
|
||||||
const props = {
|
const props = {
|
||||||
fileList,
|
|
||||||
beforeUpload: file => {
|
beforeUpload: file => {
|
||||||
if (file.type !== 'image/png') {
|
if (file.type !== 'image/png') {
|
||||||
message.error(`${file.name} is not a png file`);
|
message.error(`${file.name} is not a png file`);
|
||||||
}
|
}
|
||||||
return file.type === 'image/png';
|
return file.type === 'image/png' ? true : Upload.LIST_IGNORE;
|
||||||
},
|
},
|
||||||
onChange: info => {
|
onChange: info => {
|
||||||
console.log(info.fileList);
|
console.log(info.fileList);
|
||||||
// file.status is empty when beforeUpload return false
|
|
||||||
updateFileList(info.fileList.filter(file => !!file.status));
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
|
@ -37,7 +37,7 @@ export interface UploadFile<T = any> {
|
|||||||
export interface UploadChangeParam<T extends object = UploadFile> {
|
export interface UploadChangeParam<T extends object = UploadFile> {
|
||||||
// https://github.com/ant-design/ant-design/issues/14420
|
// https://github.com/ant-design/ant-design/issues/14420
|
||||||
file: T;
|
file: T;
|
||||||
fileList: Array<UploadFile>;
|
fileList: UploadFile[];
|
||||||
event?: { percent: number };
|
event?: { percent: number };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
import { useRef, useEffect } from 'react';
|
|
||||||
import raf from 'rc-util/lib/raf';
|
|
||||||
import useForceUpdate from '../_util/hooks/useForceUpdate';
|
|
||||||
|
|
||||||
// Note. Only for upload usage. Do not export to global util hooks
|
|
||||||
export default function useFreshState<T>(
|
|
||||||
defaultValue: T,
|
|
||||||
propValue?: T,
|
|
||||||
): [(displayValue?: boolean) => T, (newValue: T) => void] {
|
|
||||||
const valueRef = useRef(defaultValue);
|
|
||||||
const forceUpdate = useForceUpdate();
|
|
||||||
const rafRef = useRef<number>();
|
|
||||||
|
|
||||||
// Set value
|
|
||||||
function setValue(newValue: T) {
|
|
||||||
valueRef.current = newValue;
|
|
||||||
forceUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanUp() {
|
|
||||||
raf.cancel(rafRef.current!);
|
|
||||||
}
|
|
||||||
|
|
||||||
function rafSyncValue(newValue: T) {
|
|
||||||
cleanUp();
|
|
||||||
rafRef.current = raf(() => {
|
|
||||||
setValue(newValue);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get value
|
|
||||||
function getValue(displayValue = false) {
|
|
||||||
if (displayValue) {
|
|
||||||
return propValue || valueRef.current;
|
|
||||||
}
|
|
||||||
|
|
||||||
return valueRef.current;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Effect will always update in a next frame to avoid sync state overwrite current processing state
|
|
||||||
useEffect(() => {
|
|
||||||
if (propValue) {
|
|
||||||
rafSyncValue(propValue);
|
|
||||||
}
|
|
||||||
}, [propValue]);
|
|
||||||
|
|
||||||
// Clean up
|
|
||||||
useEffect(
|
|
||||||
() => () => {
|
|
||||||
cleanUp();
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
return [getValue, setValue];
|
|
||||||
}
|
|
@ -4,11 +4,13 @@ export function T() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix IE file.status problem
|
/**
|
||||||
// via coping a new Object
|
* Wrap file with Proxy to provides more info. Will fallback to object if Proxy not support.
|
||||||
export function fileToObject(file: RcFile): UploadFile {
|
*
|
||||||
return {
|
* Origin comment: Fix IE file.status problem via coping a new Object
|
||||||
...file,
|
*/
|
||||||
|
export function wrapFile(file: RcFile | UploadFile): UploadFile {
|
||||||
|
const filledProps = {
|
||||||
lastModified: file.lastModified,
|
lastModified: file.lastModified,
|
||||||
lastModifiedDate: file.lastModifiedDate,
|
lastModifiedDate: file.lastModifiedDate,
|
||||||
name: file.name,
|
name: file.name,
|
||||||
@ -17,6 +19,41 @@ export function fileToObject(file: RcFile): UploadFile {
|
|||||||
uid: file.uid,
|
uid: file.uid,
|
||||||
percent: 0,
|
percent: 0,
|
||||||
originFileObj: file,
|
originFileObj: file,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof Proxy !== 'undefined') {
|
||||||
|
const data = new Map<string | symbol, any>(Object.entries(filledProps));
|
||||||
|
|
||||||
|
return new Proxy(file, {
|
||||||
|
get(target, key) {
|
||||||
|
if (data.has(key)) {
|
||||||
|
return data.get(key);
|
||||||
|
}
|
||||||
|
return (target as any)[key];
|
||||||
|
},
|
||||||
|
set(_, key, value) {
|
||||||
|
data.set(key, value);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
has(target, prop) {
|
||||||
|
return data.has(prop) || prop in target;
|
||||||
|
},
|
||||||
|
ownKeys(target) {
|
||||||
|
const keys = [...Object.keys(target), ...data.keys()];
|
||||||
|
return [...new Set(keys)];
|
||||||
|
},
|
||||||
|
getOwnPropertyDescriptor() {
|
||||||
|
return {
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...file,
|
||||||
|
...filledProps,
|
||||||
} as UploadFile;
|
} as UploadFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@
|
|||||||
"rc-tree": "~4.1.0",
|
"rc-tree": "~4.1.0",
|
||||||
"rc-tree-select": "~4.3.0",
|
"rc-tree-select": "~4.3.0",
|
||||||
"rc-trigger": "^5.2.1",
|
"rc-trigger": "^5.2.1",
|
||||||
"rc-upload": "~3.3.4",
|
"rc-upload": "~4.0.0-alpha.6",
|
||||||
"rc-util": "^5.8.1",
|
"rc-util": "^5.8.1",
|
||||||
"scroll-into-view-if-needed": "^2.2.25",
|
"scroll-into-view-if-needed": "^2.2.25",
|
||||||
"warning": "^4.0.3"
|
"warning": "^4.0.3"
|
||||||
|
Loading…
Reference in New Issue
Block a user