Skip to content

Commit

Permalink
fix(exports): when cell value is empty object return empty string
Browse files Browse the repository at this point in the history
- when dealing with complex object, it could in some cases return an empty object when targeted object is undefined or not part of the object itself
  • Loading branch information
ghiscoding committed Dec 9, 2020
1 parent cf69f5d commit 0534d13
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Column } from '../../models';
import { complexObjectFormatter } from '../complexObjectFormatter';

describe('the ComplexObject Formatter', () => {
const allRoles = [{ roleId: 0, name: 'Administrator' }, { roleId: 1, name: 'Regular User' }];
const allRoles = [{ roleId: 0, name: 'Administrator' }, { roleId: 1, name: 'Regular User', empty: {} }];

const dataset = [
{ id: 0, firstName: 'John', lastName: 'Smith', email: '[email protected]', role: allRoles[0] },
Expand All @@ -11,54 +11,60 @@ describe('the ComplexObject Formatter', () => {
];

it('should throw an error when omitting to pass "complexFieldLabel" to "params"', () => {
expect(() => complexObjectFormatter(0, 0, 'anything', {} as Column, {}, {}))
expect(() => complexObjectFormatter(0, 0, 'anything', {} as Column, {}, {} as any))
.toThrowError('For the Formatters.complexObject to work properly');
});

it('should return empty string when no column definition is provided', () => {
const result = complexObjectFormatter(0, 0, 'anything', null as Column, {}, {});
const result = complexObjectFormatter(0, 0, 'anything', null as Column, {}, {} as any);
expect(result).toBe('');
});

it('should return original input value when the "field" property does not include a not ".", neither "complexFieldLabel"', () => {
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role' } as Column, {}, {});
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role' } as Column, {}, {} as any);
expect(result).toBe('anything');
});

it('should return original input value when the "field" property was not found in the data context object', () => {
const result = complexObjectFormatter(0, 0, 'anything', { field: 'invalid.object' } as Column, dataset[2], {});
expect(result).toBe('anything');
it('should return empty string when the "field" property was not found in the data context object', () => {
const result = complexObjectFormatter(0, 0, 'anything', { field: 'invalid.object' } as Column, dataset[2], {} as any);
expect(result).toBe('');
});

it('should return original input value when the "complexFieldLabel" does not include a not "." within its string', () => {
const params = { complexFieldLabel: 'name' };
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, {}, {});
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, {}, {} as any);
expect(result).toBe('anything');
});

it('should return original input value when the "complexFieldLabel" was not found in the data context object', () => {
const params = { complexFieldLabel: 'invalid.object' };
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, dataset[2], {});
expect(result).toBe('anything');
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, dataset[2], {} as any);
expect(result).toBe('');
});

it('should return the value from the complex object when "field" property with dot notation was found in the data context object', () => {
const expectedOutput = 'Administrator';
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role.name' } as Column, dataset[0], {});
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role.name' } as Column, dataset[0], {} as any);
expect(result).toBe(expectedOutput);
});

it('should return an empty string when the value from the complex object when "field" has dot notation and the empty returned from it is an empty object', () => {
const expectedOutput = '';
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role.empty' } as Column, dataset[1], {} as any);
expect(result).toBe(expectedOutput);
});

it('should return the value from the complex object when "complexFieldLabel" property with dot notation was found in the data context object', () => {
const params = { complexFieldLabel: 'role.name' };
const expectedOutput = 'Administrator';
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, dataset[0], {});
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', params } as Column, dataset[0], {} as any);
expect(result).toBe(expectedOutput);
});

it('should return the value from the complex object when "complexFieldLabel" is not dot notation but has a "labelKey" was found in the data context object', () => {
const params = { complexFieldLabel: 'role' };
const expectedOutput = 'Administrator';
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', labelKey: 'name', params } as Column, dataset[0], {});
const result = complexObjectFormatter(0, 0, 'anything', { field: 'role', labelKey: 'name', params } as Column, dataset[0], {} as any);
expect(result).toBe(expectedOutput);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ export const complexObjectFormatter: Formatter = (row: number, cell: number, cel
// when complexFieldLabel includes the dot ".", we will do the split and get the value from the complex object
// however we also need to make sure that the complex objet exist, else we'll return the cell value (original value)
if (typeof complexFieldLabel === 'string' && complexFieldLabel.indexOf('.') > 0) {
return complexFieldLabel.split('.').reduce((obj, i) => (obj && obj.hasOwnProperty(i) ? obj[i] : cellValue), dataContext);
let outputValue = complexFieldLabel.split('.').reduce((obj, i) => (obj && obj.hasOwnProperty(i) ? obj[i] : ''), dataContext);
if (typeof outputValue === 'object' && Object.entries(outputValue).length === 0) {
outputValue = ''; // return empty string when value ends up being an empty object
}
return outputValue;
}
return cellValue;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { exportWithFormatterWhenDefined } from '../export-utilities';
import { Column, Formatter, SlickGrid } from '../../models/index';

describe('Export Utilities', () => {
let mockItem;
let mockColumn: Column;
const myBoldHtmlFormatter: Formatter = (_row, _cell, value) => value !== null ? { text: value ? `<b>${value}</b>` : '' } : null as any;
const myUppercaseFormatter: Formatter = (_row, _cell, value) => value ? { text: value.toUpperCase() } : null as any;

beforeEach(() => {
mockItem = { firstName: 'John', lastName: 'Doe', age: 45, address: { zip: 12345 }, empty: {} };
mockColumn = { id: 'firstName', name: 'First Name', field: 'firstName', formatter: myUppercaseFormatter };
});

describe('exportWithFormatterWhenDefined method', () => {
it('should NOT enable exportWithFormatter and expect the firstName to returned', () => {
const output = exportWithFormatterWhenDefined(1, 1, mockItem, mockColumn, {} as SlickGrid, { exportWithFormatter: false });
expect(output).toBe('John');
});

it('should provide a column definition field defined with a dot (.) notation and expect a complex object result', () => {
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, field: 'address.zip' }, {} as SlickGrid, {});
expect(output).toEqual({ zip: 12345 });
});

it('should provide a column definition field defined with a dot (.) notation and expect an empty string when the complex result is an empty object', () => {
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, field: 'empty' }, {} as SlickGrid, {});
expect(output).toEqual('');
});

it('should provide a column definition field defined with a dot (.) notation and expect an empty string when the complex result is an empty object', () => {
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, field: 'empty' }, {} as SlickGrid, {});
expect(output).toEqual('');
});

it('should provide a exportCustomFormatter in the column definition and expect the output to be formatted', () => {
const output = exportWithFormatterWhenDefined(1, 1, mockItem, { ...mockColumn, exportCustomFormatter: myBoldHtmlFormatter }, {} as SlickGrid, { exportWithFormatter: true });
expect(output).toBe('<b>John</b>');
});

it('should provide a exportCustomFormatter in the column definition and expect empty string when associated item property is null', () => {
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: null }, { ...mockColumn, exportCustomFormatter: myBoldHtmlFormatter }, {} as SlickGrid, { exportWithFormatter: true });
expect(output).toBe('');
});

it('should provide a exportCustomFormatter in the column definition and expect empty string when associated item property is undefined', () => {
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: undefined }, { ...mockColumn, exportCustomFormatter: myBoldHtmlFormatter }, {} as SlickGrid, { exportWithFormatter: true });
expect(output).toBe('');
});

it('should enable exportWithFormatter as an exportOption and expect the firstName to be formatted', () => {
const output = exportWithFormatterWhenDefined(1, 1, mockItem, mockColumn, {} as SlickGrid, { exportWithFormatter: true });
expect(output).toBe('JOHN');
});

it('should enable exportWithFormatter as a grid option and expect the firstName to be formatted', () => {
mockColumn.exportWithFormatter = true;
const output = exportWithFormatterWhenDefined(1, 1, mockItem, mockColumn, {} as SlickGrid, { exportWithFormatter: true });
expect(output).toBe('JOHN');
});

it('should enable exportWithFormatter as a grid option and expect empty string when associated item property is null', () => {
mockColumn.exportWithFormatter = true;
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: null }, mockColumn, {} as SlickGrid, { exportWithFormatter: true });
expect(output).toBe('');
});

it('should enable exportWithFormatter as a grid option and expect empty string when associated item property is undefined', () => {
mockColumn.exportWithFormatter = true;
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: undefined }, mockColumn, {} as SlickGrid, { exportWithFormatter: true });
expect(output).toBe('');
});

it('should expect empty string when associated item property is undefined and has no formatter defined', () => {
const output = exportWithFormatterWhenDefined(1, 1, { ...mockItem, firstName: undefined }, mockColumn, {} as SlickGrid, {});
expect(output).toBe('');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,10 @@ export function exportWithFormatterWhenDefined(row: number, col: number, dataCon
}
}

// if at the end we have an empty object, then replace it with an empty string
if (typeof output === 'object' && Object.entries(output).length === 0) {
output = '';
}

return output;
}

0 comments on commit 0534d13

Please sign in to comment.