diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..ff56d10
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,21 @@
+const base = require("@umijs/fabric/dist/eslint");
+
+module.exports = {
+ ...base,
+ rules: {
+ ...base.rules,
+ "react/no-array-index-key": 0,
+ "react/sort-comp": 0,
+ "@typescript-eslint/no-explicit-any": 0,
+ "@typescript-eslint/no-empty-interface": 0,
+ "@typescript-eslint/no-inferrable-types": 0,
+ "react/no-find-dom-node": 0,
+ "react/require-default-props": 0,
+ "no-confusing-arrow": 0,
+ "import/no-named-as-default-member": 0,
+ "jsx-a11y/label-has-for": 0,
+ "jsx-a11y/label-has-associated-control": 0,
+ "import/no-extraneous-dependencies": 0,
+ "no-underscore-dangle": 0,
+ },
+};
diff --git a/.fatherrc.js b/.fatherrc.js
new file mode 100644
index 0000000..9d8c16b
--- /dev/null
+++ b/.fatherrc.js
@@ -0,0 +1,9 @@
+export default {
+ cjs: "babel",
+ esm: { type: "babel", importLibToEs: true },
+ preCommit: {
+ eslint: true,
+ prettier: true,
+ },
+ runtimeHelpers: true,
+};
diff --git a/.gitignore b/.gitignore
index 9d6f5bc..bc73d2e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,5 @@ es
package-lock.json
tmp/
.history
+.storybook
+.doc
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..895b8bd
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,6 @@
+{
+ "singleQuote": true,
+ "trailingComma": "all",
+ "proseWrap": "never",
+ "printWidth": 100
+}
diff --git a/.travis.yml b/.travis.yml
index 8edbf2c..70cdd0e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,7 +7,7 @@ notifications:
- yiminghe@gmail.com
node_js:
-- 6
+- 10
before_install:
- |
@@ -29,4 +29,5 @@ env:
matrix:
- TEST_TYPE=lint
- TEST_TYPE=test
- - TEST_TYPE=coverage
\ No newline at end of file
+ - TEST_TYPE=coverage
+ - TEST_TYPE=compile
diff --git a/examples/asyncAction.html b/examples/asyncAction.html
deleted file mode 100644
index e69de29..0000000
diff --git a/examples/asyncAction.js b/examples/asyncAction.tsx
similarity index 69%
rename from examples/asyncAction.js
rename to examples/asyncAction.tsx
index a81ef6f..61b6773 100644
--- a/examples/asyncAction.js
+++ b/examples/asyncAction.tsx
@@ -1,11 +1,10 @@
/* eslint no-console:0 */
import React from 'react';
-import ReactDOM from 'react-dom';
-import Upload from 'rc-upload';
+import Upload from '..';
const props = {
action: () => {
- return new Promise((resolve) => {
+ return new Promise(resolve => {
setTimeout(() => {
resolve('/upload.do');
}, 2000);
@@ -31,10 +30,12 @@ const Test = () => {
}}
>
);
};
-ReactDOM.render(, document.getElementById('__react-content'));
+export default Test;
diff --git a/examples/beforeUpload.html b/examples/beforeUpload.html
deleted file mode 100644
index 48cdce8..0000000
--- a/examples/beforeUpload.html
+++ /dev/null
@@ -1 +0,0 @@
-placeholder
diff --git a/examples/beforeUpload.js b/examples/beforeUpload.tsx
similarity index 73%
rename from examples/beforeUpload.js
rename to examples/beforeUpload.tsx
index 8417f28..fcad0fe 100644
--- a/examples/beforeUpload.js
+++ b/examples/beforeUpload.tsx
@@ -1,8 +1,7 @@
/* eslint no-console:0 */
import React from 'react';
-import ReactDOM from 'react-dom';
-import Upload from 'rc-upload';
+import Upload from '..';
const props = {
action: '/upload.do',
@@ -18,7 +17,7 @@ const props = {
},
beforeUpload(file, fileList) {
console.log(file, fileList);
- return new Promise((resolve) => {
+ return new Promise(resolve => {
console.log('start check');
setTimeout(() => {
console.log('check finshed');
@@ -36,10 +35,12 @@ const Test = () => {
}}
>
);
};
-ReactDOM.render(, document.getElementById('__react-content'));
+export default Test;
diff --git a/examples/customRequest.html b/examples/customRequest.html
deleted file mode 100644
index 48cdce8..0000000
--- a/examples/customRequest.html
+++ /dev/null
@@ -1 +0,0 @@
-placeholder
diff --git a/examples/customRequest.js b/examples/customRequest.tsx
similarity index 85%
rename from examples/customRequest.js
rename to examples/customRequest.tsx
index 9ef7b2d..611251d 100644
--- a/examples/customRequest.js
+++ b/examples/customRequest.tsx
@@ -1,8 +1,7 @@
/* eslint no-console:0 */
import React from 'react';
-import ReactDOM from 'react-dom';
-import Upload from 'rc-upload';
import axios from 'axios';
+import Upload from '..';
const uploadProps = {
action: '/upload.do',
@@ -49,7 +48,7 @@ const uploadProps = {
withCredentials,
headers,
onUploadProgress: ({ total, loaded }) => {
- onProgress({ percent: Math.round(loaded / total * 100).toFixed(2) }, file);
+ onProgress({ percent: Math.round((loaded / total) * 100).toFixed(2) }, file);
},
})
.then(({ data: response }) => {
@@ -74,11 +73,11 @@ const Test = () => {
>
-
+
);
};
-ReactDOM.render(, document.getElementById('__react-content'));
+export default Test;
diff --git a/examples/directoryUpload.html b/examples/directoryUpload.html
deleted file mode 100644
index b3a4252..0000000
--- a/examples/directoryUpload.html
+++ /dev/null
@@ -1 +0,0 @@
-placeholder
\ No newline at end of file
diff --git a/examples/directoryUpload.js b/examples/directoryUpload.js
deleted file mode 100644
index ad035fe..0000000
--- a/examples/directoryUpload.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/* eslint no-console:0 */
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-import Upload from 'rc-upload';
-
-class Test extends React.Component {
- constructor(props) {
- super(props);
- this.uploaderProps = {
- action: '/upload.do',
- data: { a: 1, b: 2 },
- headers: {
- Authorization: 'xxxxxxx',
- },
- directory: true,
- beforeUpload(file) {
- console.log('beforeUpload', file.name);
- },
- onStart: (file) => {
- console.log('onStart', file.name);
- },
- onSuccess(file) {
- console.log('onSuccess', file);
- },
- onProgress(step, file) {
- console.log('onProgress', Math.round(step.percent), file.name);
- },
- onError(err) {
- console.log('onError', err);
- },
- };
- }
- render() {
- return ();
- }
-}
-
-ReactDOM.render(, document.getElementById('__react-content'));
diff --git a/examples/directoryUpload.tsx b/examples/directoryUpload.tsx
new file mode 100644
index 0000000..3615dd3
--- /dev/null
+++ b/examples/directoryUpload.tsx
@@ -0,0 +1,43 @@
+/* eslint no-console:0 */
+
+import React from 'react';
+import Upload from '..';
+
+const Test = () => {
+ const uploaderProps = {
+ action: '/upload.do',
+ data: { a: 1, b: 2 },
+ directory: true,
+ beforeUpload(file) {
+ console.log('beforeUpload', file.name);
+ },
+ onStart: file => {
+ console.log('onStart', file.name);
+ },
+ onSuccess(file) {
+ console.log('onSuccess', file);
+ },
+ onProgress(step, file) {
+ console.log('onProgress', Math.round(step.percent), file.name);
+ },
+ onError(err) {
+ console.log('onError', err);
+ },
+ };
+
+ return (
+
+ );
+};
+
+export default Test;
diff --git a/examples/drag.html b/examples/drag.html
deleted file mode 100644
index 48cdce8..0000000
--- a/examples/drag.html
+++ /dev/null
@@ -1 +0,0 @@
-placeholder
diff --git a/examples/drag.js b/examples/drag.tsx
similarity index 67%
rename from examples/drag.js
rename to examples/drag.tsx
index da307e6..cb695fa 100644
--- a/examples/drag.js
+++ b/examples/drag.tsx
@@ -1,8 +1,6 @@
/* eslint no-console:0 */
-
import React from 'react';
-import ReactDOM from 'react-dom';
-import Upload from 'rc-upload';
+import Upload from '..';
const props = {
action: '/upload.do',
@@ -11,7 +9,7 @@ const props = {
beforeUpload(file) {
console.log('beforeUpload', file.name);
},
- onStart: (file) => {
+ onStart: file => {
console.log('onStart', file.name);
},
onSuccess(file) {
@@ -27,4 +25,20 @@ const props = {
// openFileDialogOnClick: false
};
-ReactDOM.render(, document.getElementById('__react-content'));
+const Test = () => {
+ return (
+
+ );
+};
+
+export default Test;
diff --git a/examples/simple.html b/examples/simple.html
deleted file mode 100644
index 48cdce8..0000000
--- a/examples/simple.html
+++ /dev/null
@@ -1 +0,0 @@
-placeholder
diff --git a/examples/simple.js b/examples/simple.js
deleted file mode 100644
index cffc81d..0000000
--- a/examples/simple.js
+++ /dev/null
@@ -1,98 +0,0 @@
-/* eslint no-console:0 */
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-import Upload from 'rc-upload';
-
-const style = `
- .rc-upload-disabled {
- opacity:0.5;
- `;
-
-class Test extends React.Component {
- constructor(props) {
- super(props);
- this.uploaderProps = {
- action: '/upload.do',
- data: { a: 1, b: 2 },
- headers: {
- Authorization: 'xxxxxxx',
- },
- multiple: true,
- beforeUpload(file) {
- console.log('beforeUpload', file.name);
- },
- onStart: (file) => {
- console.log('onStart', file.name);
- },
- onSuccess(file) {
- console.log('onSuccess', file);
- },
- onProgress(step, file) {
- console.log('onProgress', Math.round(step.percent), file.name);
- },
- onError(err) {
- console.log('onError', err);
- },
- };
- this.state = {
- destroyed: false,
- };
- }
- destroy = () => {
- this.setState({
- destroyed: true,
- });
- }
- render() {
- if (this.state.destroyed) {
- return null;
- }
- return (
-
固定位置
-
-
-
-
-
-
滚动
-
-
-
-
-
);
- }
-}
-
-ReactDOM.render(, document.getElementById('__react-content'));
diff --git a/examples/simple.tsx b/examples/simple.tsx
new file mode 100644
index 0000000..713f830
--- /dev/null
+++ b/examples/simple.tsx
@@ -0,0 +1,76 @@
+/* eslint no-console:0 */
+
+import React from 'react';
+import Upload from '..';
+
+const style = `
+ .rc-upload-disabled {
+ opacity:0.5;
+ `;
+
+const uploaderProps = {
+ action: '/upload.do',
+ data: { a: 1, b: 2 },
+ multiple: true,
+ beforeUpload(file) {
+ console.log('beforeUpload', file.name);
+ },
+ onStart: file => {
+ console.log('onStart', file.name);
+ },
+ onSuccess(file) {
+ console.log('onSuccess', file);
+ },
+ onProgress(step, file) {
+ console.log('onProgress', Math.round(step.percent), file.name);
+ },
+ onError(err) {
+ console.log('onError', err);
+ },
+};
+
+const Test = () => {
+ const [destroyed, setDestroyed] = React.useState(false);
+
+ const destroy = () => {
+ setDestroyed(true);
+ };
+
+ if (destroyed) {
+ return null;
+ }
+
+ return (
+
+
固定位置
+
+
+
滚动
+
+
+
+
+ );
+};
+
+export default Test;
diff --git a/examples/transformFile.html b/examples/transformFile.html
deleted file mode 100644
index 48cdce8..0000000
--- a/examples/transformFile.html
+++ /dev/null
@@ -1 +0,0 @@
-placeholder
diff --git a/examples/transformFile.js b/examples/transformFile.tsx
similarity index 84%
rename from examples/transformFile.js
rename to examples/transformFile.tsx
index 31b23ba..b918d5c 100644
--- a/examples/transformFile.js
+++ b/examples/transformFile.tsx
@@ -1,7 +1,6 @@
/* eslint no-console:0 */
import React from 'react';
-import ReactDOM from 'react-dom';
-import Upload from 'rc-upload';
+import Upload from '..';
const uploadProps = {
action: '/upload.do',
@@ -23,7 +22,7 @@ const uploadProps = {
console.log('onProgress', `${percent}%`, file.name);
},
transformFile(file) {
- return new Promise((resolve) => {
+ return new Promise(resolve => {
// eslint-disable-next-line no-undef
const reader = new FileReader();
reader.readAsDataURL(file);
@@ -50,11 +49,11 @@ const Test = () => {
>
-
+
);
};
-ReactDOM.render(, document.getElementById('__react-content'));
+export default Test;
diff --git a/jest.config.js b/jest.config.js
new file mode 100644
index 0000000..0a09639
--- /dev/null
+++ b/jest.config.js
@@ -0,0 +1,4 @@
+module.exports = {
+ setupFiles: ["./tests/setup.js"],
+ snapshotSerializers: [require.resolve("enzyme-to-json/serializer")],
+};
diff --git a/now.json b/now.json
new file mode 100644
index 0000000..fd2f2ad
--- /dev/null
+++ b/now.json
@@ -0,0 +1,11 @@
+{
+ "version": 2,
+ "name": "rc-upload",
+ "builds": [
+ {
+ "src": "package.json",
+ "use": "@now/static-build",
+ "config": { "distDir": ".doc" }
+ }
+ ]
+}
diff --git a/package.json b/package.json
index 1383f26..da896af 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "rc-upload",
- "version": "3.2.0",
+ "version": "3.2.1",
"description": "upload ui component for react",
"keywords": [
"react",
@@ -23,40 +23,46 @@
],
"main": "./lib/index",
"module": "./es/index",
- "config": {
- "port": 8020
- },
"scripts": {
- "build": "rc-tools run build",
- "gh-pages": "rc-tools run gh-pages",
- "start": "node server",
- "compile": "rc-tools run compile",
- "pub": "rc-tools run pub",
- "lint": "rc-tools run lint",
- "test": "jest --setupTestFrameworkScriptFile=raf/polyfill",
- "coverage": "jest --coverage && cat ./coverage/lcov.info | coveralls"
+ "start": "cross-env NODE_ENV=development father doc dev --storybook",
+ "build": "father doc build --storybook",
+ "compile": "father build",
+ "gh-pages": "npm run build && father doc deploy",
+ "prepublishOnly": "npm run compile && np --yolo --no-publish",
+ "postpublish": "npm run gh-pages",
+ "lint": "eslint src/ --ext .ts,.tsx,.jsx,.js,.md",
+ "prettier": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
+ "test": "father test",
+ "coverage": "father test --coverage"
},
"devDependencies": {
+ "@types/jest": "^26.0.0",
+ "@types/react": "^16.9.2",
+ "@types/react-dom": "^16.9.0",
+ "@umijs/fabric": "^2.0.0",
"axios": "^0.20.0",
"co-busboy": "^1.3.0",
"coveralls": "^3.0.3",
- "expect.js": "0.3.x",
+ "cross-env": "^7.0.0",
+ "enzyme": "^3.1.1",
+ "enzyme-adapter-react-16": "^1.0.1",
+ "enzyme-to-json": "^3.1.2",
+ "eslint": "^7.1.0",
+ "father": "^2.22.0",
"fs-extra": "^9.0.0",
"gh-pages": "^3.0.0",
- "jest": "^20.0.1",
- "pre-commit": "1.x",
"raf": "^3.4.0",
"rc-tools": "8.x",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"sinon": "^9.0.2",
+ "typescript": "^3.7.2",
"vinyl-fs": "^3.0.3"
},
- "pre-commit": [
- "lint"
- ],
"dependencies": {
- "classnames": "^2.2.5"
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.5",
+ "rc-util": "^5.2.0"
},
"jest": {
"collectCoverageFrom": [
diff --git a/src/AjaxUploader.jsx b/src/AjaxUploader.tsx
similarity index 52%
rename from src/AjaxUploader.jsx
rename to src/AjaxUploader.tsx
index 2a7612b..c19fade 100644
--- a/src/AjaxUploader.jsx
+++ b/src/AjaxUploader.tsx
@@ -1,57 +1,52 @@
/* eslint react/no-is-mounted:0,react/sort-comp:0,react/prop-types:0 */
-import React, { Component } from 'react';
+import React, { Component, ReactElement } from 'react';
import classNames from 'classnames';
+import pickAttrs from 'rc-util/lib/pickAttrs';
import defaultRequest from './request';
import getUid from './uid';
import attrAccept from './attr-accept';
import traverseFileTree from './traverseFileTree';
+import { UploadProps, UploadProgressEvent, UploadRequestError, RcFile } from './interface';
-const dataOrAriaAttributeProps = (props) => {
- return Object.keys(props).reduce(
- (acc, key) => {
- if (key.substr(0, 5) === 'data-' || key.substr(0, 5) === 'aria-' || key === 'role') {
- acc[key] = props[key];
- }
- return acc;
- },
- {},
- );
-};
+class AjaxUploader extends Component {
+ state = { uid: getUid() };
+
+ reqs: any = {};
-class AjaxUploader extends Component {
- state = { uid: getUid() }
+ private fileInput: HTMLInputElement;
- reqs = {}
+ private _isMounted: boolean;
- onChange = e => {
- const files = e.target.files;
+ onChange = (e: React.ChangeEvent) => {
+ const { files } = e.target;
this.uploadFiles(files);
this.reset();
- }
+ };
- onClick = (e) => {
+ onClick = (e: React.MouseEvent | React.KeyboardEvent) => {
const el = this.fileInput;
if (!el) {
return;
}
const { children, onClick } = this.props;
- if (children && children.type === 'button') {
- el.parentNode.focus();
- el.parentNode.querySelector('button').blur();
+ if (children && (children as ReactElement).type === 'button') {
+ const parent = el.parentNode as HTMLInputElement;
+ parent.focus();
+ parent.querySelector('button').blur();
}
el.click();
if (onClick) {
onClick(e);
}
- }
+ };
- onKeyDown = e => {
+ onKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
- this.onClick();
+ this.onClick(e);
}
- }
+ };
- onFileDrop = e => {
+ onFileDrop = (e: React.DragEvent) => {
const { multiple } = this.props;
e.preventDefault();
@@ -62,15 +57,14 @@ class AjaxUploader extends Component {
if (this.props.directory) {
traverseFileTree(
- Array.prototype.slice
- .call(e.dataTransfer.items),
+ Array.prototype.slice.call(e.dataTransfer.items),
this.uploadFiles,
- _file => attrAccept(_file, this.props.accept)
+ (_file: RcFile) => attrAccept(_file, this.props.accept),
);
} else {
let files = Array.prototype.slice
.call(e.dataTransfer.files)
- .filter(file => attrAccept(file, this.props.accept));
+ .filter((file: RcFile) => attrAccept(file, this.props.accept));
if (multiple === false) {
files = files.slice(0, 1);
@@ -78,7 +72,7 @@ class AjaxUploader extends Component {
this.uploadFiles(files);
}
- }
+ };
componentDidMount() {
this._isMounted = true;
@@ -89,10 +83,11 @@ class AjaxUploader extends Component {
this.abort();
}
- uploadFiles = (files) => {
- const postFiles = Array.prototype.slice.call(files);
+ uploadFiles = (files: FileList) => {
+ const postFiles: Array = Array.prototype.slice.call(files);
postFiles
- .map(file => {
+ .map((file: RcFile & { uid?: string }) => {
+ // eslint-disable-next-line no-param-reassign
file.uid = getUid();
return file;
})
@@ -101,7 +96,7 @@ class AjaxUploader extends Component {
});
};
- upload(file, fileList) {
+ upload(file: RcFile, fileList: Array) {
const { props } = this;
if (!props.beforeUpload) {
// always async in case use react state to keep fileList
@@ -109,33 +104,31 @@ class AjaxUploader extends Component {
}
const before = props.beforeUpload(file, fileList);
- if (before && before.then) {
- before.then((processedFile) => {
- const processedFileType = Object.prototype.toString.call(processedFile);
- if (processedFileType === '[object File]' || processedFileType === '[object Blob]') {
- return this.post(processedFile);
- }
- return this.post(file);
- }).catch(e => {
- // eslint-disable-next-line no-console
- console.log(e);
- });
+ if (before && typeof before !== 'boolean' && before.then) {
+ before
+ .then(processedFile => {
+ const processedFileType = Object.prototype.toString.call(processedFile);
+ if (processedFileType === '[object File]' || processedFileType === '[object Blob]') {
+ return this.post(processedFile);
+ }
+ return this.post(file);
+ })
+ .catch(e => {
+ // eslint-disable-next-line no-console
+ console.log(e);
+ });
} else if (before !== false) {
setTimeout(() => this.post(file), 0);
}
return undefined;
}
- post(file) {
+ post(file: RcFile) {
if (!this._isMounted) {
return;
}
const { props } = this;
- const {
- onStart,
- onProgress,
- transformFile = (originFile) => originFile,
- } = props;
+ const { onStart, onProgress, transformFile = originFile => originFile } = props;
new Promise(resolve => {
let { action } = props;
@@ -143,21 +136,22 @@ class AjaxUploader extends Component {
action = action(file);
}
return resolve(action);
- }).then(action => {
+ }).then((action: string) => {
const { uid } = file;
const request = props.customRequest || defaultRequest;
const transform = Promise.resolve(transformFile(file))
- .then((transformedFile) => {
+ .then(transformedFile => {
let { data } = props;
if (typeof data === 'function') {
data = data(transformedFile);
}
return Promise.all([transformedFile, data]);
- }).catch(e => {
+ })
+ .catch(e => {
console.error(e); // eslint-disable-line no-console
});
- transform.then(([transformedFile, data]) => {
+ transform.then(([transformedFile, data]: [RcFile, object]) => {
const requestOption = {
action,
filename: props.name,
@@ -166,20 +160,23 @@ class AjaxUploader extends Component {
headers: props.headers,
withCredentials: props.withCredentials,
method: props.method || 'post',
- onProgress: onProgress ? e => {
- onProgress(e, file);
- } : null,
- onSuccess: (ret, xhr) => {
+ onProgress: onProgress
+ ? (e: UploadProgressEvent) => {
+ onProgress(e, file);
+ }
+ : null,
+ onSuccess: (ret: any, xhr: XMLHttpRequest) => {
delete this.reqs[uid];
props.onSuccess(ret, file, xhr);
},
- onError: (err, ret) => {
+ onError: (err: UploadRequestError, ret: any) => {
delete this.reqs[uid];
props.onError(err, ret, file);
},
};
- this.reqs[uid] = request(requestOption);
+
onStart(file);
+ this.reqs[uid] = request(requestOption);
});
});
}
@@ -190,19 +187,16 @@ class AjaxUploader extends Component {
});
}
- abort(file) {
+ abort(file?: any) {
const { reqs } = this;
if (file) {
- let uid = file;
- if (file && file.uid) {
- uid = file.uid;
- }
+ const uid = file.uid ? file.uid : file;
if (reqs[uid] && reqs[uid].abort) {
reqs[uid].abort();
}
delete reqs[uid];
} else {
- Object.keys(reqs).forEach((uid) => {
+ Object.keys(reqs).forEach(uid => {
if (reqs[uid] && reqs[uid].abort) {
reqs[uid].abort();
}
@@ -211,15 +205,25 @@ class AjaxUploader extends Component {
}
}
- saveFileInput = (node) => {
+ saveFileInput = (node: HTMLInputElement) => {
this.fileInput = node;
- }
+ };
render() {
const {
- component: Tag, prefixCls, className, disabled, id,
- style, multiple, accept, children, directory, openFileDialogOnClick,
- onMouseEnter, onMouseLeave,
+ component: Tag,
+ prefixCls,
+ className,
+ disabled,
+ id,
+ style,
+ multiple,
+ accept,
+ children,
+ directory,
+ openFileDialogOnClick,
+ onMouseEnter,
+ onMouseLeave,
...otherProps
} = this.props;
const cls = classNames({
@@ -227,24 +231,25 @@ class AjaxUploader extends Component {
[`${prefixCls}-disabled`]: disabled,
[className]: className,
});
- const events = disabled ? {} : {
- onClick: openFileDialogOnClick ? this.onClick : () => {},
- onKeyDown: openFileDialogOnClick ? this.onKeyDown : () => {},
- onMouseEnter,
- onMouseLeave,
- onDrop: this.onFileDrop,
- onDragOver: this.onFileDrop,
- tabIndex: '0',
- };
+ // because input don't have directory/webkitdirectory type declaration
+ const dirProps: any = directory
+ ? { directory: 'directory', webkitdirectory: 'webkitdirectory' }
+ : {};
+ const events = disabled
+ ? {}
+ : {
+ onClick: openFileDialogOnClick ? this.onClick : () => {},
+ onKeyDown: openFileDialogOnClick ? this.onKeyDown : () => {},
+ onMouseEnter,
+ onMouseLeave,
+ onDrop: this.onFileDrop,
+ onDragOver: this.onFileDrop,
+ tabIndex: '0',
+ };
return (
-
+
diff --git a/src/Upload.jsx b/src/Upload.tsx
similarity index 73%
rename from src/Upload.jsx
rename to src/Upload.tsx
index 303a774..10df10a 100644
--- a/src/Upload.jsx
+++ b/src/Upload.tsx
@@ -1,11 +1,11 @@
/* eslint react/prop-types:0 */
import React, { Component } from 'react';
import AjaxUpload from './AjaxUploader';
+import { UploadProps, RcFile } from './interface';
-function empty() {
-}
+function empty() {}
-class Upload extends Component {
+class Upload extends Component {
static defaultProps = {
component: 'span',
prefixCls: 'rc-upload',
@@ -21,15 +21,17 @@ class Upload extends Component {
customRequest: null,
withCredentials: false,
openFileDialogOnClick: true,
- }
+ };
- abort(file) {
+ private uploader: AjaxUpload;
+
+ abort(file: RcFile) {
this.uploader.abort(file);
}
- saveUploader = (node) => {
+ saveUploader = (node: AjaxUpload) => {
this.uploader = node;
- }
+ };
render() {
return ;
diff --git a/src/attr-accept.js b/src/attr-accept.ts
similarity index 78%
rename from src/attr-accept.js
rename to src/attr-accept.ts
index 4099a0f..f6ae14e 100644
--- a/src/attr-accept.js
+++ b/src/attr-accept.ts
@@ -1,8 +1,10 @@
-function endsWith(str, suffix) {
+import { RcFile } from './interface';
+
+function endsWith(str: string, suffix: string) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
-export default (file, acceptedFiles) => {
+export default (file: RcFile, acceptedFiles: string | Array) => {
if (file && acceptedFiles) {
const acceptedFilesArray = Array.isArray(acceptedFiles)
? acceptedFiles
@@ -15,7 +17,8 @@ export default (file, acceptedFiles) => {
const validType = type.trim();
if (validType.charAt(0) === '.') {
return endsWith(fileName.toLowerCase(), validType.toLowerCase());
- } else if (/\/\*$/.test(validType)) {
+ }
+ if (/\/\*$/.test(validType)) {
// This is something like a image/* mime type
return baseMimeType === validType.replace(/\/.*$/, '');
}
diff --git a/src/index.js b/src/index.js
deleted file mode 100644
index 1eeceb0..0000000
--- a/src/index.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// export this package's api
-import Upload from './Upload';
-
-export default Upload;
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..1cbbd3e
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,6 @@
+import Upload from './Upload';
+import { UploadProps } from './interface';
+
+export { UploadProps };
+
+export default Upload;
diff --git a/src/interface.tsx b/src/interface.tsx
new file mode 100644
index 0000000..a919680
--- /dev/null
+++ b/src/interface.tsx
@@ -0,0 +1,64 @@
+import * as React from 'react';
+
+export interface UploadProps
+ extends Omit, 'onError' | 'onProgress'> {
+ name?: string;
+ style?: React.CSSProperties;
+ className?: string;
+ disabled?: boolean;
+ component?: React.JSXElementConstructor;
+ action?: string | ((file: RcFile) => string);
+ method?: UploadRequestMethod;
+ directory?: boolean;
+ data?: object | ((file: RcFile | string | Blob) => object);
+ headers?: UploadRequestHeader;
+ accept?: string;
+ multiple?: boolean;
+ onStart?: (file: RcFile) => void;
+ onError?: (error: Error, ret: object, file: RcFile) => void;
+ onSuccess?: (response: object, file: RcFile, xhr: object) => void;
+ onProgress?: (event: UploadProgressEvent, file: RcFile) => void;
+ beforeUpload?: (file: RcFile, FileList: RcFile[]) => boolean | Promise;
+ customRequest?: () => void;
+ withCredentials?: boolean;
+ openFileDialogOnClick?: boolean;
+ transformFile?: (file: RcFile) => string | Blob | RcFile | PromiseLike;
+ prefixCls?: string;
+ id?: string;
+ onMouseEnter?: (e: React.MouseEvent) => void;
+ onMouseLeave?: (e: React.MouseEvent) => void;
+ onClick?: (e: React.MouseEvent | React.KeyboardEvent) => void;
+}
+
+export interface UploadProgressEvent extends ProgressEvent {
+ percent: number;
+}
+
+export type UploadRequestMethod = 'POST' | 'PUT' | 'PATCH' | 'post' | 'put' | 'patch';
+
+export interface UploadRequestHeader {
+ [key: string]: string;
+}
+
+export interface UploadRequestError extends Error {
+ status?: number;
+ method?: UploadRequestMethod;
+ url?: string;
+}
+
+export interface UploadRequestOption {
+ onProgress?: (event: UploadProgressEvent) => void;
+ onError?: (event: UploadRequestError | ProgressEvent, body?: T) => void;
+ onSuccess?: (body: T, xhr: XMLHttpRequest) => void;
+ data?: object;
+ filename?: string;
+ file: RcFile;
+ withCredentials?: boolean;
+ action: string;
+ headers?: UploadRequestHeader;
+ method: UploadRequestMethod;
+}
+
+export interface RcFile extends File {
+ uid: string;
+}
diff --git a/src/request.js b/src/request.ts
similarity index 81%
rename from src/request.js
rename to src/request.ts
index 38b4c89..d41b38e 100644
--- a/src/request.js
+++ b/src/request.ts
@@ -1,13 +1,15 @@
-function getError(option, xhr) {
+import { UploadRequestOption, UploadRequestError, UploadProgressEvent } from './interface';
+
+function getError(option: UploadRequestOption, xhr: XMLHttpRequest) {
const msg = `cannot ${option.method} ${option.action} ${xhr.status}'`;
- const err = new Error(msg);
+ const err = new Error(msg) as UploadRequestError;
err.status = xhr.status;
err.method = option.method;
err.url = option.action;
return err;
}
-function getBody(xhr) {
+function getBody(xhr: XMLHttpRequest) {
const text = xhr.responseText || xhr.response;
if (!text) {
return text;
@@ -20,25 +22,14 @@ function getBody(xhr) {
}
}
-// option {
-// onProgress: (event: { percent: number }): void,
-// onError: (event: Error, body?: Object): void,
-// onSuccess: (body: Object): void,
-// data: Object,
-// filename: String,
-// file: File,
-// withCredentials: Boolean,
-// action: String,
-// headers: Object,
-// }
-export default function upload(option) {
+export default function upload(option: UploadRequestOption) {
// eslint-disable-next-line no-undef
const xhr = new XMLHttpRequest();
if (option.onProgress && xhr.upload) {
- xhr.upload.onprogress = function progress(e) {
+ xhr.upload.onprogress = function progress(e: UploadProgressEvent) {
if (e.total > 0) {
- e.percent = e.loaded / e.total * 100;
+ e.percent = (e.loaded / e.total) * 100;
}
option.onProgress(e);
};
@@ -103,7 +94,7 @@ export default function upload(option) {
Object.keys(headers).forEach(h => {
if (headers[h] !== null) {
xhr.setRequestHeader(h, headers[h]);
- }
+ }
});
xhr.send(formData);
diff --git a/src/traverseFileTree.js b/src/traverseFileTree.ts
similarity index 56%
rename from src/traverseFileTree.js
rename to src/traverseFileTree.ts
index 3747a92..9de92cc 100644
--- a/src/traverseFileTree.js
+++ b/src/traverseFileTree.ts
@@ -1,9 +1,21 @@
-function loopFiles(item, callback) {
+import { RcFile } from './interface';
+
+interface InternalDataTransferItem extends DataTransferItem {
+ isFile: boolean;
+ file: (cd: (file: RcFile & { webkitRelativePath?: string }) => void) => void;
+ createReader: () => any;
+ fullPath: string;
+ isDirectory: boolean;
+ name: string;
+ path: string;
+}
+
+function loopFiles(item: InternalDataTransferItem, callback) {
const dirReader = item.createReader();
let fileList = [];
function sequence() {
- dirReader.readEntries((entries) => {
+ dirReader.readEntries((entries: Array) => {
const entryList = Array.prototype.slice.apply(entries);
fileList = fileList.concat(entryList);
@@ -21,11 +33,13 @@ function loopFiles(item, callback) {
sequence();
}
-const traverseFileTree = (files, callback, isAccepted) => {
- const _traverseFileTree = (item, path) => {
- path = path || '';
+const traverseFileTree = (files: Array, callback, isAccepted) => {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ const _traverseFileTree = (item: InternalDataTransferItem, path?: string) => {
+ // eslint-disable-next-line no-param-reassign
+ item.path = path || '';
if (item.isFile) {
- item.file((file) => {
+ item.file(file => {
if (isAccepted(file)) {
// https://github.com/ant-design/ant-design/issues/16426
if (item.fullPath && !file.webkitRelativePath) {
@@ -34,6 +48,7 @@ const traverseFileTree = (files, callback, isAccepted) => {
writable: true,
},
});
+ // eslint-disable-next-line no-param-reassign
file.webkitRelativePath = item.fullPath.replace(/^\//, '');
Object.defineProperties(file, {
webkitRelativePath: {
@@ -45,8 +60,8 @@ const traverseFileTree = (files, callback, isAccepted) => {
}
});
} else if (item.isDirectory) {
- loopFiles(item, (entries) => {
- entries.forEach((entryItem) => {
+ loopFiles(item, (entries: Array) => {
+ entries.forEach(entryItem => {
_traverseFileTree(entryItem, `${path}${item.name}/`);
});
});
diff --git a/src/uid.js b/src/uid.ts
similarity index 57%
rename from src/uid.js
rename to src/uid.ts
index 789a6f6..3ad3f8e 100644
--- a/src/uid.js
+++ b/src/uid.ts
@@ -1,6 +1,7 @@
-const now = +(new Date());
+const now = +new Date();
let index = 0;
export default function uid() {
+ // eslint-disable-next-line no-plusplus
return `rc-upload-${now}-${++index}`;
}
diff --git a/tests/index.js b/tests/index.js
deleted file mode 100644
index ed92f29..0000000
--- a/tests/index.js
+++ /dev/null
@@ -1,2 +0,0 @@
-import './uploader.spec';
-import './request.spec';
diff --git a/tests/request.spec.js b/tests/request.spec.js
index 3997b2c..f5fae71 100644
--- a/tests/request.spec.js
+++ b/tests/request.spec.js
@@ -1,13 +1,11 @@
/* eslint no-console:0 */
-import expect from 'expect.js';
import sinon from 'sinon';
import request from '../src/request';
let xhr;
let requests;
-const empty = () => {
-};
+const empty = () => {};
const option = {
onSuccess: empty,
action: 'upload.do',
@@ -37,8 +35,8 @@ describe('request', () => {
it('upload request success', done => {
option.onError = done;
option.onSuccess = ret => {
- expect(ret).to.eql({ success: true });
- expect(requests[0].requestBody.getAll('c[]')).to.eql([3, 4]);
+ expect(ret).toEqual({ success: true });
+ expect(requests[0].requestBody.getAll('c[]')).toEqual(['3', '4']);
done();
};
request(option);
@@ -47,7 +45,7 @@ describe('request', () => {
it('40x code should be error', done => {
option.onError = e => {
- expect(e.toString()).to.contain('404');
+ expect(e.toString()).toContain('404');
done();
};
@@ -59,7 +57,7 @@ describe('request', () => {
it('2xx code should be success', done => {
option.onError = done;
option.onSuccess = ret => {
- expect(ret).to.equal('');
+ expect(ret).toEqual('');
done();
};
request(option);
@@ -68,7 +66,7 @@ describe('request', () => {
it('get headers', () => {
request(option);
- expect(requests[0].requestHeaders).to.eql({
+ expect(requests[0].requestHeaders).toEqual({
'X-Requested-With': 'XMLHttpRequest',
from: 'hello',
});
@@ -77,6 +75,6 @@ describe('request', () => {
it('can empty X-Requested-With', () => {
option.headers['X-Requested-With'] = null;
request(option);
- expect(requests[0].requestHeaders).to.eql({ from: 'hello' });
+ expect(requests[0].requestHeaders).toEqual({ from: 'hello' });
});
});
diff --git a/tests/setup.js b/tests/setup.js
new file mode 100644
index 0000000..4c18e28
--- /dev/null
+++ b/tests/setup.js
@@ -0,0 +1,6 @@
+global.requestAnimationFrame = cb => setTimeout(cb, 0);
+
+const Enzyme = require('enzyme');
+const Adapter = require('enzyme-adapter-react-16');
+
+Enzyme.configure({ adapter: new Adapter() });
diff --git a/tests/uploader.spec.js b/tests/uploader.spec.js
index b509544..2df046d 100644
--- a/tests/uploader.spec.js
+++ b/tests/uploader.spec.js
@@ -1,14 +1,10 @@
/* eslint no-console:0 */
-import expect from 'expect.js';
import React from 'react';
-import ReactDOM from 'react-dom';
-import TestUtils from 'react-dom/test-utils';
import { format } from 'util';
+import { mount } from 'enzyme';
import sinon from 'sinon';
import Uploader from '../index';
-const { Simulate } = TestUtils;
-
function Item(name) {
this.name = name;
this.toString = () => this.name;
@@ -73,7 +69,6 @@ describe('uploader', () => {
return;
}
- let node;
let uploader;
const handlers = {};
@@ -105,83 +100,48 @@ describe('uploader', () => {
},
};
- beforeEach(done => {
- node = document.createElement('div');
- document.body.appendChild(node);
-
- ReactDOM.render(, node, function init() {
- uploader = this;
- done();
- });
+ beforeEach(() => {
+ uploader = mount();
});
afterEach(() => {
- ReactDOM.unmountComponentAtNode(node);
+ uploader.unmount();
});
- it('with id', done => {
- ReactDOM.render(, node, function init() {
- expect(TestUtils.findRenderedDOMComponentWithTag(this, 'input').id).to.be('bamboo');
- done();
- });
+ it('with id', () => {
+ const wrapper = mount();
+ expect(wrapper.find('input').props().id).toBe('bamboo');
});
- it('should pass through data attributes', done => {
- ReactDOM.render(
- (
-
- ),
- node,
- function init() {
- expect(TestUtils.findRenderedDOMComponentWithTag(this, 'input')
- .getAttribute('data-testid'))
- .to.be('data-testid');
- expect(TestUtils.findRenderedDOMComponentWithTag(this, 'input')
- .getAttribute('data-my-custom-attr'))
- .to.be('custom data attribute');
- done();
- }
+ it('should pass through data & aria attributes', () => {
+ const wrapper = mount(
+ ,
);
+ expect(wrapper.find('input').props()['data-testid']).toBe('data-testid');
+ expect(wrapper.find('input').props()['data-my-custom-attr']).toBe('custom data attribute');
+ expect(wrapper.find('input').props()['aria-label']).toBe('Upload a file');
});
- it('should pass through aria attributes', done => {
- ReactDOM.render(, node, function init() {
- expect(TestUtils.findRenderedDOMComponentWithTag(this, 'input')
- .getAttribute('aria-label'))
- .to.be('Upload a file');
- done();
- });
+ it('should pass through role attributes', () => {
+ const wrapper = mount();
+ expect(wrapper.find('input').props().role).toBe('button');
});
- it('should pass through role attributes', done => {
- ReactDOM.render(, node, function init() {
- expect(TestUtils.findRenderedDOMComponentWithTag(this, 'input')
- .getAttribute('role'))
- .to.be('button');
- done();
- });
- });
-
- it('should not pass through unknown props', done => {
- ReactDOM.render(,
- node,
- () => {
- // Fails when React reports unrecognized prop is added to DOM in console.error
- done();
- }
- );
+ it('should not pass through unknown props', () => {
+ const wrapper = mount();
+ expect(wrapper.find('input').props().customProp).toBeUndefined();
});
it('create works', () => {
- expect(TestUtils.scryRenderedDOMComponentsWithTag(uploader, 'span').length).to.be(1);
+ expect(uploader.find('span').length).toBeTruthy();
});
it('upload success', done => {
- const input = TestUtils.findRenderedDOMComponentWithTag(uploader, 'input');
-
+ const input = uploader.find('input').first();
const files = [
{
name: 'success.png',
@@ -193,24 +153,22 @@ describe('uploader', () => {
files.item = i => files[i];
handlers.onSuccess = (ret, file) => {
- expect(ret[1]).to.eql(file.name);
- expect(file).to.have.property('uid');
+ expect(ret[1]).toEqual(file.name);
+ expect(file).toHaveProperty('uid');
done();
};
handlers.onError = err => {
done(err);
};
-
- Simulate.change(input, { target: { files } });
-
+ input.simulate('change', { target: { files } });
setTimeout(() => {
requests[0].respond(200, {}, `["","${files[0].name}"]`);
}, 100);
});
it('upload error', done => {
- const input = TestUtils.findRenderedDOMComponentWithTag(uploader, 'input');
+ const input = uploader.find('input').first();
const files = [
{
@@ -223,20 +181,20 @@ describe('uploader', () => {
files.item = i => files[i];
handlers.onError = (err, ret) => {
- expect(err instanceof Error).to.equal(true);
- expect(err.status).to.equal(400);
- expect(ret).to.equal('error 400');
+ expect(err instanceof Error).toEqual(true);
+ expect(err.status).toEqual(400);
+ expect(ret).toEqual('error 400');
done();
};
- Simulate.change(input, { target: { files } });
+ input.simulate('change', { target: { files } });
setTimeout(() => {
requests[0].respond(400, {}, `error 400`);
}, 100);
});
it('drag to upload', done => {
- const input = TestUtils.findRenderedDOMComponentWithTag(uploader, 'input');
+ const input = uploader.find('input').first();
const files = [
{
@@ -249,8 +207,8 @@ describe('uploader', () => {
files.item = i => files[i];
handlers.onSuccess = (ret, file) => {
- expect(ret[1]).to.eql(file.name);
- expect(file).to.have.property('uid');
+ expect(ret[1]).toEqual(file.name);
+ expect(file).toHaveProperty('uid');
done();
};
@@ -258,7 +216,7 @@ describe('uploader', () => {
done(err);
};
- Simulate.drop(input, { dataTransfer: { files } });
+ input.simulate('drop', { dataTransfer: { files } });
setTimeout(() => {
requests[0].respond(200, {}, `["","${files[0].name}"]`);
@@ -266,7 +224,7 @@ describe('uploader', () => {
});
it('drag unaccepted type files to upload will not trigger onStart', done => {
- const input = TestUtils.findRenderedDOMComponentWithTag(uploader, 'input');
+ const input = uploader.find('input').first();
const files = [
{
name: 'success.jpg',
@@ -276,66 +234,57 @@ describe('uploader', () => {
},
];
files.item = i => files[i];
- Simulate.drop(input, { dataTransfer: { files } });
+ input.simulate('drop', { dataTransfer: { files } });
const mockStart = jest.fn();
handlers.onStart = mockStart;
setTimeout(() => {
- expect(mockStart.mock.calls.length).to.be(0);
+ expect(mockStart.mock.calls.length).toBe(0);
done();
}, 100);
});
it('drag files with multiple false', done => {
- ReactDOM.unmountComponentAtNode(node);
-
- // Create new one
- node = document.createElement('div');
- document.body.appendChild(node);
-
- ReactDOM.render(, node, function init() {
- uploader = this;
-
- const input = TestUtils.findRenderedDOMComponentWithTag(uploader, 'input');
+ const wrapper = mount();
+ const input = wrapper.find('input').first();
- const files = [
- {
- name: 'success.png',
- toString() {
- return this.name;
- },
+ const files = [
+ {
+ name: 'success.png',
+ toString() {
+ return this.name;
},
- {
- name: 'filtered.png',
- toString() {
- return this.name;
- },
+ },
+ {
+ name: 'filtered.png',
+ toString() {
+ return this.name;
},
- ];
- files.item = i => files[i];
-
- // Only can trigger once
- let triggerTimes = 0;
- handlers.onStart = () => {
- triggerTimes += 1;
- };
-
- handlers.onSuccess = (ret, file) => {
- expect(ret[1]).to.eql(file.name);
- expect(file).to.have.property('uid');
- expect(triggerTimes).to.eql(1);
- done();
- };
+ },
+ ];
+ files.item = i => files[i];
+
+ // Only can trigger once
+ let triggerTimes = 0;
+ handlers.onStart = () => {
+ triggerTimes += 1;
+ };
+
+ handlers.onSuccess = (ret, file) => {
+ expect(ret[1]).toEqual(file.name);
+ expect(file).toHaveProperty('uid');
+ expect(triggerTimes).toEqual(1);
+ done();
+ };
- handlers.onError = err => {
- done(err);
- };
+ handlers.onError = err => {
+ done(err);
+ };
- Simulate.drop(input, { dataTransfer: { files } });
+ input.simulate('drop', { dataTransfer: { files } });
- setTimeout(() => {
- requests[0].respond(200, {}, `["","${files[0].name}"]`);
- }, 100);
- });
+ setTimeout(() => {
+ requests[0].respond(200, {}, `["","${files[0].name}"]`);
+ }, 100);
});
it('support action and data is function returns Promise', done => {
@@ -353,30 +302,29 @@ describe('uploader', () => {
}, 1000);
});
};
- ReactDOM.render(, node, function init() {
- uploader = this;
- const input = TestUtils.findRenderedDOMComponentWithTag(uploader, 'input');
- const files = [
- {
- name: 'success.png',
- toString() {
- return this.name;
- },
+ const wrapper = mount();
+ const input = wrapper.find('input').first();
+
+ const files = [
+ {
+ name: 'success.png',
+ toString() {
+ return this.name;
},
- ];
- files.item = i => files[i];
- Simulate.change(input, { target: { files } });
+ },
+ ];
+ files.item = i => files[i];
+ input.simulate('change', { target: { files } });
+ setTimeout(() => {
+ expect(requests.length).toBe(0);
setTimeout(() => {
- expect(requests.length).to.be(0);
- setTimeout(() => {
- console.log(requests);
- expect(requests.length).to.be(1);
- expect(requests[0].url).to.be('/upload.do');
- expect(requests[0].requestBody.get('field1')).to.be('a');
- done();
- }, 2000);
- }, 100);
- });
+ console.log(requests);
+ expect(requests.length).toBe(1);
+ expect(requests[0].url).toBe('/upload.do');
+ expect(requests[0].requestBody.get('field1')).toBe('a');
+ done();
+ }, 2000);
+ }, 100);
});
});
@@ -385,7 +333,6 @@ describe('uploader', () => {
return;
}
- let node;
let uploader;
const handlers = {};
@@ -417,18 +364,12 @@ describe('uploader', () => {
},
};
- beforeEach(done => {
- node = document.createElement('div');
- document.body.appendChild(node);
-
- ReactDOM.render(, node, function init() {
- uploader = this;
- done();
- });
+ beforeEach(() => {
+ uploader = mount();
});
it('unaccepted type files to upload will not trigger onStart', done => {
- const input = TestUtils.findRenderedDOMComponentWithTag(uploader, 'input');
+ const input = uploader.find('input').first();
const files = {
name: 'foo',
children: [
@@ -442,78 +383,70 @@ describe('uploader', () => {
},
],
};
- Simulate.drop(input, { dataTransfer: { items: [makeDataTransferItem(files)] } });
+ input.simulate('drop', { dataTransfer: { items: [makeDataTransferItem(files)] } });
const mockStart = jest.fn();
handlers.onStart = mockStart;
setTimeout(() => {
- expect(mockStart.mock.calls.length).to.be(0);
+ expect(mockStart.mock.calls.length).toBe(0);
done();
}, 100);
});
});
describe('transform file before request', () => {
- let node;
let uploader;
- beforeEach(done => {
- node = document.createElement('div');
- document.body.appendChild(node);
-
- ReactDOM.render(, node, function init() {
- uploader = this;
- done();
- });
+ beforeEach(() => {
+ uploader = mount();
});
afterEach(() => {
- ReactDOM.unmountComponentAtNode(node);
+ uploader.unmount();
});
it('transform file function should be called before data function', done => {
const props = {
action: '/test',
- data (file) {
- return new Promise((resolve) => {
+ data(file) {
+ return new Promise(resolve => {
setTimeout(() => {
resolve({
- url: file.url
- })
- }, 500)
- })
+ url: file.url,
+ });
+ }, 500);
+ });
},
- transformFile (file) {
- return new Promise((resolve) => {
+ transformFile(file) {
+ return new Promise(resolve => {
setTimeout(() => {
+ // eslint-disable-next-line no-param-reassign
file.url = 'this is file url';
resolve(file);
}, 500);
});
},
};
- ReactDOM.render(, node, function init() {
- uploader = this;
- const input = TestUtils.findRenderedDOMComponentWithTag(uploader, 'input');
+ const wrapper = mount();
+ const input = wrapper.find('input').first();
- const files = [
- {
- name: 'success.png',
- toString() {
- return this.name;
- },
+ const files = [
+ {
+ name: 'success.png',
+ toString() {
+ return this.name;
},
- ];
+ },
+ ];
- files.item = i => files[i];
+ files.item = i => files[i];
- Simulate.change(input, { target: { files } });
+ input.simulate('change', { target: { files } });
+ setTimeout(() => {
setTimeout(() => {
- setTimeout(() => {
- expect(requests[0].requestBody.get('url')).to.be('this is file url');
- done();
- }, 1000);
- }, 100);
- });
+ expect(requests[0].requestBody.get('url')).toBe('this is file url');
+ done();
+ }, 1000);
+ }, 100);
});
it('noes not affect receive origin file when transform file is null', done => {
@@ -529,33 +462,31 @@ describe('uploader', () => {
return null;
},
};
- ReactDOM.render(, node, function init() {
- uploader = this;
- const input = TestUtils.findRenderedDOMComponentWithTag(uploader, 'input');
+ const wrapper = mount();
+ const input = wrapper.find('input').first();
- const files = [
- {
- name: 'success.png',
- toString() {
- return this.name;
- },
+ const files = [
+ {
+ name: 'success.png',
+ toString() {
+ return this.name;
},
- ];
+ },
+ ];
- files.item = i => files[i];
+ files.item = i => files[i];
- handlers.onSuccess = (ret, file) => {
- expect(ret[1]).to.eql(file.name);
- expect(file).to.have.property('uid');
- done();
- };
+ handlers.onSuccess = (ret, file) => {
+ expect(ret[1]).toEqual(file.name);
+ expect(file).toHaveProperty('uid');
+ done();
+ };
- Simulate.change(input, { target: { files } });
+ input.simulate('change', { target: { files } });
- setTimeout(() => {
- requests[0].respond(200, {}, `["","${files[0].name}"]`);
- }, 100);
- });
+ setTimeout(() => {
+ requests[0].respond(200, {}, `["","${files[0].name}"]`);
+ }, 100);
});
});
});