forked from elastic/kibana
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Unit Tests for Common Functions: Data Manipulation (elastic#442)
* unit tests for altercolumn * unit tests for as * Added tests for as * fixed typo * Refactored alterColumn to not mutate context. Updated unit tests for altercolumn * Updated unit tests for as * Updated altercolumn to return original context when name and type are not provided as args * Added unit tests for columns. Refactored columns function to return empty array of rows if columns is empty instead of an array of empty objects * Changed describe from 'as' to 'columns' * Unit tests for getCell. Added throw for invalid column in getCell * Unit tests for head * Added functionWrapper that fills in default args * fixed merge conflict * Added default name for as function. Added unit test for as * Updated tests for getCell and head * Cleaned up unit tests for alterColumn * Updated unit tests for as * Cleaned up tests for columns * Cleaned up tests for getCell * Cleaned up tests for head * Added unit tests for tail * Unit tests for rowCount * Added throw for missing column name and default for value in staticColumn. Added unit tests for staticColumn * Removed .only from unit tests for rowCount * Fixed typo * Removed jsonquery function. Moving to canvas-extras * Added alias for args._ in sort and removed aliases key from function definition * Added logic to sort on first column by default if column isn't provided as an arg. Added unit tests for sort * Added test for staticColumn * Added throw for missing column name. Refactored mapColumn to not mutate context. Added unit tests for mapColumn * Merged functionWrapper from common-tests * Removed compare unit tests from this branch. Unit tests for compare are in PR elastic#415 * WIP: unit tests for ply * WIP: unit tests for ply * Fixed tests for mapColumn * Added unit tests for ply. Add checks for missing args in ply * Fixed unit tests for ply * Changed functionWrapper to function_wrapper and fixed import paths. Removed .js extension in imports. * Added check for column arg in alterColumn. Cleaned up tests for alterColumn * Cleaned up tests for alterColumn and as * Added tests to alterColumn * Cleaned up columns tests * Cleaned up getCell tests * Cleaned up tests for head and tail * Cleaned up mapColumn tests * Cleaned up tests for mapColumn, ply, and sort * Cleaned up tests for staticColumn * Cleaned up tests * Fixed jquery version * Changed alterColumn, mapColumn, and staticColumn to overwrite existing columns if provided name of existing columns * fixed tests for ply * Fixed spacing in unit tests * Fixed typo * Condensed tests. Used '.and' where applicable. * Changed getCell to default to first column if args._ is missing
- Loading branch information
Showing
25 changed files
with
1,012 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { mapValues } from 'lodash'; | ||
|
||
export const functionWrapper = fnSpec => { | ||
const spec = fnSpec(); | ||
const defaultArgs = mapValues(spec.args, argSpec => { | ||
return argSpec.default; | ||
}); | ||
|
||
return (context, args, handlers) => spec.fn(context, { ...defaultArgs, ...args }, handlers); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
import expect from 'expect.js'; | ||
import { alterColumn } from '../alterColumn'; | ||
import { functionWrapper } from '../../../__tests__/helpers/function_wrapper'; | ||
import { emptyTable, testTable } from './fixtures/test_tables'; | ||
|
||
describe('alterColumn', () => { | ||
const fn = functionWrapper(alterColumn); | ||
const nameColumnIndex = testTable.columns.findIndex(({ name }) => name === 'name'); | ||
const timeColumnIndex = testTable.columns.findIndex(({ name }) => name === 'time'); | ||
const priceColumnIndex = testTable.columns.findIndex(({ name }) => name === 'price'); | ||
const inStockColumnIndex = testTable.columns.findIndex(({ name }) => name === 'in_stock'); | ||
|
||
it('returns a datatable', () => { | ||
const alteredTable = fn(testTable, { column: 'price', type: 'string', name: 'priceString' }); | ||
|
||
expect(alteredTable.type).to.be('datatable'); | ||
}); | ||
|
||
describe('args', () => { | ||
it('returns original context if no args are provided', () => { | ||
expect(fn(testTable)).to.eql(testTable); | ||
}); | ||
|
||
describe('column', () => { | ||
// ISO 8601 string -> date | ||
it('specifies which column to alter', () => { | ||
const dateToString = fn(testTable, { column: 'time', type: 'string', name: 'timeISO' }); | ||
const originalColumn = testTable.columns[timeColumnIndex]; | ||
const newColumn = dateToString.columns[timeColumnIndex]; | ||
const arbitraryRowIndex = 6; | ||
|
||
expect(newColumn.name).to.not.be(originalColumn.name); | ||
expect(newColumn.type).to.not.be(originalColumn.type); | ||
expect(dateToString.rows[arbitraryRowIndex].timeISO).to.be.a('string'); | ||
expect(new Date(dateToString.rows[arbitraryRowIndex].timeISO)).to.eql( | ||
new Date(testTable.rows[arbitraryRowIndex].time) | ||
); | ||
}); | ||
|
||
it('returns original context if column is not specified', () => { | ||
expect(fn(testTable, { type: 'date', name: 'timeISO' })).to.eql(testTable); | ||
}); | ||
|
||
it('throws if column does not exists', () => { | ||
expect(() => fn(emptyTable, { column: 'foo', type: 'number' })).to.throwException(e => { | ||
expect(e.message).to.be("Column not found: 'foo'"); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('type', () => { | ||
it('converts the column to the specified type', () => { | ||
const dateToString = fn(testTable, { column: 'time', type: 'string', name: 'timeISO' }); | ||
|
||
expect(dateToString.columns[timeColumnIndex].type).to.be('string'); | ||
expect(dateToString.rows[timeColumnIndex].timeISO).to.be.a('string'); | ||
expect(new Date(dateToString.rows[timeColumnIndex].timeISO)).to.eql( | ||
new Date(testTable.rows[timeColumnIndex].time) | ||
); | ||
}); | ||
|
||
it('does not change column if type is not specified', () => { | ||
const unconvertedColumn = fn(testTable, { column: 'price', name: 'foo' }); | ||
const originalType = testTable.columns[priceColumnIndex].type; | ||
const arbitraryRowIndex = 2; | ||
|
||
expect(unconvertedColumn.columns[priceColumnIndex].type).to.be(originalType); | ||
expect(unconvertedColumn.rows[arbitraryRowIndex].foo).to.be.a( | ||
originalType, | ||
testTable.rows[arbitraryRowIndex].price | ||
); | ||
}); | ||
|
||
it('throws when converting to an invalid type', () => { | ||
expect(() => fn(testTable, { column: 'name', type: 'foo' })).to.throwException(e => { | ||
expect(e.message).to.be('Cannot convert to foo'); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('name', () => { | ||
it('changes column name to specified name', () => { | ||
const dateToString = fn(testTable, { column: 'time', type: 'date', name: 'timeISO' }); | ||
const arbitraryRowIndex = 8; | ||
|
||
expect(dateToString.columns[timeColumnIndex].name).to.be('timeISO'); | ||
expect(dateToString.rows[arbitraryRowIndex]).to.have.property('timeISO'); | ||
}); | ||
|
||
it('overwrites existing column if provided an existing column name', () => { | ||
const overwriteName = fn(testTable, { column: 'time', type: 'string', name: 'name' }); | ||
const originalColumn = testTable.columns[timeColumnIndex]; | ||
const newColumn = overwriteName.columns[nameColumnIndex]; | ||
const arbitraryRowIndex = 5; | ||
|
||
expect(newColumn.name).to.not.be(originalColumn.name); | ||
expect(newColumn.type).to.not.be(originalColumn.type); | ||
expect(overwriteName.rows[arbitraryRowIndex].name).to.be.a('string'); | ||
expect(new Date(overwriteName.rows[arbitraryRowIndex].name)).to.eql( | ||
new Date(testTable.rows[arbitraryRowIndex].time) | ||
); | ||
}); | ||
|
||
it('retains original column name if name is not provided', () => { | ||
const unchangedName = fn(testTable, { column: 'price', type: 'string' }); | ||
|
||
expect(unchangedName.columns[priceColumnIndex].name).to.be( | ||
testTable.columns[priceColumnIndex].name | ||
); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('valid type conversions', () => { | ||
it('converts number <-> string', () => { | ||
const arbitraryRowIndex = 4; | ||
const numberToString = fn(testTable, { column: 'price', type: 'string' }); | ||
|
||
expect(numberToString.columns[priceColumnIndex]) | ||
.to.have.property('name', 'price') | ||
.and.to.have.property('type', 'string'); | ||
expect(numberToString.rows[arbitraryRowIndex].price) | ||
.to.be.a('string') | ||
.and.to.eql(testTable.rows[arbitraryRowIndex].price); | ||
|
||
const stringToNumber = fn(numberToString, { column: 'price', type: 'number' }); | ||
|
||
expect(stringToNumber.columns[priceColumnIndex]) | ||
.to.have.property('name', 'price') | ||
.and.to.have.property('type', 'number'); | ||
expect(stringToNumber.rows[arbitraryRowIndex].price) | ||
.to.be.a('number') | ||
.and.to.eql(numberToString.rows[arbitraryRowIndex].price); | ||
}); | ||
|
||
it('converts date <-> string', () => { | ||
const arbitraryRowIndex = 4; | ||
const dateToString = fn(testTable, { column: 'time', type: 'string' }); | ||
|
||
expect(dateToString.columns[timeColumnIndex]) | ||
.to.have.property('name', 'time') | ||
.and.to.have.property('type', 'string'); | ||
expect(dateToString.rows[arbitraryRowIndex].time).to.be.a('string'); | ||
expect(new Date(dateToString.rows[arbitraryRowIndex].time)).to.eql( | ||
new Date(testTable.rows[arbitraryRowIndex].time) | ||
); | ||
|
||
const stringToDate = fn(dateToString, { column: 'time', type: 'date' }); | ||
|
||
expect(stringToDate.columns[timeColumnIndex]) | ||
.to.have.property('name', 'time') | ||
.and.to.have.property('type', 'date'); | ||
expect(new Date(stringToDate.rows[timeColumnIndex].time)) | ||
.to.be.a(Date) | ||
.and.to.eql(new Date(dateToString.rows[timeColumnIndex].time)); | ||
}); | ||
|
||
it('converts date <-> number', () => { | ||
const dateToNumber = fn(testTable, { column: 'time', type: 'number' }); | ||
const arbitraryRowIndex = 1; | ||
|
||
expect(dateToNumber.columns[timeColumnIndex]) | ||
.to.have.property('name', 'time') | ||
.and.to.have.property('type', 'number'); | ||
expect(dateToNumber.rows[arbitraryRowIndex].time) | ||
.to.be.a('number') | ||
.and.to.eql(testTable.rows[arbitraryRowIndex].time); | ||
|
||
const numberToDate = fn(dateToNumber, { column: 'time', type: 'date' }); | ||
|
||
expect(numberToDate.columns[timeColumnIndex]) | ||
.to.have.property('name', 'time') | ||
.and.to.have.property('type', 'date'); | ||
expect(new Date(numberToDate.rows[arbitraryRowIndex].time)) | ||
.to.be.a(Date) | ||
.and.to.eql(testTable.rows[arbitraryRowIndex].time); | ||
}); | ||
|
||
it('converts bool <-> number', () => { | ||
const booleanToNumber = fn(testTable, { column: 'in_stock', type: 'number' }); | ||
const arbitraryRowIndex = 7; | ||
|
||
expect(booleanToNumber.columns[inStockColumnIndex]) | ||
.to.have.property('name', 'in_stock') | ||
.and.to.have.property('type', 'number'); | ||
expect(booleanToNumber.rows[arbitraryRowIndex].in_stock) | ||
.to.be.a('number') | ||
.and.to.eql(booleanToNumber.rows[arbitraryRowIndex].in_stock); | ||
|
||
const numberToBoolean = fn(booleanToNumber, { column: 'in_stock', type: 'boolean' }); | ||
|
||
expect(numberToBoolean.columns[inStockColumnIndex]) | ||
.to.have.property('name', 'in_stock') | ||
.and.to.have.property('type', 'boolean'); | ||
expect(numberToBoolean.rows[arbitraryRowIndex].in_stock) | ||
.to.be.a('boolean') | ||
.and.to.eql(numberToBoolean.rows[arbitraryRowIndex].in_stock); | ||
}); | ||
|
||
it('converts any type -> null', () => { | ||
const stringToNull = fn(testTable, { column: 'name', type: 'null' }); | ||
const arbitraryRowIndex = 0; | ||
|
||
expect(stringToNull.columns[nameColumnIndex]) | ||
.to.have.property('name', 'name') | ||
.and.to.have.property('type', 'null'); | ||
expect(stringToNull.rows[arbitraryRowIndex].name).to.be(null); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import expect from 'expect.js'; | ||
import { asFn } from '../as'; | ||
import { functionWrapper } from '../../../__tests__/helpers/function_wrapper'; | ||
|
||
describe('as', () => { | ||
const fn = functionWrapper(asFn); | ||
|
||
it('returns a datatable with a single column and single row', () => { | ||
expect(fn('foo', { _: 'bar' })).to.eql({ | ||
type: 'datatable', | ||
columns: [{ name: 'bar', type: 'string' }], | ||
rows: [{ bar: 'foo' }], | ||
}); | ||
|
||
expect(fn(2, { _: 'num' })).to.eql({ | ||
type: 'datatable', | ||
columns: [{ name: 'num', type: 'number' }], | ||
rows: [{ num: 2 }], | ||
}); | ||
|
||
expect(fn(true, { _: 'bool' })).to.eql({ | ||
type: 'datatable', | ||
columns: [{ name: 'bool', type: 'boolean' }], | ||
rows: [{ bool: true }], | ||
}); | ||
}); | ||
|
||
describe('args', () => { | ||
describe('_', () => { | ||
it('sets the column name of the resulting datatable', () => { | ||
expect(fn(null, { _: 'foo' }).columns[0].name).to.eql('foo'); | ||
}); | ||
|
||
it("returns a datatable with the column name 'value'", () => { | ||
expect(fn(null).columns[0].name).to.eql('value'); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import expect from 'expect.js'; | ||
import { columns } from '../columns'; | ||
import { functionWrapper } from '../../../__tests__/helpers/function_wrapper'; | ||
import { emptyTable, testTable } from './fixtures/test_tables'; | ||
|
||
describe('columns', () => { | ||
const fn = functionWrapper(columns); | ||
|
||
it('returns a datatable', () => { | ||
expect(fn(testTable, { include: 'name' }).type).to.be('datatable'); | ||
}); | ||
|
||
describe('args', () => { | ||
it('returns a datatable with included columns and without excluded columns', () => { | ||
const arbitraryRowIndex = 7; | ||
const result = fn(testTable, { | ||
include: 'name, price, quantity, foo, bar', | ||
exclude: 'price, quantity, fizz, buzz', | ||
}); | ||
|
||
expect(result.columns[0]).to.have.property('name', 'name'); | ||
expect(result.rows[arbitraryRowIndex]) | ||
.to.have.property('name', testTable.rows[arbitraryRowIndex].name) | ||
.and.to.not.have.property('price') | ||
.and.to.not.have.property('quantity') | ||
.and.to.not.have.property('foo') | ||
.and.to.not.have.property('bar') | ||
.and.to.not.have.property('fizz') | ||
.and.to.not.have.property('buzz'); | ||
}); | ||
|
||
it('returns original context if args are not provided', () => { | ||
expect(fn(testTable)).to.eql(testTable); | ||
}); | ||
|
||
it('returns an empty datatable if include and exclude both reference the same column(s)', () => { | ||
expect(fn(testTable, { include: 'price', exclude: 'price' })).to.eql(emptyTable); | ||
|
||
expect( | ||
fn(testTable, { | ||
include: 'price, quantity, in_stock', | ||
exclude: 'price, quantity, in_stock', | ||
}) | ||
).to.eql(emptyTable); | ||
}); | ||
|
||
describe('include', () => { | ||
it('returns a datatable with included columns only', () => { | ||
const arbitraryRowIndex = 3; | ||
const result = fn(testTable, { | ||
include: 'name, time, in_stock', | ||
}); | ||
|
||
expect(result.columns).to.have.length(3); | ||
expect(Object.keys(result.rows[0])).to.have.length(3); | ||
|
||
expect(result.columns[0]).to.have.property('name', 'name'); | ||
expect(result.columns[1]).to.have.property('name', 'time'); | ||
expect(result.columns[2]).to.have.property('name', 'in_stock'); | ||
expect(result.rows[arbitraryRowIndex]) | ||
.to.have.property('name', testTable.rows[arbitraryRowIndex].name) | ||
.and.to.have.property('time', testTable.rows[arbitraryRowIndex].time) | ||
.and.to.have.property('in_stock', testTable.rows[arbitraryRowIndex].in_stock); | ||
}); | ||
|
||
it('ignores invalid columns', () => { | ||
const arbitraryRowIndex = 6; | ||
const result = fn(testTable, { | ||
include: 'name, foo, bar', | ||
}); | ||
|
||
expect(result.columns[0]).to.have.property('name', 'name'); | ||
expect(result.rows[arbitraryRowIndex]) | ||
.to.have.property('name', testTable.rows[arbitraryRowIndex].name) | ||
.and.to.not.have.property('foo') | ||
.and.to.not.have.property('bar'); | ||
}); | ||
|
||
it('returns an empty datable if include only has invalid columns', () => { | ||
expect(fn(testTable, { include: 'foo, bar' })).to.eql(emptyTable); | ||
}); | ||
}); | ||
|
||
describe('exclude', () => { | ||
it('returns a datatable without excluded columns', () => { | ||
const arbitraryRowIndex = 5; | ||
const result = fn(testTable, { exclude: 'price, quantity, foo, bar' }); | ||
|
||
expect(result.columns.length).to.equal(testTable.columns.length - 2); | ||
expect(Object.keys(result.rows[0])).to.have.length(testTable.columns.length - 2); | ||
expect(result.rows[arbitraryRowIndex]) | ||
.to.not.have.property('price') | ||
.and.to.not.have.property('quantity') | ||
.and.to.not.have.property('foo') | ||
.and.to.not.have.property('bar'); | ||
}); | ||
|
||
it('ignores invalid columns', () => { | ||
const arbitraryRowIndex = 1; | ||
const result = fn(testTable, { exclude: 'time, foo, bar' }); | ||
|
||
expect(result.columns.length).to.equal(testTable.columns.length - 1); | ||
expect(result.rows[arbitraryRowIndex]) | ||
.to.not.have.property('time') | ||
.and.to.not.have.property('foo') | ||
.and.to.not.have.property('bar'); | ||
}); | ||
|
||
it('returns original context if exclude only references invalid column name(s)', () => { | ||
expect(fn(testTable, { exclude: 'foo, bar, fizz, buzz' })).to.eql(testTable); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.