amzn/style-dictionary

View on GitHub
__tests__/utils/resolveObject.test.js

Summary

Maintainability
F
3 days
Test Coverage
/*
 * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
 * the License. A copy of the License is located at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
 * and limitations under the License.
 */

var resolveObject = require('../../lib/utils/resolveObject');
var helpers = require('../__helpers');
var GroupMessages = require('../../lib/utils/groupMessages');

var PROPERTY_REFERENCE_WARNINGS = GroupMessages.GROUP.PropertyReferenceWarnings;

describe('utils', () => {
  describe('resolveObject', () => {

    it('should error on non-objects', () => {
      expect(
        resolveObject.bind(null)
      ).toThrow('Please pass an object in');
      expect(
        resolveObject.bind(null, 'foo')
      ).toThrow('Please pass an object in');
      expect(
        resolveObject.bind(null, 0)
      ).toThrow('Please pass an object in');
    });

    it('should not mutate the original object', () => {
      var original = helpers.fileToJSON(__dirname + '/../__json_files/nested_references.json');
      var test = resolveObject( original );
      expect(original).toHaveProperty('a.b.d', '{e.f.g}');
      expect(test).toHaveProperty('a.b.d', 2);
    });

    it('should do simple references', () => {
      var test = resolveObject( helpers.fileToJSON(__dirname + '/../__json_files/simple.json') );
      expect(test).toHaveProperty('bar', 'bar');
    });

    it('should do nested references', () => {
      var obj = helpers.fileToJSON(__dirname + '/../__json_files/nested_references.json');
      var test = resolveObject( obj );
      expect(test).toHaveProperty('i', 2);
      expect(test).toHaveProperty('a.b.d', 2);
      expect(test).toHaveProperty('e.f.h', 1);
    });

    it('should handle nested pointers', () => {
      var test = resolveObject( helpers.fileToJSON(__dirname + '/../__json_files/nested_pointers.json') );
      expect(test).toHaveProperty('b', 1);
      expect(test).toHaveProperty('c', 1);
    });

    it('should handle deep nested pointers', () => {
      var test = resolveObject( helpers.fileToJSON(__dirname + '/../__json_files/nested_pointers_2.json') );
      expect(test).toHaveProperty('a', 1);
      expect(test).toHaveProperty('b', 1);
      expect(test).toHaveProperty('c', 1);
      expect(test).toHaveProperty('d', 1);
      expect(test).toHaveProperty('e', 1);
      expect(test).toHaveProperty('f', 1);
      expect(test).toHaveProperty('g', 1);
    });

    it('should handle deep nested pointers with string interpolation', () => {
        var test = resolveObject( helpers.fileToJSON(__dirname + '/../__json_files/nested_pointers_3.json') );
        expect(test).toHaveProperty('a', 'foo bon bee bae boo bla baz bar');
        expect(test).toHaveProperty('b', 'foo bon bee bae boo bla baz');
        expect(test).toHaveProperty('c', 'foo bon bee bae boo bla');
        expect(test).toHaveProperty('d', 'foo bon bee bae boo');
        expect(test).toHaveProperty('e', 'foo bon bee bae');
        expect(test).toHaveProperty('f', 'foo bon bee');
        expect(test).toHaveProperty('g', 'foo bon');
      }
    );

    it('should handle deep nested pointers and nested references', () => {
      var test = resolveObject( helpers.fileToJSON(__dirname + '/../__json_files/nested_pointers_4.json') );
      expect(test).toHaveProperty('a.a.a', 1);
      expect(test).toHaveProperty('b.b.b', 1);
      expect(test).toHaveProperty('c.c.c', 1);
      expect(test).toHaveProperty('d.d.d', 1);
      expect(test).toHaveProperty('e.e.e', 1);
      expect(test).toHaveProperty('f.f.f', 1);
      expect(test).toHaveProperty('g.g.g', 1);
    });


    it('should keep the type of the referenced property', () => {
      var test = resolveObject( helpers.fileToJSON(__dirname + '/../__json_files/reference_type.json') );
      expect(test).toHaveProperty('d', 1);
      expect(typeof test.d).toBe('number');
      expect(typeof test.e).toBe('object');
      expect(Array.isArray(test.f)).toBeTruthy();
      expect(test).toHaveProperty('e.c', 2);
    });

    it('should handle and evaluate items in an array', () => {
      var test = resolveObject( helpers.fileToJSON(__dirname + '/../__json_files/array.json') );
      expect(test.d[0]).toBe(2);
      expect(test.d[1]).toBe(1);
      expect(test.e[0].a).toBe(1);
      expect(test.e[1].a).toBe(2);
    });

    it('should throw if pointers don\'t exist', () => {
      expect(
        resolveObject.bind( helpers.fileToJSON(__dirname + '/../__json_files/non_existent.json'))
      ).toThrow();
    });

    it('should gracefully handle basic circular references', () => {
      GroupMessages.clear(PROPERTY_REFERENCE_WARNINGS);

      resolveObject(helpers.fileToJSON(__dirname + '/../__json_files/circular.json'));
      expect(GroupMessages.count(PROPERTY_REFERENCE_WARNINGS)).toBe(1);
      expect(JSON.stringify(GroupMessages.fetchMessages(PROPERTY_REFERENCE_WARNINGS))).toBe(JSON.stringify([
         'Circular definition cycle:  a, b, c, d, a'
      ]));
    });

    it('should gracefully handle basic and nested circular references', () => {
      GroupMessages.clear(PROPERTY_REFERENCE_WARNINGS);

      resolveObject(helpers.fileToJSON(__dirname + '/../__json_files/circular_2.json'));
      expect(GroupMessages.count(PROPERTY_REFERENCE_WARNINGS)).toBe(1);
      expect(JSON.stringify(GroupMessages.fetchMessages(PROPERTY_REFERENCE_WARNINGS))).toBe(JSON.stringify([
        'Circular definition cycle:  a.b.c, j, a.b.c'
      ]));
    });

    it('should gracefully handle nested circular references', () => {
      GroupMessages.clear(PROPERTY_REFERENCE_WARNINGS);

      resolveObject(helpers.fileToJSON(__dirname + '/../__json_files/circular_3.json'));
      expect(GroupMessages.count(PROPERTY_REFERENCE_WARNINGS)).toBe(1);
      expect(JSON.stringify(GroupMessages.fetchMessages(PROPERTY_REFERENCE_WARNINGS))).toBe(JSON.stringify([
        'Circular definition cycle:  a.b, c.d.e, a.b'
      ]));
    });

    it('should gracefully handle multiple nested circular references', () => {
      GroupMessages.clear(PROPERTY_REFERENCE_WARNINGS);

      resolveObject(helpers.fileToJSON(__dirname + '/../__json_files/circular_4.json'));
      expect(GroupMessages.count(PROPERTY_REFERENCE_WARNINGS)).toBe(1);
      expect(JSON.stringify(GroupMessages.fetchMessages(PROPERTY_REFERENCE_WARNINGS))).toBe(JSON.stringify([
        'Circular definition cycle:  a.b.c.d, e.f.g, h.i, a.b.c.d',
      ]));
    });

    it('should gracefully handle down-chain circular references', () => {
      GroupMessages.clear(PROPERTY_REFERENCE_WARNINGS);

      resolveObject(helpers.fileToJSON(__dirname + '/../__json_files/circular_5.json'));
      expect(GroupMessages.count(PROPERTY_REFERENCE_WARNINGS)).toBe(1);
      expect(JSON.stringify(GroupMessages.fetchMessages(PROPERTY_REFERENCE_WARNINGS))).toBe(JSON.stringify([
        'Circular definition cycle:  l, m, l',
      ]));
    });

    it('should correctly replace multiple references without reference errors', function() {
      GroupMessages.clear(PROPERTY_REFERENCE_WARNINGS);

      var obj = resolveObject(helpers.fileToJSON(__dirname + '/../__json_files/not_circular.json'));
      expect(GroupMessages.count(PROPERTY_REFERENCE_WARNINGS)).toBe(0);
      expect(JSON.stringify(obj)).toBe(JSON.stringify({
        prop1: { value: 'test1 value' },
        prop2: { value: 'test2 value' },
        prop3: { value: 'test1 value' },
        prop4: { value: 'test1 value' },
        prop12: { value: 'test1 value, test2 value and some extra stuff' },
        prop124: { value: 'test1 value, test2 value and test1 value' }
      }));
    });

    describe('ignoreKeys', () => {
      it('should handle default value of original', () => {
        var test = resolveObject({
          foo: { value: 'bar' },
          bar: {
            value: '{foo.value}',
            original: '{foo.value}'
          }
        });
        expect(test).toHaveProperty ('bar.original', '{foo.value}');
      });

      it('should handle any nested keys under the ignoreKey', () => {
        var test = resolveObject({
          foo: { value: 'bar' },
          bar: {
            value: '{foo.value}',
            original: {
              value: '{foo.value}',
              foo: {
                bar: '{foo.value}'
              }
            }
          }
        });
        expect(test).toHaveProperty ('bar.original.value', '{foo.value}');
        expect(test).toHaveProperty ('bar.original.foo.bar', '{foo.value}');
      });

      it('should handle passing in custom ignoreKeys', () => {
        var test = resolveObject({
          foo: { value: 'bar' },
          bar: {
            value: '{foo.value}',
            baz: '{foo.value}'
          }
        }, {
          ignoreKeys: ['baz']
        });
        expect(test).toHaveProperty ('bar.baz', '{foo.value}');
      });

      it('should handle multiple keys', () => {
        var test = resolveObject({
          foo: { value: 'bar' },
          bar: {
            value: '{foo.value}',
            original: '{foo.value}',
            baz: '{foo.value}'
          }
        },{
          ignoreKeys: ['baz','original']
        });
        expect(test).toHaveProperty ('bar.original', '{foo.value}');
        expect(test).toHaveProperty ('bar.baz', '{foo.value}');
      });

      it('should not ignore anything if set to null or empty array', () => {
        var test = resolveObject({
          foo: { value: 'bar' },
          bar: {
            value: '{foo.value}',
            original: '{foo.value}'
          }
        },{
          ignoreKeys: []
        });
        expect(test).toHaveProperty ('bar.original', 'bar');

        var test2 = resolveObject({
          foo: { value: 'bar' },
          bar: {
            value: '{foo.value}',
            original: '{foo.value}'
          }
        },{
          ignoreKeys: null
        });
        expect(test2).toHaveProperty ('bar.original', 'bar');

        var test3 = resolveObject({
          foo: { value: 'bar' },
          bar: {
            value: '{foo.value}',
            original: '{foo.value}'
          }
        },{
          ignoreKeys: undefined
        });
        expect(test3).toHaveProperty ('bar.original', 'bar');
      });
    });

    it('should handle spaces', () => {
      var test = resolveObject({
        foo: { value: 'bar' },
        bar: { value: '{ foo.value }'}
      });
      expect(test).toHaveProperty ('foo.value', test.bar.value);
    });

    it('should collect multiple reference errors', () => {
      GroupMessages.clear(PROPERTY_REFERENCE_WARNINGS);

      resolveObject(helpers.fileToJSON(__dirname + '/../__json_files/multiple_reference_errors.json'));
      expect(GroupMessages.count(PROPERTY_REFERENCE_WARNINGS)).toBe(3);
      expect(JSON.stringify(GroupMessages.fetchMessages(PROPERTY_REFERENCE_WARNINGS))).toBe(JSON.stringify([
         "Reference doesn't exist: a.b tries to reference b.a, which is not defined",
         "Reference doesn't exist: a.c tries to reference b.c, which is not defined",
         "Reference doesn't exist: a.d tries to reference d, which is not defined"
      ]));
    });

    it('should handle 0', () => {
      GroupMessages.clear(PROPERTY_REFERENCE_WARNINGS);
      var test = resolveObject({
        "test": { "value": "{zero.value}" },
        "zero": { "value": 0}
      });
      expect(GroupMessages.fetchMessages(PROPERTY_REFERENCE_WARNINGS).length).toBe(0);
      expect(test.test.value).toBe(0);
    });

  });
});