Create a mocked-up FetchResult object to pass to a function

#1

I’m trying to create a jasmine test for a function that takes a fetch result object and returns a Dataset. I can’t seem to get the mocked-up object to work; it keeps failing when passed through the function. However, the function works perfectly fine with a real type.fetch().objs call.

First, the code I’m trying to test.

/**
 *  This function should already exist but I am seeing some errors.
 */
function firstAtPath(obj, path) {
    if (obj == null) {
      return null;
    }
    if (!path || path.length == 0) {
      return obj;
    }
    var step = path.split(".")[0];
    var stepsTail = path.split(".").slice(1).join(".");

    var subObj = obj[step]
    if (subObj && subObj.length > 0) {
      subObj = subObj[0]
    }

    return firstAtPath(subObj, stepsTail);
  }


  /**
   * This function turns a collection of objects into a dataset
   */ 
  function fromObjArray(objs, columns, missingValue){
    var data = [];
    var mv = missingValue || 0;

    // Iterate through the objects and extract the value at a given path
    _.each(objs, function(obj){
      _.each(columns, function(c) {
        data.push(firstAtPath(obj, c) || mv)
      })
    })

    return Dataset.make({
      data: data,
      orient: "row",
      indices:{"0": objs.pluck("id"), "1": columns},
      shape: [objs.length, columns.length]
    })
  }

When I attempt to generate a generic object array to pass to it, all I can get is errors. See attached image. You can also see the successful use of the function when doing an actual fetch.

Strangely when I attempt to replicate the function through the console, I get a different error.

0 Likes

#2

If I comment out the following line of code, then it successfully creates a Dataset, but the indices are missing.

indices:{"0": objs.pluck("id"), "1": columns},
0 Likes

#3

I’ve tracked down the problem to the simple fact that the actual fetch result’s id field is a boxed, but the mock fetch result is anything (just like what the error message points to).

Actual:

Mock:
fromObjArray_elem_bad

Now the question is, how to I set the id field in the mocked object to be a C3 string instead of merely a string.

0 Likes

#4

I can’t see the actual values (the images are fuzzy), but you can convert an [any] to a [string] by explicitly making it: c3Make('[string]', mock.slice()). If you need to perform some conversion on the elements before this, use map.

The values you get back from fetch should not be boxed, particularly not the “id” field (which is declared as a primitive string in Identifiable).

1 Like

#5

This is perhaps a step in the right direction, but I can’t quite figure out how to do an in-place assignment of the type.

Just realized I didn’t share my console commands. This will help reconstruct my scenario above.

var fetchResultObjectArray = [{"id":"0","feature": 6, "label": 0},{"id":"1","feature": 7, "label": 1},{"id":"2","feature": 8}];
var oArry = Obj.array();
oArry.push(fetchResultObjectArray[0]);
oArry.push(fetchResultObjectArray[1]);
oArry.push(fetchResultObjectArray[2]);
var mockDataset = Dataset__fromObjs.fromObjArray(oArry,["feature","label"],0);

Clearly I can create an array with the type [string] using c3Make(), but I can’t get it into oArry.

0 Likes

#6

This works, but I don’t like that I have to reference an extant type as that builds a dependency into the test.

var filename = "test_Dataset__fromObjs";

var typeRefMock = TypeRef.make();
typeRefMock.typeName = "Persistable<Tag>";
var tagMockGen = typeRefMock.toType();
var tagMock = tagMockGen.make({});
tagMock.objs = c3Make('[Tag]',[{"id":"0"},{"id":"1"},{"id":"2"}]);
tagMock.objs[0].version = 6;
tagMock.objs[1].version = 7;
tagMock.objs[2].version = 8;
tagMock.objs[0].tenantTagId = 0;
tagMock.objs[1].tenantTagId = 1;

describe(filename, function() {
  var ctx,
    mockDataset;

  it("setup", function() {
    ctx = TestApi.createContext(filename);
  });

  it("create dataset", function() {
    mockDataset = Dataset__fromObjs.fromObjArray(tagMock.objs,["version","tenantTagId"],0);
    expect(mockDataset.slice([0],1,false).data[0]).toBe(6); // check version field in row 0
    expect(mockDataset.slice([1],1,false).data[1]).toBe(1); // check tenantTagId field in row 1
    expect(mockDataset.slice([1],1,false).data[2]).toBe(0); // check tenantTagId field in row 2, which was NULL and replaced with 0
  });

  it("teardown", function() {
    TestApi.teardown(ctx, null);
    expect(ctx.numObjects()).toEqual(0);
  });
});
0 Likes

#7

Make the array of the correct type initially and things will work more naturally. Obj.array will create an [Obj] (non-specific), so pluck and such will not know the field types. If you create the array of the correct type, operations will know how to deal with it.

oArray = c3Make('[User]', [
  { id: "joe" },
  { id: "bob" },
  { id: "jack" }
]);
oArray.pluck('id').type().toString();
0 Likes