test: verify useCalculateKclExpression cancellation
This commit is contained in:
68
src/lib/useCalculateKclExpression.test.tsx
Normal file
68
src/lib/useCalculateKclExpression.test.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import { renderHook, act } from '@testing-library/react'
|
||||
import { vi } from 'vitest'
|
||||
|
||||
import { useCalculateKclExpression } from '@src/lib/useCalculateKclExpression'
|
||||
import { getCalculatedKclExpressionValue } from '@src/lib/kclHelpers'
|
||||
|
||||
vi.mock('@src/lib/kclHelpers', () => {
|
||||
return {
|
||||
getCalculatedKclExpressionValue: vi.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@src/lang/KclProvider', () => {
|
||||
return {
|
||||
useKclContext: () => ({ code: '', variables: {} }),
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@src/hooks/useModelingContext', () => {
|
||||
return {
|
||||
useModelingContext: () => ({ context: { selectionRanges: { graphSelections: [] } } }),
|
||||
}
|
||||
})
|
||||
|
||||
const mockedGetValue = getCalculatedKclExpressionValue as unknown as ReturnType<typeof vi.fn>
|
||||
|
||||
describe('useCalculateKclExpression', () => {
|
||||
it('ignores outdated asynchronous results', async () => {
|
||||
let resolveFirst: (v: any) => void
|
||||
let resolveSecond: (v: any) => void
|
||||
|
||||
mockedGetValue
|
||||
.mockImplementationOnce(
|
||||
() =>
|
||||
new Promise((res) => {
|
||||
resolveFirst = res
|
||||
})
|
||||
)
|
||||
.mockImplementationOnce(
|
||||
() =>
|
||||
new Promise((res) => {
|
||||
resolveSecond = res
|
||||
})
|
||||
)
|
||||
|
||||
const { result, rerender } = renderHook(
|
||||
({ value }) => useCalculateKclExpression({ value }),
|
||||
{ initialProps: { value: '1+1' } }
|
||||
)
|
||||
|
||||
// Trigger a new calculation before the first one resolves
|
||||
rerender({ value: '2+2' })
|
||||
|
||||
await act(async () => {
|
||||
resolveSecond!({ astNode: {}, valueAsString: '4' })
|
||||
await Promise.resolve()
|
||||
})
|
||||
|
||||
expect(result.current.calcResult).toBe('4')
|
||||
|
||||
await act(async () => {
|
||||
resolveFirst!({ astNode: {}, valueAsString: '2' })
|
||||
await Promise.resolve()
|
||||
})
|
||||
|
||||
expect(result.current.calcResult).toBe('4')
|
||||
})
|
||||
})
|
||||
@ -115,8 +115,11 @@ export function useCalculateKclExpression({
|
||||
}, [kclManager.ast, kclManager.variables, endingSourceRange])
|
||||
|
||||
useEffect(() => {
|
||||
let isCurrent = true
|
||||
|
||||
const execAstAndSetResult = async () => {
|
||||
const result = await getCalculatedKclExpressionValue(value)
|
||||
if (!isCurrent) return
|
||||
setIsExecuting(false)
|
||||
if (result instanceof Error || 'errors' in result || !result.astNode) {
|
||||
setCalcResult('NAN')
|
||||
@ -131,10 +134,15 @@ export function useCalculateKclExpression({
|
||||
if (!value) return
|
||||
setIsExecuting(true)
|
||||
execAstAndSetResult().catch(() => {
|
||||
if (!isCurrent) return
|
||||
setCalcResult('NAN')
|
||||
setIsExecuting(false)
|
||||
setValueNode(null)
|
||||
})
|
||||
|
||||
return () => {
|
||||
isCurrent = false
|
||||
}
|
||||
}, [value, availableVarInfo, code, kclManager.variables])
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user