Question

I want to write a spec for an UIView I use. The UIView should be dragged to a certain location to test wether it calls the wright delegate methods. For this I'm using the "drag" method. However the drag command does not seem to be to any dragging. Perhaps I'm using it in the wrong way? I used macbacon spec for inspiration.

Here is the code:

describe "DraggableView" do
  tests SpecDragViewController

  before do 
    @drag = MyDragableView.alloc.initWithFrame [[10,200],[100,100]]
    @drag.backgroundColor = UIColor.redColor

    controller.view.addSubview @drag
  end

  it "should not accept wrong drop" do
    @drag.frame.should != nil
    @drag.accessibilityLabel = "Drag View"

    delegate = Object.new
    delegate.mock!(:draggableViewHasBeenDroppedAtWrongLocation) {|view|
       view.should == @drag
    }

    p @drag.center
    drag "Drag View", :from => CGPointMake(15,250), :to => CGPointMake(300,300)

    wait 10{} # Long wait, just so I could play with the view in the simulator
    p @drag.frame
  end    

end

class SpecDragViewController < UIViewController
end

class MyDragableView < UIView
  attr_accessor :destination_view
  attr_accessor :delegate

  def initWithFrame (rect)
    if super
      addBehaviour
    end
    self
  end  

  private 
  def addBehaviour
    @panGesture = UIPanGestureRecognizer.alloc.initWithTarget(self, action:'dragGesture:'); 

    self.addGestureRecognizer(@panGesture)
    self.userInteractionEnabled=true
  end

  def dragGesture(panGesture)
    translation = panGesture.translationInView(self.superview)
    case panGesture.state
    when UIGestureRecognizerStateBegan
      @originalCenter = self.center
      delegate.draggableViewStartedDragging(self) if delegate
    when UIGestureRecognizerStateChanged
      self.center = CGPointMake(self.center.x + translation.x,
                                     self.center.y + translation.y)
    when UIGestureRecognizerStateEnded
      if (@destination_view && CGRectContainsPoint(@destination_view.frame, self.center) && delegate.draggableViewCanBeDropped?(self))      
        self.removeGestureRecognizer(@panGesture)
        delegate.draggableViewHasBeenDropped(self)        
      else                  
        delegate.draggableViewHasBeenDroppedAtWrongLocation(self)        
      end
    end

    panGesture.setTranslation(CGPointZero, inView:self.superview)
  end

end
Was it helpful?

Solution

I am still interested in a real solution, but I For now I am working around the problem. Perhaps interesting for other people running into the same problem.

I decided to fake the UIGestures and send them to delegate functions of the DraggableView. In this way I can still test the correct working of the function, without a drag of the simulator. I have stubbed three gestures: a start gesture, a change gesture and an end gesture.

  before do 
    @drag = DragableView.alloc.initWithFrame [[10,200],[100,100]]
    @drag.backgroundColor = UIColor.redColor

    @start_gesture = Object.new
    @start_gesture.stub!(:setTranslation) {|v1,v2|}
    @start_gesture.stub!(:state, :return=> UIGestureRecognizerStateBegan)
    @start_gesture.stub!("translationInView") {|v| [0,0]}

    @end_gesture = Object.new
    @end_gesture.stub!(:state, :return=> UIGestureRecognizerStateEnded)
    @end_gesture.stub!("translationInView") {|v| [100,100]}
    @end_gesture.stub!(:setTranslation) {|v1,v2|}


    controller.view.addSubview @drag
  end
  it "should not accept wrong drop" do

    @wrong_gesture = Object.new
    @wrong_gesture.stub!(:state, :return=> UIGestureRecognizerStateChanged)
    @wrong_gesture.stub!("translationInView") {|v| CGPointMake(100,100)}
    @wrong_gesture.stub!(:setTranslation) {|v1,v2|}

    delegate = Object.new

    delegate.mock! (:draggableViewStartedDragging) {|view|}
    delegate.mock!(:draggableViewHasBeenDroppedAtWrongLocation) {|view|
      view.should == @drag
    }
    @drag.delegate = delegate

    @drag.send :dragGesture, @start_gesture
    @drag.send :dragGesture, @wrong_gesture
    @drag.send :dragGesture, @end_gesture


    CGRectEqualToRect(@drag.frame, [[10,200], [100,100]]).should.be.true
  end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top