MetaPhase-Consulting/State-TalentMAP

View on GitHub
src/Constants/Menu.test.js

Summary

Maintainability
A
0 mins
Test Coverage
import { compact, forOwn, has, isArray, isBoolean, isNumber, isObject, isString, keys, pickBy } from 'lodash';
import { GET_PROFILE_MENU } from './Menu';

/**
 * Utility function that verifies if objects contains
 * all keys in array of keys passed
 * @param {object} item Object with keys values
 * @param {array} keys Array of keys to search for
 * @returns {boolean} Whether all keys exists
 * @example
 *
 * hasKeys({ key1: 'value1', key2: 'value2' }, ['key2', 'key3'])
 * // => false
 */
function hasKeys(item, searchKeys) {
  const result = compact( // Removes false values from array
    // Maps array to result of has()
    searchKeys.map(key => has(item, key)),
  );

  return (result.length === keys.length);
}

describe('Menu', () => {
  /**
   * @interface Rule
   *  interface Rule {
   *    type: 'boolean'|'number'|'array'|'string'|'object'
   *    required: boolean,
   *  }
   */
  const rules = {
    text: { type: 'string', required: true },
    icon: { type: 'string', required: false },
    route: { type: 'string', required: false },
    params: { type: 'string', required: false },
    toggleMenuSection: { type: 'boolean', required: false },
    expandedSection: { type: 'boolean', required: false },
    roles: { type: 'array', required: false },
    isGlossaryEditor: { type: 'boolean', required: false },
    children: { type: 'array', required: false },
  };

  const types = {
    array: isArray,
    boolean: isBoolean,
    number: isNumber,
    object: isObject,
    string: isString,
  };

  it('Verify GET_PROFILE_MENU contains required options', () => {
    const requiredRules = pickBy(rules, item => item.required);
    const requiredKeys = keys(requiredRules);
    const expectAllToContainRequired = (items) => {
      items.forEach((item) => {
        expect(hasKeys(item, requiredKeys)).toBeDefined();

        if (isArray(item.children)) {
          expectAllToContainRequired(item.children);
        }
      });
    };

    expectAllToContainRequired(GET_PROFILE_MENU());
  });

  it('Verify GET_PROFILE_MENU contains valid option values', () => {
    /**
     * Iterates through object keys and validates against rule definitions
     * @param  {object} item value
     * @return {boolean}     validation result
     */
    const validateRules = (item) => {
      let rule;
      let type;
      let validate;

      forOwn(item, (value, key) => {
        rule = rules[key];
        type = rule.type;
        validate = types[type];

        // console.log([key, rule, type, value, validate]);
        // If tests fail, use: console.log([key, type, value, validate(value)]);
        if (!validate(value)) {
          return false;
        }

        return true;
      });

      return true;
    };

    const expectAllToValidate = (items) => {
      items.forEach((item) => {
        // If tests fail, use: console.log([key, validateRules(item)]);
        expect(validateRules(item)).toBe(true);

        if (isArray(item.children)) {
          expectAllToValidate(item.children);
        }
      });
    };

    expectAllToValidate(GET_PROFILE_MENU());
  });
});