/** * @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); }); });