@ -1,3 +1,4 @@
import { AnyAction } from 'redux' ;
import { UrlQueryMap } from '@grafana/runtime' ;
import { getTemplatingAndLocationRootReducer , getTemplatingRootReducer , variableMockBuilder } from './helpers' ;
@ -8,10 +9,23 @@ import { createTextBoxVariableAdapter } from '../textbox/adapter';
import { createConstantVariableAdapter } from '../constant/adapter' ;
import { reduxTester } from '../../../../test/core/redux/reduxTester' ;
import { TemplatingState } from 'app/features/variables/state/reducers' ;
import { initDashboardTemplating , processVariables , setOptionFromUrl , validateVariableSelectionState } from './actions' ;
import {
initDashboardTemplating ,
onTimeRangeUpdated ,
OnTimeRangeUpdatedDependencies ,
processVariables ,
setOptionFromUrl ,
validateVariableSelectionState ,
} from './actions' ;
import { addInitLock , addVariable , removeInitLock , resolveInitLock , setCurrentVariableValue } from './sharedReducer' ;
import { toVariableIdentifier , toVariablePayload } from './types' ;
import { AnyAction } from 'redux' ;
import { TemplateSrv } from '../../templating/template_srv' ;
import { Emitter } from '../../../core/core' ;
import { createIntervalVariableAdapter } from '../interval/adapter' ;
import { VariableRefresh } from '../../templating/variable' ;
import { DashboardModel } from '../../dashboard/state' ;
import { DashboardState } from '../../../types' ;
import { dateTime , TimeRange } from '@grafana/data' ;
describe ( 'shared actions' , ( ) = > {
describe ( 'when initDashboardTemplating is dispatched' , ( ) = > {
@ -267,4 +281,161 @@ describe('shared actions', () => {
) ;
} ) ;
} ) ;
describe ( 'when onTimeRangeUpdated is dispatched' , ( ) = > {
const getOnTimeRangeUpdatedContext = ( args : { update? : boolean ; throw ? : boolean } ) = > {
const range : TimeRange = {
from : dateTime ( new Date ( ) . getTime ( ) ) . subtract ( 1 , 'minutes' ) ,
to : dateTime ( new Date ( ) . getTime ( ) ) ,
raw : {
from : 'now-1m' ,
to : 'now' ,
} ,
} ;
const updateTimeRangeMock = jest . fn ( ) ;
const templateSrvMock = ( { updateTimeRange : updateTimeRangeMock } as unknown ) as TemplateSrv ;
const emitMock = jest . fn ( ) ;
const appEventsMock = ( { emit : emitMock } as unknown ) as Emitter ;
const dependencies : OnTimeRangeUpdatedDependencies = { templateSrv : templateSrvMock , appEvents : appEventsMock } ;
const templateVariableValueUpdatedMock = jest . fn ( ) ;
const dashboard = ( {
getModel : ( ) = >
( ( {
templateVariableValueUpdated : templateVariableValueUpdatedMock ,
startRefresh : startRefreshMock ,
} as unknown ) as DashboardModel ) ,
} as unknown ) as DashboardState ;
const startRefreshMock = jest . fn ( ) ;
const adapter = createIntervalVariableAdapter ( ) ;
adapter . updateOptions = args . throw
? jest . fn ( ) . mockRejectedValue ( 'Something broke' )
: jest . fn ( ) . mockResolvedValue ( { } ) ;
variableAdapters . set ( 'interval' , adapter ) ;
variableAdapters . set ( 'constant' , createConstantVariableAdapter ( ) ) ;
// initial variable state
const initialVariable = variableMockBuilder ( 'interval' )
. withUuid ( '0' )
. withName ( 'interval-0' )
. withOptions ( '1m' , '10m' , '30m' , '1h' , '6h' , '12h' , '1d' , '7d' , '14d' , '30d' )
. withCurrent ( '1m' )
. withRefresh ( VariableRefresh . onTimeRangeChanged )
. create ( ) ;
// the constant variable should be filtered out
const constant = variableMockBuilder ( 'constant' )
. withUuid ( '1' )
. withName ( 'constant-1' )
. withOptions ( 'a constant' )
. withCurrent ( 'a constant' )
. create ( ) ;
const initialState = {
templating : { variables : { '0' : { . . . initialVariable } , '1' : { . . . constant } } } ,
dashboard ,
} ;
// updated variable state
const updatedVariable = variableMockBuilder ( 'interval' )
. withUuid ( '0' )
. withName ( 'interval-0' )
. withOptions ( '1m' )
. withCurrent ( '1m' )
. withRefresh ( VariableRefresh . onTimeRangeChanged )
. create ( ) ;
const variable = args . update ? { . . . updatedVariable } : { . . . initialVariable } ;
const state = { templating : { variables : { '0' : variable , '1' : { . . . constant } } } , dashboard } ;
const getStateMock = jest
. fn ( )
. mockReturnValueOnce ( initialState )
. mockReturnValue ( state ) ;
const dispatchMock = jest . fn ( ) ;
return {
range ,
dependencies ,
dispatchMock ,
getStateMock ,
updateTimeRangeMock ,
templateVariableValueUpdatedMock ,
startRefreshMock ,
emitMock ,
} ;
} ;
describe ( 'and options are changed by update' , ( ) = > {
it ( 'then correct dependencies are called' , async ( ) = > {
const {
range ,
dependencies ,
dispatchMock ,
getStateMock ,
updateTimeRangeMock ,
templateVariableValueUpdatedMock ,
startRefreshMock ,
emitMock ,
} = getOnTimeRangeUpdatedContext ( { update : true } ) ;
await onTimeRangeUpdated ( range , dependencies ) ( dispatchMock , getStateMock , undefined ) ;
expect ( dispatchMock ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( getStateMock ) . toHaveBeenCalledTimes ( 4 ) ;
expect ( updateTimeRangeMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( updateTimeRangeMock ) . toHaveBeenCalledWith ( range ) ;
expect ( templateVariableValueUpdatedMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( startRefreshMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( emitMock ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
} ) ;
describe ( 'and options are not changed by update' , ( ) = > {
it ( 'then correct dependencies are called' , async ( ) = > {
const {
range ,
dependencies ,
dispatchMock ,
getStateMock ,
updateTimeRangeMock ,
templateVariableValueUpdatedMock ,
startRefreshMock ,
emitMock ,
} = getOnTimeRangeUpdatedContext ( { update : false } ) ;
await onTimeRangeUpdated ( range , dependencies ) ( dispatchMock , getStateMock , undefined ) ;
expect ( dispatchMock ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( getStateMock ) . toHaveBeenCalledTimes ( 3 ) ;
expect ( updateTimeRangeMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( updateTimeRangeMock ) . toHaveBeenCalledWith ( range ) ;
expect ( templateVariableValueUpdatedMock ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( startRefreshMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( emitMock ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
} ) ;
describe ( 'and updateOptions throws' , ( ) = > {
it ( 'then correct dependencies are called' , async ( ) = > {
const {
range ,
dependencies ,
dispatchMock ,
getStateMock ,
updateTimeRangeMock ,
templateVariableValueUpdatedMock ,
startRefreshMock ,
emitMock ,
} = getOnTimeRangeUpdatedContext ( { update : false , throw : true } ) ;
await onTimeRangeUpdated ( range , dependencies ) ( dispatchMock , getStateMock , undefined ) ;
expect ( dispatchMock ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( getStateMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( updateTimeRangeMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( updateTimeRangeMock ) . toHaveBeenCalledWith ( range ) ;
expect ( templateVariableValueUpdatedMock ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( startRefreshMock ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( emitMock ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
} ) ;
} ) ;
} ) ;