├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .fatherrc.ts ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc.js ├── README.md ├── jest.config.js ├── package.json ├── src ├── autoComplete │ ├── __tests__ │ │ └── autoComplete.test.tsx │ └── index.ts ├── button │ ├── __tests__ │ │ └── button.test.tsx │ └── index.ts ├── cascader │ ├── __tests__ │ │ └── cascader.test.tsx │ └── index.ts ├── checkbox │ ├── __tests__ │ │ └── checkbox.test.tsx │ └── index.ts ├── collapse │ ├── __tests__ │ │ └── collapse.test.tsx │ └── index.ts ├── datePicker │ ├── __tests__ │ │ └── datePicker.test.tsx │ └── index.ts ├── drawer │ ├── __tests__ │ │ └── drawer.test.tsx │ └── index.ts ├── dropdown │ └── index.ts ├── form │ ├── __tests__ │ │ └── form.test.tsx │ └── index.ts ├── index.ts ├── input │ ├── __tests__ │ │ ├── input.test.tsx │ │ └── textarea.test.tsx │ ├── index.ts │ └── textarea.ts ├── inputNumber │ └── index.ts ├── interface.ts ├── message │ ├── __tests__ │ │ └── message.test.tsx │ └── index.ts ├── modal │ ├── __tests__ │ │ ├── confirm.test.tsx │ │ └── modal.test.tsx │ ├── confirm.ts │ └── index.ts ├── pagination │ ├── __tests__ │ │ └── pagination.test.tsx │ └── index.ts ├── popconfirm │ ├── __tests__ │ │ └── popconfirm.test.tsx │ └── index.ts ├── provider │ └── index.ts ├── radio │ ├── __tests__ │ │ └── radio.test.tsx │ └── index.ts ├── select │ ├── __tests__ │ │ └── select.test.tsx │ └── index.ts ├── switch │ ├── __tests__ │ │ └── switch.test.tsx │ └── index.ts ├── table │ ├── __tests__ │ │ └── table.test.tsx │ └── index.tsx ├── tabs │ ├── __tests__ │ │ └── tabs.test.tsx │ └── index.ts ├── timePicker │ ├── __tests__ │ │ └── timePicker.test.tsx │ └── index.ts ├── tooltip │ ├── __tests__ │ │ └── tooltip.test.tsx │ └── index.ts ├── transfer │ ├── __tests__ │ │ └── transfer.test.tsx │ └── index.ts ├── tree │ ├── __tests__ │ │ └── tree.test.tsx │ └── index.ts ├── treeSelect │ ├── __tests__ │ │ └── treeSelect.test.tsx │ └── index.ts ├── upload │ ├── __tests__ │ │ └── upload.test.tsx │ └── index.ts └── utils │ ├── __tests__ │ └── utils.test.tsx │ └── index.ts ├── tests └── setupTests.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # 🎨 editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 4 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Please Checkout And Make Sure Patterns Isn't Exist In .gitignore File First 2 | coverage 3 | dist 4 | *.yaml -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [require.resolve('ko-lint-config/.eslintrc')], 3 | rules: { 4 | '@typescript-eslint/no-non-null-assertion': 2, 5 | }, 6 | overrides: [ 7 | { 8 | files: ['**/__tests__/*.tsx'], 9 | rules: { 10 | '@typescript-eslint/no-non-null-assertion': 0, 11 | '@typescript-eslint/ban-ts-comment': 0, 12 | }, 13 | }, 14 | ], 15 | }; 16 | -------------------------------------------------------------------------------- /.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | platform: 'node', 5 | cjs: {}, 6 | prebundle: { 7 | deps: {} 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | .DS_Store 4 | coverage 5 | pnpm-lock.yaml 6 | *.lock 7 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | pnpm exec lint-staged 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Please Checkout And Make Sure Patterns Isn't Exist In .gitignore File First 2 | coverage 3 | dist 4 | *.yaml 5 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('ko-lint-config/.prettierrc'), 3 | printWidth: 120, 4 | }; 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
ant-design-testing
2 | 3 | _Easier testing for ant-design-based UI library_ 4 | 5 | ## Usage 6 | 7 | ```shell 8 | $ pnpm install ant-design-testing -D 9 | ``` 10 | 11 | then, modify the prefixCls if you need it 12 | 13 | ```tsx 14 | // setupTests.ts 15 | import { provider } from 'ant-design-testing'; 16 | 17 | provider({ prefixCls: 'ant' }); 18 | ``` 19 | 20 | ```tsx 21 | // yourInput.test.tsx 22 | import { input } from 'ant-design-testing'; 23 | 24 | describe("Test input's fire functions", () => { 25 | test('fireChange', () => { 26 | const fn = jest.fn(); 27 | const { container } = render(); 28 | input.fireChange(container, 'test'); 29 | expect(fn).toBeCalled(); 30 | }); 31 | }); 32 | ``` 33 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | setupFilesAfterEnv: ['./tests/setupTests.ts'], 3 | testEnvironment: 'jsdom', 4 | transform: { 5 | '^.+\\.(t|j)sx?$': ['@swc/jest'], 6 | }, 7 | testPathIgnorePatterns: ['/node_modules/'], 8 | testMatch: ['**/__tests__/**/(*.)+(spec|test).[jt]s?(x)'], 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | }; 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ant-design-testing", 3 | "version": "0.1.0-beta.4", 4 | "description": "Easier testing for ant-design-based UI library", 5 | "main": "dist/cjs/index.js", 6 | "types": "dist/cjs/index.d.ts", 7 | "scripts": { 8 | "dev": "father dev", 9 | "build": "father build", 10 | "build:deps": "father prebundle", 11 | "prepublishOnly": "father doctor && npm run build", 12 | "test": "jest", 13 | "release": "bumpp --commit --push --tag && npm publish", 14 | "prepare": "husky install" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/mortalYoung/ant-design-testing" 19 | }, 20 | "keywords": [ 21 | "Ant Design", 22 | "UI library" 23 | ], 24 | "authors": [ 25 | "mortalYoung " 26 | ], 27 | "license": "MIT", 28 | "files": [ 29 | "dist", 30 | "compiled" 31 | ], 32 | "publishConfig": { 33 | "access": "public", 34 | "registry": "https://registry.npmjs.org/" 35 | }, 36 | "peerDependencies": { 37 | "@testing-library/react": "*", 38 | "antd": "4", 39 | "rc-resize-observer": "*" 40 | }, 41 | "peerDependenciesMeta": { 42 | "rc-resize-observer": { 43 | "optional": true 44 | } 45 | }, 46 | "devDependencies": { 47 | "@swc/core": "^1.3.58", 48 | "@swc/jest": "^0.2.26", 49 | "@testing-library/react": "^13.0.0", 50 | "@types/jest": "^29.5.1", 51 | "antd": "4", 52 | "bumpp": "^9.1.0", 53 | "father": "^4.2.0", 54 | "husky": "^8.0.3", 55 | "jest": "^29.5.0", 56 | "jest-environment-jsdom": "^29.5.0", 57 | "ko-lint-config": "^2.2.20", 58 | "lint-staged": "^13.2.2", 59 | "moment": "^2.29.4", 60 | "prettier": "^2.8.8", 61 | "rc-resize-observer": "*", 62 | "react": "^18.2.0", 63 | "react-dom": "^18.2.0", 64 | "typescript": "^4.8.0" 65 | }, 66 | "lint-staged": { 67 | "*.{ts,js,tsx}": [ 68 | "eslint --fix", 69 | "prettier --write" 70 | ] 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/autoComplete/__tests__/autoComplete.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { AutoComplete } from 'antd'; 4 | 5 | import * as autoComplete from '..'; 6 | 7 | describe('Test Select fire functions', () => { 8 | beforeEach(() => { 9 | jest.useFakeTimers(); 10 | cleanup(); 11 | }); 12 | 13 | afterEach(() => { 14 | jest.useRealTimers(); 15 | }); 16 | 17 | it('query', () => { 18 | const { container, getByTestId } = render( 19 | <> 20 | 21 | 22 | 23 | ); 24 | expect(autoComplete.query(container)).toBe(getByTestId('autoComplete1')); 25 | expect(autoComplete.query(container, 1)).toBe(getByTestId('autoComplete2')); 26 | }); 27 | 28 | it('querySelector', () => { 29 | const { container } = render( 30 | <> 31 | 32 | 33 | 34 | ); 35 | expect(autoComplete.querySelector(container)).not.toBe(autoComplete.querySelector(container, 1)); 36 | }); 37 | 38 | it('queryOption', () => { 39 | const { container } = render( 40 | node.parentNode} 42 | options={[ 43 | { label: 'a', value: 'a' }, 44 | { label: 'b', value: 'b' }, 45 | ]} 46 | /> 47 | ); 48 | autoComplete.fireOpen(container); 49 | expect(autoComplete.queryOption(container)?.textContent).toBe('a'); 50 | expect(autoComplete.queryOption(container, 1)?.textContent).toBe('b'); 51 | }); 52 | 53 | it('queryOption', () => { 54 | const fn1 = jest.fn(); 55 | const fn2 = jest.fn(); 56 | const { container } = render( 57 | <> 58 | 59 | 60 | 61 | ); 62 | autoComplete.fireClear(autoComplete.queryClear(container)!); 63 | expect(fn1).toBeCalledTimes(1); 64 | expect(fn2).not.toBeCalled(); 65 | autoComplete.fireClear(autoComplete.queryClear(container, 1)!); 66 | expect(fn2).toBeCalledTimes(1); 67 | }); 68 | 69 | it('queryInput', () => { 70 | const { container, getByTestId } = render( 71 | <> 72 | 73 | 74 | 75 | ); 76 | expect(autoComplete.queryInput(container)).toBe(getByTestId('autoComplete1').querySelector('input')); 77 | expect(autoComplete.queryInput(container, 1)).toBe(getByTestId('autoComplete2').querySelector('input')); 78 | }); 79 | 80 | it('fireOpen', () => { 81 | const fn = jest.fn(); 82 | const { container } = render( 83 | 84 | ); 85 | autoComplete.fireOpen(container); 86 | expect(fn).toBeCalledWith(true); 87 | }); 88 | 89 | it('fireSelect', () => { 90 | const fn = jest.fn(); 91 | const { container } = render( 92 | node.parentNode} 95 | options={[{ label: 'a', value: 'a' }]} 96 | /> 97 | ); 98 | autoComplete.fireOpen(container); 99 | autoComplete.fireSelect(container, 0); 100 | expect(fn).toBeCalled(); 101 | }); 102 | 103 | it('fireSearch', () => { 104 | const fn = jest.fn(); 105 | const { container } = render(); 106 | autoComplete.fireSearch(container, 'test'); 107 | expect(fn).toBeCalled(); 108 | }); 109 | 110 | it('fireFocus', () => { 111 | const fn = jest.fn(); 112 | const { container } = render(); 113 | autoComplete.fireFocus(container); 114 | expect(fn).toBeCalled(); 115 | }); 116 | 117 | it('fireBlur', () => { 118 | const fn = jest.fn(); 119 | const { container } = render(); 120 | autoComplete.fireFocus(container); 121 | autoComplete.fireBlur(container); 122 | expect(fn).toBeCalled(); 123 | }); 124 | 125 | it('fireClear', () => { 126 | const fn = jest.fn(); 127 | const { container } = render( 128 | 129 | ); 130 | autoComplete.fireClear(container); 131 | expect(fn).toBeCalled(); 132 | }); 133 | }); 134 | -------------------------------------------------------------------------------- /src/autoComplete/index.ts: -------------------------------------------------------------------------------- 1 | import type { IContainer } from '../interface'; 2 | import { getProvider } from '../provider'; 3 | import * as select from '../select'; 4 | import { queryViaSelector } from '../utils'; 5 | 6 | /** 7 | * Fires onSearch function 8 | */ 9 | export function fireSearch(container: IContainer, value: any) { 10 | select.fireSearch(container, value); 11 | } 12 | 13 | /** 14 | * Fires onDropdownVisibleChange function. 15 | * Meanwhile, open Dropdown 16 | * @prerequisite call `jest.useFakeTimers()` 17 | */ 18 | export function fireOpen(container: IContainer) { 19 | select.fireOpen(container); 20 | } 21 | 22 | /** 23 | * Fires onSelect function 24 | */ 25 | export function fireSelect(container: IContainer, index: number) { 26 | select.fireSelect(container, index); 27 | } 28 | 29 | /** 30 | * Fires onFocus function 31 | */ 32 | export function fireFocus(container: IContainer) { 33 | select.fireFocus(container); 34 | } 35 | 36 | /** 37 | * Fires onBlur function 38 | */ 39 | export function fireBlur(container: IContainer) { 40 | select.fireBlur(container); 41 | } 42 | 43 | /** 44 | * Fires onClear function 45 | */ 46 | export function fireClear(container: IContainer) { 47 | select.fireClear(container); 48 | } 49 | 50 | /** 51 | * Returns the `index` container of AutoComplete 52 | * @param index default is `0` 53 | */ 54 | export function query(container: IContainer, index = 0) { 55 | const selector = `.${getProvider('prefixCls')}-select-auto-complete`; 56 | const ele = queryViaSelector(container, selector, index); 57 | return ele; 58 | } 59 | 60 | /** 61 | * Returns input element of AutoComplete 62 | */ 63 | export function queryInput(container: IContainer, index = 0) { 64 | return select.queryInput(container, index); 65 | } 66 | 67 | /** 68 | * Returns selector element of AutoComplete 69 | */ 70 | export function querySelector(container: IContainer, index = 0) { 71 | return select.querySelector(container, index); 72 | } 73 | 74 | /** 75 | * Returns option element of AutoComplete 76 | */ 77 | export function queryOption(container: IContainer, index = 0) { 78 | return select.queryOption(container, index); 79 | } 80 | 81 | /** 82 | * Returns clear icon element of AutoComplete 83 | */ 84 | export function queryClear(container: IContainer, index = 0) { 85 | return select.queryClear(container, index); 86 | } 87 | -------------------------------------------------------------------------------- /src/button/__tests__/button.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import { Button } from 'antd'; 4 | 5 | import * as button from '..'; 6 | 7 | describe("Test Button's fire functions", () => { 8 | test('query', () => { 9 | const { container, getByTestId } = render( 10 | <> 11 | 12 | 13 | 14 | ); 15 | expect(button.query(container)).toBe(getByTestId('button1')); 16 | expect(button.query(container, 1)).toBe(getByTestId('button2')); 17 | }); 18 | test('test fireClick', () => { 19 | const fn = jest.fn(); 20 | const { container } = render(); 21 | button.fireClick(container); 22 | expect(fn).toBeCalled(); 23 | }); 24 | 25 | test('fireClick support dom self', () => { 26 | const fn = jest.fn(); 27 | const { container } = render(); 28 | button.fireClick(button.query(container)!); 29 | expect(fn).toBeCalled(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/button/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | 7 | /** 8 | * Fires onClick function for Button 9 | */ 10 | export const fireClick = (container: IContainer) => { 11 | const selector = `.${getProvider('prefixCls')}-btn`; 12 | const ele = query(container); 13 | if (!ele) throw failedQuerySelector(selector); 14 | fireEvent.click(ele); 15 | }; 16 | 17 | /** 18 | * Returns the `index` button that is a descendant of node. 19 | * @param {number} index default is `0` 20 | */ 21 | export const query = (container: IContainer, index = 0) => { 22 | const selector = `.${getProvider('prefixCls')}-btn`; 23 | const ele = queryViaSelector(container, selector, index); 24 | return ele; 25 | }; 26 | -------------------------------------------------------------------------------- /src/cascader/__tests__/cascader.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, fireEvent, render } from '@testing-library/react'; 3 | import { Cascader } from 'antd'; 4 | 5 | import * as cascader from '..'; 6 | 7 | const options = [ 8 | { 9 | label: '1', 10 | value: '1', 11 | children: [ 12 | { 13 | label: '1-1', 14 | value: '1-1', 15 | children: [ 16 | { 17 | label: '1-1-1', 18 | value: '1-1-1', 19 | }, 20 | ], 21 | }, 22 | ], 23 | }, 24 | ]; 25 | 26 | describe("Test Cascader's fire functions", () => { 27 | beforeEach(() => { 28 | cleanup(); 29 | jest.useFakeTimers(); 30 | }); 31 | afterEach(() => { 32 | jest.useRealTimers(); 33 | }); 34 | 35 | test('query', () => { 36 | const { container, getByTestId } = render( 37 |
38 | 39 | 40 |
41 | ); 42 | expect(cascader.query(container)).toBe(getByTestId('cascader1')); 43 | expect(cascader.query(container, 1)).toBe(getByTestId('cascader2')); 44 | }); 45 | 46 | test('querySelect', () => { 47 | const fn = jest.fn(); 48 | const { container } = render( 49 |
50 | 51 | 52 |
53 | ); 54 | cascader.fireOpen(cascader.querySelect(container)!); 55 | expect(fn).toBeCalledTimes(1); 56 | cascader.fireOpen(cascader.querySelect(container, 1)!); 57 | // The second time is called because of hidden the first one 58 | expect(fn).toBeCalledTimes(3); 59 | }); 60 | 61 | test('queryInput', () => { 62 | const fn = jest.fn(); 63 | const { container, getByTestId } = render( 64 |
65 | 66 | 67 |
68 | ); 69 | 70 | expect(cascader.queryInput(container)).toBe(getByTestId('cascader1').querySelector('input')); 71 | expect(cascader.queryInput(container, 1)).toBe(getByTestId('cascader2').querySelector('input')); 72 | }); 73 | 74 | test('queryDropdown', () => { 75 | render(); 76 | expect(cascader.queryDropdown(document)).not.toBeNull(); 77 | }); 78 | 79 | test('queryMenu', () => { 80 | const fn = jest.fn(); 81 | render(); 82 | cascader.fireChange(cascader.queryMenu(document)!, 0); 83 | expect(fn).toBeCalled(); 84 | }); 85 | 86 | test('queryMenuItem', () => { 87 | const fn = jest.fn(); 88 | render(); 89 | fireEvent.click(cascader.queryMenuItem(document)!); 90 | expect(fn).toBeCalled(); 91 | }); 92 | 93 | test('fireOpen', () => { 94 | const fn = jest.fn(); 95 | const { container } = render(); 96 | cascader.fireOpen(container); 97 | expect(fn).toBeCalledTimes(1); 98 | }); 99 | 100 | test('fireChange', () => { 101 | const fn = jest.fn(); 102 | const { container } = render( 103 | node.parentNode} options={options} /> 104 | ); 105 | cascader.fireOpen(container); 106 | cascader.fireChange(container, 0, 0, 0); 107 | expect(fn).toBeCalled(); 108 | }); 109 | 110 | test('fireChange with hover trigger', () => { 111 | const fn = jest.fn(); 112 | const { container } = render( 113 | node.parentNode} 117 | options={options} 118 | /> 119 | ); 120 | cascader.fireOpen(container); 121 | cascader.fireChange(container, 'hover', 0, 0, 0); 122 | expect(fn).toBeCalled(); 123 | }); 124 | 125 | test('fireSearch', () => { 126 | const fn = jest.fn(); 127 | const { container } = render( 128 | 131 | path.some( 132 | (option) => (option.label as string).toLowerCase().indexOf(inputValue.toLowerCase()) > -1 133 | ), 134 | }} 135 | onSearch={fn} 136 | /> 137 | ); 138 | cascader.fireSearch(container, 'test'); 139 | expect(fn).toBeCalled(); 140 | }); 141 | 142 | test('fireClear', () => { 143 | const fn = jest.fn(); 144 | const { container } = render( 145 | 146 | ); 147 | cascader.fireClear(container); 148 | expect(fn).toBeCalled(); 149 | }); 150 | 151 | test('fireChange with multiple', () => { 152 | const fn1 = jest.fn(); 153 | const fn2 = jest.fn(); 154 | const { container } = render( 155 | <> 156 | node.parentNode} options={options} /> 157 | node.parentNode} options={options} /> 158 | 159 | ); 160 | cascader.fireOpen(container); 161 | cascader.fireChange(container, 0, 0, 0); 162 | expect(fn1).toBeCalledTimes(1); 163 | expect(fn2).toBeCalledTimes(0); 164 | 165 | cascader.fireOpen(cascader.query(container, 1)!); 166 | cascader.fireChange(cascader.queryDropdown(container, 1)!, 0, 0, 0); 167 | expect(fn1).toBeCalledTimes(1); 168 | expect(fn2).toBeCalledTimes(1); 169 | }); 170 | }); 171 | -------------------------------------------------------------------------------- /src/cascader/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | import type { CascaderProps } from 'antd'; 3 | 4 | import type { IContainer } from '../interface'; 5 | import { getProvider } from '../provider'; 6 | import { fireClear as selectFireClear, fireOpen as selectFireOpen } from '../select'; 7 | import { failedQuerySelector, queryViaSelector, queryViaSelectors } from '../utils'; 8 | 9 | /** 10 | * Fires onDropdownVisibleChange for Cascader, and open drowdown 11 | */ 12 | export function fireOpen(container: IContainer) { 13 | selectFireOpen(container); 14 | } 15 | 16 | /** 17 | * Fires onChange for Cascader 18 | * @param indexes each panel's index 19 | */ 20 | export function fireChange(container: IContainer, ...indexes: number[]): void; 21 | /** 22 | * Fires onChange for Cascader by click or hover 23 | * @param type as same as Cascader's expandTrigger 24 | * @param indexes each panel's index 25 | */ 26 | export function fireChange(container: IContainer, type: CascaderProps['expandTrigger'], ...indexes: number[]): void; 27 | export function fireChange( 28 | container: IContainer, 29 | typeOrIndex: CascaderProps['expandTrigger'] | number, 30 | ...rest: number[] 31 | ) { 32 | const type = typeof typeOrIndex === 'string' ? typeOrIndex : 'click'; 33 | const indexes = typeof typeOrIndex === 'number' ? [typeOrIndex].concat(rest) : rest; 34 | const triggerEvent = { 35 | click: 'click', 36 | hover: 'mouseEnter', 37 | } as const; 38 | for (let i = 0; i < indexes.length; i++) { 39 | const index = indexes[i]; 40 | const selectors = [ 41 | `ul.${getProvider('prefixCls')}-cascader-menu`, 42 | `li.${getProvider('prefixCls')}-cascader-menu-item`, 43 | ]; 44 | const ele = queryViaSelectors(container, selectors, [i, index]); 45 | if (!ele) throw failedQuerySelector(selectors.join(' ')); 46 | 47 | const last = i === indexes.length - 1; 48 | fireEvent[last ? 'click' : triggerEvent[type]]?.(ele); 49 | } 50 | } 51 | 52 | /** 53 | * Fires onSearch for Cascader 54 | */ 55 | export function fireSearch(container: IContainer, value: string) { 56 | const selector = 'input'; 57 | const ele = queryInput(container); 58 | if (!ele) throw failedQuerySelector(selector); 59 | fireEvent.change(ele, { target: { value } }); 60 | } 61 | 62 | /** 63 | * Fires onClear for Cascader 64 | * @notice clear button **ONLY** accessible for non-empty value 65 | */ 66 | export function fireClear(container: IContainer) { 67 | selectFireClear(container); 68 | } 69 | 70 | /** 71 | * Returns the `index` element of Cascader's container 72 | * @param index the order of Cascader's container, default is `0` 73 | */ 74 | export function query(container: IContainer, index = 0) { 75 | const selector = `.${getProvider('prefixCls')}-cascader`; 76 | const ele = queryViaSelector(container, selector, index); 77 | return ele; 78 | } 79 | 80 | /** 81 | * Returns the `index` element of Cascader's Select 82 | * @param index the order of Cascader's Select, default is `0` 83 | */ 84 | export function querySelect(container: IContainer, index = 0) { 85 | const selector = `.${getProvider('prefixCls')}-select-selector`; 86 | const ele = queryViaSelector(container, selector, index); 87 | return ele; 88 | } 89 | 90 | /** 91 | * Returns the `index` element of Cascader's Input 92 | * @param index the order of Cascader's Input, default is `0` 93 | */ 94 | export function queryInput(container: IContainer, index = 0) { 95 | const selector = 'input'; 96 | const ele = queryViaSelector(container, selector, index); 97 | return ele; 98 | } 99 | 100 | /** 101 | * Returns the `index` element of Cascader's Dropdown 102 | * @notice Be aware of the different parentElement affected by getPopupContainer 103 | * @param index the order of Cascader's Dropdown, default is `0` 104 | */ 105 | export function queryDropdown(container: IContainer, index = 0) { 106 | const selector = `.${getProvider('prefixCls')}-cascader-dropdown`; 107 | const ele = queryViaSelector(container, selector, index); 108 | return ele; 109 | } 110 | 111 | /** 112 | * Returns the `index` element of Menu inside Cascader's Dropdown 113 | * @param index the order of Menu, default is `0` 114 | */ 115 | export function queryMenu(container: IContainer, index = 0) { 116 | const selector = `ul.${getProvider('prefixCls')}-cascader-menu`; 117 | const ele = queryViaSelector(container, selector, index); 118 | return ele; 119 | } 120 | 121 | /** 122 | * Returns the `index` element of MenuItem inside Cascader's Dropdown 123 | * @param index the order of MenuItem, default is `0` 124 | */ 125 | export function queryMenuItem(container: IContainer, index = 0) { 126 | const selector = `li.${getProvider('prefixCls')}-cascader-menu-item`; 127 | const ele = queryViaSelector(container, selector, index); 128 | return ele; 129 | } 130 | -------------------------------------------------------------------------------- /src/checkbox/__tests__/checkbox.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Checkbox } from 'antd'; 4 | 5 | import * as checkbox from '..'; 6 | 7 | describe('Test checkbox', () => { 8 | beforeEach(cleanup); 9 | 10 | test('query', () => { 11 | const { container, getByTestId } = render( 12 | <> 13 | Checkbox 14 | Checkbox 15 | 16 | ); 17 | expect(checkbox.query(container)?.querySelector('input')).toBe(getByTestId('Checkbox1')); 18 | expect(checkbox.query(container, 1)?.querySelector('input')).toBe(getByTestId('Checkbox2')); 19 | }); 20 | 21 | test('queryGroup', () => { 22 | const { container, getByTestId } = render( 23 | <> 24 | 25 | 26 | 27 | ); 28 | expect(checkbox.queryGroup(container)).toBe(getByTestId('Checkbox1')); 29 | expect(checkbox.queryGroup(container, 1)).toBe(getByTestId('Checkbox2')); 30 | }); 31 | 32 | test('queryInput', () => { 33 | const fn = jest.fn(); 34 | const { container } = render(); 35 | checkbox.fireChange(checkbox.queryInput(container)!, 0); 36 | expect(fn).toBeCalledWith(['Apple']); 37 | }); 38 | 39 | test('fireChange', () => { 40 | const fn = jest.fn(); 41 | const { container } = render(); 42 | checkbox.fireChange(container, 0); 43 | expect(fn).toBeCalledWith(['Apple']); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/checkbox/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | 7 | /** 8 | * Fires onChange function 9 | */ 10 | export function fireChange(container: IContainer, index: number) { 11 | const selector = `.${getProvider('prefixCls')}-checkbox-input`; 12 | const ele = queryInput(container, index); 13 | if (!ele) throw failedQuerySelector(selector); 14 | fireEvent.click(ele); 15 | } 16 | 17 | /** 18 | * Returns the `index` container 19 | * @param index default is `0` 20 | */ 21 | export function query(container: IContainer, index = 0) { 22 | const selector = `.${getProvider('prefixCls')}-checkbox-wrapper`; 23 | const ele = queryViaSelector(container, selector, index); 24 | return ele; 25 | } 26 | 27 | /** 28 | * Returns the `index` container for checkbox's group 29 | * @param index default is `0` 30 | */ 31 | export function queryGroup(container: IContainer, index = 0) { 32 | const selector = `.${getProvider('prefixCls')}-checkbox-group`; 33 | const ele = queryViaSelector(container, selector, index); 34 | return ele; 35 | } 36 | 37 | /** 38 | * Returns the `index` input inside Checkbox 39 | * @param index default is `0` 40 | */ 41 | export function queryInput(container: IContainer, index = 0) { 42 | const selector = `.${getProvider('prefixCls')}-checkbox-input`; 43 | const ele = queryViaSelector(container, selector, index); 44 | return ele; 45 | } 46 | -------------------------------------------------------------------------------- /src/collapse/__tests__/collapse.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Collapse } from 'antd'; 4 | 5 | import * as collapse from '..'; 6 | 7 | describe("Test Collapse's fire functions", () => { 8 | beforeEach(cleanup); 9 | 10 | test('query', () => { 11 | const fn1 = jest.fn(); 12 | const fn2 = jest.fn(); 13 | const { container } = render( 14 | <> 15 | 16 | 17 | 1 18 | 19 | 20 | 21 | 22 | 1 23 | 24 | 25 | 26 | ); 27 | collapse.fireChange(collapse.query(container, 1)!, 0); 28 | expect(fn1).not.toBeCalled(); 29 | expect(fn2).toBeCalled(); 30 | }); 31 | 32 | test('fireChange', () => { 33 | const fn = jest.fn(); 34 | const { container } = render( 35 | 36 | 37 | 1 38 | 39 | 40 | 2 41 | 42 | 43 | ); 44 | 45 | collapse.fireChange(container, 0); 46 | expect(fn).toBeCalled(); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/collapse/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | 7 | /** 8 | * Fires onChange function 9 | */ 10 | export function fireChange(container: IContainer, index: number) { 11 | const selector = `.${getProvider('prefixCls')}-collapse-header`; 12 | const ele = queryViaSelector(container, selector, index); 13 | if (!ele) throw failedQuerySelector(selector); 14 | fireEvent.click(ele); 15 | } 16 | 17 | /** 18 | * Returns the `index` container of Collapse 19 | */ 20 | export function query(container: IContainer, index = 0) { 21 | const selector = `.${getProvider('prefixCls')}-collapse`; 22 | const ele = queryViaSelector(container, selector, index); 23 | return ele; 24 | } 25 | -------------------------------------------------------------------------------- /src/datePicker/__tests__/datePicker.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { DatePicker } from 'antd'; 4 | import moment from 'moment'; 5 | 6 | import * as datePicker from '..'; 7 | 8 | const dateAdaptor = moment; 9 | 10 | describe("Test DatePicker's fire functions", () => { 11 | beforeEach(cleanup); 12 | 13 | test('query', () => { 14 | const { container, getByTestId } = render( 15 | <> 16 | 17 | 18 | 19 | ); 20 | expect(datePicker.query(container)?.querySelector('input')).toBe(getByTestId('datePicker1')); 21 | expect(datePicker.query(container, 1)?.querySelector('input')).toBe(getByTestId('datePicker2')); 22 | }); 23 | 24 | test('queryInput', () => { 25 | const { container, getByTestId } = render( 26 | <> 27 | 28 | 29 | 30 | ); 31 | expect(datePicker.queryInput(container)).toBe(getByTestId('datePicker1')); 32 | expect(datePicker.queryInput(container, 1)).toBe(getByTestId('datePicker2')); 33 | }); 34 | 35 | test('queryDropdown', () => { 36 | const fn = jest.fn(); 37 | const { container } = render( 38 | node.parentElement!} 42 | /> 43 | ); 44 | datePicker.fireOpen(container); 45 | datePicker.fireChange(datePicker.queryDropdown(container)!, '24'); 46 | expect( 47 | (fn.mock.calls[0][0] as ReturnType).isSame(dateAdaptor('2018-04-24 19:18')) 48 | ).toBeTruthy(); 49 | expect(fn.mock.calls[0][1]).toBe(dateAdaptor('2018-04-24 19:18').format('YYYY-MM-DD')); 50 | }); 51 | 52 | test('querySuperPrevButton', () => { 53 | const { container } = render( 54 | node.parentElement!} /> 55 | ); 56 | datePicker.fireOpen(container); 57 | expect(datePicker.querySuperPrevButton(container)?.nodeName).toBe('BUTTON'); 58 | }); 59 | 60 | test('fireOpen', () => { 61 | const fn = jest.fn(); 62 | const { container } = render(); 63 | datePicker.fireOpen(container); 64 | expect(fn).toBeCalledTimes(1); 65 | }); 66 | 67 | test('fireClose', () => { 68 | const fn = jest.fn(); 69 | const { container } = render(); 70 | datePicker.fireClose(container); 71 | expect(fn).toBeCalledTimes(1); 72 | }); 73 | 74 | test('firePanelChange', () => { 75 | const fn = jest.fn(); 76 | const { container } = render( 77 | node.parentElement!} 81 | /> 82 | ); 83 | datePicker.fireOpen(container); 84 | datePicker.firePanelChange(container); 85 | expect(fn).lastCalledWith(dateAdaptor('2018-04-13 19:18').subtract(1, 'year'), 'date'); 86 | }); 87 | 88 | test('firePanelChange with certain button', () => { 89 | const fn = jest.fn(); 90 | const { container } = render( 91 | node.parentElement!} 95 | /> 96 | ); 97 | datePicker.fireOpen(container); 98 | datePicker.firePanelChange(datePicker.queryPrevButton(container)!); 99 | expect(fn).lastCalledWith(dateAdaptor('2018-04-13 19:18').subtract(1, 'month'), 'date'); 100 | 101 | datePicker.firePanelChange(datePicker.queryNextButton(container)!); 102 | expect(fn).lastCalledWith(dateAdaptor('2018-04-13 19:18'), 'date'); 103 | 104 | datePicker.firePanelChange(datePicker.querySuperNextButton(container)!); 105 | expect(fn).lastCalledWith(dateAdaptor('2018-04-13 19:18').add(1, 'year'), 'date'); 106 | 107 | datePicker.firePanelChange(datePicker.queryMonthButton(container)!); 108 | expect(fn).lastCalledWith(dateAdaptor('2018-04-13 19:18').add(1, 'year'), 'month'); 109 | 110 | datePicker.firePanelChange(datePicker.queryYearButton(container)!); 111 | expect(fn).lastCalledWith(dateAdaptor('2018-04-13 19:18').add(1, 'year'), 'year'); 112 | 113 | datePicker.firePanelChange(datePicker.queryDecadeButton(container)!); 114 | expect(fn).lastCalledWith(dateAdaptor('2018-04-13 19:18').add(1, 'year'), 'decade'); 115 | }); 116 | 117 | test('fireChange', () => { 118 | const fn = jest.fn(); 119 | const { container } = render( 120 | node.parentElement!} 124 | /> 125 | ); 126 | datePicker.fireOpen(container); 127 | datePicker.fireChange(container, '24'); 128 | expect( 129 | (fn.mock.calls[0][0] as ReturnType).isSame(dateAdaptor('2018-04-24 19:18')) 130 | ).toBeTruthy(); 131 | expect(fn.mock.calls[0][1]).toBe(dateAdaptor('2018-04-24 19:18').format('YYYY-MM-DD')); 132 | }); 133 | 134 | test('fireCalendarChange', () => { 135 | const fn = jest.fn(); 136 | const { container } = render( 137 | node.parentElement!} 141 | /> 142 | ); 143 | datePicker.fireOpen(container); 144 | datePicker.fireChange(container, '15'); 145 | 146 | expect(fn).toBeCalled(); 147 | }); 148 | 149 | test('fireOk', () => { 150 | const fn = jest.fn(); 151 | const { container } = render( 152 | node.parentElement!} 157 | /> 158 | ); 159 | 160 | datePicker.fireOpen(container); 161 | datePicker.fireOk(container); 162 | expect(fn).toBeCalledTimes(1); 163 | }); 164 | }); 165 | -------------------------------------------------------------------------------- /src/datePicker/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, failedTriggerElement, queryViaSelector } from '../utils'; 6 | 7 | /** 8 | * Fires onOpenChange function. 9 | * Meanwhile, open Dropdown 10 | */ 11 | export function fireOpen(container: IContainer) { 12 | const selector = 'input'; 13 | const ele = queryInput(container); 14 | if (!ele) throw failedQuerySelector(selector); 15 | fireEvent.mouseDown(ele); 16 | fireEvent.focus(ele); 17 | } 18 | 19 | /** 20 | * Fires onOpenChange function. 21 | * Meanwhile, close dropdown 22 | */ 23 | export function fireClose(container: IContainer) { 24 | const selector = 'input'; 25 | const ele = queryInput(container); 26 | if (!ele) throw failedQuerySelector(selector); 27 | fireEvent.blur(ele); 28 | } 29 | 30 | /** 31 | * Fires onPanelChange function 32 | * @notice there are majority ways to call onPanelChange depends on current panel's status 33 | * 34 | * The sequence of calling onPanelChange is like 35 | * `[super prev] -> [prev] -> [next] -> [super next] -> [month] -> [year] -> [decade]` 36 | * 37 | * _If you intent to call specific button, call firePanelChange with queryXXX_ 38 | * 39 | * @param mode defualt is `date` 40 | */ 41 | export function firePanelChange(container: IContainer) { 42 | const ele = 43 | querySuperPrevButton(container) || 44 | queryPrevButton(container) || 45 | queryNextButton(container) || 46 | querySuperNextButton(container) || 47 | queryMonthButton(container) || 48 | queryYearButton(container) || 49 | queryDecadeButton(container); 50 | if (!ele) throw failedTriggerElement(); 51 | fireEvent.click(ele); 52 | } 53 | 54 | /** 55 | * Fires onChange function or onCalendarChange function for DatePicker.RangePicker 56 | * @notice May **NOT** call onChange certainly, it depends on whether called firePanelChange before 57 | * @param text current text on Panel 58 | */ 59 | export function fireChange(container: IContainer, text: string) { 60 | const eles = container.querySelectorAll('table td'); 61 | const selector = '-in-view'; 62 | const cell = Array.from(eles).find((td) => { 63 | return td.textContent === String(text) && td.className.includes(selector); 64 | }); 65 | if (!cell) throw failedQuerySelector(`end with ${selector}`); 66 | fireEvent.click(cell); 67 | } 68 | 69 | /** 70 | * Fires onOk function 71 | */ 72 | export function fireOk(container: IContainer) { 73 | const selector = `.${getProvider('prefixCls')}-picker-ok > *`; 74 | const ele = queryViaSelector(container, selector); 75 | if (!ele) throw failedQuerySelector(selector); 76 | fireEvent.click(ele); 77 | } 78 | 79 | /** 80 | * Returns the `index` container of DatePicker 81 | * @param index defualt is `0` 82 | */ 83 | export function query(container: IContainer, index = 0) { 84 | const selector = `.${getProvider('prefixCls')}-picker`; 85 | const ele = queryViaSelector(container, selector, index); 86 | return ele; 87 | } 88 | 89 | /** 90 | * Returns the `index` input element in DatePicker 91 | * @param index default is `0` 92 | */ 93 | export function queryInput(container: IContainer, index = 0) { 94 | const selector = `input`; 95 | const ele = queryViaSelector(container, selector, index); 96 | return ele; 97 | } 98 | 99 | /** 100 | * Returns the `index` dropdown's container about DatePicker 101 | * @param index default is `0` 102 | * @returns 103 | */ 104 | export function queryDropdown(container: IContainer, index = 0) { 105 | const selector = `.${getProvider('prefixCls')}-picker-dropdown`; 106 | const ele = queryViaSelector(container, selector, index); 107 | return ele; 108 | } 109 | 110 | /** 111 | * Returns the `index` super prev button 112 | * @param index defualt is `0` 113 | */ 114 | export function querySuperPrevButton(container: IContainer, index = 0) { 115 | const selector = `.${getProvider('prefixCls')}-picker-header-super-prev-btn`; 116 | const ele = queryViaSelector(container, selector, index); 117 | return ele; 118 | } 119 | 120 | /** 121 | * Returns the `index` prev button 122 | * @param index defualt is `0` 123 | */ 124 | export function queryPrevButton(container: IContainer, index = 0) { 125 | const selector = `.${getProvider('prefixCls')}-picker-header-prev-btn`; 126 | const ele = queryViaSelector(container, selector, index); 127 | return ele; 128 | } 129 | 130 | /** 131 | * Returns the `index` super next button 132 | * @param index defualt is `0` 133 | */ 134 | export function querySuperNextButton(container: IContainer, index = 0) { 135 | const selector = `.${getProvider('prefixCls')}-picker-header-super-next-btn`; 136 | const ele = queryViaSelector(container, selector, index); 137 | return ele; 138 | } 139 | 140 | /** 141 | * Returns the `index` next button 142 | * @param index defualt is `0` 143 | */ 144 | export function queryNextButton(container: IContainer, index = 0) { 145 | const selector = `.${getProvider('prefixCls')}-picker-header-next-btn`; 146 | const ele = queryViaSelector(container, selector, index); 147 | return ele; 148 | } 149 | 150 | /** 151 | * Returns the `index` decade button 152 | * @param index default is `0` 153 | */ 154 | export function queryDecadeButton(container: IContainer, index = 0) { 155 | const selector = `.${getProvider('prefixCls')}-picker-decade-btn`; 156 | const ele = queryViaSelector(container, selector, index); 157 | return ele; 158 | } 159 | 160 | /** 161 | * Returns the `index` year button 162 | * @param index default is `0` 163 | */ 164 | export function queryYearButton(container: IContainer, index = 0) { 165 | const selector = `.${getProvider('prefixCls')}-picker-year-btn`; 166 | const ele = queryViaSelector(container, selector, index); 167 | return ele; 168 | } 169 | 170 | /** 171 | * Returns the `index` month button 172 | * @param index default is `0` 173 | */ 174 | export function queryMonthButton(container: IContainer, index = 0) { 175 | const selector = `.${getProvider('prefixCls')}-picker-month-btn`; 176 | const ele = queryViaSelector(container, selector, index); 177 | return ele; 178 | } 179 | -------------------------------------------------------------------------------- /src/drawer/__tests__/drawer.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Drawer } from 'antd'; 4 | 5 | import * as drawer from '..'; 6 | 7 | describe("Test Drawer fire's functions", () => { 8 | beforeEach(cleanup); 9 | 10 | test('fireClose', () => { 11 | const fn = jest.fn(); 12 | const { container } = render(); 13 | drawer.fireClose(container); 14 | expect(fn).toBeCalled(); 15 | }); 16 | 17 | test('fireClose by icon', () => { 18 | const fn = jest.fn(); 19 | const { container } = render(); 20 | drawer.fireClose(container, { closeByMask: true }); 21 | expect(fn).toBeCalled(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/drawer/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | 7 | /** 8 | * Fires onClose function. 9 | * 10 | * Call onClose via close icon by default 11 | */ 12 | export function fireClose(container: IContainer, opt: { closeByMask: boolean } = { closeByMask: true }) { 13 | const selector = opt.closeByMask 14 | ? `.${getProvider('prefixCls')}-drawer-mask` 15 | : `.${getProvider('prefixCls')}-drawer-close`; 16 | const ele = queryViaSelector(container, selector); 17 | if (!ele) throw failedQuerySelector(selector); 18 | fireEvent.click(ele); 19 | } 20 | -------------------------------------------------------------------------------- /src/dropdown/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | export function fireCloseWithESC() { 4 | fireEvent.keyDown(window, { key: 'Esc', keyCode: 27 }); 5 | } 6 | -------------------------------------------------------------------------------- /src/form/__tests__/form.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render, waitFor } from '@testing-library/react'; 3 | import { Button, Form, Input } from 'antd'; 4 | 5 | import * as button from '../../button'; 6 | import * as form from '../'; 7 | 8 | describe("Test form's functions", () => { 9 | beforeEach(() => { 10 | cleanup(); 11 | jest.useFakeTimers(); 12 | }); 13 | afterEach(() => { 14 | jest.useRealTimers(); 15 | }); 16 | 17 | test('query', () => { 18 | const { container } = render( 19 | <> 20 |
21 | 22 | 23 | ); 24 | expect(form.query(container)?.id).toBe('basic'); 25 | expect(form.query(container, 1)?.id).toBe('advance'); 26 | }); 27 | 28 | test('queryFormItems', async () => { 29 | const fn = jest.fn(); 30 | const { container } = render( 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 | ); 40 | button.fireClick(form.queryFormItems(container, 1)!); 41 | await waitFor(() => { 42 | expect(fn).toBeCalledTimes(1); 43 | }); 44 | }); 45 | 46 | test('queryFormItemControls', () => { 47 | const { container } = render( 48 |
49 | 50 | 51 | 52 |
53 | ); 54 | expect(form.queryFormItemControls(container)?.querySelector('label')).toBeNull(); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /src/form/index.ts: -------------------------------------------------------------------------------- 1 | import { IContainer } from '../interface'; 2 | import { getProvider } from '../provider'; 3 | import { queryViaSelector } from '../utils'; 4 | 5 | /** 6 | * Returns the `index` container of Form 7 | * @param index default is `0` 8 | */ 9 | export function query(container: IContainer, index = 0) { 10 | const selector = `.${getProvider('prefixCls')}-form`; 11 | return queryViaSelector(container, selector, index); 12 | } 13 | 14 | /** 15 | * Returns the `index` form item's element 16 | * @param index default is `0` 17 | */ 18 | export function queryFormItems(container: IContainer, index = 0) { 19 | const selector = `.${getProvider('prefixCls')}-form-item`; 20 | return queryViaSelector(container, selector, index); 21 | } 22 | 23 | /** 24 | * Returns the `index` form item's control's element 25 | * @param index default is `0` 26 | */ 27 | export function queryFormItemControls(container: IContainer, index = 0) { 28 | const selector = `.${getProvider('prefixCls')}-form-item-control`; 29 | return queryViaSelector(container, selector, index); 30 | } 31 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * as autoComplete from './autoComplete'; 2 | export * as button from './button'; 3 | export * as cascader from './cascader'; 4 | export * as checkbox from './checkbox'; 5 | export * as collapse from './collapse'; 6 | export * as datePicker from './datePicker'; 7 | export * as drawer from './drawer'; 8 | export * as dropdown from './dropdown'; 9 | export * as form from './form'; 10 | export * as input from './input'; 11 | export * as inputNumber from './inputNumber'; 12 | export * as message from './message'; 13 | export * as modal from './modal'; 14 | export * as pagination from './pagination'; 15 | export * as popconfirm from './popconfirm'; 16 | export { getProvider, getProviders, provider } from './provider'; 17 | export * as radio from './radio'; 18 | export * as select from './select'; 19 | export * as switch from './switch'; 20 | export * as table from './table'; 21 | export * as tabs from './tabs'; 22 | export * as timePicker from './timePicker'; 23 | export * as tooltip from './tooltip'; 24 | export * as transfer from './transfer'; 25 | export * as tree from './tree'; 26 | export * as treeSelect from './treeSelect'; 27 | export * as upload from './upload'; 28 | -------------------------------------------------------------------------------- /src/input/__tests__/input.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import { Input } from 'antd'; 4 | 5 | import * as input from '..'; 6 | 7 | describe("Test input's fire functions", () => { 8 | test('query', () => { 9 | const { container, getByTestId } = render( 10 |
11 | 12 | 13 |
14 | ); 15 | expect(input.query(container)).toBe(getByTestId('input1')); 16 | expect(input.query(container, 1)).toBe(getByTestId('input2')); 17 | }); 18 | 19 | test('fireChange', () => { 20 | const fn = jest.fn(); 21 | const { container } = render(); 22 | input.fireChange(container, 'test'); 23 | 24 | expect(fn).toBeCalled(); 25 | }); 26 | 27 | test('fireFocus', () => { 28 | const fn = jest.fn(); 29 | const { container } = render(); 30 | input.fireFocus(container); 31 | 32 | expect(fn).toBeCalled(); 33 | }); 34 | 35 | test('fireBlur', () => { 36 | const fn = jest.fn(); 37 | const { container } = render(); 38 | input.fireBlur(container); 39 | 40 | expect(fn).toBeCalled(); 41 | }); 42 | 43 | test('fireClear', () => { 44 | const fn = jest.fn(); 45 | const { container } = render(); 46 | input.fireClear(container); 47 | expect(fn).toBeCalled(); 48 | }); 49 | 50 | test('firePressEnter', () => { 51 | const fn = jest.fn(); 52 | const { container } = render(); 53 | input.firePressEnter(container); 54 | 55 | expect(fn).toBeCalled(); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/input/__tests__/textarea.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render, waitFor } from '@testing-library/react'; 3 | import { Input } from 'antd'; 4 | 5 | import * as textarea from '../textarea'; 6 | 7 | describe("Test textarea's fire functions", () => { 8 | beforeEach(cleanup); 9 | test('query', () => { 10 | const { container, getByTestId } = render( 11 | <> 12 | 13 | 14 | 15 | ); 16 | expect(textarea.query(container)).toBe(getByTestId('textarea1')); 17 | expect(textarea.query(container, 1)).toBe(getByTestId('textarea2')); 18 | }); 19 | 20 | test('fireChange', () => { 21 | const fn = jest.fn(); 22 | const { container } = render(); 23 | textarea.fireChange(container, 'test'); 24 | 25 | expect(fn).toBeCalled(); 26 | }); 27 | 28 | test('fireFocus', () => { 29 | const fn = jest.fn(); 30 | const { container } = render(); 31 | textarea.fireFocus(container); 32 | 33 | expect(fn).toBeCalled(); 34 | }); 35 | 36 | test('fireBlur', () => { 37 | const fn = jest.fn(); 38 | const { container } = render(); 39 | textarea.fireBlur(container); 40 | 41 | expect(fn).toBeCalled(); 42 | }); 43 | 44 | test('fireClear', () => { 45 | const fn = jest.fn(); 46 | const { container } = render(); 47 | textarea.fireClear(container); 48 | expect(fn).toBeCalled(); 49 | }); 50 | 51 | test('firePressEnter', () => { 52 | const fn = jest.fn(); 53 | const { container } = render(); 54 | textarea.firePressEnter(container); 55 | 56 | expect(fn).toBeCalled(); 57 | }); 58 | 59 | test('fireResize', async () => { 60 | const fn = jest.fn(); 61 | const { container } = render(); 62 | textarea.fireResize(container, { width: 200, height: 300 } as DOMRect); 63 | 64 | await waitFor(() => { 65 | expect(fn).toBeCalled(); 66 | }); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /src/input/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | 7 | /** 8 | * Fires onFocus function 9 | */ 10 | export function fireFocus(container: IContainer) { 11 | const selector = 'input'; 12 | const inputEl = query(container); 13 | if (!inputEl) throw failedQuerySelector(selector); 14 | fireEvent.focus(inputEl); 15 | } 16 | 17 | /** 18 | * Fires onBlur function 19 | */ 20 | export function fireBlur(container: IContainer) { 21 | const selector = 'input'; 22 | const inputEl = query(container); 23 | if (!inputEl) throw failedQuerySelector(selector); 24 | fireEvent.blur(inputEl); 25 | } 26 | 27 | /** 28 | * Fires onChange function 29 | */ 30 | export function fireChange(container: IContainer, value: any) { 31 | const selector = 'input'; 32 | const inputEl = query(container); 33 | if (!inputEl) throw failedQuerySelector(selector); 34 | fireEvent.change(inputEl, { target: { value } }); 35 | } 36 | 37 | /** 38 | * Fires onClear function 39 | */ 40 | export function fireClear(container: IContainer) { 41 | const selector = `.${getProvider('prefixCls')}-input-clear-icon`; 42 | const ele = 43 | container instanceof HTMLInputElement 44 | ? query(container.parentElement as HTMLElement) 45 | : queryViaSelector(container, selector); 46 | 47 | if (!ele) throw failedQuerySelector(selector); 48 | fireEvent.click(ele); 49 | } 50 | 51 | /** 52 | * Fires onPressEnter function 53 | */ 54 | export function firePressEnter(container: IContainer) { 55 | const selector = 'input'; 56 | const inputEl = query(container); 57 | if (!inputEl) throw failedQuerySelector(selector); 58 | fireEvent.keyDown(inputEl, { key: 'Enter' }); 59 | } 60 | 61 | /** 62 | * Returns the input element 63 | */ 64 | export function query(container: IContainer, index = 0) { 65 | const selector = `input.${getProvider('prefixCls')}-input`; 66 | const ele = queryViaSelector(container, selector, index); 67 | return ele; 68 | } 69 | 70 | export * as textarea from './textarea'; 71 | -------------------------------------------------------------------------------- /src/input/textarea.ts: -------------------------------------------------------------------------------- 1 | import { act, fireEvent } from '@testing-library/react'; 2 | import { _rs as onResize } from 'rc-resize-observer/lib/utils/observerUtil'; 3 | 4 | import type { IContainer } from '../interface'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | import { fireClear as inputFireClear } from '.'; 7 | 8 | /** 9 | * Fires onFocus function 10 | */ 11 | export function fireFocus(container: IContainer) { 12 | const selector = 'textarea'; 13 | const textareaEl = query(container); 14 | if (!textareaEl) throw failedQuerySelector(selector); 15 | fireEvent.focus(textareaEl); 16 | } 17 | 18 | /** 19 | * Fires onBlur function 20 | */ 21 | export function fireBlur(container: IContainer) { 22 | const selector = 'textarea'; 23 | const textareaEl = query(container); 24 | if (!textareaEl) throw failedQuerySelector(selector); 25 | fireEvent.blur(textareaEl); 26 | } 27 | 28 | /** 29 | * Fires onChange functionƒ 30 | */ 31 | export function fireChange(container: IContainer, value: any) { 32 | const selector = 'textarea'; 33 | const textareaEl = query(container); 34 | if (!textareaEl) throw failedQuerySelector(selector); 35 | fireEvent.change(textareaEl, { target: { value } }); 36 | } 37 | 38 | /** 39 | * Fires onClear function 40 | */ 41 | export function fireClear(container: IContainer) { 42 | // directly call input's fireClear 43 | inputFireClear(container); 44 | } 45 | 46 | /** 47 | * Fires onClear function 48 | */ 49 | export function firePressEnter(container: IContainer) { 50 | const selector = 'textarea'; 51 | const textareaEl = query(container); 52 | if (!textareaEl) throw failedQuerySelector(selector); 53 | fireEvent.keyDown(textareaEl, { keyCode: 13 }); 54 | } 55 | 56 | /** 57 | * Fires onResize function 58 | */ 59 | export function fireResize(container: IContainer, rect: DOMRect) { 60 | const selector = 'textarea'; 61 | const textareaEl = query(container); 62 | if (!textareaEl) throw failedQuerySelector(selector); 63 | const originGetBoundingClientRect = textareaEl.getBoundingClientRect; 64 | textareaEl.getBoundingClientRect = () => rect; 65 | 66 | act(() => { 67 | onResize([{ target: textareaEl } as unknown as ResizeObserverEntry]); 68 | }); 69 | 70 | textareaEl.getBoundingClientRect = originGetBoundingClientRect; 71 | } 72 | 73 | /** 74 | * Returns the textarea element 75 | */ 76 | export function query(container: IContainer, index = 0) { 77 | const selector = 'textarea'; 78 | return queryViaSelector(container, selector, index); 79 | } 80 | -------------------------------------------------------------------------------- /src/inputNumber/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | 7 | /** 8 | * Fires onChange function 9 | */ 10 | export function fireChange(container: IContainer, value: any) { 11 | const selector = `input.${getProvider('prefixCls')}-input-number-input`; 12 | const ele = queryInput(container); 13 | if (!ele) throw failedQuerySelector(selector); 14 | fireEvent.change(ele, { target: { value } }); 15 | } 16 | 17 | /** 18 | * Fires onStepUp function 19 | */ 20 | export function fireStepUp(container: IContainer) { 21 | const selector = `.${getProvider('prefixCls')}-input-number-handler-up`; 22 | const ele = queryViaSelector(container, selector); 23 | if (!ele) throw failedQuerySelector(selector); 24 | fireEvent.mouseDown(ele); 25 | } 26 | 27 | /** 28 | * Fires onStepDown function 29 | */ 30 | export function fireStepDown(container: IContainer) { 31 | const selector = `.${getProvider('prefixCls')}-input-number-handler-down`; 32 | const ele = queryViaSelector(container, selector); 33 | if (!ele) throw failedQuerySelector(selector); 34 | fireEvent.mouseDown(ele); 35 | } 36 | 37 | /** 38 | * Fires onPressEnter function 39 | */ 40 | export function firePressEnter(container: IContainer) { 41 | const selector = `input.${getProvider('prefixCls')}-input-number-input`; 42 | const inputEl = queryInput(container); 43 | if (!inputEl) throw failedQuerySelector(selector); 44 | fireEvent.keyDown(inputEl, { key: 'Enter' }); 45 | } 46 | 47 | /** 48 | * Fires onFocus function 49 | */ 50 | export function fireFocus(container: IContainer) { 51 | const selector = `input.${getProvider('prefixCls')}-input-number-input`; 52 | const inputEl = queryInput(container); 53 | if (!inputEl) throw failedQuerySelector(selector); 54 | fireEvent.focus(inputEl); 55 | } 56 | 57 | /** 58 | * Fires onBlur function 59 | */ 60 | export function fireBlur(container: IContainer) { 61 | const selector = `input.${getProvider('prefixCls')}-input-number-input`; 62 | const inputEl = queryInput(container); 63 | if (!inputEl) throw failedQuerySelector(selector); 64 | fireEvent.blur(inputEl); 65 | } 66 | 67 | /** 68 | * Returns the container of InputNumber 69 | */ 70 | export function query(container: IContainer, index = 0) { 71 | const selector = `.${getProvider('prefixCls')}-input-number`; 72 | const ele = queryViaSelector(container, selector, index); 73 | return ele; 74 | } 75 | 76 | /** 77 | * Returns the input element of InputNumber 78 | */ 79 | export function queryInput(container: IContainer, index = 0) { 80 | const selector = `input.${getProvider('prefixCls')}-input-number-input`; 81 | const ele = queryViaSelector(container, selector, index); 82 | return ele; 83 | } 84 | -------------------------------------------------------------------------------- /src/interface.ts: -------------------------------------------------------------------------------- 1 | export type IContainer = HTMLElement | Document; 2 | -------------------------------------------------------------------------------- /src/message/__tests__/message.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Button, message as Message } from 'antd'; 4 | 5 | import * as button from '../../button'; 6 | import * as message from '../index'; 7 | 8 | describe('Test Message', () => { 9 | beforeEach(() => { 10 | cleanup(); 11 | document.body.innerHTML = ''; 12 | jest.useFakeTimers(); 13 | }); 14 | afterEach(() => { 15 | jest.useRealTimers(); 16 | Message.destroy(); 17 | }); 18 | 19 | it('query', () => { 20 | const { container } = render(); 21 | button.fireClick(container); 22 | expect(message.query(document)).not.toBeNull(); 23 | }); 24 | 25 | it('fireClick', () => { 26 | const fn = jest.fn(); 27 | const { container } = render( 28 | 38 | ); 39 | button.fireClick(container); 40 | message.fireClick(document); 41 | expect(fn).toBeCalledTimes(1); 42 | }); 43 | 44 | it('fireClose', async () => { 45 | const fn = jest.fn(); 46 | const { container } = render( 47 | 58 | ); 59 | button.fireClick(container); 60 | await message.fireClose(4000); 61 | expect(fn).toBeCalledTimes(1); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /src/message/index.ts: -------------------------------------------------------------------------------- 1 | import { act, fireEvent } from '@testing-library/react'; 2 | 3 | import { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | 7 | /** 8 | * Fires onClick function 9 | */ 10 | export function fireClick(container: IContainer) { 11 | const ele = queryContent(container); 12 | if (!ele) throw failedQuerySelector(`.${getProvider('prefixCls')}-notice-content`); 13 | fireEvent.click(ele); 14 | } 15 | 16 | /** 17 | * Fires onClose function by waiting duration 18 | * @param {number} duration ms 19 | */ 20 | export async function fireClose(duration = 3000) { 21 | for (let i = 0; i < 10; i += 1) { 22 | // eslint-disable-next-line no-await-in-loop 23 | await Promise.resolve(); 24 | } 25 | 26 | act(() => { 27 | jest.advanceTimersByTime(duration); 28 | }); 29 | } 30 | 31 | /** 32 | * Returns the container element 33 | */ 34 | export function query(container: IContainer, index = 0) { 35 | const selector = `.${getProvider('prefixCls')}-message`; 36 | const ele = queryViaSelector(container, selector, index); 37 | return ele; 38 | } 39 | 40 | /** 41 | * Returns the content element 42 | */ 43 | export function queryContent(container: IContainer, index = 0) { 44 | const selector = `.${getProvider('prefixCls')}-message-notice-content`; 45 | const ele = queryViaSelector(container, selector, index); 46 | return ele; 47 | } 48 | -------------------------------------------------------------------------------- /src/modal/__tests__/confirm.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Modal } from 'antd'; 4 | 5 | import { getProvider } from '../../provider'; 6 | import * as confirm from '../confirm'; 7 | 8 | function Confirm({ onOk, onCancel }: any) { 9 | const handleConfirm = () => { 10 | Modal.confirm({ 11 | title: 'Do you Want to delete these items?', 12 | onOk, 13 | onCancel, 14 | }); 15 | }; 16 | 17 | return ( 18 | 21 | ); 22 | } 23 | 24 | describe("Test confirm's fire functions", () => { 25 | beforeEach(() => { 26 | cleanup(); 27 | jest.useFakeTimers(); 28 | document.body.innerHTML = ''; 29 | }); 30 | 31 | afterEach(() => { 32 | jest.useRealTimers(); 33 | }); 34 | 35 | test('query', () => { 36 | const { getByTestId } = render(); 37 | confirm.fireOpen(getByTestId('trigger')); 38 | expect(confirm.query(document)).not.toBeNull(); 39 | }); 40 | 41 | test('queryBtns', () => { 42 | const { getByTestId } = render(); 43 | confirm.fireOpen(getByTestId('trigger')); 44 | expect(confirm.queryBtns(document)).not.toBeNull(); 45 | }); 46 | 47 | test('queryCancelButton', () => { 48 | const fn = jest.fn(); 49 | const { getByTestId } = render(); 50 | confirm.fireOpen(getByTestId('trigger')); 51 | confirm.fireCancel(confirm.queryCancelButton(document)!); 52 | expect(fn).toBeCalled(); 53 | }); 54 | 55 | test('queryOkButton', () => { 56 | const fn = jest.fn(); 57 | const { getByTestId } = render(); 58 | confirm.fireOpen(getByTestId('trigger')); 59 | confirm.fireOk(confirm.queryOkButton(document)!); 60 | expect(fn).toBeCalled(); 61 | }); 62 | 63 | test('fireOpen', () => { 64 | const fn = jest.fn(); 65 | const { getByTestId } = render(); 66 | confirm.fireOpen(getByTestId('trigger')); 67 | 68 | expect(document.querySelector(`.${getProvider('prefixCls')}-modal-root`)).not.toBeNull(); 69 | }); 70 | 71 | test('fireOk', () => { 72 | const fn = jest.fn(); 73 | const { getByTestId } = render(); 74 | confirm.fireOpen(getByTestId('trigger')); 75 | confirm.fireOk(document.body); 76 | expect(fn).toBeCalled(); 77 | }); 78 | 79 | test('fireCancel', () => { 80 | const fn = jest.fn(); 81 | const { getByTestId } = render(); 82 | confirm.fireOpen(getByTestId('trigger')); 83 | confirm.fireCancel(document.body); 84 | expect(fn).toBeCalled(); 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /src/modal/__tests__/modal.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Modal } from 'antd'; 4 | 5 | import * as modal from '..'; 6 | 7 | describe("Test Modal fire's functions", () => { 8 | beforeEach(cleanup); 9 | 10 | test('queryModalFooter', () => { 11 | const { container } = render(); 12 | expect(modal.queryModalFooter(container)).not.toBeNull(); 13 | }); 14 | 15 | test('queryCancelButton', () => { 16 | const fn = jest.fn(); 17 | const { container } = render(); 18 | modal.fireCancel(modal.queryCancelButton(container)!); 19 | expect(fn).toBeCalled(); 20 | }); 21 | 22 | test('queryOkButton', () => { 23 | const fn = jest.fn(); 24 | const { container } = render(); 25 | modal.fireOk(modal.queryOkButton(container)!); 26 | expect(fn).toBeCalled(); 27 | }); 28 | 29 | test('fireCancel', () => { 30 | const fn = jest.fn(); 31 | const { container } = render(); 32 | modal.fireCancel(container); 33 | expect(fn).toBeCalled(); 34 | }); 35 | 36 | test('fireCancel with queryMask', () => { 37 | const fn = jest.fn(); 38 | const { container } = render(); 39 | modal.fireCancel(modal.queryMask(container)!); 40 | expect(fn).toBeCalled(); 41 | }); 42 | 43 | test('fireOk', () => { 44 | const fn = jest.fn(); 45 | const { container } = render(); 46 | modal.fireOk(container); 47 | expect(fn).toBeCalled(); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/modal/confirm.ts: -------------------------------------------------------------------------------- 1 | import { act, fireEvent } from '@testing-library/react'; 2 | 3 | import * as button from '../button'; 4 | import type { IContainer } from '../interface'; 5 | import { getProvider } from '../provider'; 6 | import { failedTriggerElement, queryViaSelector } from '../utils'; 7 | import * as modal from './'; 8 | 9 | /** 10 | * Open confirm 11 | * @prerequisite call `jest.useFakeTimers()` 12 | */ 13 | export function fireOpen(ele?: HTMLElement) { 14 | if (!ele) throw failedTriggerElement(); 15 | 16 | act(() => { 17 | fireEvent.click(ele); 18 | jest.runAllTimers(); 19 | }); 20 | } 21 | 22 | /** 23 | * Fires onOk function 24 | */ 25 | export function fireOk(container: IContainer) { 26 | const ele = queryOkButton(container); 27 | if (!ele) throw failedTriggerElement(); 28 | fireEvent.click(ele); 29 | } 30 | 31 | /** 32 | * Fires onCancel function 33 | */ 34 | export function fireCancel(container: IContainer) { 35 | const ele = queryCancelButton(container); 36 | if (!ele) throw failedTriggerElement(); 37 | fireEvent.click(ele); 38 | } 39 | 40 | /** 41 | * Returns the container element 42 | */ 43 | export function query(container: IContainer, index = 0) { 44 | return modal.query(container, index); 45 | } 46 | 47 | /** 48 | * Returns the btns area inside Modal.confirm 49 | */ 50 | export function queryBtns(container: IContainer, index = 0) { 51 | const selector = `.${getProvider('prefixCls')}-modal-confirm-btns`; 52 | const ele = queryViaSelector(container, selector, index); 53 | return ele; 54 | } 55 | 56 | /** 57 | * Returns the cancel button 58 | */ 59 | export function queryCancelButton(container: IContainer, index = 0) { 60 | if (container instanceof HTMLButtonElement) { 61 | return container; 62 | } 63 | const btns = queryBtns(container, index); 64 | if (!btns) return null; 65 | return button.query(btns, 0); 66 | } 67 | 68 | /** 69 | * Returns the Ok button 70 | */ 71 | export function queryOkButton(container: IContainer, index = 0) { 72 | if (container instanceof HTMLButtonElement) { 73 | return container; 74 | } 75 | const btns = queryBtns(container, index); 76 | if (!btns) return null; 77 | return button.query(btns, 1); 78 | } 79 | -------------------------------------------------------------------------------- /src/modal/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import * as button from '../button'; 4 | import type { IContainer } from '../interface'; 5 | import { getProvider } from '../provider'; 6 | import { failedTriggerElement, queryViaSelector } from '../utils'; 7 | 8 | /** 9 | * Fires onOk function 10 | */ 11 | export function fireOk(container: IContainer) { 12 | const ele = queryOkButton(container); 13 | if (!ele) throw failedTriggerElement(); 14 | fireEvent.click(ele); 15 | } 16 | 17 | /** 18 | * Fires onCancel function 19 | * @notice Since there are two ways to call onCancel, called via cancel button by default. 20 | * If you intent to call onCancel by mask clicked, please call fireCancel with queryMask 21 | */ 22 | export function fireCancel(container: IContainer) { 23 | const ele = queryCancelButton(container) || queryMask(container); 24 | if (!ele) throw failedTriggerElement(); 25 | fireEvent.click(ele); 26 | } 27 | 28 | /** 29 | * Returns the `index` container root element of Modal 30 | */ 31 | export function query(container: IContainer, index = 0) { 32 | const selector = `.${getProvider('prefixCls')}-modal`; 33 | const ele = queryViaSelector(container, selector, index); 34 | return ele; 35 | } 36 | 37 | /** 38 | * Returns the `index` footer element 39 | */ 40 | export function queryModalFooter(container: IContainer, index = 0) { 41 | const selector = `.${getProvider('prefixCls')}-modal-footer`; 42 | const ele = queryViaSelector(container, selector, index); 43 | return ele; 44 | } 45 | 46 | /** 47 | * Returns the cancel button 48 | */ 49 | export function queryCancelButton(container: IContainer, index = 0) { 50 | if (container instanceof HTMLButtonElement) { 51 | return container; 52 | } 53 | const ele = queryModalFooter(container, index); 54 | if (!ele) return null; 55 | return button.query(ele, 0); 56 | } 57 | 58 | /** 59 | * Returns the ok button 60 | */ 61 | export function queryOkButton(container: IContainer, index = 0) { 62 | if (container instanceof HTMLButtonElement) { 63 | return container; 64 | } 65 | const ele = queryModalFooter(container, index); 66 | if (!ele) return null; 67 | return button.query(ele, 1); 68 | } 69 | 70 | /** 71 | * Returns the mask element 72 | */ 73 | export function queryMask(container: IContainer, index = 0) { 74 | const selector = `.${getProvider('prefixCls')}-modal-close`; 75 | const ele = queryViaSelector(container, selector, index); 76 | return ele; 77 | } 78 | 79 | export * as confirm from './confirm'; 80 | -------------------------------------------------------------------------------- /src/pagination/__tests__/pagination.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Pagination } from 'antd'; 4 | 5 | import * as pagination from '../'; 6 | 7 | describe('Test Pagination', () => { 8 | beforeEach(() => { 9 | cleanup(); 10 | jest.useFakeTimers(); 11 | }); 12 | 13 | afterEach(() => { 14 | jest.useRealTimers(); 15 | }); 16 | 17 | it('query', () => { 18 | const { container } = render(); 19 | expect(pagination.query(container)).not.toBeNull(); 20 | }); 21 | 22 | it('queryPrevButton', () => { 23 | const { container } = render(); 24 | expect(pagination.queryPrevButton(container)).not.toBeNull(); 25 | }); 26 | 27 | it('queryNextButton', () => { 28 | const { container } = render(); 29 | expect(pagination.queryNextButton(container)).not.toBeNull(); 30 | }); 31 | 32 | it('queryPaginationItem', () => { 33 | const { container } = render(); 34 | expect(pagination.queryPaginationItem(container, 1)).not.toBeNull(); 35 | }); 36 | 37 | it('fireSizeChange', () => { 38 | const fn = jest.fn(); 39 | const { container } = render(); 40 | pagination.fireSizeOpen(container); 41 | pagination.fireSizeChange(container, 1); 42 | expect(fn).toBeCalledWith(6, 20); 43 | }); 44 | 45 | it('fireChange', () => { 46 | const fn = jest.fn(); 47 | const { container } = render(); 48 | pagination.fireChange(container); 49 | expect(fn).toBeCalledWith(2, 10); 50 | }); 51 | 52 | it('fireChange with queryPrevButton', () => { 53 | const fn = jest.fn(); 54 | const { container } = render(); 55 | pagination.fireChange(container); 56 | expect(fn).toBeCalledWith(2, 10); 57 | pagination.fireChange(pagination.queryPrevButton(container)!); 58 | expect(fn).toBeCalledWith(1, 10); 59 | }); 60 | 61 | it('fireChange with specific item', () => { 62 | const fn = jest.fn(); 63 | const { container } = render(); 64 | pagination.fireChange(pagination.queryPaginationItem(container, 3)!); 65 | expect(fn).toBeCalledWith(3, 10); 66 | }); 67 | 68 | it('fireChange with jump next', () => { 69 | const fn = jest.fn(); 70 | const { container } = render(); 71 | pagination.fireChange(pagination.queryJumpNext(container)!); 72 | expect(fn).toBeCalledWith(6, 10); 73 | }); 74 | 75 | it('fireChange with jump prev', () => { 76 | const fn = jest.fn(); 77 | const { container } = render(); 78 | pagination.fireChange(pagination.queryJumpPrev(container)!); 79 | expect(fn).toBeCalledWith(1, 10); 80 | }); 81 | 82 | it('fireChange with quick jump', () => { 83 | const fn = jest.fn(); 84 | const { container } = render(); 85 | pagination.fireChange(pagination.queryQuickJump(container)!, 20); 86 | expect(fn).toBeCalledWith(20, 10); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /src/pagination/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import * as select from '../select'; 6 | import { failedTriggerElement, queryViaSelector, queryViaSelectors } from '../utils'; 7 | 8 | /** 9 | * Fires pageSize's dropdown open 10 | */ 11 | export function fireSizeOpen(container: IContainer) { 12 | select.fireOpen(container); 13 | } 14 | /** 15 | * Fires onShowSizeChange function 16 | */ 17 | export function fireSizeChange(container: IContainer, index: number) { 18 | const dropdown = select.queryDropdown(container); 19 | if (!dropdown) throw failedTriggerElement(); 20 | select.fireSelect(dropdown, index); 21 | } 22 | /** 23 | * Fires onChange function 24 | * @notice there are majority ways to call onChange 25 | * 26 | * The sequence of calling onChange is like 27 | * `[next button] -> [prev button] -> [container self]` 28 | * 29 | * _If you intent to call specific button, call fireChange with queryXXX_ 30 | */ 31 | export function fireChange(container: HTMLInputElement, value: number): void; 32 | export function fireChange(Container: IContainer): void; 33 | export function fireChange(container: IContainer, value?: number) { 34 | if (container instanceof HTMLInputElement) { 35 | if (!value) throw new Error('Call quick jump must pass through value'); 36 | fireEvent.focus(container); 37 | fireEvent.change(container, { target: { value } }); 38 | fireEvent.blur(container); 39 | } else { 40 | const ele = queryNextButton(container) || queryPrevButton(container) || container; 41 | if (!ele) throw failedTriggerElement(); 42 | fireEvent.click(ele); 43 | } 44 | } 45 | 46 | /** 47 | * Returns the container 48 | */ 49 | export function query(container: IContainer, index = 0) { 50 | const selector = `.${getProvider('prefixCls')}-pagination`; 51 | const ele = queryViaSelector(container, selector, index); 52 | return ele; 53 | } 54 | 55 | /** 56 | * Returns the prev button element 57 | */ 58 | export function queryPrevButton(container: IContainer, index = 0) { 59 | const selectors = [ 60 | `.${getProvider('prefixCls')}-pagination-prev`, 61 | `.${getProvider('prefixCls')}-pagination-item-link`, 62 | ]; 63 | const ele = queryViaSelectors(container, selectors, [index]); 64 | return ele; 65 | } 66 | 67 | /** 68 | * Returns the next button element 69 | */ 70 | export function queryNextButton(container: IContainer, index = 0) { 71 | const selectors = [ 72 | `.${getProvider('prefixCls')}-pagination-next`, 73 | `.${getProvider('prefixCls')}-pagination-item-link`, 74 | ]; 75 | const ele = queryViaSelectors(container, selectors, [index]); 76 | return ele; 77 | } 78 | 79 | /** 80 | * Returns the pagination item element 81 | * @index page number 82 | */ 83 | export function queryPaginationItem(container: IContainer, index: number) { 84 | if (index === 0) { 85 | console.warn('Page number should not start from 0'); 86 | return null; 87 | } 88 | const selector = `.${getProvider('prefixCls')}-pagination-item-${index}`; 89 | const ele = queryViaSelector(container, selector, 0); 90 | return ele; 91 | } 92 | 93 | /** 94 | * Returns the jump next element 95 | */ 96 | export function queryJumpNext(container: IContainer, index = 0) { 97 | const selector = `.${getProvider('prefixCls')}-pagination-jump-next`; 98 | const ele = queryViaSelector(container, selector, index); 99 | return ele; 100 | } 101 | 102 | /** 103 | * Returns the jump prev element 104 | */ 105 | export function queryJumpPrev(container: IContainer, index = 0) { 106 | const selector = `.${getProvider('prefixCls')}-pagination-jump-prev`; 107 | const ele = queryViaSelector(container, selector, index); 108 | return ele; 109 | } 110 | 111 | /** 112 | * Returns the quick jump input element 113 | */ 114 | export function queryQuickJump(container: IContainer, index = 0) { 115 | const selectors = [`.${getProvider('prefixCls')}-pagination-options-quick-jumper`, 'input']; 116 | const ele = queryViaSelectors(container, selectors, [index]); 117 | return ele; 118 | } 119 | -------------------------------------------------------------------------------- /src/popconfirm/__tests__/popconfirm.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Button, Popconfirm } from 'antd'; 4 | 5 | import * as button from '../../button'; 6 | import * as confirm from '..'; 7 | 8 | describe("Test popconfirm fire's functions", () => { 9 | beforeEach(() => { 10 | cleanup(); 11 | jest.useFakeTimers(); 12 | }); 13 | 14 | afterEach(() => { 15 | jest.useRealTimers(); 16 | }); 17 | 18 | test('query', () => { 19 | const { container } = render( 20 | node.parentElement!}> 21 | 22 | 23 | ); 24 | confirm.fireOpen(button.query(container)!); 25 | expect(confirm.query(container)).not.toBeNull(); 26 | }); 27 | 28 | test('queryButtons', () => { 29 | const { container } = render( 30 | node.parentElement!}> 31 | 32 | 33 | ); 34 | confirm.fireOpen(button.query(container)!); 35 | expect(confirm.queryButtons(container)).not.toBeNull(); 36 | }); 37 | 38 | test('queryCancelButton', () => { 39 | const fn = jest.fn(); 40 | const { container } = render( 41 | node.parentElement!}> 42 | 43 | 44 | ); 45 | confirm.fireOpen(button.query(container)!); 46 | confirm.fireCancel(confirm.queryCancelButton(container)!); 47 | expect(fn).toBeCalled(); 48 | }); 49 | 50 | test('queryConfirmButton', () => { 51 | const fn = jest.fn(); 52 | const { container } = render( 53 | node.parentElement!}> 54 | 55 | 56 | ); 57 | confirm.fireOpen(button.query(container)!); 58 | confirm.fireConfirm(confirm.queryConfirmButton(container)!); 59 | expect(fn).toBeCalled(); 60 | }); 61 | 62 | test('fireOpen', () => { 63 | const fn = jest.fn(); 64 | const { container } = render( 65 | node.parentElement!}> 66 | 67 | 68 | ); 69 | confirm.fireOpen(button.query(container)!); 70 | expect(fn).toBeCalledTimes(1); 71 | }); 72 | 73 | test('fireCancel', () => { 74 | const fn = jest.fn(); 75 | const { container } = render( 76 | node.parentElement!}> 77 | 78 | 79 | ); 80 | confirm.fireOpen(button.query(container)!); 81 | confirm.fireCancel(container); 82 | expect(fn).toBeCalled(); 83 | }); 84 | 85 | test('fireConfirm', () => { 86 | const fn = jest.fn(); 87 | const { container } = render( 88 | node.parentElement!}> 89 | 90 | 91 | ); 92 | confirm.fireOpen(button.query(container)!); 93 | confirm.fireConfirm(container); 94 | expect(fn).toBeCalled(); 95 | }); 96 | }); 97 | -------------------------------------------------------------------------------- /src/popconfirm/index.ts: -------------------------------------------------------------------------------- 1 | import { act, fireEvent } from '@testing-library/react'; 2 | 3 | import * as button from '../button'; 4 | import type { IContainer } from '../interface'; 5 | import { getProvider } from '../provider'; 6 | import { failedQuerySelector, failedTriggerElement, queryViaSelector } from '../utils'; 7 | 8 | /** 9 | * Open popconfirm 10 | */ 11 | export function fireOpen(trigger: HTMLElement) { 12 | if (!trigger) throw failedTriggerElement(); 13 | act(() => { 14 | jest.runAllTimers(); 15 | fireEvent.click(trigger); 16 | }); 17 | } 18 | 19 | /** 20 | * Fires onCancel function 21 | */ 22 | export function fireCancel(container: IContainer) { 23 | const selector = `.${getProvider('prefixCls')}-popover-buttons .${getProvider('prefixCls')}-btn`; 24 | const ele = queryCancelButton(container); 25 | if (!ele) throw failedQuerySelector(selector); 26 | fireEvent.click(ele); 27 | } 28 | 29 | /** 30 | * Fires onConfirm function 31 | */ 32 | export function fireConfirm(container: IContainer) { 33 | const selector = `.${getProvider('prefixCls')}-popover-buttons .${getProvider('prefixCls')}-btn`; 34 | const ele = queryConfirmButton(container); 35 | if (!ele) throw failedQuerySelector(selector); 36 | fireEvent.click(ele); 37 | } 38 | 39 | /** 40 | * Returns the container element 41 | */ 42 | export function query(container: IContainer, index = 0) { 43 | const selector = `.${getProvider('prefixCls')}-popover`; 44 | const ele = queryViaSelector(container, selector, index); 45 | return ele; 46 | } 47 | 48 | /** 49 | * Returns the buttons element 50 | */ 51 | export function queryButtons(container: IContainer, index = 0) { 52 | const selector = `.${getProvider('prefixCls')}-popover-buttons`; 53 | const ele = queryViaSelector(container, selector, index); 54 | return ele; 55 | } 56 | 57 | /** 58 | * Returns the cancel button inside buttons 59 | */ 60 | export function queryCancelButton(container: IContainer, index = 0) { 61 | if (container instanceof HTMLButtonElement) { 62 | return container; 63 | } 64 | const ele = queryButtons(container, index); 65 | if (!ele) return null; 66 | return button.query(ele, 0); 67 | } 68 | 69 | /** 70 | * Returns the confirm button inside buttons 71 | */ 72 | export function queryConfirmButton(container: IContainer, index = 0) { 73 | if (container instanceof HTMLButtonElement) { 74 | return container; 75 | } 76 | const ele = queryButtons(container, index); 77 | if (!ele) return null; 78 | return button.query(ele, 1); 79 | } 80 | -------------------------------------------------------------------------------- /src/provider/index.ts: -------------------------------------------------------------------------------- 1 | const globalConfig = { 2 | prefixCls: 'rc', 3 | }; 4 | 5 | export function getProviders() { 6 | return globalConfig; 7 | } 8 | 9 | export function getProvider(key: keyof typeof globalConfig) { 10 | return globalConfig[key]; 11 | } 12 | 13 | export function provider(opt: Partial) { 14 | Object.assign(globalConfig, opt); 15 | } 16 | -------------------------------------------------------------------------------- /src/radio/__tests__/radio.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Radio } from 'antd'; 4 | 5 | import * as radio from '..'; 6 | 7 | describe("Test Radio's fire functions", () => { 8 | beforeEach(cleanup); 9 | 10 | test('query', () => { 11 | const { container } = render(Radio); 12 | expect(radio.query(container)).not.toBeNull(); 13 | }); 14 | 15 | test('queryGroup', () => { 16 | const { container } = render(); 17 | expect(radio.queryGroup(container)).not.toBeNull(); 18 | }); 19 | 20 | test('queryInput', () => { 21 | const { container } = render(); 22 | expect(radio.queryInput(container)).not.toBeNull(); 23 | }); 24 | 25 | test('fireMouseEnter', () => { 26 | const fn = jest.fn(); 27 | const { container } = render(Radio); 28 | 29 | radio.fireMouseEnter(container); 30 | expect(fn).toBeCalledTimes(1); 31 | }); 32 | 33 | test('fireMouseEnter with group', () => { 34 | const fn = jest.fn(); 35 | const { container } = render( 36 | 37 | A 38 | 39 | ); 40 | 41 | radio.fireMouseEnter(container); 42 | expect(fn).toBeCalledTimes(1); 43 | }); 44 | 45 | test('fireMouseLeave', () => { 46 | const fn = jest.fn(); 47 | const { container } = render(Radio); 48 | 49 | radio.fireMouseLeave(container); 50 | expect(fn).toBeCalledTimes(1); 51 | }); 52 | 53 | test('fireMouseLeave with group', () => { 54 | const fn = jest.fn(); 55 | const { container } = render( 56 | 57 | A 58 | 59 | ); 60 | 61 | radio.fireMouseLeave(container); 62 | expect(fn).toBeCalledTimes(1); 63 | }); 64 | 65 | test('fireChange', () => { 66 | const fn = jest.fn(); 67 | const { container } = render( 68 | 69 | A 70 | B 71 | 72 | ); 73 | 74 | radio.fireChange(container, 1); 75 | expect(fn).toBeCalledTimes(1); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /src/radio/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | 7 | /** 8 | * Fires onMouseEnter function 9 | */ 10 | export function fireMouseEnter(container: IContainer) { 11 | const ele = queryGroup(container) || query(container); 12 | if (!ele) throw failedQuerySelector('radio'); 13 | fireEvent.mouseEnter(ele); 14 | } 15 | 16 | /** 17 | * Fires onMouseLeave function 18 | */ 19 | export function fireMouseLeave(container: IContainer) { 20 | const ele = queryGroup(container) || query(container); 21 | if (!ele) throw failedQuerySelector('radio'); 22 | fireEvent.mouseLeave(ele); 23 | } 24 | 25 | /** 26 | * Fires onChange function 27 | */ 28 | export function fireChange(container: IContainer, index: number) { 29 | const ele = queryInput(container, index); 30 | if (!ele) throw failedQuerySelector(`input.${getProvider('prefixCls')}-radio-input`); 31 | fireEvent.click(ele); 32 | } 33 | 34 | /** 35 | * Returns the wrapper element for each Radio 36 | */ 37 | export function query(container: IContainer, index = 0) { 38 | const selector = `.${getProvider('prefixCls')}-radio-wrapper`; 39 | const ele = queryViaSelector(container, selector, index); 40 | return ele; 41 | } 42 | 43 | /** 44 | * Returns the group element 45 | */ 46 | export function queryGroup(container: IContainer, index = 0) { 47 | const selector = `.${getProvider('prefixCls')}-radio-group`; 48 | const ele = queryViaSelector(container, selector, index); 49 | return ele; 50 | } 51 | 52 | /** 53 | * Returns the input element in Radio 54 | */ 55 | export function queryInput(container: IContainer, index = 0) { 56 | const selector = `input.${getProvider('prefixCls')}-radio-input`; 57 | const ele = queryViaSelector(container, selector, index); 58 | return ele; 59 | } 60 | -------------------------------------------------------------------------------- /src/select/__tests__/select.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Select } from 'antd'; 4 | 5 | import * as select from '..'; 6 | 7 | describe('Test Select fire functions', () => { 8 | beforeEach(() => { 9 | jest.useFakeTimers(); 10 | document.body.innerHTML = ''; 11 | cleanup(); 12 | }); 13 | 14 | afterEach(() => { 15 | jest.useRealTimers(); 16 | }); 17 | 18 | test('query', () => { 19 | const { container, getByTestId } = render( 20 | <> 21 | 23 | 24 | ); 25 | expect(select.query(container)).toBe(getByTestId('select1')); 26 | expect(select.query(container, 1)).toBe(getByTestId('select2')); 27 | }); 28 | 29 | test('queryInput', () => { 30 | const fn1 = jest.fn(); 31 | const fn2 = jest.fn(); 32 | const { container } = render( 33 | <> 34 | 36 | 37 | ); 38 | select.fireSearch(select.queryInput(container)!, 'test1'); 39 | select.fireSearch(select.queryInput(container, 1)!, 'test2'); 40 | expect(fn1).toBeCalledWith('test1'); 41 | expect(fn2).toBeCalledWith('test2'); 42 | }); 43 | 44 | test('querySelector', () => { 45 | const fn1 = jest.fn(); 46 | const fn2 = jest.fn(); 47 | const { container } = render( 48 | <> 49 | 51 | 52 | ); 53 | select.fireOpen(select.querySelector(container)!); 54 | expect(fn1).toBeCalledTimes(1); 55 | select.fireOpen(select.querySelector(container, 1)!); 56 | expect(fn2).toBeCalledTimes(1); 57 | }); 58 | 59 | test('queryDropdown', () => { 60 | const fn1 = jest.fn(); 61 | const fn2 = jest.fn(); 62 | const { container } = render( 63 | <> 64 | 66 | 67 | ); 68 | select.fireOpen(select.querySelector(container)!); 69 | select.fireSelect(select.queryDropdown(document)!, 0); 70 | expect(fn1).toBeCalledWith(1, expect.objectContaining({ label: 1, value: 1 })); 71 | select.fireOpen(select.querySelector(container, 1)!); 72 | select.fireSelect(select.queryDropdown(document, 1)!, 0); 73 | expect(fn2).toBeCalledWith(2, expect.objectContaining({ label: 2, value: 2 })); 74 | }); 75 | 76 | test('queryOption', () => { 77 | const fn = jest.fn(); 78 | const { container } = render( 79 | ); 96 | select.fireOpen(container); 97 | expect(fn).toBeCalledWith(true); 98 | }); 99 | 100 | it('fireSelect', () => { 101 | const fn = jest.fn(); 102 | const { container } = render( 103 | ); 113 | select.fireSearch(container, 'test'); 114 | expect(fn).toBeCalled(); 115 | }); 116 | 117 | it('fireFocus', () => { 118 | const fn = jest.fn(); 119 | const { container } = render(); 127 | select.fireFocus(container); 128 | select.fireBlur(container); 129 | expect(fn).toBeCalled(); 130 | }); 131 | 132 | it('fireClear', () => { 133 | const fn = jest.fn(); 134 | const { container } = render( 135 | 145 | ); 146 | select.fireDeSelect(container, 0); 147 | expect(fn).toBeCalled(); 148 | }); 149 | }); 150 | -------------------------------------------------------------------------------- /src/select/index.ts: -------------------------------------------------------------------------------- 1 | import { act, fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector, queryViaSelectors } from '../utils'; 6 | 7 | /** 8 | * Fires onSearch function 9 | */ 10 | export function fireSearch(container: IContainer, value: any) { 11 | const selector = `input.${getProvider('prefixCls')}-select-selection-search-input`; 12 | const ele = queryInput(container); 13 | if (!ele) throw failedQuerySelector(selector); 14 | fireEvent.change(ele, { target: { value } }); 15 | } 16 | 17 | /** 18 | * Fires onDropdownVisibleChange function. 19 | * Meanwhile, open Dropdown 20 | * @prerequisite call `jest.useFakeTimers()` 21 | */ 22 | export function fireOpen(container: IContainer) { 23 | const selector = `.${getProvider('prefixCls')}-select-selector`; 24 | const ele = querySelector(container); 25 | if (!ele) throw failedQuerySelector(selector); 26 | act(() => { 27 | fireEvent.mouseDown(ele); 28 | jest.runAllTimers(); 29 | }); 30 | } 31 | 32 | /** 33 | * Fires onSelect function 34 | * @param container Be aware of the dropdown's renderRoot 35 | * @param index Select the `index` options 36 | */ 37 | export function fireSelect(container: IContainer, index: number) { 38 | const selector = `div.${getProvider('prefixCls')}-select-item-option-content`; 39 | const ele = queryOption(container, index); 40 | if (!ele) throw failedQuerySelector(selector); 41 | fireEvent.click(ele); 42 | } 43 | 44 | /** 45 | * Fires onDeselect function, **ONLY** works for tag or multiply mode 46 | * @param index Deselect the `index` tag 47 | */ 48 | export function fireDeSelect(container: IContainer, index: number) { 49 | const selectors = [ 50 | `.${getProvider('prefixCls')}-select-selection-item`, 51 | `.${getProvider('prefixCls')}-select-selection-item-remove`, 52 | ]; 53 | const ele = queryViaSelectors(container, selectors, [index]); 54 | if (!ele) throw failedQuerySelector(`${selectors[0]}[${index}] ${selectors[1]}`); 55 | fireEvent.click(ele); 56 | } 57 | 58 | /** 59 | * Fires onFocus function 60 | */ 61 | export function fireFocus(container: IContainer) { 62 | const selector = `input.${getProvider('prefixCls')}-select-selection-search-input`; 63 | const ele = queryInput(container); 64 | if (!ele) throw failedQuerySelector(selector); 65 | fireEvent.focus(ele); 66 | } 67 | 68 | /** 69 | * Fires onBlur function 70 | */ 71 | export function fireBlur(container: IContainer) { 72 | const selector = `input.${getProvider('prefixCls')}-select-selection-search-input`; 73 | const ele = queryInput(container); 74 | if (!ele) throw failedQuerySelector(selector); 75 | fireEvent.blur(ele); 76 | } 77 | 78 | /** 79 | * Fires onClear function 80 | * @notice Be aware of value before call fireClear 81 | */ 82 | export function fireClear(container: IContainer) { 83 | const selector = `.${getProvider('prefixCls')}-select-clear`; 84 | const ele = queryClear(container); 85 | if (!ele) throw failedQuerySelector(selector); 86 | fireEvent.mouseDown(ele); 87 | } 88 | 89 | /** 90 | * Returns the `index` Select's container 91 | * @param index default is 0 92 | */ 93 | export function query(container: IContainer, index = 0) { 94 | const selector = `.${getProvider('prefixCls')}-select`; 95 | const ele = queryViaSelector(container, selector, index); 96 | return ele; 97 | } 98 | 99 | /** 100 | * Returns the `index` Input inside Select 101 | * @param index default is 0 102 | */ 103 | export function queryInput(container: IContainer, index = 0) { 104 | const selector = `input.${getProvider('prefixCls')}-select-selection-search-input`; 105 | const ele = queryViaSelector(container, selector, index); 106 | return ele; 107 | } 108 | 109 | /** 110 | * Returns the `index` Selector dom inside Select, 111 | * the main element to call fireOpen 112 | * @param index default is 0 113 | */ 114 | export function querySelector(container: IContainer, index = 0) { 115 | const selector = `.${getProvider('prefixCls')}-select-selector`; 116 | const ele = queryViaSelector(container, selector, index); 117 | return ele; 118 | } 119 | 120 | /** 121 | * Returns the `index` dropdown's container for Select 122 | * @param index default is 0 123 | */ 124 | export function queryDropdown(container: IContainer, index = 0) { 125 | const selector = `.${getProvider('prefixCls')}-select-dropdown`; 126 | const ele = queryViaSelector(container, selector, index); 127 | return ele; 128 | } 129 | 130 | /** 131 | * Returns the `index` Option for Select 132 | * @param index default is 0 133 | */ 134 | export function queryOption(container: IContainer, index = 0) { 135 | const selector = `div.${getProvider('prefixCls')}-select-item-option-content`; 136 | const ele = queryViaSelector(container, selector, index); 137 | return ele; 138 | } 139 | 140 | /** 141 | * Returns the `index` clear icon's container 142 | */ 143 | export function queryClear(container: IContainer, index = 0) { 144 | const selector = `.${getProvider('prefixCls')}-select-clear`; 145 | const ele = queryViaSelector(container, selector, index); 146 | return ele; 147 | } 148 | -------------------------------------------------------------------------------- /src/switch/__tests__/switch.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Switch } from 'antd'; 4 | 5 | import * as switchEl from '..'; 6 | 7 | describe("Test Switch's fire functions", () => { 8 | beforeEach(cleanup); 9 | 10 | test('query', () => { 11 | const { container, getByTestId } = render( 12 | <> 13 | 14 | 15 | 16 | ); 17 | expect(switchEl.query(container)).toBe(getByTestId('switch1')); 18 | expect(switchEl.query(container, 1)).toBe(getByTestId('switch2')); 19 | }); 20 | 21 | test('fireClick', () => { 22 | const fn = jest.fn(); 23 | const { container } = render(); 24 | 25 | switchEl.fireClick(container); 26 | expect(fn).toBeCalledTimes(1); 27 | }); 28 | 29 | test('fireChange', () => { 30 | const fn = jest.fn(); 31 | const { container } = render(); 32 | 33 | switchEl.fireChange(container); 34 | expect(fn).toBeCalledTimes(1); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/switch/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | 7 | /** 8 | * Fires onClick function 9 | */ 10 | export function fireClick(container: IContainer) { 11 | const ele = query(container); 12 | if (!ele) throw failedQuerySelector(`.${getProvider('prefixCls')}-switch`); 13 | fireEvent.click(ele); 14 | } 15 | 16 | /** 17 | * Fires onChange function 18 | */ 19 | export function fireChange(container: IContainer) { 20 | fireClick(container); 21 | } 22 | 23 | /** 24 | * Returns the container element 25 | */ 26 | export function query(container: IContainer, index = 0) { 27 | const selector = `.${getProvider('prefixCls')}-switch`; 28 | const ele = queryViaSelector(container, selector, index); 29 | return ele; 30 | } 31 | -------------------------------------------------------------------------------- /src/table/__tests__/table.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Table } from 'antd'; 4 | import type { ColumnType } from 'antd/lib/table'; 5 | 6 | import * as table from '..'; 7 | 8 | const columns: ColumnType<(typeof dataSource)[number]>[] = [ 9 | { dataIndex: 'name', title: 'Name' }, 10 | { dataIndex: 'address', title: 'Address' }, 11 | ]; 12 | 13 | const dataSource = [ 14 | { id: 1, name: 'ZhangSan', age: 17, address: 'New York No. 1 Lake Park' }, 15 | { id: 2, name: 'LiSi', age: 17, address: 'Bei Jing No. 1 Lake Park' }, 16 | { id: 3, name: 'WangWu', age: 17, address: 'Zhe Jiang No. 1 Lake Park' }, 17 | ]; 18 | 19 | describe("Test Table's fire functions", () => { 20 | beforeEach(cleanup); 21 | 22 | test('query', () => { 23 | const { container } = render(); 24 | expect(table.query(container)).not.toBeNull(); 25 | }); 26 | 27 | test('queryHeader', () => { 28 | const { container } = render(
); 29 | expect(table.queryHeader(container)).not.toBeNull(); 30 | }); 31 | 32 | test('queryHeader with fixed columns', () => { 33 | const { container } = render( 34 |
35 | ); 36 | expect(table.queryHeader(container)).not.toBeNull(); 37 | }); 38 | 39 | test('queryBody', () => { 40 | const { container } = render(
); 41 | expect(table.queryBody(container)).not.toBeNull(); 42 | }); 43 | 44 | test('queryBody with fixed columns', () => { 45 | const { container } = render( 46 |
47 | ); 48 | expect(table.queryBody(container)).not.toBeNull(); 49 | }); 50 | 51 | test('queryRow', () => { 52 | const { container } = render(
); 53 | expect(table.queryRow(container)).not.toBeNull(); 54 | }); 55 | 56 | test('fireSelect', () => { 57 | const handleSelect = jest.fn(); 58 | const { container } = render( 59 |
67 | ); 68 | table.fireSelect(container, 1); 69 | expect(handleSelect.mock.calls[0][0]).toEqual([2]); 70 | }); 71 | 72 | test('fireSelectAll', () => { 73 | const handleSelect = jest.fn(); 74 | const { container } = render( 75 |
83 | ); 84 | table.fireSelectAll(container); 85 | expect(handleSelect.mock.calls[0][0]).toBeTruthy(); 86 | }); 87 | 88 | test('fireExpand', () => { 89 | const handleExpand = jest.fn(); 90 | const { container } = render( 91 |

{record.name}

, 97 | rowExpandable: (record) => record.id !== 2, 98 | onExpand: handleExpand, 99 | }} 100 | /> 101 | ); 102 | table.fireExpand(container, 2); 103 | expect(handleExpand.mock.calls[0][0]).toBeTruthy(); 104 | expect(handleExpand.mock.calls[0][1]).toEqual(dataSource[2]); 105 | }); 106 | }); 107 | -------------------------------------------------------------------------------- /src/table/index.tsx: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import * as checkbox from '../checkbox'; 4 | import type { IContainer } from '../interface'; 5 | import { getProvider } from '../provider'; 6 | import { failedQuerySelector, queryViaSelector, queryViaSelectors } from '../utils'; 7 | 8 | /** 9 | * Fires rowSelection's onChange function 10 | */ 11 | export const fireSelect = (container: IContainer, index: number) => { 12 | const row = queryRow(container, index); 13 | if (!row) throw failedQuerySelector(`.${getProvider('prefixCls')}-table-row`); 14 | const ele = checkbox.query(row); 15 | if (!ele) throw failedQuerySelector(`.${getProvider('prefixCls')}-checkbox-input`); 16 | fireEvent.click(ele); 17 | }; 18 | 19 | /** 20 | * Fires rowSelection's onSelectAll function 21 | */ 22 | export const fireSelectAll = (container: IContainer) => { 23 | const header = queryHeader(container); 24 | if (!header) throw failedQuerySelector('table'); 25 | const ele = checkbox.query(header); 26 | if (!ele) throw failedQuerySelector(`.${getProvider('prefixCls')}-checkbox-input`); 27 | fireEvent.click(ele); 28 | }; 29 | 30 | /** 31 | * Fires expandable's onExpand function 32 | */ 33 | export const fireExpand = (container: IContainer, index: number) => { 34 | const selectors = [ 35 | `.${getProvider('prefixCls')}-table-row`, 36 | `button.${getProvider('prefixCls')}-table-row-expand-icon`, 37 | ]; 38 | const ele = queryViaSelectors(container, selectors, [index]); 39 | if (!ele) throw failedQuerySelector(`${selectors[0]}[${index}] ${selectors[1]}`); 40 | fireEvent.click(ele); 41 | }; 42 | 43 | /** 44 | * Returns the wrapper element for Table 45 | */ 46 | export function query(container: IContainer, index = 0) { 47 | const selector = `.${getProvider('prefixCls')}-table-wrapper`; 48 | const ele = queryViaSelector(container, selector, index); 49 | return ele; 50 | } 51 | 52 | /** 53 | * Returns the header element for Table 54 | */ 55 | export function queryHeader(container: IContainer, index = 0) { 56 | const wrapper = query(container, index); 57 | if (!wrapper) return null; 58 | const fixedHeader = wrapper.classList.contains(`.${getProvider('prefixCls')}-table-fixed-header`); 59 | const selector = fixedHeader 60 | ? `.${getProvider('prefixCls')}-table-header` 61 | : `.${getProvider('prefixCls')}-table-thead`; 62 | const ele = queryViaSelector(container, selector); 63 | return ele; 64 | } 65 | 66 | /** 67 | * Returns the body element for Table 68 | */ 69 | export function queryBody(container: IContainer, index = 0) { 70 | const wrapper = query(container, index); 71 | if (!wrapper) return null; 72 | const fixedHeader = wrapper.classList.contains(`.${getProvider('prefixCls')}-table-fixed-header`); 73 | const selector = fixedHeader 74 | ? `.${getProvider('prefixCls')}-table-body` 75 | : `.${getProvider('prefixCls')}-table-tbody`; 76 | const ele = queryViaSelector(container, selector, index); 77 | return ele; 78 | } 79 | 80 | /** 81 | * Returns the row element for Table 82 | */ 83 | export function queryRow(container: IContainer, index = 0) { 84 | const selector = `.${getProvider('prefixCls')}-table-row`; 85 | const ele = queryViaSelector(container, selector, index); 86 | return ele; 87 | } 88 | -------------------------------------------------------------------------------- /src/tabs/__tests__/tabs.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Tabs, type TabsProps } from 'antd'; 4 | 5 | import * as tabs from '..'; 6 | 7 | const items: TabsProps['items'] = [ 8 | { 9 | key: '1', 10 | label: `Tab 1`, 11 | children: `Content of Tab Pane 1`, 12 | }, 13 | { 14 | key: '2', 15 | label: `Tab 2`, 16 | children: `Content of Tab Pane 2`, 17 | }, 18 | { 19 | key: '3', 20 | label: `Tab 3`, 21 | children: `Content of Tab Pane 3`, 22 | }, 23 | ]; 24 | 25 | describe("Test Tabs' fire functions", () => { 26 | beforeEach(cleanup); 27 | 28 | test('query', () => { 29 | const { container } = render(); 30 | expect(tabs.query(container)).not.toBeNull(); 31 | }); 32 | 33 | test('queryTabTitle', () => { 34 | const { container } = render(); 35 | expect(tabs.queryTabTitle(container, '1')?.textContent).toBe('Tab 1'); 36 | }); 37 | 38 | test('queryAddButton', () => { 39 | const { container } = render(); 40 | expect(tabs.queryAddButton(container)).toBeInstanceOf(HTMLButtonElement); 41 | }); 42 | 43 | test('queryRemoveButton', () => { 44 | const { container } = render(); 45 | expect(tabs.queryRemoveButton(container, '1')).toBeInstanceOf(HTMLButtonElement); 46 | }); 47 | 48 | test('fireChange', () => { 49 | const fn = jest.fn(); 50 | const { container } = render(); 51 | tabs.fireChange(container, '2'); 52 | expect(fn).toBeCalled(); 53 | }); 54 | 55 | test('fireClick', () => { 56 | const fn = jest.fn(); 57 | const { container } = render(); 58 | tabs.fireClick(container, '1'); 59 | expect(fn).toBeCalled(); 60 | }); 61 | 62 | test('fireEdit', () => { 63 | const fn = jest.fn(); 64 | const { container } = render(); 65 | tabs.fireEdit(container, 'add'); 66 | expect(fn).toBeCalledTimes(1); 67 | 68 | tabs.fireEdit(container, 'remove', '1'); 69 | expect(fn).toBeCalledTimes(2); 70 | }); 71 | 72 | test('fireEdit should throw error', () => { 73 | const fn = jest.fn(); 74 | const { container } = render(); 75 | // @ts-ignore 76 | expect(() => tabs.fireEdit(container, 'test')).toThrow(); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /src/tabs/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | import type { TabsProps } from 'antd'; 3 | 4 | import type { IContainer } from '../interface'; 5 | import { getProvider } from '../provider'; 6 | import { failedQuerySelector, failedTriggerElement, queryViaSelector, queryViaSelectors } from '../utils'; 7 | 8 | /** 9 | * Fires onTabClick function 10 | */ 11 | export function fireClick(container: IContainer, activeKey: string) { 12 | const selector = `.${getProvider('prefixCls')}-tabs-tab[data-node-key="${activeKey}"]`; 13 | const ele = queryTabTitle(container, activeKey); 14 | if (!ele) throw failedQuerySelector(selector); 15 | fireEvent.click(ele); 16 | } 17 | 18 | /** 19 | * Fires onChange function 20 | */ 21 | export function fireChange(container: IContainer, activeKey: string) { 22 | fireClick(container, activeKey); 23 | } 24 | 25 | type ActionType = Parameters>[1]; 26 | /** 27 | * Fires onEdit function 28 | */ 29 | export function fireEdit(container: IContainer, action: 'add'): void; 30 | export function fireEdit(container: IContainer, action: 'remove', activeKey: string): void; 31 | export function fireEdit(container: IContainer, action: ActionType, activeKey?: string) { 32 | switch (action) { 33 | case 'add': { 34 | const ele = queryAddButton(container); 35 | if (!ele) throw failedQuerySelector(`.${getProvider('prefixCls')}-tabs-nav-add`); 36 | fireEvent.click(ele); 37 | break; 38 | } 39 | case 'remove': { 40 | if (!activeKey) throw new Error('Remove action should specify activeKey!'); 41 | const ele = queryRemoveButton(container, activeKey); 42 | if (!ele) throw failedTriggerElement(); 43 | fireEvent.click(ele); 44 | break; 45 | } 46 | 47 | default: 48 | throw new Error('Invalid action for Tabs. Please ensure action between add or remove'); 49 | } 50 | } 51 | 52 | /** 53 | * Returns the container element of Tab 54 | */ 55 | export function query(container: IContainer, index = 0) { 56 | const selector = `.${getProvider('prefixCls')}-tabs`; 57 | const ele = queryViaSelector(container, selector, index); 58 | return ele; 59 | } 60 | 61 | /** 62 | * Returns the title element in Tab 63 | */ 64 | export function queryTabTitle(container: IContainer, activeKey: string) { 65 | const selector = `.${getProvider('prefixCls')}-tabs-tab[data-node-key="${activeKey}"]`; 66 | const ele = queryViaSelector(container, selector); 67 | return ele; 68 | } 69 | 70 | /** 71 | * Returns the add button element in Tab 72 | */ 73 | export function queryAddButton(container: IContainer, index = 0) { 74 | const selector = `.${getProvider('prefixCls')}-tabs-nav-add`; 75 | const ele = queryViaSelector(container, selector, index); 76 | return ele; 77 | } 78 | 79 | /** 80 | * Returns the remove button in Tab 81 | */ 82 | export function queryRemoveButton(container: IContainer, activeKey: string) { 83 | const selectors = [ 84 | `.${getProvider('prefixCls')}-tabs-tab[data-node-key="${activeKey}"]`, 85 | `.${getProvider('prefixCls')}-tabs-tab-remove`, 86 | ]; 87 | const ele = queryViaSelectors(container, selectors, []); 88 | return ele; 89 | } 90 | -------------------------------------------------------------------------------- /src/timePicker/__tests__/timePicker.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { TimePicker } from 'antd'; 4 | import moment from 'moment'; 5 | 6 | import * as timePicker from '..'; 7 | 8 | const dateAdaptor = moment; 9 | 10 | describe("Test TimePicker's fire functions", () => { 11 | beforeEach(() => { 12 | jest.useFakeTimers(); 13 | cleanup(); 14 | document.body.innerHTML = ''; 15 | }); 16 | afterEach(() => { 17 | jest.useRealTimers(); 18 | }); 19 | 20 | test('query', () => { 21 | const { container } = render( node.parentElement!} />); 22 | expect(timePicker.query(container)).not.toBeNull(); 23 | }); 24 | 25 | test('queryDropdown', () => { 26 | const { container } = render( node.parentElement!} />); 27 | timePicker.fireOpen(container); 28 | expect(timePicker.queryDropdown(container)).not.toBeNull(); 29 | }); 30 | 31 | test('queryOk', () => { 32 | const { container } = render( node.parentElement!} />); 33 | timePicker.fireOpen(container); 34 | expect(timePicker.queryOk(container)).not.toBeNull(); 35 | }); 36 | 37 | test('fireOk', () => { 38 | const fn = jest.fn(); 39 | const { container } = render( 40 | node.parentElement!} 44 | /> 45 | ); 46 | 47 | timePicker.fireOpen(container); 48 | timePicker.fireOk(container); 49 | expect(fn).toBeCalled(); 50 | }); 51 | 52 | test('fireOpen', () => { 53 | const fn = jest.fn(); 54 | const { container } = render( 55 | 56 | ); 57 | 58 | timePicker.fireOpen(container); 59 | expect(fn).toBeCalled(); 60 | }); 61 | 62 | test('fireChange', () => { 63 | const fn = jest.fn(); 64 | const { container } = render( 65 | node.parentElement!} 68 | defaultValue={dateAdaptor('00:00:00', 'HH:mm:ss')} 69 | /> 70 | ); 71 | 72 | timePicker.fireOpen(container); 73 | timePicker.fireChange(container, '12:33:44'); 74 | expect(fn).toBeCalled(); 75 | }); 76 | 77 | test('fireChange with RangePicker', () => { 78 | const fn = jest.fn(); 79 | const { container } = render( 80 | node.parentElement!} /> 81 | ); 82 | 83 | timePicker.fireOpen(container); 84 | timePicker.fireChange(container, ['00:00:00', '12:33:44']); 85 | expect(fn).toBeCalled(); 86 | }); 87 | 88 | test('fireChange with format', () => { 89 | const fn = jest.fn(); 90 | const { container } = render( 91 | node.parentElement!} /> 92 | ); 93 | 94 | timePicker.fireOpen(container); 95 | timePicker.fireChange(container, ['00:00:00', '12:33:44']); 96 | expect(fn).toBeCalled(); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /src/timePicker/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import * as datePicker from '../datePicker'; 4 | import type { IContainer } from '../interface'; 5 | import { getProvider } from '../provider'; 6 | import { failedQuerySelector, queryViaSelector } from '../utils'; 7 | 8 | /** 9 | * Fires onOpenChange function 10 | */ 11 | export function fireOpen(container: IContainer) { 12 | datePicker.fireOpen(container); 13 | } 14 | 15 | export function fireOk(container: IContainer) { 16 | const ele = queryOk(container); 17 | if (!ele) throw failedQuerySelector(`.${getProvider('prefixCls')}-picker-ok button`); 18 | fireEvent.click(ele); 19 | } 20 | 21 | type TimeString = `${string}:${string}:${string}` | `${string}:${string}`; 22 | /** 23 | * Select a cell 24 | */ 25 | export function fireSelectCell(container: IContainer, index: number) { 26 | const selector = `li.${getProvider('prefixCls')}-picker-time-panel-cell`; 27 | const ele = queryViaSelector(container, selector, index); 28 | if (!ele) throw failedQuerySelector(selector); 29 | fireEvent.click(ele); 30 | } 31 | 32 | function fireSinglePanel(container: HTMLCollection, time: TimeString) { 33 | const [hour, minute, second] = time.split(':'); 34 | if (hour) { 35 | fireSelectCell(container.item(0) as HTMLElement, Number(hour)); 36 | } 37 | if (minute) { 38 | fireSelectCell(container.item(1) as HTMLElement, Number(minute)); 39 | } 40 | if (second) { 41 | fireSelectCell(container.item(2) as HTMLElement, Number(second)); 42 | } 43 | } 44 | 45 | /** 46 | * Fires onChange function 47 | * @param time give array when RangePicker 48 | */ 49 | export function fireChange(container: IContainer, time: TimeString | [TimeString, TimeString]) { 50 | const selector = `.${getProvider('prefixCls')}-picker-content`; 51 | const ele = queryViaSelector(container, selector); 52 | if (!ele) throw failedQuerySelector(selector); 53 | 54 | if (Array.isArray(time)) { 55 | // It's for RangePicker 56 | fireSinglePanel(ele.children, time[0]); 57 | fireOk(container); 58 | fireSinglePanel(ele.children, time[1]); 59 | fireOk(container); 60 | } else { 61 | fireSinglePanel(ele.children, time); 62 | fireOk(container); 63 | } 64 | } 65 | 66 | /** 67 | * Returns the container element 68 | */ 69 | export function query(container: IContainer, index = 0) { 70 | const selector = `.${getProvider('prefixCls')}-picker`; 71 | const ele = queryViaSelector(container, selector, index); 72 | return ele; 73 | } 74 | 75 | /** 76 | * Returns the dropdown element of timePicker 77 | */ 78 | export function queryDropdown(container: IContainer, index = 0) { 79 | datePicker.queryDropdown(container, index); 80 | } 81 | 82 | /** 83 | * Returns the ok button 84 | */ 85 | export function queryOk(container: IContainer, index = 0) { 86 | const selector = `.${getProvider('prefixCls')}-picker-ok button`; 87 | const ele = queryViaSelector(container, selector, index); 88 | return ele; 89 | } 90 | -------------------------------------------------------------------------------- /src/tooltip/__tests__/tooltip.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Tooltip } from 'antd'; 4 | 5 | import * as tooltip from '..'; 6 | 7 | describe("test tooltip's fire functions", () => { 8 | beforeEach(() => { 9 | cleanup(); 10 | jest.useFakeTimers(); 11 | }); 12 | afterEach(() => { 13 | jest.useRealTimers(); 14 | }); 15 | 16 | test('fireOpen', () => { 17 | const fn = jest.fn(); 18 | const { getByText, getByTestId } = render( 19 | node.parentElement!} onOpenChange={fn}> 20 | trigger 21 | 22 | ); 23 | tooltip.fireOpen(getByTestId('trigger')); 24 | 25 | expect(fn).toBeCalledTimes(1); 26 | expect(getByText("This's title")).not.toBeNull(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | import { act, fireEvent } from '@testing-library/react'; 2 | 3 | import { failedTriggerElement } from '../utils'; 4 | 5 | /** 6 | * Show up tooltip 7 | */ 8 | export function fireOpen(ele?: HTMLElement) { 9 | if (!ele) throw failedTriggerElement(); 10 | act(() => { 11 | fireEvent.mouseEnter(ele); 12 | jest.runAllTimers(); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /src/transfer/__tests__/transfer.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Transfer } from 'antd'; 4 | 5 | import * as transfer from '..'; 6 | 7 | const dataSource = [ 8 | { key: 'a', title: 'a' }, 9 | { key: 'b', title: 'b' }, 10 | { key: 'c', title: 'c' }, 11 | ]; 12 | 13 | describe("Test Transfer's fire functions", () => { 14 | afterEach(() => cleanup()); 15 | beforeEach(() => { 16 | jest.useFakeTimers(); 17 | }); 18 | 19 | test('query', () => { 20 | const { container } = render(); 21 | expect(transfer.query(container)).not.toBeNull(); 22 | }); 23 | 24 | test('queryOperationButton', () => { 25 | const { container } = render(); 26 | expect(transfer.queryOperationButton(container)).not.toBeNull(); 27 | }); 28 | 29 | test('fireChange', () => { 30 | const fn = jest.fn(); 31 | const { container } = render( 32 | 33 | ); 34 | transfer.fireChange(container, 'right'); 35 | expect(fn).lastCalledWith(['a', 'b', 'c'], 'right', ['a']); 36 | }); 37 | 38 | test('fireChange with left direction', () => { 39 | const fn = jest.fn(); 40 | const { container } = render( 41 | 42 | ); 43 | transfer.fireChange(container, 'left'); 44 | expect(fn).lastCalledWith([], 'left', ['b', 'c']); 45 | }); 46 | 47 | test('fireScroll', () => { 48 | const fn = jest.fn(); 49 | const { container } = render(); 50 | transfer.fireScroll(container); 51 | expect(fn).toBeCalled(); 52 | }); 53 | 54 | test('fireSearch', () => { 55 | const fn = jest.fn(); 56 | const { container } = render( 57 | item.title} 63 | onSearch={fn} 64 | /> 65 | ); 66 | transfer.fireSearch(container, { searchText: 'a', direction: 'left' }); 67 | expect(fn).toBeCalledWith('left', 'a'); 68 | fn.mockReset(); 69 | transfer.fireSearch(container, { searchText: 'b', direction: 'right' }); 70 | expect(fn).toBeCalledWith('right', 'b'); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /src/transfer/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector, queryViaSelectors } from '../utils'; 6 | 7 | /** 8 | * Fires onChange function 9 | */ 10 | export const fireChange = (container: IContainer, direction: 'left' | 'right') => { 11 | const toRightBtn = queryOperationButton(container, 0); 12 | const toLeftBtn = queryOperationButton(container, 1); 13 | 14 | const btn = direction === 'left' ? toLeftBtn : toRightBtn; 15 | if (!btn) throw failedQuerySelector('button'); 16 | fireEvent.click(btn); 17 | }; 18 | 19 | /** 20 | * Fires onScroll function 21 | */ 22 | export const fireScroll = (container: IContainer, type: 'source' | 'target' = 'source') => { 23 | const selectors = [ 24 | `.${getProvider('prefixCls')}-transfer-list`, 25 | `.${getProvider('prefixCls')}-transfer-list-content`, 26 | ]; 27 | const scrollTargetIndex = type === 'source' ? 0 : 1; 28 | const ele = queryViaSelectors(container, selectors, [scrollTargetIndex, 0]); 29 | if (!ele) throw failedQuerySelector(`${selectors[0]}[${scrollTargetIndex}] ${selectors[1]}[0]`); 30 | fireEvent.scroll(ele); 31 | }; 32 | 33 | /** 34 | * Fires onSearch function 35 | */ 36 | export const fireSearch = (container: IContainer, opts: { searchText: string; direction: 'left' | 'right' }) => { 37 | const { direction, searchText } = opts; 38 | const selectors = [`.${getProvider('prefixCls')}-transfer-list-search`, `.${getProvider('prefixCls')}-input`]; 39 | const searchTargetIndex = direction === 'left' ? 0 : 1; 40 | const ele = queryViaSelectors(container, selectors, [searchTargetIndex]); 41 | if (!ele) throw failedQuerySelector(`${selectors[0]}[${searchTargetIndex}] ${selectors[1]}`); 42 | 43 | fireEvent.change(ele, { target: { value: searchText } }); 44 | }; 45 | 46 | /** 47 | * Returns the container element 48 | */ 49 | export function query(container: IContainer, index = 0) { 50 | const selector = `.${getProvider('prefixCls')}-transfer`; 51 | const ele = queryViaSelector(container, selector, index); 52 | return ele; 53 | } 54 | 55 | /** 56 | * Returns the operation's button element 57 | */ 58 | export function queryOperationButton(container: IContainer, index = 0) { 59 | const selector = `.${getProvider('prefixCls')}-transfer .${getProvider('prefixCls')}-transfer-operation button`; 60 | const ele = queryViaSelector(container, selector, index); 61 | return ele; 62 | } 63 | -------------------------------------------------------------------------------- /src/tree/__tests__/tree.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { Tree } from 'antd'; 4 | import type { DataNode } from 'antd/es/tree'; 5 | 6 | import * as tree from '..'; 7 | 8 | const treeData: DataNode[] = [ 9 | { 10 | title: 'parent 1', 11 | key: '0-0', 12 | children: [ 13 | { 14 | title: 'parent 1-0', 15 | key: '0-0-0', 16 | disabled: true, 17 | children: [ 18 | { 19 | title: 'leaf', 20 | key: '0-0-0-0', 21 | disableCheckbox: true, 22 | }, 23 | { 24 | title: 'leaf', 25 | key: '0-0-0-1', 26 | }, 27 | ], 28 | }, 29 | { 30 | title: 'parent 1-1', 31 | key: '0-0-1', 32 | children: [ 33 | { 34 | title: sss, 35 | key: '0-0-1-0', 36 | }, 37 | ], 38 | }, 39 | ], 40 | }, 41 | ]; 42 | 43 | describe("Test Tree's fire functions", () => { 44 | beforeEach(cleanup); 45 | 46 | test('fireCheck', () => { 47 | const fn = jest.fn(); 48 | const { container } = render(); 49 | 50 | tree.fireCheck(container, 'parent 1'); 51 | expect(fn).toBeCalled(); 52 | }); 53 | 54 | test('fireExpand', () => { 55 | const fn = jest.fn(); 56 | const { container } = render(); 57 | 58 | tree.fireExpand(container, 'parent 1'); 59 | expect(fn).toBeCalled(); 60 | }); 61 | 62 | test('fireRightClick', () => { 63 | const fn = jest.fn(); 64 | const { container } = render(); 65 | 66 | tree.fireRightClick(container, 'parent 1'); 67 | expect(fn).toBeCalled(); 68 | }); 69 | 70 | test('fireSelect', () => { 71 | const fn = jest.fn(); 72 | const { container } = render(); 73 | 74 | tree.fireSelect(container, 'parent 1'); 75 | expect(fn).toBeCalled(); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /src/tree/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | 7 | export function fireCheck(container: IContainer, title: string) { 8 | const selector = `.${getProvider('prefixCls')}-tree-node-content-wrapper[title="${title}"]`; 9 | const checkbox = `.${getProvider('prefixCls')}-tree-checkbox`; 10 | const ele = container.querySelector(selector)?.parentElement?.querySelector(checkbox); 11 | if (!ele) throw failedQuerySelector(`${selector}'s parentElement ${checkbox}`); 12 | fireEvent.click(ele); 13 | } 14 | 15 | export function fireExpand(container: IContainer, title: string) { 16 | const selector = `.${getProvider('prefixCls')}-tree-node-content-wrapper[title="${title}"]`; 17 | const switcher = `.${getProvider('prefixCls')}-tree-switcher`; 18 | const ele = container.querySelector(selector)?.parentElement?.querySelector(switcher); 19 | if (!ele) throw failedQuerySelector(`${selector}'s parentElement ${switcher}`); 20 | fireEvent.click(ele); 21 | } 22 | 23 | export function fireRightClick(container: IContainer, title: string) { 24 | const selector = `.${getProvider('prefixCls')}-tree-node-content-wrapper[title="${title}"]`; 25 | const ele = queryViaSelector(container, selector); 26 | if (!ele) throw failedQuerySelector(selector); 27 | fireEvent.contextMenu(ele); 28 | } 29 | 30 | export function fireSelect(container: IContainer, title: string) { 31 | const selector = `.${getProvider('prefixCls')}-tree-node-content-wrapper[title="${title}"]`; 32 | const ele = queryViaSelector(container, selector); 33 | if (!ele) throw failedQuerySelector(selector); 34 | fireEvent.click(ele); 35 | } 36 | 37 | // TODO 38 | export function fireDrag() {} 39 | -------------------------------------------------------------------------------- /src/treeSelect/__tests__/treeSelect.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import { TreeSelect } from 'antd'; 4 | 5 | import * as treeSelect from '..'; 6 | 7 | describe("Test treeSelect's fire functions", () => { 8 | beforeEach(() => { 9 | jest.useFakeTimers(); 10 | cleanup(); 11 | document.body.innerHTML = ''; 12 | }); 13 | afterEach(() => { 14 | jest.useRealTimers(); 15 | }); 16 | 17 | test('fireOpen', () => { 18 | const fn = jest.fn(); 19 | const { container } = render(); 20 | 21 | treeSelect.fireOpen(container); 22 | expect(fn).toBeCalled(); 23 | }); 24 | 25 | test('fireSearch', () => { 26 | const fn = jest.fn(); 27 | const { container } = render(); 28 | 29 | treeSelect.fireSearch(container, 'test'); 30 | expect(fn).toBeCalled(); 31 | }); 32 | 33 | test('fireSelect', () => { 34 | const fn = jest.fn(); 35 | const treeData = [ 36 | { 37 | title: 'Node1', 38 | value: '0-0', 39 | children: [ 40 | { 41 | title: 'Child Node1', 42 | value: '0-0-1', 43 | }, 44 | { 45 | title: 'Child Node2', 46 | value: '0-0-2', 47 | }, 48 | ], 49 | }, 50 | { 51 | title: 'Node2', 52 | value: '0-1', 53 | }, 54 | ]; 55 | const { container } = render( 56 | node.parentNode} onSelect={fn} /> 57 | ); 58 | 59 | treeSelect.fireOpen(container); 60 | treeSelect.fireSelect(container, 0); 61 | expect(fn).toBeCalled(); 62 | }); 63 | 64 | test('fireTreeExpand', () => { 65 | const fn = jest.fn(); 66 | const treeData = [ 67 | { 68 | title: 'Node1', 69 | value: '0-0', 70 | children: [ 71 | { 72 | title: 'Child Node1', 73 | value: '0-0-1', 74 | }, 75 | { 76 | title: 'Child Node2', 77 | value: '0-0-2', 78 | }, 79 | ], 80 | }, 81 | { 82 | title: 'Node2', 83 | value: '0-1', 84 | }, 85 | ]; 86 | const { container } = render( 87 | node.parentNode} onTreeExpand={fn} /> 88 | ); 89 | 90 | treeSelect.fireOpen(container); 91 | treeSelect.fireTreeExpand(container, 0); 92 | expect(fn).toBeCalled(); 93 | }); 94 | }); 95 | -------------------------------------------------------------------------------- /src/treeSelect/index.ts: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { fireOpen as fireSelectOpen } from '../select'; 6 | import { failedQuerySelector, queryViaSelector } from '../utils'; 7 | 8 | export function fireOpen(container: IContainer) { 9 | fireSelectOpen(container); 10 | } 11 | 12 | export function fireSearch(container: IContainer, value: any) { 13 | const selector = 'input'; 14 | const ele = queryViaSelector(container, selector); 15 | if (!ele) throw failedQuerySelector(selector); 16 | fireEvent.change(ele, { target: { value } }); 17 | } 18 | 19 | export function fireSelect(container: IContainer, index: number) { 20 | const selector = `span.${getProvider('prefixCls')}-select-tree-node-content-wrapper`; 21 | const ele = queryViaSelector(container, selector, index); 22 | if (!ele) throw failedQuerySelector(selector); 23 | fireEvent.click(ele); 24 | } 25 | 26 | export function fireTreeExpand(container: IContainer, index: number) { 27 | const selector = `span.${getProvider('prefixCls')}-select-tree-node-content-wrapper`; 28 | const switcher = `.${getProvider('prefixCls')}-select-tree-switcher`; 29 | const ele = container.querySelectorAll(selector).item(index)?.parentElement?.querySelector(switcher); 30 | if (!ele) throw failedQuerySelector(`${selector}[${index}]'s parentElement ${switcher}`); 31 | fireEvent.click(ele); 32 | } 33 | -------------------------------------------------------------------------------- /src/upload/__tests__/upload.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render, waitFor } from '@testing-library/react'; 3 | import { Upload, type UploadFile } from 'antd'; 4 | 5 | import * as upload from '..'; 6 | 7 | describe("Test Upload's fire functions", () => { 8 | beforeEach(() => { 9 | cleanup(); 10 | jest.useFakeTimers(); 11 | }); 12 | afterEach(() => { 13 | jest.useRealTimers(); 14 | }); 15 | 16 | test('fireUpload', async () => { 17 | const fn = jest.fn(); 18 | const { container } = render( 19 | false} onChange={fn}> 20 | 21 | 22 | ); 23 | 24 | upload.fireUploadAsync(container, [{ file: 'foo.png' }]); 25 | await waitFor(() => { 26 | expect(fn).toBeCalledTimes(1); 27 | expect(fn.mock.calls[0][0].fileList[0].file).toBe('foo.png'); 28 | }); 29 | }); 30 | 31 | test('fireRemove', () => { 32 | const fn = jest.fn(); 33 | const files = [ 34 | { 35 | uid: '-1', 36 | name: 'foo.png', 37 | status: 'done', 38 | url: 'http://www.baidu.com/xxx.png', 39 | }, 40 | { 41 | uid: '-2', 42 | name: 'bar.png', 43 | status: 'done', 44 | url: 'http://www.baidu.com/xxx.png', 45 | }, 46 | ]; 47 | const { container } = render( 48 | false} fileList={files as UploadFile[]} onRemove={fn}> 49 | 50 | 51 | ); 52 | upload.fireRemove(container, 1); 53 | waitFor(() => { 54 | expect(fn.mock.calls[0][0]).toMatchObject({ name: 'bar.png' }); 55 | }); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/upload/index.ts: -------------------------------------------------------------------------------- 1 | import { act, fireEvent } from '@testing-library/react'; 2 | 3 | import type { IContainer } from '../interface'; 4 | import { getProvider } from '../provider'; 5 | import { failedQuerySelector, queryViaSelector } from '../utils'; 6 | 7 | export const fireUploadAsync = (container: IContainer, files: File[] | { file: string }[]) => { 8 | const selector = 'input[type=file]'; 9 | const ele = queryViaSelector(container, selector); 10 | if (!ele) throw failedQuerySelector(selector); 11 | act(() => { 12 | fireEvent.change(ele, { target: { files } }); 13 | jest.runAllTimers(); 14 | }); 15 | }; 16 | 17 | export const fireRemove = (container: IContainer, index = 0) => { 18 | const selector = `.${getProvider('prefixCls')}-upload-list-text-container:nth-child(${index + 1}) .${getProvider( 19 | 'prefixCls' 20 | )}-upload-list-item .anticon-delete`; 21 | const ele = queryViaSelector(container, selector); 22 | if (!ele) throw failedQuerySelector(selector); 23 | fireEvent.click(ele); 24 | }; 25 | -------------------------------------------------------------------------------- /src/utils/__tests__/utils.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import { failedQuerySelector, failedQuerySelectors, failedTriggerElement, queryViaSelector } from '..'; 5 | 6 | describe('Test utils', () => { 7 | [failedQuerySelector, failedTriggerElement].forEach((fn) => { 8 | it(fn.name, () => { 9 | expect(fn('test')).toBeInstanceOf(Error); 10 | }); 11 | }); 12 | it('failedQuerySelectors', () => { 13 | expect(failedQuerySelectors(['test', 'test2'])).toBeInstanceOf(Error); 14 | }); 15 | 16 | it('queryViaSelector', () => { 17 | const { container, getByTestId } = render( 18 |
19 | 20 | 21 |
22 | ); 23 | 24 | expect(queryViaSelector(container, 'span', 0)).toBe(getByTestId('span1')); 25 | expect(queryViaSelector(getByTestId('span1'), 'span', 0)).toBe(getByTestId('span1')); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | import type { IContainer } from '../interface'; 2 | 3 | export const failedQuerySelector = (selector: string) => new Error(`Failed to query selector about "${selector}"`); 4 | 5 | export const failedQuerySelectors = (selectors: string[]) => 6 | new Error(`Failed to query selector neither "${selectors.join('" nor "')}"`); 7 | 8 | export const failedTriggerElement = () => new Error('Failed to trigger element for NOT found element'); 9 | 10 | /** 11 | * 判断容器元素自身是否匹配选择器 12 | */ 13 | export function queryViaSelector(container: IContainer, selector: string, index?: number) { 14 | if (!(container instanceof Document) && container.matches(selector)) { 15 | return container as T; 16 | } 17 | if (typeof index === 'number') { 18 | return container.querySelectorAll(selector).item(index); 19 | } 20 | return container.querySelector(selector); 21 | } 22 | 23 | export function queryViaSelectors(container: IContainer, selectors: string[], index: number[]) { 24 | const i = selectors.findIndex( 25 | function (this: { className: string }, selector) { 26 | this.className += ` ${selector}`; 27 | return !(container instanceof Document) && !container.matches(this.className); 28 | }, 29 | { 30 | className: '', 31 | } 32 | ); 33 | const restSelectors = selectors.slice(i); 34 | const restIndex = index.slice(i); 35 | return restSelectors.reduce((acc, cur, idx) => { 36 | const queryAll = typeof restIndex[idx] === 'number'; 37 | if (queryAll) { 38 | return acc?.querySelectorAll(cur).item(restIndex[idx]); 39 | } 40 | return acc?.querySelector(cur); 41 | }, container as T); 42 | } 43 | -------------------------------------------------------------------------------- /tests/setupTests.ts: -------------------------------------------------------------------------------- 1 | import { provider } from '../src/provider'; 2 | 3 | Object.defineProperty(global.window, 'matchMedia', { 4 | writable: true, 5 | configurable: true, 6 | value: jest.fn((query) => ({ 7 | matches: query.includes('max-width'), 8 | addListener: jest.fn(), 9 | removeListener: jest.fn(), 10 | })), 11 | }); 12 | 13 | provider({ prefixCls: 'ant' }); 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react", 4 | "esModuleInterop": true, 5 | "strict": true, 6 | "declaration": true, 7 | "skipLibCheck": true, 8 | "baseUrl": "./" 9 | } 10 | } 11 | --------------------------------------------------------------------------------