0

I've been creating some tests for my Dojo widget to check that boolean flags are being set correctly. However, I've found that since I have altered my constructor to pass in an object, previously ran tests seem to affect the subsequent tests.

I've tried destroying the widget in the tear down methods, but whatever I seem to do, the value persists.

Can anyone suggest what I might be doing wrong?

My widget code:

var showControls = true;

    return declare([WidgetBase, TemplatedMixin, _WidgetsInTemplateMixin], {

        templateString: template,

        constructor: function (params) {

            this.showControls = (typeof params.showControls === "undefined" || typeof params.showControls != "boolean") ? this.showControls : params.showControls;
        }
    });

My test class is:

var customWidget;

doh.register("Test controls", [ 
    {
        name: "Test controls are not visible when set in constructor",
        runTest: function() {
            var params = { showControls: false };
            customWidget = new CustomWidget(params);
            doh.assertFalse(customWidget.getShowControls());
        }
    },
    {
        name: "Test controls are visible when set in constructor with string instead of boolean",
        runTest: function() {
            var params = { showControls: "wrong" };
            customWidget= new CustomWidget(params);
            doh.assertTrue(customWidget.getShowControls());
        }
    }
]);

So, the first test passes, as showControls is set to false, however the 2nd test attempts to create a new instance, in which the constructor will check that the value is a boolean. When I debug this however, it thinks showControls starts out as 'false', not true.

Any clues?!

Thanks

phusick
  • 7,342
  • 1
  • 21
  • 26

2 Answers2

1

dijit/_WidgetBase has a mechanism of mixing in constructor parameters and it is the reason of the behavior you described. One of the possible solutions is to define a custom setter as a method _set[PropertyName]Attr:

var defaults = {
    showControls: true
}

var CustomWidget = declare([_WidgetBase, _TemplatedMixin], {
    templateString: "<div></div>",

    constructor: function(params) {
        declare.safeMixin(this, defaults);
    },

    _setShowControlsAttr: function(value) {
        this.showControls = (typeof value === "boolean") ? value : defaults.showControls;
    }
});

See it in action: http://jsfiddle.net/phusick/wrBHp/

phusick
  • 7,342
  • 1
  • 21
  • 26
  • Thanks phusick, I've tried what you've suggested and it works. I'm still trying to get my head around how it works under the hood to be honest and how you can be sure that an attribute within the params object (in this case params.showControls) would actually get set in the private setter. How does Dojo know to match these 2 up? – IpponSolutions Feb 07 '13 at 09:38
0

I would suggest you list any members of your widget, if you do not, things passed into the constructor may not be properly recognised. It seems you want to use this.showControls, so you should have a showControls member. like this :

return declare([WidgetBase, TemplatedMixin, _WidgetsInTemplateMixin], {

    templateString: template,

    showControls: true, // default value

    constructor: function (params) {
         // no further action, params are automatically mixed in already
    }
});

Be careful when listing members, dojo interprets arrays and objects as class members (like static in Java, AFAIK they're attached to the prototype) so if you want each object to have e.g., a separate array of values, list it as null and initialize in your constructor.

Frances McMullin
  • 5,516
  • 2
  • 18
  • 19
  • This won't work (http://jsfiddle.net/phusick/BzZQB) because mixing in the constructor parameters happens after `constructor`, `create` and `postMixInProperties` and before `postCreate`, so whatever you change in the constructor, it will be changed back later during instantiation (via `_applyAttributes` method). Other possibility, if you want to avoid using setters/getters, is to mutate `this.params` object in `postMixInProperties` like here http://jsfiddle.net/phusick/ZupZE, but this is much less readable than having setters/getters and default parameters in an object named `defaults`. – phusick Feb 04 '13 at 20:28
  • What are you trying to achieve here? In that fiddle this.showControls was true, "wrong" and undefined (actually threw an error, so you may want to change that line in the constructor) what is your desired behaviour? Why do you expect this.showControls to be set already? In your first code block, do you think the var showControls = true is attached to your declaration? Look at my code sample, to set a default, just do showControls : true, – Frances McMullin Feb 04 '13 at 21:08
  • I can't say for sure what @user2010651 is about achieve, but since you react to my comment, I'll provide my insight: if `showControls` property of the 1st argument object of the constructor is `boolean` then set instance property `showControls` to this value (true || false), otherwise set it to the default value (which is true). Your code sets it to any value passed and therefore it won't pass the unit tests provided. – phusick Feb 04 '13 at 21:31
  • sorry! confused you with the original commenter because of the edit (still getting used to SO). I can't tell what they're trying to achieve at this stage, would be wise for them to provide a fiddle showing the problem I guess... – Frances McMullin Feb 04 '13 at 23:04