Skip to content

Commit f451cef

Browse files
committed
Fix pending 'reorder redirects' cucumber test
1 parent b173726 commit f451cef

File tree

6 files changed

+273
-38
lines changed

6 files changed

+273
-38
lines changed

Gemfile.lock

+25-25
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,23 @@ PATH
1212
GEM
1313
remote: http://rubygems.org/
1414
specs:
15-
activemodel (3.2.1)
16-
activesupport (= 3.2.1)
15+
activemodel (3.2.2)
16+
activesupport (= 3.2.2)
1717
builder (~> 3.0.0)
18-
activerecord (3.2.1)
19-
activemodel (= 3.2.1)
20-
activesupport (= 3.2.1)
21-
arel (~> 3.0.0)
18+
activerecord (3.2.2)
19+
activemodel (= 3.2.2)
20+
activesupport (= 3.2.2)
21+
arel (~> 3.0.2)
2222
tzinfo (~> 0.3.29)
23-
activeresource (3.2.1)
24-
activemodel (= 3.2.1)
25-
activesupport (= 3.2.1)
26-
activesupport (3.2.1)
23+
activeresource (3.2.2)
24+
activemodel (= 3.2.2)
25+
activesupport (= 3.2.2)
26+
activesupport (3.2.2)
2727
i18n (~> 0.6)
2828
multi_json (~> 1.0)
2929
addressable (2.2.7)
3030
archive-tar-minitar (0.5.2)
31-
arel (3.0.0)
31+
arel (3.0.2)
3232
awesome_print (1.0.2)
3333
builder (3.0.0)
3434
capybara (1.1.2)
@@ -43,18 +43,18 @@ GEM
4343
childprocess (0.3.1)
4444
ffi (~> 1.0.6)
4545
columnize (0.3.6)
46-
cucumber (1.1.4)
46+
cucumber (1.1.9)
4747
builder (>= 2.1.2)
4848
diff-lcs (>= 1.1.2)
49-
gherkin (~> 2.7.1)
49+
gherkin (~> 2.9.0)
5050
json (>= 1.4.6)
5151
term-ansicolor (>= 1.0.6)
5252
daemons (1.1.8)
5353
database_cleaner (0.7.1)
5454
diff-lcs (1.1.3)
5555
eventmachine (0.12.10)
5656
ffi (1.0.11)
57-
gherkin (2.7.7)
57+
gherkin (2.9.0)
5858
json (>= 1.4.6)
5959
growl (1.0.3)
6060
guard (1.0.0)
@@ -72,12 +72,12 @@ GEM
7272
addressable (~> 2.2.6)
7373
linecache (0.46)
7474
rbx-require-relative (> 0.0.4)
75-
linecache19 (0.5.13)
75+
linecache19 (0.5.12)
7676
ruby_core_source (>= 0.1.4)
7777
mime-types (1.17.2)
78-
multi_json (1.0.4)
78+
multi_json (1.1.0)
7979
mysql2 (0.3.11)
80-
nokogiri (1.5.0)
80+
nokogiri (1.5.2)
8181
pg (0.13.2)
8282
rack (1.4.1)
8383
rack-protection (1.2.0)
@@ -87,7 +87,7 @@ GEM
8787
rake (0.9.2.2)
8888
rb-fsevent (0.9.0)
8989
rb-readline (0.4.2)
90-
rbx-require-relative (0.0.5)
90+
rbx-require-relative (0.0.9)
9191
relish (0.5.3)
9292
archive-tar-minitar (>= 0.5.2)
9393
json (>= 1.4.6)
@@ -107,7 +107,7 @@ GEM
107107
ruby-debug-base (~> 0.10.4.0)
108108
ruby-debug-base (0.10.4)
109109
linecache (>= 0.3)
110-
ruby-debug-base19 (0.11.26)
110+
ruby-debug-base19 (0.11.25)
111111
columnize (>= 0.3.1)
112112
linecache19 (>= 0.5.11)
113113
ruby_core_source (>= 0.1.4)
@@ -118,14 +118,14 @@ GEM
118118
ruby_core_source (0.1.5)
119119
archive-tar-minitar (>= 0.5.2)
120120
rubyzip (0.9.6.1)
121-
selenium-webdriver (2.19.0)
121+
selenium-webdriver (2.20.0)
122122
childprocess (>= 0.2.5)
123-
ffi (~> 1.0.9)
124-
multi_json (~> 1.0.4)
123+
ffi (~> 1.0)
124+
multi_json (~> 1.0)
125125
rubyzip
126126
shoulda-matchers (1.0.0)
127-
simplecov (0.5.4)
128-
multi_json (~> 1.0.3)
127+
simplecov (0.6.1)
128+
multi_json (~> 1.0)
129129
simplecov-html (~> 0.5.3)
130130
simplecov-html (0.5.3)
131131
sinatra (1.3.2)
@@ -146,7 +146,7 @@ GEM
146146
rack (>= 1.0.0)
147147
thor (0.14.6)
148148
tilt (1.3.3)
149-
tzinfo (0.3.31)
149+
tzinfo (0.3.32)
150150
xpath (0.1.4)
151151
nokogiri (~> 1.3)
152152

features/step_definitions/redirect_rules_steps.rb

+5-7
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,17 @@
4646
end
4747

4848
When /^I reorder second redirect to be the first one$/ do
49-
handler = find("#redirects #redirect_#{RestAssured::Models::Redirect.last.id} td.handle")
50-
target = find('#redirects thead')
51-
52-
handler.drag_to target
49+
page.execute_script %{
50+
$('#redirects #redirect_#{RestAssured::Models::Redirect.order('position').last.id}').simulateDragSortable({move: -1, handle: '.handle'})
51+
}
52+
sleep 2
5353
end
5454

5555
Then /^"([^"]*)" should be redirected to "([^"]*)"$/ do |missing_request, url|
56-
pending('This does not pass due to Capybara/Selelium broken drag and drop support')
57-
5856
get missing_request
5957
follow_redirect!
6058

61-
last_request.url.should == "#{url}#{missing_request}"
59+
last_request.url.should == url
6260
end
6361

6462
Given /^blank slate$/ do

features/web_ui/redirects.feature

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ Feature: manage redirects via ui
4949
| /api/bbb | http://twitter.com/api |
5050
And I am on "redirects" page
5151
When I reorder second redirect to be the first one
52-
Then "/api/bbb" should be redirected to "http://twitter.com/api"
52+
Then "/api/bbb/ccc" should be redirected to "http://twitter.com/api/ccc"
5353
When I reorder second redirect to be the first one
54-
Then "/api/bbb" should be redirected to "http://google.com/api"
54+
Then "/api/bbb/ccc" should be redirected to "http://google.com/api"
5555

5656
@javascript
5757
Scenario: delete redirect

lib/rest-assured/version.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module RestAssured
2-
VERSION = '1.1.2'
2+
VERSION = '1.1.3'
33
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
(function($) {
2+
/*
3+
* Simulate drag of a JQuery UI sortable list
4+
* Repository: https://github.com/mattheworiordan/jquery.simulate.drag-sortable.js
5+
* Author: http://mattheworiordan.com
6+
*
7+
* options are:
8+
* - move: move item up (positive) or down (negative) by Integer amount
9+
* - dropOn: move item to a new linked list, move option now represents position in the new list (zero indexed)
10+
* - handle: selector for the draggable handle element (optional)
11+
* - listItem: selector to limit which sibling items can be used for reordering
12+
* - placeHolder: if a placeholder is used during dragging, we need to consider it's height
13+
* - tolerance: (optional) number of pixels to overlap by instead of the default 50% of the element height
14+
*
15+
*/
16+
$.fn.simulateDragSortable = function(options) {
17+
// build main options before element iteration
18+
var opts = $.extend({}, $.fn.simulateDragSortable.defaults, options);
19+
20+
applyDrag = function(options) {
21+
// allow for a drag handle if item is not draggable
22+
var that = this,
23+
options = options || opts, // default to plugin opts unless options explicitly provided
24+
handle = options.handle ? $(this).find(options.handle)[0] : $(this)[0],
25+
listItem = options.listItem,
26+
placeHolder = options.placeHolder,
27+
sibling = $(this),
28+
moveCounter = Math.floor(options.move),
29+
direction = moveCounter > 0 ? 'down' : 'up',
30+
moveVerticalAmount = 0,
31+
initialVerticalPosition = 0,
32+
extraDrag = !isNaN(parseInt(options.tolerance, 10)) ? function() { return Number(options.tolerance); } : function(obj) { return ($(obj).outerHeight() / 2) + 5; },
33+
dragPastBy = 0, // represents the additional amount one drags past an element and bounce back
34+
dropOn = options.dropOn ? $(options.dropOn) : false,
35+
center = findCenter(handle),
36+
x = Math.floor(center.x),
37+
y = Math.floor(center.y),
38+
mouseUpAfter = (opts.debug ? 2500 : 10);
39+
40+
if (dropOn) {
41+
if (dropOn.length === 0) {
42+
if (console && console.log) { console.log('simulate.drag-sortable.js ERROR: Drop on target could not be found'); console.log(options.dropOn); }
43+
return;
44+
}
45+
sibling = dropOn.find('>*:last');
46+
moveCounter = -(dropOn.find('>*').length + 1) + (moveCounter + 1); // calculate length of list after this move, use moveCounter as a positive index position in list to reverse back up
47+
if (dropOn.offset().top - $(this).offset().top < 0) {
48+
// moving to a list above this list, so move to just above top of last item (tried moving to top but JQuery UI wouldn't bite)
49+
initialVerticalPosition = sibling.offset().top - $(this).offset().top - extraDrag(this);
50+
} else {
51+
// moving to a list below this list, so move to bottom and work up (JQuery UI does not trigger new list below unless you move past top item first)
52+
initialVerticalPosition = sibling.offset().top - $(this).offset().top - $(this).height();
53+
}
54+
} else if (moveCounter === 0) {
55+
if (console && console.log) { console.log('simulate.drag-sortable.js WARNING: Drag with move set to zero has no effect'); }
56+
return;
57+
} else {
58+
while (moveCounter !== 0) {
59+
if (direction === 'down') {
60+
if (sibling.next(listItem).length) {
61+
sibling = sibling.next(listItem);
62+
moveVerticalAmount += sibling.outerHeight();
63+
}
64+
moveCounter -= 1;
65+
} else {
66+
if (sibling.prev(listItem).length) {
67+
sibling = sibling.prev(listItem);
68+
moveVerticalAmount -= sibling.outerHeight();
69+
}
70+
moveCounter += 1;
71+
}
72+
}
73+
}
74+
75+
dispatchEvent(handle, 'mousedown', createEvent('mousedown', handle, { clientX: x, clientY: y }));
76+
// simulate drag start
77+
dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x+1, clientY: y+1 }));
78+
79+
if (dropOn) {
80+
// jump to top or bottom of new list but do it in increments so that JQuery UI registers the drag events
81+
slideUpTo(x, y, initialVerticalPosition);
82+
83+
// reset y position to top or bottom of list and move from there
84+
y += initialVerticalPosition;
85+
86+
// now call regular shift/down in a list
87+
options = jQuery.extend(options, { move: moveCounter });
88+
delete options.dropOn;
89+
90+
// add some delays to allow JQuery UI to catch up
91+
setTimeout(function() {
92+
dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y }));
93+
}, 5);
94+
setTimeout(function() {
95+
dispatchEvent(handle, 'mouseup', createEvent('mouseup', handle, { clientX: x, clientY: y }));
96+
setTimeout(function() {
97+
if (options.move) {
98+
applyDrag.call(that, options);
99+
}
100+
}, 5);
101+
}, mouseUpAfter);
102+
103+
// stop execution as applyDrag has been called again
104+
return;
105+
}
106+
107+
// Sortable is using a fixed height placeholder meaning items jump up and down as you drag variable height items into fixed height placeholder
108+
placeHolder = placeHolder && $(this).parent().find(placeHolder);
109+
110+
if (!placeHolder && (direction === 'down')) {
111+
// need to move at least as far as this item and or the last sibling
112+
if ($(this).outerHeight() > $(sibling).outerHeight()) {
113+
moveVerticalAmount += $(this).outerHeight() - $(sibling).outerHeight();
114+
}
115+
moveVerticalAmount += extraDrag(sibling);
116+
dragPastBy += extraDrag(sibling);
117+
} else if (direction === 'up') {
118+
// move a little extra to ensure item clips into next position
119+
moveVerticalAmount -= Math.max(extraDrag(this), 5);
120+
} else if (direction === 'down') {
121+
// moving down with a place holder
122+
if (placeHolder.height() < $(this).height()) {
123+
moveVerticalAmount += Math.max(placeHolder.height(), 5);
124+
} else {
125+
moveVerticalAmount += extraDrag(sibling);
126+
}
127+
}
128+
129+
if (sibling[0] !== $(this)[0]) {
130+
// step through so that the UI controller can determine when to show the placeHolder
131+
slideUpTo(x, y, moveVerticalAmount, dragPastBy);
132+
} else {
133+
if (window.console) {
134+
console.log('simulate.drag-sortable.js WARNING: Could not move as at top or bottom already');
135+
}
136+
}
137+
138+
setTimeout(function() {
139+
dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + moveVerticalAmount }));
140+
}, 5);
141+
setTimeout(function() {
142+
dispatchEvent(handle, 'mouseup', createEvent('mouseup', handle, { clientX: x, clientY: y + moveVerticalAmount }));
143+
}, mouseUpAfter);
144+
};
145+
146+
// iterate and move each matched element
147+
return this.each(applyDrag);
148+
};
149+
150+
// fire mouse events, go half way, then the next half, so small mouse movements near target and big at the start
151+
function slideUpTo(x, y, targetOffset, goPastBy) {
152+
var moveBy, offset;
153+
154+
if (!goPastBy) { goPastBy = 0; }
155+
if ((targetOffset < 0) && (goPastBy > 0)) { goPastBy = -goPastBy; } // ensure go past is in the direction as often passed in from object height so always positive
156+
157+
// go forwards including goPastBy
158+
for (offset = 0; Math.abs(offset) + 1 < Math.abs(targetOffset + goPastBy); offset += ((targetOffset + goPastBy - offset)/2) ) {
159+
dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + Math.ceil(offset) }));
160+
}
161+
offset = targetOffset + goPastBy;
162+
dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + offset }));
163+
164+
// now bounce back
165+
for (; Math.abs(offset) - 1 >= Math.abs(targetOffset); offset += ((targetOffset - offset)/2) ) {
166+
dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + Math.ceil(offset) }));
167+
}
168+
dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + targetOffset }));
169+
}
170+
171+
function createEvent(type, target, options) {
172+
var evt;
173+
var e = $.extend({
174+
target: target,
175+
preventDefault: function() { },
176+
stopImmediatePropagation: function() { },
177+
stopPropagation: function() { },
178+
isPropagationStopped: function() { return true; },
179+
isImmediatePropagationStopped: function() { return true; },
180+
isDefaultPrevented: function() { return true; },
181+
bubbles: true,
182+
cancelable: (type != "mousemove"),
183+
view: window,
184+
detail: 0,
185+
screenX: 0,
186+
screenY: 0,
187+
clientX: 0,
188+
clientY: 0,
189+
ctrlKey: false,
190+
altKey: false,
191+
shiftKey: false,
192+
metaKey: false,
193+
button: 0,
194+
relatedTarget: undefined
195+
}, options || {});
196+
197+
if ($.isFunction(document.createEvent)) {
198+
evt = document.createEvent("MouseEvents");
199+
evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail,
200+
e.screenX, e.screenY, e.clientX, e.clientY,
201+
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
202+
e.button, e.relatedTarget || document.body.parentNode);
203+
} else if (document.createEventObject) {
204+
evt = document.createEventObject();
205+
$.extend(evt, e);
206+
evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button;
207+
}
208+
return evt;
209+
}
210+
211+
function dispatchEvent(el, type, evt) {
212+
if (el.dispatchEvent) {
213+
el.dispatchEvent(evt);
214+
} else if (el.fireEvent) {
215+
el.fireEvent('on' + type, evt);
216+
}
217+
return evt;
218+
}
219+
220+
function findCenter(el) {
221+
var elm = $(el),
222+
o = elm.offset();
223+
return {
224+
x: o.left + elm.outerWidth() / 2,
225+
y: o.top + elm.outerHeight() / 2
226+
};
227+
}
228+
229+
//
230+
// plugin defaults
231+
//
232+
$.fn.simulateDragSortable.defaults = {
233+
move: 0
234+
};
235+
})(jQuery);

0 commit comments

Comments
 (0)