6 Replies Latest reply on Feb 3, 2011 4:55 PM by mlabriola

    Testing a Component with Two Way Binding


      Does anyone know of a good workaround for testing a spark component whose value is tied to the model with bidirectional binding?


      What I want to do seems very simple. I have a spark TextInput whose text property is bound to a string value in mxml using the @{ target } syntax. In my FlexUnit4 test I want to simulate the user entering some text into that field and then do some assertions to verify that the correct value was saved to the model and that my buttons were enabled/disabled correctly based on the value entered. I tied following the example in the docs and created a Sequence that sets the text of the TextInput, waits for the ValueCommit event and then calls my assertion handler. When I ran my tests, the changes made to the text were not showing up in the model. If I go in and do the same set of operations by hand in my application then everything works correctly.


      The problem seems to be coming from the fact the using a SequenceSetter is the equvalent of calling myTextInput.text="someValue". When a field uses two way binding however, the only changes that affect the underlying model are those made directly by the user, say by typing or copy/pasting. Programatic changes to the text property like those generated by the sequence don't show up.


      There has got to be some way to do this short of taking all the two way binding out of my app. Any ideas on this would be much appreciated.

        • 1. Re: Testing a Component with Two Way Binding
          bucpatr1 Level 2

          If anyone else is strugling with this issue, I think I've found a work around. It's a bit hacky but at least I can do my test.Since the two-way binding is only triggered during a user interaction, the test needs to set the value of the text field in two stages. In the first you use a SequenceSetter to get the desired value into the textDisplay of the input. Once that is complete, the second stage 'tricks' flex into thinking a user interaction has occurred by using a SequenceEventDispatcher to send a  TextOperationEvent to the textDispaly part of the TextInput.


          I would still like to find a less clunky method of doing this, if ayone has suggestions please let me know.

          • 2. Re: Testing a Component with Two Way Binding
            mlabriola Level 4

            I quickly looked at the generated code for a 2 way binding with a TextInput in Flex. Basically, the code is looking for a 'change' or 'textChanged' event to be dispatched from the TextInput to update the binding.


            So, you do need to set the value and then dispatch the event for the 2 way binding to click. I know this seems complex, but the reality is that this test you are writing probably covers 20 classes when you look at all of the binding code involved,  but of which is generated.. not much can be done.


            To make it easier to maintain in your tests, I would create a new class and extend SequenceSetter, let's pretend it is called TwoWaySetter.


            In your new class, override the execute() method:


            override public function execute():void {


                 target.dispatchEvent( new TextOperationEvent( TextOperationEvent.CHANGE)  );



            Then use your new TwoWaySetter instead of the SequenceSetter and all show work as you hope. The goal of the sequence code has always been to let others create new steps when needed. This seems like an ideal use case.





            1 person found this helpful
            • 3. Re: Testing a Component with Two Way Binding
              bucpatr1 Level 2

              That might work. The problem though is that as calling super.execute() is going to result in a ValueCommit event being dispatched (and thus triggering the corresponding SequenceWaiter) before the code for dispatching my TextFlowEvent ever gets called. Can I use the Async class inside that execute method to make sure the text gets set before my custom code runs? Even if I did that, how would I prevent that early ValueCommit event from prematurely triggering the SequenceWaiter?

              • 4. Re: Testing a Component with Two Way Binding
                mlabriola Level 4

                Instead of waiting for the valueCommit in the SequenceWaiter, wait for the change event just like the binding. Since the SeqeunceWaiter gets added after the binding events, it will be called second in the sequence.



                • 5. Re: Testing a Component with Two Way Binding
                  bucpatr1 Level 2

                  That did the trick. Thanks for all the help.

                  • 6. Re: Testing a Component with Two Way Binding
                    mlabriola Level 4

                    Sure, glad it worked out