metry 2.0.3 → 2.0.4

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.
@@ -1,3 +1,10 @@
1
+ === 2.0.4 / 2009-08-09
2
+
3
+ * Improved goal display.
4
+ * Properly submoduled webrat.
5
+ * Goal paths are now Regexp's.
6
+ * Added goal editing.
7
+
1
8
  === 2.0.3 / 2009-08-08
2
9
 
3
10
  * Really ignore events generated by Psycho.
data/TODO CHANGED
@@ -1,5 +1,3 @@
1
- Figure out why Psycho events are not being ignored in production
2
- Allow goals to have N paths
3
1
  Limit visitors on dashboard to 10 most recent
4
2
  Add full listing of visitors
5
3
  Show more details about visitors
@@ -8,8 +6,6 @@ Add display of last 10 events to dashboard
8
6
  Show goal conversion for each experiment
9
7
  Allow manually viewing a particular alternatively
10
8
 
11
- Switch to submodules for vendor'd libs
12
-
13
9
  More unit tests
14
10
 
15
11
  Add support for non-pageview event tracking
@@ -11,14 +11,43 @@ Feature: Track Goals
11
11
  Scenario: Create a goal
12
12
  Given I view "/admin/metry"
13
13
  And I follow "New Goal"
14
- And I fill in "name" with "Cool goal"
14
+ And I fill in "name" with "Cool"
15
15
  And I fill in "path" with "/goal"
16
16
  And I press "Create"
17
- Then I should be on "/admin/metry/"
18
- And the page should have "#goals .goal"
17
+ Then I should be on "/admin/metry/goals/1"
18
+ And I should see "Cool"
19
19
 
20
20
  Scenario: Goal count
21
21
  Given I add a goal named "My Goal" with path "/"
22
22
  And I view "/"
23
23
  When I view "/admin/metry"
24
- Then I should see "My Goal: 1 visits"
24
+ Then I should see "My Goal: 1 visits"
25
+
26
+ Scenario: Goal Regexp
27
+ Given I add a goal named "Subpage" with path "/subpage/?"
28
+ When I view "/subpage"
29
+ And I view "/subpage/"
30
+ And I view "/admin/metry"
31
+ Then I should see "Subpage: 2 visits"
32
+
33
+ Scenario: View Goal Detail
34
+ Given I add a goal named "Root" with path "/"
35
+ And I view "/"
36
+ And I view "/"
37
+ When I view "/admin/metry"
38
+ And I follow "Root"
39
+ Then I should see "Root"
40
+ And I should see "Path: /"
41
+ And I should see "Visitor 1"
42
+
43
+ Scenario: Edit a Goal
44
+ Given I add a goal named "Bogus" with path "/"
45
+ When I view "/admin/metry"
46
+ And I follow "Bogus"
47
+ And I follow "Edit"
48
+ And I fill in "name" with "Right"
49
+ And I fill in "path" with "/subpage"
50
+ And I press "Save"
51
+ Then I should be on "/admin/metry/goals/1"
52
+ And I should see "Right"
53
+ And I should see "Path: /subpage"
@@ -6,7 +6,7 @@ require 'metry/experiment'
6
6
  require 'metry/psycho'
7
7
 
8
8
  module Metry
9
- VERSION = '2.0.3'
9
+ VERSION = '2.0.4'
10
10
 
11
11
  def self.init(dbname)
12
12
  @storage = Storage.new(dbname)
@@ -30,46 +30,88 @@ module Metry
30
30
  erb :dashboard
31
31
  end
32
32
 
33
- get "#{path}/visitor/:id" do
33
+ get "#{path}/visitors/:id" do
34
34
  @visitor = Visitor.find(params["id"])
35
35
  erb :visitor
36
36
  end
37
37
 
38
38
  post "#{path}/goals" do
39
- Goal.create!(params[:name], params[:path])
40
- redirect url('/')
39
+ goal = Goal.create!(params[:name], params[:path])
40
+ redirect url("/goals/#{goal.id}")
41
41
  end
42
42
 
43
43
  get "#{path}/goals/new" do
44
44
  erb :new_goal
45
45
  end
46
+
47
+ get "#{path}/goals/:id" do
48
+ @goal = Goal.find(params[:id])
49
+ erb :goal
50
+ end
51
+
52
+ get "#{path}/goals/:id/edit" do
53
+ @goal = Goal.find(params[:id])
54
+ erb :edit_goal
55
+ end
56
+
57
+ post "#{path}/goals/:id" do
58
+ goal = Goal.find(params[:id])
59
+ goal.name = params[:name]
60
+ goal.path = params[:path]
61
+ goal.save
62
+ redirect url("/goals/#{goal.id}")
63
+ end
46
64
 
47
65
  helpers do
48
66
  define_method(:url) do |url|
49
67
  "#{path}#{url}"
50
68
  end
69
+
70
+ include ::Rack::Utils
71
+ alias_method :h, :escape_html
51
72
  end
52
73
  end
53
74
  end
54
75
 
55
76
  class Goal
77
+ def self.find(id)
78
+ new(Metry.current.goal(id))
79
+ end
80
+
56
81
  def self.create!(name, path)
57
- Metry.current.add_goal('name' => name, 'path' => path)
82
+ new(Metry.current.add_goal('name' => name, 'path' => path))
58
83
  end
59
84
 
60
85
  def self.all
61
86
  Metry.current.goals.collect{|e| new(e)}
62
87
  end
63
88
 
64
- attr_reader :name, :path
89
+ attr_accessor :path, :id, :name
65
90
 
66
91
  def initialize(hash)
92
+ @id = hash['_id'].to_s
67
93
  @name = hash['name']
68
94
  @path = hash['path']
69
95
  end
70
96
 
97
+ def save
98
+ Metry.current.save_goal({'_id' => id, 'name' => name, 'path' => path})
99
+ end
100
+
101
+ def path_regexp
102
+ Regexp.new("^#{path}$")
103
+ end
104
+
71
105
  def visits
72
- Metry.current.all_events({'path' => @path}).size
106
+ events.size
107
+ end
108
+
109
+ def events
110
+ Metry.current.all_events({'path' => path_regexp})
111
+ end
112
+
113
+ def visitors
114
+ events.collect{|e| e['visitor']}.uniq.collect{|e| Visitor.find(e)}
73
115
  end
74
116
  end
75
117
 
@@ -1,7 +1,7 @@
1
1
  <h1>Goals</h1>
2
2
  <ul id="goals">
3
3
  <% @goals.each do |goal| %>
4
- <li class="goal"><%= goal.name %>: <%= goal.visits %> visits</li>
4
+ <li class="goal"><a href="<%= url "/goals/#{goal.id}" %>"><%= goal.name %></a>: <%= goal.visits %> visits</li>
5
5
  <% end %>
6
6
  </ul>
7
7
  <p><a href="<%= url "/goals/new" %>">New Goal</a></p>
@@ -9,6 +9,6 @@
9
9
  <h1>Recent Visitors</h1>
10
10
  <ul>
11
11
  <% @visitors.each do |v| %>
12
- <li><a href="<%= url "/visitor/#{v.id}" %>">Visitor <%= v.id %></a> (<%= v.events.size %> events)</li>
12
+ <li><a href="<%= url "/visitors/#{v.id}" %>">Visitor <%= v.id %></a> (<%= v.events.size %> events)</li>
13
13
  <% end %>
14
14
  </ul>
@@ -1,9 +1,9 @@
1
1
  <h1>New Goal</h1>
2
2
 
3
- <form action="<%= url "/goals" %>" method="POST">
3
+ <form action="<%= url "/goals" %>" method="post">
4
4
  <fieldset>
5
- <p><label for="name">Name</label><input type="text" name="name" /></p>
6
- <p><label for="path">Path</label><input type="text" name="path" /></p>
5
+ <p><label for="name">Name</label> <input type="text" name="name" /></p>
6
+ <p><label for="path">Path</label> <input type="text" name="path" /></p>
7
7
  <p><input type="submit" value="Create" /></p>
8
8
  </fieldset>
9
9
  </form>
@@ -74,12 +74,20 @@ module Metry
74
74
  end
75
75
 
76
76
  def add_goal(goal)
77
- @db.collection('goals') << goal
77
+ goal(@db.collection('goals').insert(goal))
78
78
  end
79
79
 
80
80
  def goals
81
81
  @db.collection('goals').find.to_a
82
82
  end
83
+
84
+ def goal(id)
85
+ @db.collection('goals').find(prep_selector('_id' => id)).next_object
86
+ end
87
+
88
+ def save_goal(goal)
89
+ @db.collection('goals').repsert(prep_selector('_id' => goal['_id']), goal)
90
+ end
83
91
 
84
92
  def clear
85
93
  %w(visitors events goals).each{|e| @db.drop_collection(e)}
@@ -9,6 +9,8 @@
9
9
 
10
10
  * Minor enhancements
11
11
 
12
+ * Upgrade to selenium-client to 1.2.16 (Brian Landau)
13
+ * Upgrade selenium-server.jar to 1.0.1 (Brian Landau)
12
14
  * Make redirect detection work in the face of rational maths (like when ruby-units is active) (Piers Cawley)
13
15
  * Use Launchy to handle opening pages in the browser with cross-platform compatibility (Bryan Helmkamp)
14
16
  * Added support for field_labeled_locators ending in non word characters
@@ -23,8 +23,14 @@ module Webrat
23
23
  def process_request(http_method, url, data = {}, headers = {})
24
24
  headers ||= {}
25
25
  data ||= {}
26
-
27
- env = headers.merge(:params => data, :method => http_method.to_s.upcase)
26
+
27
+ params = data.inject({}) do |data, (key,value)|
28
+ data[key] = Rack::Utils.unescape(value)
29
+ data
30
+ end
31
+
32
+ headers["HTTP_HOST"] = "www.example.com"
33
+ env = headers.merge(:params => params, :method => http_method.to_s.upcase)
28
34
  @rack_test_session.request(url, env)
29
35
  end
30
36
 
@@ -1,5 +1,5 @@
1
1
  require "webrat"
2
- gem "selenium-client", ">=1.2.14"
2
+ gem "selenium-client", ">=1.2.16"
3
3
  require "selenium/client"
4
4
  require "webrat/selenium/silence_stream"
5
5
  require "webrat/selenium/selenium_session"
@@ -34,7 +34,7 @@ module Webrat
34
34
 
35
35
  @remote_control = ::Selenium::RemoteControl::RemoteControl.new("0.0.0.0",
36
36
  Webrat.configuration.selenium_server_port,
37
- Webrat.configuration.selenium_browser_startup_timeout)
37
+ :timeout => Webrat.configuration.selenium_browser_startup_timeout)
38
38
  @remote_control.jar_file = jar_path
39
39
 
40
40
  return @remote_control
@@ -74,7 +74,9 @@ module Webrat
74
74
 
75
75
  def stop
76
76
  silence_stream(STDOUT) do
77
- ::Selenium::RemoteControl::RemoteControl.new("0.0.0.0", Webrat.configuration.selenium_server_port, 5).stop
77
+ ::Selenium::RemoteControl::RemoteControl.new("0.0.0.0",
78
+ Webrat.configuration.selenium_server_port,
79
+ :timeout => 5).stop
78
80
  end
79
81
  end
80
82
 
@@ -2,8 +2,74 @@ require "rubygems"
2
2
  require "sinatra/base"
3
3
 
4
4
  class RackApp < Sinatra::Default
5
+ template :layout do
6
+ <<TEMPLATE
7
+ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
8
+ <html>
9
+ <title>sinatra testing with webrat</title>
10
+ <body>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
14
+ TEMPLATE
15
+ end
16
+
17
+ template :home do
18
+ <<TEMPLATE
19
+ <p> visit <a href="/go">there</a></p>
20
+
21
+ <form>
22
+ <label>
23
+ Prefilled
24
+ <input type="text" name="prefilled" value="text" />
25
+ </label>
26
+ </form>
27
+ TEMPLATE
28
+ end
29
+
30
+ template :go do
31
+ <<TEMPLATE
32
+ <form method="post" action="/go">
33
+ <div>
34
+ <label for="name">Name</label>
35
+ <input type="text" name="name" id="name">
36
+ </div>
37
+ <div>
38
+ <label for="email">Email</label>
39
+ <input type="text" name="email" id="email">
40
+ </div>
41
+ <input type="submit" value="Submit" />
42
+ </form>
43
+ TEMPLATE
44
+ end
45
+
46
+ template :hello do
47
+ <<TEMPLATE
48
+ <p>Hello, <%= @user %></p>
49
+ <p>Your email is: <%= @email %></p>
50
+ TEMPLATE
51
+ end
52
+
5
53
  get "/" do
6
- "Hello World"
54
+ erb :home
55
+ end
56
+
57
+ get "/go" do
58
+ erb :go
59
+ end
60
+
61
+ get "/internal_redirect" do
62
+ redirect "/"
63
+ end
64
+
65
+ get "/external_redirect" do
66
+ redirect "http://google.com"
67
+ end
68
+
69
+ post "/go" do
70
+ @user = params[:name]
71
+ @email = params[:email]
72
+ erb :hello
7
73
  end
8
74
 
9
75
  get "/redirect_absolute_url" do
@@ -14,6 +14,8 @@ class Test::Unit::TestCase
14
14
  include Webrat::Methods
15
15
  include Webrat::Matchers
16
16
 
17
+ Webrat::Methods.delegate_to_session :response_code, :response_body
18
+
17
19
  def app
18
20
  RackApp.new
19
21
  end
@@ -2,66 +2,40 @@ require File.dirname(__FILE__) + "/test_helper"
2
2
  require File.dirname(__FILE__) + "/../rack_app"
3
3
 
4
4
  class WebratRackTest < Test::Unit::TestCase
5
- def test_visit_returns_response
6
- response = visit "/"
7
- assert response.ok?
5
+ def test_visits_pages
6
+ visit "/"
7
+ assert response_body.include?("visit")
8
+
9
+ click_link "there"
10
+ assert response_body.include?('<form method="post" action="/go">')
8
11
  end
9
12
 
10
- def test_last_response_is_available
11
- visit "/"
12
- assert last_response.ok?
13
+ def test_submits_form
14
+ visit "/go"
15
+ fill_in "Name", :with => "World"
16
+ fill_in "Email", :with => "world@example.org"
17
+ click_button "Submit"
18
+ assert response_body.include?("Hello, World")
19
+ assert response_body.include?("Your email is: world@example.org")
13
20
  end
14
21
 
15
- def test_last_request_is_available
22
+ def test_check_value_of_field
16
23
  visit "/"
17
- assert_equal "/", last_request.env["PATH_INFO"]
24
+ assert field_labeled("Prefilled").value, "text"
18
25
  end
19
26
 
20
- # def test_redirects
21
- # visit "/redirect_absolute_url"
22
- # assert_equal "spam", response_body
23
- # end
24
-
25
- def test_assertions_after_visit
26
- visit "/"
27
- assert_contain "Hello World"
27
+ def test_follows_internal_redirects
28
+ visit "/internal_redirect"
29
+ assert response_body.include?("visit")
28
30
  end
29
31
 
30
- def test_assertions_after_visit
31
- get "/"
32
- assert_contain "Hello World"
32
+ def test_does_not_follow_external_redirects
33
+ visit "/external_redirect"
34
+ assert response_code == 302
33
35
  end
34
36
 
35
- # def test_visits_pages
36
- # visit "/"
37
- # assert response_body.include?("visit")
38
- #
39
- # click_link "there"
40
- # assert response_body.include?('<form method="post" action="/go">')
41
- # end
42
- #
43
- # def test_submits_form
44
- # visit "/go"
45
- # fill_in "Name", :with => "World"
46
- # fill_in "Email", :with => "world@example.org"
47
- # click_button "Submit"
48
- #
49
- # assert response_body.include?("Hello, World")
50
- # assert response_body.include?("Your email is: world@example.org")
51
- # end
52
- #
53
- # def test_check_value_of_field
54
- # visit "/"
55
- # assert field_labeled("Prefilled").value, "text"
56
- # end
57
- #
58
- # def test_follows_internal_redirects
59
- # visit "/internal_redirect"
60
- # assert response_body.include?("visit")
61
- # end
62
- #
63
- # def test_does_not_follow_external_redirects
64
- # visit "/external_redirect"
65
- # assert response_code == 302
66
- # end
37
+ def test_redirects
38
+ visit "/redirect_absolute_url"
39
+ assert_equal "spam", response_body
40
+ end
67
41
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metry
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathaniel Talbott
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-08 00:00:00 -04:00
12
+ date: 2009-08-09 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency