216 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			216 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|   | import test from 'tape'; | ||
|  | import sinon from 'sinon'; | ||
|  | 
 | ||
|  | import { | ||
|  |   getNode, | ||
|  |   createMapUi, | ||
|  |   traverseMapUi, | ||
|  |   updateSingleNode, | ||
|  |   toggleThisPanel, | ||
|  |   expandAllPanels, | ||
|  |   collapseAllPanels | ||
|  | } from './utils.js'; | ||
|  | 
 | ||
|  | test('createMapUi', t => { | ||
|  |   t.plan(3); | ||
|  |   t.test('should return an `{}` when proper args not supplied', t => { | ||
|  |     t.plan(3); | ||
|  |     t.equal( | ||
|  |       Object.keys(createMapUi()).length, | ||
|  |       0 | ||
|  |     ); | ||
|  |     t.equal( | ||
|  |       Object.keys(createMapUi({}, [])).length, | ||
|  |       0 | ||
|  |     ); | ||
|  |     t.equal( | ||
|  |       Object.keys(createMapUi({ superBlock: {} }, [])).length, | ||
|  |       0 | ||
|  |     ); | ||
|  |   }); | ||
|  |   t.test('should return a map tree', t => { | ||
|  |     const expected = { | ||
|  |       children: [{ | ||
|  |         name: 'superBlockA', | ||
|  |         children: [{ | ||
|  |           name: 'blockA', | ||
|  |           children: [{ | ||
|  |             name: 'challengeA' | ||
|  |           }] | ||
|  |         }] | ||
|  |       }] | ||
|  |     }; | ||
|  |     const actual = createMapUi({ | ||
|  |       superBlock: { | ||
|  |         superBlockA: { | ||
|  |           blocks: [ | ||
|  |             'blockA' | ||
|  |           ] | ||
|  |         } | ||
|  |       }, | ||
|  |       block: { | ||
|  |         blockA: { | ||
|  |           challenges: [ | ||
|  |             'challengeA' | ||
|  |           ] | ||
|  |         } | ||
|  |       } | ||
|  |     }, | ||
|  |     { superBlocks: ['superBlockA'] }, | ||
|  |     { challengeA: 'ChallengeA title'} | ||
|  |   ); | ||
|  |     t.plan(3); | ||
|  |     t.equal(actual.children[0].name, expected.children[0].name); | ||
|  |     t.equal( | ||
|  |       actual.children[0].children[0].name, | ||
|  |       expected.children[0].children[0].name | ||
|  |     ); | ||
|  |     t.equal( | ||
|  |       actual.children[0].children[0].children[0].name, | ||
|  |       expected.children[0].children[0].children[0].name | ||
|  |     ); | ||
|  |   }); | ||
|  |   t.test('should protect against malformed data', t => { | ||
|  |     t.plan(2); | ||
|  |     t.equal( | ||
|  |       createMapUi({ | ||
|  |         superBlock: {}, | ||
|  |         block: { | ||
|  |           blockA: { | ||
|  |             challenges: [ | ||
|  |               'challengeA' | ||
|  |             ] | ||
|  |           } | ||
|  |         } | ||
|  |       }, { superBlocks: ['superBlockA'] }).children[0].children.length, | ||
|  |       0 | ||
|  |     ); | ||
|  |     t.equal( | ||
|  |       createMapUi({ | ||
|  |         superBlock: { | ||
|  |           superBlockA: { | ||
|  |             blocks: [ | ||
|  |               'blockA' | ||
|  |             ] | ||
|  |           } | ||
|  |         }, | ||
|  |         block: {} | ||
|  |       }, | ||
|  |       { superBlocks: ['superBlockA'] }).children[0].children[0].children.length, | ||
|  |       0 | ||
|  |     ); | ||
|  |   }); | ||
|  | }); | ||
|  | test('traverseMapUi', t => { | ||
|  |   t.test('should return tree', t => { | ||
|  |     t.plan(2); | ||
|  |     const expectedTree = {}; | ||
|  |     const actaulTree = traverseMapUi(expectedTree, tree => { | ||
|  |       t.equal(tree, expectedTree); | ||
|  |       return tree; | ||
|  |     }); | ||
|  |     t.equal(actaulTree, expectedTree); | ||
|  |   }); | ||
|  |   t.test('should hit every node', t => { | ||
|  |     t.plan(4); | ||
|  |     const expected = { children: [{ children: [{}] }] }; | ||
|  |     const spy = sinon.spy(t => t); | ||
|  |     spy.withArgs(expected); | ||
|  |     spy.withArgs(expected.children[0]); | ||
|  |     spy.withArgs(expected.children[0].children[0]); | ||
|  |     traverseMapUi(expected, spy); | ||
|  |     t.equal(spy.callCount, 3); | ||
|  |     t.ok(spy.withArgs(expected).calledOnce, 'foo'); | ||
|  |     t.ok(spy.withArgs(expected.children[0]).calledOnce, 'bar'); | ||
|  |     t.ok(spy.withArgs(expected.children[0].children[0]).calledOnce, 'baz'); | ||
|  |   }); | ||
|  |   t.test('should create new object when children change', t => { | ||
|  |     t.plan(9); | ||
|  |     const expected = { children: [{ bar: true }, {}] }; | ||
|  |     const actual = traverseMapUi(expected, node => ({ ...node, foo: true })); | ||
|  |     t.notEqual(actual, expected); | ||
|  |     t.notEqual(actual.children, expected.children); | ||
|  |     t.notEqual(actual.children[0], expected.children[0]); | ||
|  |     t.notEqual(actual.children[1], expected.children[1]); | ||
|  |     t.equal(actual.children[0].bar, expected.children[0].bar); | ||
|  |     t.notOk(expected.children[0].foo); | ||
|  |     t.notOk(expected.children[1].foo); | ||
|  |     t.true(actual.children[0].foo); | ||
|  |     t.true(actual.children[1].foo); | ||
|  |   }); | ||
|  | }); | ||
|  | test('getNode', t => { | ||
|  |   t.test('should return node', t => { | ||
|  |     t.plan(1); | ||
|  |     const expected = { name: 'foo' }; | ||
|  |     const tree = { children: [{ name: 'notfoo' }, expected ] }; | ||
|  |     const actual = getNode(tree, 'foo'); | ||
|  |     t.equal(expected, actual); | ||
|  |   }); | ||
|  |   t.test('should returned undefined if not found', t => { | ||
|  |     t.plan(1); | ||
|  |     const tree = { | ||
|  |       children: [ { name: 'foo' }, { children: [ { name: 'bar' } ] } ] | ||
|  |     }; | ||
|  |     const actual = getNode(tree, 'baz'); | ||
|  |     t.notOk(actual); | ||
|  |   }); | ||
|  | }); | ||
|  | test('updateSingleNode', t => { | ||
|  |   t.test('should update single node', t => { | ||
|  |     const expected = { name: 'foo' }; | ||
|  |     const untouched = { name: 'notFoo' }; | ||
|  |     const actual = updateSingleNode( | ||
|  |       { children: [ untouched, expected ] }, | ||
|  |       'foo', | ||
|  |       node => ({ ...node, tag: true }) | ||
|  |     ); | ||
|  |     t.plan(4); | ||
|  |     t.ok(actual.children[1].tag); | ||
|  |     t.equal(actual.children[1].name, expected.name); | ||
|  |     t.notEqual(actual.children[1], expected); | ||
|  |     t.equal(actual.children[0], untouched); | ||
|  |   }); | ||
|  | }); | ||
|  | test('toggleThisPanel', t => { | ||
|  |   t.test('should update single node', t => { | ||
|  |     const expected = { name: 'foo', isOpen: true }; | ||
|  |     const actual = toggleThisPanel( | ||
|  |       { children: [ { name: 'foo', isOpen: false }] }, | ||
|  |       'foo' | ||
|  |     ); | ||
|  |     t.plan(1); | ||
|  |     t.deepLooseEqual(actual.children[0], expected); | ||
|  |   }); | ||
|  | }); | ||
|  | test('toggleAllPanels', t => { | ||
|  |   t.test('should add `isOpen: true` to every node without children', t => { | ||
|  |     const expected = { | ||
|  |       isOpen: true, | ||
|  |       children: [{ | ||
|  |         isOpen: true, | ||
|  |         children: [{}, {}] | ||
|  |       }] | ||
|  |     }; | ||
|  |     const actual = expandAllPanels({ children: [{ children: [{}, {}] }] }); | ||
|  |     t.plan(1); | ||
|  |     t.deepLooseEqual(actual, expected); | ||
|  |   }); | ||
|  |   t.test('should add `isOpen: false` to every node without children', t => { | ||
|  |     const leaf = {}; | ||
|  |     const expected = { | ||
|  |       isOpen: false, | ||
|  |       children: [{ | ||
|  |         isOpen: false, | ||
|  |         children: [{}, leaf] | ||
|  |       }] | ||
|  |     }; | ||
|  |     const actual = collapseAllPanels( | ||
|  |       { isOpen: true, children: [{ children: [{}, leaf]}]}, | ||
|  |     ); | ||
|  |     t.plan(2); | ||
|  |     t.deepLooseEqual(actual, expected); | ||
|  |     t.equal(actual.children[0].children[1], leaf); | ||
|  |   }); | ||
|  | }); |