فهرست منبع

Test: add some test cases (#11485)

hetech 7 سال پیش
والد
کامیت
7df9a1e38c

+ 0 - 167
packages/upload/src/iframe-upload.vue

@@ -1,167 +0,0 @@
-<script>
-import UploadDragger from './upload-dragger.vue';
-
-export default {
-  components: {
-    UploadDragger
-  },
-  props: {
-    type: String,
-    data: {},
-    action: {
-      type: String,
-      required: true
-    },
-    name: {
-      type: String,
-      default: 'file'
-    },
-    withCredentials: Boolean,
-    accept: String,
-    onStart: Function,
-    onProgress: Function,
-    onSuccess: Function,
-    onError: Function,
-    beforeUpload: Function,
-    onPreview: {
-      type: Function,
-      default: function() {}
-    },
-    onRemove: {
-      type: Function,
-      default: function() {}
-    },
-    drag: Boolean,
-    listType: String,
-    disabled: Boolean,
-    limit: Number,
-    onExceed: Function
-  },
-
-  data() {
-    return {
-      mouseover: false,
-      domain: '',
-      file: null,
-      submitting: false
-    };
-  },
-
-  methods: {
-    isImage(str) {
-      return str.indexOf('image') !== -1;
-    },
-    handleClick() {
-      if (!this.disabled) {
-        this.$refs.input.click();
-      }
-    },
-    handleChange(ev) {
-      const file = ev.target.value;
-      if (file) {
-        this.uploadFiles(file);
-      }
-    },
-    uploadFiles(file) {
-      if (this.limit && this.$parent.uploadFiles.length + file.length > this.limit) {
-        this.onExceed && this.onExceed(this.fileList);
-        return;
-      }
-
-      if (this.submitting) return;
-      this.submitting = true;
-      this.file = file;
-      this.onStart(file);
-
-      const formNode = this.getFormNode();
-      const dataSpan = this.getFormDataNode();
-      let data = this.data;
-      if (typeof data === 'function') {
-        data = data(file);
-      }
-      const inputs = [];
-      for (const key in data) {
-        if (data.hasOwnProperty(key)) {
-          inputs.push(`<input name="${key}" value="${data[key]}"/>`);
-        }
-      }
-      dataSpan.innerHTML = inputs.join('');
-      formNode.submit();
-      dataSpan.innerHTML = '';
-    },
-    getFormNode() {
-      return this.$refs.form;
-    },
-    getFormDataNode() {
-      return this.$refs.data;
-    }
-  },
-
-  created() {
-    this.frameName = 'frame-' + Date.now();
-  },
-
-  mounted() {
-    const self = this;
-    !this.$isServer && window.addEventListener('message', (event) => {
-      if (!self.file) return;
-      const targetOrigin = new URL(self.action).origin;
-      if (event.origin !== targetOrigin) return;
-      const response = event.data;
-      if (response.result === 'success') {
-        self.onSuccess(response, self.file);
-      } else if (response.result === 'failed') {
-        self.onError(response, self.file);
-      }
-      self.submitting = false;
-      self.file = null;
-    }, false);
-  },
-
-  render(h) {
-    const {
-      drag,
-      uploadFiles,
-      listType,
-      frameName,
-      disabled
-    } = this;
-    const oClass = { 'el-upload': true };
-    oClass[`el-upload--${listType}`] = true;
-
-    return (
-      <div
-        class={oClass}
-        on-click={this.handleClick}
-        nativeOn-drop={this.onDrop}
-        nativeOn-dragover={this.handleDragover}
-        nativeOn-dragleave={this.handleDragleave}
-      >
-        <iframe
-          on-load={this.onload}
-          ref="iframe"
-          name={frameName}
-        >
-        </iframe>
-        <form ref="form" action={this.action} target={frameName} enctype="multipart/form-data" method="POST">
-          <input
-            class="el-upload__input"
-            type="file"
-            ref="input"
-            name="file"
-            on-change={this.handleChange}
-            accept={this.accept}>
-          </input>
-          <input type="hidden" name="documentDomain" value={ this.$isServer ? '' : document.domain } />
-          <span ref="data"></span>
-        </form>
-        {
-          drag
-            ? <upload-dragger on-file={uploadFiles} disabled={disabled}>{this.$slots.default}</upload-dragger>
-            : this.$slots.default
-        }
-      </div>
-    );
-  }
-};
-</script>

+ 2 - 6
packages/upload/src/index.vue

@@ -1,7 +1,6 @@
 <script>
 import UploadList from './upload-list';
 import Upload from './upload';
-import IframeUpload from './iframe-upload';
 import ElProgress from 'element-ui/packages/progress';
 import Migrating from 'element-ui/src/mixins/migrating';
 
@@ -15,8 +14,7 @@ export default {
   components: {
     ElProgress,
     UploadList,
-    Upload,
-    IframeUpload
+    Upload
   },
 
   provide() {
@@ -288,9 +286,7 @@ export default {
     };
 
     const trigger = this.$slots.trigger || this.$slots.default;
-    const uploadComponent = (typeof FormData !== 'undefined' || this.$isServer)
-      ? <upload {...uploadData}>{trigger}</upload>
-      : <iframeUpload {...uploadData}>{trigger}</iframeUpload>;
+    const uploadComponent = <upload {...uploadData}>{trigger}</upload>;
 
     return (
       <div>

+ 137 - 1
test/unit/specs/autocomplete.spec.js

@@ -1,4 +1,4 @@
-import { createVue, triggerClick, destroyVM } from '../util';
+import { createVue, triggerClick, destroyVM, triggerKeyDown } from '../util';
 
 describe('Autocomplete', () => {
   let vm;
@@ -127,6 +127,142 @@ describe('Autocomplete', () => {
       }, 500);
     }, 500);
   });
+  it('input', done => {
+    vm = createVue({
+      template: `
+        <el-autocomplete
+          ref="autocomplete"
+          v-model="state"
+          :trigger-on-focus="false"
+          :fetch-suggestions="querySearch"
+        ></el-autocomplete>
+      `,
+      data() {
+        return {
+          restaurants: [],
+          state: ''
+        };
+      },
+      methods: {
+        querySearch(queryString, cb) {
+          var restaurants = this.restaurants;
+          var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
+          cb(results);
+        },
+        createFilter(queryString) {
+          return (restaurant) => {
+            return (restaurant.value.indexOf(queryString.toLowerCase()) === 0);
+          };
+        },
+        loadAll() {
+          return [
+            { 'value': '三全鲜食(北新泾店)', 'address': '长宁区新渔路144号' },
+            { 'value': 'Hot honey 首尔炸鸡(仙霞路)', 'address': '上海市长宁区淞虹路661号' },
+            { 'value': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' },
+            { 'value': '泷千家(天山西路店)', 'address': '天山西路438号' }
+          ];
+        }
+      },
+      mounted() {
+        this.restaurants = this.loadAll();
+      }
+    }, true);
+    const autocomplete = vm.$refs.autocomplete;
+    const input = autocomplete.$refs.input;
+    input.$emit('input', '三');
+    setTimeout(() => {
+      expect(vm.state).to.be.equal('三');
+      expect(autocomplete.suggestions[0].value).to.be.equal('三全鲜食(北新泾店)');
+      input.$emit('input', '');
+      setTimeout(() => {
+        expect(vm.state).to.be.equal('');
+        expect(autocomplete.suggestions.length).to.be.equal(0);
+        done();
+      }, 500);
+    }, 500);
+  });
+  describe('enter select', () => {
+    const createVm = (selectWhenUnmatched = false) => {
+      return createVue({
+        template: `
+          <el-autocomplete
+            ref="autocomplete"
+            v-model="state"
+            @select="handleSelect"
+            :trigger-on-focus="false"
+            :select-when-unmatched="selectWhenUnmatched"
+            :fetch-suggestions="querySearch"
+          ></el-autocomplete>
+        `,
+        data() {
+          return {
+            restaurants: [],
+            state: '',
+            selectWhenUnmatched: selectWhenUnmatched,
+            item: {}
+          };
+        },
+        methods: {
+          querySearch(queryString, cb) {
+            var restaurants = this.restaurants;
+            var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
+            cb(results);
+          },
+          createFilter(queryString) {
+            return (restaurant) => {
+              return (restaurant.value.indexOf(queryString.toLowerCase()) === 0);
+            };
+          },
+          loadAll() {
+            return [
+              { 'value': '三全鲜食(北新泾店)', 'address': '长宁区新渔路144号' },
+              { 'value': 'Hot honey 首尔炸鸡(仙霞路)', 'address': '上海市长宁区淞虹路661号' },
+              { 'value': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' },
+              { 'value': '泷千家(天山西路店)', 'address': '天山西路438号' }
+            ];
+          },
+          handleSelect(item) {
+            this.item = item;
+          }
+        },
+        mounted() {
+          this.restaurants = this.loadAll();
+        }
+      }, true);
+    };
+    it('select', done => {
+      vm = createVm();
+      const autocomplete = vm.$refs.autocomplete;
+      const input = autocomplete.$refs.input;
+      input.$el.querySelector('input').focus();
+      input.$emit('input', '三');
+      setTimeout(() => {
+        triggerKeyDown(input.$el, 40); // down
+        setTimeout(() => {
+          triggerKeyDown(input.$el, 13); // enter
+          setTimeout(() => {
+            expect(vm.item.address).to.be.equal('长宁区新渔路144号');
+            done();
+          }, 200);
+        }, 200);
+      }, 500);
+    });
+    it('select unmatched', done => {
+      vm = createVm(true);
+      const autocomplete = vm.$refs.autocomplete;
+      const input = autocomplete.$refs.input;
+      input.$emit('input', '关键字');
+      setTimeout(() => {
+        expect(autocomplete.suggestions.length).to.be.equal(0);
+        triggerKeyDown(input.$el, 13); // enter
+        setTimeout(() => {
+          expect(autocomplete.highlightedIndex).to.be.equal(-1);
+          expect(vm.item.value).to.be.equal('关键字');
+          done();
+        }, 500);
+      }, 500);
+    });
+  });
   it('props', done => {
     vm = createVue({
       template: `

+ 5 - 12
test/unit/specs/dropdown.spec.js

@@ -1,11 +1,4 @@
-import { createVue, triggerEvent, destroyVM } from '../util';
-
-const keyDown = (el, keyCode) => {
-  const evt = document.createEvent('Events');
-  evt.initEvent('keydown', true, true);
-  evt.keyCode = keyCode;
-  el.dispatchEvent(evt);
-};
+import { createVue, triggerEvent, destroyVM, triggerKeyDown } from '../util';
 
 describe('Dropdown', () => {
   let vm;
@@ -209,10 +202,10 @@ describe('Dropdown', () => {
     let dropdown = vm.$refs.dropdown;
     let dropdownElm = dropdown.$el;
     let triggerElm = dropdownElm.children[0];
-    keyDown(triggerElm, 13); // enter
+    triggerKeyDown(triggerElm, 13); // enter
     setTimeout(() => {
       expect(dropdown.visible).to.be.true;
-      keyDown(triggerElm, 27); // esc
+      triggerKeyDown(triggerElm, 27); // esc
       setTimeout(() => {
         expect(dropdown.visible).to.be.false;
         done();
@@ -245,9 +238,9 @@ describe('Dropdown', () => {
 
     setTimeout(() => {
       expect(dropdown.visible).to.be.true;
-      keyDown(dropdownMenu, 40); // down
+      triggerKeyDown(dropdownMenu, 40); // down
       setTimeout(() => {
-        keyDown(dropdownMenu, 13); // enter
+        triggerKeyDown(dropdownMenu, 13); // enter
         setTimeout(() => {
           expect(dropdown.visible).to.be.false;
           done();

+ 20 - 0
test/unit/specs/tooltip.spec.js

@@ -133,4 +133,24 @@ describe('Tooltip', () => {
       }, 100);
     });
   });
+  it('reference element focus', done => {
+    vm = createVue(`
+    <el-tooltip ref="tooltip" content="提示文字">
+      <button>click</button>
+    </el-tooltip>`);
+    const tooltip = vm.$refs.tooltip;
+    vm.$nextTick(_ => {
+      triggerEvent(tooltip.$el, 'focus');
+      setTimeout(() => {
+        expect(tooltip.showPopper).to.be.true;
+        expect(tooltip.focusing).to.be.true;
+        triggerEvent(tooltip.$el, 'blur');
+        setTimeout(() => {
+          expect(tooltip.showPopper).to.be.false;
+          expect(tooltip.focusing).to.be.false;
+          done();
+        }, 300);
+      }, 100);
+    });
+  });
 });

+ 61 - 3
test/unit/specs/upload.spec.js

@@ -74,9 +74,6 @@ describe('Upload', () => {
   });
 
   describe('ajax upload', () => {
-    if (typeof FormData === 'undefined') {
-      return;
-    }
 
     let uploader;
     let handlers = {};
@@ -104,6 +101,20 @@ describe('Upload', () => {
           if (handlers.onExceed) {
             handlers.onExceed(files, fileList);
           }
+        },
+        beforeUpload(file) {
+          if (handlers.beforeUpload) {
+            return handlers.beforeUpload(file);
+          } else {
+            return true;
+          }
+        },
+        beforeRemove(file, fileList) {
+          if (handlers.beforeRemove) {
+            return handlers.beforeRemove(file);
+          } else {
+            return true;
+          }
         }
       }
     };
@@ -231,7 +242,54 @@ describe('Upload', () => {
         requests[0].respond(200, {}, `${files[0].name}`);
       }, 100);
     });
+    it('beforeUpload return promise', done => {
+      const spy = sinon.spy();
+      const file = new Blob([JSON.stringify({}, null, 2)], {
+        type: 'application/json'
+      });
+      const files = [file];
+      handlers.onSuccess = () => {
+        expect(spy.calledOnce).to.equal(true);
+        done();
+      };
+      handlers.beforeUpload = (file) => {
+        return new window.Promise((resolve) => {
+          spy();
+          resolve(file);
+        });
+      };
+      uploader.$refs['upload-inner'].handleChange({ target: { files }});
+      setTimeout(() => {
+        requests[0].respond(200, {}, `${files[0].name}`);
+      }, 100);
+    });
+    it('beforeRemove return rejected promise', done => {
+      const spy = sinon.spy();
+      handlers.beforeRemove = (file) => {
+        return new window.Promise((resolve, reject) => {
+          spy();
+          reject();
+        });
+      };
+      const file = new Blob([JSON.stringify({}, null, 2)], {
+        type: 'application/json'
+      });
+      file.name = 'success.png';
+      const files = [file];
 
+      handlers.onSuccess = (res, file, fileList) => {
+        uploader.$el.querySelector('.el-upload-list .el-icon-close').click();
+        setTimeout(() => {
+          expect(spy.calledOnce).to.equal(true);
+          expect(uploader.uploadFiles.length).to.equal(1);
+          done();
+        }, 200);
+      };
+      uploader.$refs['upload-inner'].handleChange({ target: { files }});
+      setTimeout(() => {
+        requests[0].respond(200, {}, `${files[0].name}`);
+      }, 100);
+    });
     it('limit files', done => {
       const files = [{
         name: 'exceed2.png',

+ 12 - 0
test/unit/util.js

@@ -94,3 +94,15 @@ exports.triggerClick = function(elm, ...opts) {
 
   return elm;
 };
+
+/**
+ * 触发 keydown 事件
+ * @param {Element} elm
+ * @param {keyCode} int
+ */
+exports.triggerKeyDown = function(el, keyCode) {
+  const evt = document.createEvent('Events');
+  evt.initEvent('keydown', true, true);
+  evt.keyCode = keyCode;
+  el.dispatchEvent(evt);
+};