From 53312852e9941ab3e99f7cd22896612971c394c5 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 22 Mar 2016 20:23:27 +0100 Subject: [PATCH 1/6] tests(influxdb): adds tests for influxdb response --- .../plugins/datasource/influxdb/datasource.ts | 23 ++------ .../datasource/influxdb/response_parser.ts | 23 ++++++++ .../influxdb/specs/response_parser_specs.ts | 58 +++++++++++++++++++ 3 files changed, 86 insertions(+), 18 deletions(-) create mode 100644 public/app/plugins/datasource/influxdb/response_parser.ts create mode 100644 public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index 1136c9709bd..7052201b422 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -6,6 +6,7 @@ import _ from 'lodash'; import * as dateMath from 'app/core/utils/datemath'; import InfluxSeries from './influx_series'; import InfluxQuery from './influx_query'; +import ResponseParser from './response_parser'; /** @ngInject */ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) { @@ -22,6 +23,7 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) this.interval = (instanceSettings.jsonData || {}).timeInterval; this.supportAnnotations = true; this.supportMetrics = true; + this.responseParser = new ResponseParser(); this.query = function(options) { var timeFilter = getTimeFilter(options); @@ -101,7 +103,7 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) }); }; - this.metricFindQuery = function (query) { + this.metricFindQuery = function (query, queryType) { var interpolated; try { interpolated = templateSrv.replace(query, null, 'regex'); @@ -109,23 +111,8 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) return $q.reject(err); } - return this._seriesQuery(interpolated).then(function (results) { - if (!results || results.results.length === 0) { return []; } - - var influxResults = results.results[0]; - if (!influxResults.series) { - return []; - } - - var series = influxResults.series[0]; - return _.map(series.values, function(value) { - if (_.isArray(value)) { - return { text: value[0] }; - } else { - return { text: value }; - } - }); - }); + return this._seriesQuery(interpolated) + .then(_.curry(this.responseParser.parse)(queryType)); }; this._seriesQuery = function(query) { diff --git a/public/app/plugins/datasource/influxdb/response_parser.ts b/public/app/plugins/datasource/influxdb/response_parser.ts new file mode 100644 index 00000000000..8d2cdff0e54 --- /dev/null +++ b/public/app/plugins/datasource/influxdb/response_parser.ts @@ -0,0 +1,23 @@ +/// + +import _ from 'lodash'; + +export default class ResponseParser { + parse(queryType, results) { + if (!results || results.results.length === 0) { return []; } + + var influxResults = results.results[0]; + if (!influxResults.series) { + return []; + } + + var series = influxResults.series[0]; + return _.map(series.values, function(value) { + if (_.isArray(value)) { + return { text: value[0] }; + } else { + return { text: value }; + } + }); + } +} diff --git a/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts b/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts new file mode 100644 index 00000000000..a52c98f0e05 --- /dev/null +++ b/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts @@ -0,0 +1,58 @@ +import _ from 'lodash'; +import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'; +import ResponseParser from '../response_parser'; + +describe.only("influxdb response parser", () => { + describe("SHOW_TAGS response", () => { + this.parser = new ResponseParser(); + + describe("response from 0.10.0", () => { + var response = { + "results": [ + { + "series": [ + { + "name": "hostnameTagValues", + "columns": ["hostname"], + "values": [ ["server1"], ["server2"] ] + } + ] + } + ] + }; + + var result = this.parser.parse('SHOW_TAGS', response); + + it("should get two responses", () => { + expect(_.size(result)).to.be(2); + expect(result[0].text).to.be("server1"); + expect(result[1].text).to.be("server2"); + }); + }); + }); + + describe("SHOW_FIELDS response", () => { + describe("response from 0.10.0", () => { + var response = { + "results": [ + { + "series": [ + { + "name": "measurements", + "columns": ["name"], + "values": [ + ["cpu"], ["derivative"], ["logins.count"], ["logs"], ["payment.ended"], ["payment.started"] + ] + } + ] + } + ] + }; + + var result = this.parser.parse('SHOW_FIELDS', response); + it("should get two responses", () => { + expect(_.size(result)).to.be(6); + }); + }); + }); +}); From 6fafc8dba1dee490dc782bd4122522b0054026b7 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 22 Mar 2016 22:43:55 +0100 Subject: [PATCH 2/6] add(influxdb): add support for 0.11.0 tags --- .../datasource/influxdb/response_parser.ts | 33 +++++++----- .../influxdb/specs/response_parser_specs.ts | 51 +++++++++++++++++-- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/public/app/plugins/datasource/influxdb/response_parser.ts b/public/app/plugins/datasource/influxdb/response_parser.ts index 8d2cdff0e54..ff99ee24284 100644 --- a/public/app/plugins/datasource/influxdb/response_parser.ts +++ b/public/app/plugins/datasource/influxdb/response_parser.ts @@ -3,21 +3,26 @@ import _ from 'lodash'; export default class ResponseParser { - parse(queryType, results) { - if (!results || results.results.length === 0) { return []; } - var influxResults = results.results[0]; - if (!influxResults.series) { - return []; - } + parse(queryType, results) { + if (!results || results.results.length === 0) { return []; } - var series = influxResults.series[0]; - return _.map(series.values, function(value) { - if (_.isArray(value)) { - return { text: value[0] }; - } else { - return { text: value }; - } - }); + var influxResults = results.results[0]; + if (!influxResults.series) { + return []; } + + var series = influxResults.series[0]; + return _.map(series.values, function(value) { + if (_.isArray(value)) { + if (queryType === 'SHOW_TAGS') { + return { text: (value[1] || value[0]) }; + } else { + return { text: value[0] }; + } + } else { + return { text: value }; + } + }); + } } diff --git a/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts b/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts index a52c98f0e05..506d828ab7e 100644 --- a/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts +++ b/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts @@ -2,10 +2,9 @@ import _ from 'lodash'; import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'; import ResponseParser from '../response_parser'; -describe.only("influxdb response parser", () => { +describe("influxdb response parser", () => { + this.parser = new ResponseParser(); describe("SHOW_TAGS response", () => { - this.parser = new ResponseParser(); - describe("response from 0.10.0", () => { var response = { "results": [ @@ -29,6 +28,30 @@ describe.only("influxdb response parser", () => { expect(result[1].text).to.be("server2"); }); }); + + describe("response from 0.11.0", () => { + var response = { + "results": [ + { + "series": [ + { + "name": "cpu", + "columns": [ "key", "value"], + "values": [ [ "source", "site" ], [ "source", "api" ] ] + } + ] + } + ] + }; + + var result = this.parser.parse('SHOW_TAGS', response); + + it("should get two responses", () => { + expect(_.size(result)).to.be(2); + expect(result[0].text).to.be('site'); + expect(result[1].text).to.be('api'); + }); + }); }); describe("SHOW_FIELDS response", () => { @@ -54,5 +77,27 @@ describe.only("influxdb response parser", () => { expect(_.size(result)).to.be(6); }); }); + + describe("response from 0.11.0", () => { + var response = { + "results": [ + { + "series": [ + { + "name": "cpu", + "columns": ["fieldKey"], + "values": [ [ "value"] ] + } + ] + } + ] + }; + + var result = this.parser.parse('SHOW_FIELDS', response); + + it("should get two responses", () => { + expect(_.size(result)).to.be(1); + }); + }); }); }); From ba48f40d2181eae2eace4eedfb562dc5be267a4d Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 23 Mar 2016 11:09:57 +0100 Subject: [PATCH 3/6] feat(influxdb): bases parsing upon query --- .../plugins/datasource/influxdb/datasource.ts | 2 +- .../datasource/influxdb/response_parser.ts | 6 +- .../influxdb/specs/response_parser_specs.ts | 66 +++++++++++++++++-- 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index 7052201b422..fd5f4b0bb77 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -112,7 +112,7 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) } return this._seriesQuery(interpolated) - .then(_.curry(this.responseParser.parse)(queryType)); + .then(_.curry(this.responseParser.parse)(query)); }; this._seriesQuery = function(query) { diff --git a/public/app/plugins/datasource/influxdb/response_parser.ts b/public/app/plugins/datasource/influxdb/response_parser.ts index ff99ee24284..ae6f2cb75a9 100644 --- a/public/app/plugins/datasource/influxdb/response_parser.ts +++ b/public/app/plugins/datasource/influxdb/response_parser.ts @@ -4,7 +4,7 @@ import _ from 'lodash'; export default class ResponseParser { - parse(queryType, results) { + parse(query, results) { if (!results || results.results.length === 0) { return []; } var influxResults = results.results[0]; @@ -13,9 +13,9 @@ export default class ResponseParser { } var series = influxResults.series[0]; - return _.map(series.values, function(value) { + return _.map(series.values, (value) => { if (_.isArray(value)) { - if (queryType === 'SHOW_TAGS') { + if (query.indexOf('SHOW TAG VALUES') >= 0) { return { text: (value[1] || value[0]) }; } else { return { text: value[0] }; diff --git a/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts b/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts index 506d828ab7e..d83b3ab4fa2 100644 --- a/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts +++ b/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts @@ -4,7 +4,56 @@ import ResponseParser from '../response_parser'; describe("influxdb response parser", () => { this.parser = new ResponseParser(); - describe("SHOW_TAGS response", () => { + describe("SHOW TAG response", () => { + var query = 'SHOW TAG KEYS FROM "cpu"'; + describe("response from 0.10.0", () => { + var response = { + "results": [ + { + "series": [ + { + "name": "cpu", + "columns": ["tagKey"], + "values": [ ["datacenter"], ["hostname"], ["source"] ] + } + ] + } + ] + }; + + var result = this.parser.parse(query, response); + + it("expects three results", () => { + expect(_.size(result)).to.be(3); + }); + }); + + describe("response from 0.11.0", () => { + var response = { + "results": [ + { + "series": [ + { + "name": "cpu", + "columns": ["tagKey"], + "values": [ ["datacenter"], ["hostname"], ["source"] ] + } + ] + } + ] + }; + + var result = this.parser.parse(query, response); + + it("expects three results", () => { + expect(_.size(result)).to.be(3); + }); + }); + }); + + describe("SHOW TAG VALUES response", () => { + var query = 'SHOW TAG VALUES FROM "cpu" WITH KEY = "hostname"'; + describe("response from 0.10.0", () => { var response = { "results": [ @@ -20,7 +69,7 @@ describe("influxdb response parser", () => { ] }; - var result = this.parser.parse('SHOW_TAGS', response); + var result = this.parser.parse(query, response); it("should get two responses", () => { expect(_.size(result)).to.be(2); @@ -44,7 +93,7 @@ describe("influxdb response parser", () => { ] }; - var result = this.parser.parse('SHOW_TAGS', response); + var result = this.parser.parse(query, response); it("should get two responses", () => { expect(_.size(result)).to.be(2); @@ -52,9 +101,14 @@ describe("influxdb response parser", () => { expect(result[1].text).to.be('api'); }); }); + + + + }); - describe("SHOW_FIELDS response", () => { + describe("SHOW FIELD response", () => { + var query = 'SHOW FIELD KEYS FROM "cpu"'; describe("response from 0.10.0", () => { var response = { "results": [ @@ -72,7 +126,7 @@ describe("influxdb response parser", () => { ] }; - var result = this.parser.parse('SHOW_FIELDS', response); + var result = this.parser.parse(query, response); it("should get two responses", () => { expect(_.size(result)).to.be(6); }); @@ -93,7 +147,7 @@ describe("influxdb response parser", () => { ] }; - var result = this.parser.parse('SHOW_FIELDS', response); + var result = this.parser.parse(query, response); it("should get two responses", () => { expect(_.size(result)).to.be(1); From 5b75eea8cf22f9e69a5e4d6d2d9621521bf685cb Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 23 Mar 2016 14:00:22 +0100 Subject: [PATCH 4/6] fix(influxdb): remove unused parameter --- public/app/plugins/datasource/influxdb/datasource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index fd5f4b0bb77..dabfd73bd76 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -103,7 +103,7 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) }); }; - this.metricFindQuery = function (query, queryType) { + this.metricFindQuery = (query) => { var interpolated; try { interpolated = templateSrv.replace(query, null, 'regex'); From 991b6eafcae2a412b8db89351d2eb61ca8b437c2 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 23 Mar 2016 14:42:18 +0100 Subject: [PATCH 5/6] tech(influxdb): convert datasource to TS class --- .../plugins/datasource/influxdb/datasource.ts | 96 +++++++++++-------- .../datasource/influxdb/influx_query.ts | 1 + .../app/plugins/datasource/influxdb/module.ts | 2 +- 3 files changed, 57 insertions(+), 42 deletions(-) diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index dabfd73bd76..daa6ada3420 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -8,35 +8,49 @@ import InfluxSeries from './influx_series'; import InfluxQuery from './influx_query'; import ResponseParser from './response_parser'; -/** @ngInject */ -export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) { - this.type = 'influxdb'; - this.urls = _.map(instanceSettings.url.split(','), function(url) { - return url.trim(); - }); +export default class InfluxDatasource { + type: string; + urls: any; + username: string; + password: string; + name: string; + database: any; + basicAuth: any; + interval: any; + supportAnnotations: boolean; + supportMetrics: boolean; + responseParser: any; - this.username = instanceSettings.username; - this.password = instanceSettings.password; - this.name = instanceSettings.name; - this.database = instanceSettings.database; - this.basicAuth = instanceSettings.basicAuth; - this.interval = (instanceSettings.jsonData || {}).timeInterval; - this.supportAnnotations = true; - this.supportMetrics = true; - this.responseParser = new ResponseParser(); + /** @ngInject */ + constructor(instanceSettings, private $q, private backendSrv, private templateSrv) { + this.type = 'influxdb'; + this.urls = _.map(instanceSettings.url.split(','), function(url) { + return url.trim(); + }); - this.query = function(options) { - var timeFilter = getTimeFilter(options); + this.username = instanceSettings.username; + this.password = instanceSettings.password; + this.name = instanceSettings.name; + this.database = instanceSettings.database; + this.basicAuth = instanceSettings.basicAuth; + this.interval = (instanceSettings.jsonData || {}).timeInterval; + this.supportAnnotations = true; + this.supportMetrics = true; + this.responseParser = new ResponseParser(); + } + + query(options) { + var timeFilter = this.getTimeFilter(options); var queryTargets = []; var i, y; - var allQueries = _.map(options.targets, function(target) { + var allQueries = _.map(options.targets, (target) => { if (target.hide) { return []; } queryTargets.push(target); // build query - var queryModel = new InfluxQuery(target, templateSrv, options.scopedVars); + var queryModel = new InfluxQuery(target, this.templateSrv, options.scopedVars); var query = queryModel.render(true); query = query.replace(/\$interval/g, (target.interval || options.interval)); return query; @@ -47,9 +61,9 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) allQueries = allQueries.replace(/\$timeFilter/g, timeFilter); // replace templated variables - allQueries = templateSrv.replace(allQueries, options.scopedVars); + allQueries = this.templateSrv.replace(allQueries, options.scopedVars); - return this._seriesQuery(allQueries).then(function(data): any { + return this._seriesQuery(allQueries).then((data): any => { if (!data || !data.results) { return []; } @@ -62,7 +76,7 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) var target = queryTargets[i]; var alias = target.alias; if (alias) { - alias = templateSrv.replace(target.alias, options.scopedVars); + alias = this.templateSrv.replace(target.alias, options.scopedVars); } var influxSeries = new InfluxSeries({ series: data.results[i].series, alias: alias }); @@ -86,16 +100,16 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) }); }; - this.annotationQuery = function(options) { + annotationQuery(options) { if (!options.annotation.query) { - return $q.reject({message: 'Query missing in annotation definition'}); + return this.$q.reject({message: 'Query missing in annotation definition'}); } - var timeFilter = getTimeFilter({rangeRaw: options.rangeRaw}); + var timeFilter = this.getTimeFilter({rangeRaw: options.rangeRaw}); var query = options.annotation.query.replace('$timeFilter', timeFilter); - query = templateSrv.replace(query); + query = this.templateSrv.replace(query); - return this._seriesQuery(query).then(function(data) { + return this._seriesQuery(query).then(data => { if (!data || !data.results || !data.results[0]) { throw { message: 'No results in response from InfluxDB' }; } @@ -103,29 +117,29 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) }); }; - this.metricFindQuery = (query) => { + metricFindQuery(query) { var interpolated; try { - interpolated = templateSrv.replace(query, null, 'regex'); + interpolated = this.templateSrv.replace(query, null, 'regex'); } catch (err) { - return $q.reject(err); + return this.$q.reject(err); } return this._seriesQuery(interpolated) .then(_.curry(this.responseParser.parse)(query)); }; - this._seriesQuery = function(query) { + _seriesQuery(query) { return this._influxRequest('GET', '/query', {q: query, epoch: 'ms'}); - }; + } - this.testDatasource = function() { - return this.metricFindQuery('SHOW MEASUREMENTS LIMIT 1').then(function () { + testDatasource() { + return this.metricFindQuery('SHOW MEASUREMENTS LIMIT 1').then(() => { return { status: "success", message: "Data source is working", title: "Success" }; }); - }; + } - this._influxRequest = function(method, url, data) { + _influxRequest(method, url, data) { var self = this; var currentUrl = self.urls.shift(); @@ -159,7 +173,7 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) options.headers.Authorization = self.basicAuth; } - return backendSrv.datasourceRequest(options).then(function(result) { + return this.backendSrv.datasourceRequest(options).then(result => { return result.data; }, function(err) { if (err.status !== 0 || err.status >= 300) { @@ -172,9 +186,9 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) }); }; - function getTimeFilter(options) { - var from = getInfluxTime(options.rangeRaw.from, false); - var until = getInfluxTime(options.rangeRaw.to, true); + getTimeFilter(options) { + var from = this.getInfluxTime(options.rangeRaw.from, false); + var until = this.getInfluxTime(options.rangeRaw.to, true); var fromIsAbsolute = from[from.length-1] === 's'; if (until === 'now()' && !fromIsAbsolute) { @@ -184,7 +198,7 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) return 'time > ' + from + ' and time < ' + until; } - function getInfluxTime(date, roundUp) { + getInfluxTime(date, roundUp) { if (_.isString(date)) { if (date === 'now') { return 'now()'; diff --git a/public/app/plugins/datasource/influxdb/influx_query.ts b/public/app/plugins/datasource/influxdb/influx_query.ts index 72d08909ac4..85457c7a8b3 100644 --- a/public/app/plugins/datasource/influxdb/influx_query.ts +++ b/public/app/plugins/datasource/influxdb/influx_query.ts @@ -11,6 +11,7 @@ export default class InfluxQuery { templateSrv: any; scopedVars: any; + /** @ngInject */ constructor(target, templateSrv?, scopedVars?) { this.target = target; this.templateSrv = templateSrv; diff --git a/public/app/plugins/datasource/influxdb/module.ts b/public/app/plugins/datasource/influxdb/module.ts index f2a21cc9022..26b067227a0 100644 --- a/public/app/plugins/datasource/influxdb/module.ts +++ b/public/app/plugins/datasource/influxdb/module.ts @@ -1,4 +1,4 @@ -import {InfluxDatasource} from './datasource'; +import InfluxDatasource from './datasource'; import {InfluxQueryCtrl} from './query_ctrl'; class InfluxConfigCtrl { From 5f2f4a0897d9d460bd4c3b5b378268593522f41c Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 23 Mar 2016 15:23:14 +0100 Subject: [PATCH 6/6] test(influxdb): remove redundant test --- .../influxdb/specs/response_parser_specs.ts | 56 ++++++------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts b/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts index d83b3ab4fa2..e58fe32dd1b 100644 --- a/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts +++ b/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts @@ -6,48 +6,24 @@ describe("influxdb response parser", () => { this.parser = new ResponseParser(); describe("SHOW TAG response", () => { var query = 'SHOW TAG KEYS FROM "cpu"'; - describe("response from 0.10.0", () => { - var response = { - "results": [ - { - "series": [ - { - "name": "cpu", - "columns": ["tagKey"], - "values": [ ["datacenter"], ["hostname"], ["source"] ] - } - ] - } - ] - }; + var response = { + "results": [ + { + "series": [ + { + "name": "cpu", + "columns": ["tagKey"], + "values": [ ["datacenter"], ["hostname"], ["source"] ] + } + ] + } + ] + }; - var result = this.parser.parse(query, response); + var result = this.parser.parse(query, response); - it("expects three results", () => { - expect(_.size(result)).to.be(3); - }); - }); - - describe("response from 0.11.0", () => { - var response = { - "results": [ - { - "series": [ - { - "name": "cpu", - "columns": ["tagKey"], - "values": [ ["datacenter"], ["hostname"], ["source"] ] - } - ] - } - ] - }; - - var result = this.parser.parse(query, response); - - it("expects three results", () => { - expect(_.size(result)).to.be(3); - }); + it("expects three results", () => { + expect(_.size(result)).to.be(3); }); });