wally 0.0.33 → 0.0.34
Sign up to get free protection for your applications and to get access to all the features.
- 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
|