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
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