From b2c4397d9167426d498cb285996e336eacd05218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E8=89=B3=E5=85=B5?= Date: Thu, 21 May 2026 10:06:18 +0800 Subject: [PATCH] test: migrate switch tests to testing library --- package.json | 14 ++--- src/index.tsx | 9 ++-- tests/index.spec.js | 125 +++++++++++++++++++++++++------------------- 3 files changed, 81 insertions(+), 67 deletions(-) diff --git a/package.json b/package.json index ab9614d..15deee7 100644 --- a/package.json +++ b/package.json @@ -43,22 +43,19 @@ ] }, "dependencies": { - "@rc-component/util": "^1.3.0", + "@rc-component/util": "^1.11.1", "clsx": "^2.1.1" }, "devDependencies": { - "@rc-component/father-plugin": "^2.0.0", + "@rc-component/father-plugin": "^2.2.0", "@rc-component/np": "^1.0.3", + "@testing-library/react": "^16.0.1", "@types/jest": "^29.4.0", "@types/node": "^24.5.2", "@types/react": "^19.1.14", "@types/react-dom": "^19.1.9", "@umijs/fabric": "^3.0.0", - "cheerio": "1.0.0-rc.12", "dumi": "^2.0.0", - "enzyme": "^3.0.0", - "enzyme-adapter-react-16": "^1.0.1", - "enzyme-to-json": "^3.0.0", "eslint": "^8.55.0", "eslint-plugin-jest": "^27.6.0", "eslint-plugin-unicorn": "^49.0.0", @@ -68,9 +65,8 @@ "less": "^4.1.3", "lint-staged": "^15.1.0", "prettier": "^3.1.0", - "react": "^16.0.0", - "react-dom": "^16.0.0", - "react-test-renderer": "^16.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0", "umi-test": "^1.9.7" }, "peerDependencies": { diff --git a/src/index.tsx b/src/index.tsx index 08c2c98..c3daa4b 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { clsx } from 'clsx'; -import useControlledState from '@rc-component/util/lib/hooks/useControlledState'; -import KeyCode from '@rc-component/util/lib/KeyCode'; +import { KeyCode, useControlledState } from '@rc-component/util'; export type SwitchChangeEventHandler = ( checked: boolean, @@ -9,8 +8,10 @@ export type SwitchChangeEventHandler = ( ) => void; export type SwitchClickEventHandler = SwitchChangeEventHandler; -interface SwitchProps - extends Omit, 'onChange' | 'onClick'> { +interface SwitchProps extends Omit< + React.HTMLAttributes, + 'onChange' | 'onClick' +> { className?: string; prefixCls?: string; disabled?: boolean; diff --git a/tests/index.spec.js b/tests/index.spec.js index 4863932..c980bf3 100644 --- a/tests/index.spec.js +++ b/tests/index.spec.js @@ -1,11 +1,15 @@ import React from 'react'; -import KeyCode from '@rc-component/util/lib/KeyCode'; -import { mount } from 'enzyme'; +import { KeyCode } from '@rc-component/util'; +import { fireEvent, render } from '@testing-library/react'; import Switch from '..'; describe('rc-switch', () => { + function keyDownWithWhich(target, which) { + fireEvent.keyDown(target, { keyCode: which }); + } + function createSwitch(props = {}) { - return mount( + return render( } unCheckedChildren={} @@ -15,127 +19,140 @@ describe('rc-switch', () => { } it('works', () => { - const wrapper = createSwitch(); - expect(wrapper.exists('.unchecked')).toBeTruthy(); - wrapper.simulate('click'); - expect(wrapper.exists('.checked')).toBeTruthy(); + const { getByRole } = createSwitch(); + const switchNode = getByRole('switch'); + + expect(switchNode.getAttribute('aria-checked')).toBe('false'); + fireEvent.click(switchNode); + expect(switchNode.getAttribute('aria-checked')).toBe('true'); }); it('should be checked upon right key and unchecked on left key', () => { - const wrapper = createSwitch(); - expect(wrapper.exists('.unchecked')).toBeTruthy(); - wrapper.simulate('keydown', { which: KeyCode.RIGHT }); - expect(wrapper.exists('.checked')).toBeTruthy(); - wrapper.simulate('keydown', { which: KeyCode.LEFT }); - expect(wrapper.exists('.unchecked')).toBeTruthy(); + const { getByRole } = createSwitch(); + const switchNode = getByRole('switch'); + + expect(switchNode.getAttribute('aria-checked')).toBe('false'); + keyDownWithWhich(switchNode, KeyCode.RIGHT); + expect(switchNode.getAttribute('aria-checked')).toBe('true'); + keyDownWithWhich(switchNode, KeyCode.LEFT); + expect(switchNode.getAttribute('aria-checked')).toBe('false'); }); it('should change from an initial checked state of true to false on click', () => { const onChange = jest.fn(); - const wrapper = createSwitch({ defaultChecked: true, onChange }); - expect(wrapper.exists('.checked')).toBeTruthy(); - wrapper.simulate('click'); - expect(wrapper.exists('.unchecked')).toBeTruthy(); + const { getByRole } = createSwitch({ defaultChecked: true, onChange }); + const switchNode = getByRole('switch'); + + expect(switchNode.getAttribute('aria-checked')).toBe('true'); + fireEvent.click(switchNode); + expect(switchNode.getAttribute('aria-checked')).toBe('false'); expect(onChange.mock.calls.length).toBe(1); }); it('should support onClick', () => { const onClick = jest.fn(); - const wrapper = createSwitch({ onClick }); - wrapper.simulate('click'); + const { getByRole } = createSwitch({ onClick }); + const switchNode = getByRole('switch'); + + fireEvent.click(switchNode); expect(onClick).toHaveBeenCalledWith(true, expect.objectContaining({ type: 'click' })); expect(onClick.mock.calls.length).toBe(1); - wrapper.simulate('click'); + fireEvent.click(switchNode); expect(onClick).toHaveBeenCalledWith(false, expect.objectContaining({ type: 'click' })); expect(onClick.mock.calls.length).toBe(2); }); it('should not toggle when clicked in a disabled state', () => { const onChange = jest.fn(); - const wrapper = createSwitch({ disabled: true, checked: true, onChange }); - expect(wrapper.exists('.checked')).toBeTruthy(); - wrapper.simulate('click'); - expect(wrapper.exists('.checked')).toBeTruthy(); + const { getByRole } = createSwitch({ disabled: true, checked: true, onChange }); + const switchNode = getByRole('switch'); + + expect(switchNode.getAttribute('aria-checked')).toBe('true'); + fireEvent.click(switchNode); + expect(switchNode.getAttribute('aria-checked')).toBe('true'); expect(onChange.mock.calls.length).toBe(0); }); it('should support loading icon node', () => { - const wrapper = mount(loading} />); - expect(wrapper.find('.extra').text()).toBe('loading'); + const { container } = render(loading} />); + expect(container.querySelector('.extra').textContent).toBe('loading'); }); it('focus()', () => { - const container = document.createElement('div'); - document.body.appendChild(container); const handleFocus = jest.fn(); const ref = React.createRef(); - mount(, { - attachTo: container, - }); + render(); + ref.current.focus(); + expect(document.activeElement).toBe(ref.current); + fireEvent.focus(ref.current); expect(handleFocus).toHaveBeenCalled(); }); it('blur()', () => { - const container = document.createElement('div'); - document.body.appendChild(container); const handleBlur = jest.fn(); const ref = React.createRef(); - mount(, { - attachTo: container, - }); + render(); + ref.current.focus(); + expect(document.activeElement).toBe(ref.current); ref.current.blur(); + expect(document.activeElement).not.toBe(ref.current); + fireEvent.blur(ref.current); expect(handleBlur).toHaveBeenCalled(); }); describe('autoFocus', () => { it('basic', () => { - const container = document.createElement('div'); - document.body.appendChild(container); const handleFocus = jest.fn(); - mount(, { attachTo: container }); + const { getByRole } = render(); + const switchNode = getByRole('switch'); + + expect(document.activeElement).toBe(switchNode); + fireEvent.focus(switchNode); expect(handleFocus).toHaveBeenCalled(); }); it('not work when disabled', () => { - const container = document.createElement('div'); - document.body.appendChild(container); const handleFocus = jest.fn(); - mount(, { attachTo: container }); + render(); expect(handleFocus).not.toHaveBeenCalled(); }); }); it('disabled', () => { - const wrapper = createSwitch({ disabled: true }); - expect(wrapper.exists('.unchecked')).toBeTruthy(); - wrapper.simulate('keydown', { keyCode: 39 }); - expect(wrapper.exists('.unchecked')).toBeTruthy(); + const { getByRole } = createSwitch({ disabled: true }); + const switchNode = getByRole('switch'); + + expect(switchNode.getAttribute('aria-checked')).toBe('false'); + keyDownWithWhich(switchNode, KeyCode.RIGHT); + expect(switchNode.getAttribute('aria-checked')).toBe('false'); }); it('onMouseUp', () => { const onMouseUp = jest.fn(); - const wrapper = createSwitch({ onMouseUp }); - wrapper.simulate('mouseup'); + const { getByRole } = createSwitch({ onMouseUp }); + + fireEvent.mouseUp(getByRole('switch')); expect(onMouseUp).toHaveBeenCalled(); }); it('disabled should click not to change', () => { const onChange = jest.fn(); const onClick = jest.fn(); - const wrapper = createSwitch({ disabled: true, onChange, onClick, checked: true }); + const { getByRole } = createSwitch({ disabled: true, onChange, onClick, checked: true }); - wrapper.simulate('click'); + fireEvent.click(getByRole('switch')); expect(onChange).not.toHaveBeenCalled(); }); it('support classnames and styles', () => { - const wrapper = createSwitch({ + const { container } = createSwitch({ classNames: { content: 'custom-content' }, styles: { content: { background: 'red' } }, }); - const contentElement = wrapper.find('.custom-content').at(0); - expect(contentElement.exists()).toBe(true); - expect(contentElement.prop('style')).toEqual({ background: 'red' }); + const contentElement = container.querySelector('.custom-content'); + + expect(contentElement).toBeTruthy(); + expect(contentElement.style.background).toBe('red'); }); });