wally 0.0.33 → 0.0.34

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/README.md +5 -3
  2. data/Rakefile +4 -0
  3. data/features/counts.feature +10 -3
  4. data/features/feature_page.feature +17 -9
  5. data/features/list_tags.feature +5 -5
  6. data/features/notifications.feature +1 -1
  7. data/features/progress_bar.feature +25 -0
  8. data/features/{home_page.feature → project_home.feature} +3 -16
  9. data/features/projects.feature +12 -0
  10. data/features/push_features.feature +4 -4
  11. data/features/scenario_page.feature +4 -27
  12. data/features/search_features.feature +7 -7
  13. data/features/step_definitions/feature_page_steps.rb +15 -0
  14. data/features/step_definitions/notifications_steps.rb +1 -1
  15. data/features/step_definitions/project_home_steps.rb +10 -0
  16. data/features/step_definitions/projects_steps.rb +11 -0
  17. data/features/step_definitions/push_features_steps.rb +10 -6
  18. data/features/step_definitions/scenario_page_steps.rb +15 -0
  19. data/features/step_definitions/search_features_steps.rb +1 -1
  20. data/features/step_definitions/steps.rb +15 -3
  21. data/features/step_definitions/welcome_page.rb +19 -0
  22. data/features/support/env.rb +28 -6
  23. data/features/welcome_page.feature +30 -0
  24. data/lib/wally.rb +0 -3
  25. data/lib/wally/application.rb +39 -22
  26. data/lib/wally/counts_tags.rb +3 -3
  27. data/lib/wally/feature.rb +1 -1
  28. data/lib/wally/project.rb +8 -0
  29. data/lib/wally/public/scripts/projects.js +6 -0
  30. data/lib/wally/public/skin.css +7 -0
  31. data/lib/wally/search_features.rb +1 -1
  32. data/lib/wally/version.rb +1 -1
  33. data/lib/wally/views/feature_link.haml +1 -1
  34. data/lib/wally/views/layout.haml +32 -21
  35. data/lib/wally/views/{index.haml → project.haml} +0 -0
  36. data/lib/wally/views/search.haml +3 -3
  37. data/spec/spec_helper.rb +24 -0
  38. data/spec/wally/counts_tags_spec.rb +10 -22
  39. data/spec/wally/feature_spec.rb +12 -15
  40. data/spec/wally/project_spec.rb +18 -0
  41. data/spec/wally/search_features_spec.rb +18 -25
  42. data/wally.gemspec +1 -0
  43. metadata +58 -29
  44. 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
+
@@ -9,12 +9,34 @@ require "fakefs/spec_helpers"
9
9
  Capybara.app = Sinatra::Application
10
10
 
11
11
  After do
12
- Wally::Feature.delete_all
12
+ Wally::Project.delete_all
13
13
  end
14
14
 
15
- def create_feature path, content
16
- feature = Wally::Feature.new
17
- feature.path = path
18
- feature.gherkin = Wally::ParsesFeatures.new.parse(content)
19
- feature.save
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
@@ -5,6 +5,3 @@ $:.unshift(File.expand_path(File.dirname(__FILE__)))
5
5
 
6
6
  require "wally/version"
7
7
  require "wally/application"
8
- require "wally/search_features"
9
- require "wally/counts_tags"
10
- require "wally/parses_features"
@@ -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
- Wally::CountsTags.new(Wally::Feature).count_tags
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
- Feature.all.inject(0) do |count, feature|
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
- Wally::Feature.delete_all
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
- feature = Wally::Feature.new
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
- haml :index
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 |id|
77
- Wally::Feature.all.each do |feature|
78
- @feature = feature if feature.gherkin["id"] == 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(Wally::Feature).find(:query => params[:q])
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/?' do |feature_id, scenario_id|
95
- Wally::Feature.all.each do |feature|
96
- if feature.gherkin["id"] == feature_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"] == "#{feature_id};#{scenario_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)
@@ -1,11 +1,11 @@
1
1
  module Wally
2
2
  class CountsTags
3
- def initialize lists_features
4
- @lists_features = lists_features
3
+ def initialize project
4
+ @project = project
5
5
  end
6
6
 
7
7
  def count_tags
8
- @lists_features.all.inject(Hash.new(0)) do |tag_count, feature|
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
@@ -1,6 +1,6 @@
1
1
  module Wally
2
2
  class Feature
3
- include MongoMapper::Document
3
+ include MongoMapper::EmbeddedDocument
4
4
 
5
5
  key :path, String
6
6
  key :gherkin, Hash
@@ -0,0 +1,8 @@
1
+ module Wally
2
+ class Project
3
+ include MongoMapper::Document
4
+
5
+ key :name, String
6
+ many :features, :class => Wally::Feature
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ $().ready(function(){
2
+ $("#projects").change(function(){
3
+ var project = $("#projects option:selected").val();
4
+ window.location = "/projects/" + project;
5
+ });
6
+ });
@@ -187,3 +187,10 @@ section.feature p:first-child {
187
187
  .search-result {
188
188
  background: #F7F77E;
189
189
  }
190
+
191
+ .project-list {
192
+ float: right;
193
+ padding-top: 10px;
194
+ background: white;
195
+ }
196
+
@@ -9,7 +9,7 @@ module Wally
9
9
  def find(query)
10
10
  searchables = []
11
11
 
12
- @lists_features.all.each do |feature|
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
@@ -1,3 +1,3 @@
1
1
  module Wally
2
- VERSION = "0.0.33"
2
+ VERSION = "0.0.34"
3
3
  end
@@ -1,5 +1,5 @@
1
1
  %li
2
- %a{:href => "/features/#{feature.gherkin["id"]}"}
2
+ %a{:href => "/#{current_project.name}/features/#{feature.gherkin["id"]}"}
3
3
  = feature.gherkin["name"]
4
4
  - if feature.gherkin["tags"]
5
5
  - tags = feature.gherkin["tags"]
@@ -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
- %div.container-fluid
19
- %div.sidebar
20
- %ul
21
- %li
22
- %a{:href => "/progress"}
23
- Progress
24
- %h2
25
- = "Features (#{Wally::Feature.all.count})"
26
- %ul
27
- - Wally::Feature.sort(:name).each do |feature|
28
- = haml :feature_link, {:locals => {:feature => feature}, :layout => false}
29
- - if tag_count.any?
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
- %div.content
38
- - if excessive_wip_tags
39
- %div.alert-message.error
40
- %p
41
- = "You have #{tag_count["@wip"]} @wip tags :("
42
- = yield
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
@@ -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(Feature).count_tags.should == {
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(Feature).count_tags.should == {
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(Feature).count_tags.should == {
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