Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/AjaxUploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,12 @@ class AjaxUploader extends Component<UploadProps> {
const { multiple, directory } = this.props;

const items: DataTransferItem[] = [...(dataTransfer.items || [])];
let files: File[] = [...(dataTransfer.files || [])];
let files: File[] = [...(dataTransfer.files || [])].map((file: File) => {
return new File([file], file.name, {
type: file.type,
lastModified: file.lastModified,
});
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

为了代码更简洁,这里的 map 函数可以简化为单行表达式,使用隐式返回。

Suggested change
let files: File[] = [...(dataTransfer.files || [])].map((file: File) => {
return new File([file], file.name, {
type: file.type,
lastModified: file.lastModified,
});
});
let files: File[] = [...(dataTransfer.files || [])].map(file => (
new File([file], file.name, {
type: file.type,
lastModified: file.lastModified,
})
));


if (files.length > 0 || items.some(item => item.kind === 'file')) {
existFileCallback?.();
Expand Down Expand Up @@ -296,7 +301,6 @@ class AjaxUploader extends Component<UploadProps> {
delete this.reqs[uid];
},
};
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whitespace-only change appears to be unintentional. Consider keeping the blank line after the object definition for better readability.

Suggested change
};
};

Copilot uses AI. Check for mistakes.

onStart(origin);
this.reqs[uid] = request(requestOption, { defaultRequest });
}
Expand Down
122 changes: 119 additions & 3 deletions tests/uploader.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ describe('uploader', () => {
Object.defineProperty(files, 'item', {
value: i => files[i],
});

Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whitespace-only change appears to be unintentional. Consider keeping the original blank line for consistency with the rest of the codebase.

Suggested change

Copilot uses AI. Check for mistakes.
// Only can trigger once
let triggerTimes = 0;
handlers.onStart = () => {
Expand All @@ -345,7 +345,7 @@ describe('uploader', () => {
fireEvent.drop(input, { dataTransfer: { files } });

setTimeout(() => {
handlers.onSuccess!(['', files[0].name] as any, files[0] as any, null!);
requests[0].respond(200, {}, `["","${files[0].name}"]`);
}, 100);
});

Expand Down Expand Up @@ -432,7 +432,7 @@ describe('uploader', () => {
fireEvent.paste(input, { clipboardData: { files } });

await sleep(100);
handlers.onSuccess!(['', files[0].name] as any, files[0] as any, null!);
requests[0].respond(200, {}, `["","${files[0].name}"]`);
});

it('support action and data is function returns Promise', async () => {
Expand Down Expand Up @@ -524,6 +524,122 @@ describe('uploader', () => {
expect(preventDefaultSpy).toHaveBeenCalledTimes(0);
preventDefaultSpy.mockRestore();
});

it('should prevent uid overwritten when multiple upload components paste simultaneously', async () => {
const handlers1: UploadProps = {};
const handlers2: UploadProps = {};

const props1: UploadProps = {
...props,
beforeUpload(file, fileList) {
if (handlers1.beforeUpload) {
return handlers1.beforeUpload(file, fileList);
}
return true;
},
onStart(file) {
if (handlers1.onStart) {
handlers1.onStart(file);
}
},
onSuccess(ret, file) {
if (handlers1.onSuccess) {
handlers1.onSuccess(ret, file, null!);
}
},
onError(err, result, file) {
if (handlers1.onError) {
handlers1.onError(err, result, file);
}
},
};

const props2: UploadProps = {
...props,
beforeUpload(file, fileList) {
if (handlers2.beforeUpload) {
return handlers2.beforeUpload(file, fileList);
}
return true;
},
onStart(file) {
if (handlers2.onStart) {
handlers2.onStart(file);
}
},
onSuccess(ret, file) {
if (handlers2.onSuccess) {
handlers2.onSuccess(ret, file, null!);
}
},
onError(err, result, file) {
if (handlers2.onError) {
handlers2.onError(err, result, file);
}
},
};

let uid1: string | undefined;
handlers1.beforeUpload = (file, fileList) => {
expect(file).toHaveProperty('uid');
uid1 = file.uid;
return true;
};
handlers1.onStart = file => {
expect(file).toHaveProperty('uid');
expect(file.uid).toEqual(uid1);
};
handlers1.onSuccess = (ret, file) => {
expect(ret[1]).toEqual(file.name);
expect(file).toHaveProperty('uid');
expect(file.uid).toEqual(uid1);
};
handlers1.onError = (err, result, file) => {
expect(file).toHaveProperty('uid');
expect(file.uid).toEqual(uid1);
throw err;
};

let uid2: string | undefined;
handlers2.beforeUpload = (file, fileList) => {
expect(file).toHaveProperty('uid');
uid2 = file.uid;
return true;
};
handlers2.onStart = file => {
expect(file).toHaveProperty('uid');
expect(file.uid).toEqual(uid2);
};
handlers2.onSuccess = (ret, file) => {
expect(ret[1]).toEqual(file.name);
expect(file).toHaveProperty('uid');
expect(file.uid).toEqual(uid2);
};
handlers2.onError = (err, result, file) => {
expect(file).toHaveProperty('uid');
expect(file.uid).toEqual(uid2);
throw err;
};

const { container: container } = render(<Upload {...props1} pastable />);
render(<Upload {...props2} pastable />);

const input = container.querySelector('input')!;

const files = [
new File([''], 'success.png', { type: 'image/png' }),
];
Object.defineProperty(files, 'item', {
value: i => files[i],
});

fireEvent.paste(input, {
clipboardData: { files },
});

await sleep(100);
requests[0].respond(200, {}, `["","${files[0].name}"]`);
Comment on lines 562 to 576

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这个测试用例很好地覆盖了并发粘贴的场景。不过,它可以更健壮一些。目前它只完成了一个上传请求,并且没有验证两个组件生成的 uid 是唯一的。

我建议更新测试以:

  1. 断言创建了两个独立的请求。
  2. 断言 uid 是不同的。
  3. 完成两个上传请求,以确保两个组件的生命周期回调都得到测试。
      await sleep(100);

      expect(requests).toHaveLength(2);
      expect(uid1).toBeDefined();
      expect(uid2).toBeDefined();
      expect(uid1).not.toEqual(uid2);

      // 完成两个上传
      requests[0].respond(200, {}, `["","${files[0].name}"]`);
      requests[1].respond(200, {}, `["","${files[0].name}"]`);

});
});

describe('directory uploader', () => {
Expand Down