From 31b466770509c15b1eea6283b40c83d2259623e5 Mon Sep 17 00:00:00 2001 From: oasis-cloud Date: Fri, 17 Jan 2025 11:35:54 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(inputnumber):=20=E5=A2=9E=E5=8A=A0=20be?= =?UTF-8?q?foreChange=EF=BC=8C=E4=BC=98=E5=8C=96=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/inputnumber/demos/h5/demo8.tsx | 30 +++- src/packages/inputnumber/demos/taro/demo8.tsx | 29 +++- src/packages/inputnumber/doc.en-US.md | 5 +- src/packages/inputnumber/doc.md | 5 +- src/packages/inputnumber/doc.taro.md | 3 +- src/packages/inputnumber/doc.zh-TW.md | 4 +- src/packages/inputnumber/inputnumber.taro.tsx | 154 +++++++----------- src/packages/inputnumber/inputnumber.tsx | 151 +++++++---------- 8 files changed, 176 insertions(+), 205 deletions(-) diff --git a/src/packages/inputnumber/demos/h5/demo8.tsx b/src/packages/inputnumber/demos/h5/demo8.tsx index e66949dddf..ef91fe0d5c 100644 --- a/src/packages/inputnumber/demos/h5/demo8.tsx +++ b/src/packages/inputnumber/demos/h5/demo8.tsx @@ -1,27 +1,43 @@ -import React, { useState } from 'react' +import React, { useRef, useState } from 'react' import { InputNumber, Toast } from '@nutui/nutui-react' +type DebounceFunction = (...args: T) => void + +function useDebounce( + func: (...args: T) => void, + delay: number +): DebounceFunction { + const timeoutId: any = useRef() + return function (...args: T) { + if (timeoutId.current) { + clearTimeout(timeoutId.current) + } + timeoutId.current = setTimeout(() => { + func(...args) + }, delay) + } +} + const Demo8 = () => { const [inputValue, setInputValue] = useState(0) const overlimit = (e: any) => { console.log('超出限制事件触发', e) } - const onChange = (value: string | number) => { + + const onChange = useDebounce((value: string | number) => { Toast.show({ icon: 'loading', content: '异步演示2秒后更改' }) - console.log('onChange', value) setTimeout(() => { setInputValue(Number(value)) Toast.clear() }, 2000) - } + }, 300) + return ( ) } diff --git a/src/packages/inputnumber/demos/taro/demo8.tsx b/src/packages/inputnumber/demos/taro/demo8.tsx index 6b59ffac5e..85f93d267f 100644 --- a/src/packages/inputnumber/demos/taro/demo8.tsx +++ b/src/packages/inputnumber/demos/taro/demo8.tsx @@ -1,6 +1,23 @@ -import React, { useState } from 'react' +import React, { useRef, useState } from 'react' import { InputNumber, Toast } from '@nutui/nutui-react-taro' +type DebounceFunction = (...args: T) => void + +function useDebounce( + func: (...args: T) => void, + delay: number +): DebounceFunction { + const timeoutId: any = useRef() + return function (...args: T) { + if (timeoutId.current) { + clearTimeout(timeoutId.current) + } + timeoutId.current = setTimeout(() => { + func(...args) + }, delay) + } +} + const Demo8 = () => { const [inputValue, setInputValue] = useState(0) const [show, SetShow] = useState(false) @@ -15,23 +32,21 @@ const Demo8 = () => { const overlimit = (e: any) => { console.log('超出限制事件触发', e) } - const onChange = (value: string | number) => { + const onChange = useDebounce((value: string | number) => { toastShow('异步演示 2 秒后更改', 'loading') - console.log('onChange', value) setTimeout(() => { setInputValue(Number(value)) SetShow(false) }, 2000) - } + }, 300) + return ( <> boolean \| Promise` | `-` | | onPlus | Triggered when the Add button is clicked | `(e: MouseEvent) => void` | `-` | | onMinus | Triggered when the decrease button is clicked | `(e: MouseEvent) => void` | `-` | | onOverlimit | Triggered when an unavailable button is clicked | `(e: MouseEvent) => void` | `-` | diff --git a/src/packages/inputnumber/doc.md b/src/packages/inputnumber/doc.md index d2afd0b4d1..796702b0cf 100644 --- a/src/packages/inputnumber/doc.md +++ b/src/packages/inputnumber/doc.md @@ -121,9 +121,10 @@ import { InputNumber } from '@nutui/nutui-react' | digits | 设置保留的小数位 | `string` \| `number` | `0` | | disabled | 禁用所有功能 | `boolean` | `false` | | readOnly | 只读状态禁用输入框操作行为 | `boolean` | `false` | -| async | 支持异步修改 | `boolean` | `false` | -| select | 支持取消文本全选中 | `boolean` | `true` | +| ~~async~~`2.8.0` | 支持异步修改 | `boolean` | `false` | +| select`2.7.0` | 支持取消文本全选中 | `boolean` | `true` | | formatter | 指定输入框展示值的格式 | `function(value: number \| string): string` | `-` | +| beforeChange`2.8.0` | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise` | `-` | | onPlus | 点击增加按钮时触发 | `(e: MouseEvent) => void` | `-` | | onMinus | 点击减少按钮时触发 | `(e: MouseEvent) => void` | `-` | | onOverlimit | 点击不可用的按钮时触发 | `(e: MouseEvent) => void` | `-` | diff --git a/src/packages/inputnumber/doc.taro.md b/src/packages/inputnumber/doc.taro.md index fb9a619b1c..5c4c446245 100644 --- a/src/packages/inputnumber/doc.taro.md +++ b/src/packages/inputnumber/doc.taro.md @@ -114,8 +114,9 @@ import { InputNumber } from '@nutui/nutui-react-taro' | digits | 设置保留的小数位 | `string` \| `number` | `0` | | disabled | 禁用所有功能 | `boolean` | `false` | | readOnly | 只读状态禁用输入框操作行为 | `boolean` | `false` | -| async | 支持异步修改 | `boolean` | `false` | +| ~~async~~`2.8.0` | 支持异步修改 | `boolean` | `false` | | formatter | 指定输入框展示值的格式 | `function(value: number \| string): string` | `-` | +| beforeChange`2.8.0` | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise` | `-` | | onPlus | 点击增加按钮时触发 | `(e: MouseEvent) => void` | `-` | | onMinus | 点击减少按钮时触发 | `(e: MouseEvent) => void` | `-` | | onOverlimit | 点击不可用的按钮时触发 | `(e: MouseEvent) => void` | `-` | diff --git a/src/packages/inputnumber/doc.zh-TW.md b/src/packages/inputnumber/doc.zh-TW.md index 5a1cb78e4c..4d7f253b40 100644 --- a/src/packages/inputnumber/doc.zh-TW.md +++ b/src/packages/inputnumber/doc.zh-TW.md @@ -113,8 +113,10 @@ import { InputNumber } from '@nutui/nutui-react' | digits | 設置保留的小數位 | `string` \| `number` | `0` | | disabled | 禁用所有功能 | `boolean` | `false` | | readOnly | 只讀狀態禁用輸入框操作行為 | `boolean` | `false` | -| async | 支持異步修改 | `boolean` | `false` | +| ~~async~~`2.8.0` | 支持異步修改 | `boolean` | `false` | +| select`2.7.0` | 支持取消文本全选中 | `boolean` | `true` | | formatter | 指定輸入框展示值的格式 | `function(value: number \| string): string` | `-` | +| beforeChange`2.8.0` | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise` | `-` | | onPlus | 點擊增加按鈕時觸發 | `(e: MouseEvent) => void` | `-` | | onMinus | 點擊減少按鈕時觸發 | `(e: MouseEvent) => void` | `-` | | onOverlimit | 點擊不可用的按鈕時觸發 | `(e: MouseEvent) => void` | `-` | diff --git a/src/packages/inputnumber/inputnumber.taro.tsx b/src/packages/inputnumber/inputnumber.taro.tsx index 451057b9ff..3c3ab17b26 100644 --- a/src/packages/inputnumber/inputnumber.taro.tsx +++ b/src/packages/inputnumber/inputnumber.taro.tsx @@ -10,6 +10,7 @@ import classNames from 'classnames' import { InputProps } from '@tarojs/components' import { usePropsValue } from '@/utils/use-props-value' import { BasicComponent, ComponentDefaults } from '@/utils/typings' +import { bound } from '@/utils/bound' export interface InputNumberProps extends BasicComponent { value: number | string @@ -22,7 +23,6 @@ export interface InputNumberProps extends BasicComponent { readOnly: boolean step: number digits: number - async: boolean select: boolean formatter?: (value?: string | number) => string onPlus: (e: React.MouseEvent) => void @@ -30,6 +30,7 @@ export interface InputNumberProps extends BasicComponent { onOverlimit: (e: React.MouseEvent | ChangeEvent) => void onBlur: (e: React.FocusEvent) => void onFocus: (e: React.FocusEvent) => void + beforeChange: (value: number | string) => boolean | Promise onChange: ( param: string | number, e: React.MouseEvent | ChangeEvent @@ -43,11 +44,10 @@ const defaultProps = { allowEmpty: false, min: 1, max: 9999, - type: 'digit', step: 1, digits: 0, - async: false, select: true, + beforeChange: (value) => Promise.resolve(true), } as InputNumberProps const classPrefix = `nut-inputnumber` @@ -67,7 +67,6 @@ export const InputNumber: FunctionComponent< allowEmpty, digits, step, - async, select, className, style, @@ -78,6 +77,7 @@ export const InputNumber: FunctionComponent< onBlur, onFocus, onChange, + beforeChange, ...restProps } = { ...defaultProps, @@ -101,23 +101,16 @@ export const InputNumber: FunctionComponent< ? parseFloat(defaultValue) : defaultValue, finalValue: 0, - onChange: (value) => {}, }) - const bound = (value: number, min: number, max: number) => { - let res = value - if (min !== undefined) { - res = Math.max(Number(min), res) - } - if (max !== undefined) { - res = Math.min(Number(max), res) - } - return res - } + const format = (value: number | null | string): string => { if (value === null) return '' // 如果超过 min 或 max, 需要纠正 - if (typeof value === 'string') value = parseFloat(value) - const fixedValue = bound(value, Number(min), Number(max)) + const fixedValue = bound( + typeof value === 'string' ? parseFloat(value) : value, + Number(min), + Number(max) + ) if (formatter) { return formatter(fixedValue) } @@ -126,57 +119,53 @@ export const InputNumber: FunctionComponent< } return fixedValue.toString() } + const [inputValue, setInputValue] = useState(format(shadowValue)) useEffect(() => { - if (!focused && !async) { - setShadowValue(bound(Number(shadowValue), Number(min), Number(max))) + if (!focused) { setInputValue(format(shadowValue)) } }, [focused, shadowValue]) - useEffect(() => { - if (async) { - setShadowValue(bound(Number(value), Number(min), Number(max))) - setInputValue(format(value)) - } - }, [value]) - - const calcNextValue = (current: any, step: any, symbol: number) => { + const calcNextValue = (current: any, stepValue: any, symbol: number) => { const dig = digits + 1 - return ( - (parseFloat(current || '0') * dig + parseFloat(step) * dig * symbol) / dig - ) + const currentValue = parseFloat(current || '0') + const stepAmount = parseFloat(stepValue) * symbol + return (currentValue * dig + stepAmount * dig) / dig } - const update = (negative: boolean, e: React.MouseEvent) => { - if (step !== undefined) { - const shouldOverBoundary = calcNextValue( - shadowValue, - step, - negative ? -1 : 1 - ) - const nextValue = bound(shouldOverBoundary, Number(min), Number(max)) - setShadowValue(nextValue) - if ( - negative - ? shouldOverBoundary < Number(min) - : shouldOverBoundary > Number(max) - ) { - onOverlimit?.(e) - } else { - onChange?.(nextValue, e) - } + + const update = async (negative: boolean, e: React.MouseEvent) => { + if (step === undefined) return + negative ? onMinus?.(e) : onPlus?.(e) + + const shouldOverBoundary = calcNextValue( + shadowValue, + step, + negative ? -1 : 1 + ) + const maybeResume = await beforeChange(Number(shouldOverBoundary)) + if (!maybeResume) return + + const nextValue = bound(shouldOverBoundary, Number(min), Number(max)) + setShadowValue(nextValue) + if ( + negative + ? shouldOverBoundary < Number(min) + : shouldOverBoundary > Number(max) + ) { + onOverlimit?.(e) + } else { + onChange?.(nextValue, e) } } - const handleReduce = (e: React.MouseEvent) => { + const handleReduce = async (e: React.MouseEvent) => { if (disabled) return - onMinus?.(e) - update(true, e) + await update(true, e) } - const handlePlus = (e: React.MouseEvent) => { + const handlePlus = async (e: React.MouseEvent) => { if (disabled) return - onPlus?.(e) - update(false, e) + await update(false, e) } const parseValue = (text: string) => { @@ -184,38 +173,26 @@ export const InputNumber: FunctionComponent< if (text === '-') return null return text } - const clampValue = (valueStr: string | null) => { - if (valueStr === null) return defaultValue - const val = Number(parseFloat(valueStr || '0').toFixed(digits)) - return Math.max(Number(min), Math.min(Number(max), val)) - } - const handleValueChange = ( - valueStr: string | null, - e: React.ChangeEvent - ) => { - const val = clampValue(valueStr) - // input暂不触发onOverlimit - // if (val !== Number(e.target.value)) { - // onOverlimit?.(e) - // } - if (val !== Number(shadowValue)) { - onChange?.(val, e) - } - } - const handleInputChange = (e: ChangeEvent) => { + const handleInputChange = async (e: React.ChangeEvent) => { // 设置 input 值, 在 blur 时格式化 setInputValue(e.target.value) const valueStr = parseValue(e.target.value) - if (valueStr === null) { - if (allowEmpty) { - setShadowValue(null) - } else { - setShadowValue(defaultValue) - } + const maybeResume = await beforeChange(Number(valueStr)) + if (!maybeResume) return + + setShadowValue( + // eslint-disable-next-line no-nested-ternary + valueStr === null ? (allowEmpty ? null : defaultValue) : valueStr + ) + + if ( + valueStr !== null && + (Number(valueStr) < Number(min) || Number(valueStr) > Number(max)) + ) { + onOverlimit?.(e) } else { - setShadowValue(clampValue(valueStr) as any) + onChange?.(parseFloat(valueStr || '0').toFixed(digits), e) } - !async && handleValueChange(valueStr, e) } const handleFocus = (e: React.FocusEvent) => { setFocused(true) @@ -228,18 +205,9 @@ export const InputNumber: FunctionComponent< } const handleBlur = (e: React.FocusEvent) => { setFocused(false) - onBlur?.(e) + onBlur && onBlur(e) const valueStr = parseValue(e.target.value) - if (valueStr === null) { - if (allowEmpty) { - setShadowValue(null) - } else { - setShadowValue(defaultValue) - } - } else { - setShadowValue(clampValue(valueStr) as any) - } - async && handleValueChange(valueStr, e) + onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e) } return ( @@ -252,8 +220,6 @@ export const InputNumber: FunctionComponent< /> string onPlus: (e: React.MouseEvent) => void @@ -28,6 +28,7 @@ export interface InputNumberProps extends BasicComponent { onOverlimit: (e: React.MouseEvent | ChangeEvent) => void onBlur: (e: React.FocusEvent) => void onFocus: (e: React.FocusEvent) => void + beforeChange: (value: number | string) => boolean | Promise onChange: ( param: string | number, e: React.MouseEvent | ChangeEvent @@ -43,8 +44,8 @@ const defaultProps = { max: 9999, step: 1, digits: 0, - async: false, select: true, + beforeChange: (value) => Promise.resolve(true), } as InputNumberProps const classPrefix = `nut-inputnumber` @@ -63,7 +64,6 @@ export const InputNumber: FunctionComponent< allowEmpty, digits, step, - async, select, className, style, @@ -74,6 +74,7 @@ export const InputNumber: FunctionComponent< onBlur, onFocus, onChange, + beforeChange, ...restProps } = { ...defaultProps, @@ -97,23 +98,16 @@ export const InputNumber: FunctionComponent< ? parseFloat(defaultValue) : defaultValue, finalValue: 0, - onChange: (value) => {}, }) - const bound = (value: number, min: number, max: number) => { - let res = value - if (min !== undefined) { - res = Math.max(Number(min), res) - } - if (max !== undefined) { - res = Math.min(Number(max), res) - } - return res - } + const format = (value: number | null | string): string => { if (value === null) return '' // 如果超过 min 或 max, 需要纠正 - if (typeof value === 'string') value = parseFloat(value) - const fixedValue = bound(value, Number(min), Number(max)) + const fixedValue = bound( + typeof value === 'string' ? parseFloat(value) : value, + Number(min), + Number(max) + ) if (formatter) { return formatter(fixedValue) } @@ -122,57 +116,53 @@ export const InputNumber: FunctionComponent< } return fixedValue.toString() } + const [inputValue, setInputValue] = useState(format(shadowValue)) useEffect(() => { - if (!focused && !async) { - setShadowValue(bound(Number(shadowValue), Number(min), Number(max))) + if (!focused) { setInputValue(format(shadowValue)) } }, [focused, shadowValue]) - useEffect(() => { - if (async) { - setShadowValue(bound(Number(value), Number(min), Number(max))) - setInputValue(format(value)) - } - }, [value]) - - const calcNextValue = (current: any, step: any, symbol: number) => { + const calcNextValue = (current: any, stepValue: any, symbol: number) => { const dig = digits + 1 - return ( - (parseFloat(current || '0') * dig + parseFloat(step) * dig * symbol) / dig - ) + const currentValue = parseFloat(current || '0') + const stepAmount = parseFloat(stepValue) * symbol + return (currentValue * dig + stepAmount * dig) / dig } - const update = (negative: boolean, e: React.MouseEvent) => { - if (step !== undefined) { - const shouldOverBoundary = calcNextValue( - shadowValue, - step, - negative ? -1 : 1 - ) - const nextValue = bound(shouldOverBoundary, Number(min), Number(max)) - setShadowValue(nextValue) - if ( - negative - ? shouldOverBoundary < Number(min) - : shouldOverBoundary > Number(max) - ) { - onOverlimit?.(e) - } else { - onChange?.(nextValue, e) - } + + const update = async (negative: boolean, e: React.MouseEvent) => { + if (step === undefined) return + negative ? onMinus?.(e) : onPlus?.(e) + + const shouldOverBoundary = calcNextValue( + shadowValue, + step, + negative ? -1 : 1 + ) + const maybeResume = await beforeChange(Number(shouldOverBoundary)) + if (!maybeResume) return + + const nextValue = bound(shouldOverBoundary, Number(min), Number(max)) + setShadowValue(nextValue) + if ( + negative + ? shouldOverBoundary < Number(min) + : shouldOverBoundary > Number(max) + ) { + onOverlimit?.(e) + } else { + onChange?.(nextValue, e) } } - const handleReduce = (e: React.MouseEvent) => { + const handleReduce = async (e: React.MouseEvent) => { if (disabled) return - onMinus?.(e) - update(true, e) + await update(true, e) } - const handlePlus = (e: React.MouseEvent) => { + const handlePlus = async (e: React.MouseEvent) => { if (disabled) return - onPlus?.(e) - update(false, e) + await update(false, e) } const parseValue = (text: string) => { @@ -180,38 +170,26 @@ export const InputNumber: FunctionComponent< if (text === '-') return null return text } - const clampValue = (valueStr: string | null) => { - if (valueStr === null) return defaultValue - const val = Number(parseFloat(valueStr || '0').toFixed(digits)) - return Math.max(Number(min), Math.min(Number(max), val)) - } - const handleValueChange = ( - valueStr: string | null, - e: React.ChangeEvent - ) => { - const val = clampValue(valueStr) - // input暂不触发onOverlimit - // if (val !== Number(e.target.value)) { - // onOverlimit?.(e) - // } - if (val !== Number(shadowValue)) { - onChange?.(val, e) - } - } - const handleInputChange = (e: React.ChangeEvent) => { + const handleInputChange = async (e: React.ChangeEvent) => { // 设置 input 值, 在 blur 时格式化 setInputValue(e.target.value) const valueStr = parseValue(e.target.value) - if (valueStr === null) { - if (allowEmpty) { - setShadowValue(null) - } else { - setShadowValue(defaultValue) - } + const maybeResume = await beforeChange(Number(valueStr)) + if (!maybeResume) return + + setShadowValue( + // eslint-disable-next-line no-nested-ternary + valueStr === null ? (allowEmpty ? null : defaultValue) : valueStr + ) + + if ( + valueStr !== null && + (Number(valueStr) < Number(min) || Number(valueStr) > Number(max)) + ) { + onOverlimit?.(e) } else { - setShadowValue(clampValue(valueStr) as any) + onChange?.(parseFloat(valueStr || '0').toFixed(digits), e) } - !async && handleValueChange(valueStr, e) } const handleFocus = (e: React.FocusEvent) => { setFocused(true) @@ -224,18 +202,9 @@ export const InputNumber: FunctionComponent< } const handleBlur = (e: React.FocusEvent) => { setFocused(false) - onBlur?.(e) + onBlur && onBlur(e) const valueStr = parseValue(e.target.value) - if (valueStr === null) { - if (allowEmpty) { - setShadowValue(null) - } else { - setShadowValue(defaultValue) - } - } else { - setShadowValue(clampValue(valueStr) as any) - } - async && handleValueChange(valueStr, e) + onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e) } return ( From c91aa96d884b228e135f41c59da66f6517c2e62a Mon Sep 17 00:00:00 2001 From: oasis-cloud Date: Fri, 17 Jan 2025 16:54:59 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(inputnumber):=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=8D=95=E6=B5=8B=EF=BC=8C=E5=9B=A0=E4=B8=BA=20onChange=20?= =?UTF-8?q?=E5=92=8C=20update=20=E6=96=B9=E6=B3=95=E6=94=B9=E6=88=90?= =?UTF-8?q?=E4=BA=86=20async=20=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/inputnumber.spec.tsx | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/src/packages/inputnumber/__tests__/inputnumber.spec.tsx b/src/packages/inputnumber/__tests__/inputnumber.spec.tsx index 606fec2100..cff6e24306 100644 --- a/src/packages/inputnumber/__tests__/inputnumber.spec.tsx +++ b/src/packages/inputnumber/__tests__/inputnumber.spec.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { render, fireEvent, waitFor } from '@testing-library/react' +import { render, fireEvent, waitFor, act } from '@testing-library/react' import '@testing-library/jest-dom' import { InputNumber } from '../inputnumber' @@ -9,7 +9,7 @@ test('should render modelValue', () => { expect(container.querySelector('input')?.value).toBe('12') }) -test('should add step 2 when trigger click plus button', () => { +test('should add step 2 when trigger click plus button', async () => { const overlimit = vi.fn() const add = vi.fn() const change = vi.fn() @@ -23,13 +23,16 @@ test('should add step 2 when trigger click plus button', () => { /> ) const iconPlus = container.querySelectorAll('.nut-icon-Plus')[0] - fireEvent.click(iconPlus) + await act(async () => { + fireEvent.click(iconPlus) + }) + expect(overlimit).not.toBeCalled() - expect(add).toBeCalled() + expect(add).toHaveBeenCalled() expect(change.mock.calls[0][0]).toBe(3) }) -test('should minis step 2 when trigger click minis button', () => { +test('should minis step 2 when trigger click minis button', async () => { const overlimit = vi.fn() const reduce = vi.fn() const change = vi.fn() @@ -43,13 +46,15 @@ test('should minis step 2 when trigger click minis button', () => { /> ) const iconMinus = container.querySelectorAll('.nut-icon-Minus')[0] - fireEvent.click(iconMinus) + await act(async () => { + fireEvent.click(iconMinus) + }) expect(overlimit).not.toBeCalled() expect(reduce).toBeCalled() expect(change.mock.calls[0][0]).toBe(1) }) -test('should render max props', () => { +test('should render max props', async () => { const overlimit = vi.fn() const add = vi.fn() const change = vi.fn() @@ -64,13 +69,15 @@ test('should render max props', () => { /> ) const iconPlus = container.querySelectorAll('.nut-icon-Plus')[0] - fireEvent.click(iconPlus) + await act(async () => { + fireEvent.click(iconPlus) + }) expect(overlimit).toBeCalled() expect(add).toBeCalled() expect(change).not.toBeCalled() }) -test('should render min props', () => { +test('should render min props', async () => { const overlimit = vi.fn() const reduce = vi.fn() const change = vi.fn() @@ -85,7 +92,9 @@ test('should render min props', () => { /> ) const iconMinus = container.querySelectorAll('.nut-icon-Minus')[0] - fireEvent.click(iconMinus) + await act(async () => { + fireEvent.click(iconMinus) + }) expect(overlimit).toBeCalled() expect(reduce).toBeCalled() expect(change).not.toBeCalled() @@ -104,23 +113,27 @@ test('should not trigger click when disabled props to be true', () => { expect(container.querySelector('input')?.value).toBe('1') }) -test('should not focus input when readOnly props to be true', () => { +test('should not focus input when readOnly props to be true', async () => { const focus = vi.fn() const { container } = render( ) const iconMinus = container.querySelectorAll('.nut-icon-Minus')[0] - fireEvent.click(iconMinus) + await act(async () => { + fireEvent.click(iconMinus) + }) expect(container.querySelector('input')?.value).toBe('1') expect(focus).not.toBeCalled() }) -test('should render decimal when step props to be 0.2', () => { +test('should render decimal when step props to be 0.2', async () => { const { container } = render( ) const iconPlus = container.querySelectorAll('.nut-icon-Plus')[0] - fireEvent.click(iconPlus) + await act(async () => { + fireEvent.click(iconPlus) + }) expect(container.querySelector('input')?.value).toBe('2.2') }) @@ -158,19 +171,15 @@ test('allowEmpty', () => { }) }) -test('should overlimit when input', () => { - const change = vi.fn() +test('should overlimit when input', async () => { const overlimit = vi.fn() const { container } = render( - + ) const input = container.querySelectorAll('input')[0] input.value = '200' - fireEvent.input(input) - expect(change).toBeCalled() + await act(async () => { + fireEvent.input(input) + }) + expect(overlimit).toBeCalled() })