convector icon indicating copy to clipboard operation
convector copied to clipboard

Issue with properties in complex objects and tests.

Open friendly-tech opened this issue 6 years ago • 4 comments

The problem

When passing a model to a controller in a test and that model has a property that is a simple class (not a convector model), any properties on that child class are not populated when hitting the controller method.

Details

I have a convector Model (lets call it Parent), this has a property called Child with a type of ChildClass (this is a simple class, not Convector model) - this child class has a property called Name (string).

I decorate all of my properties correctly and manually create the schema using yup for the plain old typescript object.

I have a simple controller with a method that just returns whats passed in (and calls .ToJSON()), i write a test that creates an instance of Parent, then creates and instance of Parent.Child and sets Name equal to "NAME".

i simply pass this instance of parent into my controller method - when i hit the controller method, my instance of Parent indeed has an instance of ChildClass in the .Child property but the Name property of this instance is not set.

When running this in the actual network, this does not happen - only in the test.

Current Behavior

Child properties of child classes are not populated on the way in to the controller.

Expected Behavior

All properties should be populated correctly.

Code To Reproduce Issue [ Good To Have ]

Models


import * as yup from 'yup';
import {
  ConvectorModel,
  Default,
  ReadOnly,
  Required,
  Validate,
  getPropertiesValidation
} from '@worldsibu/convector-core-model';

export class ChildClass {
    @Required()
    @Validate(yup.string())
    public childClassName: string;

    public static schema()  {
        var inst = new ChildClass();
        return yup.object().shape({
            ...getPropertiesValidation(inst)
        });
    }
}

export class ParentClass extends ConvectorModel<ParentClass> {
  @ReadOnly()
  @Required()
  public readonly type = 'io.worldsibu.ParentClass';

  @Required()
  @Validate(yup.string())
  public name: string;

  @Required()
  @Validate(ChildClass.schema())
  public Child: ChildClass;
  
  
}

Controller

import {
  Controller,
  ConvectorController,
  Invokable,
  Param
} from '@worldsibu/convector-core-controller';

import { ParentClass } from './bugrepro.model';

@Controller('bugrepro')
export class BugreproController extends ConvectorController {
  @Invokable()
  public async test(@Param(ParentClass) pc: ParentClass): Promise<any> {
    // The issue isnt that this toJSON doesnt allow the property out, its that its not here on the way in
    if (!pc.Child.childClassName)   {
      // Was set in our test so shouldnt be missing, but it is...?
        // Toggle debug with --inspect-brk
        //pc.Child._childClassName is  set.. ?
      debugger;
    }
    return pc.toJSON();
  }
}

Test


// tslint:disable:no-unused-expression
import { join } from 'path';
import { expect } from 'chai';
import * as uuid from 'uuid/v4';
import { MockControllerAdapter } from '@worldsibu/convector-adapter-mock';
import 'mocha';

import {ChildClass, ParentClass} from '../src/bugrepro.model';
import { BugreproControllerClient } from '../client';

describe('Bugrepro', () => {
    let modelSample: ParentClass;
    let adapter: MockControllerAdapter;
    let bugreproCtrl: BugreproControllerClient;

    before(async () => {
        const now = new Date().getTime();
        modelSample = new ParentClass();
       
        modelSample.name = 'Parent';
        modelSample.Child = new ChildClass();
        modelSample.Child.childClassName = 'Child';
        adapter = new MockControllerAdapter();
        bugreproCtrl = new BugreproControllerClient(adapter);
        await adapter.init([
            {
            version: '*',
            controller: 'BugreproController',
            name: join(__dirname, '..')
            }
        ]);

    });

    it('should return whats passed in', async () => {
        var item = await bugreproCtrl.test(modelSample);
        expect(item.Child.childClassName).to.equal('Child');
    });
});

friendly-tech avatar Feb 27 '19 09:02 friendly-tech

Thanks for reporting. This is an issue in the .toJSON method in the core-model package, it's not being recursive on objects. We just need to iterate over each of the properties and normalize the properties. https://github.com/hyperledger-labs/convector/blob/e5db472d707c92c255c1bd9c5f6306fe9df36b28/%40worldsibu/convector-core-model/src/convector-model.ts#L200-L238

diestrin avatar Feb 27 '19 09:02 diestrin

I had a look at that method, and did think should be be recursive - thanks for looking into it for me.

friendly-tech avatar Feb 27 '19 09:02 friendly-tech

Would all required checks + validation also need be recursive in this way. Im about to start testing that

friendly-tech avatar Feb 27 '19 10:02 friendly-tech

@crazyman1979 I don't think so, toJSON only serealizes the info, so it should be just a matter of removing the lodash in front of the properties only.

diestrin avatar Mar 01 '19 07:03 diestrin