Compare commits

...

1 Commits

Author SHA1 Message Date
9b901dfe51 test: verify useCalculateKclExpression cancellation 2025-05-16 19:53:57 -07:00
2 changed files with 76 additions and 0 deletions

View 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')
})
})

View File

@ -115,8 +115,11 @@ export function useCalculateKclExpression({
}, [kclManager.ast, kclManager.variables, endingSourceRange]) }, [kclManager.ast, kclManager.variables, endingSourceRange])
useEffect(() => { useEffect(() => {
let isCurrent = true
const execAstAndSetResult = async () => { const execAstAndSetResult = async () => {
const result = await getCalculatedKclExpressionValue(value) const result = await getCalculatedKclExpressionValue(value)
if (!isCurrent) return
setIsExecuting(false) setIsExecuting(false)
if (result instanceof Error || 'errors' in result || !result.astNode) { if (result instanceof Error || 'errors' in result || !result.astNode) {
setCalcResult('NAN') setCalcResult('NAN')
@ -131,10 +134,15 @@ export function useCalculateKclExpression({
if (!value) return if (!value) return
setIsExecuting(true) setIsExecuting(true)
execAstAndSetResult().catch(() => { execAstAndSetResult().catch(() => {
if (!isCurrent) return
setCalcResult('NAN') setCalcResult('NAN')
setIsExecuting(false) setIsExecuting(false)
setValueNode(null) setValueNode(null)
}) })
return () => {
isCurrent = false
}
}, [value, availableVarInfo, code, kclManager.variables]) }, [value, availableVarInfo, code, kclManager.variables])
return { return {