casper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ Casper
2
+ ======
3
+
4
+ A DSL for automated mouse <del>and keyboard</del> input in X11.
5
+
6
+ Usage
7
+ -----
8
+
9
+ Right now Casper only does mouse input, it looks something like this:
10
+
11
+ Casper::Mouse.move 200, 300 # puts the cursor at x: 200px, y: 300px
12
+ Casper::Mouse.down # presses the primary mouse button
13
+ Casper::Mouse.up # releases the primary mouse button
14
+ Casper::Mouse.click # clicks with the primary mouse button
15
+ Casper::Mouse.location # => [ 200, 300 ]
16
+
17
+ Which is all well and good, but the more useful stuff looks like:
18
+
19
+ Casper::Mouse.drag :from => [ 200, 300 ], :distance => [ 30, 60 ], :increments => 10 do
20
+ Casper::Mouse.drag :distance => [ 80, 100 ] do
21
+ sleep 0.5
22
+ end
23
+ end
24
+
25
+ We've found it particularly useful in conjunction with Selenium-based
26
+ Javascript testing. We use it to reliably test complex movements (such as a
27
+ velocity-aware drag, or drag and drop between multiple containers with
28
+ timeouts, etc...)
29
+
30
+ Requirements
31
+ ------------
32
+
33
+ Requires `libxdo` (comes with `xdotool`). Details and installation
34
+ instructions can be found at http://www.semicomplete.com/projects/xdotool/.
35
+
36
+ Quick build instructions for Ubuntu (tested on 10.04):
37
+
38
+ $ sudo apt-get install xorg-dev
39
+ $ wget http://semicomplete.googlecode.com/files/xdotool-2.20100818.3004.tar.gz
40
+ $ tar xzvf xdotool-2.20100818.3004.tar.gz
41
+ $ cd xdotool-2.20100818.3004
42
+ $ sudo make all install
43
+
44
+ Testing
45
+ -------
46
+
47
+ We test Casper in a VM environment set up by Vagrant. If you have Vagrant
48
+ (http://www.vagrantup.com/) set up and running, and you have the lucid32.box,
49
+ you can just do:
50
+
51
+ $ cd test && vagrant up
52
+
53
+ Once your VM is provisioned and running, ssh in (`vagrant ssh`) and then:
54
+
55
+ $ startx &
56
+ $ cd ~/casper/test
57
+ $ ruby casper_test.rb
58
+
59
+ If you don't have Vagrant set up, you can follow the getting started guide at
60
+ http://www.vagrantup.com/, or you can install the necessary dependencies on
61
+ your local machine and test locally. Instructions for installing the
62
+ dependencies can be found under `test/cookbooks`.
63
+
64
+ License
65
+ -------
66
+
67
+ Copyright (c) 2010 Ben Alavi and Chris Schneider
68
+
69
+ Permission is hereby granted, free of charge, to any person obtaining a copy
70
+ of this software and associated documentation files (the "Software"), to deal
71
+ in the Software without restriction, including without limitation the rights
72
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
73
+ copies of the Software, and to permit persons to whom the Software is
74
+ furnished to do so, subject to the following conditions:
75
+
76
+ The above copyright notice and this permission notice shall be included in
77
+ all copies or substantial portions of the Software.
78
+
79
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
80
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
81
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
82
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
83
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
84
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
85
+ THE SOFTWARE.
data/lib/casper.rb ADDED
@@ -0,0 +1,115 @@
1
+ require "libxdo"
2
+
3
+ module Casper
4
+ class Mouse
5
+ class << self
6
+ # Move the mouse directly to the specified x/y coordinates.
7
+ #
8
+ # If relative = true the x/y coordinates used are relative from the
9
+ # current position, otherwise they are considered to be absolute.
10
+ def move(x, y, relative=false)
11
+ relative ? relative(x, y) : absolute(x, y)
12
+ end
13
+
14
+ # Press the given mouse button down (default is 1: primary)
15
+ def down(button=1)
16
+ Libxdo.xdo_mousedown xdo, Libxdo::CurrentWindow, button
17
+ end
18
+
19
+ # Release the given mouse button (default is 1: primary)
20
+ def up(button=1)
21
+ Libxdo.xdo_mouseup xdo, Libxdo::CurrentWindow, button
22
+ end
23
+
24
+ # Click the given mouse button (default is 1: primary)
25
+ def click(button=1)
26
+ Libxdo.xdo_click xdo, Libxdo::CurrentWindow, button
27
+ end
28
+
29
+ # Gives the current mouse position
30
+ def location
31
+ x = FFI::MemoryPointer.new :pointer
32
+ y = FFI::MemoryPointer.new :pointer
33
+ s = FFI::MemoryPointer.new :pointer
34
+ Libxdo.xdo_mouselocation xdo, x, y, s
35
+ [ x.read_int, y.read_int ]
36
+ end
37
+
38
+ # Perform a drag operation with the given options. A drag is performed
39
+ # by moving the mouse to a starting location, pressing the primary mouse
40
+ # button down, incrementally moving to another location, and then
41
+ # releasing the primary mouse button.
42
+ #
43
+ # Available options are:
44
+ #
45
+ # * :from => [ x, y ] -- The absolute x/y coordinates to start from. If
46
+ # omitted the drag will be started from the current mouse location.
47
+ # * :to => [ x, y ] -- The absolute x/y coordinates to end at. Can use
48
+ # :distance instead for relative movements.
49
+ # * :distance => [ x, y ] -- Can be used instead of :to to provide an
50
+ # end point relative to the starting point.
51
+ # * :increments => i -- The number of increments to include in the drag
52
+ # from the start to the end, defaults to 10. More increments cause a
53
+ # smoother, slower drag. Fewer increments cause a faster "jerkier"
54
+ # drag.
55
+ #
56
+ # Also a block can be passed which will be yielded before the mouse is
57
+ # released. This can be used to drag and hover for a period of time, or
58
+ # chain multiple drags, etc...
59
+ #
60
+ # i.e.
61
+ #
62
+ # drag :to => [ 300, 350 ]
63
+ # drag :from => [ 200, 300 ], :to => [ 400, 800 ]
64
+ # drag :from => [ 200, 300 ], :distance => [ 200, 500 ]
65
+ # drag :from => [ 200, 300 ], :distance => [ 220, 340 ], :increments => 20
66
+ # drag :from => [ 200, 300 ], :to => [ 300, 400 ] do
67
+ # sleep 0.5
68
+ # end
69
+ # drag :distance => [ 20, 0 ] do
70
+ # drag :distance => [ 0, 30 ]
71
+ # end
72
+ def drag(options={}, &block)
73
+ raise ArgumentError.new(":to or :distance is required to provide ending location") unless options.has_key?(:to) || options.has_key?(:distance)
74
+ raise ArgumentError.new(":increments must be > 0") if options.has_key?(:increments) && options[:increments] <= 0
75
+
76
+ from ||= options[:from] || location
77
+ increments = options[:increments] || 10
78
+ distance = options[:distance] || [ options[:to][0] - from[0], options[:to][1] - from[1] ]
79
+
80
+ shift_x = distance[0] / increments
81
+ shift_y = distance[1] / increments
82
+
83
+ move from[0], from[1]
84
+ down
85
+ increments.times{ |i| move(shift_x, shift_y, true) }
86
+ yield if block_given?
87
+ up
88
+ end
89
+
90
+ private
91
+
92
+ # Returns a new xdo instance
93
+ def xdo
94
+ Libxdo.xdo_new(nil)
95
+ end
96
+
97
+ # Performs an absolute mouse move
98
+ def absolute(x, y)
99
+ xdor = xdo
100
+
101
+ Libxdo.xdo_mousemove(xdor, x, y, 0)
102
+ Libxdo.xdo_mouse_wait_for_move_to(xdor, x, y)
103
+ end
104
+
105
+ # Performs a relative mouse move
106
+ def relative(x, y)
107
+ xdor = xdo
108
+ loc = location
109
+
110
+ Libxdo.xdo_mousemove_relative(xdor, x, y)
111
+ Libxdo.xdo_mouse_wait_for_move_to(xdor, loc[0] + x, loc[1] + y)
112
+ end
113
+ end
114
+ end
115
+ end
data/lib/libxdo.rb ADDED
@@ -0,0 +1,256 @@
1
+ require "ffi"
2
+
3
+ module Casper
4
+ module Libxdo
5
+ extend FFI::Library
6
+
7
+ CurrentWindow = 0
8
+
9
+ ffi_lib "xdo"
10
+
11
+ # xdo_t * xdo_new (char *display)
12
+ attach_function "xdo_new", [ :string ], :pointer
13
+
14
+ # xdo_t * xdo_new_with_opened_display (Display *xdpy, const char *display, int close_display_when_freed)
15
+ attach_function "xdo_new_with_opened_display", [:pointer, :string, :int], :pointer
16
+
17
+ # const char * xdo_version (void)
18
+ attach_function "xdo_version", [], :string
19
+
20
+ # void xdo_free (xdo_t *xdo)
21
+ attach_function "xdo_free", [:pointer], :void
22
+
23
+ # int xdo_mousemove (const xdo_t *xdo, int x, int y, int screen)
24
+ attach_function "xdo_mousemove", [:pointer, :int, :int, :int], :int
25
+
26
+ # int xdo_mousemove_relative_to_window (const xdo_t *xdo, Window window, int x, int y)
27
+ # XXX: Window is not a pointer - find the typedef
28
+ attach_function "xdo_mousemove_relative_to_window", [:pointer, :pointer, :int, :int], :int
29
+
30
+ # int xdo_mousemove_relative (const xdo_t *xdo, int x, int y)
31
+ attach_function "xdo_mousemove_relative", [:pointer, :int, :int], :int
32
+
33
+ # int xdo_mousedown (const xdo_t *xdo, Window window, int button)
34
+ attach_function "xdo_mousedown", [:pointer, :int, :int], :int
35
+
36
+ # int xdo_mouseup (const xdo_t *xdo, Window window, int button)
37
+ attach_function "xdo_mouseup", [:pointer, :int, :int], :int
38
+
39
+ # int xdo_mouselocation (const xdo_t *xdo, int *x, int *y, int *screen_num)
40
+ attach_function "xdo_mouselocation", [:pointer, :pointer, :pointer, :pointer], :int
41
+
42
+ # int xdo_mouse_wait_for_move_from (const xdo_t *xdo, int origin_x, int origin_y)
43
+ attach_function "xdo_mouse_wait_for_move_from", [:pointer, :int, :int], :int
44
+
45
+ # int xdo_mouse_wait_for_move_to (const xdo_t *xdo, int dest_x, int dest_y)
46
+ attach_function "xdo_mouse_wait_for_move_to", [:pointer, :int, :int], :int
47
+
48
+ # int xdo_click (const xdo_t *xdo, Window window, int button)
49
+ attach_function "xdo_click", [:pointer, :int, :int], :int
50
+
51
+ # int xdo_type (const xdo_t *xdo, Window window, char *string, useconds_t delay)
52
+ # XXX: Map useconds_t
53
+ attach_function "xdo_type", [:pointer, :int, :string, :int], :int
54
+
55
+ # int xdo_keysequence (const xdo_t *xdo, Window window, const char *keysequence, useconds_t delay)
56
+ # XXX: Window != pointer
57
+ # XXX: Map useconds_t
58
+ attach_function "xdo_keysequence", [:pointer, :pointer, :string, :int], :int
59
+
60
+ # int xdo_keysequence_up (const xdo_t *xdo, Window window, const char *keysequence, useconds_t delay)
61
+ # XXX: Window != pointer
62
+ # XXX: Map useconds_t
63
+ attach_function "xdo_keysequence_up", [:pointer, :pointer, :string, :int], :int
64
+
65
+ # int xdo_keysequence_down (const xdo_t *xdo, Window window, const char *keysequence, useconds_t delay)
66
+ # XXX: Window != pointer
67
+ # XXX: Map useconds_t
68
+ attach_function "xdo_keysequence_down", [:pointer, :pointer, :string, :int], :int
69
+
70
+ # int xdo_keysequence_list_do (const xdo_t *xdo, Window window, charcodemap_t *keys, int nkeys, int pressed, int *modifier, useconds_t delay)
71
+ # XXX: Window != pointer
72
+ # XXX: What"s a charcodemap_t?
73
+ # XXX: Map useconds_t
74
+ attach_function "xdo_keysequence_list_do", [:pointer, :pointer, :pointer, :int, :int, :pointer, :int], :int
75
+
76
+ # int xdo_active_keys_to_keycode_list (const xdo_t *xdo, charcodemap_t **keys, int *nkeys)
77
+ # XXX: Map useconds_t
78
+ # XXX: What"s a pointer to pointer to charcodemap_t?
79
+ attach_function "xdo_active_keys_to_keycode_list", [:pointer, :pointer, :pointer], :int
80
+
81
+ # int xdo_window_wait_for_map_state (const xdo_t *xdo, Window wid, int map_state)
82
+ # XXX: Window != pointer
83
+ attach_function "xdo_window_wait_for_map_state", [:pointer, :pointer, :int], :int
84
+
85
+ # int xdo_window_move (const xdo_t *xdo, Window wid, int x, int y)
86
+ # XXX: Window != pointer
87
+ attach_function "xdo_window_move", [:pointer, :pointer, :int, :int], :int
88
+
89
+ # int xdo_window_setsize (const xdo_t *xdo, Window wid, int w, int h, int flags)
90
+ # XXX: Window != pointer
91
+ attach_function "xdo_window_setsize", [:pointer, :pointer, :int, :int, :int], :int
92
+
93
+ # int xdo_window_setprop (const xdo_t *xdo, Window wid, const char *property, const char *value)
94
+ # XXX: Window != pointer
95
+ attach_function "xdo_window_setprop", [:pointer, :pointer, :string, :string], :int
96
+
97
+ # int xdo_window_setclass (const xdo_t *xdo, Window wid, const char *name, const char *class)
98
+ # XXX: Window != pointer
99
+ attach_function "xdo_window_setclass", [:pointer, :pointer, :string, :string], :int
100
+
101
+ # int xdo_window_focus (const xdo_t *xdo, Window wid)
102
+ # XXX: Window != pointer
103
+ attach_function "xdo_window_focus", [:pointer, :pointer], :int
104
+
105
+ # int xdo_window_raise (const xdo_t *xdo, Window wid)
106
+ # XXX: Window != pointer
107
+ attach_function "xdo_window_raise", [:pointer, :pointer], :int
108
+
109
+ # int xdo_window_get_focus (const xdo_t *xdo, Window *window_ret)
110
+ # NOTE: This window is actually a pointer. Watch out
111
+ attach_function "xdo_window_get_focus", [:pointer, :pointer], :int
112
+
113
+ # int xdo_window_wait_for_focus (const xdo_t *xdo, Window window, int want_focus)
114
+ # XXX: Window != pointer
115
+ attach_function "xdo_window_wait_for_focus", [:pointer, :pointer, :int], :int
116
+
117
+ # int xdo_window_get_pid (const xdo_t *xdo, Window window)
118
+ # XXX: Window != pointer
119
+ attach_function "xdo_window_get_pid", [:pointer, :pointer], :int
120
+
121
+ # int xdo_window_sane_get_focus (const xdo_t *xdo, Window *window_ret)
122
+ # NOTE: This window is actually a pointer. Watch out
123
+ attach_function "xdo_window_sane_get_focus", [:pointer, :pointer], :int
124
+
125
+ # int xdo_window_activate (const xdo_t *xdo, Window wid)
126
+ # XXX: Window != pointer
127
+ attach_function "xdo_window_activate", [:pointer, :pointer], :int
128
+
129
+ # int xdo_window_wait_for_active (const xdo_t *xdo, Window window, int active)
130
+ # XXX: Window != pointer
131
+ attach_function "xdo_window_wait_for_active", [:pointer, :pointer, :int], :int
132
+
133
+ # int xdo_window_map (const xdo_t *xdo, Window wid)
134
+ # XXX: Window != pointer
135
+ attach_function "xdo_window_map", [:pointer, :pointer], :int
136
+
137
+ # int xdo_window_unmap (const xdo_t *xdo, Window wid)
138
+ attach_function "xdo_window_unmap", [:pointer, :pointer], :int
139
+
140
+ # int xdo_get_window_location (const xdo_t *xdo, Window wid, int *x_ret, int *y_ret, Screen **screen_ret)
141
+ # XXX: Window != pointer
142
+ # XXX: What"s a screen double pointer
143
+ attach_function "xdo_get_window_location", [:pointer, :pointer, :pointer, :pointer, :pointer], :int
144
+
145
+ # int xdo_get_window_size (const xdo_t *xdo, Window wid, unsigned int *width_ret, unsigned int *height_ret)
146
+ # XXX: Window != pointer
147
+ attach_function "xdo_get_window_size", [:pointer, :pointer, :pointer, :pointer], :int
148
+
149
+ # int xdo_window_get_active (const xdo_t *xdo, Window *window_ret)
150
+ # NOTE: This window is actually a pointer. Watch out
151
+ attach_function "xdo_window_get_active", [:pointer, :pointer], :int
152
+
153
+ # int xdo_set_number_of_desktops (const xdo_t *xdo, long ndesktops)
154
+ attach_function "xdo_set_number_of_desktops", [:pointer, :long], :int
155
+
156
+ # int xdo_get_number_of_desktops (const xdo_t *xdo, long *ndesktops)
157
+ attach_function "xdo_get_number_of_desktops", [:pointer, :pointer], :int
158
+
159
+ # int xdo_set_current_desktop (const xdo_t *xdo, long desktop)
160
+ attach_function "xdo_set_current_desktop", [:pointer, :long], :int
161
+
162
+ # int xdo_get_current_desktop (const xdo_t *xdo, long *desktop)
163
+ attach_function "xdo_get_current_desktop", [:pointer, :pointer], :int
164
+
165
+ # int xdo_set_desktop_for_window (const xdo_t *xdo, Window wid, long desktop)
166
+ # XXX: Window != pointer
167
+ attach_function "xdo_set_desktop_for_window", [:pointer, :pointer, :long], :int
168
+
169
+ # int xdo_get_desktop_for_window (const xdo_t *xdo, Window wid, long *desktop)
170
+ # XXX: Window != pointer
171
+ attach_function "xdo_get_desktop_for_window", [:pointer, :pointer, :pointer], :int
172
+
173
+ # int xdo_window_search (const xdo_t *xdo, const xdo_search_t *search, Window **windowlist_ret, int *nwindows_ret)
174
+ # XXX: xdo_search_t? How do I make that.
175
+ attach_function "xdo_window_search", [:pointer, :pointer, :pointer, :pointer], :int
176
+
177
+ # unsigned char * xdo_getwinprop (const xdo_t *xdo, Window window, Atom atom, long *nitems, Atom *type, int *size)
178
+ # XXX: Window != pointer
179
+ # XXX: Atom != pointer
180
+ # XXX: Unsigned char * != :string?
181
+ attach_function "xdo_getwinprop", [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :string
182
+
183
+ # unsigned int xdo_get_input_state (const xdo_t *xdo)
184
+ attach_function "xdo_get_input_state", [:pointer], :uint
185
+
186
+ # const keysym_charmap_t * xdo_keysym_charmap (void)
187
+ attach_function "xdo_keysym_charmap", [], :pointer
188
+
189
+ # XXX: char** is an array of strings?
190
+ # const char ** xdo_symbol_map (void)
191
+ attach_function "xdo_symbol_map", [], :string
192
+
193
+ # xdo_active_mods_t * xdo_get_active_modifiers (const xdo_t *xdo)
194
+ attach_function "xdo_get_active_modifiers", [:pointer], :pointer
195
+
196
+ # int xdo_clear_active_modifiers (const xdo_t *xdo, Window window, xdo_active_mods_t *active_mods)
197
+ attach_function "xdo_clear_active_modifiers", [:pointer, :pointer, :pointer], :int
198
+
199
+ # int xdo_set_active_modifiers (const xdo_t *xdo, Window window, const xdo_active_mods_t *active_mods)
200
+ # XXX: Window != pointer
201
+ attach_function "xdo_set_active_modifiers", [], :int
202
+
203
+ # void xdo_free_active_modifiers (xdo_active_mods_t *active_mods)
204
+ attach_function "xdo_free_active_modifiers", [:pointer], :void
205
+
206
+ class Xdo < FFI::Struct
207
+ # The Display for Xlib.
208
+ # Display * xdpy
209
+ layout :xdpy ,:pointer, # Display * xdpy
210
+ :display_name ,:string, # The display name.
211
+ :charcodes ,:pointer, # charcodemap_t * charcodes
212
+ :charcodes_len ,:int,
213
+ :modmap ,:pointer, # XModifierKeymap * modmap
214
+ :keymap ,:pointer, # KeySym * keymap
215
+ :keycode_high ,:int,
216
+ :keycode_low ,:int,
217
+ :keysyms_per_keycode ,:int,
218
+ :close_display_when_freed ,:int # Should we close the display when calling xdo_free?
219
+ end
220
+
221
+ class KeysymCharmap < FFI::Struct
222
+ layout :keysym ,:string,
223
+ :key ,:char
224
+ end
225
+
226
+ # XXX: Is the native documentation off by a field? Feels like it.
227
+ # class Charcodemap < FFI::Struct
228
+ # # XXX: keycode isn"t a type
229
+ # layout :code ,:KeyCode, # the letter for this key, like "a"
230
+ # :symbol ,:KeySym, # the keycode that this key is on
231
+ # :index ,:int, # the symbol representing this key
232
+ # :modmask ,:int, # the index in the keysym-per-keycode list that is this key
233
+ # :needs_binding ,:int # the modifiers activated by this key
234
+ # end
235
+
236
+ class XdoActiveMods < FFI::Struct
237
+ layout :keymods, :pointer, # charcodemap_t * keymods
238
+ :nkeymods, :int, # int nkeymods
239
+ :input_state, :uint # unsigned int input_state
240
+ end
241
+
242
+ # class XdoSearch < FFI::Struct
243
+ # layout :title ,:string, # char * title
244
+ # :winclass ,:string, # char * winclass # pattern to test against a window title
245
+ # :winclassname ,:string, # char * winclassname # pattern to test against a window class
246
+ # :winname ,:string, # char * winname # pattern to test against a window class
247
+ # :pid ,:int, # int pid # window pid (From window atom _NET_WM_PID)
248
+ # :max_depth ,:long, # long max_depth # depth of search.
249
+ # :only_visible ,:int, # only_visible boolean; set true to search only visible windows
250
+ # :screen ,:int, # screen
251
+ # # XXX: Map this enum. Not sure how that works.
252
+ # :xdo_search ,:search_enum, # what screen to search, if any.
253
+ # :searchmask ,:uint # unsigned int searchmask # bitmask of things you are searching for, such as SEARCH_NAME , etc.
254
+ # end
255
+ end
256
+ end
data/test/Vagrantfile ADDED
@@ -0,0 +1,20 @@
1
+ Vagrant::Config.run do |config|
2
+ config.vm.box = "base"
3
+ config.vm.customize do |vm|
4
+ vm.name = "casper"
5
+ vm.memory_size = 512
6
+ end
7
+
8
+ config.vm.network("33.33.33.10")
9
+ config.vm.share_folder("v-root", "~/casper", "..", :nfs => true)
10
+ config.vm.provisioner = :chef_solo
11
+ config.vm.boot_mode = :gui
12
+
13
+ config.chef.run_list = %w(
14
+ recipe[application::vagrant]
15
+ recipe[rvm]
16
+ recipe[testing]
17
+ )
18
+
19
+ config.chef.log_level = :debug
20
+ end
@@ -0,0 +1,116 @@
1
+ require File.dirname(__FILE__) + "/lib/test_helper"
2
+ require "casper"
3
+
4
+ # Yeah, we use Capybara & Selenium & jQuery & Firefox and X11 and all sorts
5
+ # of other stuff when we could just as easily mock out the xdo lib and
6
+ # simply make sure we're sending the right commands.
7
+ #
8
+ # But this is way more fun =)
9
+ class CasperTest < Test::Unit::TestCase
10
+ # Places a target div onto the document body with the given attributes
11
+ def target!(id, x, y, width=50, height=50)
12
+ evaluate_script <<-JS
13
+ $('<div class="target" id="#{id}"></div>').
14
+ appendTo("body").
15
+ css({ left: #{x}, top: #{y}, width: #{width}, height: #{height }}).
16
+ draggable()
17
+ JS
18
+ end
19
+
20
+ setup do
21
+ Casper::Mouse.move 0, 0
22
+ # Gets rid of the menu if it was left open (i.e. from leaving the mouse
23
+ # button down and moving over it).
24
+ Casper::Mouse.click
25
+ resize_browser 1024, 768
26
+ visit "/"
27
+ end
28
+
29
+ describe "mouse actions" do
30
+ setup do
31
+ target! "a", 300, 220
32
+ end
33
+
34
+ should "position the mouse at 320, 240" do
35
+ assert !has_class?("#a", "mouseover")
36
+
37
+ Casper::Mouse.move(320, 350)
38
+ assert has_class?("#a", "mouseover")
39
+ end
40
+
41
+ should "press the primary mouse button down on the element" do
42
+ assert !has_class?("#a", "mousedown")
43
+
44
+ Casper::Mouse.move(320, 350)
45
+ Casper::Mouse.down(1)
46
+ assert has_class?("#a", "mousedown")
47
+ end
48
+
49
+ should "release the primary mouse button on the element" do
50
+ assert !has_class?("#a", "mousedown")
51
+
52
+ Casper::Mouse.move(320, 350)
53
+ Casper::Mouse.down(1)
54
+ assert has_class?("#a", "mousedown")
55
+
56
+ Casper::Mouse.up(1)
57
+ assert !has_class?("#a", "mousedown")
58
+ end
59
+
60
+ should "provide the current mouse location" do
61
+ Casper::Mouse.move 318, 473
62
+ assert_equal [ 318, 473 ], Casper::Mouse.location
63
+ end
64
+ end
65
+
66
+ describe "dragging" do
67
+ setup do
68
+ target! "a", 300, 220
69
+ end
70
+
71
+ should "drag an item" do
72
+ Casper::Mouse.drag :from => [ 320, 350 ], :to => [ 350, 400 ]
73
+ assert_has_position? "#a", :left => 330, :top => 270
74
+ end
75
+
76
+ should "use the current mouse position when no :from option is provided" do
77
+ Casper::Mouse.move 320, 350
78
+ assert_has_position? "#a", :left => 300, :top => 220
79
+
80
+ Casper::Mouse.drag :distance => [ 20, 20 ]
81
+ assert_has_position? "#a", :left => 320, :top => 240
82
+ end
83
+
84
+ should "move from the current mouse position to the specified position when :to is provided without :from" do
85
+ Casper::Mouse.move 320, 350
86
+ assert_has_position? "#a", :left => 300, :top => 220
87
+
88
+ Casper::Mouse.drag :to => [ 410, 510 ]
89
+ assert_has_position? "#a", :left => 390, :top => 380
90
+ end
91
+
92
+ should "have a default increments value, making it an optional parameter" do
93
+ Casper::Mouse.drag :from => [ 1, 1 ], :to => [ 2, 2 ]
94
+ end
95
+
96
+ should "not raise an argument error if you have a positive increment value" do
97
+ Casper::Mouse.drag :from => [ 1, 1 ], :to => [ 2, 2 ], :increment => 5
98
+ end
99
+
100
+ should "raise an argument error if you have a negative, or 0 increment" do
101
+ assert_raise ArgumentError do
102
+ Casper::Mouse.drag :from => [ 1, 1 ], :to => [ 2, 2 ], :increments => 0
103
+ end
104
+
105
+ assert_raise ArgumentError do
106
+ Casper::Mouse.drag :from => [ 1, 1 ], :to => [ 2, 2 ], :increments => -5
107
+ end
108
+ end
109
+
110
+ should "raise argument error if you did not provide either to or distance" do
111
+ assert_raise ArgumentError do
112
+ Casper::Mouse.drag :from => [ 1, 1 ]
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,6 @@
1
+ require_recipe "apt"
2
+
3
+ # Packages needed
4
+ package "git-core"
5
+ package "libxml2-dev"
6
+ package "libxslt1-dev"
@@ -0,0 +1 @@
1
+ require_recipe "application"
@@ -0,0 +1,11 @@
1
+ <VirtualHost *:80>
2
+ DocumentRoot <%= @node[:vagrant][:directory] %>/public
3
+
4
+ RackEnv development
5
+ RailsEnv development
6
+
7
+ <Directory <%= @node[:vagrant][:directory] %>/public>
8
+ Allow from all
9
+ Options -MultiViews
10
+ </Directory>
11
+ </VirtualHost>
@@ -0,0 +1,44 @@
1
+ DESCRIPTION
2
+ ===========
3
+
4
+ Configures various APT components on Debian-like systems.
5
+
6
+ RECIPES
7
+ =======
8
+
9
+ default
10
+ -------
11
+
12
+ The default recipe runs apt-get update during the Compile Phase of the Chef run to ensure that the system's package cache is updated with the latest. It is recommended that this recipe appear first in a node's run list (directly or through a role) to ensure that when installing packages, Chef will be able to download the latest version available on the remote APT repository.
13
+
14
+ This recipe also sets up a local cache directory for preseeding packages.
15
+
16
+ cacher
17
+ ------
18
+
19
+ Installs the apt-cacher package and service so the system can be an APT cache.
20
+
21
+ proxy
22
+ -----
23
+
24
+ Installs the apt-proxy package and service so the system can be an APT proxy.
25
+
26
+ LICENSE AND AUTHOR
27
+ ==================
28
+
29
+ Author:: Joshua Timberman (<joshua@opscode.com>)
30
+
31
+ Copyright 2009, Opscode, Inc.
32
+
33
+ Licensed under the Apache License, Version 2.0 (the "License");
34
+ you may not use this file except in compliance with the License.
35
+ You may obtain a copy of the License at
36
+
37
+ http://www.apache.org/licenses/LICENSE-2.0
38
+
39
+ Unless required by applicable law or agreed to in writing, software
40
+ distributed under the License is distributed on an "AS IS" BASIS,
41
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
42
+ See the License for the specific language governing permissions and
43
+ limitations under the License.
44
+
@@ -0,0 +1,9 @@
1
+ # apt-cacher startup configuration file
2
+
3
+ # IMPORTANT: check the apt-cacher.conf file before using apt-cacher as daemon.
4
+
5
+ # set to 1 to start the daemon at boot time
6
+ AUTOSTART=1
7
+
8
+ # extra settings to override the ones in apt-cacher.conf
9
+ # EXTRAOPT=" daemon_port=3142 limit=30 "