import * as sinon from "sinon" ; import { expect } from "chai" ; import { act , fireEvent , waitFor } from "@testing-library/react" ; let mochaTimeoutsEnabled ; beforeEach ( function ( ) { mochaTimeoutsEnabled = this . timeout ( 0 ) ; } ) ; /** Options for waitForSpy test helper function */ export interface WaitForSpyOptions { timeout ? : number ; error ? : string ; } /** Wait for spy to be called. Throws on timeout (250 by default) */ export const waitForSpy = async ( spy , options ? ) => { const defaultValues = { timeout : 250 , error : "Waiting for spy timed out!" } ; const { timeout , error } = options ? { ... defaultValues , ... options } : defaultValues ; return waitFor ( ( ) => { if ( ! spy . called ) throw new Error ( error ) ; } , { timeout , interval : 10 } ) ; } ; /**
 * Waits for `spy` to be called `count` number of times during and after the `action`
 */ export const waitForUpdate = async ( action , spy , count = 1 ) => { const stack = ( new Error ( ) ) . stack ; const timeout = mochaTimeoutsEnabled ? undefined : Number . MAX_VALUE ; const callCountBefore = spy . callCount ; act ( ( ) => { action ( ) ; } ) ; await waitFor ( ( ) => { if ( spy . callCount - callCountBefore !== count ) { const err = new Error ( `Calls count doesn't match. Expected ${ count }, got ${ spy . callCount - callCountBefore } (${ spy . callCount } in total)` ) ; err . stack = stack ; throw err ; } } , { timeout , interval : 1 } ) ; } ; /**
 * Select component pick value using index
 */ export const selectChangeValueByIndex = ( select , index , onError ? , useOwnerDoc ? ) : void => { fireEvent . click ( select . querySelector ( ".iui-select-button" ) as HTMLElement ) ; const menu = useOwnerDoc ? select . ownerDocument . querySelector ( "ul.iui-menu" ) as HTMLUListElement : select . querySelector ( "ul.iui-menu" ) as HTMLUListElement ; if ( ! menu ) onError && onError ( `Couldn't find menu` ) ; expect ( menu ) . to . exist ; const menuItem = menu . querySelectorAll ( "li" ) ; if ( menuItem [ index ] === undefined ) onError && onError ( `Couldn't find menu item ${ index }` ) ; expect ( menuItem [ index ] ) . to . not . be . undefined ; fireEvent . click ( menuItem [ index ] ) ; } ; /**
 * Select component change value using text of menu item to find item
 */ export const selectChangeValueByText = ( select , label , onError ? , useOwnerDoc ? ) : void => { fireEvent . click ( select . querySelector ( ".iui-select-button" ) as HTMLElement ) ; const menu = useOwnerDoc ? select . ownerDocument . querySelector ( "ul.iui-menu" ) as HTMLUListElement : select . querySelector ( "ul.iui-menu" ) as HTMLUListElement ; if ( ! menu ) onError && onError ( `Couldn't find menu` ) ; expect ( menu ) . to . exist ; const menuItems = menu . querySelectorAll ( "li span.iui-content" ) ; if ( menuItems . length <= 0 ) onError && onError ( "Couldn't find any menu items" ) ; expect ( menuItems . length ) . to . be . greaterThan ( 0 ) ; const menuItem = [ ... menuItems ] . find ( ( span ) => span . textContent === label ) ; if ( ! menuItem ) onError && onError ( `Couldn't find menu item with '${ label }' label` ) ; expect ( menuItem ) . to . not . be . undefined ; fireEvent . click ( menuItem ! ) ; } ; /**
 * Get a iTwinUI Button with a given label
 */ export function getButtonWithText ( container , label , onError ? ) { const selector = "button.iui-button" ; const buttons = container . querySelectorAll ( selector ) ; if ( buttons . length <= 0 ) onError && onError ( `Couldn't find any '${ selector }' buttons` ) ; const button = [ ... buttons ] . find ( ( btn ) => { const span = btn . querySelector ( "span.iui-button-label" ) ; return span ! . textContent === label ; } ) ; if ( ! button ) onError && onError ( `No button found with '${ label }' label` ) ; return button ; } /** Handle an error when attempting to get an element */ export function handleError ( msg ) { console . log ( msg ) ; } /** Creates Promise */ export class ResolvablePromise < T > implements PromiseLike < T > { private _wrapped : Promise < T > ; private _resolve ! : ( value : T ) => void ; public constructor ( ) { this . _wrapped = new Promise < T > ( ( resolve ) => { this . _resolve = resolve ; } ) ; } public then < TResult1 = T , TResult2 = never > ( onfulfilled ? , onrejected ? ) { return this . _wrapped . then ( onfulfilled , onrejected ) ; } public async resolve ( result ) { this . _resolve ( result ) ; await new Promise < void > ( ( resolve ) => { setImmediate ( resolve ) ; } ) ; } } /** Stubs scrollIntoView. */ export function stubScrollIntoView ( ) { const originalScrollIntoView = window . HTMLElement . prototype . scrollIntoView ; const scrollIntoViewMock = function ( ) { } ; beforeEach ( ( ) => { window . HTMLElement . prototype . scrollIntoView = scrollIntoViewMock ; } ) ; afterEach ( ( ) => { window . HTMLElement . prototype . scrollIntoView = originalScrollIntoView ; } ) ; }