Uploaded image for project: 'Fluid Infusion'
  1. Fluid Infusion
  2. FLUID-5633

Listeners bound using the IoCSS syntax using the IoC testing framework are never unbound



    • Type: Bug
    • Status: Resolved
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: IoC Testing Framework
    • Labels:


      The IoC Testing framework uses a private "ad hoc" scheme for allowing IoCSS-like syntax in event binding for test fixtures. Unfortunately this implementation is bugged - after the listener instance in a fixture sequence executes, the listener should be unbound - unfortunately, all the confused implementor has done is to unregister the distribution that would bind the listener again - rather than, in addition, removing the listener itself.

      This emerged in work with the "first discovery tool" that had a sequence:

      sequence: [{
       listener: "gpii.tests.firstDiscovery.testInitButtonTops",
       args: ["{firstDiscovery}", "{that}"],
       priority: "last",
       event: "\{gpii.tests.firstDiscovery.langTests firstDiscovery}.events.onButtonTopsReady"
       }, {
       func: "{firstDiscovery}.prefsEditorLoader.applier.change",
       args: ["currentPanelNum", 3]
       }, {
       listener: "gpii.tests.firstDiscovery.testUnchangedButtonTops",
       args: ["{firstDiscovery}", "{that}.buttonTops"],
       event: "{firstDiscovery}.events.onPanelShown"
       }, {
       jQueryTrigger: "click",
       element: "{firstDiscovery}.prefsEditorLoader.prefsEditor.gpii_firstDiscovery_panel_textSize.dom.increase"
       }, {
       func: "\{firstDiscovery}.prefsEditorLoader.applier.change",
       args: ["currentPanelNum", 1]
       }, {
       listener: "gpii.tests.firstDiscovery.testChangedButtonTops",
       args: ["{firstDiscovery}", "\{that}.buttonTops"],
       event: "\{firstDiscovery}.events.onButtonTopsReady"

      The IoCSS syntax is used with the first element, as always, to avoid triggering premature construction of the tree and confusing the manually issued QUnit timeout. Unfortunately, the selfsame event fires as sequence point 6 - the initial listener is still bound and causes a failure

      Uncaught TypeError: Cannot read property 'execute' of undefined
      fluid.test.sequenceExecutor.that.execute @ IoCTestUtils.js:482
      fluid.test.composeSimple @ IoCTestUtils.js:303
      fluid.test.makeBinder.that.bind.wrapped @ IoCTestUtils.js:314
      fluid.event.invokeListener @ infusion-custom.js:12900

      In fact, the sequence has finished, but listeners to the final event are still synchronously executing - so there is time for one more trigger of "that.execute" which attempts to trigger the sequence onto the 7th position - in fact, on behalf of the first listener, which did not believe it was the test-finishing listener.

      The faulty code is in fluid.test.decoders.event in IoCTestUtils.js and reads:

      else if (analysed.path) {
          var id;
          bind = function (wrapped) {
              var options = {};
              fluid.set(options, ["listeners"].concat(analysed.path),{ 
                  listener: wrapped, 
                  args: fixture.args, 
                  namespace: fixture.namespace, 
                  priority: fixture.priority });
          id = fluid.pushDistributions(analysed.head, analysed.selector, [
              {options: options, recordType: "distribution", priority: fluid.mergeRecordTypes.distribution}
              ] );
          unbind = function () {
              fluid.clearDistributions(analysed.head, id); 

      as is clear, the "unbind" action only revokes the distribution and does not take any action to eliminate the listener which the framework directed into the options via the fluid.set directive.

      This is a little awkward since the listener gets bound declaratively and so cannot be unbound by instance. It seems that we could only resolve this by taking control of the listener namespace (we would have to advertise to fixture writers that this can not be controlled) and using it to set the listener into a uniquely guid-ed namespace in which we could then identify it.

      In general this issue can't be solved before the FLUID-5249 work gets in and we gain the ability to write fluid.queryIoCSelector - since otherwise we could not discover the component holding the listener.




            antranig Antranig Basman
            antranig Antranig Basman
            0 Vote for this issue
            4 Start watching this issue