Browse Source

test: add test for hotKeys

yanzhuoran 1 year ago
parent
commit
8cf9de168f

+ 1 - 1
.vscode/launch.json

@@ -10,7 +10,7 @@
             "runtimeArgs": [
             "runtimeArgs": [
                 "--inspect-brk",
                 "--inspect-brk",
                 "${workspaceRoot}/node_modules/jest/bin/jest",
                 "${workspaceRoot}/node_modules/jest/bin/jest",
-                "packages/semi-ui/select/", // Replace with the folder path of the component you want to debug
+                "packages/semi-ui/hotKeys/", // Replace with the folder path of the component you want to debug
                 "--runInBand",
                 "--runInBand",
                 "--silent" // ignore warning such as componentWillReceiveProps will be abondon...
                 "--silent" // ignore warning such as componentWillReceiveProps will be abondon...
             ],
             ],

+ 13 - 5
cypress.config.ts

@@ -1,15 +1,23 @@
-import { defineConfig } from 'cypress'
+import { defineConfig } from "cypress";
 
 
 export default defineConfig({
 export default defineConfig({
-  projectId: 'k83u7j',
+  projectId: "k83u7j",
   scrollBehavior: false,
   scrollBehavior: false,
+
   e2e: {
   e2e: {
     // We've imported your old cypress plugins here.
     // We've imported your old cypress plugins here.
     // You may want to clean this up later by importing these.
     // You may want to clean this up later by importing these.
     setupNodeEvents(on, config) {
     setupNodeEvents(on, config) {
-      return require('./cypress/plugins/index.js')(on, config)
+      return require("./cypress/plugins/index.js")(on, config);
     },
     },
-    specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
+    specPattern: "cypress/e2e/**/*.{js,jsx,ts,tsx}",
     experimentalRunAllSpecs: true,
     experimentalRunAllSpecs: true,
   },
   },
-})
+
+  component: {
+    devServer: {
+      framework: "react",
+      bundler: "webpack",
+    },
+  },
+});

+ 37 - 0
cypress/e2e/hotKeys.spec.js

@@ -0,0 +1,37 @@
+describe('hotKeys', () => {
+    it('Basic Demo', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?path=/story/hotkeys--demo')
+
+        cy.get('body').click().type('{alt}{k}')
+        cy.get('pre').should('have.text', '1')
+    });
+
+    it('Clickable', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?path=/story/hotkeys--clickable')
+
+        cy.get('body').click().type('{alt}{k}')
+        cy.get('div.semi-hotKeys').click()
+        cy.get('pre').should('exist').and('have.text', '2')
+    });
+
+    it('Combine', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?path=/story/hotkeys--combine')
+
+        cy.get('body').click().type('{meta}{alt}{k}').type('{meta}{shift}{k}')
+        cy.get('pre').should('exist').and('have.text', '2')
+    });
+
+    it('Target', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?path=/story/hotkeys--target')
+
+        cy.get('input#test').type('{meta}{s}')
+        cy.get('pre').should('exist').and('have.text', '1')
+    });
+
+    it('Disabled', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?path=/story/hotkeys--disabled')
+
+        cy.get('body').click().type('{meta}{k}')
+        cy.get('pre').should('exist').and('have.text', '0')
+    });
+});

+ 37 - 0
cypress/support/commands.ts

@@ -0,0 +1,37 @@
+/// <reference types="cypress" />
+// ***********************************************
+// This example commands.ts shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add('login', (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
+//
+// declare global {
+//   namespace Cypress {
+//     interface Chainable {
+//       login(email: string, password: string): Chainable<void>
+//       drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
+//       dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
+//       visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
+//     }
+//   }
+// }

+ 12 - 0
cypress/support/component-index.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <title>Components App</title>
+  </head>
+  <body>
+    <div data-cy-root></div>
+  </body>
+</html>

+ 39 - 0
cypress/support/component.ts

@@ -0,0 +1,39 @@
+// ***********************************************************
+// This example support/component.ts is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands'
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
+
+import { mount } from 'cypress/react'
+
+// Augment the Cypress namespace to include type definitions for
+// your custom command.
+// Alternatively, can be defined in cypress/support/component.d.ts
+// with a <reference path="./component" /> at the top of your spec.
+declare global {
+  namespace Cypress {
+    interface Chainable {
+      mount: typeof mount
+    }
+  }
+}
+
+Cypress.Commands.add('mount', mount)
+
+// Example use:
+// cy.mount(<MyComponent />)

+ 1 - 249
packages/semi-ui/hotKeys/__test__/hotkeys.test.js

@@ -32,258 +32,10 @@ describe('HotKeys', () => {
             style: {
             style: {
                 color: 'red',
                 color: 'red',
             },
             },
+            hotKeys: ['r']
         };
         };
         const hotkeys = getHK(props);
         const hotkeys = getHK(props);
         expect(hotkeys.exists(`.${BASE_CLASS_PREFIX}-hotKeys.test`)).toEqual(true);
         expect(hotkeys.exists(`.${BASE_CLASS_PREFIX}-hotKeys.test`)).toEqual(true);
         expect(hotkeys.find(`.${BASE_CLASS_PREFIX}-hotKeys`)).toHaveStyle('color', 'red');
         expect(hotkeys.find(`.${BASE_CLASS_PREFIX}-hotKeys`)).toHaveStyle('color', 'red');
     });
     });
-
-    // Dropdown can't find `.${BASE_CLASS_PREFIX}-portal` (can confirm it't existence through documenty.body.innerHTML)
-    // but find `.${BASE_CLASS_PREFIX}-portal-inner`
-
-    // 由于.${BASE_CLASS_PREFIX}-portal 不是有dropdown或其子元素的render函数渲染出来的dom,而是portal在constructore阶段通过createElement/appendChild 插入的,所以无法使用find来找
-    // 只能通过document.querySelector来获取
-    it('Dropdown-zIndex', () => {
-        let zIndex = 2000;
-        let props = {
-            visible: true,
-            trigger: 'custom',
-            zIndex: zIndex,
-        };
-        const dropdown = getDD(props);
-        expect(Number(document.querySelector(`.${BASE_CLASS_PREFIX}-portal`).style.zIndex)).toEqual(zIndex);
-    });
-
-    it('Dropdown-trigger-hover', async () => {
-        let props = {
-            trigger: 'hover',
-        };
-        const dropdown = getDD(props);
-        // Before hover, dropdown is not displayed
-        expect(dropdown.exists(el_portal_inner)).toEqual(false);
-        // After trigger, dropdown content will show
-        dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('mouseEnter', {});
-        expect(dropdown.exists(el_portal_inner)).toEqual(true);
-        expect(dropdown.find(el_item)).toHaveLength(3);
-        await sleep(1000);
-        // auto hide
-        dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('mouseLeave', {});
-        await sleep(1000);
-        expect(dropdown.exists(el_portal_inner)).toEqual(false);
-        expect(dropdown.find(el_item)).toHaveLength(0);
-    });
-
-    it('Dropdown-trigger-click', () => {
-        let props = {
-            trigger: 'click',
-        };
-        const dropdown = getDD(props);
-        // Before click
-        expect(dropdown.exists(el_portal_inner)).toEqual(false);
-        expect(dropdown.exists(el_item)).toEqual(false);
-        // After click
-        dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('click', {});
-        expect(dropdown.exists(el_portal_inner)).toEqual(true);
-        expect(dropdown.find(el_item)).toHaveLength(3);
-    });
-
-    it('Dropdown-contentClassName', () => {
-        let props = {
-            contentClassName: 'test',
-            trigger: 'custom',
-            visible: true,
-        };
-        const dd = getDD(props);
-        expect(dd.exists(`.${BASE_CLASS_PREFIX}-dropdown.test`)).toEqual(true);
-    });
-
-    // TODO ??? visibleChange在Jest中没有被触发,实际上代码是work的
-    // it('Dropdown-onVisibleChange', () => {
-    //     let onVisibleChange = visible => {
-    //         debugger;
-    //     };
-    //     // let spyVisibleChange = sinon.spy(onVisibleChange);
-    //     let props = {
-    //         trigger: 'hover',
-    //         onVisibleChange: onVisibleChange,
-    //     };
-    //     const dropdown = getDD(props);
-    //     dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('mouseEnter', {});
-    //     expect(spyVisibleChange.calledOnce).toBe(true);
-    //     expect(spyVisibleChange.calledWithMatch(true)).toBe(true);
-    //     dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('mouseLeave', {});
-    //     expect(spyVisibleChange.calledWithMatch(false)).toBe(true);
-    // });
-
-    // it('Dropdown-clickToHide', () => {
-    //     let props = {
-    //         clickToHide: true,
-    //     };
-    // });
-
-    it('Dropdown-showTick', () => {
-        let items = [{ children: 'Item 1' }, { active: true, children: 'Item 2' }, { children: 'Item 3' }];
-        let props = {
-            showTick: true,
-            render: getSubMenu(items),
-            visible: true,
-            trigger: 'custom',
-        };
-        let DD = getDD(props);
-        expect(DD.find(`.${BASE_CLASS_PREFIX}-dropdown-item-withTick.${BASE_CLASS_PREFIX}-dropdown-item-active`).text()).toEqual('Item 2');
-    });
-
-    it('Dropdown.Item active', () => {
-        let items = [{ children: 'Item 1' }, { active: true, children: 'Item 2' }, { children: 'Item 3' }];
-        let props = {
-            render: getSubMenu(items),
-            visible: true,
-            trigger: 'custom',
-        };
-        let DD = getDD(props);
-        expect(DD.find(`.${BASE_CLASS_PREFIX}-dropdown-item-active`).text()).toEqual('Item 2');
-    });
-
-    it('Dropdown.Item type', () => {
-        let types = ['primary', 'secondary', 'tertiary', 'warning', 'danger'];
-        let items = types.map(type => {
-            return { type, children: `${type}Item` };
-        });
-        let props = {
-            render: getSubMenu(items),
-            trigger: 'custom',
-            visible: true,
-        };
-        let DD = getDD(props);
-        items.forEach(item => {
-            expect(DD.find(`.${BASE_CLASS_PREFIX}-dropdown-item-${item.type}`).text()).toEqual(`${item.children}`);
-        });
-    });
-
-    it('Dropdown.Item className & style', () => {
-        let items = [
-            { type: 'primary', children: 'primaryItem', className: 'primary-test', style: { color: 'red' } },
-            { type: 'secondary', children: 'secondaryItem' },
-        ];
-        let props = {
-            render: getSubMenu(items),
-            trigger: 'custom',
-            visible: true,
-        };
-        let DD = getDD(props);
-        expect(DD.find('li.primary-test')).toHaveStyle('color', 'red');
-    });
-
-    it('Dropdown.Item disabled', () => {
-        let items = [
-            { disabled: true, children: 'Item 1' },
-            { disabled: false, children: 'Item 2' },
-        ];
-        let props = {
-            render: getSubMenu(items),
-            trigger: 'custom',
-            visible: true,
-        };
-        let DD = getDD(props);
-        expect(DD.find(`.${BASE_CLASS_PREFIX}-dropdown-item-disabled`).text()).toEqual('Item 1');
-    });
-
-    it('Dropdown.Item onClick', () => {
-        let onClick = event => {};
-        let spyItemCLick = sinon.spy(onClick);
-        let items = [{ children: 'A' }, { children: 'B', onClick: spyItemCLick, className: 'test' }];
-        let props = {
-            render: getSubMenu(items),
-            trigger: 'custom',
-            visible: true,
-        };
-        let DD = getDD(props);
-        let targetItem = DD.find('li.test');
-        let event = {
-            button:0,
-            target: {
-                value: 'B1',
-            },
-        };
-        targetItem.simulate('click', event);
-        expect(spyItemCLick.calledOnce).toEqual(true);
-        expect(spyItemCLick.calledWithMatch(event)).toEqual(true);
-    });
-
-    it('Dropdown.Item onMouseEnter/onMouseLeave', () => {
-        let onMouseEnter = e => {};
-        let spyItemMouseEnter = sinon.spy(onMouseEnter);
-        let spyItemMouseLeave = sinon.spy(e => {});
-        let items = [
-            { children: 'A' },
-            { children: 'B', onMouseEnter: spyItemMouseEnter, onMouseLeave: spyItemMouseLeave, className: 'test' },
-        ];
-        let props = {
-            render: getSubMenu(items),
-            trigger: 'custom',
-            visible: true,
-        };
-        let DD = getDD(props);
-        let targetItem = DD.find('li.test');
-        let event = {
-            target: {
-                value: 'B1',
-            },
-        };
-        targetItem.simulate('mouseEnter', event);
-        expect(spyItemMouseEnter.calledOnce).toEqual(true);
-        expect(spyItemMouseEnter.calledWithMatch(event)).toEqual(true);
-        targetItem.simulate('mouseLeave', event);
-        expect(spyItemMouseLeave.calledOnce).toEqual(true);
-        expect(spyItemMouseLeave.calledWithMatch(event)).toEqual(true);
-    });
-
-    it('Dropdown.Title className & style', () => {
-        let props = {
-            render: (
-                <Dropdown.Menu>
-                    <Dropdown.Title className="test" style={{ margin: 5 }}>
-                        分组1
-                    </Dropdown.Title>
-                    <Dropdown.Item>primary</Dropdown.Item>
-                    <Dropdown.Item type="secondary">secondary</Dropdown.Item>
-                    <Dropdown.Divider />
-                    <Dropdown.Title>分组2</Dropdown.Title>
-                    <Dropdown.Item type="danger">danger</Dropdown.Item>
-                </Dropdown.Menu>
-            ),
-            trigger: 'custom',
-            visible: true,
-        };
-        let DD = getDD(props);
-        expect(DD.find('div.test')).toHaveStyle('margin', 5);
-    });
-
-
-    it('Dropdown array menu', () => {
-        const menu = [
-            { node: 'title', name: '分组1' },
-            { node: 'item', name: 'primary1', type: 'primary', onClick: () => console.log('click primary') },
-            { node: 'item', name: 'secondary', type: 'secondary' },
-            { node: 'divider', },
-            { node: 'title', name: '分组2' },
-            { node: 'item', name: 'tertiary', type: 'tertiary' },
-            { node: 'item', name: 'warning', type: 'warning', active: true },
-            { node: 'item', name: 'danger', type: 'danger' },
-        ];
-        let DD = mount(<Dropdown menu={menu} trigger="custom" visible ></Dropdown>, {
-            attachTo: document.getElementById('container'),
-        });
-        expect(DD.find('.semi-dropdown-menu').children().length).toEqual(menu.length);
-        const menu2 = [
-            { node: 'title', name: '分组1', iconType: 'menu' },
-            { node: 'item', name: 'secondary', type: 'secondary' },
-            { node: 'divider', },
-            { node: 'title', name: '分组2' },
-            { node: 'invalid node', name: '分组2' },
-        ];
-        DD.setProps({ menu: menu2 })
-        DD.update()
-        expect(DD.find('.semi-dropdown-menu').children().length).toEqual(menu2.length - 1);
-    });
 });
 });

+ 1 - 1
packages/semi-ui/hotKeys/_story/hotKeys.stories.jsx

@@ -50,7 +50,7 @@ export const renderButton = () => {
   }
   }
   return (
   return (
     <div>
     <div>
-      <span>{" cnt:" + cnt}</span>
+      <pre>{" cnt:" + cnt}</pre>
       <HotKeys hotKeys={hotKeys} onClick={onClick} render={button} clickable></HotKeys>
       <HotKeys hotKeys={hotKeys} onClick={onClick} render={button} clickable></HotKeys>
     </div>
     </div>