Repository: ant-design/ant-design-mobile
Pull request #5483 (2022-07-19 07:27:00)

enhance(PasscodeInput): export type `PasscodeInputRef` and add some tests


Patch:
diff --git a/src/components/passcode-input/index.ts b/src/components/passcode-input/index.ts
index 33b182489..397c6ce76 100644
--- a/src/components/passcode-input/index.ts
+++ b/src/components/passcode-input/index.ts
@@ -1,6 +1,6 @@
 import './passcode-input.less'
 import { PasscodeInput } from './passcode-input'
 
-export type { PasscodeInputProps } from './passcode-input'
+export type { PasscodeInputProps, PasscodeInputRef } from './passcode-input'
 
 export default PasscodeInput


Test patch:
diff --git a/src/components/passcode-input/tests/passcode-input.test.tsx b/src/components/passcode-input/tests/passcode-input.test.tsx
new file mode 100644
index 000000000..31261ca82
--- /dev/null
+++ b/src/components/passcode-input/tests/passcode-input.test.tsx
@@ -0,0 +1,114 @@
+import React, { createRef } from 'react'
+import { render, screen, fireEvent, userEvent, act } from 'testing'
+import PasscodeInput, { PasscodeInputRef } from '..'
+import { NumberKeyboard } from 'antd-mobile'
+
+const classPrefix = 'adm-passcode-input'
+const cellClassPrefix = 'adm-passcode-input-cell'
+
+function getCells() {
+  return document.body.querySelectorAll(`.${classPrefix}-cell`)
+}
+
+function mockClick(el: HTMLElement) {
+  fireEvent.touchStart(el, { touches: [{}] })
+  fireEvent.touchEnd(el, { touches: [{}] })
+}
+
+describe('PasscodeInput', () => {
+  test('basic usage', () => {
+    render(<PasscodeInput keyboard={<NumberKeyboard />} />)
+    const input = screen.getByRole('button', { name: '密码输入框' })
+    fireEvent.focus(input)
+    expect(input).toHaveClass(`${classPrefix}-focused`)
+
+    mockClick(screen.getByText('1'))
+    const cells = getCells()
+    expect(cells[0]).toHaveClass(`${cellClassPrefix}-dot`)
+    expect(cells[1]).toHaveClass(
+      `${cellClassPrefix}-caret ${cellClassPrefix}-focused`
+    )
+  })
+
+  test('plain should be work', () => {
+    render(<PasscodeInput plain keyboard={<NumberKeyboard />} />)
+    const input = screen.getByRole('button', { name: '密码输入框' })
+    fireEvent.focus(input)
+
+    mockClick(screen.getByText('1'))
+    const cells = getCells()
+    expect(cells[0]).not.toHaveClass(`${cellClassPrefix}-dot`)
+    expect(cells[0]).toHaveTextContent('1')
+  })
+
+  test('renders with error', () => {
+    render(<PasscodeInput error />)
+    const input = screen.getByRole('button', { name: '密码输入框' })
+    expect(input).toHaveClass(`${classPrefix}-error`)
+  })
+
+  test('seperated should be work', () => {
+    render(<PasscodeInput seperated keyboard={<NumberKeyboard />} />)
+    const input = screen.getByRole('button', { name: '密码输入框' })
+    expect(input).toHaveClass(`${classPrefix}-seperated`)
+    fireEvent.focus(input)
+
+    const cells = getCells()
+    expect(cells[0]).toHaveClass(
+      `${cellClassPrefix}-caret ${cellClassPrefix}-focused`
+    )
+
+    mockClick(screen.getByText('1'))
+    expect(cells[0]).toHaveClass(`${cellClassPrefix}-dot`)
+    expect(cells[1]).toHaveClass(
+      `${cellClassPrefix}-caret ${cellClassPrefix}-focused`
+    )
+  })
+
+  test('native keyboard should be work', async () => {
+    render(<PasscodeInput plain />)
+    const input = screen.getByRole('button', { name: '密码输入框' })
+    fireEvent.focus(input)
+    await userEvent.keyboard('abc')
+    expect(input).toHaveTextContent('abc')
+  })
+
+  test('event callbacks should be called', async () => {
+    const onBlur = jest.fn()
+    const onChange = jest.fn()
+    const onFill = jest.fn()
+    const onFocus = jest.fn()
+    render(
+      <PasscodeInput
+        length={4}
+        onBlur={onBlur}
+        onChange={onChange}
+        onFill={onFill}
+        onFocus={onFocus}
+      />
+    )
+
+    const input = screen.getByRole('button', { name: '密码输入框' })
+    fireEvent.focus(input)
+    expect(onFocus).toBeCalled()
+    await userEvent.keyboard('abcde')
+    expect(onFill).toBeCalled()
+    expect(onChange).toBeCalledTimes(4)
+    fireEvent.blur(input)
+    expect(onBlur).toBeCalled()
+  })
+
+  test('imperative handle', () => {
+    const ref = createRef<PasscodeInputRef>()
+    render(<PasscodeInput ref={ref} />)
+    const input = screen.getByRole('button', { name: '密码输入框' })
+    act(() => {
+      ref.current?.focus()
+    })
+    expect(input).toHaveClass(`${classPrefix}-focused`)
+    act(() => {
+      ref.current?.blur()
+    })
+    expect(input).not.toHaveClass(`${classPrefix}-focused`)
+  })
+})