diff --git a/README.md b/README.md index c4391d52..ba29c9ac 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,21 @@ For this project, we're using: * We don't use camel case for file naming but in everything Javascript related * We use `let` instead of `var`: [SA Post](http://stackoverflow.com/questions/762011/javascript-let-keyword-vs-var-keyword) +Testing +=============== +We're using Facebook's jest to do testing as it integrates nicely with react.js as well. + +Tests are always created per directory by creating a `__tests__` folder. To test a specific file, a `_tests.js` file needs to be created. + +Since we're using mixed syntax, test files are not linted using ES6Lint. +This is due to the fact that jest's function mocking and ES6 module syntax are [fundamentally incompatible](https://github.com/babel/babel-jest/issues/16). + +Therefore, to require a module in your test file, you need to use CommonJS's `require` syntax. Except for this, all tests can be written in ES6 syntax. + +## Workflow +Generally, when you're runing `gulp serve`, all tests are being run. +If you want to test exclusively (without having the obnoxious ES6Linter warnings), you can just run `gulp jest:watch`. + Troubleshooting =============== diff --git a/js/utils/__tests__/general_utils_test.js b/js/utils/__tests__/general_utils_test.js index 5edb50df..9b37782c 100644 --- a/js/utils/__tests__/general_utils_test.js +++ b/js/utils/__tests__/general_utils_test.js @@ -1,9 +1,70 @@ -jest.dontMock('../general_utils'); +jest.dontMock('../general_utils.js'); -import * as GeneralUtils from '../general_utils'; + +let GeneralUtils = require('../general_utils') + +let sanitize = GeneralUtils.sanitize; +let sumNumList = GeneralUtils.sumNumList; +let formatText = GeneralUtils.formatText; +let mergeOptions = GeneralUtils.mergeOptions; describe('GeneralUtils', () => { - it('should do something', () => { - return false; + it('should sanitize object (delete all empty strings, null and undefined values)', () => { + let obj = { + definedValue: 1, + undefinedValue: undefined, + nullValue: null, + emptyString: '', + notEmptyString: 'Something else' + }; + + let sanitizedObj = sanitize(obj); + expect(sanitizedObj.definedValue).toBeDefined(); + expect(sanitizedObj.notEmptyString).toBeDefined(); + expect(sanitizedObj.undefinedValue).toBeUndefined(); + expect(sanitizedObj.nullValue).toBeUndefined(); + expect(sanitizedObj.emptyString).toBeUndefined(); + }); + + it('should sum up all values of a list', () => { + expect(sumNumList([1,2,3])).toBe(6); + expect(sumNumList([1,-2,3])).toBe(2); + expect(sumNumList(['string',2,3])).toBe(5); + expect(sumNumList([0,0,0])).toBe(0); + expect(sumNumList([() => 'asdasd',2,3])).toBe(5); + }); + + it('should format a string with inline variables to a plain string using an arbitrary number of arguments', () => { + expect(formatText('Number %d', 1)).toBe('Number 1'); + expect(formatText('Number %s', 1)).toBe('Number 1'); + expect(formatText('Number %d %s', '1', 2)).toBe('Number 1 2'); + expect(formatText('Number %d %d %d %s %d %d %d', 1, 2, 3, 4, 5, 6, 7)).toBe('Number 1 2 3 4 5 6 7'); + }); + + it('should merge n objects keys and values and throw an error on matching-keys-overwrite', () => { + let obj1 = { + name: 'Obj1', + someValue: 'hello' + }; + let obj2 = { + othername: 'Obj2', + someValue: 'world' + }; + let obj3 = { + othername: 'Obj3', + someFn: () => parseFloat(0.9), + numberValue: 2 + }; + + expect(() => mergeOptions(obj1, obj2)).toThrow(); + + // jasmine actually does a deep comparison for functions as well + expect(mergeOptions(obj1, obj3)).toEqual({ + name: obj1.name, + someValue: obj1.someValue, + othername: obj3.othername, + someFn: obj3.someFn, + numberValue: obj3.numberValue + }); }); }); \ No newline at end of file diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 4caf3d15..a323b65d 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -2,6 +2,17 @@ // TODO: Create Unittests that test all functions +/** + * Takes an object and deletes all keys that are + * + * - empty strings; or + * - null; or + * - undefined + * + * + * @param {object} obj regular javascript object + * @return {object} regular javascript object without null values or empty strings + */ export function sanitize(obj) { Object .keys(obj) @@ -16,15 +27,6 @@ export function sanitize(obj) { return obj; } -/** - * Returns the values of an object. - */ -export function valuesOfObject(obj) { - return Object - .keys(obj) - .map(key => obj[key]); -} - /** * Sums up a list of numbers. Like a Epsilon-math-kinda-sum... */ @@ -37,17 +39,14 @@ export function sumNumList(l) { /* Taken from http://stackoverflow.com/a/4795914/1263876 Behaves like C's format string function - - REFACTOR TO ES6 (let instead of var) - */ export function formatText() { - var args = arguments, + let args = arguments, string = args[0], i = 1; - return string.replace(/%((%)|s|d)/g, function (m) { + return string.replace(/%((%)|s|d)/g, (m) => { // m is the matched format, e.g. %s, %d - var val = null; + let val = null; if (m[2]) { val = m[2]; } else { @@ -79,7 +78,6 @@ export function mergeOptions(...l) { for(let i = 1; i < l.length; i++) { newObj = _mergeOptions(newObj, _mergeOptions(l[i - 1], l[i])); } - return newObj; } @@ -92,7 +90,16 @@ export function mergeOptions(...l) { */ function _mergeOptions(obj1, obj2){ let obj3 = {}; - for (let attrname in obj1) { obj3[attrname] = obj1[attrname]; } - for (let attrname in obj2) { obj3[attrname] = obj2[attrname]; } + + for (let attrname in obj1) { + obj3[attrname] = obj1[attrname]; + } + for (let attrname in obj2) { + if(attrname in obj3) { + throw Error('Overwrite Conflict: You\'re merging two objects with the same keys: ' + attrname); + } else { + obj3[attrname] = obj2[attrname]; + } + } return obj3; }