mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Tests: Adds expects for observables (#28929)
* Tests: Adds expects for observables * Refactor: renames matcher * Chore: changed jest version and removed as dev dependency * Refactor: Changes after PR review * wip * Chore: revert * Chore: Adds jest-matcher-utils * Chore: fixed merge error * Tests: Removed inline snapshots as they are env dependent * Tests: missed a snapshot * Refactor: Removed type file after PR comments
This commit is contained in:
@@ -163,6 +163,7 @@
|
||||
"jest": "26.4.2",
|
||||
"jest-canvas-mock": "2.2.0",
|
||||
"jest-date-mock": "1.0.8",
|
||||
"jest-matcher-utils": "26.0.0",
|
||||
"lerna": "^3.20.2",
|
||||
"lint-staged": "10.0.7",
|
||||
"load-grunt-tasks": "5.1.0",
|
||||
|
@@ -7,7 +7,6 @@ import { transformDataFrame } from '../transformDataFrame';
|
||||
import { CalculateFieldMode, calculateFieldTransformer, ReduceOptions } from './calculateField';
|
||||
import { DataFrameView } from '../../dataframe';
|
||||
import { BinaryOperationID } from '../../utils';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
const seriesA = toDataFrame({
|
||||
fields: [
|
||||
@@ -30,7 +29,7 @@ describe('calculateField transformer w/ timeseries', () => {
|
||||
mockTransformationsRegistry([calculateFieldTransformer]);
|
||||
});
|
||||
|
||||
it('will filter and alias', done => {
|
||||
it('will filter and alias', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.calculateField,
|
||||
options: {
|
||||
@@ -39,35 +38,32 @@ describe('calculateField transformer w/ timeseries', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesA, seriesBC]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
const rows = new DataFrameView(filtered).toArray();
|
||||
expect(rows).toEqual([
|
||||
{
|
||||
A: 1,
|
||||
B: 2,
|
||||
C: 3,
|
||||
D: 'first',
|
||||
'The Total': 6,
|
||||
TheTime: 1000,
|
||||
},
|
||||
{
|
||||
A: 100,
|
||||
B: 200,
|
||||
C: 300,
|
||||
D: 'second',
|
||||
'The Total': 600,
|
||||
TheTime: 2000,
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesA, seriesBC])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
const rows = new DataFrameView(filtered).toArray();
|
||||
expect(rows).toEqual([
|
||||
{
|
||||
A: 1,
|
||||
B: 2,
|
||||
C: 3,
|
||||
D: 'first',
|
||||
'The Total': 6,
|
||||
TheTime: 1000,
|
||||
},
|
||||
{
|
||||
A: 100,
|
||||
B: 200,
|
||||
C: 300,
|
||||
D: 'second',
|
||||
'The Total': 600,
|
||||
TheTime: 2000,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('will replace other fields', done => {
|
||||
it('will replace other fields', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.calculateField,
|
||||
options: {
|
||||
@@ -79,27 +75,24 @@ describe('calculateField transformer w/ timeseries', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesA, seriesBC]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
const rows = new DataFrameView(filtered).toArray();
|
||||
expect(rows).toEqual([
|
||||
{
|
||||
Mean: 2,
|
||||
TheTime: 1000,
|
||||
},
|
||||
{
|
||||
Mean: 200,
|
||||
TheTime: 2000,
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesA, seriesBC])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
const rows = new DataFrameView(filtered).toArray();
|
||||
expect(rows).toEqual([
|
||||
{
|
||||
Mean: 2,
|
||||
TheTime: 1000,
|
||||
},
|
||||
{
|
||||
Mean: 200,
|
||||
TheTime: 2000,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('will filter by name', done => {
|
||||
it('will filter by name', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.calculateField,
|
||||
options: {
|
||||
@@ -112,27 +105,24 @@ describe('calculateField transformer w/ timeseries', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesBC]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
const rows = new DataFrameView(filtered).toArray();
|
||||
expect(rows).toEqual([
|
||||
{
|
||||
Mean: 2,
|
||||
TheTime: 1000,
|
||||
},
|
||||
{
|
||||
Mean: 200,
|
||||
TheTime: 2000,
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesBC])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
const rows = new DataFrameView(filtered).toArray();
|
||||
expect(rows).toEqual([
|
||||
{
|
||||
Mean: 2,
|
||||
TheTime: 1000,
|
||||
},
|
||||
{
|
||||
Mean: 200,
|
||||
TheTime: 2000,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('binary math', done => {
|
||||
it('binary math', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.calculateField,
|
||||
options: {
|
||||
@@ -146,27 +136,24 @@ describe('calculateField transformer w/ timeseries', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesBC]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
const rows = new DataFrameView(filtered).toArray();
|
||||
expect(rows).toEqual([
|
||||
{
|
||||
'B + C': 5,
|
||||
TheTime: 1000,
|
||||
},
|
||||
{
|
||||
'B + C': 500,
|
||||
TheTime: 2000,
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesBC])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
const rows = new DataFrameView(filtered).toArray();
|
||||
expect(rows).toEqual([
|
||||
{
|
||||
'B + C': 5,
|
||||
TheTime: 1000,
|
||||
},
|
||||
{
|
||||
'B + C': 500,
|
||||
TheTime: 2000,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('field + static number', done => {
|
||||
it('field + static number', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.calculateField,
|
||||
options: {
|
||||
@@ -180,23 +167,20 @@ describe('calculateField transformer w/ timeseries', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesBC]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
const rows = new DataFrameView(filtered).toArray();
|
||||
expect(rows).toEqual([
|
||||
{
|
||||
'B + 2': 4,
|
||||
TheTime: 1000,
|
||||
},
|
||||
{
|
||||
'B + 2': 202,
|
||||
TheTime: 2000,
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesBC])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
const rows = new DataFrameView(filtered).toArray();
|
||||
expect(rows).toEqual([
|
||||
{
|
||||
'B + 2': 4,
|
||||
TheTime: 1000,
|
||||
},
|
||||
{
|
||||
'B + 2': 202,
|
||||
TheTime: 2000,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -5,7 +5,6 @@ import { mockTransformationsRegistry } from '../../utils/tests/mockTransformatio
|
||||
import { transformDataFrame } from '../transformDataFrame';
|
||||
import { ensureColumnsTransformer } from './ensureColumns';
|
||||
import { seriesToColumnsTransformer } from './seriesToColumns';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
const seriesA = toDataFrame({
|
||||
fields: [
|
||||
@@ -36,7 +35,7 @@ describe('ensureColumns transformer', () => {
|
||||
mockTransformationsRegistry([ensureColumnsTransformer, seriesToColumnsTransformer]);
|
||||
});
|
||||
|
||||
it('will transform to columns if time field exists and multiple frames', done => {
|
||||
it('will transform to columns if time field exists and multiple frames', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.ensureColumns,
|
||||
options: {},
|
||||
@@ -44,79 +43,62 @@ describe('ensureColumns transformer', () => {
|
||||
|
||||
const data = [seriesA, seriesBC];
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], data),
|
||||
expect: filtered => {
|
||||
expect(filtered.length).toEqual(1);
|
||||
expect(filtered[0]).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"fields": Array [
|
||||
Object {
|
||||
"config": Object {},
|
||||
"labels": undefined,
|
||||
"name": "TheTime",
|
||||
"type": "time",
|
||||
"values": Array [
|
||||
1000,
|
||||
2000,
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"config": Object {},
|
||||
"labels": Object {},
|
||||
"name": "A",
|
||||
"type": "number",
|
||||
"values": Array [
|
||||
1,
|
||||
100,
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"config": Object {},
|
||||
"labels": Object {},
|
||||
"name": "B",
|
||||
"type": "number",
|
||||
"values": Array [
|
||||
2,
|
||||
200,
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"config": Object {},
|
||||
"labels": Object {},
|
||||
"name": "C",
|
||||
"type": "number",
|
||||
"values": Array [
|
||||
3,
|
||||
300,
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"config": Object {},
|
||||
"labels": Object {},
|
||||
"name": "D",
|
||||
"type": "string",
|
||||
"values": Array [
|
||||
"first",
|
||||
"second",
|
||||
],
|
||||
},
|
||||
],
|
||||
"meta": Object {
|
||||
"transformations": Array [
|
||||
"ensureColumns",
|
||||
await expect(transformDataFrame([cfg], data)).toEmitValuesWith(received => {
|
||||
const filtered = received[0];
|
||||
expect(filtered.length).toEqual(1);
|
||||
|
||||
const frame = filtered[0];
|
||||
expect(frame.fields.length).toEqual(5);
|
||||
expect(filtered[0]).toEqual(
|
||||
toDataFrame({
|
||||
fields: [
|
||||
{
|
||||
name: 'TheTime',
|
||||
type: 'time',
|
||||
config: {},
|
||||
values: [1000, 2000],
|
||||
labels: undefined,
|
||||
},
|
||||
{
|
||||
name: 'A',
|
||||
type: 'number',
|
||||
config: {},
|
||||
values: [1, 100],
|
||||
labels: {},
|
||||
},
|
||||
{
|
||||
name: 'B',
|
||||
type: 'number',
|
||||
config: {},
|
||||
values: [2, 200],
|
||||
labels: {},
|
||||
},
|
||||
{
|
||||
name: 'C',
|
||||
type: 'number',
|
||||
config: {},
|
||||
values: [3, 300],
|
||||
labels: {},
|
||||
},
|
||||
{
|
||||
name: 'D',
|
||||
type: 'string',
|
||||
config: {},
|
||||
values: ['first', 'second'],
|
||||
labels: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
"name": undefined,
|
||||
"refId": undefined,
|
||||
}
|
||||
`);
|
||||
},
|
||||
done,
|
||||
meta: {
|
||||
transformations: ['ensureColumns'],
|
||||
},
|
||||
name: undefined,
|
||||
refId: undefined,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('will not transform to columns if time field is missing for any of the series', done => {
|
||||
it('will not transform to columns if time field is missing for any of the series', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.ensureColumns,
|
||||
options: {},
|
||||
@@ -124,16 +106,10 @@ describe('ensureColumns transformer', () => {
|
||||
|
||||
const data = [seriesBC, seriesNoTime];
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], data),
|
||||
expect: filtered => {
|
||||
expect(filtered).toEqual(data);
|
||||
},
|
||||
done,
|
||||
});
|
||||
await expect(transformDataFrame([cfg], data)).toEmitValues([data]);
|
||||
});
|
||||
|
||||
it('will not transform to columns if only one series', done => {
|
||||
it('will not transform to columns if only one series', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.ensureColumns,
|
||||
options: {},
|
||||
@@ -141,12 +117,6 @@ describe('ensureColumns transformer', () => {
|
||||
|
||||
const data = [seriesBC];
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], data),
|
||||
expect: filtered => {
|
||||
expect(filtered).toEqual(data);
|
||||
},
|
||||
done,
|
||||
});
|
||||
await expect(transformDataFrame([cfg], data)).toEmitValues([data]);
|
||||
});
|
||||
});
|
||||
|
@@ -5,7 +5,6 @@ import { FieldMatcherID } from '../matchers/ids';
|
||||
import { mockTransformationsRegistry } from '../../utils/tests/mockTransformationsRegistry';
|
||||
import { filterFieldsTransformer } from './filter';
|
||||
import { transformDataFrame } from '../transformDataFrame';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
export const simpleSeriesWithTypes = toDataFrame({
|
||||
fields: [
|
||||
@@ -21,7 +20,7 @@ describe('Filter Transformer', () => {
|
||||
mockTransformationsRegistry([filterFieldsTransformer]);
|
||||
});
|
||||
|
||||
it('filters by include', done => {
|
||||
it('filters by include', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterFields,
|
||||
options: {
|
||||
@@ -29,14 +28,11 @@ describe('Filter Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [simpleSeriesWithTypes]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(1);
|
||||
expect(filtered.fields[0].name).toBe('D');
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [simpleSeriesWithTypes])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(1);
|
||||
expect(filtered.fields[0].name).toBe('D');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -5,7 +5,6 @@ import { mockTransformationsRegistry } from '../../utils/tests/mockTransformatio
|
||||
import { filterFieldsByNameTransformer } from './filterByName';
|
||||
import { filterFieldsTransformer } from './filter';
|
||||
import { transformDataFrame } from '../transformDataFrame';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
export const seriesWithNamesToMatch = toDataFrame({
|
||||
fields: [
|
||||
@@ -21,24 +20,21 @@ describe('filterByName transformer', () => {
|
||||
mockTransformationsRegistry([filterFieldsByNameTransformer, filterFieldsTransformer]);
|
||||
});
|
||||
|
||||
it('returns original series if no options provided', done => {
|
||||
it('returns original series if no options provided', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterFields,
|
||||
options: {},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesWithNamesToMatch]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(4);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesWithNamesToMatch])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('respects', () => {
|
||||
it('inclusion by pattern', done => {
|
||||
it('inclusion by pattern', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterFieldsByName,
|
||||
options: {
|
||||
@@ -48,18 +44,15 @@ describe('filterByName transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesWithNamesToMatch]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('startsWithA');
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesWithNamesToMatch])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('startsWithA');
|
||||
});
|
||||
});
|
||||
|
||||
it('exclusion by pattern', done => {
|
||||
it('exclusion by pattern', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterFieldsByName,
|
||||
options: {
|
||||
@@ -69,18 +62,15 @@ describe('filterByName transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesWithNamesToMatch]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesWithNamesToMatch])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
});
|
||||
});
|
||||
|
||||
it('inclusion and exclusion by pattern', done => {
|
||||
it('inclusion and exclusion by pattern', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterFieldsByName,
|
||||
options: {
|
||||
@@ -89,18 +79,15 @@ describe('filterByName transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesWithNamesToMatch]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(1);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesWithNamesToMatch])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(1);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
});
|
||||
});
|
||||
|
||||
it('inclusion by names', done => {
|
||||
it('inclusion by names', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterFieldsByName,
|
||||
options: {
|
||||
@@ -110,18 +97,15 @@ describe('filterByName transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesWithNamesToMatch]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('startsWithA');
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesWithNamesToMatch])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('startsWithA');
|
||||
});
|
||||
});
|
||||
|
||||
it('exclusion by names', done => {
|
||||
it('exclusion by names', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterFieldsByName,
|
||||
options: {
|
||||
@@ -131,18 +115,15 @@ describe('filterByName transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesWithNamesToMatch]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesWithNamesToMatch])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
});
|
||||
});
|
||||
|
||||
it('inclusion and exclusion by names', done => {
|
||||
it('inclusion and exclusion by names', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterFieldsByName,
|
||||
options: {
|
||||
@@ -151,18 +132,15 @@ describe('filterByName transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesWithNamesToMatch]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(1);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesWithNamesToMatch])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(1);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
});
|
||||
});
|
||||
|
||||
it('inclusion by both', done => {
|
||||
it('inclusion by both', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterFieldsByName,
|
||||
options: {
|
||||
@@ -173,18 +151,15 @@ describe('filterByName transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesWithNamesToMatch]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('startsWithA');
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesWithNamesToMatch])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('startsWithA');
|
||||
});
|
||||
});
|
||||
|
||||
it('exclusion by both', done => {
|
||||
it('exclusion by both', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterFieldsByName,
|
||||
options: {
|
||||
@@ -195,18 +170,15 @@ describe('filterByName transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesWithNamesToMatch]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesWithNamesToMatch])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(2);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
});
|
||||
});
|
||||
|
||||
it('inclusion and exclusion by both', done => {
|
||||
it('inclusion and exclusion by both', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterFieldsByName,
|
||||
options: {
|
||||
@@ -215,14 +187,11 @@ describe('filterByName transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesWithNamesToMatch]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(1);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [seriesWithNamesToMatch])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields.length).toBe(1);
|
||||
expect(filtered.fields[0].name).toBe('B');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -3,7 +3,6 @@ import { toDataFrame } from '../../dataframe/processDataFrame';
|
||||
import { mockTransformationsRegistry } from '../../utils/tests/mockTransformationsRegistry';
|
||||
import { filterFramesByRefIdTransformer } from './filterByRefId';
|
||||
import { transformDataFrame } from '../transformDataFrame';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
export const allSeries = [
|
||||
toDataFrame({
|
||||
@@ -25,23 +24,20 @@ describe('filterByRefId transformer', () => {
|
||||
mockTransformationsRegistry([filterFramesByRefIdTransformer]);
|
||||
});
|
||||
|
||||
it('returns all series if no options provided', done => {
|
||||
it('returns all series if no options provided', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterByRefId,
|
||||
options: {},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], allSeries),
|
||||
expect: filtered => {
|
||||
expect(filtered.length).toBe(3);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], allSeries)).toEmitValuesWith(received => {
|
||||
const filtered = received[0];
|
||||
expect(filtered.length).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('respects', () => {
|
||||
it('inclusion', done => {
|
||||
it('inclusion', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.filterByRefId,
|
||||
options: {
|
||||
@@ -49,12 +45,9 @@ describe('filterByRefId transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], allSeries),
|
||||
expect: filtered => {
|
||||
expect(filtered.map(f => f.refId)).toEqual(['A', 'B']);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], allSeries)).toEmitValuesWith(received => {
|
||||
const filtered = received[0];
|
||||
expect(filtered.map(f => f.refId)).toEqual(['A', 'B']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -7,14 +7,13 @@ import { DataTransformerID } from './ids';
|
||||
import { ArrayVector } from '../../vector';
|
||||
import { ReducerID } from '../fieldReducer';
|
||||
import { DataTransformerConfig } from '@grafana/data';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
describe('GroupBy transformer', () => {
|
||||
beforeAll(() => {
|
||||
mockTransformationsRegistry([groupByTransformer]);
|
||||
});
|
||||
|
||||
it('should not apply transformation if config is missing group by fields', done => {
|
||||
it('should not apply transformation if config is missing group by fields', async () => {
|
||||
const testSeries = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -36,16 +35,13 @@ describe('GroupBy transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [testSeries]),
|
||||
expect: result => {
|
||||
expect(result[0]).toBe(testSeries);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [testSeries])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
expect(result[0]).toBe(testSeries);
|
||||
});
|
||||
});
|
||||
|
||||
it('should group values by message', done => {
|
||||
it('should group values by message', async () => {
|
||||
const testSeries = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -67,25 +63,22 @@ describe('GroupBy transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [testSeries]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'message',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['one', 'two', 'three']),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [testSeries])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'message',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['one', 'two', 'three']),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
|
||||
expect(result[0].fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(result[0].fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('should group values by message and summarize values', done => {
|
||||
it('should group values by message and summarize values', async () => {
|
||||
const testSeries = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -111,31 +104,28 @@ describe('GroupBy transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [testSeries]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'message',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['one', 'two', 'three']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'values (sum)',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([1, 4, 9]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [testSeries])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'message',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['one', 'two', 'three']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'values (sum)',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([1, 4, 9]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
|
||||
expect(result[0].fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(result[0].fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('should group by and compute a few calculations for each group of values', done => {
|
||||
it('should group by and compute a few calculations for each group of values', async () => {
|
||||
const testSeries = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -165,43 +155,40 @@ describe('GroupBy transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [testSeries]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'message',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['one', 'two', 'three']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'time (count)',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([1, 2, 3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'time (last)',
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 5000, 8000]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'values (sum)',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([1, 4, 9]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [testSeries])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'message',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['one', 'two', 'three']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'time (count)',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([1, 2, 3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'time (last)',
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 5000, 8000]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'values (sum)',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([1, 4, 9]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
|
||||
expect(result[0].fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(result[0].fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('should group values in data frames induvidually', done => {
|
||||
it('should group values in data frames individually', async () => {
|
||||
const testSeries = [
|
||||
toDataFrame({
|
||||
name: 'A',
|
||||
@@ -237,43 +224,40 @@ describe('GroupBy transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], testSeries),
|
||||
expect: result => {
|
||||
const expectedA: Field[] = [
|
||||
{
|
||||
name: 'message',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['one', 'two', 'three']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'values (sum)',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([1, 4, 9]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
await expect(transformDataFrame([cfg], testSeries)).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expectedA: Field[] = [
|
||||
{
|
||||
name: 'message',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['one', 'two', 'three']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'values (sum)',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([1, 4, 9]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
|
||||
const expectedB: Field[] = [
|
||||
{
|
||||
name: 'message',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['one', 'two', 'three']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'values (sum)',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([0, 7, 8]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
const expectedB: Field[] = [
|
||||
{
|
||||
name: 'message',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['one', 'two', 'three']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'values (sum)',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([0, 7, 8]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
|
||||
expect(result[0].fields).toEqual(expectedA);
|
||||
expect(result[1].fields).toEqual(expectedB);
|
||||
},
|
||||
done,
|
||||
expect(result[0].fields).toEqual(expectedA);
|
||||
expect(result[1].fields).toEqual(expectedB);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -4,14 +4,13 @@ import { DataTransformerConfig, FieldDTO, FieldType } from '../../types';
|
||||
import { DataTransformerID } from './ids';
|
||||
import { toDataFrame, toDataFrameDTO } from '../../dataframe';
|
||||
import { transformDataFrame } from '../transformDataFrame';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
describe('Labels as Columns', () => {
|
||||
beforeAll(() => {
|
||||
mockTransformationsRegistry([labelsToFieldsTransformer]);
|
||||
});
|
||||
|
||||
it('data frame with two labels', done => {
|
||||
it('data frame with two labels', async () => {
|
||||
const cfg: DataTransformerConfig<LabelsToFieldsOptions> = {
|
||||
id: DataTransformerID.labelsToFields,
|
||||
options: {},
|
||||
@@ -25,30 +24,27 @@ describe('Labels as Columns', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [source]),
|
||||
expect: data => {
|
||||
const result = toDataFrameDTO(data[0]);
|
||||
await expect(transformDataFrame([cfg], [source])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const result = toDataFrameDTO(data[0]);
|
||||
|
||||
const expected: FieldDTO[] = [
|
||||
{ name: 'time', type: FieldType.time, values: [1000, 2000], config: {} },
|
||||
{
|
||||
name: 'location',
|
||||
type: FieldType.string,
|
||||
values: ['inside', 'inside'],
|
||||
config: {},
|
||||
},
|
||||
{ name: 'feelsLike', type: FieldType.string, values: ['ok', 'ok'], config: {} },
|
||||
{ name: 'Value', type: FieldType.number, values: [1, 2], config: {} },
|
||||
];
|
||||
const expected: FieldDTO[] = [
|
||||
{ name: 'time', type: FieldType.time, values: [1000, 2000], config: {} },
|
||||
{
|
||||
name: 'location',
|
||||
type: FieldType.string,
|
||||
values: ['inside', 'inside'],
|
||||
config: {},
|
||||
},
|
||||
{ name: 'feelsLike', type: FieldType.string, values: ['ok', 'ok'], config: {} },
|
||||
{ name: 'Value', type: FieldType.number, values: [1, 2], config: {} },
|
||||
];
|
||||
|
||||
expect(result.fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(result.fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('data frame with two labels and valueLabel option', done => {
|
||||
it('data frame with two labels and valueLabel option', async () => {
|
||||
const cfg: DataTransformerConfig<LabelsToFieldsOptions> = {
|
||||
id: DataTransformerID.labelsToFields,
|
||||
options: { valueLabel: 'name' },
|
||||
@@ -71,29 +67,26 @@ describe('Labels as Columns', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [source]),
|
||||
expect: data => {
|
||||
const result = toDataFrameDTO(data[0]);
|
||||
await expect(transformDataFrame([cfg], [source])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const result = toDataFrameDTO(data[0]);
|
||||
|
||||
const expected: FieldDTO[] = [
|
||||
{ name: 'time', type: FieldType.time, values: [1000, 2000], config: {} },
|
||||
{
|
||||
name: 'location',
|
||||
type: FieldType.string,
|
||||
values: ['inside', 'inside'],
|
||||
config: {},
|
||||
},
|
||||
{ name: 'Request', type: FieldType.number, values: [1, 2], config: {} },
|
||||
];
|
||||
const expected: FieldDTO[] = [
|
||||
{ name: 'time', type: FieldType.time, values: [1000, 2000], config: {} },
|
||||
{
|
||||
name: 'location',
|
||||
type: FieldType.string,
|
||||
values: ['inside', 'inside'],
|
||||
config: {},
|
||||
},
|
||||
{ name: 'Request', type: FieldType.number, values: [1, 2], config: {} },
|
||||
];
|
||||
|
||||
expect(result.fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(result.fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('two data frames with 1 value and 1 label', done => {
|
||||
it('two data frames with 1 value and 1 label', async () => {
|
||||
const cfg: DataTransformerConfig<LabelsToFieldsOptions> = {
|
||||
id: DataTransformerID.labelsToFields,
|
||||
options: {},
|
||||
@@ -115,20 +108,17 @@ describe('Labels as Columns', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [oneValueOneLabelA, oneValueOneLabelB]),
|
||||
expect: data => {
|
||||
const result = toDataFrameDTO(data[0]);
|
||||
await expect(transformDataFrame([cfg], [oneValueOneLabelA, oneValueOneLabelB])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const result = toDataFrameDTO(data[0]);
|
||||
|
||||
const expected: FieldDTO[] = [
|
||||
{ name: 'time', type: FieldType.time, values: [1000, 2000], config: {} },
|
||||
{ name: 'location', type: FieldType.string, values: ['inside', 'outside'], config: {} },
|
||||
{ name: 'temp', type: FieldType.number, values: [1, -1], config: {} },
|
||||
];
|
||||
const expected: FieldDTO[] = [
|
||||
{ name: 'time', type: FieldType.time, values: [1000, 2000], config: {} },
|
||||
{ name: 'location', type: FieldType.string, values: ['inside', 'outside'], config: {} },
|
||||
{ name: 'temp', type: FieldType.number, values: [1, -1], config: {} },
|
||||
];
|
||||
|
||||
expect(result.fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(result.fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -5,9 +5,8 @@ import { toDataFrame } from '../../dataframe';
|
||||
import { transformDataFrame } from '../transformDataFrame';
|
||||
import { ArrayVector } from '../../vector';
|
||||
import { mergeTransformer, MergeTransformerOptions } from './merge';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
describe('Merge multipe to single', () => {
|
||||
describe('Merge multiple to single', () => {
|
||||
const cfg: DataTransformerConfig<MergeTransformerOptions> = {
|
||||
id: DataTransformerID.merge,
|
||||
options: {},
|
||||
@@ -17,7 +16,7 @@ describe('Merge multipe to single', () => {
|
||||
mockTransformationsRegistry([mergeTransformer]);
|
||||
});
|
||||
|
||||
it('combine two series into one', done => {
|
||||
it('combine two series into one', async () => {
|
||||
const seriesA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -34,21 +33,18 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesA, seriesB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [1000, 2000]),
|
||||
createField('Temp', FieldType.number, [1, -1]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [seriesA, seriesB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [1000, 2000]),
|
||||
createField('Temp', FieldType.number, [1, -1]),
|
||||
];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two series with multiple values into one', done => {
|
||||
it('combine two series with multiple values into one', async () => {
|
||||
const seriesA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -65,21 +61,18 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesA, seriesB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [seriesA, seriesB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3]),
|
||||
];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine three series into one', done => {
|
||||
it('combine three series into one', async () => {
|
||||
const seriesA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -104,21 +97,18 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesA, seriesB, seriesC]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [1000, 2000, 500]),
|
||||
createField('Temp', FieldType.number, [1, -1, 2]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [seriesA, seriesB, seriesC])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [1000, 2000, 500]),
|
||||
createField('Temp', FieldType.number, [1, -1, 2]),
|
||||
];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine one serie and two tables into one table', done => {
|
||||
it('combine one serie and two tables into one table', async () => {
|
||||
const tableA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -145,22 +135,19 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [tableA, seriesB, tableB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [1000, 1000, 500]),
|
||||
createField('Temp', FieldType.number, [1, -1, 2]),
|
||||
createField('Humidity', FieldType.number, [10, null, 5]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [tableA, seriesB, tableB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [1000, 1000, 500]),
|
||||
createField('Temp', FieldType.number, [1, -1, 2]),
|
||||
createField('Humidity', FieldType.number, [10, null, 5]),
|
||||
];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine one serie and two tables with ISO dates into one table', done => {
|
||||
it('combine one serie and two tables with ISO dates into one table', async () => {
|
||||
const tableA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -187,22 +174,19 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [tableA, seriesB, tableC]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, ['2019-10-01T11:10:23Z', '2019-09-01T11:10:23Z', '2019-11-01T11:10:23Z']),
|
||||
createField('Temp', FieldType.number, [1, -1, 2]),
|
||||
createField('Humidity', FieldType.number, [10, null, 5]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [tableA, seriesB, tableC])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, ['2019-10-01T11:10:23Z', '2019-09-01T11:10:23Z', '2019-11-01T11:10:23Z']),
|
||||
createField('Temp', FieldType.number, [1, -1, 2]),
|
||||
createField('Humidity', FieldType.number, [10, null, 5]),
|
||||
];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two tables, where first is partial overlapping, into one', done => {
|
||||
it('combine two tables, where first is partial overlapping, into one', async () => {
|
||||
const tableA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -228,39 +212,36 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [tableA, tableB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Country', FieldType.string, [
|
||||
'United States',
|
||||
'United States',
|
||||
'Mexico',
|
||||
'Germany',
|
||||
'Canada',
|
||||
'Canada',
|
||||
null,
|
||||
]),
|
||||
createField('AgeGroup', FieldType.string, [
|
||||
'50 or over',
|
||||
'35 - 49',
|
||||
'0 - 17',
|
||||
'35 - 49',
|
||||
'35 - 49',
|
||||
'25 - 34',
|
||||
'18 - 24',
|
||||
]),
|
||||
createField('Sum', FieldType.number, [998, 1193, 1675, 146, 166, 219, null]),
|
||||
createField('Count', FieldType.number, [2, 4, 1, 4, 4, 2, 3]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [tableA, tableB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Country', FieldType.string, [
|
||||
'United States',
|
||||
'United States',
|
||||
'Mexico',
|
||||
'Germany',
|
||||
'Canada',
|
||||
'Canada',
|
||||
null,
|
||||
]),
|
||||
createField('AgeGroup', FieldType.string, [
|
||||
'50 or over',
|
||||
'35 - 49',
|
||||
'0 - 17',
|
||||
'35 - 49',
|
||||
'35 - 49',
|
||||
'25 - 34',
|
||||
'18 - 24',
|
||||
]),
|
||||
createField('Sum', FieldType.number, [998, 1193, 1675, 146, 166, 219, null]),
|
||||
createField('Count', FieldType.number, [2, 4, 1, 4, 4, 2, 3]),
|
||||
];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two tables, where second is partial overlapping, into one', done => {
|
||||
it('combine two tables, where second is partial overlapping, into one', async () => {
|
||||
/**
|
||||
* This behavior feels wrong. I would expect the same behavior regardless of the order
|
||||
* of the frames. But when testing the old table panel it had this behavior so I am
|
||||
@@ -291,39 +272,36 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [tableA, tableB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('AgeGroup', FieldType.string, [
|
||||
'0 - 17',
|
||||
'18 - 24',
|
||||
'25 - 34',
|
||||
'35 - 49',
|
||||
'50 or over',
|
||||
'35 - 49',
|
||||
'35 - 49',
|
||||
]),
|
||||
createField('Count', FieldType.number, [1, 3, 2, 4, 2, null, null]),
|
||||
createField('Country', FieldType.string, [
|
||||
'Mexico',
|
||||
null,
|
||||
'Canada',
|
||||
'United States',
|
||||
'United States',
|
||||
'Germany',
|
||||
'Canada',
|
||||
]),
|
||||
createField('Sum', FieldType.number, [1675, null, 219, 1193, 998, 146, 166]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [tableA, tableB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('AgeGroup', FieldType.string, [
|
||||
'0 - 17',
|
||||
'18 - 24',
|
||||
'25 - 34',
|
||||
'35 - 49',
|
||||
'50 or over',
|
||||
'35 - 49',
|
||||
'35 - 49',
|
||||
]),
|
||||
createField('Count', FieldType.number, [1, 3, 2, 4, 2, null, null]),
|
||||
createField('Country', FieldType.string, [
|
||||
'Mexico',
|
||||
null,
|
||||
'Canada',
|
||||
'United States',
|
||||
'United States',
|
||||
'Germany',
|
||||
'Canada',
|
||||
]),
|
||||
createField('Sum', FieldType.number, [1675, null, 219, 1193, 998, 146, 166]),
|
||||
];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine three tables with multiple values into one', done => {
|
||||
it('combine three tables with multiple values into one', async () => {
|
||||
const tableA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -351,23 +329,20 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [tableA, tableB, tableC]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126, 100, 124, 149]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3, 1, 4, 5]),
|
||||
createField('Humidity', FieldType.number, [10, 14, 55, null, null, null, 22, 25, 30]),
|
||||
createField('Enabled', FieldType.boolean, [null, null, null, true, false, true, null, null, null]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [tableA, tableB, tableC])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126, 100, 124, 149]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3, 1, 4, 5]),
|
||||
createField('Humidity', FieldType.number, [10, 14, 55, null, null, null, 22, 25, 30]),
|
||||
createField('Enabled', FieldType.boolean, [null, null, null, true, false, true, null, null, null]),
|
||||
];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two time series, where first serie fields has displayName, into one', done => {
|
||||
it('combine two time series, where first serie fields has displayName, into one', async () => {
|
||||
const serieA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -384,24 +359,21 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [serieA, serieB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [serieA, serieB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3]),
|
||||
];
|
||||
|
||||
const fields = unwrap(result[0].fields);
|
||||
const fields = unwrap(result[0].fields);
|
||||
|
||||
expect(fields[1].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(fields[1].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two time series, where first serie fields has display processor, into one', done => {
|
||||
it('combine two time series, where first serie fields has display processor, into one', async () => {
|
||||
const displayProcessor: DisplayProcessor = jest.fn();
|
||||
|
||||
const serieA = toDataFrame({
|
||||
@@ -420,24 +392,21 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [serieA, serieB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126], {}, displayProcessor),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [serieA, serieB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126], {}, displayProcessor),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3]),
|
||||
];
|
||||
|
||||
const fields = unwrap(result[0].fields);
|
||||
const fields = unwrap(result[0].fields);
|
||||
|
||||
expect(fields[0].display).toBe(displayProcessor);
|
||||
expect(fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(fields[0].display).toBe(displayProcessor);
|
||||
expect(fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two time series, where first serie fields has units, into one', done => {
|
||||
it('combine two time series, where first serie fields has units, into one', async () => {
|
||||
const serieA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -454,24 +423,21 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [serieA, serieB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3], { units: 'celsius' }),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [serieA, serieB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3], { units: 'celsius' }),
|
||||
];
|
||||
|
||||
const fields = unwrap(result[0].fields);
|
||||
const fields = unwrap(result[0].fields);
|
||||
|
||||
expect(fields[1].config).toEqual({ units: 'celsius' });
|
||||
expect(fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(fields[1].config).toEqual({ units: 'celsius' });
|
||||
expect(fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two time series, where second serie fields has units, into one', done => {
|
||||
it('combine two time series, where second serie fields has units, into one', async () => {
|
||||
const serieA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -488,24 +454,21 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [serieA, serieB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [serieA, serieB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200, 100, 125, 126]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5, -1, 2, 3]),
|
||||
];
|
||||
|
||||
const fields = unwrap(result[0].fields);
|
||||
const fields = unwrap(result[0].fields);
|
||||
|
||||
expect(fields[1].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(fields[1].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine one regular serie with an empty serie should return the regular serie', done => {
|
||||
it('combine one regular serie with an empty serie should return the regular serie', async () => {
|
||||
const serieA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -519,24 +482,21 @@ describe('Merge multipe to single', () => {
|
||||
fields: [],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [serieA, serieB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [serieA, serieB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5]),
|
||||
];
|
||||
|
||||
const fields = unwrap(result[0].fields);
|
||||
const fields = unwrap(result[0].fields);
|
||||
|
||||
expect(fields[1].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(fields[1].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two regular series with an empty serie should return the combination of the regular series', done => {
|
||||
it('combine two regular series with an empty serie should return the combination of the regular series', async () => {
|
||||
const serieA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [
|
||||
@@ -558,25 +518,22 @@ describe('Merge multipe to single', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [serieA, serieB, serieC]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5]),
|
||||
createField('Humidity', FieldType.number, [6, 7, 8]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [serieA, serieB, serieC])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [100, 150, 200]),
|
||||
createField('Temp', FieldType.number, [1, 4, 5]),
|
||||
createField('Humidity', FieldType.number, [6, 7, 8]),
|
||||
];
|
||||
|
||||
const fields = unwrap(result[0].fields);
|
||||
const fields = unwrap(result[0].fields);
|
||||
|
||||
expect(fields[1].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(fields[1].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine multiple empty series should return one empty serie', done => {
|
||||
it('combine multiple empty series should return one empty serie', async () => {
|
||||
const serieA = toDataFrame({
|
||||
name: 'A',
|
||||
fields: [],
|
||||
@@ -592,16 +549,13 @@ describe('Merge multipe to single', () => {
|
||||
fields: [],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [serieA, serieB, serieC]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [];
|
||||
const fields = unwrap(result[0].fields);
|
||||
await expect(transformDataFrame([cfg], [serieA, serieB, serieC])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
const expected: Field[] = [];
|
||||
const fields = unwrap(result[0].fields);
|
||||
|
||||
expect(fields).toEqual(expected);
|
||||
expect(result.length).toEqual(1);
|
||||
},
|
||||
done,
|
||||
expect(fields).toEqual(expected);
|
||||
expect(result.length).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -8,7 +8,6 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { orderFieldsTransformer, OrderFieldsTransformerOptions } from './order';
|
||||
import { mockTransformationsRegistry } from '../../utils/tests/mockTransformationsRegistry';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
describe('Order Transformer', () => {
|
||||
beforeAll(() => {
|
||||
@@ -24,7 +23,7 @@ describe('Order Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
it('should order according to config', done => {
|
||||
it('should order according to config', async () => {
|
||||
const cfg: DataTransformerConfig<OrderFieldsTransformerOptions> = {
|
||||
id: DataTransformerID.order,
|
||||
options: {
|
||||
@@ -36,44 +35,41 @@ describe('Order Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [data]),
|
||||
expect: data => {
|
||||
const ordered = data[0];
|
||||
expect(ordered.fields).toEqual([
|
||||
{
|
||||
config: {},
|
||||
name: 'temperature',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'temperature',
|
||||
},
|
||||
await expect(transformDataFrame([cfg], [data])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const ordered = data[0];
|
||||
expect(ordered.fields).toEqual([
|
||||
{
|
||||
config: {},
|
||||
name: 'temperature',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'temperature',
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'humidity',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'humidity',
|
||||
},
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'humidity',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'humidity',
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'time',
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'time',
|
||||
},
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'time',
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'time',
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -88,7 +84,7 @@ describe('Order Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
it('should append fields missing in config at the end', done => {
|
||||
it('should append fields missing in config at the end', async () => {
|
||||
const cfg: DataTransformerConfig<OrderFieldsTransformerOptions> = {
|
||||
id: DataTransformerID.order,
|
||||
options: {
|
||||
@@ -100,44 +96,41 @@ describe('Order Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [data]),
|
||||
expect: data => {
|
||||
const ordered = data[0];
|
||||
expect(ordered.fields).toEqual([
|
||||
{
|
||||
config: {},
|
||||
name: 'humidity',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'humidity',
|
||||
},
|
||||
await expect(transformDataFrame([cfg], [data])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const ordered = data[0];
|
||||
expect(ordered.fields).toEqual([
|
||||
{
|
||||
config: {},
|
||||
name: 'humidity',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'humidity',
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'time',
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'time',
|
||||
},
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'time',
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'time',
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'pressure',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'pressure',
|
||||
},
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'pressure',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'pressure',
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -152,7 +145,7 @@ describe('Order Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
it('should keep the same order as in the incoming data', done => {
|
||||
it('should keep the same order as in the incoming data', async () => {
|
||||
const cfg: DataTransformerConfig<OrderFieldsTransformerOptions> = {
|
||||
id: DataTransformerID.order,
|
||||
options: {
|
||||
@@ -160,32 +153,29 @@ describe('Order Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [data]),
|
||||
expect: data => {
|
||||
const ordered = data[0];
|
||||
expect(ordered.fields).toEqual([
|
||||
{
|
||||
config: {},
|
||||
name: 'time',
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'pressure',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'humidity',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [data])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const ordered = data[0];
|
||||
expect(ordered.fields).toEqual([
|
||||
{
|
||||
config: {},
|
||||
name: 'time',
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'pressure',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'humidity',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -8,7 +8,6 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { organizeFieldsTransformer, OrganizeFieldsTransformerOptions } from './organize';
|
||||
import { mockTransformationsRegistry } from '../../utils/tests/mockTransformationsRegistry';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
describe('OrganizeFields Transformer', () => {
|
||||
beforeAll(() => {
|
||||
@@ -25,7 +24,7 @@ describe('OrganizeFields Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
it('should order and filter according to config', done => {
|
||||
it('should order and filter according to config', async () => {
|
||||
const cfg: DataTransformerConfig<OrganizeFieldsTransformerOptions> = {
|
||||
id: DataTransformerID.organize,
|
||||
options: {
|
||||
@@ -43,36 +42,33 @@ describe('OrganizeFields Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [data]),
|
||||
expect: data => {
|
||||
const organized = data[0];
|
||||
expect(organized.fields).toEqual([
|
||||
{
|
||||
config: {},
|
||||
labels: undefined,
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
await expect(transformDataFrame([cfg], [data])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const organized = data[0];
|
||||
expect(organized.fields).toEqual([
|
||||
{
|
||||
config: {},
|
||||
labels: undefined,
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature',
|
||||
},
|
||||
{
|
||||
config: {
|
||||
displayName: 'renamed_humidity',
|
||||
},
|
||||
labels: undefined,
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'renamed_humidity',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
},
|
||||
{
|
||||
config: {
|
||||
displayName: 'renamed_humidity',
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
labels: undefined,
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'renamed_humidity',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -87,7 +83,7 @@ describe('OrganizeFields Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
it('should append fields missing in config at the end', done => {
|
||||
it('should append fields missing in config at the end', async () => {
|
||||
const cfg: DataTransformerConfig<OrganizeFieldsTransformerOptions> = {
|
||||
id: DataTransformerID.organize,
|
||||
options: {
|
||||
@@ -105,36 +101,33 @@ describe('OrganizeFields Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [data]),
|
||||
expect: data => {
|
||||
const organized = data[0];
|
||||
expect(organized.fields).toEqual([
|
||||
{
|
||||
labels: undefined,
|
||||
config: {
|
||||
displayName: 'renamed_time',
|
||||
},
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'renamed_time',
|
||||
},
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
await expect(transformDataFrame([cfg], [data])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const organized = data[0];
|
||||
expect(organized.fields).toEqual([
|
||||
{
|
||||
labels: undefined,
|
||||
config: {
|
||||
displayName: 'renamed_time',
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
labels: undefined,
|
||||
name: 'pressure',
|
||||
state: {
|
||||
displayName: 'pressure',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'renamed_time',
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
labels: undefined,
|
||||
name: 'pressure',
|
||||
state: {
|
||||
displayName: 'pressure',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -6,7 +6,6 @@ import { reduceFields, reduceTransformer } from './reduce';
|
||||
import { transformDataFrame } from '../transformDataFrame';
|
||||
import { Field, FieldType } from '../../types';
|
||||
import { ArrayVector } from '../../vector';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
import { notTimeFieldMatcher } from '../matchers/predicates';
|
||||
import { DataFrameView } from '../../dataframe';
|
||||
|
||||
@@ -49,7 +48,7 @@ describe('Reducer Transformer', () => {
|
||||
mockTransformationsRegistry([reduceTransformer]);
|
||||
});
|
||||
|
||||
it('reduces multiple data frames with many fields', done => {
|
||||
it('reduces multiple data frames with many fields', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.reduce,
|
||||
options: {
|
||||
@@ -57,9 +56,9 @@ describe('Reducer Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesAWithMultipleFields, seriesBWithMultipleFields]),
|
||||
expect: processed => {
|
||||
await expect(transformDataFrame([cfg], [seriesAWithMultipleFields, seriesBWithMultipleFields])).toEmitValuesWith(
|
||||
received => {
|
||||
const processed = received[0];
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'Field',
|
||||
@@ -96,12 +95,11 @@ describe('Reducer Transformer', () => {
|
||||
expect(processed.length).toEqual(1);
|
||||
expect(processed[0].length).toEqual(4);
|
||||
expect(processed[0].fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('reduces multiple data frames with single field', done => {
|
||||
it('reduces multiple data frames with single field', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.reduce,
|
||||
options: {
|
||||
@@ -109,9 +107,9 @@ describe('Reducer Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesAWithSingleField, seriesBWithSingleField]),
|
||||
expect: processed => {
|
||||
await expect(transformDataFrame([cfg], [seriesAWithSingleField, seriesBWithSingleField])).toEmitValuesWith(
|
||||
received => {
|
||||
const processed = received[0];
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'Field',
|
||||
@@ -148,12 +146,11 @@ describe('Reducer Transformer', () => {
|
||||
expect(processed.length).toEqual(1);
|
||||
expect(processed[0].length).toEqual(2);
|
||||
expect(processed[0].fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('reduces single data frame with many fields', done => {
|
||||
it('reduces single data frame with many fields', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.reduce,
|
||||
options: {
|
||||
@@ -161,51 +158,48 @@ describe('Reducer Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesAWithMultipleFields]),
|
||||
expect: processed => {
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'Field',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['A temperature', 'A humidity']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'First',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([3, 10000.3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Min',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([3, 10000.3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Max',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([6, 10000.6]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Last',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([6, 10000.6]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [seriesAWithMultipleFields])).toEmitValuesWith(received => {
|
||||
const processed = received[0];
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'Field',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['A temperature', 'A humidity']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'First',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([3, 10000.3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Min',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([3, 10000.3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Max',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([6, 10000.6]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Last',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([6, 10000.6]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
|
||||
expect(processed.length).toEqual(1);
|
||||
expect(processed[0].length).toEqual(2);
|
||||
expect(processed[0].fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(processed.length).toEqual(1);
|
||||
expect(processed[0].length).toEqual(2);
|
||||
expect(processed[0].fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('reduces single data frame with single field', done => {
|
||||
it('reduces single data frame with single field', async () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.reduce,
|
||||
options: {
|
||||
@@ -213,47 +207,44 @@ describe('Reducer Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesAWithSingleField]),
|
||||
expect: processed => {
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'Field',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['A temperature']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'First',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Min',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Max',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([6]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Last',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([6]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [seriesAWithSingleField])).toEmitValuesWith(received => {
|
||||
const processed = received[0];
|
||||
const expected: Field[] = [
|
||||
{
|
||||
name: 'Field',
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['A temperature']),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'First',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Min',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Max',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([6]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'Last',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([6]),
|
||||
config: {},
|
||||
},
|
||||
];
|
||||
|
||||
expect(processed.length).toEqual(1);
|
||||
expect(processed[0].length).toEqual(1);
|
||||
expect(processed[0].fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
expect(processed.length).toEqual(1);
|
||||
expect(processed[0].length).toEqual(1);
|
||||
expect(processed[0].fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -8,7 +8,6 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { renameFieldsTransformer, RenameFieldsTransformerOptions } from './rename';
|
||||
import { mockTransformationsRegistry } from '../../utils/tests/mockTransformationsRegistry';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
describe('Rename Transformer', () => {
|
||||
beforeAll(() => {
|
||||
@@ -25,62 +24,59 @@ describe('Rename Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
it('should rename according to config', done => {
|
||||
it('should rename according to config', async () => {
|
||||
const cfg: DataTransformerConfig<RenameFieldsTransformerOptions> = {
|
||||
id: DataTransformerID.rename,
|
||||
options: {
|
||||
renameByName: {
|
||||
time: 'Total time',
|
||||
humidity: 'Moistiness',
|
||||
humidity: 'Moistness',
|
||||
temperature: 'how cold is it?',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [data]),
|
||||
expect: data => {
|
||||
const renamed = data[0];
|
||||
expect(renamed.fields).toEqual([
|
||||
{
|
||||
config: {
|
||||
displayName: 'Total time',
|
||||
},
|
||||
labels: undefined,
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'Total time',
|
||||
},
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
await expect(transformDataFrame([cfg], [data])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const renamed = data[0];
|
||||
expect(renamed.fields).toEqual([
|
||||
{
|
||||
config: {
|
||||
displayName: 'Total time',
|
||||
},
|
||||
{
|
||||
config: {
|
||||
displayName: 'how cold is it?',
|
||||
},
|
||||
labels: undefined,
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'how cold is it?',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
labels: undefined,
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'Total time',
|
||||
},
|
||||
{
|
||||
config: {
|
||||
displayName: 'Moistiness',
|
||||
},
|
||||
name: 'humidity',
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'Moistiness',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
},
|
||||
{
|
||||
config: {
|
||||
displayName: 'how cold is it?',
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
labels: undefined,
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'how cold is it?',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
},
|
||||
{
|
||||
config: {
|
||||
displayName: 'Moistness',
|
||||
},
|
||||
name: 'humidity',
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'Moistness',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -95,7 +91,7 @@ describe('Rename Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
it('should not rename fields missing in config', done => {
|
||||
it('should not rename fields missing in config', async () => {
|
||||
const cfg: DataTransformerConfig<RenameFieldsTransformerOptions> = {
|
||||
id: DataTransformerID.rename,
|
||||
options: {
|
||||
@@ -107,48 +103,45 @@ describe('Rename Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [data]),
|
||||
expect: data => {
|
||||
const renamed = data[0];
|
||||
expect(renamed.fields).toEqual([
|
||||
{
|
||||
config: {
|
||||
displayName: 'ttl',
|
||||
},
|
||||
name: 'time',
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'ttl',
|
||||
},
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
await expect(transformDataFrame([cfg], [data])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const renamed = data[0];
|
||||
expect(renamed.fields).toEqual([
|
||||
{
|
||||
config: {
|
||||
displayName: 'ttl',
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
labels: undefined,
|
||||
name: 'pressure',
|
||||
state: {
|
||||
displayName: 'pressure',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
name: 'time',
|
||||
labels: undefined,
|
||||
state: {
|
||||
displayName: 'ttl',
|
||||
},
|
||||
{
|
||||
config: {
|
||||
displayName: 'hum',
|
||||
},
|
||||
labels: undefined,
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'hum',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
labels: undefined,
|
||||
name: 'pressure',
|
||||
state: {
|
||||
displayName: 'pressure',
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
},
|
||||
{
|
||||
config: {
|
||||
displayName: 'hum',
|
||||
},
|
||||
labels: undefined,
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'hum',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -163,7 +156,7 @@ describe('Rename Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
it('should keep the same names as in the incoming data', done => {
|
||||
it('should keep the same names as in the incoming data', async () => {
|
||||
const cfg: DataTransformerConfig<RenameFieldsTransformerOptions> = {
|
||||
id: DataTransformerID.rename,
|
||||
options: {
|
||||
@@ -171,32 +164,29 @@ describe('Rename Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [data]),
|
||||
expect: data => {
|
||||
const renamed = data[0];
|
||||
expect(renamed.fields).toEqual([
|
||||
{
|
||||
config: {},
|
||||
name: 'time',
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'pressure',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'humidity',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [data])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const renamed = data[0];
|
||||
expect(renamed.fields).toEqual([
|
||||
{
|
||||
config: {},
|
||||
name: 'time',
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000]),
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'pressure',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6]),
|
||||
},
|
||||
{
|
||||
config: {},
|
||||
name: 'humidity',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6]),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -9,7 +9,6 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { SeriesToColumnsOptions, seriesToColumnsTransformer } from './seriesToColumns';
|
||||
import { mockTransformationsRegistry } from '../../utils/tests/mockTransformationsRegistry';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
describe('SeriesToColumns Transformer', () => {
|
||||
beforeAll(() => {
|
||||
@@ -34,7 +33,7 @@ describe('SeriesToColumns Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
it('joins by time field', done => {
|
||||
it('joins by time field', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToColumnsOptions> = {
|
||||
id: DataTransformerID.seriesToColumns,
|
||||
options: {
|
||||
@@ -42,68 +41,65 @@ describe('SeriesToColumns Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [everySecondSeries, everyOtherSecondSeries]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields).toEqual([
|
||||
{
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'time',
|
||||
},
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([1000, 3000, 4000, 5000, 6000, 7000]),
|
||||
config: {},
|
||||
labels: undefined,
|
||||
await expect(transformDataFrame([cfg], [everySecondSeries, everyOtherSecondSeries])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields).toEqual([
|
||||
{
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'time',
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature even',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([null, 10.3, 10.4, 10.5, 10.6, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([1000, 3000, 4000, 5000, 6000, 7000]),
|
||||
config: {},
|
||||
labels: undefined,
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature even',
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity even',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([null, 10000.3, 10000.4, 10000.5, 10000.6, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([null, 10.3, 10.4, 10.5, 10.6, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity even',
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature odd',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([11.1, 11.3, null, 11.5, null, 11.7]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([null, 10000.3, 10000.4, 10000.5, 10000.6, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature odd',
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity odd',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([11000.1, 11000.3, null, 11000.5, null, 11000.7]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([11.1, 11.3, null, 11.5, null, 11.7]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity odd',
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([11000.1, 11000.3, null, 11000.5, null, 11000.7]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('joins by temperature field', done => {
|
||||
it('joins by temperature field', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToColumnsOptions> = {
|
||||
id: DataTransformerID.seriesToColumns,
|
||||
options: {
|
||||
@@ -111,68 +107,65 @@ describe('SeriesToColumns Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [everySecondSeries, everyOtherSecondSeries]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields).toEqual([
|
||||
{
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6, 11.1, 11.3, 11.5, 11.7]),
|
||||
config: {},
|
||||
labels: undefined,
|
||||
await expect(transformDataFrame([cfg], [everySecondSeries, everyOtherSecondSeries])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields).toEqual([
|
||||
{
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature',
|
||||
},
|
||||
{
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'time even',
|
||||
},
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000, null, null, null, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10.3, 10.4, 10.5, 10.6, 11.1, 11.3, 11.5, 11.7]),
|
||||
config: {},
|
||||
labels: undefined,
|
||||
},
|
||||
{
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'time even',
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity even',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6, null, null, null, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([3000, 4000, 5000, 6000, null, null, null, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity even',
|
||||
},
|
||||
{
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'time odd',
|
||||
},
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([null, null, null, null, 1000, 3000, 5000, 7000]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10000.3, 10000.4, 10000.5, 10000.6, null, null, null, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
},
|
||||
{
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'time odd',
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity odd',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([null, null, null, null, 11000.1, 11000.3, 11000.5, 11000.7]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([null, null, null, null, 1000, 3000, 5000, 7000]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity odd',
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([null, null, null, null, 11000.1, 11000.3, 11000.5, 11000.7]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('joins by time field in reverse order', done => {
|
||||
it('joins by time field in reverse order', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToColumnsOptions> = {
|
||||
id: DataTransformerID.seriesToColumns,
|
||||
options: {
|
||||
@@ -184,64 +177,61 @@ describe('SeriesToColumns Transformer', () => {
|
||||
everySecondSeries.fields[1].values = new ArrayVector(everySecondSeries.fields[1].values.toArray().reverse());
|
||||
everySecondSeries.fields[2].values = new ArrayVector(everySecondSeries.fields[2].values.toArray().reverse());
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [everySecondSeries, everyOtherSecondSeries]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields).toEqual([
|
||||
{
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'time',
|
||||
},
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([1000, 3000, 4000, 5000, 6000, 7000]),
|
||||
config: {},
|
||||
labels: undefined,
|
||||
await expect(transformDataFrame([cfg], [everySecondSeries, everyOtherSecondSeries])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields).toEqual([
|
||||
{
|
||||
name: 'time',
|
||||
state: {
|
||||
displayName: 'time',
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature even',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([null, 10.3, 10.4, 10.5, 10.6, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([1000, 3000, 4000, 5000, 6000, 7000]),
|
||||
config: {},
|
||||
labels: undefined,
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature even',
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity even',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([null, 10000.3, 10000.4, 10000.5, 10000.6, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([null, 10.3, 10.4, 10.5, 10.6, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity even',
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature odd',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([11.1, 11.3, null, 11.5, null, 11.7]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([null, 10000.3, 10000.4, 10000.5, 10000.6, null]),
|
||||
config: {},
|
||||
labels: { name: 'even' },
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: {
|
||||
displayName: 'temperature odd',
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity odd',
|
||||
},
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([11000.1, 11000.3, null, 11000.5, null, 11000.7]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([11.1, 11.3, null, 11.5, null, 11.7]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
},
|
||||
{
|
||||
name: 'humidity',
|
||||
state: {
|
||||
displayName: 'humidity odd',
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([11000.1, 11000.3, null, 11000.5, null, 11000.7]),
|
||||
config: {},
|
||||
labels: { name: 'odd' },
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -262,7 +252,7 @@ describe('SeriesToColumns Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
it('when dataframe and field share the same name then use the field name', done => {
|
||||
it('when dataframe and field share the same name then use the field name', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToColumnsOptions> = {
|
||||
id: DataTransformerID.seriesToColumns,
|
||||
options: {
|
||||
@@ -270,9 +260,9 @@ describe('SeriesToColumns Transformer', () => {
|
||||
},
|
||||
};
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesWithSameFieldAndDataFrameName, seriesB]),
|
||||
expect: data => {
|
||||
await expect(transformDataFrame([cfg], [seriesWithSameFieldAndDataFrameName, seriesB])).toEmitValuesWith(
|
||||
received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
const expected: Field[] = [
|
||||
{
|
||||
@@ -308,13 +298,12 @@ describe('SeriesToColumns Transformer', () => {
|
||||
];
|
||||
|
||||
expect(filtered.fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('joins if fields are missing', done => {
|
||||
it('joins if fields are missing', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToColumnsOptions> = {
|
||||
id: DataTransformerID.seriesToColumns,
|
||||
options: {
|
||||
@@ -343,41 +332,38 @@ describe('SeriesToColumns Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [frame1, frame2, frame3]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields).toEqual([
|
||||
{
|
||||
name: 'time',
|
||||
state: { displayName: 'time' },
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([1, 2, 3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: { displayName: 'temperature A' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10, 11, 12]),
|
||||
config: {},
|
||||
labels: { name: 'A' },
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: { displayName: 'temperature C' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([20, 22, 24]),
|
||||
config: {},
|
||||
labels: { name: 'C' },
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [frame1, frame2, frame3])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields).toEqual([
|
||||
{
|
||||
name: 'time',
|
||||
state: { displayName: 'time' },
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([1, 2, 3]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: { displayName: 'temperature A' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10, 11, 12]),
|
||||
config: {},
|
||||
labels: { name: 'A' },
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: { displayName: 'temperature C' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([20, 22, 24]),
|
||||
config: {},
|
||||
labels: { name: 'C' },
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles duplicate field name', done => {
|
||||
it('handles duplicate field name', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToColumnsOptions> = {
|
||||
id: DataTransformerID.seriesToColumns,
|
||||
options: {
|
||||
@@ -399,37 +385,34 @@ describe('SeriesToColumns Transformer', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [frame1, frame2]),
|
||||
expect: data => {
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields).toEqual([
|
||||
{
|
||||
name: 'time',
|
||||
state: { displayName: 'time' },
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([1]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: { displayName: 'temperature 1' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10]),
|
||||
config: {},
|
||||
labels: {},
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: { displayName: 'temperature 2' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([20]),
|
||||
config: {},
|
||||
labels: {},
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
await expect(transformDataFrame([cfg], [frame1, frame2])).toEmitValuesWith(received => {
|
||||
const data = received[0];
|
||||
const filtered = data[0];
|
||||
expect(filtered.fields).toEqual([
|
||||
{
|
||||
name: 'time',
|
||||
state: { displayName: 'time' },
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([1]),
|
||||
config: {},
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: { displayName: 'temperature 1' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([10]),
|
||||
config: {},
|
||||
labels: {},
|
||||
},
|
||||
{
|
||||
name: 'temperature',
|
||||
state: { displayName: 'temperature 2' },
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector([20]),
|
||||
config: {},
|
||||
labels: {},
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -5,14 +5,13 @@ import { toDataFrame } from '../../dataframe';
|
||||
import { transformDataFrame } from '../transformDataFrame';
|
||||
import { ArrayVector } from '../../vector';
|
||||
import { seriesToRowsTransformer, SeriesToRowsTransformerOptions } from './seriesToRows';
|
||||
import { observableTester } from '../../utils/tests/observableTester';
|
||||
|
||||
describe('Series to rows', () => {
|
||||
beforeAll(() => {
|
||||
mockTransformationsRegistry([seriesToRowsTransformer]);
|
||||
});
|
||||
|
||||
it('combine two series into one', done => {
|
||||
it('combine two series into one', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToRowsTransformerOptions> = {
|
||||
id: DataTransformerID.seriesToRows,
|
||||
options: {},
|
||||
@@ -34,22 +33,20 @@ describe('Series to rows', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesA, seriesB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [2000, 1000]),
|
||||
createField('Metric', FieldType.string, ['B', 'A']),
|
||||
createField('Value', FieldType.number, [-1, 1]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [seriesA, seriesB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [2000, 1000]),
|
||||
createField('Metric', FieldType.string, ['B', 'A']),
|
||||
createField('Value', FieldType.number, [-1, 1]),
|
||||
];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two series with multiple values into one', done => {
|
||||
it('combine two series with multiple values into one', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToRowsTransformerOptions> = {
|
||||
id: DataTransformerID.seriesToRows,
|
||||
options: {},
|
||||
@@ -71,22 +68,20 @@ describe('Series to rows', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesA, seriesB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [200, 150, 126, 125, 100, 100]),
|
||||
createField('Metric', FieldType.string, ['A', 'A', 'B', 'B', 'A', 'B']),
|
||||
createField('Value', FieldType.number, [5, 4, 3, 2, 1, -1]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [seriesA, seriesB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [200, 150, 126, 125, 100, 100]),
|
||||
createField('Metric', FieldType.string, ['A', 'A', 'B', 'B', 'A', 'B']),
|
||||
createField('Value', FieldType.number, [5, 4, 3, 2, 1, -1]),
|
||||
];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine three series into one', done => {
|
||||
it('combine three series into one', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToRowsTransformerOptions> = {
|
||||
id: DataTransformerID.seriesToRows,
|
||||
options: {},
|
||||
@@ -116,22 +111,20 @@ describe('Series to rows', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [seriesA, seriesB, seriesC]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [2000, 1000, 500]),
|
||||
createField('Metric', FieldType.string, ['B', 'A', 'C']),
|
||||
createField('Value', FieldType.number, [-1, 1, 2]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [seriesA, seriesB, seriesC])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [2000, 1000, 500]),
|
||||
createField('Metric', FieldType.string, ['B', 'A', 'C']),
|
||||
createField('Value', FieldType.number, [-1, 1, 2]),
|
||||
];
|
||||
|
||||
expect(unwrap(result[0].fields)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two time series, where first serie fields has displayName, into one', done => {
|
||||
it('combine two time series, where first serie fields has displayName, into one', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToRowsTransformerOptions> = {
|
||||
id: DataTransformerID.seriesToRows,
|
||||
options: {},
|
||||
@@ -153,25 +146,23 @@ describe('Series to rows', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [serieA, serieB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [200, 150, 126, 125, 100, 100]),
|
||||
createField('Metric', FieldType.string, ['A', 'A', 'B', 'B', 'A', 'B']),
|
||||
createField('Value', FieldType.number, [5, 4, 3, 2, 1, -1]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [serieA, serieB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
|
||||
const fields = unwrap(result[0].fields);
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [200, 150, 126, 125, 100, 100]),
|
||||
createField('Metric', FieldType.string, ['A', 'A', 'B', 'B', 'A', 'B']),
|
||||
createField('Value', FieldType.number, [5, 4, 3, 2, 1, -1]),
|
||||
];
|
||||
|
||||
expect(fields[2].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
const fields = unwrap(result[0].fields);
|
||||
|
||||
expect(fields[2].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two time series, where first serie fields has units, into one', done => {
|
||||
it('combine two time series, where first serie fields has units, into one', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToRowsTransformerOptions> = {
|
||||
id: DataTransformerID.seriesToRows,
|
||||
options: {},
|
||||
@@ -193,25 +184,23 @@ describe('Series to rows', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [serieA, serieB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [200, 150, 126, 125, 100, 100]),
|
||||
createField('Metric', FieldType.string, ['A', 'A', 'B', 'B', 'A', 'B']),
|
||||
createField('Value', FieldType.number, [5, 4, 3, 2, 1, -1], { units: 'celsius' }),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [serieA, serieB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
|
||||
const fields = unwrap(result[0].fields);
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [200, 150, 126, 125, 100, 100]),
|
||||
createField('Metric', FieldType.string, ['A', 'A', 'B', 'B', 'A', 'B']),
|
||||
createField('Value', FieldType.number, [5, 4, 3, 2, 1, -1], { units: 'celsius' }),
|
||||
];
|
||||
|
||||
expect(fields[2].config).toEqual({ units: 'celsius' });
|
||||
expect(fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
const fields = unwrap(result[0].fields);
|
||||
|
||||
expect(fields[2].config).toEqual({ units: 'celsius' });
|
||||
expect(fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('combine two time series, where second serie fields has units, into one', done => {
|
||||
it('combine two time series, where second serie fields has units, into one', async () => {
|
||||
const cfg: DataTransformerConfig<SeriesToRowsTransformerOptions> = {
|
||||
id: DataTransformerID.seriesToRows,
|
||||
options: {},
|
||||
@@ -233,21 +222,19 @@ describe('Series to rows', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: transformDataFrame([cfg], [serieA, serieB]),
|
||||
expect: result => {
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [200, 150, 126, 125, 100, 100]),
|
||||
createField('Metric', FieldType.string, ['A', 'A', 'B', 'B', 'A', 'B']),
|
||||
createField('Value', FieldType.number, [5, 4, 3, 2, 1, -1]),
|
||||
];
|
||||
await expect(transformDataFrame([cfg], [serieA, serieB])).toEmitValuesWith(received => {
|
||||
const result = received[0];
|
||||
|
||||
const fields = unwrap(result[0].fields);
|
||||
const expected: Field[] = [
|
||||
createField('Time', FieldType.time, [200, 150, 126, 125, 100, 100]),
|
||||
createField('Metric', FieldType.string, ['A', 'A', 'B', 'B', 'A', 'B']),
|
||||
createField('Value', FieldType.number, [5, 4, 3, 2, 1, -1]),
|
||||
];
|
||||
|
||||
expect(fields[2].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
},
|
||||
done,
|
||||
const fields = unwrap(result[0].fields);
|
||||
|
||||
expect(fields[2].config).toEqual({});
|
||||
expect(fields).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -7,5 +7,10 @@
|
||||
},
|
||||
"exclude": ["dist", "node_modules"],
|
||||
"extends": "@grafana/tsconfig",
|
||||
"include": ["src/**/*.ts*", "../../public/app/types/jquery/*.ts", "../../public/app/types/sanitize-url.d.ts"]
|
||||
"include": [
|
||||
"src/**/*.ts*",
|
||||
"typings/jest",
|
||||
"../../public/app/types/jquery/*.ts",
|
||||
"../../public/app/types/sanitize-url.d.ts"
|
||||
]
|
||||
}
|
||||
|
12
packages/grafana-data/typings/jest/index.d.ts
vendored
Normal file
12
packages/grafana-data/typings/jest/index.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
type ObservableType<T> = T extends Observable<infer V> ? V : never;
|
||||
|
||||
declare global {
|
||||
namespace jest {
|
||||
interface Matchers<R, T = {}> {
|
||||
toEmitValues<E = ObservableType<T>>(expected: E[]): Promise<CustomMatcherResult>;
|
||||
toEmitValuesWith<E = ObservableType<T>>(expectations: (received: E[]) => void): Promise<CustomMatcherResult>;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
import { FieldType, observableTester, toDataFrame } from '@grafana/data';
|
||||
import { FieldType, toDataFrame } from '@grafana/data';
|
||||
import { getAnnotationsFromData } from './standardAnnotationSupport';
|
||||
|
||||
describe('DataFrame to annotations', () => {
|
||||
test('simple conversion', done => {
|
||||
test('simple conversion', async () => {
|
||||
const frame = toDataFrame({
|
||||
fields: [
|
||||
{ type: FieldType.time, values: [1, 2, 3, 4, 5] },
|
||||
@@ -11,48 +11,44 @@ describe('DataFrame to annotations', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: getAnnotationsFromData([frame]),
|
||||
expect: events => {
|
||||
expect(events).toEqual([
|
||||
{
|
||||
color: 'red',
|
||||
tags: ['aaa', 'bbb'],
|
||||
text: 't1',
|
||||
time: 1,
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
tags: ['bbb', 'ccc'],
|
||||
text: 't2',
|
||||
time: 2,
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
tags: ['zyz'],
|
||||
text: 't3',
|
||||
time: 3,
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
time: 4,
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
time: 5,
|
||||
type: 'default',
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
});
|
||||
await expect(getAnnotationsFromData([frame])).toEmitValues([
|
||||
[
|
||||
{
|
||||
color: 'red',
|
||||
tags: ['aaa', 'bbb'],
|
||||
text: 't1',
|
||||
time: 1,
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
tags: ['bbb', 'ccc'],
|
||||
text: 't2',
|
||||
time: 2,
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
tags: ['zyz'],
|
||||
text: 't3',
|
||||
time: 3,
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
time: 4,
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
time: 5,
|
||||
type: 'default',
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
test('explicit mappins', done => {
|
||||
test('explicit mappins', async () => {
|
||||
const frame = toDataFrame({
|
||||
fields: [
|
||||
{ name: 'time1', values: [111, 222, 333] },
|
||||
@@ -62,42 +58,40 @@ describe('DataFrame to annotations', () => {
|
||||
],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext({
|
||||
observable: getAnnotationsFromData([frame], {
|
||||
text: { value: 'bbbbb' },
|
||||
time: { value: 'time2' },
|
||||
timeEnd: { value: 'time1' },
|
||||
title: { value: 'aaaaa' },
|
||||
}),
|
||||
expect: events => {
|
||||
expect(events).toEqual([
|
||||
{
|
||||
color: 'red',
|
||||
text: 'b1',
|
||||
time: 100,
|
||||
timeEnd: 111,
|
||||
title: 'a1',
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
text: 'b2',
|
||||
time: 200,
|
||||
timeEnd: 222,
|
||||
title: 'a2',
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
text: 'b3',
|
||||
time: 300,
|
||||
timeEnd: 333,
|
||||
title: 'a3',
|
||||
type: 'default',
|
||||
},
|
||||
]);
|
||||
},
|
||||
done,
|
||||
const observable = getAnnotationsFromData([frame], {
|
||||
text: { value: 'bbbbb' },
|
||||
time: { value: 'time2' },
|
||||
timeEnd: { value: 'time1' },
|
||||
title: { value: 'aaaaa' },
|
||||
});
|
||||
|
||||
await expect(observable).toEmitValues([
|
||||
[
|
||||
{
|
||||
color: 'red',
|
||||
text: 'b1',
|
||||
time: 100,
|
||||
timeEnd: 111,
|
||||
title: 'a1',
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
text: 'b2',
|
||||
time: 200,
|
||||
timeEnd: 222,
|
||||
title: 'a2',
|
||||
type: 'default',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
text: 'b3',
|
||||
time: 300,
|
||||
timeEnd: 333,
|
||||
title: 'a3',
|
||||
type: 'default',
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@@ -1,16 +1,7 @@
|
||||
import { of, Subject } from 'rxjs';
|
||||
import { first, last, take } from 'rxjs/operators';
|
||||
import { of, throwError } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { omit } from 'lodash';
|
||||
import {
|
||||
AnnotationQueryRequest,
|
||||
CoreApp,
|
||||
DataFrame,
|
||||
DataQueryResponse,
|
||||
dateTime,
|
||||
FieldCache,
|
||||
observableTester,
|
||||
TimeRange,
|
||||
} from '@grafana/data';
|
||||
import { AnnotationQueryRequest, CoreApp, DataFrame, dateTime, FieldCache, TimeRange } from '@grafana/data';
|
||||
import { BackendSrvRequest, FetchResponse } from '@grafana/runtime';
|
||||
|
||||
import LokiDatasource from './datasource';
|
||||
@@ -20,7 +11,6 @@ import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { CustomVariableModel } from '../../../features/variables/types';
|
||||
import { initialCustomVariableModelState } from '../../../features/variables/custom/reducer';
|
||||
import { expect } from '../../../../test/lib/common';
|
||||
import { makeMockLokiDatasource } from './mocks';
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
@@ -60,13 +50,11 @@ const testResponse: FetchResponse<LokiResponse> = {
|
||||
};
|
||||
|
||||
describe('LokiDatasource', () => {
|
||||
let fetchStream: Subject<FetchResponse>;
|
||||
const fetchMock = jest.spyOn(backendSrv, 'fetch');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
fetchStream = new Subject<FetchResponse>();
|
||||
fetchMock.mockImplementation(() => fetchStream.asObservable());
|
||||
fetchMock.mockImplementation(() => of(createFetchResponse({})));
|
||||
});
|
||||
|
||||
describe('when creating range query', () => {
|
||||
@@ -109,12 +97,11 @@ describe('LokiDatasource', () => {
|
||||
});
|
||||
|
||||
describe('when querying with limits', () => {
|
||||
const runLimitTest = ({
|
||||
const runLimitTest = async ({
|
||||
maxDataPoints = 123,
|
||||
queryMaxLines,
|
||||
dsMaxLines = 456,
|
||||
expectedLimit,
|
||||
done,
|
||||
expr = '{label="val"}',
|
||||
}: any) => {
|
||||
let settings: any = {
|
||||
@@ -134,46 +121,32 @@ describe('LokiDatasource', () => {
|
||||
const options = getQueryOptions<LokiQuery>({ targets: [{ expr, refId: 'B', maxLines: queryMaxLines }] });
|
||||
options.maxDataPoints = maxDataPoints;
|
||||
|
||||
observableTester().subscribeAndExpectOnComplete<DataQueryResponse>({
|
||||
observable: ds.query(options).pipe(take(1)),
|
||||
expect: () => {
|
||||
expect(fetchMock.mock.calls.length).toBe(1);
|
||||
expect(fetchMock.mock.calls[0][0].url).toContain(`limit=${expectedLimit}`);
|
||||
},
|
||||
done,
|
||||
});
|
||||
fetchMock.mockImplementation(() => of(testResponse));
|
||||
|
||||
fetchStream.next(testResponse);
|
||||
await expect(ds.query(options).pipe(take(1))).toEmitValuesWith(() => {
|
||||
expect(fetchMock.mock.calls.length).toBe(1);
|
||||
expect(fetchMock.mock.calls[0][0].url).toContain(`limit=${expectedLimit}`);
|
||||
});
|
||||
};
|
||||
|
||||
it('should use datasource max lines when no limit given and it is log query', done => {
|
||||
runLimitTest({
|
||||
expectedLimit: 456,
|
||||
done,
|
||||
});
|
||||
it('should use datasource max lines when no limit given and it is log query', async () => {
|
||||
await runLimitTest({ expectedLimit: 456 });
|
||||
});
|
||||
|
||||
it('should use custom max lines from query if set and it is logs query', done => {
|
||||
runLimitTest({
|
||||
queryMaxLines: 20,
|
||||
expectedLimit: 20,
|
||||
done,
|
||||
});
|
||||
it('should use custom max lines from query if set and it is logs query', async () => {
|
||||
await runLimitTest({ queryMaxLines: 20, expectedLimit: 20 });
|
||||
});
|
||||
|
||||
it('should use custom max lines from query if set and it is logs query even if it is higher than data source limit', done => {
|
||||
runLimitTest({
|
||||
queryMaxLines: 500,
|
||||
expectedLimit: 500,
|
||||
done,
|
||||
});
|
||||
it('should use custom max lines from query if set and it is logs query even if it is higher than data source limit', async () => {
|
||||
await runLimitTest({ queryMaxLines: 500, expectedLimit: 500 });
|
||||
});
|
||||
|
||||
it('should use maxDataPoints if it is metrics query', () => {
|
||||
runLimitTest({
|
||||
expr: 'rate({label="val"}[10m])',
|
||||
expectedLimit: 123,
|
||||
});
|
||||
it('should use maxDataPoints if it is metrics query', async () => {
|
||||
await runLimitTest({ expr: 'rate({label="val"}[10m])', expectedLimit: 123 });
|
||||
});
|
||||
|
||||
it('should use maxDataPoints if it is metrics query and using search', async () => {
|
||||
await runLimitTest({ expr: 'rate({label="val"}[10m])', expectedLimit: 123 });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -210,84 +183,76 @@ describe('LokiDatasource', () => {
|
||||
expect(ds.runRangeQuery).toBeCalled();
|
||||
});
|
||||
|
||||
it('should return series data for both queries in Explore if metrics query', done => {
|
||||
it('should return series data for both queries in Explore if metrics query', async () => {
|
||||
const ds = createLokiDSForTests();
|
||||
const options = getQueryOptions<LokiQuery>({
|
||||
targets: [{ expr: 'rate({job="grafana"} |= "foo" [10m])', refId: 'B' }],
|
||||
app: CoreApp.Explore,
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext<DataQueryResponse>({
|
||||
observable: ds.query(options).pipe(first()), // first result always comes from runInstantQuery
|
||||
expect: res => {
|
||||
expect(res).toEqual({
|
||||
data: [],
|
||||
key: 'B_instant',
|
||||
});
|
||||
},
|
||||
done,
|
||||
});
|
||||
fetchMock
|
||||
.mockImplementationOnce(() => of(testResponse))
|
||||
.mockImplementation(() => of(omit(testResponse, 'data.status')));
|
||||
|
||||
observableTester().subscribeAndExpectOnNext<DataQueryResponse>({
|
||||
observable: ds.query(options).pipe(last()), // last result always comes from runRangeQuery
|
||||
expect: res => {
|
||||
const dataFrame = res.data[0] as DataFrame;
|
||||
const fieldCache = new FieldCache(dataFrame);
|
||||
expect(fieldCache.getFieldByName('line')?.values.get(0)).toBe('hello');
|
||||
expect(dataFrame.meta?.limit).toBe(20);
|
||||
expect(dataFrame.meta?.searchWords).toEqual(['foo']);
|
||||
},
|
||||
done,
|
||||
});
|
||||
await expect(ds.query(options)).toEmitValuesWith(received => {
|
||||
// first result always comes from runInstantQuery
|
||||
const firstResult = received[0];
|
||||
expect(firstResult).toEqual({ data: [], key: 'B_instant' });
|
||||
|
||||
fetchStream.next(testResponse);
|
||||
fetchStream.next(omit(testResponse, 'data.status'));
|
||||
// second result always comes from runRangeQuery
|
||||
const secondResult = received[1];
|
||||
const dataFrame = secondResult.data[0] as DataFrame;
|
||||
const fieldCache = new FieldCache(dataFrame);
|
||||
|
||||
expect(fieldCache.getFieldByName('line')?.values.get(0)).toBe('hello');
|
||||
expect(dataFrame.meta?.limit).toBe(500);
|
||||
expect(dataFrame.meta?.searchWords).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return series data for range query in Dashboard', done => {
|
||||
it('should return series data for range query in Dashboard', async () => {
|
||||
const ds = createLokiDSForTests();
|
||||
const options = getQueryOptions<LokiQuery>({
|
||||
targets: [{ expr: '{job="grafana"} |= "foo"', refId: 'B' }],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnNext<DataQueryResponse>({
|
||||
observable: ds.query(options).pipe(first()), // first result will come from runRangeQuery
|
||||
expect: res => {
|
||||
const dataFrame = res.data[0] as DataFrame;
|
||||
const fieldCache = new FieldCache(dataFrame);
|
||||
expect(fieldCache.getFieldByName('line')?.values.get(0)).toBe('hello');
|
||||
expect(dataFrame.meta?.limit).toBe(20);
|
||||
expect(dataFrame.meta?.searchWords).toEqual(['foo']);
|
||||
},
|
||||
done,
|
||||
});
|
||||
fetchMock
|
||||
.mockImplementationOnce(() => of(testResponse))
|
||||
.mockImplementation(() => of(omit(testResponse, 'data.status')));
|
||||
|
||||
fetchStream.next(testResponse);
|
||||
fetchStream.next(omit(testResponse, 'data.status'));
|
||||
await expect(ds.query(options)).toEmitValuesWith(received => {
|
||||
// first result will come from runRangeQuery
|
||||
const firstResult = received[0];
|
||||
const dataFrame = firstResult.data[0] as DataFrame;
|
||||
const fieldCache = new FieldCache(dataFrame);
|
||||
|
||||
expect(fieldCache.getFieldByName('line')?.values.get(0)).toBe('hello');
|
||||
expect(dataFrame.meta?.limit).toBe(20);
|
||||
expect(dataFrame.meta?.searchWords).toEqual(['foo']);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return custom error message when Loki returns escaping error', done => {
|
||||
it('should return custom error message when Loki returns escaping error', async () => {
|
||||
const ds = createLokiDSForTests();
|
||||
const options = getQueryOptions<LokiQuery>({
|
||||
targets: [{ expr: '{job="gra\\fana"}', refId: 'B' }],
|
||||
});
|
||||
|
||||
observableTester().subscribeAndExpectOnError<DataQueryResponse>({
|
||||
observable: ds.query(options),
|
||||
expect: err => {
|
||||
expect(err.data.message).toBe(
|
||||
'Error: parse error at line 1, col 6: invalid char escape. Make sure that all special characters are escaped with \\. For more information on escaping of special characters visit LogQL documentation at https://grafana.com/docs/loki/latest/logql/.'
|
||||
);
|
||||
},
|
||||
done,
|
||||
});
|
||||
fetchMock.mockImplementation(() =>
|
||||
throwError({
|
||||
data: {
|
||||
message: 'parse error at line 1, col 6: invalid char escape',
|
||||
},
|
||||
status: 400,
|
||||
statusText: 'Bad Request',
|
||||
})
|
||||
);
|
||||
|
||||
fetchStream.error({
|
||||
data: {
|
||||
message: 'parse error at line 1, col 6: invalid char escape',
|
||||
},
|
||||
status: 400,
|
||||
statusText: 'Bad Request',
|
||||
await expect(ds.query(options)).toEmitValuesWith(received => {
|
||||
const err: any = received[0];
|
||||
expect(err.data.message).toBe(
|
||||
'Error: parse error at line 1, col 6: invalid char escape. Make sure that all special characters are escaped with \\. For more information on escaping of special characters visit LogQL documentation at https://grafana.com/docs/loki/latest/logql/.'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -339,27 +304,12 @@ describe('LokiDatasource', () => {
|
||||
});
|
||||
|
||||
describe('when performing testDataSource', () => {
|
||||
const getTestContext = () => {
|
||||
const ds = createLokiDSForTests({} as TemplateSrv);
|
||||
const promise = ds.testDatasource();
|
||||
|
||||
return { promise };
|
||||
};
|
||||
|
||||
describe('and call succeeds', () => {
|
||||
it('should return successfully', async () => {
|
||||
const { promise } = getTestContext();
|
||||
fetchMock.mockImplementation(() => of(createFetchResponse({ values: ['avalue'] })));
|
||||
const ds = createLokiDSForTests({} as TemplateSrv);
|
||||
|
||||
fetchStream.next(({
|
||||
status: 200,
|
||||
data: {
|
||||
values: ['avalue'],
|
||||
},
|
||||
} as unknown) as FetchResponse);
|
||||
|
||||
fetchStream.complete();
|
||||
|
||||
const result = await promise;
|
||||
const result = await ds.testDatasource();
|
||||
|
||||
expect(result.status).toBe('success');
|
||||
});
|
||||
@@ -367,17 +317,18 @@ describe('LokiDatasource', () => {
|
||||
|
||||
describe('and call fails with 401 error', () => {
|
||||
it('should return error status and a detailed error message', async () => {
|
||||
const { promise } = getTestContext();
|
||||
fetchMock.mockImplementation(() =>
|
||||
throwError({
|
||||
statusText: 'Unauthorized',
|
||||
status: 401,
|
||||
data: {
|
||||
message: 'Unauthorized',
|
||||
},
|
||||
})
|
||||
);
|
||||
const ds = createLokiDSForTests({} as TemplateSrv);
|
||||
|
||||
fetchStream.error({
|
||||
statusText: 'Unauthorized',
|
||||
status: 401,
|
||||
data: {
|
||||
message: 'Unauthorized',
|
||||
},
|
||||
});
|
||||
|
||||
const result = await promise;
|
||||
const result = await ds.testDatasource();
|
||||
|
||||
expect(result.status).toEqual('error');
|
||||
expect(result.message).toBe('Loki: Unauthorized. 401. Unauthorized');
|
||||
@@ -386,17 +337,19 @@ describe('LokiDatasource', () => {
|
||||
|
||||
describe('and call fails with 404 error', () => {
|
||||
it('should return error status and a detailed error message', async () => {
|
||||
const { promise } = getTestContext();
|
||||
fetchMock.mockImplementation(() =>
|
||||
throwError({
|
||||
statusText: 'Not found',
|
||||
status: 404,
|
||||
data: {
|
||||
message: '404 page not found',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
fetchStream.error({
|
||||
statusText: 'Not found',
|
||||
status: 404,
|
||||
data: {
|
||||
message: '404 page not found',
|
||||
},
|
||||
});
|
||||
const ds = createLokiDSForTests({} as TemplateSrv);
|
||||
|
||||
const result = await promise;
|
||||
const result = await ds.testDatasource();
|
||||
|
||||
expect(result.status).toEqual('error');
|
||||
expect(result.message).toBe('Loki: Not found. 404. 404 page not found');
|
||||
@@ -405,15 +358,17 @@ describe('LokiDatasource', () => {
|
||||
|
||||
describe('and call fails with 502 error', () => {
|
||||
it('should return error status and a detailed error message', async () => {
|
||||
const { promise } = getTestContext();
|
||||
fetchMock.mockImplementation(() =>
|
||||
throwError({
|
||||
statusText: 'Bad Gateway',
|
||||
status: 502,
|
||||
data: '',
|
||||
})
|
||||
);
|
||||
|
||||
fetchStream.error({
|
||||
statusText: 'Bad Gateway',
|
||||
status: 502,
|
||||
data: '',
|
||||
});
|
||||
const ds = createLokiDSForTests({} as TemplateSrv);
|
||||
|
||||
const result = await promise;
|
||||
const result = await ds.testDatasource();
|
||||
|
||||
expect(result.status).toEqual('error');
|
||||
expect(result.message).toBe('Loki: Bad Gateway. 502');
|
||||
@@ -440,8 +395,10 @@ describe('LokiDatasource', () => {
|
||||
});
|
||||
|
||||
describe('when calling annotationQuery', () => {
|
||||
const getTestContext = () => {
|
||||
const getTestContext = (response: any) => {
|
||||
const query = makeAnnotationQueryRequest();
|
||||
fetchMock.mockImplementation(() => of(response));
|
||||
|
||||
const ds = createLokiDSForTests();
|
||||
const promise = ds.annotationQuery(query);
|
||||
|
||||
@@ -449,7 +406,6 @@ describe('LokiDatasource', () => {
|
||||
};
|
||||
|
||||
it('should transform the loki data to annotation response', async () => {
|
||||
const { promise } = getTestContext();
|
||||
const response: FetchResponse = ({
|
||||
data: {
|
||||
data: {
|
||||
@@ -473,9 +429,7 @@ describe('LokiDatasource', () => {
|
||||
status: 'success',
|
||||
},
|
||||
} as unknown) as FetchResponse;
|
||||
|
||||
fetchStream.next(response);
|
||||
fetchStream.complete();
|
||||
const { promise } = getTestContext(response);
|
||||
|
||||
const res = await promise;
|
||||
|
||||
@@ -590,3 +544,17 @@ function makeMetadataAndVersionsMocks() {
|
||||
}
|
||||
return mocks;
|
||||
}
|
||||
|
||||
function createFetchResponse<T>(data: T): FetchResponse<T> {
|
||||
return {
|
||||
data,
|
||||
status: 200,
|
||||
url: 'http://localhost:3000/api/query',
|
||||
config: { url: 'http://localhost:3000/api/query' },
|
||||
type: 'basic',
|
||||
statusText: 'Ok',
|
||||
redirected: false,
|
||||
headers: ({} as unknown) as Headers,
|
||||
ok: true,
|
||||
};
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { of } from 'rxjs';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
import { FetchResponse } from '@grafana/runtime';
|
||||
import { dateTime, observableTester, toUtc } from '@grafana/data';
|
||||
import { dateTime, toUtc } from '@grafana/data';
|
||||
|
||||
import { PostgresDatasource } from '../datasource';
|
||||
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
||||
@@ -207,7 +207,7 @@ describe('PostgreSQLDatasource', () => {
|
||||
});
|
||||
|
||||
describe('When performing a query with hidden target', () => {
|
||||
it('should return empty result and backendSrv.fetch should not be called', done => {
|
||||
it('should return empty result and backendSrv.fetch should not be called', async () => {
|
||||
const options = {
|
||||
range: {
|
||||
from: dateTime(1432288354),
|
||||
@@ -227,15 +227,9 @@ describe('PostgreSQLDatasource', () => {
|
||||
|
||||
const { ds } = setupTestContext({});
|
||||
|
||||
observableTester().subscribeAndExpectOnNextAndComplete({
|
||||
observable: ds.query(options),
|
||||
expectOnNext: value => {
|
||||
expect(value).toEqual({ data: [] });
|
||||
},
|
||||
expectOnComplete: () => {
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
},
|
||||
done,
|
||||
await expect(ds.query(options)).toEmitValuesWith(received => {
|
||||
expect(received[0]).toEqual({ data: [] });
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
9
public/test/matchers/index.ts
Normal file
9
public/test/matchers/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { ObservableMatchers } from './types';
|
||||
import { toEmitValues } from './toEmitValues';
|
||||
import { toEmitValuesWith } from './toEmitValuesWith';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export const matchers: ObservableMatchers<void, Observable<any>> = {
|
||||
toEmitValues,
|
||||
toEmitValuesWith,
|
||||
};
|
139
public/test/matchers/toEmitValues.test.ts
Normal file
139
public/test/matchers/toEmitValues.test.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { interval, Observable, of, throwError } from 'rxjs';
|
||||
import { map, mergeMap, take } from 'rxjs/operators';
|
||||
import { OBSERVABLE_TEST_TIMEOUT_IN_MS } from './types';
|
||||
|
||||
describe('toEmitValues matcher', () => {
|
||||
describe('failing tests', () => {
|
||||
describe('passing null in expect', () => {
|
||||
it('should fail', async () => {
|
||||
const observable = (null as unknown) as Observable<number>;
|
||||
|
||||
const rejects = expect(() => expect(observable).toEmitValues([1, 2, 3])).rejects;
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('passing undefined in expect', () => {
|
||||
it('should fail', async () => {
|
||||
const observable = (undefined as unknown) as Observable<number>;
|
||||
|
||||
const rejects = expect(() => expect(observable).toEmitValues([1, 2, 3])).rejects;
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('passing number instead of Observable in expect', () => {
|
||||
it('should fail', async () => {
|
||||
const observable = (1 as unknown) as Observable<number>;
|
||||
|
||||
const rejects = expect(() => expect(observable).toEmitValues([1, 2, 3])).rejects;
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('wrong number of emitted values', () => {
|
||||
it('should fail', async () => {
|
||||
const observable = interval(10).pipe(take(3));
|
||||
|
||||
const rejects = expect(() => expect(observable).toEmitValues([0, 1])).rejects;
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('wrong emitted values', () => {
|
||||
it('should fail', async () => {
|
||||
const observable = interval(10).pipe(take(3));
|
||||
|
||||
const rejects = expect(() => expect(observable).toEmitValues([1, 2, 3])).rejects;
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('wrong emitted value types', () => {
|
||||
it('should fail', async () => {
|
||||
const observable = (interval(10).pipe(take(3)) as unknown) as Observable<string>;
|
||||
|
||||
const rejects = expect(() => expect(observable).toEmitValues(['0', '1', '2'])).rejects;
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe(`observable that does not complete within ${OBSERVABLE_TEST_TIMEOUT_IN_MS}ms`, () => {
|
||||
it('should fail', async () => {
|
||||
const observable = interval(600);
|
||||
|
||||
const rejects = expect(() => expect(observable).toEmitValues([0])).rejects;
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('passing tests', () => {
|
||||
describe('correct emitted values', () => {
|
||||
it('should pass with correct message', async () => {
|
||||
const observable = interval(10).pipe(take(3));
|
||||
await expect(observable).toEmitValues([0, 1, 2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('using nested arrays', () => {
|
||||
it('should pass with correct message', async () => {
|
||||
const observable = interval(10).pipe(
|
||||
map(interval => [{ text: interval.toString(), value: interval }]),
|
||||
take(3)
|
||||
);
|
||||
await expect(observable).toEmitValues([
|
||||
[{ text: '0', value: 0 }],
|
||||
[{ text: '1', value: 1 }],
|
||||
[{ text: '2', value: 2 }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('using nested objects', () => {
|
||||
it('should pass with correct message', async () => {
|
||||
const observable = interval(10).pipe(
|
||||
map(interval => ({ inner: { text: interval.toString(), value: interval } })),
|
||||
take(3)
|
||||
);
|
||||
await expect(observable).toEmitValues([
|
||||
{ inner: { text: '0', value: 0 } },
|
||||
{ inner: { text: '1', value: 1 } },
|
||||
{ inner: { text: '2', value: 2 } },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('correct emitted values with throw', () => {
|
||||
it('should pass with correct message', async () => {
|
||||
const observable = (interval(10).pipe(
|
||||
map(interval => {
|
||||
if (interval > 1) {
|
||||
throw 'an error';
|
||||
}
|
||||
|
||||
return interval;
|
||||
})
|
||||
) as unknown) as Observable<string | number>;
|
||||
|
||||
await expect(observable).toEmitValues([0, 1, 'an error']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('correct emitted values with throwError', () => {
|
||||
it('should pass with correct message', async () => {
|
||||
const observable = (interval(10).pipe(
|
||||
mergeMap(interval => {
|
||||
if (interval === 1) {
|
||||
return throwError('an error');
|
||||
}
|
||||
|
||||
return of(interval);
|
||||
})
|
||||
) as unknown) as Observable<string | number>;
|
||||
|
||||
await expect(observable).toEmitValues([0, 'an error']);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
88
public/test/matchers/toEmitValues.ts
Normal file
88
public/test/matchers/toEmitValues.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { matcherHint, printExpected, printReceived } from 'jest-matcher-utils';
|
||||
import { expectObservable, forceObservableCompletion } from './utils';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
|
||||
function passMessage(received: any[], expected: any[]) {
|
||||
return `${matcherHint('.not.toEmitValues')}
|
||||
|
||||
Expected observable to emit values:
|
||||
${printExpected(expected)}
|
||||
Received:
|
||||
${printReceived(received)}
|
||||
`;
|
||||
}
|
||||
|
||||
function failMessage(received: any[], expected: any[]) {
|
||||
return `${matcherHint('.toEmitValues')}
|
||||
|
||||
Expected observable to emit values:
|
||||
${printExpected(expected)}
|
||||
Received:
|
||||
${printReceived(received)}
|
||||
`;
|
||||
}
|
||||
|
||||
function tryExpectations(received: any[], expected: any[]): jest.CustomMatcherResult {
|
||||
try {
|
||||
if (received.length !== expected.length) {
|
||||
return {
|
||||
pass: false,
|
||||
message: () => failMessage(received, expected),
|
||||
};
|
||||
}
|
||||
|
||||
for (let index = 0; index < received.length; index++) {
|
||||
const left = received[index];
|
||||
const right = expected[index];
|
||||
|
||||
if (!isEqual(left, right)) {
|
||||
return {
|
||||
pass: false,
|
||||
message: () => failMessage(received, expected),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
pass: true,
|
||||
message: () => passMessage(received, expected),
|
||||
};
|
||||
} catch (err) {
|
||||
return {
|
||||
pass: false,
|
||||
message: () => err,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function toEmitValues(received: Observable<any>, expected: any[]): Promise<jest.CustomMatcherResult> {
|
||||
const failsChecks = expectObservable(received);
|
||||
if (failsChecks) {
|
||||
return Promise.resolve(failsChecks);
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
const receivedValues: any[] = [];
|
||||
const subscription = new Subscription();
|
||||
|
||||
subscription.add(
|
||||
received.subscribe({
|
||||
next: value => {
|
||||
receivedValues.push(value);
|
||||
},
|
||||
error: err => {
|
||||
receivedValues.push(err);
|
||||
subscription.unsubscribe();
|
||||
resolve(tryExpectations(receivedValues, expected));
|
||||
},
|
||||
complete: () => {
|
||||
subscription.unsubscribe();
|
||||
resolve(tryExpectations(receivedValues, expected));
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
forceObservableCompletion(subscription, resolve);
|
||||
});
|
||||
}
|
153
public/test/matchers/toEmitValuesWith.test.ts
Normal file
153
public/test/matchers/toEmitValuesWith.test.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { interval, Observable, of, throwError } from 'rxjs';
|
||||
import { map, mergeMap, take } from 'rxjs/operators';
|
||||
|
||||
import { OBSERVABLE_TEST_TIMEOUT_IN_MS } from './types';
|
||||
|
||||
describe('toEmitValuesWith matcher', () => {
|
||||
describe('failing tests', () => {
|
||||
describe('passing null in expect', () => {
|
||||
it('should fail with correct message', async () => {
|
||||
const observable = (null as unknown) as Observable<number>;
|
||||
|
||||
const rejects = expect(() =>
|
||||
expect(observable).toEmitValuesWith(received => {
|
||||
expect(received).toEqual([1, 2, 3]);
|
||||
})
|
||||
).rejects;
|
||||
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('passing undefined in expect', () => {
|
||||
it('should fail with correct message', async () => {
|
||||
const observable = (undefined as unknown) as Observable<number>;
|
||||
|
||||
const rejects = expect(() =>
|
||||
expect(observable).toEmitValuesWith(received => {
|
||||
expect(received).toEqual([1, 2, 3]);
|
||||
})
|
||||
).rejects;
|
||||
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('passing number instead of Observable in expect', () => {
|
||||
it('should fail with correct message', async () => {
|
||||
const observable = (1 as unknown) as Observable<number>;
|
||||
|
||||
const rejects = expect(() =>
|
||||
expect(observable).toEmitValuesWith(received => {
|
||||
expect(received).toEqual([1, 2, 3]);
|
||||
})
|
||||
).rejects;
|
||||
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('wrong number of emitted values', () => {
|
||||
it('should fail with correct message', async () => {
|
||||
const observable = interval(10).pipe(take(3));
|
||||
|
||||
const rejects = expect(() =>
|
||||
expect(observable).toEmitValuesWith(received => {
|
||||
expect(received).toEqual([0, 1]);
|
||||
})
|
||||
).rejects;
|
||||
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('wrong emitted values', () => {
|
||||
it('should fail with correct message', async () => {
|
||||
const observable = interval(10).pipe(take(3));
|
||||
|
||||
const rejects = expect(() =>
|
||||
expect(observable).toEmitValuesWith(received => {
|
||||
expect(received).toEqual([1, 2, 3]);
|
||||
})
|
||||
).rejects;
|
||||
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('wrong emitted value types', () => {
|
||||
it('should fail with correct message', async () => {
|
||||
const observable = (interval(10).pipe(take(3)) as unknown) as Observable<string>;
|
||||
|
||||
const rejects = expect(() =>
|
||||
expect(observable).toEmitValuesWith(received => {
|
||||
expect(received).toEqual(['0', '1', '2']);
|
||||
})
|
||||
).rejects;
|
||||
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe(`observable that does not complete within ${OBSERVABLE_TEST_TIMEOUT_IN_MS}ms`, () => {
|
||||
it('should fail with correct message', async () => {
|
||||
const observable = interval(600);
|
||||
|
||||
const rejects = expect(() =>
|
||||
expect(observable).toEmitValuesWith(received => {
|
||||
expect(received).toEqual([0]);
|
||||
})
|
||||
).rejects;
|
||||
|
||||
await rejects.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('passing tests', () => {
|
||||
describe('correct emitted values', () => {
|
||||
it('should pass with correct message', async () => {
|
||||
const observable = interval(10).pipe(take(3));
|
||||
await expect(observable).toEmitValuesWith(received => {
|
||||
expect(received).toEqual([0, 1, 2]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('correct emitted values with throw', () => {
|
||||
it('should pass with correct message', async () => {
|
||||
const observable = interval(10).pipe(
|
||||
map(interval => {
|
||||
if (interval > 1) {
|
||||
throw 'an error';
|
||||
}
|
||||
|
||||
return interval;
|
||||
})
|
||||
);
|
||||
|
||||
await expect(observable).toEmitValuesWith(received => {
|
||||
expect(received).toEqual([0, 1, 'an error']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('correct emitted values with throwError', () => {
|
||||
it('should pass with correct message', async () => {
|
||||
const observable = interval(10).pipe(
|
||||
mergeMap(interval => {
|
||||
if (interval === 1) {
|
||||
return throwError('an error');
|
||||
}
|
||||
|
||||
return of(interval);
|
||||
})
|
||||
);
|
||||
|
||||
await expect(observable).toEmitValuesWith(received => {
|
||||
expect(received).toEqual([0, 'an error']);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
56
public/test/matchers/toEmitValuesWith.ts
Normal file
56
public/test/matchers/toEmitValuesWith.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { expectObservable, forceObservableCompletion } from './utils';
|
||||
import { matcherHint, printReceived } from 'jest-matcher-utils';
|
||||
|
||||
function tryExpectations(received: any[], expectations: (received: any[]) => void): jest.CustomMatcherResult {
|
||||
try {
|
||||
expectations(received);
|
||||
return {
|
||||
pass: true,
|
||||
message: () => `${matcherHint('.not.toEmitValues')}
|
||||
|
||||
Expected observable to complete with
|
||||
${printReceived(received)}
|
||||
`,
|
||||
};
|
||||
} catch (err) {
|
||||
return {
|
||||
pass: false,
|
||||
message: () => 'failed ' + err,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function toEmitValuesWith(
|
||||
received: Observable<any>,
|
||||
expectations: (actual: any[]) => void
|
||||
): Promise<jest.CustomMatcherResult> {
|
||||
const failsChecks = expectObservable(received);
|
||||
if (failsChecks) {
|
||||
return Promise.resolve(failsChecks);
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
const receivedValues: any[] = [];
|
||||
const subscription = new Subscription();
|
||||
|
||||
subscription.add(
|
||||
received.subscribe({
|
||||
next: value => {
|
||||
receivedValues.push(value);
|
||||
},
|
||||
error: err => {
|
||||
receivedValues.push(err);
|
||||
subscription.unsubscribe();
|
||||
resolve(tryExpectations(receivedValues, expectations));
|
||||
},
|
||||
complete: () => {
|
||||
subscription.unsubscribe();
|
||||
resolve(tryExpectations(receivedValues, expectations));
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
forceObservableCompletion(subscription, resolve);
|
||||
});
|
||||
}
|
13
public/test/matchers/types.ts
Normal file
13
public/test/matchers/types.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export const OBSERVABLE_TEST_TIMEOUT_IN_MS = 1000;
|
||||
|
||||
export type ObservableType<T> = T extends Observable<infer V> ? V : never;
|
||||
|
||||
export interface ObservableMatchers<R, T = {}> extends jest.ExpectExtendMap {
|
||||
toEmitValues<E = ObservableType<T>>(received: T, expected: E[]): Promise<jest.CustomMatcherResult>;
|
||||
toEmitValuesWith<E = ObservableType<T>>(
|
||||
received: T,
|
||||
expectations: (received: E[]) => void
|
||||
): Promise<jest.CustomMatcherResult>;
|
||||
}
|
62
public/test/matchers/utils.ts
Normal file
62
public/test/matchers/utils.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { matcherHint, printExpected, printReceived } from 'jest-matcher-utils';
|
||||
import { OBSERVABLE_TEST_TIMEOUT_IN_MS } from './types';
|
||||
import { asapScheduler, Observable, Subscription, timer } from 'rxjs';
|
||||
|
||||
export function forceObservableCompletion(subscription: Subscription, resolve: (args: any) => void) {
|
||||
const timeoutObservable = timer(OBSERVABLE_TEST_TIMEOUT_IN_MS, asapScheduler);
|
||||
|
||||
subscription.add(
|
||||
timeoutObservable.subscribe(() => {
|
||||
subscription.unsubscribe();
|
||||
resolve({
|
||||
pass: false,
|
||||
message: () =>
|
||||
`${matcherHint('.toEmitValues')}
|
||||
|
||||
Expected ${printReceived('Observable')} to be ${printExpected(
|
||||
`completed within ${OBSERVABLE_TEST_TIMEOUT_IN_MS}ms`
|
||||
)} but it did not.`,
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function expectObservableToBeDefined(received: any): jest.CustomMatcherResult | null {
|
||||
if (received) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
pass: false,
|
||||
message: () => `${matcherHint('.toEmitValues')}
|
||||
|
||||
Expected ${printReceived(received)} to be ${printExpected('defined')}.`,
|
||||
};
|
||||
}
|
||||
|
||||
export function expectObservableToBeObservable(received: any): jest.CustomMatcherResult | null {
|
||||
if (received instanceof Observable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
pass: false,
|
||||
message: () => `${matcherHint('.toEmitValues')}
|
||||
|
||||
Expected ${printReceived(received)} to be ${printExpected('an Observable')}.`,
|
||||
};
|
||||
}
|
||||
|
||||
export function expectObservable(received: any): jest.CustomMatcherResult | null {
|
||||
const toBeDefined = expectObservableToBeDefined(received);
|
||||
if (toBeDefined) {
|
||||
return toBeDefined;
|
||||
}
|
||||
|
||||
const toBeObservable = expectObservableToBeObservable(received);
|
||||
if (toBeObservable) {
|
||||
return toBeObservable;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
@@ -1 +1,4 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import { matchers } from './matchers';
|
||||
|
||||
expect.extend(matchers);
|
||||
|
@@ -19,6 +19,7 @@
|
||||
"public/e2e-test/**/*.ts",
|
||||
"public/test/**/*.ts",
|
||||
"public/vendor/**/*.ts",
|
||||
"packages/jaeger-ui-components/typings"
|
||||
"packages/jaeger-ui-components/typings",
|
||||
"packages/grafana-data/typings"
|
||||
]
|
||||
}
|
||||
|
12
yarn.lock
12
yarn.lock
@@ -16693,7 +16693,7 @@ jest-get-type@^25.2.6:
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877"
|
||||
integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==
|
||||
|
||||
jest-get-type@^26.3.0:
|
||||
jest-get-type@^26.0.0, jest-get-type@^26.3.0:
|
||||
version "26.3.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0"
|
||||
integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==
|
||||
@@ -16831,6 +16831,16 @@ jest-leak-detector@^26.5.2:
|
||||
jest-get-type "^26.3.0"
|
||||
pretty-format "^26.5.2"
|
||||
|
||||
jest-matcher-utils@26.0.0:
|
||||
version "26.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.0.0.tgz#1b288fee2362639a61975ce52b003034a6c2b39e"
|
||||
integrity sha512-ektfkGT4pByMWc6NaCzHGCVZWl3XR1nNizVP1jVsGs/Qlh9iDunITrJxSTd8xK9/XgWA3oJ13orpUt82JIc2UA==
|
||||
dependencies:
|
||||
chalk "^4.0.0"
|
||||
jest-diff "^26.0.0"
|
||||
jest-get-type "^26.0.0"
|
||||
pretty-format "^26.0.0"
|
||||
|
||||
jest-matcher-utils@^25.5.0:
|
||||
version "25.5.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-25.5.0.tgz#fbc98a12d730e5d2453d7f1ed4a4d948e34b7867"
|
||||
|
Reference in New Issue
Block a user