Commit 4b711372 by Hugo Häggmark Committed by GitHub

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
parent 112a755e
......@@ -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]);
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: {} },
];
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: {} },
];
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]);
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: {} },
];
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: {} },
];
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);
});
});
});
......@@ -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]),
},
]);
});
});
});
......
......@@ -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]),
];
expect(unwrap(result[0].fields)).toEqual(expected);
},
done,
await expect(transformDataFrame([cfg], [seriesA, seriesB])).toEmitValuesWith(received => {
const result = received[0];
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]),
];
expect(unwrap(result[0].fields)).toEqual(expected);
},
done,
await expect(transformDataFrame([cfg], [seriesA, seriesB])).toEmitValuesWith(received => {
const result = received[0];
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]),
];
expect(unwrap(result[0].fields)).toEqual(expected);
},
done,
await expect(transformDataFrame([cfg], [seriesA, seriesB, seriesC])).toEmitValuesWith(received => {
const result = received[0];
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]),
];
const fields = unwrap(result[0].fields);
expect(fields[2].config).toEqual({});
expect(fields).toEqual(expected);
},
done,
await expect(transformDataFrame([cfg], [serieA, serieB])).toEmitValuesWith(received => {
const result = received[0];
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]),
];
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' }),
];
const fields = unwrap(result[0].fields);
expect(fields[2].config).toEqual({ units: 'celsius' });
expect(fields).toEqual(expected);
},
done,
await expect(transformDataFrame([cfg], [serieA, serieB])).toEmitValuesWith(received => {
const result = received[0];
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' }),
];
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]),
];
const fields = unwrap(result[0].fields);
expect(fields[2].config).toEqual({});
expect(fields).toEqual(expected);
},
done,
await expect(transformDataFrame([cfg], [serieA, serieB])).toEmitValuesWith(received => {
const result = received[0];
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]),
];
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"
]
}
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>;
}
}
}
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',
},
],
]);
});
});
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();
});
});
});
......
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,
};
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']);
});
});
});
});
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);
});
}
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']);
});
});
});
});
});
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);
});
}
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>;
}
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;
}
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"
]
}
......@@ -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"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment