monomer-1.4.0.0: test/unit/Monomer/Widgets/Singles/NumericFieldSpec.hs
{-|
Module : Monomer.Widgets.Singles.NumericFieldSpec
Copyright : (c) 2018 Francisco Vallarino
License : BSD-3-Clause (see the LICENSE file)
Maintainer : fjvallarino@gmail.com
Stability : experimental
Portability : non-portable
Unit tests for NumericField widget.
-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module Monomer.Widgets.Singles.NumericFieldSpec (spec) where
import Control.Lens ((&), (^.), (.~))
import Control.Lens.TH (abbreviatedFields, makeLensesWith)
import Data.Default
import Data.Text (Text)
import Test.Hspec
import qualified Data.Sequence as Seq
import Monomer.Core
import Monomer.Core.Combinators
import Monomer.Event
import Monomer.TestUtil
import Monomer.TestEventUtil
import Monomer.Widgets.Containers.Stack
import Monomer.Widgets.Singles.Button
import Monomer.Widgets.Singles.NumericField
import qualified Monomer.Lens as L
data TestEvt
= IntegralChanged Int
| FractionalChanged (Maybe Double)
| ValidNumber Bool
| GotFocus Path
| LostFocus Path
deriving (Eq, Show)
data IntegralModel = IntegralModel {
_imIntegralValue :: Int,
_imIntegralValid :: Bool
} deriving (Eq, Show)
data FractionalModel = FractionalModel {
_fmFractionalValue :: Maybe Double,
_fmFractionalValid :: Bool
} deriving (Eq, Show)
makeLensesWith abbreviatedFields ''IntegralModel
makeLensesWith abbreviatedFields ''FractionalModel
spec :: Spec
spec = describe "NumericField" $ do
specIntegral
specFractional
specIntegral :: Spec
specIntegral = describe "IntegralField" $ do
handleEventIntegral
handleEventValueIntegral
handleEventMouseDragIntegral
handleEventReadOnly
getSizeReqIntegral
testIntegralWidgetType
handleEventIntegral :: Spec
handleEventIntegral = describe "handleEventIntegral" $ do
it "should remove the contents and get Nothing as model value" $ do
modelBasic [evtKG keyA, evtK keyBackspace] ^. integralValue `shouldBe` 0
modelBasic [evtKG keyA, evtK keyBackspace] ^. integralValid `shouldBe` False
it "should input '123' without select on focus" $ do
modelBasic [evtT "1", evtT "2", evtT "3"] ^. integralValue `shouldBe` 1230
modelBasic [evtT "1", evtT "2", evtT "3"] ^. integralValid `shouldBe` True
it "should input '1'" $ do
model [evtT "1"] ^. integralValue `shouldBe` 1
model [evtT "1"] ^. integralValid `shouldBe` True
events [evtT "1"] `shouldBe` Seq.fromList [ValidNumber True]
it "should input '-1'" $ do
model [evtT "-1"] ^. integralValue `shouldBe` -1
model [evtT "-1"] ^. integralValid `shouldBe` True
events [evtT "-1"] `shouldBe` Seq.fromList [ValidNumber True]
it "should input '1501'" $ do
model [evtT "1", evtT "5", evtT "0", evtT "1"] ^. integralValue `shouldBe` 1501
model [evtT "1", evtT "5", evtT "0", evtT "1"] ^. integralValid `shouldBe` True
events [evtT "1", evtT "5", evtT "0", evtT "1"] `shouldBe` Seq.fromList (replicate 4 (ValidNumber True))
it "should input '1502', but fail because of maxValue" $ do
model [evtT "1", evtT "5", evtT "0", evtT "2"] ^. integralValue `shouldBe` 150
model [evtT "1", evtT "5", evtT "0", evtT "2"] ^. integralValid `shouldBe` False
events [evtT "1", evtT "5", evtT "0", evtT "2"] `shouldBe` Seq.fromList (replicate 3 (ValidNumber True) ++ [ValidNumber False])
it "should input '123', remove one character and input '4'" $ do
model [evtT "123", delCharL, evtT "4"] ^. integralValue `shouldBe` 124
model [evtT "123", delCharL, evtT "4"] ^. integralValid `shouldBe` True
events [evtT "123", delCharL, evtT "4"] `shouldBe` Seq.fromList (replicate 3 (ValidNumber True))
it "should input '123', remove one word and input '456'" $ do
model [evtT "123", delWordL, evtT "456"] ^. integralValue `shouldBe` 456
model [evtT "123", delWordL, evtT "456"] ^. integralValid `shouldBe` True
events [evtT "123", delWordL, evtT "456"] `shouldBe` Seq.fromList [ValidNumber True, ValidNumber False, ValidNumber True]
it "should update the model when using the wheel" $ do
let p = Point 100 10
let steps1 = [WheelScroll p (Point 0 (-64)) WheelNormal]
let steps2 = [WheelScroll p (Point 0 300) WheelFlipped]
let steps3 = [WheelScroll p (Point 0 100) WheelNormal]
let steps4 = [WheelScroll p (Point 0 2000) WheelNormal]
model steps1 ^. integralValue `shouldBe` -64
model steps2 ^. integralValue `shouldBe` -200
model steps3 ^. integralValue `shouldBe` 100
model steps4 ^. integralValue `shouldBe` 1501
it "should generate IgnoreParentEvents when using the wheel" $ do
let p = Point 100 10
let steps = [WheelScroll p (Point 0 (-64)) WheelNormal]
reqs steps `shouldSatisfy` (IgnoreParentEvents `elem`)
it "should generate an event when focus is received" $
events [evtFocus] `shouldBe` Seq.singleton (GotFocus emptyPath)
it "should generate an event when focus is lost" $
events [evtBlur] `shouldBe` Seq.singleton (LostFocus emptyPath)
where
wenv = mockWenv (IntegralModel 0 True)
basicIntNode :: WidgetNode IntegralModel TestEvt
basicIntNode = numericField_ integralValue [validInput integralValid, selectOnFocus_ False]
intCfg = [minValue (-200), maxValue 1501, validInput integralValid, validInputV ValidNumber, onFocus GotFocus, onBlur LostFocus]
intNode = numericField_ integralValue intCfg
model es = nodeHandleEventModel wenv (evtFocus : es) intNode
modelBasic es = nodeHandleEventModel wenv es basicIntNode
events es = nodeHandleEventEvts wenv es intNode
reqs es = nodeHandleEventReqs wenv es intNode
handleEventValueIntegral :: Spec
handleEventValueIntegral = describe "handleEventIntegral" $ do
it "should input an '10'" $
evts [evtT "1", evtT "0"] `shouldBe` Seq.fromList [IntegralChanged 1, IntegralChanged 10]
it "should input '1', move to beginning and input '5'" $ do
let steps = [evtT "1", moveLineL, evtT "5"]
lastEvt steps `shouldBe` IntegralChanged 51
it "should input '1', input '.' then input '5'" $ do
let steps = [evtT "1", evtT ".", evtT "5"]
lastEvt steps `shouldBe` IntegralChanged 15
model steps ^. integralValid `shouldBe` True
it "should input '3', input 'a' then input '6'" $ do
let steps = [evtT "3", evtT "a", evtT "6"]
lastEvt steps `shouldBe` IntegralChanged 36
model steps ^. integralValid `shouldBe` True
it "should input '1234', delete line then input '777'" $ do
let steps = [evtT "1234", selLineL, evtT "777"]
lastEvt steps `shouldBe` IntegralChanged 777
model steps ^. integralValid `shouldBe` True
where
wenv = mockWenv (IntegralModel 0 False)
intNode = numericFieldV_ 0 IntegralChanged [maxValue 2345, selectOnFocus, validInput integralValid]
evts es = nodeHandleEventEvts wenv (evtFocus : es) intNode
model es = nodeHandleEventModel wenv (evtFocus : es) intNode
lastIdx es = Seq.index es (Seq.length es - 1)
lastEvt es = lastIdx (evts es)
handleEventMouseDragIntegral :: Spec
handleEventMouseDragIntegral = describe "handleEventMouseDragIntegral" $ do
it "should drag upwards 100 pixels, setting the value to 100" $ do
let selStart = Point 50 30
let selEnd = Point 50 (-70)
let steps = [evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. integralValue `shouldBe` 100
it "should drag downwards 100 pixels, setting the value to -200 (dragRate = 2)" $ do
let selStart = Point 50 50
let selEnd = Point 50 150
let steps = [evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. integralValue `shouldBe` -200
it "should drag downwards 1000 pixels, staying at -500 (the minimum)" $ do
let selStart = Point 50 50
let selEnd = Point 50 1050
let steps = [evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. integralValue `shouldBe` -500
it "should drag upwnwards 1000 pixels, staying at 500 (the maximum)" $ do
let selStart = Point 50 50
let selEnd = Point 50 (-950)
let steps = [evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. integralValue `shouldBe` 500
it "should drag downwards 30 and 20 pixels, setting the value to -5" $ do
let selStart = Point 50 30
let selMid = Point 50 60
let selEnd = Point 50 50
let steps = [
evtPress selStart, evtMove selMid, evtRelease selMid,
evtPress selStart, evtMove selEnd, evtRelease selEnd
]
model steps ^. integralValue `shouldBe` -50
it "should set focus and drag upwards 100 pixels, but value stay at 0 since shift is not pressed" $ do
let selStart = Point 50 30
let selEnd = Point 50 (-70)
let steps = [evtK keyTab, evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. integralValue `shouldBe` 0
it "should set focus and drag upwards 100 pixels, setting the value to 100 since shift is pressed" $ do
let selStart = Point 50 30
let selEnd = Point 50 (-70)
let steps = [evtKS keyTab, evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. integralValue `shouldBe` 100
it "should drag upwards 100 pixels, setting the value to 100 even if it was double clicked on" $ do
let selStart = Point 50 30
let selEnd = Point 50 (-70)
let steps = [evtDblClick selStart, evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. integralValue `shouldBe` 100
where
wenv = mockWenv (IntegralModel 0 False)
& L.inputStatus . L.keyMod . L.leftShift .~ True
integralNode = vstack [
button "Test" (IntegralChanged 0), -- Used only to have focus
numericField integralValue,
numericField_ integralValue [dragRate 2, minValue (-500), maxValue 500]
]
evts es = nodeHandleEventEvts wenv es integralNode
model es = nodeHandleEventModel wenv es integralNode
lastIdx es = Seq.index es (Seq.length es - 1)
lastEvt es = lastIdx (evts es)
getSizeReqIntegral :: Spec
getSizeReqIntegral = describe "getSizeReqIntegral" $ do
it "should return width = Flex 50 1" $
sizeReqW `shouldBe` expandSize 50 1
it "should return height = Fixed 20" $
sizeReqH `shouldBe` fixedSize 20
it "should return width = Flex 110 1 when resizeOnChange = True" $
sizeReqW2 `shouldBe` expandSize 110 1
it "should return height = Fixed 20 when resizeOnChange = True" $
sizeReqH2 `shouldBe` fixedSize 20
where
wenv = mockWenvEvtUnit (IntegralModel 10000000000 True)
(sizeReqW, sizeReqH) = nodeGetSizeReq wenv (numericField integralValue)
numericResize = numericField_ integralValue [resizeOnChange]
(sizeReqW2, sizeReqH2) = nodeGetSizeReq wenv numericResize
testIntegralWidgetType :: Spec
testIntegralWidgetType = describe "testIntegralWidgetType" $ do
it "should set the correct widgetType" $
node ^. L.info . L.widgetType `shouldBe` "numericField-Int"
where
node :: WidgetNode IntegralModel TestEvt
node = numericField integralValue
-- ------------------------------
-- Fractional field
-- ------------------------------
specFractional :: Spec
specFractional = describe "FractionalField" $ do
handleEventFractional
handleEventValueFractional
handleEventMouseDragFractional
handleShiftFocusFractional
getSizeReqFractional
testFractionalWidgetType
handleEventFractional :: Spec
handleEventFractional = describe "handleEventFractional" $ do
it "should remove the contents and get Nothing as model value" $ do
modelBasic [evtKG keyA, evtK keyBackspace] ^. fractionalValue `shouldBe` Nothing
modelBasic [evtKG keyA, evtK keyBackspace] ^. fractionalValid `shouldBe` True
it "should input '123' without select on focus" $ do
modelBasic [evtT "1", evtT "2", evtT "3"] ^. fractionalValue `shouldBe` Just 1230
modelBasic [evtT "1", evtT "2", evtT "3"] ^. fractionalValid `shouldBe` True
it "should input '1.23'" $ do
model [evtT "1.23"] ^. fractionalValue `shouldBe` Just 1.23
model [evtT "1.23"] ^. fractionalValid `shouldBe` True
it "should input '-1'" $ do
model [evtT "-1"] ^. fractionalValue `shouldBe` Just (-1)
model [evtT "-1"] ^. fractionalValid `shouldBe` True
it "should input '1501'" $ do
model [evtT "1", evtT "5", evtT "0", evtT "1"] ^. fractionalValue `shouldBe` Just 1501
model [evtT "1", evtT "5", evtT "0", evtT "1"] ^. fractionalValid `shouldBe` True
it "should input '1502', but fail because of maxValue" $ do
model [evtT "1", evtT "5", evtT "0", evtT "2"] ^. fractionalValue `shouldBe` Just 150
model [evtT "1", evtT "5", evtT "0", evtT "2"] ^. fractionalValid `shouldBe` False
it "should input '123', remove one character and input '4'" $ do
model [evtT "123", delCharL, evtT "4"] ^. fractionalValue `shouldBe` Just 124
model [evtT "123", delCharL, evtT "4"] ^. fractionalValid `shouldBe` True
it "should input '123', remove one word and input '456'" $ do
model [evtT "123", delWordL, evtT "456"] ^. fractionalValue `shouldBe` Just 456
model [evtT "123", delWordL, evtT "456"] ^. fractionalValid `shouldBe` True
it "should input '123.34', remove one word and input '56'" $ do
model [evtT "123.34", delWordL, evtT "56"] ^. fractionalValue `shouldBe` Just 123.56
model [evtT "123.34", delWordL, evtT "56"] ^. fractionalValid `shouldBe` True
it "should input '123.34', remove two words and input '56'" $ do
model [evtT "123.34", delWordL, delWordL, evtT "56"] ^. fractionalValue `shouldBe` Just 56
model [evtT "123.34", delWordL, delWordL, evtT "56"] ^. fractionalValid `shouldBe` True
it "should update the model when using the wheel" $ do
let p = Point 100 10
let steps1 = [WheelScroll p (Point 0 (-8000)) WheelNormal]
let steps2 = [WheelScroll p (Point 0 360) WheelFlipped]
let steps3 = [WheelScroll p (Point 0 8700) WheelNormal]
let steps4 = [WheelScroll p (Point 0 16000) WheelNormal]
model steps1 ^. fractionalValue `shouldBe` Just (-500)
model steps2 ^. fractionalValue `shouldBe` Just (-36)
model steps3 ^. fractionalValue `shouldBe` Just 870
model steps4 ^. fractionalValue `shouldBe` Just 1501
it "should generate IgnoreParentEvents when using the wheel" $ do
let p = Point 100 10
let steps = [WheelScroll p (Point 0 (-64)) WheelNormal]
reqs steps `shouldSatisfy` (IgnoreParentEvents `elem`)
it "should generate an event when focus is received" $
events evtFocus `shouldBe` Seq.singleton (GotFocus emptyPath)
it "should generate an event when focus is lost" $
events evtBlur `shouldBe` Seq.singleton (LostFocus emptyPath)
where
wenv = mockWenv (FractionalModel (Just 0) True)
basicFractionalNode :: WidgetNode FractionalModel TestEvt
basicFractionalNode = numericField_ fractionalValue [selectOnFocus_ False, validInput fractionalValid]
floatCfg = [minValue (Just (-500)), maxValue (Just 1501), validInput fractionalValid, onFocus GotFocus, onBlur LostFocus]
floatNode = numericField_ fractionalValue floatCfg
model es = nodeHandleEventModel wenv es floatNode
modelBasic es = nodeHandleEventModel wenv es basicFractionalNode
events evt = nodeHandleEventEvts wenv [evt] floatNode
reqs es = nodeHandleEventReqs wenv es floatNode
handleEventValueFractional :: Spec
handleEventValueFractional = describe "handleEventValueFractional" $ do
it "should input an '100'" $
evts [evtT "1", evtT "0", evtT "0"] `shouldBe` Seq.fromList [FractionalChanged (Just 10), FractionalChanged (Just 100)]
it "should input a '1' and be considered invalid" $ do
evts [evtT "1"] `shouldBe` Seq.fromList []
model [evtT "1"] ^. fractionalValid `shouldBe` False
it "should input '1', move to beginning and input '5'" $ do
let steps = [evtT "1", moveLineL, evtT "5"]
lastEvt steps `shouldBe` FractionalChanged (Just 51)
it "should input '1', input '.' then input '5'" $ do
let steps = [evtT "10", evtT ".", evtT "5"]
lastEvt steps `shouldBe` FractionalChanged (Just 10.5)
model steps ^. fractionalValid `shouldBe` True
it "should input '20', input '.' twice then input '777'" $ do
let steps = [evtT "20", evtT ".", evtT ".", evtT "7", evtT "7", evtT "7"]
lastEvt steps `shouldBe` FractionalChanged (Just 20.77)
model steps ^. fractionalValid `shouldBe` True
it "should input '10', '.' then input '2345'" $ do
let steps = [evtT "10", evtT ".", evtT "2", evtT "3", evtT "4", evtT "5"]
lastEvtDecimals steps `shouldBe` FractionalChanged (Just 10.234)
it "should input '3', input 'a' then input '6'" $ do
let steps = [evtT "3", evtT "a", evtT "6"]
lastEvt steps `shouldBe` FractionalChanged (Just 36)
model steps ^. fractionalValid `shouldBe` True
it "should input '1234', delete line then input '777'" $ do
let steps = [evtT "1234", selLineL, evtT "777"]
lastEvt steps `shouldBe` FractionalChanged (Just 777)
model steps ^. fractionalValid `shouldBe` True
where
wenv = mockWenv (FractionalModel (Just 0) False)
floatNode = numericFieldV_ (Just 0) FractionalChanged [minValue (Just 10), maxValue (Just 2345), selectOnFocus, validInput fractionalValid]
floatDecimalsNode = numericFieldV_ (Just 0) FractionalChanged [selectOnFocus, decimals 3]
evts es = nodeHandleEventEvts wenv (evtFocus : es) floatNode
evtsAlt es = nodeHandleEventEvts wenv (evtFocus : es) floatDecimalsNode
model es = nodeHandleEventModel wenv (evtFocus : es) floatNode
lastIdx es = Seq.index es (Seq.length es - 1)
lastEvt es = lastIdx (evts es)
lastEvtDecimals es = lastIdx (evtsAlt es)
handleEventMouseDragFractional :: Spec
handleEventMouseDragFractional = describe "handleEventMouseDragFractional" $ do
it "should drag upwards 100 pixels, setting the value to 10" $ do
let selStart = Point 50 30
let selEnd = Point 50 (-70)
let steps = [evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. fractionalValue `shouldBe` Just 10
it "should drag downwards 100 pixels, setting the value to -20 (dragRate = 0.2)" $ do
let selStart = Point 50 50
let selEnd = Point 50 150
let steps = [evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. fractionalValue `shouldBe` Just (-20)
it "should drag downwards 30 and 20 pixels, setting the value to -5" $ do
let selStart = Point 50 30
let selMid = Point 50 60
let selEnd = Point 50 50
let steps = [
evtPress selStart, evtMove selMid, evtRelease selMid,
evtPress selStart, evtMove selEnd, evtRelease selEnd
]
model steps ^. fractionalValue `shouldBe` Just (-5)
it "should drag upwards 100 pixels, but value stay at 0 since shift is not pressed" $ do
let selStart = Point 50 30
let selEnd = Point 50 (-70)
let steps = [evtK keyTab, evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. fractionalValue `shouldBe` Just 0
it "should drag upwards 100 pixels, setting the value to 10 since shift not pressed" $ do
let selStart = Point 50 30
let selEnd = Point 50 (-70)
let steps = [evtKS keyTab, evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. fractionalValue `shouldBe` Just 10
it "should drag upwards 100 pixels, setting the value to 10 even if it was double clicked on" $ do
let selStart = Point 50 30
let selEnd = Point 50 (-70)
let steps = [evtDblClick selStart, evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. fractionalValue `shouldBe` Just 10
where
wenv = mockWenv (FractionalModel (Just 0) False)
& L.inputStatus . L.keyMod . L.leftShift .~ True
floatNode = vstack [
button "Test" (FractionalChanged (Just 0)), -- Used only to have focus
numericField fractionalValue,
numericField_ fractionalValue [dragRate 0.2]
]
evts es = nodeHandleEventEvts wenv es floatNode
model es = nodeHandleEventModel wenv es floatNode
lastIdx es = Seq.index es (Seq.length es - 1)
lastEvt es = lastIdx (evts es)
handleShiftFocusFractional :: Spec
handleShiftFocusFractional = describe "handleShiftFocusFractional" $ do
it "should set focus when clicked" $ do
evts [evtPress p] `shouldBe` Seq.fromList [GotFocus $ Seq.fromList [0, 0]]
it "should not set focus when clicked with shift pressed" $ do
evts [evtKS keyA, evtPress p] `shouldBe` Seq.empty
where
wenv = mockWenv (FractionalModel (Just 0) False)
p = Point 100 30
floatNode = vstack [
numericField_ fractionalValue [wheelRate 1],
numericField_ fractionalValue [wheelRate 1, onFocus GotFocus]
]
evts es = nodeHandleEventEvts wenv es floatNode
handleEventReadOnly :: Spec
handleEventReadOnly = describe "handleEventReadOnly" $ do
it "should ignore text input" $ do
let steps = [moveCharR, delCharL, evtT "5"]
model steps ^. fractionalValue `shouldBe` initValue
it "should ignore drag" $ do
let selStart = Point 5 5
let selEnd = Point 100 2000
let steps = [evtPress selStart, evtMove selEnd, evtRelease selEnd]
model steps ^. fractionalValue `shouldBe` initValue
it "should ignore wheel" $ do
let steps = [WheelScroll (Point 100 10) (Point 0 (-2000)) WheelNormal]
model steps ^. fractionalValue `shouldBe` initValue
where
initValue = Just 42.4
wenv = mockWenv (FractionalModel initValue False)
& L.inputStatus . L.keyMod . L.leftShift .~ True
fieldCfg = [readOnly :: NumericFieldCfg FractionalModel TestEvt (Maybe Double)]
fieldNode = numericField_ fractionalValue fieldCfg
model es = nodeHandleEventModel wenv es fieldNode
getSizeReqFractional :: Spec
getSizeReqFractional = describe "getSizeReqFractional" $ do
it "should return width = Flex 70 1" $
sizeReqW `shouldBe` expandSize 70 1
it "should return height = Fixed 20" $
sizeReqH `shouldBe` fixedSize 20
it "should return width = Flex 110 1 when resizeOnChange = True" $
sizeReqW2 `shouldBe` expandSize 110 1
it "should return height = Fixed 20 when resizeOnChange = True" $
sizeReqH2 `shouldBe` fixedSize 20
where
wenv = mockWenvEvtUnit (FractionalModel (Just 10000000) True)
(sizeReqW, sizeReqH) = nodeGetSizeReq wenv (numericField fractionalValue)
numericResize = numericField_ fractionalValue [resizeOnChange]
(sizeReqW2, sizeReqH2) = nodeGetSizeReq wenv numericResize
testFractionalWidgetType :: Spec
testFractionalWidgetType = describe "testFractionalWidgetType" $ do
it "should set the correct widgetType" $
node ^. L.info . L.widgetType `shouldBe` "numericField-Maybe Double"
where
node :: WidgetNode FractionalModel TestEvt
node = numericField fractionalValue