wally 0.0.33 → 0.0.34
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/README.md +5 -3
- data/Rakefile +4 -0
- data/features/counts.feature +10 -3
- data/features/feature_page.feature +17 -9
- data/features/list_tags.feature +5 -5
- data/features/notifications.feature +1 -1
- data/features/progress_bar.feature +25 -0
- data/features/{home_page.feature → project_home.feature} +3 -16
- data/features/projects.feature +12 -0
- data/features/push_features.feature +4 -4
- data/features/scenario_page.feature +4 -27
- data/features/search_features.feature +7 -7
- data/features/step_definitions/feature_page_steps.rb +15 -0
- data/features/step_definitions/notifications_steps.rb +1 -1
- data/features/step_definitions/project_home_steps.rb +10 -0
- data/features/step_definitions/projects_steps.rb +11 -0
- data/features/step_definitions/push_features_steps.rb +10 -6
- data/features/step_definitions/scenario_page_steps.rb +15 -0
- data/features/step_definitions/search_features_steps.rb +1 -1
- data/features/step_definitions/steps.rb +15 -3
- data/features/step_definitions/welcome_page.rb +19 -0
- data/features/support/env.rb +28 -6
- data/features/welcome_page.feature +30 -0
- data/lib/wally.rb +0 -3
- data/lib/wally/application.rb +39 -22
- data/lib/wally/counts_tags.rb +3 -3
- data/lib/wally/feature.rb +1 -1
- data/lib/wally/project.rb +8 -0
- data/lib/wally/public/scripts/projects.js +6 -0
- data/lib/wally/public/skin.css +7 -0
- data/lib/wally/search_features.rb +1 -1
- data/lib/wally/version.rb +1 -1
- data/lib/wally/views/feature_link.haml +1 -1
- data/lib/wally/views/layout.haml +32 -21
- data/lib/wally/views/{index.haml → project.haml} +0 -0
- data/lib/wally/views/search.haml +3 -3
- data/spec/spec_helper.rb +24 -0
- data/spec/wally/counts_tags_spec.rb +10 -22
- data/spec/wally/feature_spec.rb +12 -15
- data/spec/wally/project_spec.rb +18 -0
- data/spec/wally/search_features_spec.rb +18 -25
- data/wally.gemspec +1 -0
- metadata +58 -29
- data/features/step_definitions/browse_features_steps.rb +0 -47
@@ -0,0 +1,19 @@
|
|
1
|
+
Given /^there aren't any projects$/ do
|
2
|
+
end
|
3
|
+
|
4
|
+
When /^I view the welcome page$/ do
|
5
|
+
visit "/"
|
6
|
+
end
|
7
|
+
|
8
|
+
Then /^I should redirected to the "([^"]*)" project page$/ do |project|
|
9
|
+
page.current_url.should include "/projects/#{project}"
|
10
|
+
end
|
11
|
+
|
12
|
+
When /^I select the project "([^"]*)"$/ do |project|
|
13
|
+
select(project, :from => "projects")
|
14
|
+
end
|
15
|
+
|
16
|
+
Then /^"([^"]*)" should be rendered$/ do |text|
|
17
|
+
page.should have_content text
|
18
|
+
end
|
19
|
+
|
data/features/support/env.rb
CHANGED
@@ -9,12 +9,34 @@ require "fakefs/spec_helpers"
|
|
9
9
|
Capybara.app = Sinatra::Application
|
10
10
|
|
11
11
|
After do
|
12
|
-
Wally::
|
12
|
+
Wally::Project.delete_all
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
require 'headless'
|
16
|
+
headless = Headless.new
|
17
|
+
at_exit do
|
18
|
+
headless.destroy
|
19
|
+
end
|
20
|
+
|
21
|
+
Before("@selenium,@javascript", "~@no-headless") do
|
22
|
+
headless.start if Capybara.current_driver == :selenium
|
23
|
+
end
|
24
|
+
|
25
|
+
After("@selenium,@javascript", "~@no-headless") do
|
26
|
+
headless.stop if Capybara.current_driver == :selenium
|
27
|
+
end
|
28
|
+
|
29
|
+
def project name
|
30
|
+
project = Wally::Project.first(:name => name)
|
31
|
+
unless project
|
32
|
+
project = Wally::Project.create(:name => name)
|
33
|
+
end
|
34
|
+
project
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_feature project, path, content
|
38
|
+
project = project(project)
|
39
|
+
feature = Wally::Feature.new(:path => path, :gherkin => Wally::ParsesFeatures.new.parse(content))
|
40
|
+
project.features << feature
|
41
|
+
project.save
|
20
42
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Feature: Welcome Page
|
2
|
+
As a stakeholder
|
3
|
+
I want a welcome page
|
4
|
+
|
5
|
+
Scenario: No projects
|
6
|
+
Given there aren't any projects
|
7
|
+
When I view the welcome page
|
8
|
+
Then "Wally is a web-based Cucumber viewer and navigator" should be rendered
|
9
|
+
|
10
|
+
@javascript
|
11
|
+
Scenario: Project links on home page
|
12
|
+
Given a feature file on the project "sample1" with the contents:
|
13
|
+
"""
|
14
|
+
Feature: Sample1
|
15
|
+
"""
|
16
|
+
And a feature file on the project "sample2" with the contents:
|
17
|
+
"""
|
18
|
+
Feature: Sample2
|
19
|
+
"""
|
20
|
+
When I view the welcome page
|
21
|
+
And I select the project "sample2"
|
22
|
+
Then I should redirected to the "sample2" project page
|
23
|
+
|
24
|
+
Scenario: Redirect to first project
|
25
|
+
Given a feature file on the project "sample1" with the contents:
|
26
|
+
"""
|
27
|
+
Feature: Sample1
|
28
|
+
"""
|
29
|
+
When I view the welcome page
|
30
|
+
Then I should redirected to the "sample1" project page
|
data/lib/wally.rb
CHANGED
data/lib/wally/application.rb
CHANGED
@@ -4,6 +4,10 @@ require "haml"
|
|
4
4
|
require "rdiscount"
|
5
5
|
require "mongo_mapper"
|
6
6
|
require "wally/feature"
|
7
|
+
require "wally/project"
|
8
|
+
require "wally/search_features"
|
9
|
+
require "wally/counts_tags"
|
10
|
+
require "wally/parses_features"
|
7
11
|
require "cgi"
|
8
12
|
|
9
13
|
configure do
|
@@ -19,18 +23,23 @@ else
|
|
19
23
|
MongoMapper.database = "wally"
|
20
24
|
end
|
21
25
|
|
26
|
+
def current_project
|
27
|
+
Wally::Project.first(:name => params[:project])
|
28
|
+
end
|
29
|
+
|
22
30
|
def tag_count
|
23
|
-
|
31
|
+
return {} if current_project.nil?
|
32
|
+
Wally::CountsTags.new(current_project).count_tags
|
24
33
|
end
|
25
34
|
|
26
35
|
def excessive_wip_tags
|
27
|
-
tag_count["@wip"] >= 10
|
36
|
+
tag_count["@wip"] >= 10 if tag_count["@wip"]
|
28
37
|
end
|
29
38
|
|
30
39
|
def scenario_count
|
31
|
-
|
40
|
+
current_project.features.inject(0) do |count, feature|
|
32
41
|
if feature.gherkin["elements"]
|
33
|
-
count += feature.gherkin["elements"].select { |e| e["type"] == "scenario" }
|
42
|
+
count += feature.gherkin["elements"].select { |e| e["type"] == "scenario" }.size
|
34
43
|
end
|
35
44
|
count
|
36
45
|
end
|
@@ -53,16 +62,15 @@ def highlighted_search_result_blurb search_result
|
|
53
62
|
highlighted
|
54
63
|
end
|
55
64
|
|
56
|
-
put '/features/?' do
|
65
|
+
put '/projects/:project/features/?' do
|
57
66
|
if File.exist?(".wally") && params[:authentication_code] == File.read(".wally").strip
|
58
|
-
|
67
|
+
current_project.delete if current_project
|
68
|
+
project = Wally::Project.create(:name => params[:project])
|
59
69
|
|
60
70
|
JSON.parse(request.body.read).each do |json|
|
61
|
-
|
62
|
-
feature.path = json["path"]
|
63
|
-
feature.gherkin = json["gherkin"]
|
64
|
-
feature.save
|
71
|
+
project.features << Wally::Feature.new(:path => json["path"], :gherkin => json["gherkin"])
|
65
72
|
end
|
73
|
+
project.save
|
66
74
|
halt 201
|
67
75
|
else
|
68
76
|
error 403
|
@@ -70,36 +78,45 @@ put '/features/?' do
|
|
70
78
|
end
|
71
79
|
|
72
80
|
get '/?' do
|
73
|
-
|
81
|
+
first_project = Wally::Project.first
|
82
|
+
if first_project
|
83
|
+
redirect "/projects/#{first_project.name}"
|
84
|
+
else
|
85
|
+
markdown File.read("README.md"), :layout => false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
get '/projects/:project/?' do
|
90
|
+
haml :project
|
74
91
|
end
|
75
92
|
|
76
|
-
get '/features/:feature/?' do
|
77
|
-
|
78
|
-
@feature = feature if feature.gherkin["id"] ==
|
93
|
+
get '/projects/:project/features/:feature/?' do
|
94
|
+
current_project.features.each do |feature|
|
95
|
+
@feature = feature if feature.gherkin["id"] == params[:feature]
|
79
96
|
end
|
80
97
|
haml :feature
|
81
98
|
end
|
82
99
|
|
83
|
-
get '/progress/?' do
|
100
|
+
get '/projects/:project/progress/?' do
|
84
101
|
haml :progress
|
85
102
|
end
|
86
103
|
|
87
|
-
get '/search/?' do
|
104
|
+
get '/projects/:project/search/?' do
|
88
105
|
if params[:q]
|
89
|
-
@search_results = Wally::SearchFeatures.new(
|
106
|
+
@search_results = Wally::SearchFeatures.new(current_project).find(:query => params[:q])
|
90
107
|
end
|
91
108
|
haml :search
|
92
109
|
end
|
93
110
|
|
94
|
-
get '/features/:feature/scenario/:scenario/?'
|
95
|
-
|
96
|
-
if feature.gherkin["id"] ==
|
111
|
+
get '/projects/:project/features/:feature/scenario/:scenario/?' do
|
112
|
+
current_project.features.each do |feature|
|
113
|
+
if feature.gherkin["id"] == params[:feature]
|
97
114
|
@feature = feature
|
98
115
|
feature.gherkin["elements"].each do |element|
|
99
116
|
if element["type"] == "background"
|
100
117
|
@background = element
|
101
118
|
end
|
102
|
-
if (element["type"] == "scenario" || element["type"] == "scenario_outline") && element["id"] == "#{
|
119
|
+
if (element["type"] == "scenario" || element["type"] == "scenario_outline") && element["id"] == "#{params[:feature]};#{params[:scenario]}"
|
103
120
|
@scenario = element
|
104
121
|
end
|
105
122
|
end
|
@@ -109,7 +126,7 @@ get '/features/:feature/scenario/:scenario/?' do |feature_id, scenario_id|
|
|
109
126
|
end
|
110
127
|
|
111
128
|
def get_scenario_url(scenario)
|
112
|
-
url = "/features/#{scenario["id"].gsub(";", "/scenario/")}"
|
129
|
+
url = "/projects/#{current_project.name}/features/#{scenario["id"].gsub(";", "/scenario/")}"
|
113
130
|
end
|
114
131
|
|
115
132
|
def get_sorted_scenarios(feature)
|
data/lib/wally/counts_tags.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module Wally
|
2
2
|
class CountsTags
|
3
|
-
def initialize
|
4
|
-
@
|
3
|
+
def initialize project
|
4
|
+
@project = project
|
5
5
|
end
|
6
6
|
|
7
7
|
def count_tags
|
8
|
-
@
|
8
|
+
@project.features.inject(Hash.new(0)) do |tag_count, feature|
|
9
9
|
if feature.gherkin["tags"]
|
10
10
|
feature.gherkin["tags"].each do |tag|
|
11
11
|
tag_count[tag["name"].downcase] += 1
|
data/lib/wally/feature.rb
CHANGED
data/lib/wally/public/skin.css
CHANGED
@@ -9,7 +9,7 @@ module Wally
|
|
9
9
|
def find(query)
|
10
10
|
searchables = []
|
11
11
|
|
12
|
-
@lists_features.
|
12
|
+
@lists_features.features.each do |feature|
|
13
13
|
feature_text = feature.gherkin["name"]
|
14
14
|
if feature.gherkin["tags"]
|
15
15
|
feature_text += " " + feature.gherkin["tags"].map { |tag| tag["name"] }.join(" ")
|
data/lib/wally/version.rb
CHANGED
data/lib/wally/views/layout.haml
CHANGED
@@ -4,39 +4,50 @@
|
|
4
4
|
%title Wally
|
5
5
|
%link{:rel => 'stylesheet', :type => 'text/css', :href => '/bootstrap.min.css'}
|
6
6
|
%link{:rel => 'stylesheet', :type => 'text/css', :href => '/skin.css'}
|
7
|
+
%script{:type => "text/javascript", :src => "http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"}
|
8
|
+
%script{:type => "text/javascript", :src => "/scripts/projects.js"}
|
7
9
|
%meta{:'http-equiv' => 'X-UA-Compatible', :content => 'IE=edge,chrome=1'}
|
8
10
|
%meta{:name => 'viewport', :content => 'width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;'}
|
9
11
|
%body
|
10
12
|
%div.container-fluid
|
11
13
|
%div.logo
|
12
14
|
%h1
|
13
|
-
%a{:href => "/"} Wally
|
15
|
+
%a{:href => "/#{current_project ? "projects/" + current_project.name : nil}"} Wally
|
16
|
+
|
17
|
+
%div.project-list
|
18
|
+
%select#projects{:name => "projects"}
|
19
|
+
- Wally::Project.all.each do |project|
|
20
|
+
%option{:value => project.name}
|
21
|
+
= project.name
|
22
|
+
|
14
23
|
%div.search-bar
|
15
|
-
%form{:method => "GET", :action => "/search", :id => "search"}
|
24
|
+
%form{:method => "GET", :action => "/projects/#{current_project.name}/search", :id => "search"}
|
16
25
|
%input{:type => "text", :id => "q", :name => "q", :placeholder => 'text, @tags etc.', :value => @q }
|
17
26
|
%input.btn{:type => "submit", :id => "search", :value => "Search"}
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
%div.container-fluid
|
28
|
+
%div.sidebar
|
29
|
+
%ul
|
30
|
+
%li
|
31
|
+
%a{:href => "/projects/#{current_project.name}/progress"}
|
32
|
+
Progress
|
33
|
+
%h2
|
34
|
+
= "Features (#{current_project.features.count})"
|
35
|
+
%ul
|
36
|
+
- current_project.features.sort{|a,b| a.name <=> b.name}.each do |feature|
|
37
|
+
= haml :feature_link, {:locals => {:feature => feature}, :layout => false}
|
38
|
+
|
30
39
|
%h2
|
31
40
|
= "Tags (#{tag_count.values.sum})"
|
32
41
|
%ul
|
33
42
|
- tag_count.each do |tag, count|
|
34
43
|
%li
|
35
|
-
%a{:href => "/search?q=#{tag}"}
|
44
|
+
%a{:href => "/projects/#{current_project.name}/search?q=#{tag}"}
|
36
45
|
= "#{tag} (#{count})"
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
%
|
41
|
-
|
42
|
-
|
46
|
+
|
47
|
+
%div.content
|
48
|
+
- if excessive_wip_tags
|
49
|
+
%div.alert-message.error
|
50
|
+
%p
|
51
|
+
= "You have #{tag_count["@wip"]} @wip tags :("
|
52
|
+
= yield
|
53
|
+
|
File without changes
|
data/lib/wally/views/search.haml
CHANGED
@@ -5,13 +5,13 @@
|
|
5
5
|
- if @search_results.suggestion
|
6
6
|
%p
|
7
7
|
Did you mean
|
8
|
-
%a{:href => "/search?q=#{@search_results.suggestion}"}
|
8
|
+
%a{:href => "/projects/#{current_project.name}/search?q=#{@search_results.suggestion}"}
|
9
9
|
= @search_results.suggestion
|
10
10
|
%ul
|
11
11
|
- @search_results.items.map {|i| i.object.feature["id"] }.uniq.each do |current_feature_id|
|
12
12
|
- root_search_result = @search_results.items.find { |r| r.object.feature["id"] == current_feature_id }
|
13
13
|
%li
|
14
|
-
%a{:href => "/features/#{root_search_result.object.feature["id"]}"}
|
14
|
+
%a{:href => "/projects/#{current_project.name}/features/#{root_search_result.object.feature["id"]}"}
|
15
15
|
= root_search_result.object.feature["name"]
|
16
16
|
- if root_search_result.object.feature["tags"]
|
17
17
|
= haml :tag_links, {:locals => {:tags => root_search_result.object.feature["tags"]}, :layout => false}
|
@@ -21,7 +21,7 @@
|
|
21
21
|
- @search_results.items.select { |r| r.object.feature["id"] == current_feature_id }.each do |search_result|
|
22
22
|
- if search_result.object.scenario && search_result.object.scenario["id"]
|
23
23
|
%li
|
24
|
-
%a{:href => "/features/#{search_result.object.scenario["id"].gsub(";", "/scenario/")}"}
|
24
|
+
%a{:href => "/projects/#{current_project.name}/features/#{search_result.object.scenario["id"].gsub(";", "/scenario/")}"}
|
25
25
|
= search_result.object.scenario["name"]
|
26
26
|
- if search_result.object.scenario["tags"]
|
27
27
|
= haml :tag_links, {:locals => {:tags => search_result.object.scenario["tags"]}, :layout => false}
|
data/spec/spec_helper.rb
CHANGED
@@ -9,3 +9,27 @@ before do
|
|
9
9
|
ARGV.clear
|
10
10
|
ARGV << "application-features"
|
11
11
|
end
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.after :each do
|
15
|
+
Wally::Project.delete_all
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def project name
|
20
|
+
project = Wally::Project.first(:name => name)
|
21
|
+
unless project
|
22
|
+
project = Wally::Project.create(:name => name)
|
23
|
+
end
|
24
|
+
project
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_feature project_name, path, content
|
28
|
+
project = project(project_name)
|
29
|
+
feature = Wally::Feature.new({
|
30
|
+
:path => path,
|
31
|
+
:gherkin => Wally::ParsesFeatures.new.parse(content)
|
32
|
+
})
|
33
|
+
project.features << feature
|
34
|
+
project.save
|
35
|
+
end
|
@@ -3,43 +3,31 @@ require 'fileutils'
|
|
3
3
|
|
4
4
|
module Wally
|
5
5
|
describe CountsTags do
|
6
|
-
after do
|
7
|
-
Feature.delete_all
|
8
|
-
end
|
9
|
-
|
10
|
-
def create_feature path, content
|
11
|
-
feature = Feature.new
|
12
|
-
feature.path = path
|
13
|
-
feature.gherkin = ParsesFeatures.new.parse(content)
|
14
|
-
feature.save
|
15
|
-
end
|
16
|
-
|
17
6
|
it "counts feature tags" do
|
18
|
-
create_feature("feature-1.feature", "@tag1 @tag2\nFeature: Feature 1")
|
19
|
-
create_feature("feature-2.feature", "@tag2 @tag2\nFeature: Feature 2")
|
20
|
-
CountsTags.new(
|
7
|
+
create_feature("project1", "feature-1.feature", "@tag1 @tag2\nFeature: Feature 1")
|
8
|
+
create_feature("project1", "feature-2.feature", "@tag2 @tag2\nFeature: Feature 2")
|
9
|
+
CountsTags.new(project("project1")).count_tags.should == {
|
21
10
|
"@tag1" => 1,
|
22
11
|
"@tag2" => 3
|
23
12
|
}
|
24
13
|
end
|
25
14
|
|
26
15
|
it "counts scenario tags" do
|
27
|
-
create_feature("feature-1.feature", "Feature: Feature 1\n@tag1@tag1\nScenario: Scenario 1")
|
28
|
-
create_feature("feature-2.feature", "Feature: Feature 2\n@tag3@tag1\nScenario: Scenario 1")
|
29
|
-
CountsTags.new(
|
16
|
+
create_feature("project1", "feature-1.feature", "Feature: Feature 1\n@tag1@tag1\nScenario: Scenario 1")
|
17
|
+
create_feature("project1", "feature-2.feature", "Feature: Feature 2\n@tag3@tag1\nScenario: Scenario 1")
|
18
|
+
CountsTags.new(project("project1")).count_tags.should == {
|
30
19
|
"@tag1" => 3,
|
31
20
|
"@tag3" => 1
|
32
21
|
}
|
33
22
|
end
|
34
23
|
|
35
24
|
it "counts feature tags irrespective of their case" do
|
36
|
-
create_feature("feature-1.feature", "@tag1\nFeature: Feature 1")
|
37
|
-
create_feature("feature-2.feature", "@TAG1\nFeature: Feature 2")
|
38
|
-
create_feature("feature-3.feature", "Feature: Feature 2\n@TAG1\nScenario: Scenario 1")
|
39
|
-
CountsTags.new(
|
25
|
+
create_feature("project1", "feature-1.feature", "@tag1\nFeature: Feature 1")
|
26
|
+
create_feature("project1", "feature-2.feature", "@TAG1\nFeature: Feature 2")
|
27
|
+
create_feature("project1", "feature-3.feature", "Feature: Feature 2\n@TAG1\nScenario: Scenario 1")
|
28
|
+
CountsTags.new(project("project1")).count_tags.should == {
|
40
29
|
"@tag1" => 3
|
41
30
|
}
|
42
31
|
end
|
43
|
-
|
44
32
|
end
|
45
33
|
end
|