Browse Source

test: add cypress test to tabs,anchor,overflowList,etc (#787)

YannLynn 3 years ago
parent
commit
6d1c15a47c
32 changed files with 929 additions and 24 deletions
  1. 44 0
      cypress/integration/anchor.spec.js
  2. 47 0
      cypress/integration/autoComplete.spec.js
  3. 68 0
      cypress/integration/cascader.spec.js
  4. 19 0
      cypress/integration/datePicker.spec.js
  5. 24 0
      cypress/integration/overflowList.spec.js
  6. 26 0
      cypress/integration/scrollList.spec.js
  7. 22 0
      cypress/integration/table.spec.js
  8. 39 0
      cypress/integration/tabs.spec.js
  9. 50 0
      cypress/integration/timePicker.spec.js
  10. 38 0
      cypress/integration/tooltip.spec.js
  11. 27 0
      cypress/integration/treeSelect.spec.js
  12. 26 0
      cypress/integration/typography.spec.js
  13. 21 0
      cypress/integration/upload.spec.js
  14. 1 0
      packages/semi-ui/anchor/__test__/anchor.test.js
  15. 23 1
      packages/semi-ui/anchor/_story/anchor.stories.js
  16. 17 2
      packages/semi-ui/cascader/_story/cascader.stories.js
  17. 1 1
      packages/semi-ui/cascader/index.tsx
  18. 37 0
      packages/semi-ui/datePicker/_story/datePicker.stories.js
  19. 12 3
      packages/semi-ui/input/__test__/input.test.js
  20. 53 0
      packages/semi-ui/input/__test__/textArea.test.js
  21. 44 0
      packages/semi-ui/overflowList/_story/overflowList.stories.js
  22. 72 0
      packages/semi-ui/scrollList/_story/SingleWheelList/index.js
  23. 7 0
      packages/semi-ui/scrollList/_story/scrolllist.stories.js
  24. 3 0
      packages/semi-ui/scrollList/scrollItem.tsx
  25. 1 0
      packages/semi-ui/table/__test__/table.test.js
  26. 2 0
      packages/semi-ui/tabs/TabPane.tsx
  27. 72 0
      packages/semi-ui/tabs/_story/tabs.stories.js
  28. 1 0
      packages/semi-ui/tabs/index.tsx
  29. 127 15
      packages/semi-ui/tooltip/_story/tooltip.stories.js
  30. 1 0
      packages/semi-ui/typography/__test__/typography.test.js
  31. 2 0
      packages/semi-ui/upload/__test__/upload.test.js
  32. 2 2
      packages/semi-ui/upload/_story/upload.stories.js

+ 44 - 0
cypress/integration/anchor.spec.js

@@ -0,0 +1,44 @@
+describe('anchor', () => {
+    it('show tooltip', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=anchor--show-tooltip&args=&viewMode=story');
+        cy.get('.semi-anchor-link').contains('工具提示是一个有用的工具').trigger('mouseover');
+        cy.get('.semi-portal').contains('工具提示是一个有用的工具');
+        cy.get('.semi-anchor-link').eq(9).contains('工具提示是一个有用的工具').trigger('mouseover');
+        cy.get('.semi-portal div[x-placement="right"]').contains('工具提示是一个有用的工具');
+    });
+
+    it('key press', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=anchor--style-position&args=&viewMode=story');
+        cy.get('.semi-anchor-link').contains('contact').type('{upArrow}').type('{enter}');
+        cy.get('h1').contains('Contact me').click();
+    });
+
+    it('scroll', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=anchor--target-offset&args=&viewMode=story');
+        cy.get('#box').scrollTo('bottom');
+        cy.get('.semi-anchor-link-title-active').contains('doc1');
+        cy.wait(500);
+        cy.get('#box').scrollTo('top');
+        cy.get('h1').contains('whatever').click();
+    });
+
+    it('click', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=anchor--target-offset&args=&viewMode=story');
+        cy.get('.semi-anchor-link').contains('api too much').click();
+        cy.get('#api').contains('API').click();
+    });
+
+    it('auto collapse', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=anchor--auto-collapse&args=&viewMode=story');
+        cy.get('.semi-anchor-link').contains('组件').should('have.length', 0);
+        cy.get('.semi-anchor-link').contains('动态展示').click();
+        cy.get('.semi-anchor-link').contains('组件').should('have.length', 1);
+        cy.get('.semi-anchor-link').contains('设计语言').click();
+        cy.get('.semi-anchor-link').contains('组件').should('have.length', 0);
+    });
+
+    it('update href', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=anchor--auto-collapse&args=&viewMode=story');
+        cy.get('#root').contains('setHref').click();
+    });
+});

+ 47 - 0
cypress/integration/autoComplete.spec.js

@@ -0,0 +1,47 @@
+describe('autoComplete', () => {
+
+    it('key press', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=autocomplete--basic-usage&args=&viewMode=story');
+
+        // test downArrow and upArrow
+        cy.get('input').type('123');
+        cy.get('input').type('{downArrow}');
+        cy.get('input').type('{downArrow}');
+        cy.get('input').type('{downArrow}');
+        cy.get('input').type('{downArrow}');
+        cy.get('input').type('{upArrow}');
+        cy.get('input').type('{esc}');
+        cy.get('input').should('have.value', '123');
+
+        // test downArrow when panel hidden
+        cy.get('input').type('{downArrow}');
+        cy.get('input').type('{downArrow}');
+        cy.get('input').type('{enter}');
+        cy.get('input').should('have.value', '123');
+
+        cy.get('input').trigger('mouseover');
+        cy.get('.semi-input-clearbtn').click();
+        cy.wait(100);
+        cy.get('#root').click('right');
+        cy.get('input').should('have.value', '');
+
+        // test enter
+        cy.get('input').click();
+        cy.get('input').type('456');
+        cy.get('input').type('{downArrow}');
+        cy.get('input').type('{enter}');
+        cy.get('#root').click('right');
+        cy.get('input').should('have.value', '[email protected]');
+    });
+
+    it('mouse over option ', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=autocomplete--basic-usage&args=&viewMode=story');
+        cy.get('input').type('123');
+        cy.get('.semi-portal').contains('[email protected]').trigger('mouseover');
+        cy.get('input').type('{downArrow}');
+        cy.get('input').type('{enter}');
+        cy.get('input').should('have.value', '[email protected]');
+
+    });
+
+});

+ 68 - 0
cypress/integration/cascader.spec.js

@@ -0,0 +1,68 @@
+describe('cascader', () => {
+    it('clear when single choose', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--show-clear&args=&viewMode=story');
+        cy.viewport(1500, 1000);
+        cy.get('input').eq(0).click();
+        cy.get('span').contains('Node1').click();
+        cy.get('span').contains('Child Node2').click();
+        cy.get('input').should('have.value', 'Node1 / Child Node2');
+        cy.get('input').eq(0).trigger('mouseover');
+        cy.get('.semi-cascader-clearbtn').click();
+        cy.get('input').should('have.value', '');
+    });
+
+    it('clear by key press', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--show-clear&args=&viewMode=story');
+        cy.viewport(1500, 1000);
+
+        cy.get('input').eq(0).click();
+        cy.get('span').contains('Node1').click();
+        cy.get('span').contains('Child Node2').click();
+        cy.get('input').should('have.value', 'Node1 / Child Node2');
+        cy.get('input').eq(0).trigger('mouseover');
+        cy.get(".semi-cascader-clearbtn").focus();
+        cy.get('.semi-cascader-clearbtn').type('{enter}');
+        cy.get('input').should('have.value', '');
+        cy.get('#root').click('right');
+
+        cy.get('.semi-cascader').eq(1).click();
+        cy.get('.semi-checkbox').eq(0).click();
+        cy.get('.semi-checkbox').eq(1).click();
+        cy.get('.semi-cascader-selection-multiple').contains('Node1');
+        cy.get('.semi-cascader-selection-multiple').contains('Node2');
+        cy.get('.semi-cascader-selection').eq(1).click();
+        cy.get(".semi-cascader-clearbtn").focus();
+        cy.get('.semi-cascader-clearbtn').type('{enter}');
+        cy.get('.semi-cascader-selection .semi-tag').should('not.exist');
+    });
+
+    it('scroll', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--super-long-list&args=&viewMode=story');
+        cy.viewport(1000, 1000);
+        cy.get('.semi-cascader').eq(0).click();
+        cy.get('.semi-cascader-option-list').scrollTo('bottom');
+    });
+
+    it('multiple close', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--cascader&args=&viewMode=story');
+        cy.get('.semi-cascader').eq(1).click();
+        cy.get('.semi-checkbox').eq(0).click();
+        cy.get('.semi-cascader-selection .semi-tag').should('exist');
+        cy.get('.semi-tag-close').click();
+        cy.get('.semi-cascader-selection .semi-tag').should('not.exist');
+    });
+
+    it('placeholder change', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--dynamic-placeholder&args=&viewMode=story');
+        cy.get('.semi-cascader-selection-placeholder').contains('Please select');
+        cy.get('.semi-button-content').contains('Toggle').click();
+        cy.get('.semi-input-default').should('have.attr', 'placeholder', 'Search something');
+    });
+
+    it('placeholder change', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=cascader--dynamic-placeholder&args=&viewMode=story');
+        cy.get('.semi-cascader-selection-placeholder').contains('Please select');
+        cy.get('.semi-button-content').contains('Toggle').click();
+        cy.get('.semi-input-default').should('have.attr', 'placeholder', 'Search something');
+    });
+});

+ 19 - 0
cypress/integration/datePicker.spec.js

@@ -283,4 +283,23 @@ describe('DatePicker', () => {
         cy.get('[x-type=dateTime] .semi-datepicker-switch-text').first().contains('1910-01-01');
         cy.get('[x-type=dateTime] .semi-datepicker-switch-text').last().contains('13:00:00');
     });
+
+    it('input complete', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--a-11-y-keyboard-demo&args=&viewMode=story');
+        cy.get('[data-cy=date] .semi-input-default').type('2022-10-10');
+        cy.get('[data-cy=date] .semi-input-default').trigger('mouseover');
+        cy.get('[data-cy=date] .semi-input-clearbtn').click();
+        cy.get('[data-cy=date] .semi-input-default').should('have.value', '');
+
+        cy.get('[data-cy=date] .semi-input-default').type('2022-10-10,2022-10-11');
+        cy.get('[data-cy=date] .semi-input-default').should('have.value', '2022-10-10,2022-10-11');
+
+        cy.get('[data-cy=dateRange] .semi-datepicker-range-input-wrapper-start').clear();
+        cy.get('[data-cy=dateRange] .semi-datepicker-range-input-wrapper-start').type('2022-07-10');
+        cy.get('[data-cy=dateRange] .semi-datepicker-range-input-wrapper-end').clear();
+        cy.get('[data-cy=dateRange] .semi-datepicker-range-input-wrapper-end').type('2022-10-11');
+        cy.get('[data-cy=dateRange] .semi-datepicker-range-input-wrapper-end').type('{enter}');
+        cy.get('[data-cy=dateRange] .semi-datepicker-range-input-wrapper-start .semi-input').should('have.value', '2022-07-10');
+        cy.get('[data-cy=dateRange] .semi-datepicker-range-input-wrapper-end .semi-input').should('have.value', '2022-10-11');
+    });
 });

+ 24 - 0
cypress/integration/overflowList.spec.js

@@ -0,0 +1,24 @@
+describe('overflowList', () => {
+    it('intersect', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=overflowlist--overlap-overflow-list&args=&viewMode=story');
+        cy.viewport(500, 500);
+        cy.get('.semi-tag').eq(0).contains('0');
+        cy.get('.semi-tag').eq(1).contains('3');
+        cy.get('.semi-overflow-list-scroll-wrapper').scrollTo('right');
+        cy.get('.semi-tag').eq(0).contains('4');
+    });
+
+    it('resize', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=overflowlist--overflow-list-with-slide&args=&viewMode=story');
+        cy.get('.semi-slider-handle')
+            .trigger('mousedown', { which: 1, pageX: 600, pageY: 100 })
+            .trigger('mousemove', { which: 1, pageX: -600, pageY: 100 })
+            .trigger('mouseup');
+        cy.get('.semi-tag').contains('+6');
+        cy.get('.semi-slider-handle')
+            .trigger('mousedown', { which: 1, pageX: -300, pageY: 100 })
+            .trigger('mousemove', { which: 1, pageX: 100, pageY: 100 })
+            .trigger('mouseup');
+        cy.get('.semi-tag').contains('+2');
+    });
+});

+ 26 - 0
cypress/integration/scrollList.spec.js

@@ -0,0 +1,26 @@
+describe('scrollList', () => {
+    it('scroll to the specified position after clicking', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=scrolllist--scroll-list-simple&args=&viewMode=story');
+        cy.get('.semi-scrolllist-item-sel').contains('1');
+        cy.get('.semi-scrolllist-item').contains('5').click();
+        cy.get('.semi-scrolllist-item-sel').contains('5');
+    });
+
+    it('infinite scroll', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=scrolllist--single-scroll-list&args=&viewMode=story');
+        cy.wait(500);
+        cy.get('li[aria-selected="true"]').contains(0);
+        cy.get('.semi-scrolllist-item-wheel .semi-scrolllist-list-outer').scrollTo('right', { duration: 2000 });
+        cy.wait(1000);
+        cy.get('.semi-scrolllist-item-wheel .semi-scrolllist-list-outer').scrollTo('top', { duration: 2000 });
+        cy.wait(500);
+        cy.get('.semi-scrolllist-item-wheel .semi-scrolllist-list-outer').scrollTo('bottom', { duration: 2000 });
+    });
+
+    it('click option', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=scrolllist--single-scroll-list&args=&viewMode=story');
+        cy.get('li[aria-selected="true"]').contains(0);
+        cy.get('.semi-scrolllist-list-outer').contains(59).click();
+        cy.get('li[aria-selected="true"]').contains(0);
+    });
+});

+ 22 - 0
cypress/integration/table.spec.js

@@ -45,4 +45,26 @@ describe('table', () => {
         cy.contains("Base Information");
         cy.contains("Company Information");
     });
+
+    it('scroll', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=table--scroll-bar&args=&viewMode=story');
+     
+        cy.get('.semi-table-body').scrollTo('bottom');
+        cy.get('.semi-table-body').scrollTo('top');
+        cy.get('.semi-table-body').scrollTo('left');
+        cy.get('.semi-table-body').scrollTo('right');
+    });
+
+    it('resizable header', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=table--resizable-columns&args=&viewMode=story');
+        
+        cy.get('.react-resizable-handle').eq(0)
+            .trigger('mousedown', { which: 1, pageX: 0, pageY: 100 })
+            .trigger('mousemove', { which: 1, pageX: 600, pageY: 100 })
+            .trigger('mouseup');
+        cy.get('.react-resizable-handle').eq(1)
+            .trigger('mousedown', { which: 1, pageX: 300, pageY: 100 })
+            .trigger('mousemove', { which: 1, pageX: -300, pageY: 100 })
+            .trigger('mouseup');
+    });
 });

+ 39 - 0
cypress/integration/tabs.spec.js

@@ -0,0 +1,39 @@
+describe('tabs', () => {
+    it('activeKey', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=tabs--active-key&args=&viewMode=story');
+
+        cy.get('.semi-tabs').contains('帮助').click();
+        cy.get('.semi-tabs-pane-active').contains('帮助');
+        cy.get('.semi-tabs').contains('关于').click();
+        cy.get('.semi-tabs-pane-active').contains('关于');
+    });
+
+    it('tab list change', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=tabs--tab-list-change&args=&viewMode=story');
+        cy.get('.semi-tabs').contains('帮助').click();
+        cy.get('.semi-tabs-bar').should('have.length', 1);
+    });
+
+    it('current pane render', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=tabs--render-current-pane&args=&viewMode=story');
+        cy.get('.semi-tabs-content').contains('文档');
+        cy.get('.semi-tabs').contains('帮助').click();
+        cy.get('.semi-tabs-content').contains('帮助');
+        cy.get('.semi-tabs').contains('关于').click();
+        cy.get('.semi-tabs-content').contains('关于');
+    });
+
+    it('collapse', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=tabs--collapse-tabs&args=&viewMode=story');
+        cy.viewport(800, 800);
+        cy.get('.semi-tabs-content').eq(0).contains('Content of card tab 0');
+        cy.get('.semi-button').eq(0).trigger('mouseover');
+        cy.get('.semi-dropdown').contains('Tab-6').click();
+        cy.get('.semi-tabs-content').eq(0).contains('Content of card tab 6');
+
+        // Tab-10 visible
+        cy.get('.semi-button').eq(0).click();
+        cy.get('.semi-tabs').contains('Tab-10').click();
+        cy.get('.semi-tabs-content').eq(0).contains('Content of card tab 10');
+    });
+});

+ 50 - 0
cypress/integration/timePicker.spec.js

@@ -0,0 +1,50 @@
+describe('timePicker', () => {
+    it('select', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=timepicker--range-picker&args=&viewMode=story');
+        cy.get('.semi-input').eq(0).click();
+        cy.wait(500);
+        cy.get('.semi-timepicker-panel-list-hour').contains('23').click();
+        cy.get('.semi-timepicker-panel-list-minute').eq(0).contains('59').click();
+        cy.get('.semi-timepicker-panel-list-second').eq(0).contains('59').click();
+        cy.get('.semi-timepicker-panel-list-hour .semi-scrolllist-item-selected').contains('23');
+        // todo: item-selected class ?
+        cy.get('.semi-timepicker-panel-list-minute').contains('59');
+        cy.get('.semi-timepicker-panel-list-second').contains('59');
+
+        cy.get('.semi-input').eq(4).click();
+        cy.wait(500);
+        cy.get('.semi-timepicker-panel-list-ampm').contains('下午').click();
+        cy.get('.semi-timepicker-panel-list-hour').eq(0).contains('09').click();
+        cy.get('.semi-timepicker-panel-list-minute').eq(0).contains('09').click();
+        cy.get('.semi-timepicker-panel-list-ampm .semi-scrolllist-item-sel').contains('下午');
+        cy.get('.semi-timepicker-panel-list-hour .semi-scrolllist-item-sel').contains('09');
+        cy.get('.semi-timepicker-panel-list-minute .semi-scrolllist-item-sel').contains('09');
+
+        cy.get('.semi-timepicker-panel-list-ampm').contains('上午').click();
+        cy.get('.semi-timepicker-panel-list-hour').eq(0).contains('10').click();
+        cy.get('.semi-timepicker-panel-list-minute').eq(0).contains('10').click();
+        cy.get('.semi-timepicker-panel-list-ampm .semi-scrolllist-item-sel').contains('上午');
+        cy.get('.semi-timepicker-panel-list-hour .semi-scrolllist-item-sel').contains('10');
+        cy.get('.semi-timepicker-panel-list-minute .semi-scrolllist-item-sel').contains('10');
+
+    });
+
+    it('clear', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=timepicker--range-picker&args=&viewMode=story');
+        cy.get('.semi-input').eq(0).click();
+        cy.wait(500);
+
+        cy.get('.semi-input').eq(0).trigger('mouseover');
+        cy.get('.semi-input-clearbtn').click();
+        cy.get('.semi-input').eq(0).should('have.value', '');
+    });
+
+    it('custom trigger', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=timepicker--custom-trigger&args=&viewMode=story');
+        cy.get('.semi-button-content').click();
+        cy.wait(500);
+
+        cy.get('.semi-timepicker-panel-list-hour .semi-scrolllist-list-outer').scrollTo('top');
+        cy.get('#root').trigger('mousedown','right');
+    });
+});

+ 38 - 0
cypress/integration/tooltip.spec.js

@@ -28,6 +28,23 @@ describe('tooltip', () => {
         cy.get('[x-placement="rightBottomOver"]').should('have.length', 1);
     });
 
+    it('position with over autoAdjustOverflow', () => {
+        const viewportWidth = 600;
+        const viewportHeight = 400;
+        const overList = ['leftTopOver', 'rightTopOver', 'rightBottomOver', 'leftBottomOver',];
+
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=tooltip--left-top-over-demo&args=&viewMode=story');
+        cy.viewport(viewportWidth, viewportHeight);
+        const dataSelector = `[data-cy=toggleVisible]`;
+        cy.get(dataSelector).click({ force: true });
+        
+        for (let i=0; i<overList.length; i++){
+            const dataSelector = `[data-cy=`+ overList[i] + `]`;
+            cy.get(dataSelector).click({ force: true });
+            cy.get('[x-placement="'+ overList[overList.length - 1 - i] +'"]').should('have.length', 1);
+        }
+    });
+
     it('autoFocusHover', () => {
         cy.visit('http://127.0.0.1:6006/iframe.html?id=tooltip--auto-focus-content-demo&args=&viewMode=story');
         const dataSelector = `[data-cy=hover]`;
@@ -82,4 +99,25 @@ describe('tooltip', () => {
         cy.get(trigger).click({ force: true });
         cy.get(input).should('be.focused');
     });
+
+    it('adjustPosIfNeed', () => {
+        const viewportWidth = 400;
+        const viewportHeight = 200;
+        const topAndLeft = ['topLeft', 'top', 'topRight', 'leftTop', 'left', 'leftBottom'];
+        const bottomAndRight = ['bottomLeft', 'bottom', 'bottomRight', 'rightTop', 'right', 'rightBottom'];
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=tooltip--adjust-pos-if-need&args=&viewMode=story');
+        cy.viewport(viewportWidth, viewportHeight);
+
+        for (let i=0; i<topAndLeft.length; i++){
+            const dataSelector = `[data-cy=`+ topAndLeft[i] + `]`;
+            cy.get(dataSelector).click({ force: true });
+            cy.get('[x-placement="'+ bottomAndRight[i] +'"]').should('have.length', 1);
+        }
+
+        for (let i=bottomAndRight.length-1; i>=0; i--){
+            const dataSelector = `[data-cy=`+ bottomAndRight[i] + `]`;
+            cy.get(dataSelector).click({ force: true });
+            cy.get('[x-placement="'+ topAndLeft[i] +'"]').should('have.length', 1);
+        }
+    });
 });

+ 27 - 0
cypress/integration/treeSelect.spec.js

@@ -0,0 +1,27 @@
+describe('treeSelect', () => {
+    it('clear', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=treeselect--check-relation-demo&args=&viewMode=story');
+        cy.get('.semi-tree-select-selection').eq(8).contains('China');
+        cy.get('.semi-tree-select-selection').eq(8).trigger('mouseover');
+        cy.get('.semi-tree-select-clearbtn').click();
+        cy.get('.semi-tagInput-wrapper .semi-tag').should('not.exist');
+    });
+
+    it('clear by key press', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=treeselect--check-relation-demo&args=&viewMode=story');
+        cy.get('.semi-tree-select-selection').eq(8).contains('China');
+        cy.get('.semi-tree-select-selection').eq(8).trigger('mouseover');
+        cy.get('.semi-tree-select-clearbtn').focus();
+        cy.get('.semi-tree-select-clearbtn').type('{enter}');
+        cy.get('.semi-tagInput-wrapper .semi-tag').should('not.exist');
+    });
+
+    it('clear by key press', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=treeselect--check-relation-demo&args=&viewMode=story');
+        cy.get('.semi-tree-select-selection').eq(8).contains('China');
+        cy.get('.semi-tree-select-selection').eq(8).trigger('mouseover');
+        cy.get('.semi-tree-select-clearbtn').focus();
+        cy.get('.semi-tree-select-clearbtn').type('{enter}');
+        cy.get('.semi-tagInput-wrapper .semi-tag').should('not.exist');
+    });
+});

+ 26 - 0
cypress/integration/typography.spec.js

@@ -0,0 +1,26 @@
+describe('typography', () => {
+    it('ellipsis', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=typography--ellipsis-collapsible&args=&viewMode=story');
+        cy.viewport(500, 500);
+        cy.get('.semi-typography span').eq(0).contains('...');
+        cy.get('.semi-typography-ellipsis-expand').eq(0).contains('展开').click();
+        cy.get('.semi-typography').eq(0).contains('四大优势');
+
+        cy.get('.semi-typography-ellipsis-expand').eq(0).contains('收起').click();
+        cy.get('.semi-typography span').eq(0).contains('...');
+
+    });
+
+    // todo:  The test currently work only in Electron
+    // because the clipboard permission is granted when Cypress starts it.
+    it('copyable', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=typography--copyable&args=&viewMode=story');
+        cy.viewport(800, 1000);
+        cy.get('.semi-typography-action-copy').eq(1).click();
+        cy.get('span').contains('复制成功');
+        // cy.window()
+        //     .its('navigator.clipboard')
+        //     .invoke('点击右边的图标复制文本。');
+    });
+
+});

+ 21 - 0
cypress/integration/upload.spec.js

@@ -0,0 +1,21 @@
+describe('upload', () => {
+    it('drag and drop', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=upload--draggable&args=&viewMode=story');
+
+        cy.get('.semi-upload-drag-area').eq(0).selectFile('README.md', { force: true, action: 'drag-drop' });
+        cy.get('.semi-upload-file-card-info-main-text').contains('README.md');
+
+        // todo: upload file folder by drag and drop
+        // cypress not surpport yet
+    });
+
+    it('limit', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=upload--auto-replace-limit-1&args=&viewMode=story');
+
+        cy.get('input[type=file]').eq(0).selectFile('README.md', { force: true });
+        cy.get('.semi-upload-file-card-info-main-text').contains('README.md');
+        cy.get('input[type=file]').eq(0).selectFile('README.md', { force: true });
+        cy.get('.semi-upload-file-card-info-main-text').contains('README.md');
+    });
+
+});

+ 1 - 0
packages/semi-ui/anchor/__test__/anchor.test.js

@@ -23,6 +23,7 @@ describe('Anchor', () => {
   it('anchor small size', () => {
     const smallAnchor = mount(<Anchor size="small" />);
     expect(smallAnchor.find(`.${BASE_CLASS_PREFIX}-anchor-size-small`)).toHaveLength(1);
+    smallAnchor.unmount();
   });
 
   it('anchor rail theme', () => {

+ 23 - 1
packages/semi-ui/anchor/_story/anchor.stories.js

@@ -1,4 +1,5 @@
-import React from 'react';
+import React, { useState } from 'react';
+import Button from '../../button';
 import { Anchor } from '../../index';
 
 export default {
@@ -264,3 +265,24 @@ export const FixContainerScrollBug1158 = () => (
     </div>
   </div>
 );
+
+export const AutoCollapse = () => {
+  const [href, setHref] = useState('#设计语言');
+  return (
+      <div>
+        <Anchor autoCollapse>
+          <Anchor.Link href="#动态展示" title="1. 动态展示">
+            <Anchor.Link href="#组件" title="1.1 组件">
+                <Anchor.Link href="#头像" title="1.1.1 Avatar" />
+                <Anchor.Link href="#按钮" title="1.1.2 Button" />
+                <Anchor.Link href="#图标" title="1.1.3 Icon" />
+            </Anchor.Link>
+            <Anchor.Link href="#物料" title="1.2 物料" />
+            <Anchor.Link href="#主题商店" title="1.3 主题商店" />
+          </Anchor.Link>
+          <Anchor.Link href={href} title="2. 设计语言" />
+        </Anchor>
+        <Button onClick={()=>{console.log('sdf');setHref('#我改变啦')}}>setHref</Button>
+      </div>
+  )
+};

+ 17 - 2
packages/semi-ui/cascader/_story/cascader.stories.js

@@ -697,7 +697,8 @@ export const ShowClear = () => {
       <Cascader
         style={{ marginLeft: 700, width: 300 }}
         treeData={treeData1}
-        placeholder="Please select"
+        placeholder="Please select when multiple"
+        multiple
         showClear
       />
       <br />
@@ -1434,4 +1435,18 @@ export const DynamicTreeData = () => {
           <br />
       </div>
   );
-}
+}
+
+
+export const SuperLongList = () => {
+    let treeData = new Array(100).fill().map(() => ({ label: '浙江省', value: 'zhejiang' }));
+    treeData.push({ label: '到底啦', value: 'bottom' })
+    return (
+        <Cascader
+            style={{ width: 300 }}
+            treeData={treeData}
+            placeholder="请选择所在地区"
+            onListScroll={()=>{console.log(123)}}
+        />
+    );
+};

+ 1 - 1
packages/semi-ui/cascader/index.tsx

@@ -828,7 +828,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
      */
     handleClearEnterPress = (e: KeyboardEvent) => {
         e && e.stopPropagation();
-        this.foundation.handleClearEnterPress();
+        this.foundation.handleClearEnterPress(e);
     };
 
     showClearBtn = () => {

+ 37 - 0
packages/semi-ui/datePicker/_story/datePicker.stories.js

@@ -814,3 +814,40 @@ export const FixTriggerRenderClosePanel = () => {
 };
 FixTriggerRenderClosePanel.storyName = "fix triggerRender close bug"
 
+export const A11yKeyboardDemo = () => {
+  const [value, setValue] = useState(new Date('2022-08-08 00:00'));
+  const [rangeValue, setRangeValue] = useState([new Date('2022-08-08 00:00'), new Date('2022-08-09 12:00')]);
+
+  const handleChange = v => {
+    console.log('change', v);
+    setValue(v);
+  };
+
+   const handleRangeChange = v => {
+    console.log('change', v);
+    setRangeValue(v);
+  };
+
+  return (
+    <Space vertical align='start' data-cy="space">
+      <div  data-cy="dateRange">
+        <DatePicker
+          value={rangeValue}
+          type="dateRange"
+          onChange={handleRangeChange}
+          showClear
+        />
+      </div>
+      <div data-cy="date">
+        <DatePicker
+          onChange={handleChange}
+          showClear
+          multiple
+        />
+      </div>
+    </Space>
+  );
+};
+
+A11yKeyboardDemo.storyName = "a11y keyboard demo"
+

+ 12 - 3
packages/semi-ui/input/__test__/input.test.js

@@ -113,9 +113,18 @@ describe('Input', () => {
   });
 
   it('input password mode', () => {
-    const inputMode = mount(<Input mode="password" />);
-    const input = inputMode.find('input');
-    expect(input.instance().type).toEqual('password');
+    const inputMode = mount(<Input />);
+    expect(inputMode.find('input').instance().type).toEqual('text');
+    inputMode.setProps({ mode: 'password' }) ;
+    expect(inputMode.find('input').instance().type).toEqual('password');
+    inputMode.setProps({ mode: '' }) ;
+    expect(inputMode.find('input').instance().type).toEqual('text');
+  });
+
+  it('input password click eyes icon', () => {
+    const inputMode = mount(<Input mode='password' defaultValue="123456" autofocus/>);
+    inputMode.simulate('mouseEnter', {}).find(`.${BASE_CLASS_PREFIX}-input-modebtn`).simulate('click');
+    expect(inputMode.find('input').instance().type).toEqual('text');
   });
 
   it('input controlled mode', () => {

+ 53 - 0
packages/semi-ui/input/__test__/textArea.test.js

@@ -116,4 +116,57 @@ describe('TextArea', () => {
         const counter2 = textarea.find(`.${BASE_CLASS_PREFIX}-input-textarea-counter`);
         expect(counter2.hasClass('semi-input-textarea-counter-exceed')).toEqual(false);
     });
+
+    it('test minLength', () => {
+        let inputValue = '💖💖💖';
+        let inputValue1 = '💖💖💖💖';
+        let minLength = 4;
+        let event = { target: { value: inputValue } };
+        let event1 = { target: { value: inputValue1 } };
+
+        let onChange = value => {
+        console.log(value);
+        };
+        let spyOnChange = sinon.spy(onChange);
+        const textArea = mount(<TextArea onChange={spyOnChange} minLength={minLength} getValueLength={getValueLength} />);
+        const textAreaDom = textArea.find('textarea');
+
+        textAreaDom.simulate('change', event);
+        expect(spyOnChange.calledOnce).toBe(true);
+        expect(spyOnChange.calledWithMatch(textAreaDom)).toBe(true);
+        expect(textAreaDom.instance().minLength).toEqual(inputValue.length + (minLength - getValueLength(inputValue)));
+
+        textAreaDom.simulate('change', event1);
+        expect(spyOnChange.calledWithMatch(textAreaDom)).toBe(true);
+        expect(textAreaDom.instance().minLength).toEqual(minLength)
+    });
+
+    it('test maxLength + truncateValue', () => {
+        function truncateValue(inputValue, maxLength, getValueLength) {
+            let event = { target: { value: inputValue } };
+            let onChange = value => {
+                console.log(value);
+            };
+
+            let spyOnChange = sinon.spy(onChange);
+            const textArea = mount(<TextArea onChange={spyOnChange} maxLength={maxLength} getValueLength={getValueLength} />);
+            const textAreaDom = textArea.find('textarea');
+            textAreaDom.simulate('change', event);
+            expect(spyOnChange.calledOnce).toBe(true);
+            return textAreaDom.instance().value;
+        }
+
+        const testCases = [
+        // 自定义valueLength
+            ['Semi', 5, getValueLength, 'Semi'],
+            ['Semi Design', 4, getValueLength, 'Semi'],
+            ['💖💖💖💖💖💖💖💖💖💖👨👩👧👦', 10, getValueLength, '💖💖💖💖💖💖💖💖💖💖'],
+            ['💖', -1, getValueLength, ''],
+            ['🆗', 1, getValueLength, '🆗'],
+        ];
+
+        for (let [value, length, fc, result] of testCases) {
+            expect(truncateValue(value, length, fc)).toBe(result);
+        }
+  })
 })

+ 44 - 0
packages/semi-ui/overflowList/_story/overflowList.stories.js

@@ -352,5 +352,49 @@ const LargeData = () => {
   );
 };
 
+export const OverflowListWithSlide = () =>{
+   const [width, setWidth] = useState(100);
+    const renderOverflow = items => {
+        return items.length ? <Tag style={{ flex: '0 0 auto' }}>+{items.length}</Tag> : null;
+    };
+    const renderItem = (item, ind) => {
+        return (
+            <Tag color="blue" key={item.key} style={{ marginRight: 8, flex: '0 0 auto' }}>
+                {item.icon}
+                {item.key}
+            </Tag>
+        );
+    };
+
+    const items = [
+        { icon: <IconAlarm style={{ marginRight: 4 }} />, key: 'alarm' },
+        { icon: <IconBookmark style={{ marginRight: 4 }} />, key: 'bookmark' },
+        { icon: <IconCamera style={{ marginRight: 4 }} />, key: 'camera' },
+        { icon: <IconDuration style={{ marginRight: 4 }} />, key: 'duration' },
+        { icon: <IconEdit style={{ marginRight: 4 }} />, key: 'edit' },
+        { icon: <IconFolder style={{ marginRight: 4 }} />, key: 'folder' },
+    ];
+
+    return (
+        <div>
+            <Slider step={1} value={width} onChange={value => setWidth(value)} />
+            <br />
+            <br />
+            <div style={{ width: `${width}%` }}>
+                <OverflowList
+                    items={items}
+                    // minVisibleItems={3}
+                    overflowRenderer={renderOverflow}
+                    visibleItemRenderer={renderItem}
+                />
+            </div>
+        </div>
+    );
+}
+
+OverflowListWithSlide.story = {
+  name: 'overflowList with slide',
+};
+
 // TODO large data will cause memory heap
 // stories.add('large amount of data', () => <LargeData />);

+ 72 - 0
packages/semi-ui/scrollList/_story/SingleWheelList/index.js

@@ -0,0 +1,72 @@
+import { ScrollList, ScrollItem, Button } from '@douyinfe/semi-ui';
+import React from 'react';
+
+class SingleScrollListDemo extends React.Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            selectIndex3: -2,
+        };
+
+        this.minutes = new Array(60).fill(0).map((itm, index) => {
+            return {
+                value: index,
+                disabled: index % 2 === 1 ? true : false,
+            };
+        });
+        this.onSelectMinute = this.onSelectMinute.bind(this);
+        this.handleClose = this.handleClose.bind(this);
+        this.renderFooter = this.renderFooter.bind(this);
+    }
+
+
+    onSelectMinute(data) {
+        console.log('You have choose the minute for: ', data.value);
+        this.setState({
+            ['selectIndex' + data.type]: data.index,
+        });
+    }
+
+    handleClose() {
+        console.log('close');
+    }
+
+    renderFooter() {
+        return (
+            <Button size="small" type="primary" onClick={this.handleClose}>
+                Ok
+            </Button>
+        );
+    }
+
+    render() {
+        let list = this.list;
+        const scrollStyle = {
+            border: 'unset',
+            boxShadow: 'unset',
+        };
+        const commonProps = {
+            // mode: 'normal',
+            mode: 'wheel',
+            cycled: false,
+            motion: false,
+        };
+        return (
+            <div>
+                <ScrollList style={scrollStyle} header={'单个无限滚动列表'} footer={this.renderFooter()}>
+                    <ScrollItem
+                        {...commonProps}
+                        list={this.minutes}
+                        type={3}
+                        selectedIndex={this.state.selectIndex3}
+                        onSelect={this.onSelectMinute}
+                        aria-label="分钟"
+                        cycled
+                    />
+                </ScrollList>
+            </div>
+        );
+    }
+}
+
+export default SingleScrollListDemo;

+ 7 - 0
packages/semi-ui/scrollList/_story/scrolllist.stories.js

@@ -1,6 +1,7 @@
 import React from 'react';
 import WheelListDemo from './WheelList';
 import ScrollListDemo from './ScrollList';
+import SingleScrollListDemo from './SingleWheelList';
 
 
 export default {
@@ -24,3 +25,9 @@ export const _WheelListDemo = () => <WheelListDemo />;
 _WheelListDemo.story = {
   name: 'wheel list demo',
 };
+
+export const SingleScrollList = () => <SingleScrollListDemo />;
+
+SingleScrollList.story = {
+  name: 'single scroll list demo',
+};

+ 3 - 0
packages/semi-ui/scrollList/scrollItem.tsx

@@ -178,6 +178,7 @@ export default class ScrollItem<T extends Item> extends BaseComponent<ScrollItem
 
     _cacheWrapperNode = (wrapper: Element) => this._cacheNode('wrapper', wrapper);
 
+    /* istanbul ignore next */
     _isFirst = (node: Element) => {
         const { list } = this;
 
@@ -191,6 +192,8 @@ export default class ScrollItem<T extends Item> extends BaseComponent<ScrollItem
         return false;
     };
 
+
+    /* istanbul ignore next */
     _isLast = (node: Element) => {
         const { list } = this;
 

+ 1 - 0
packages/semi-ui/table/__test__/table.test.js

@@ -109,6 +109,7 @@ describe(`Table`, () => {
             myCls,
             myClsIndex,
         });
+        demo.unmount();
     });
     it(`test object columns appearance`, async () => {
         const myCls = `my-tr-class`;

+ 2 - 0
packages/semi-ui/tabs/TabPane.tsx

@@ -53,6 +53,7 @@ class TabPane extends PureComponent<TabPaneProps> {
         return false;
     };
 
+    /* istanbul ignore next */
     hideScroll = (): void => {
         if (this.ref && this.ref.current) {
             this.ref.current.style.overflow = 'hidden';
@@ -60,6 +61,7 @@ class TabPane extends PureComponent<TabPaneProps> {
         }
     };
 
+    /* istanbul ignore next */
     autoScroll = (): void => {
         if (this.ref && this.ref.current) {
             this.ref.current.style.overflow = '';

+ 72 - 0
packages/semi-ui/tabs/_story/tabs.stories.js

@@ -795,3 +795,75 @@ export const TabSize = () => <TabSizeDemo />;
 TabSize.story = {
   name: 'tab size',
 };
+
+class TabListChangeDemo extends React.Component {
+   constructor() {
+    super();
+    this.state = {
+      itemKey: '1',
+      tabList:[
+      {
+        tab: '文档',
+        itemKey: '1',
+      },
+      {
+        tab: '快速起步',
+        itemKey: '2',
+      },
+      {
+        tab: '帮助',
+        itemKey: '3',
+      },
+      {
+        tab: '关于',
+        itemKey: '4',
+      },
+      {
+        tab: '资源工具',
+        itemKey: '5',
+      },
+    ]
+    };
+    this.onTabClick = this.onTabClick.bind(this);
+  }
+
+  onTabClick(itemKey, type) {
+    this.setState({
+      [type]: itemKey,
+      tabList: [{
+        tab: '文档',
+        itemKey: '1',
+      }]
+    });
+  }
+
+  render() {
+    const contentList = [
+      <div>文档</div>,
+      <div>快速起步</div>,
+      <div>帮助</div>,
+      <div>关于</div>,
+      <div>资源工具</div>,
+    ];
+    return (
+      <Tabs
+        style={style}
+        type="line"
+        tabList={this.state.tabList}
+        onTabClick={itemKey => {
+          this.onTabClick(itemKey, 'itemKey');
+        }}
+      >
+        {contentList[this.state.itemKey]}
+        <span>test</span>
+        <span>test2</span>
+      </Tabs>
+    );
+  }
+}
+
+export const TabListChange = () => <TabListChangeDemo />;
+
+TabListChange.story = {
+  name: 'tablist change',
+};

+ 1 - 0
packages/semi-ui/tabs/index.tsx

@@ -192,6 +192,7 @@ class Tabs extends BaseComponent<TabsProps, TabsState> {
         this.foundation.handleTabClick(activeKey, event);
     };
 
+    /* istanbul ignore next */
     rePosChildren = (children: ReactElement[], activeKey: string): ReactElement[] => {
         const newChildren: ReactElement[] = [];
 

+ 127 - 15
packages/semi-ui/tooltip/_story/tooltip.stories.js

@@ -404,6 +404,115 @@ AdjustPosition.story = {
   name: '自适应',
 };
 
+export const AdjustPosIfNeed = () => {
+  const tops = [
+        ['topLeft', 'TL'],
+        ['top', 'Top'],
+        ['topRight', 'TR'],
+    ];
+    const lefts = [
+        ['leftTop', 'LT'],
+        ['left', 'Left'],
+        ['leftBottom', 'LB'],
+    ];
+    const rights = [
+        ['rightTop', 'RT'],
+        ['right', 'Right'],
+        ['rightBottom', 'RB'],
+    ];
+    const bottoms = [
+        ['bottomLeft', 'BL'],
+        ['bottom', 'Bottom'],
+        ['bottomRight', 'BR'],
+    ];
+
+     return (
+        <div style={{ paddingLeft: 40 }}>
+            <div style={{ marginLeft: 40, whiteSpace: 'nowrap' }}>
+                {tops.map((pos, index) => (
+                    <Tooltip
+                        showArrow
+                        arrowPointAtCenter
+                        content={
+                            <article>
+                                Hi ByteDancer, this is a tooltip.
+                                <br /> We have 2 lines.
+                            </article>
+                        }
+                        position={Array.isArray(pos) ? pos[0] : pos}
+                        key={index}
+                    >
+                        <Tag 
+                          style={{ marginRight: '8px' }}
+                          data-cy={Array.isArray(pos) ? pos[0] : pos}
+                        >
+                          {Array.isArray(pos) ? pos[1] : pos}
+                        </Tag>
+                    </Tooltip>
+                ))}
+            </div>
+            <div style={{ width: 40, float: 'left' }}>
+                {lefts.map((pos, index) => (
+                    <Tooltip
+                        showArrow
+                        arrowPointAtCenter
+                        content={
+                            <article>
+                                Hi ByteDancer, this is a tooltip.
+                                <br /> We have 2 lines.
+                            </article>
+                        }
+                        position={Array.isArray(pos) ? pos[0] : pos}
+                        key={index}
+                    >
+                        <Tag data-cy={Array.isArray(pos) ? pos[0] : pos} style={{ marginBottom: '8px' }}>{Array.isArray(pos) ? pos[1] : pos}</Tag>
+                    </Tooltip>
+                ))}
+            </div>
+            <div style={{ width: 40, marginLeft: 180 }}>
+                {rights.map((pos, index) => (
+                    <Tooltip
+                        showArrow
+                        arrowPointAtCenter
+                        content={
+                            <article>
+                                Hi ByteDancer, this is a tooltip.
+                                <br /> We have 2 lines.
+                            </article>
+                        }
+                        position={Array.isArray(pos) ? pos[0] : pos}
+                        key={index}
+                    >
+                        <Tag data-cy={Array.isArray(pos) ? pos[0] : pos} style={{ marginBottom: '8px' }}>{Array.isArray(pos) ? pos[1] : pos}</Tag>
+                    </Tooltip>
+                ))}
+            </div>
+            <div style={{ marginLeft: 40, clear: 'both', whiteSpace: 'nowrap' }}>
+                {bottoms.map((pos, index) => (
+                    <Tooltip
+                        showArrow
+                        arrowPointAtCenter
+                        content={
+                            <article>
+                                Hi ByteDancer, this is a tooltip.
+                                <br /> We have 2 lines.
+                            </article>
+                        }
+                        position={Array.isArray(pos) ? pos[0] : pos}
+                        key={index}
+                    >
+                        <Tag data-cy={Array.isArray(pos) ? pos[0] : pos} position={Array.isArray(pos) ? pos[0] : pos} style={{ marginRight: '8px' }}>{Array.isArray(pos) ? pos[1] : pos}</Tag>
+                    </Tooltip>
+                ))}
+            </div>
+        </div>
+    );
+}
+
+AdjustPosIfNeed.story = {
+  name: '自适应位置',
+};
+
 export const CompositeComponent = () => (
   <div
     style={{
@@ -764,7 +873,7 @@ export const leftTopOverDemo = () => {
     content,
     trigger: 'click',
     showArrow: false,
-    visible,
+    visible:true,
     trigger: 'custom',
     motion: false,
   };
@@ -774,34 +883,37 @@ export const leftTopOverDemo = () => {
 
   return (
     <div data-cy="wrapper">
-      <Button onClick={() => setVisible(!visible)}>toggle visible</Button>
-      <div style={{ paddingTop: 200 }}>
+      <Button onClick={() => setVisible(!visible)} data-cy="toggleVisible">toggle visible</Button>
+      <div style={{ paddingTop: 110 }}>
         <Space spacing={80}>
-          <Tooltip {...commonProps} position="leftTopOver">
-            <Button data-cy="leftTopOver" style={buttonStyle}>
-              leftTopOver
-            </Button>
-          </Tooltip>
-          <Tooltip {...commonProps} position="leftBottomOver">
+          <Tooltip {...commonProps} position="leftBottomOver" trigger="click">
             <Button data-cy="leftBottomOver" style={buttonStyle}>
               leftBottomOver
             </Button>
           </Tooltip>
-          <Tooltip {...commonProps} position="rightTopOver">
-            <Button data-cy="rightTopOver" style={buttonStyle}>
-              rightTopOver
-            </Button>
-          </Tooltip>
-          <Tooltip {...commonProps} position="rightBottomOver">
+          <Tooltip {...commonProps} position="rightBottomOver" trigger="click">
             <Button data-cy="rightBottomOver" style={buttonStyle}>
               rightBottomOver
             </Button>
           </Tooltip>
         </Space>
       </div>
+      <Space spacing={80}>
+        <Tooltip {...commonProps} position="leftTopOver" trigger="click">
+          <Button data-cy="leftTopOver" style={buttonStyle}>
+            leftTopOver
+          </Button>
+        </Tooltip>
+        <Tooltip {...commonProps} position="rightTopOver" trigger="click">
+          <Button data-cy="rightTopOver" style={buttonStyle}>
+            rightTopOver
+          </Button>
+        </Tooltip>
+      </Space>
     </div>
   );
 };
+
 leftTopOverDemo.storyName = `leftTopOver visible`;
 leftTopOverDemo.parameters = {
   chromatic: {

+ 1 - 0
packages/semi-ui/typography/__test__/typography.test.js

@@ -24,6 +24,7 @@ describe(`Typography`, () => {
         const typographyParagraph = mount(<Typography.Paragraph {...props}>Semi Design</Typography.Paragraph>)
         const p = typographyParagraph.find('div.semi-typography-paragraph');
         expect(p.length).toEqual(1);
+        typographyParagraph.unmount();
     });
 
     it('typography copyable', () => {

+ 2 - 0
packages/semi-ui/upload/__test__/upload.test.js

@@ -564,6 +564,7 @@ describe('Upload', () => {
         requests[0].respond(200, { 'Content-Type': 'application/json' }, 'success');
         const previewContent = upload.find(`.${BASE_CLASS_PREFIX}-upload-file-card-preview`);
         expect(previewContent.contains(specificContent)).toEqual(true);
+        upload.unmount();
     });
 
     it('afterUpload', () => {
@@ -642,6 +643,7 @@ describe('Upload', () => {
         ).toEqual(true);
         expect(stateFileList.every(item => item.name !== 'remove.jpg')).toEqual(true);
         expect(stateFileList[3].status === 'uploadFail' && stateFileList[3].name === rename).toEqual(true);
+        upload.unmount();
     });
 
     it('uploadTrigger', () => {

+ 2 - 2
packages/semi-ui/upload/_story/upload.stories.js

@@ -572,8 +572,8 @@ export const Draggable = () => (
     <Upload
       {...commonProps}
       draggable={true}
-      disabled
-      accept="application/pdf,.jpeg"
+      // disabled
+      accept="application/image/*,.md"
       dragMainText={'点击上传文件或拖拽文件到这里'}
       dragSubText="支持的文件类型:.jpg、.pdf"
     ></Upload>