balena-cli/tests/framework/output.spec.ts
Scott Lowe f3fb9b6bdf v13 preparations: Standardize command data output
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2021-12-08 12:10:08 +01:00

256 lines
7.7 KiB
TypeScript

/**
* @license
* Copyright 2020-2021 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* tslint:disable: prefer-const no-empty */
import rewire = require('rewire');
import sinon = require('sinon');
import { expect } from 'chai';
const dataItem = {
name: 'item1',
id: 1,
thing_color: 'blue',
thing_shape: 'square',
};
const dataSet = [
{
name: 'item1',
id: 1,
thing_color: 'red',
thing_shape: 'square',
},
{
name: 'item2',
id: 2,
thing_color: 'blue',
thing_shape: 'round',
},
];
describe('outputData', function () {
let outputData: any;
let outputDataSetSpy: any;
let outputDataItemSpy: any;
this.beforeEach(() => {
const output = rewire('../../build/framework/output');
outputDataSetSpy = sinon.spy();
outputDataItemSpy = sinon.spy();
output.__set__('outputDataSet', outputDataSetSpy);
output.__set__('outputDataItem', outputDataItemSpy);
outputData = output.__get__('outputData');
});
it('should call outputDataSet function when data param is an array', async () => {
await outputData(dataSet);
expect(outputDataSetSpy.called).to.be.true;
expect(outputDataItemSpy.called).to.be.false;
});
it('should call outputDataItem function when data param is an object', async () => {
await outputData(dataItem);
expect(outputDataSetSpy.called).to.be.false;
expect(outputDataItemSpy.called).to.be.true;
});
});
describe('outputDataSet', function () {
let outputDataSet: any;
let printLineSpy: any;
this.beforeEach(() => {
const output = rewire('../../build/framework/output');
printLineSpy = sinon.spy();
output.__set__('printLine', printLineSpy);
outputDataSet = output.__get__('outputDataSet');
});
it('should only output fields specified in `fields` param, in that order', async () => {
const fields = ['id', 'name', 'thing_color'];
const options = {};
await outputDataSet(dataSet, fields, options);
// check correct number of rows (2 data, 2 header)
expect(printLineSpy.callCount).to.equal(4);
const headerLine = printLineSpy.firstCall.firstArg.toLowerCase();
// check we have fields we specified
fields.forEach((f) => {
expect(headerLine).to.include(f.replace(/_/g, ' '));
});
// check we don't have fields we didn't specify
expect(headerLine).to.not.include('thing_shape');
// check order
// split header using the `name` column as delimiter
const splitHeader = headerLine.split('name');
expect(splitHeader[0]).to.include('id');
expect(splitHeader[1]).to.include('thing');
});
/*
it('should output fields in the order specified in `fields` param', async () => {
const fields = ['thing_color', 'id', 'name'];
const options = {};
await outputDataSet(dataSet, fields, options);
const headerLine = printLineSpy.firstCall.firstArg.toLowerCase();
// split header using the `it` column as delimiter
const splitHeader = headerLine.split('id');
expect(splitHeader[0]).to.include('thing');
expect(splitHeader[1]).to.include('name');
});
*/
it('should only output fields specified in `options.fields` if present', async () => {
const fields = ['name', 'id', 'thing_color', 'thing_shape'];
const options = {
// test all formats
fields: 'Name,thing_color,Thing shape',
};
await outputDataSet(dataSet, fields, options);
const headerLine = printLineSpy.firstCall.firstArg.toLowerCase();
// check we have fields we specified
expect(headerLine).to.include('name');
expect(headerLine).to.include('thing color');
expect(headerLine).to.include('thing shape');
// check we don't have fields we didn't specify
expect(headerLine).to.not.include('id');
});
it('should output records in order specified by `options.sort` if present', async () => {
const fields = ['name', 'id', 'thing_color', 'thing_shape'];
const options = {
sort: 'thing shape',
'no-header': true,
};
await outputDataSet(dataSet, fields, options);
// blue should come before red
expect(printLineSpy.getCall(0).firstArg).to.include('blue');
expect(printLineSpy.getCall(1).firstArg).to.include('red');
});
it('should only output records that match filter specified by `options.filter` if present', async () => {
const fields = ['name', 'id', 'thing_color', 'thing_shape'];
const options = {
filter: 'thing color=red',
'no-header': true,
};
await outputDataSet(dataSet, fields, options);
// check correct number of rows (1 matched data, no-header)
expect(printLineSpy.callCount).to.equal(1);
expect(printLineSpy.getCall(0).firstArg).to.include('red');
});
it('should output data in json format, if `options.json` true', async () => {
const fields = ['name', 'thing_color', 'thing_shape'];
const options = {
json: true,
};
// TODO: I've run into an oclif cli-ux bug, where numbers are output as strings in json
// (this can be seen by including 'id' in the fields list above).
// Issue opened: https://github.com/oclif/cli-ux/issues/309
// For now removing id for this test.
const clonedDataSet = JSON.parse(JSON.stringify(dataSet));
clonedDataSet.forEach((d: any) => {
delete d.id;
});
const expectedJson = JSON.stringify(clonedDataSet, undefined, 2);
await outputDataSet(dataSet, fields, options);
expect(printLineSpy.callCount).to.equal(1);
expect(printLineSpy.getCall(0).firstArg).to.equal(expectedJson);
});
});
describe('outputDataItem', function () {
let outputDataItem: any;
let printLineSpy: any;
this.beforeEach(() => {
const output = rewire('../../build/framework/output');
printLineSpy = sinon.spy();
output.__set__('printLine', printLineSpy);
outputDataItem = output.__get__('outputDataItem');
});
it('should only output fields specified in `fields` param, in that order', async () => {
const fields = ['id', 'name', 'thing_color'];
const options = {};
await outputDataItem(dataItem, fields, options);
// check correct number of rows (3 fields)
expect(printLineSpy.callCount).to.equal(3);
// check we have fields we specified
fields.forEach((f, index) => {
const kvPair = printLineSpy.getCall(index).firstArg.split(':');
expect(kvPair[0].toLowerCase()).to.include(f.replace(/_/g, ' '));
expect(kvPair[1]).to.include((dataItem as any)[f]);
});
});
it('should only output fields specified in `options.fields` if present', async () => {
const fields = ['name', 'id', 'thing_color', 'thing_shape'];
const options = {
// test all formats
fields: 'Name,thing_color,Thing shape',
};
const expectedFields = ['name', 'thing_color', 'thing_shape'];
await outputDataItem(dataItem, fields, options);
// check correct number of rows (3 fields)
expect(printLineSpy.callCount).to.equal(3);
// check we have fields we specified
expectedFields.forEach((f, index) => {
const kvPair = printLineSpy.getCall(index).firstArg.split(':');
expect(kvPair[0].toLowerCase()).to.include(f.replace(/_/g, ' '));
expect(kvPair[1]).to.include((dataItem as any)[f]);
});
});
it('should output data in json format, if `options.json` true', async () => {
const fields = ['name', 'id', 'thing_color', 'thing_shape'];
const options = {
json: true,
};
const expectedJson = JSON.stringify(dataItem, undefined, 2);
await outputDataItem(dataItem, fields, options);
expect(printLineSpy.callCount).to.equal(1);
expect(printLineSpy.getCall(0).firstArg).to.equal(expectedJson);
});
});