import { expect } from "chai" ; import * as sinon from "sinon" ; import * as React from "react" ; import { fireEvent , render } from "@testing-library/react" ; import { IModelApp , MockRender , QuantityType } from "@itwin/core-frontend" ; import { QuantityInput } from "../../imodel-components-react/inputs/QuantityInput" ; import { SpecialKey } from "@itwin/appui-abstract" ; import { TestUtils } from "../TestUtils" ; describe ( "QuantityInput" , ( ) => { const rnaDescriptorToRestore = Object . getOwnPropertyDescriptor ( IModelApp , "requestNextAnimation" ) ! ; function requestNextAnimation ( ) { } before ( async ( ) => { Object . defineProperty ( IModelApp , "requestNextAnimation" , { get : ( ) => requestNextAnimation } ) ; await TestUtils . initializeUiIModelComponents ( ) ; await MockRender . App . startup ( ) ; } ) ; after ( async ( ) => { await MockRender . App . shutdown ( ) ; TestUtils . terminateUiIModelComponents ( ) ; Object . defineProperty ( IModelApp , "requestNextAnimation" , rnaDescriptorToRestore ) ; } ) ; it ( "should render input for Length" , ( ) => { const initialLength = 1 ; const spyOnChange = sinon . spy ( ) ; const wrapper = render ( < QuantityInput initialValue = { initialLength } quantityType = { QuantityType . Length } onQuantityChange = { spyOnChange } / > ) ; expect ( wrapper ) . not . to . be . undefined ; const input = wrapper . getByTestId ( "components-parsed-input" ) ; fireEvent . change ( input , { target : { value : "2.5" } } ) ; expect ( spyOnChange ) . not . to . have . been . called ; fireEvent . keyDown ( input , { key : SpecialKey . Enter } ) ; expect ( spyOnChange ) . to . have . been . called ; } ) ; const overrideLengthFormats = { metric : { composite : { includeZero : true , spacer : " " , units : [ { label : "cm" , name : "Units.CM" } ] } , formatTraits : [ "keepSingleZero" , "showUnitLabel" ] , precision : 4 , type : "Decimal" } , imperial : { composite : { includeZero : true , spacer : " " , units : [ { label : "in" , name : "Units.IN" } ] } , formatTraits : [ "keepSingleZero" , "showUnitLabel" ] , precision : 4 , type : "Decimal" } , usCustomary : { composite : { includeZero : true , spacer : " " , units : [ { label : "in" , name : "Units.IN" } ] } , formatTraits : [ "keepSingleZero" , "showUnitLabel" ] , precision : 4 , type : "Decimal" } , usSurvey : { composite : { includeZero : true , spacer : " " , units : [ { label : "in" , name : "Units.US_SURVEY_IN" } ] } , formatTraits : [ "keepSingleZero" , "showUnitLabel" ] , precision : 4 , type : "Decimal" } } ; it ( "should process ESC key" , async ( ) => { const initialLength = 1 ; const spyOnChange = sinon . spy ( ) ; await IModelApp . quantityFormatter . setActiveUnitSystem ( "metric" ) ; await TestUtils . flushAsyncOperations ( ) ; const wrapper = render ( < QuantityInput initialValue = { initialLength } quantityType = { QuantityType . Length } onQuantityChange = { spyOnChange } / > ) ; expect ( wrapper ) . not . to . be . undefined ; const input = wrapper . getByTestId ( "components-parsed-input" ) as HTMLInputElement ; const initialValue = input . value ; fireEvent . change ( input , { target : { value : "2.5" } } ) ; fireEvent . keyDown ( input , { key : SpecialKey . Escape } ) ; expect ( spyOnChange ) . not . to . have . been . called ; expect ( initialValue ) . to . eq ( input . value ) ; fireEvent . change ( input , { target : { value : "3.5" } } ) ; fireEvent . keyDown ( input , { key : SpecialKey . Enter } ) ; expect ( spyOnChange ) . to . have . been . called ; expect ( input . value ) . to . eq ( "3.5 m" ) ; await IModelApp . quantityFormatter . setActiveUnitSystem ( "imperial" ) ; await TestUtils . flushAsyncOperations ( ) ; expect ( input . value ) . to . eq ( "3'-3 3/8\"" ) ; await IModelApp . quantityFormatter . setOverrideFormats ( QuantityType . Length , overrideLengthFormats ) ; await TestUtils . flushAsyncOperations ( ) ; expect ( input . value ) . to . eq ( "39.3701 in" ) ; await IModelApp . quantityFormatter . clearOverrideFormats ( QuantityType . Length ) ; await TestUtils . flushAsyncOperations ( ) ; expect ( input . value ) . to . eq ( "3'-3 3/8\"" ) ; } ) ; it ( "should attach 'components-parsed-input-has-error' when bad input" , ( ) => { const initialLength = 1 ; const spyOnChange = sinon . spy ( ) ; const wrapper = render ( < QuantityInput initialValue = { initialLength } quantityType = { QuantityType . Length } onQuantityChange = { spyOnChange } / > ) ; expect ( wrapper ) . not . to . be . undefined ; const input = wrapper . getByTestId ( "components-parsed-input" ) as HTMLInputElement ; const initialValue = input . value ; input . focus ( ) ; fireEvent . change ( input , { target : { value : "abc" } } ) ; input . blur ( ) ; expect ( input . classList . contains ( "components-parsed-input-has-error" ) ) . to . be . true ; fireEvent . keyDown ( input , { key : SpecialKey . Escape } ) ; expect ( spyOnChange ) . not . to . have . been . called ; const currentValue = input . value ; expect ( input . classList . contains ( "components-parsed-input-has-error" ) ) . to . be . false ; expect ( initialValue ) . to . eq ( currentValue ) ; } ) ; } ) ;