Add spec tests for field helpers
parent
4e8e9b6cb2
commit
4797361622
|
@ -1,10 +1,77 @@
|
|||
import {numFunctions} from 'shared/reducers/helpers/field'
|
||||
import _ from 'lodash'
|
||||
import {
|
||||
fieldWalk,
|
||||
removeField,
|
||||
getFieldsDeep,
|
||||
fieldNamesDeep,
|
||||
} from 'shared/reducers/helpers/fields'
|
||||
|
||||
describe('Formatting helpers', () => {
|
||||
describe('formatBytes', () => {
|
||||
it('returns null when passed a falsey value', () => {
|
||||
const actual = numFunctions(null)
|
||||
expect(actual).to.equal(0)
|
||||
describe('field helpers', () => {
|
||||
it('can walk all fields and get all names', () => {
|
||||
const fields = [
|
||||
{
|
||||
name: 'fn1',
|
||||
type: 'func',
|
||||
args: [{name: 'f1', type: 'func', args: [{name: 'f2', type: 'field'}]}],
|
||||
},
|
||||
{name: 'fn1', type: 'func', args: [{name: 'f2', type: 'field'}]},
|
||||
{name: 'fn2', type: 'func', args: [{name: 'f2', type: 'field'}]},
|
||||
]
|
||||
const actual = fieldWalk(fields, f => _.get(f, 'name'))
|
||||
expect(actual).to.deep.equal(['fn1', 'f1', 'f2', 'fn1', 'f2', 'fn2', 'f2'])
|
||||
})
|
||||
|
||||
it('can return all unique fields for type field', () => {
|
||||
const fields = [
|
||||
{
|
||||
name: 'fn1',
|
||||
type: 'func',
|
||||
args: [{name: 'f1', type: 'func', args: [{name: 'f2', type: 'field'}]}],
|
||||
},
|
||||
{name: 'fn1', type: 'func', args: [{name: 'f2', type: 'field'}]},
|
||||
{name: 'fn2', type: 'func', args: [{name: 'f2', type: 'field'}]},
|
||||
]
|
||||
const actual = getFieldsDeep(fields)
|
||||
expect(actual).to.deep.equal([{name: 'f2', type: 'field'}])
|
||||
})
|
||||
|
||||
it('can return all unique field names for type field', () => {
|
||||
const fields = [
|
||||
{
|
||||
name: 'fn1',
|
||||
type: 'func',
|
||||
args: [{name: 'f1', type: 'func', args: [{name: 'f2', type: 'field'}]}],
|
||||
},
|
||||
{name: 'fn1', type: 'func', args: [{name: 'f2', type: 'field'}]},
|
||||
{name: 'fn2', type: 'func', args: [{name: 'f2', type: 'field'}]},
|
||||
]
|
||||
const actual = fieldNamesDeep(fields)
|
||||
expect(actual).to.deep.equal(['f2'])
|
||||
})
|
||||
|
||||
describe('removeField', () => {
|
||||
it('can remove fields at any level of the tree', () => {
|
||||
const fields = [
|
||||
{
|
||||
name: 'fn1',
|
||||
type: 'func',
|
||||
args: [
|
||||
{name: 'f1', type: 'func', args: [{name: 'f2', type: 'field'}]},
|
||||
],
|
||||
},
|
||||
{name: 'fn2', type: 'func', args: [{name: 'f2', type: 'field'}]},
|
||||
{name: 'fn3', type: 'func', args: [{name: 'f3', type: 'field'}]},
|
||||
]
|
||||
const actual = removeField('f2', fields)
|
||||
expect(actual).to.deep.equal([
|
||||
{name: 'fn3', type: 'func', args: [{name: 'f3', type: 'field'}]},
|
||||
])
|
||||
})
|
||||
|
||||
it('can remove fields from a flat field list', () => {
|
||||
const fields = [{name: 'f1', type: 'field'}, {name: 'f2', type: 'field'}]
|
||||
const actual = removeField('f2', fields)
|
||||
expect(actual).to.deep.equal([{name: 'f1', type: 'field'}])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
import _ from 'lodash'
|
||||
|
||||
// fieldWalk traverses fields rescursively into args
|
||||
export const fieldWalk = (fields, fn) =>
|
||||
fields.each(f => _.concat(fn(f), fieldWalk(_.get(f, 'args', []), fn)))
|
||||
// fieldWalk traverses fields rescursively into args mapping fn on every
|
||||
// field
|
||||
export const fieldWalk = (fields, fn, acc = []) =>
|
||||
_.compact(
|
||||
_.flattenDeep(
|
||||
fields.reduce((a, f) => {
|
||||
return [...a, fn(f), fieldWalk(_.get(f, 'args', []), fn, acc)]
|
||||
}, acc)
|
||||
)
|
||||
)
|
||||
|
||||
// functions returns all top-level fields with type
|
||||
export const ofType = (fields, type) =>
|
||||
|
@ -20,11 +27,14 @@ export const functionNames = fields => functions(fields).map(f => f.name)
|
|||
// getFields returns all of the top-level fields of type field
|
||||
export const getFields = fields => ofType(fields, 'field')
|
||||
|
||||
export const fieldsDeep = fields =>
|
||||
_.uniqBy(fieldWalk(fields, f => getFields(f)), 'name')
|
||||
export const getFieldsDeep = fields =>
|
||||
_.uniqBy(
|
||||
fieldWalk(fields, f => (_.get(f, 'type') === 'field' ? f : null)),
|
||||
'name'
|
||||
)
|
||||
|
||||
export const fieldNamesDeep = fields =>
|
||||
fieldsDeep(fields).map(f => _.get(f, 'name'))
|
||||
getFieldsDeep(fields).map(f => _.get(f, 'name'))
|
||||
|
||||
// firstFieldName returns the name of the first of type field
|
||||
export const firstFieldName = fields => _.head(fieldNamesDeep(fields))
|
||||
|
@ -43,17 +53,18 @@ export const everyField = fields => everyOfType(fields, 'field')
|
|||
export const everyFunction = fields => everyOfType(fields, 'func')
|
||||
|
||||
// removeField will remove the field or function from the field list with the
|
||||
// given fieldName
|
||||
// given fieldName. Preconditions: only type field OR only type func
|
||||
export const removeField = (fieldName, fields) => {
|
||||
if (everyField(fields)) {
|
||||
return fields.filter(f => f.name !== fieldName)
|
||||
}
|
||||
|
||||
return fields.reduce((acc, f) => {
|
||||
const has = fieldNamesDeep(f.args).some(n => n.name === fieldName)
|
||||
const has = fieldNamesDeep(f.args).some(n => n === fieldName)
|
||||
if (has) {
|
||||
return [...acc, f]
|
||||
return acc
|
||||
}
|
||||
return acc
|
||||
|
||||
return [...acc, f]
|
||||
}, [])
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue