pyrite 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/lib/pyrite.rb +28 -0
- data/lib/pyrite/assertions.rb +26 -0
- data/lib/pyrite/dsl.rb +116 -0
- data/lib/pyrite/helpers.rb +10 -0
- data/lib/pyrite/pyrite_test.rb +34 -0
- data/lib/pyrite/tasks.rb +2 -0
- data/lib/pyrite/tasks/pyrite.rb +36 -0
- data/lib/pyrite/tasks/selenium.rb +20 -0
- data/tasks/pyrite.rake +1 -0
- metadata +113 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Dean Strelau, Mint Digital Ltd.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/pyrite.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'selenium/client'
|
2
|
+
|
3
|
+
require 'database_cleaner'
|
4
|
+
DatabaseCleaner.strategy = :truncation
|
5
|
+
|
6
|
+
require 'pyrite/pyrite_test'
|
7
|
+
|
8
|
+
module Pyrite
|
9
|
+
# The port on which the test server will be booted
|
10
|
+
mattr_accessor :server_port
|
11
|
+
@@server_port = 2222
|
12
|
+
|
13
|
+
# The ip address the RC is running on
|
14
|
+
mattr_accessor :rc_host
|
15
|
+
@@rc_host = ENV['RC_HOST'] || '0.0.0.0'
|
16
|
+
|
17
|
+
# The url on which the test server will be booted
|
18
|
+
mattr_accessor :sever_url
|
19
|
+
@@sever_url = ENV['SERVER_URL'] || 'http://localhost'
|
20
|
+
|
21
|
+
# The browser that selenium will drive
|
22
|
+
mattr_accessor :browser
|
23
|
+
@@browser = ENV['BROWSER'] || '*chrome'
|
24
|
+
|
25
|
+
# The timeout for Selenium::Client
|
26
|
+
mattr_accessor :timeout
|
27
|
+
@@timeout = 60
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Pyrite
|
2
|
+
module Assertions
|
3
|
+
|
4
|
+
# Assert some text appears somewhere on the page
|
5
|
+
def assert_text(text, msg=nil)
|
6
|
+
assert browser.text?(text), msg || "Text '#{text}' not found on page"
|
7
|
+
end
|
8
|
+
|
9
|
+
# Assert some text does not appear somewhere on the page
|
10
|
+
def assert_no_text(text, msg=nil)
|
11
|
+
assert !browser.text?(text), msg || "Text '#{text}' not found on page"
|
12
|
+
end
|
13
|
+
|
14
|
+
# Assert an element appears on the page via CSS selector
|
15
|
+
def assert_element(selector, msg=nil)
|
16
|
+
assert browser.element?("css=#{selector}"),
|
17
|
+
msg || "Element '#{selector}' not found on page"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Assert an element does not appear on the page via CSS selector
|
21
|
+
def assert_no_element(selector, msg=nil)
|
22
|
+
assert !browser.element?("css=#{selector}"),
|
23
|
+
msg || "Element '#{selector}' was found on page but shouldn't be"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/pyrite/dsl.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
module Pyrite
|
2
|
+
module Dsl
|
3
|
+
|
4
|
+
# Fill in a form field
|
5
|
+
def fill_in(element, value)
|
6
|
+
if element.match /date/ # Try to guess at date selects
|
7
|
+
select_date(element, value)
|
8
|
+
else
|
9
|
+
browser.type(element, value)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Fill in a Rails-ish set of date_select fields
|
14
|
+
def select_date(element, value)
|
15
|
+
suffixes = {
|
16
|
+
:year => '1i',
|
17
|
+
:month => '2i',
|
18
|
+
:day => '3i',
|
19
|
+
:hour => '4i',
|
20
|
+
:minute => '5i'
|
21
|
+
}
|
22
|
+
date = value.respond_to?(:year) ? value : Date.parse(value)
|
23
|
+
browser.select "#{element}_#{suffixes[:year]}", date.year
|
24
|
+
browser.select "#{element}_#{suffixes[:month]}", date.strftime('%B')
|
25
|
+
browser.select "#{element}_#{suffixes[:day]}", date.day
|
26
|
+
end
|
27
|
+
|
28
|
+
# Open a URL
|
29
|
+
def visit(path)
|
30
|
+
browser.open(path)
|
31
|
+
wait_for :page_load
|
32
|
+
end
|
33
|
+
|
34
|
+
# Follow a link based on its text
|
35
|
+
def follow(text)
|
36
|
+
browser.click("link=#{text}")
|
37
|
+
end
|
38
|
+
|
39
|
+
# Press a button based on its text
|
40
|
+
def press(text)
|
41
|
+
browser.click("css=input[type=submit][value='#{text}']")
|
42
|
+
end
|
43
|
+
|
44
|
+
# Check a chek box or toggle a radio button
|
45
|
+
def check(locator)
|
46
|
+
browser.check(locator)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Click anything else
|
50
|
+
def click(locator)
|
51
|
+
browser.click(locator)
|
52
|
+
end
|
53
|
+
|
54
|
+
def attach(field, file)
|
55
|
+
browser.attach(field, "http://test.rodreegez.com/#{file}")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Pick an option from a select element
|
59
|
+
def select(element, option)
|
60
|
+
browser.select(element, option)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Wait for a specific element or the page to load
|
64
|
+
def wait_for(element)
|
65
|
+
if element == :page_load
|
66
|
+
browser.wait_for_page_to_load
|
67
|
+
else
|
68
|
+
browser.wait_for_element(element)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Wait for a frame with a give ID to finish loading
|
73
|
+
def wait_for_frame(frame)
|
74
|
+
browser.wait_for_frame_to_load(frame, 5000)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Excecute commands within an iframe, then switch back to the parent frame
|
78
|
+
# i.e.
|
79
|
+
# inside_frame(iframe) do
|
80
|
+
# click "Submit"
|
81
|
+
# end
|
82
|
+
def inside_iframe(frame)
|
83
|
+
wait_for frame
|
84
|
+
browser.select_frame(frame)
|
85
|
+
wait_for_frame frame
|
86
|
+
yield
|
87
|
+
browser.select_frame("relative=parent")
|
88
|
+
end
|
89
|
+
|
90
|
+
# Use this to consume JS alerts
|
91
|
+
# i.e.
|
92
|
+
# follow 'delete'
|
93
|
+
# get_confirmation
|
94
|
+
# !assert_element "h2:contains('user1')"
|
95
|
+
def get_confirmation
|
96
|
+
browser.get_confirmation
|
97
|
+
end
|
98
|
+
|
99
|
+
# drag an css selector to the center pixel of another, e.g.
|
100
|
+
# `drag_and_drop(:from => "li#element_#{my_oject.id}", :to => "div#trash")
|
101
|
+
# ProTip: if you have a list of elements you wish to re-order, drag the top element down.
|
102
|
+
def drag_and_drop(opts={})
|
103
|
+
browser.drag_and_drop_to_object("css=#{opts[:from]}", "css=#{opts[:to]}")
|
104
|
+
end
|
105
|
+
|
106
|
+
# Capture the page and try to open it
|
107
|
+
# (probably only works on os x)
|
108
|
+
def show_me
|
109
|
+
image = "#{Rails.root.join('tmp')}/pyrite-#{Time.now.to_i}.png"
|
110
|
+
browser.capture_entire_page_screenshot(image, '')
|
111
|
+
puts `open #{image}`
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'pyrite/dsl'
|
2
|
+
require 'pyrite/assertions'
|
3
|
+
require 'pyrite/helpers'
|
4
|
+
|
5
|
+
module Pyrite
|
6
|
+
class PyriteTest < ActionController::IntegrationTest
|
7
|
+
include Dsl
|
8
|
+
include Assertions
|
9
|
+
include Helpers
|
10
|
+
|
11
|
+
self.use_transactional_fixtures = false
|
12
|
+
|
13
|
+
def browser
|
14
|
+
$browser ||= Selenium::Client::Driver.new(
|
15
|
+
:host => Pyrite.rc_host,
|
16
|
+
:port => 4444,
|
17
|
+
:browser => Pyrite.browser,
|
18
|
+
:url => "#{Pyrite.sever_url}:#{Pyrite.server_port}",
|
19
|
+
:timeout_in_second => Pyrite.timeout
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup
|
24
|
+
DatabaseCleaner.clean
|
25
|
+
browser.start_new_browser_session
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def teardown
|
30
|
+
super
|
31
|
+
browser.close_current_browser_session
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/pyrite/tasks.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
namespace :pyrite do
|
2
|
+
Rake::TestTask.new(:run) do |t|
|
3
|
+
t.libs << "test"
|
4
|
+
t.pattern = 'test/pyrite/**/*_test.rb'
|
5
|
+
t.verbose = true
|
6
|
+
end
|
7
|
+
task :run # stub so that below will work
|
8
|
+
Rake::Task['pyrite:run'].comment = "Full-stack in-browser tests with pyrite"
|
9
|
+
|
10
|
+
desc "Startup Selenium RC and the server for browser testing"
|
11
|
+
task :start => 'selenium:start' do
|
12
|
+
puts `thin start -e pyrite -p 2222 -d`
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Shutdown Selenium RC and the server for browser testing"
|
16
|
+
task :stop do
|
17
|
+
begin
|
18
|
+
Rake::Task['selenium:stop'].invoke
|
19
|
+
rescue Errno::ECONNREFUSED => boom
|
20
|
+
puts "*** Could not connect to Selenium RC. Assuming it is not running."
|
21
|
+
end
|
22
|
+
if File.exist?(pidfile = Rails.root+'tmp/pids/server.pid')
|
23
|
+
puts "Stopping server process #{pid = File.read(pidfile)}"
|
24
|
+
Process.kill 'QUIT', Integer(pid)
|
25
|
+
else
|
26
|
+
puts "*** Could not read pid file for server. Assuming it is not running."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Start, run then stop pyrite"
|
31
|
+
task :all do
|
32
|
+
Rake::Task['pyrite:start'].invoke
|
33
|
+
Rake::Task['pyrite:run'].invoke
|
34
|
+
Rake::Task['pyrite:stop'].invoke
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'selenium/rake/tasks'
|
2
|
+
require 'selenium_remote_control'
|
3
|
+
|
4
|
+
namespace :selenium do
|
5
|
+
Selenium::Rake::RemoteControlStartTask.new(:start) do |rc|
|
6
|
+
rc.port = 4444
|
7
|
+
rc.timeout_in_seconds = 3 * 60
|
8
|
+
rc.background = true
|
9
|
+
rc.wait_until_up_and_running = true
|
10
|
+
rc.log_to = 'log/selenium_rc.log'
|
11
|
+
rc.additional_args << "-singleWindow"
|
12
|
+
rc.jar_file = SeleniumRC.jar_file
|
13
|
+
end
|
14
|
+
|
15
|
+
Selenium::Rake::RemoteControlStopTask.new(:stop) do |rc|
|
16
|
+
rc.host = "localhost"
|
17
|
+
rc.port = 4444
|
18
|
+
rc.timeout_in_seconds = 3 * 60
|
19
|
+
end
|
20
|
+
end
|
data/tasks/pyrite.rake
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'pyrite/tasks'
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pyrite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 5
|
8
|
+
- 0
|
9
|
+
version: 0.5.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Adam Rogers
|
13
|
+
- Dean Strelau
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-03-26 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: selenium-client
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 2
|
31
|
+
- 18
|
32
|
+
version: 1.2.18
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: selenium_remote_control
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 1
|
44
|
+
- 0
|
45
|
+
- 3
|
46
|
+
version: 1.0.3
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: database_cleaner
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ~>
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
- 5
|
59
|
+
- 0
|
60
|
+
version: 0.5.0
|
61
|
+
type: :runtime
|
62
|
+
version_requirements: *id003
|
63
|
+
description: A small, simple testing framework for use with selenium
|
64
|
+
email: adam@mintdigital.com
|
65
|
+
executables: []
|
66
|
+
|
67
|
+
extensions: []
|
68
|
+
|
69
|
+
extra_rdoc_files: []
|
70
|
+
|
71
|
+
files:
|
72
|
+
- lib/pyrite/assertions.rb
|
73
|
+
- lib/pyrite/dsl.rb
|
74
|
+
- lib/pyrite/helpers.rb
|
75
|
+
- lib/pyrite/pyrite_test.rb
|
76
|
+
- lib/pyrite/tasks.rb
|
77
|
+
- lib/pyrite/tasks/pyrite.rb
|
78
|
+
- lib/pyrite/tasks/selenium.rb
|
79
|
+
- lib/pyrite.rb
|
80
|
+
- MIT-LICENSE
|
81
|
+
- tasks/pyrite.rake
|
82
|
+
has_rdoc: true
|
83
|
+
homepage: http://github.com/mintdigital/pyrite
|
84
|
+
licenses: []
|
85
|
+
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
version: "0"
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
segments:
|
103
|
+
- 0
|
104
|
+
version: "0"
|
105
|
+
requirements: []
|
106
|
+
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 1.3.6
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: Easy peasy browser testing
|
112
|
+
test_files: []
|
113
|
+
|