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.
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