@tsmx/json-traverse
Version:
Traverse and manipulate JSON objects.
224 lines (210 loc) • 10.3 kB
JavaScript
describe('json-traverse test suite', () => {
const jt = require('../json-traverse');
var testOutput = [];
const originalConsoleLog = console.log;
const testConsoleLog = (output) => { testOutput.push(output); };
var simpleTestObj = {};
var complexTestObj = {};
var htmlTestobj = {};
beforeEach(() => {
simpleTestObj = {
'MyValue': 'test',
'OtherValue': 'zzz',
'NumberValue': 311,
'MyArray': [1, 2, 3, 50, 60, 70]
};
complexTestObj = {
'arr': [0, 0],
'arr-in-arr': [0, 1, ['two', 'three', [4, 5, 6]]],
'number': 123,
'string': 'ttt',
'parent': {
'test': 1,
'child': {
'childval': 777
},
'array': [1, 2, 66, 9, { 'array-sub-key': 'zzz', 'array-in-array': ['a', 'b', 'c'] }, 900]
},
'trail': 'testtesttest'
};
htmlTestobj = {
'arr': [0, 0],
'arr-in-arr': [0, 1, ['two', 'three', [4, 5, 6]]],
'number': 123,
'string': 'test',
'parent': {
'test': 1,
'child': {
'childval': 777
},
'array': [1, 2, 66, 9, 900]
},
'trail': 'testtesttest'
};
console.log = testConsoleLog;
testOutput = [];
});
afterEach(() => {
console.log = originalConsoleLog;
});
it('tests a manipulation of plain properties and array entries', async () => {
const callbacksChangeValue = {
processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => {
if (key.startsWith('My')) {
cbSetValue('MyNew-' + value);
}
if (isArrayElement && parseInt(value) > 50) {
cbSetValue(100 * parseInt(value));
}
}
};
jt.traverse(simpleTestObj, callbacksChangeValue);
expect(simpleTestObj.MyValue).toBe('MyNew-test');
expect(simpleTestObj.OtherValue).toBe('zzz');
expect(simpleTestObj.NumberValue).toBe(311);
expect(simpleTestObj.MyArray.length).toBe(6);
expect(simpleTestObj.MyArray[0]).toBe(1);
expect(simpleTestObj.MyArray[1]).toBe(2);
expect(simpleTestObj.MyArray[2]).toBe(3);
expect(simpleTestObj.MyArray[3]).toBe(50);
expect(simpleTestObj.MyArray[4]).toBe(6000);
expect(simpleTestObj.MyArray[5]).toBe(7000);
});
it('tests a full traversal of a complex JSON object', async () => {
const callbacks = {
processValue: (key, value, level, path, _isObjectRoot, _isArrayElement) => {
console.log(level + ' ' + (path.length > 0 ? (path.join('.') + '.') : '') + key + ' = ' + value);
},
enterLevel: (level, _path) => { console.log('Entering level ' + level + '...'); },
exitLevel: (level, _path) => { console.log('Leaving level ' + level + '...'); }
};
jt.traverse(complexTestObj, callbacks);
expect(testOutput.length).toBe(37);
expect(testOutput[0]).toBe('Entering level 0...');
expect(testOutput[1]).toBe('0 arr._0 = 0');
expect(testOutput[2]).toBe('0 arr._1 = 0');
expect(testOutput[3]).toBe('0 arr-in-arr._0 = 0');
expect(testOutput[4]).toBe('0 arr-in-arr._1 = 1');
expect(testOutput[5]).toBe('0 arr-in-arr._2 = two,three,4,5,6');
expect(testOutput[6]).toBe('Entering level 1...');
expect(testOutput[7]).toBe('1 arr-in-arr._2.0 = two');
expect(testOutput[8]).toBe('1 arr-in-arr._2.1 = three');
expect(testOutput[9]).toBe('1 arr-in-arr._2.2._0 = 4');
expect(testOutput[10]).toBe('1 arr-in-arr._2.2._1 = 5');
expect(testOutput[11]).toBe('1 arr-in-arr._2.2._2 = 6');
expect(testOutput[12]).toBe('Leaving level 1...');
expect(testOutput[13]).toBe('0 number = 123');
expect(testOutput[14]).toBe('0 string = ttt');
expect(testOutput[15]).toBe('0 parent = [object Object]');
expect(testOutput[16]).toBe('Entering level 1...');
expect(testOutput[17]).toBe('1 parent.test = 1');
expect(testOutput[18]).toBe('1 parent.child = [object Object]');
expect(testOutput[19]).toBe('Entering level 2...');
expect(testOutput[20]).toBe('2 parent.child.childval = 777');
expect(testOutput[21]).toBe('Leaving level 2...');
expect(testOutput[22]).toBe('1 parent.array._0 = 1');
expect(testOutput[23]).toBe('1 parent.array._1 = 2');
expect(testOutput[24]).toBe('1 parent.array._2 = 66');
expect(testOutput[25]).toBe('1 parent.array._3 = 9');
expect(testOutput[26]).toBe('1 parent.array._4 = [object Object]');
expect(testOutput[27]).toBe('Entering level 2...');
expect(testOutput[28]).toBe('2 parent.array._4.array-sub-key = zzz');
expect(testOutput[29]).toBe('2 parent.array._4.array-in-array._0 = a');
expect(testOutput[30]).toBe('2 parent.array._4.array-in-array._1 = b');
expect(testOutput[31]).toBe('2 parent.array._4.array-in-array._2 = c');
expect(testOutput[32]).toBe('Leaving level 2...');
expect(testOutput[33]).toBe('1 parent.array._5 = 900');
expect(testOutput[34]).toBe('Leaving level 1...');
expect(testOutput[35]).toBe('0 trail = testtesttest');
expect(testOutput[36]).toBe('Leaving level 0...');
});
it('tests a conversion to a HTML list of a complex JSON object', async () => {
const callbacksHtml = {
processValue: (key, value, level, path, isObjectRoot, _isArrayElement) => {
if (isObjectRoot) {
console.log((' ').repeat(level) + ' <li class="caret">Key: ' + key + '</li>');
}
else {
console.log((' ').repeat(level) + ' <li>Key: ' + key + ', Value: ' + value + '</li>');
}
},
enterLevel: (level, _path) => {
if (level == 0) {
console.log('<ul>');
}
else {
console.log((' ').repeat(level) + '<ul class="nested">');
}
},
exitLevel: (level, _path) => { console.log((' ').repeat(level) + '</ul>'); }
};
jt.traverse(htmlTestobj, callbacksHtml, true);
expect(testOutput.length).toBe(16);
expect(testOutput[0]).toBe('<ul>');
expect(testOutput[1]).toBe(' <li>Key: arr, Value: 0,0</li>');
expect(testOutput[2]).toBe(' <li>Key: arr-in-arr, Value: 0,1,two,three,4,5,6</li>');
expect(testOutput[3]).toBe(' <li>Key: number, Value: 123</li>');
expect(testOutput[4]).toBe(' <li>Key: string, Value: test</li>');
expect(testOutput[5]).toBe(' <li class="caret">Key: parent</li>');
expect(testOutput[6]).toBe(' <ul class="nested">');
expect(testOutput[7]).toBe(' <li>Key: test, Value: 1</li>');
expect(testOutput[8]).toBe(' <li class="caret">Key: child</li>');
expect(testOutput[9]).toBe(' <ul class="nested">');
expect(testOutput[10]).toBe(' <li>Key: childval, Value: 777</li>');
expect(testOutput[11]).toBe(' </ul>');
expect(testOutput[12]).toBe(' <li>Key: array, Value: 1,2,66,9,900</li>');
expect(testOutput[13]).toBe(' </ul>');
expect(testOutput[14]).toBe(' <li>Key: trail, Value: testtesttest</li>');
expect(testOutput[15]).toBe('</ul>');
});
it('tests a traversal with no callbacks for a simple object - nothing should happen', async () => {
const before = JSON.stringify(simpleTestObj);
jt.traverse(simpleTestObj);
const after = JSON.stringify(simpleTestObj);
expect(after).toBe(before);
expect(testOutput.length).toBe(0);
});
it('tests a traversal with no callbacks for a complex object - nothing should happen', async () => {
const before = JSON.stringify(complexTestObj);
jt.traverse(complexTestObj);
const after = JSON.stringify(complexTestObj);
expect(after).toBe(before);
expect(testOutput.length).toBe(0);
});
it('tests a manipulation of nested object in an array', async () => {
const callbacksChangeValue = {
processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => {
if (key == 'array-sub-key') {
cbSetValue('ttt');
}
}
};
expect(complexTestObj.parent.array[4]['array-sub-key']).toBe('zzz');
jt.traverse(complexTestObj, callbacksChangeValue);
expect(complexTestObj.parent.array[4]['array-sub-key']).toBe('ttt');
});
it('tests a complete exchange of nested object in an array', async () => {
const callbacksChangeValue = {
processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => {
if (isArrayElement && isObjectRoot) {
cbSetValue({ objname: 'new-object' });
}
}
};
expect(JSON.stringify(complexTestObj.parent.array[4])).toBe(JSON.stringify({ 'array-sub-key': 'zzz', 'array-in-array': ['a', 'b', 'c'] }));
jt.traverse(complexTestObj, callbacksChangeValue);
expect(JSON.stringify(complexTestObj.parent.array[4])).toBe(JSON.stringify({ objname: 'new-object' }));
});
it('tests a complete exchange of nested object', async () => {
const callbacksChangeValue = {
processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => {
if (key == 'child' && !isArrayElement && isObjectRoot) {
cbSetValue({ objname: 'new-object' });
}
}
};
expect(JSON.stringify(complexTestObj.parent.child)).toBe(JSON.stringify({ childval: 777 }));
jt.traverse(complexTestObj, callbacksChangeValue);
expect(JSON.stringify(complexTestObj.parent.child)).toBe(JSON.stringify({ objname: 'new-object' }));
});
});