diff --git a/public/app/features/templating/specs/variable_srv_specs.ts b/public/app/features/templating/specs/variable_srv.jest.ts similarity index 55% rename from public/app/features/templating/specs/variable_srv_specs.ts rename to public/app/features/templating/specs/variable_srv.jest.ts index 6ab5dcad20e..f7796434b5e 100644 --- a/public/app/features/templating/specs/variable_srv_specs.ts +++ b/public/app/features/templating/specs/variable_srv.jest.ts @@ -1,53 +1,70 @@ -import { describe, beforeEach, it, sinon, expect, angularMocks } from 'test/lib/common'; - import '../all'; - +import { VariableSrv } from '../variable_srv'; import moment from 'moment'; -import helpers from 'test/specs/helpers'; -import { Emitter } from 'app/core/core'; +import $q from 'q'; describe('VariableSrv', function() { - var ctx = new helpers.ControllerTestContext(); - - beforeEach(angularMocks.module('grafana.core')); - beforeEach(angularMocks.module('grafana.controllers')); - beforeEach(angularMocks.module('grafana.services')); - - beforeEach(ctx.providePhase(['datasourceSrv', 'timeSrv', 'templateSrv', '$location'])); - beforeEach( - angularMocks.inject(($rootScope, $q, $location, $injector) => { - ctx.$q = $q; - ctx.$rootScope = $rootScope; - ctx.$location = $location; - ctx.variableSrv = $injector.get('variableSrv'); - ctx.variableSrv.init({ - templating: { list: [] }, - events: new Emitter(), - updateSubmenuVisibility: sinon.stub(), - }); - ctx.$rootScope.$digest(); - }) - ); + var ctx = { + datasourceSrv: {}, + timeSrv: { + timeRange: () => {}, + }, + $rootScope: { + $on: () => {}, + }, + $injector: { + instantiate: (ctr, obj) => new ctr(obj.model), + }, + templateSrv: { + setGrafanaVariable: jest.fn(), + init: vars => { + this.variables = vars; + }, + updateTemplateData: () => {}, + replace: str => + str.replace(this.regex, match => { + return match; + }), + }, + $location: { + search: () => {}, + }, + }; function describeUpdateVariable(desc, fn) { - describe(desc, function() { + describe(desc, () => { var scenario: any = {}; scenario.setup = function(setupFn) { scenario.setupFn = setupFn; }; - beforeEach(function() { + beforeEach(async () => { scenario.setupFn(); + var ds: any = {}; - ds.metricFindQuery = sinon.stub().returns(ctx.$q.when(scenario.queryResult)); - ctx.datasourceSrv.get = sinon.stub().returns(ctx.$q.when(ds)); - ctx.datasourceSrv.getMetricSources = sinon.stub().returns(scenario.metricSources); + ds.metricFindQuery = () => Promise.resolve(scenario.queryResult); + + ctx.variableSrv = new VariableSrv(ctx.$rootScope, $q, ctx.$location, ctx.$injector, ctx.templateSrv); + + ctx.variableSrv.timeSrv = ctx.timeSrv; + ctx.datasourceSrv = { + get: () => Promise.resolve(ds), + getMetricSources: () => scenario.metricSources, + }; + + ctx.$injector.instantiate = (ctr, model) => { + return getVarMockConstructor(ctr, model, ctx); + }; + + ctx.variableSrv.init({ + templating: { list: [] }, + updateSubmenuVisibility: () => {}, + }); scenario.variable = ctx.variableSrv.createVariableFromModel(scenario.variableModel); ctx.variableSrv.addVariable(scenario.variable); - ctx.variableSrv.updateOptions(scenario.variable); - ctx.$rootScope.$digest(); + await ctx.variableSrv.updateOptions(scenario.variable); }); fn(scenario); @@ -64,9 +81,9 @@ describe('VariableSrv', function() { }); it('should update options array', () => { - expect(scenario.variable.options.length).to.be(4); - expect(scenario.variable.options[0].text).to.be('1s'); - expect(scenario.variable.options[0].value).to.be('1s'); + expect(scenario.variable.options.length).toBe(4); + expect(scenario.variable.options[0].text).toBe('1s'); + expect(scenario.variable.options[0].value).toBe('1s'); }); }); @@ -90,28 +107,28 @@ describe('VariableSrv', function() { to: new Date(), }; - ctx.timeSrv.timeRange = sinon.stub().returns(range); - ctx.templateSrv.setGrafanaVariable = sinon.spy(); + ctx.timeSrv.timeRange = () => range; + // ctx.templateSrv.setGrafanaVariable = jest.fn(); }); - it('should update options array', function() { - expect(scenario.variable.options.length).to.be(5); - expect(scenario.variable.options[0].text).to.be('auto'); - expect(scenario.variable.options[0].value).to.be('$__auto_interval_test'); + it('should update options array', () => { + expect(scenario.variable.options.length).toBe(5); + expect(scenario.variable.options[0].text).toBe('auto'); + expect(scenario.variable.options[0].value).toBe('$__auto_interval_test'); }); - it('should set $__auto_interval_test', function() { - var call = ctx.templateSrv.setGrafanaVariable.firstCall; - expect(call.args[0]).to.be('$__auto_interval_test'); - expect(call.args[1]).to.be('12h'); + it('should set $__auto_interval_test', () => { + var call = ctx.templateSrv.setGrafanaVariable.mock.calls[0]; + expect(call[0]).toBe('$__auto_interval_test'); + expect(call[1]).toBe('12h'); }); // updateAutoValue() gets called twice: once directly once via VariableSrv.validateVariableSelectionState() // So use lastCall instead of a specific call number - it('should set $__auto_interval', function() { - var call = ctx.templateSrv.setGrafanaVariable.lastCall; - expect(call.args[0]).to.be('$__auto_interval'); - expect(call.args[1]).to.be('12h'); + it('should set $__auto_interval', () => { + var call = ctx.templateSrv.setGrafanaVariable.mock.calls.pop(); + expect(call[0]).toBe('$__auto_interval'); + expect(call[1]).toBe('12h'); }); }); @@ -119,7 +136,7 @@ describe('VariableSrv', function() { // Query variable update // describeUpdateVariable('query variable with empty current object and refresh', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: '', @@ -129,16 +146,16 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 'backend1' }, { text: 'backend2' }]; }); - it('should set current value to first option', function() { - expect(scenario.variable.options.length).to.be(2); - expect(scenario.variable.current.value).to.be('backend1'); + it('should set current value to first option', () => { + expect(scenario.variable.options.length).toBe(2); + expect(scenario.variable.current.value).toBe('backend1'); }); }); describeUpdateVariable( 'query variable with multi select and new options does not contain some selected values', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: '', @@ -151,9 +168,9 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 'val2' }, { text: 'val3' }]; }); - it('should update current value', function() { - expect(scenario.variable.current.value).to.eql(['val2', 'val3']); - expect(scenario.variable.current.text).to.eql('val2 + val3'); + it('should update current value', () => { + expect(scenario.variable.current.value).toEqual(['val2', 'val3']); + expect(scenario.variable.current.text).toEqual('val2 + val3'); }); } ); @@ -161,7 +178,7 @@ describe('VariableSrv', function() { describeUpdateVariable( 'query variable with multi select and new options does not contain any selected values', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: '', @@ -174,15 +191,15 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 'val5' }, { text: 'val6' }]; }); - it('should update current value with first one', function() { - expect(scenario.variable.current.value).to.eql('val5'); - expect(scenario.variable.current.text).to.eql('val5'); + it('should update current value with first one', () => { + expect(scenario.variable.current.value).toEqual('val5'); + expect(scenario.variable.current.text).toEqual('val5'); }); } ); describeUpdateVariable('query variable with multi select and $__all selected', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: '', @@ -196,14 +213,14 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 'val5' }, { text: 'val6' }]; }); - it('should keep current All value', function() { - expect(scenario.variable.current.value).to.eql(['$__all']); - expect(scenario.variable.current.text).to.eql('All'); + it('should keep current All value', () => { + expect(scenario.variable.current.value).toEqual(['$__all']); + expect(scenario.variable.current.text).toEqual('All'); }); }); describeUpdateVariable('query variable with numeric results', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: '', @@ -213,45 +230,45 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 12, value: 12 }]; }); - it('should set current value to first option', function() { - expect(scenario.variable.current.value).to.be('12'); - expect(scenario.variable.options[0].value).to.be('12'); - expect(scenario.variable.options[0].text).to.be('12'); + it('should set current value to first option', () => { + expect(scenario.variable.current.value).toBe('12'); + expect(scenario.variable.options[0].value).toBe('12'); + expect(scenario.variable.options[0].text).toBe('12'); }); }); describeUpdateVariable('basic query variable', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', name: 'test' }; scenario.queryResult = [{ text: 'backend1' }, { text: 'backend2' }]; }); - it('should update options array', function() { - expect(scenario.variable.options.length).to.be(2); - expect(scenario.variable.options[0].text).to.be('backend1'); - expect(scenario.variable.options[0].value).to.be('backend1'); - expect(scenario.variable.options[1].value).to.be('backend2'); + it('should update options array', () => { + expect(scenario.variable.options.length).toBe(2); + expect(scenario.variable.options[0].text).toBe('backend1'); + expect(scenario.variable.options[0].value).toBe('backend1'); + expect(scenario.variable.options[1].value).toBe('backend2'); }); - it('should select first option as value', function() { - expect(scenario.variable.current.value).to.be('backend1'); + it('should select first option as value', () => { + expect(scenario.variable.current.value).toBe('backend1'); }); }); describeUpdateVariable('and existing value still exists in options', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', name: 'test' }; scenario.variableModel.current = { value: 'backend2', text: 'backend2' }; scenario.queryResult = [{ text: 'backend1' }, { text: 'backend2' }]; }); - it('should keep variable value', function() { - expect(scenario.variable.current.text).to.be('backend2'); + it('should keep variable value', () => { + expect(scenario.variable.current.text).toBe('backend2'); }); }); describeUpdateVariable('and regex pattern exists', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', name: 'test' }; scenario.variableModel.regex = '/apps.*(backend_[0-9]+)/'; scenario.queryResult = [ @@ -260,13 +277,13 @@ describe('VariableSrv', function() { ]; }); - it('should extract and use match group', function() { - expect(scenario.variable.options[0].value).to.be('backend_01'); + it('should extract and use match group', () => { + expect(scenario.variable.options[0].value).toBe('backend_01'); }); }); describeUpdateVariable('and regex pattern exists and no match', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', name: 'test' }; scenario.variableModel.regex = '/apps.*(backendasd[0-9]+)/'; scenario.queryResult = [ @@ -275,14 +292,14 @@ describe('VariableSrv', function() { ]; }); - it('should not add non matching items, None option should be added instead', function() { - expect(scenario.variable.options.length).to.be(1); - expect(scenario.variable.options[0].isNone).to.be(true); + it('should not add non matching items, None option should be added instead', () => { + expect(scenario.variable.options.length).toBe(1); + expect(scenario.variable.options[0].isNone).toBe(true); }); }); describeUpdateVariable('regex pattern without slashes', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', name: 'test' }; scenario.variableModel.regex = 'backend_01'; scenario.queryResult = [ @@ -291,13 +308,13 @@ describe('VariableSrv', function() { ]; }); - it('should return matches options', function() { - expect(scenario.variable.options.length).to.be(1); + it('should return matches options', () => { + expect(scenario.variable.options.length).toBe(1); }); }); describeUpdateVariable('regex pattern remove duplicates', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', name: 'test' }; scenario.variableModel.regex = '/backend_01/'; scenario.queryResult = [ @@ -306,13 +323,13 @@ describe('VariableSrv', function() { ]; }); - it('should return matches options', function() { - expect(scenario.variable.options.length).to.be(1); + it('should return matches options', () => { + expect(scenario.variable.options.length).toBe(1); }); }); describeUpdateVariable('with include All', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', @@ -322,14 +339,14 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 'backend1' }, { text: 'backend2' }, { text: 'backend3' }]; }); - it('should add All option', function() { - expect(scenario.variable.options[0].text).to.be('All'); - expect(scenario.variable.options[0].value).to.be('$__all'); + it('should add All option', () => { + expect(scenario.variable.options[0].text).toBe('All'); + expect(scenario.variable.options[0].value).toBe('$__all'); }); }); describeUpdateVariable('with include all and custom value', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', @@ -340,13 +357,13 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 'backend1' }, { text: 'backend2' }, { text: 'backend3' }]; }); - it('should add All option with custom value', function() { - expect(scenario.variable.options[0].value).to.be('$__all'); + it('should add All option with custom value', () => { + expect(scenario.variable.options[0].value).toBe('$__all'); }); }); describeUpdateVariable('without sort', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', @@ -356,15 +373,15 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 'bbb2' }, { text: 'aaa10' }, { text: 'ccc3' }]; }); - it('should return options without sort', function() { - expect(scenario.variable.options[0].text).to.be('bbb2'); - expect(scenario.variable.options[1].text).to.be('aaa10'); - expect(scenario.variable.options[2].text).to.be('ccc3'); + it('should return options without sort', () => { + expect(scenario.variable.options[0].text).toBe('bbb2'); + expect(scenario.variable.options[1].text).toBe('aaa10'); + expect(scenario.variable.options[2].text).toBe('ccc3'); }); }); describeUpdateVariable('with alphabetical sort (asc)', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', @@ -374,15 +391,15 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 'bbb2' }, { text: 'aaa10' }, { text: 'ccc3' }]; }); - it('should return options with alphabetical sort', function() { - expect(scenario.variable.options[0].text).to.be('aaa10'); - expect(scenario.variable.options[1].text).to.be('bbb2'); - expect(scenario.variable.options[2].text).to.be('ccc3'); + it('should return options with alphabetical sort', () => { + expect(scenario.variable.options[0].text).toBe('aaa10'); + expect(scenario.variable.options[1].text).toBe('bbb2'); + expect(scenario.variable.options[2].text).toBe('ccc3'); }); }); describeUpdateVariable('with alphabetical sort (desc)', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', @@ -392,15 +409,15 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 'bbb2' }, { text: 'aaa10' }, { text: 'ccc3' }]; }); - it('should return options with alphabetical sort', function() { - expect(scenario.variable.options[0].text).to.be('ccc3'); - expect(scenario.variable.options[1].text).to.be('bbb2'); - expect(scenario.variable.options[2].text).to.be('aaa10'); + it('should return options with alphabetical sort', () => { + expect(scenario.variable.options[0].text).toBe('ccc3'); + expect(scenario.variable.options[1].text).toBe('bbb2'); + expect(scenario.variable.options[2].text).toBe('aaa10'); }); }); describeUpdateVariable('with numerical sort (asc)', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', @@ -410,15 +427,15 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 'bbb2' }, { text: 'aaa10' }, { text: 'ccc3' }]; }); - it('should return options with numerical sort', function() { - expect(scenario.variable.options[0].text).to.be('bbb2'); - expect(scenario.variable.options[1].text).to.be('ccc3'); - expect(scenario.variable.options[2].text).to.be('aaa10'); + it('should return options with numerical sort', () => { + expect(scenario.variable.options[0].text).toBe('bbb2'); + expect(scenario.variable.options[1].text).toBe('ccc3'); + expect(scenario.variable.options[2].text).toBe('aaa10'); }); }); describeUpdateVariable('with numerical sort (desc)', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'query', query: 'apps.*', @@ -428,10 +445,10 @@ describe('VariableSrv', function() { scenario.queryResult = [{ text: 'bbb2' }, { text: 'aaa10' }, { text: 'ccc3' }]; }); - it('should return options with numerical sort', function() { - expect(scenario.variable.options[0].text).to.be('aaa10'); - expect(scenario.variable.options[1].text).to.be('ccc3'); - expect(scenario.variable.options[2].text).to.be('bbb2'); + it('should return options with numerical sort', () => { + expect(scenario.variable.options[0].text).toBe('aaa10'); + expect(scenario.variable.options[1].text).toBe('ccc3'); + expect(scenario.variable.options[2].text).toBe('bbb2'); }); }); @@ -439,7 +456,7 @@ describe('VariableSrv', function() { // datasource variable update // describeUpdateVariable('datasource variable with regex filter', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'datasource', query: 'graphite', @@ -455,14 +472,14 @@ describe('VariableSrv', function() { ]; }); - it('should set only contain graphite ds and filtered using regex', function() { - expect(scenario.variable.options.length).to.be(2); - expect(scenario.variable.options[0].value).to.be('backend2_pee'); - expect(scenario.variable.options[1].value).to.be('backend4_pee'); + it('should set only contain graphite ds and filtered using regex', () => { + expect(scenario.variable.options.length).toBe(2); + expect(scenario.variable.options[0].value).toBe('backend2_pee'); + expect(scenario.variable.options[1].value).toBe('backend4_pee'); }); - it('should keep current value if available', function() { - expect(scenario.variable.current.value).to.be('backend4_pee'); + it('should keep current value if available', () => { + expect(scenario.variable.current.value).toBe('backend4_pee'); }); }); @@ -470,7 +487,7 @@ describe('VariableSrv', function() { // Custom variable update // describeUpdateVariable('update custom variable', function(scenario) { - scenario.setup(function() { + scenario.setup(() => { scenario.variableModel = { type: 'custom', query: 'hej, hop, asd', @@ -478,25 +495,25 @@ describe('VariableSrv', function() { }; }); - it('should update options array', function() { - expect(scenario.variable.options.length).to.be(3); - expect(scenario.variable.options[0].text).to.be('hej'); - expect(scenario.variable.options[1].value).to.be('hop'); + it('should update options array', () => { + expect(scenario.variable.options.length).toBe(3); + expect(scenario.variable.options[0].text).toBe('hej'); + expect(scenario.variable.options[1].value).toBe('hop'); }); }); - describe('multiple interval variables with auto', function() { + describe('multiple interval variables with auto', () => { var variable1, variable2; - beforeEach(function() { + beforeEach(() => { var range = { from: moment(new Date()) .subtract(7, 'days') .toDate(), to: new Date(), }; - ctx.timeSrv.timeRange = sinon.stub().returns(range); - ctx.templateSrv.setGrafanaVariable = sinon.spy(); + ctx.timeSrv.timeRange = () => range; + ctx.templateSrv.setGrafanaVariable = jest.fn(); var variableModel1 = { type: 'interval', @@ -520,38 +537,38 @@ describe('VariableSrv', function() { ctx.variableSrv.updateOptions(variable1); ctx.variableSrv.updateOptions(variable2); - ctx.$rootScope.$digest(); + // ctx.$rootScope.$digest(); }); - it('should update options array', function() { - expect(variable1.options.length).to.be(5); - expect(variable1.options[0].text).to.be('auto'); - expect(variable1.options[0].value).to.be('$__auto_interval_variable1'); - expect(variable2.options.length).to.be(4); - expect(variable2.options[0].text).to.be('auto'); - expect(variable2.options[0].value).to.be('$__auto_interval_variable2'); + it('should update options array', () => { + expect(variable1.options.length).toBe(5); + expect(variable1.options[0].text).toBe('auto'); + expect(variable1.options[0].value).toBe('$__auto_interval_variable1'); + expect(variable2.options.length).toBe(4); + expect(variable2.options[0].text).toBe('auto'); + expect(variable2.options[0].value).toBe('$__auto_interval_variable2'); }); - it('should correctly set $__auto_interval_variableX', function() { + it('should correctly set $__auto_interval_variableX', () => { var variable1Set, variable2Set, legacySet, unknownSet = false; // updateAutoValue() gets called repeatedly: once directly once via VariableSrv.validateVariableSelectionState() // So check that all calls are valid rather than expect a specific number and/or ordering of calls - for (var i = 0; i < ctx.templateSrv.setGrafanaVariable.callCount; i++) { - var call = ctx.templateSrv.setGrafanaVariable.getCall(i); - switch (call.args[0]) { + for (var i = 0; i < ctx.templateSrv.setGrafanaVariable.mock.calls.length; i++) { + var call = ctx.templateSrv.setGrafanaVariable.mock.calls[i]; + switch (call[0]) { case '$__auto_interval_variable1': - expect(call.args[1]).to.be('12h'); + expect(call[1]).toBe('12h'); variable1Set = true; break; case '$__auto_interval_variable2': - expect(call.args[1]).to.be('10m'); + expect(call[1]).toBe('10m'); variable2Set = true; break; case '$__auto_interval': - expect(call.args[1]).to.match(/^(12h|10m)$/); + expect(call[1]).toEqual(expect.stringMatching(/^(12h|10m)$/)); legacySet = true; break; default: @@ -559,10 +576,25 @@ describe('VariableSrv', function() { break; } } - expect(variable1Set).to.be.equal(true); - expect(variable2Set).to.be.equal(true); - expect(legacySet).to.be.equal(true); - expect(unknownSet).to.be.equal(false); + expect(variable1Set).toEqual(true); + expect(variable2Set).toEqual(true); + expect(legacySet).toEqual(true); + expect(unknownSet).toEqual(false); }); }); }); + +function getVarMockConstructor(variable, model, ctx) { + switch (model.model.type) { + case 'datasource': + return new variable(model.model, ctx.datasourceSrv, ctx.variableSrv, ctx.templateSrv); + case 'query': + return new variable(model.model, ctx.datasourceSrv, ctx.templateSrv, ctx.variableSrv); + case 'interval': + return new variable(model.model, ctx.timeSrv, ctx.templateSrv, ctx.variableSrv); + case 'custom': + return new variable(model.model, ctx.variableSrv); + default: + return new variable(model.model); + } +}