watch_tower 0.0.0.1

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 (115) hide show
  1. data/.gitignore +10 -0
  2. data/.todo +33 -0
  3. data/.travis.yml +14 -0
  4. data/Gemfile +43 -0
  5. data/Guardfile +25 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +38 -0
  8. data/Rakefile +8 -0
  9. data/TODO +17 -0
  10. data/bin/watchtower +10 -0
  11. data/ci/adapters/jruby-mysql.yml +8 -0
  12. data/ci/adapters/jruby-postgresql.yml +6 -0
  13. data/ci/adapters/jruby-sqlite.yml +6 -0
  14. data/ci/adapters/ruby-mysql.yml +8 -0
  15. data/ci/adapters/ruby-postgresql.yml +6 -0
  16. data/ci/adapters/ruby-sqlite.yml +6 -0
  17. data/ci/travis.rb +102 -0
  18. data/lib/watch_tower.rb +60 -0
  19. data/lib/watch_tower/appscript.rb +22 -0
  20. data/lib/watch_tower/cli.rb +15 -0
  21. data/lib/watch_tower/cli/.gitkeep +0 -0
  22. data/lib/watch_tower/cli/install.rb +63 -0
  23. data/lib/watch_tower/cli/open.rb +24 -0
  24. data/lib/watch_tower/cli/start.rb +140 -0
  25. data/lib/watch_tower/config.rb +38 -0
  26. data/lib/watch_tower/core_ext.rb +4 -0
  27. data/lib/watch_tower/core_ext/.gitkeep +0 -0
  28. data/lib/watch_tower/editor.rb +17 -0
  29. data/lib/watch_tower/editor/.gitkeep +0 -0
  30. data/lib/watch_tower/editor/base_appscript.rb +34 -0
  31. data/lib/watch_tower/editor/base_ps.rb +6 -0
  32. data/lib/watch_tower/editor/textmate.rb +17 -0
  33. data/lib/watch_tower/editor/xcode.rb +22 -0
  34. data/lib/watch_tower/errors.rb +25 -0
  35. data/lib/watch_tower/eye.rb +79 -0
  36. data/lib/watch_tower/project.rb +14 -0
  37. data/lib/watch_tower/project/.gitkeep +0 -0
  38. data/lib/watch_tower/project/any_based.rb +22 -0
  39. data/lib/watch_tower/project/git_based.rb +86 -0
  40. data/lib/watch_tower/project/init.rb +38 -0
  41. data/lib/watch_tower/project/path_based.rb +144 -0
  42. data/lib/watch_tower/server.rb +62 -0
  43. data/lib/watch_tower/server/.gitkeep +0 -0
  44. data/lib/watch_tower/server/app.rb +37 -0
  45. data/lib/watch_tower/server/assets/images/WatchTower.jpg +0 -0
  46. data/lib/watch_tower/server/assets/images/percentage.png +0 -0
  47. data/lib/watch_tower/server/assets/javascripts/application.js +3 -0
  48. data/lib/watch_tower/server/assets/javascripts/percentage.coffee +8 -0
  49. data/lib/watch_tower/server/assets/stylesheets/application.css +7 -0
  50. data/lib/watch_tower/server/assets/stylesheets/global.sass +71 -0
  51. data/lib/watch_tower/server/assets/stylesheets/project.sass +59 -0
  52. data/lib/watch_tower/server/configurations.rb +10 -0
  53. data/lib/watch_tower/server/configurations/asset.rb +43 -0
  54. data/lib/watch_tower/server/database.rb +105 -0
  55. data/lib/watch_tower/server/db/migrate/001_create_projects.rb +15 -0
  56. data/lib/watch_tower/server/db/migrate/002_create_files.rb +16 -0
  57. data/lib/watch_tower/server/db/migrate/003_create_time_entries.rb +12 -0
  58. data/lib/watch_tower/server/db/migrate/004_create_durations.rb +14 -0
  59. data/lib/watch_tower/server/db/migrate/005_add_hash_to_time_entries.rb +6 -0
  60. data/lib/watch_tower/server/db/migrate/006_add_hash_to_files.rb +6 -0
  61. data/lib/watch_tower/server/decorator.rb +21 -0
  62. data/lib/watch_tower/server/decorator/application_decorator.rb +91 -0
  63. data/lib/watch_tower/server/decorator/file_decorator.rb +38 -0
  64. data/lib/watch_tower/server/decorator/project_decorator.rb +51 -0
  65. data/lib/watch_tower/server/helpers.rb +13 -0
  66. data/lib/watch_tower/server/helpers/asset.rb +29 -0
  67. data/lib/watch_tower/server/helpers/improved_partials.rb +41 -0
  68. data/lib/watch_tower/server/models/duration.rb +11 -0
  69. data/lib/watch_tower/server/models/file.rb +31 -0
  70. data/lib/watch_tower/server/models/project.rb +17 -0
  71. data/lib/watch_tower/server/models/time_entry.rb +64 -0
  72. data/lib/watch_tower/server/public/assets/WatchTower-4d6de11e1bd34165ad91ac46fb711bf3.jpg +0 -0
  73. data/lib/watch_tower/server/public/assets/application-7829b53b5ece1a16d22dc3d00f329023.css +107 -0
  74. data/lib/watch_tower/server/public/assets/application-e0e6b7731aade460f680331e65cf0682.js +9359 -0
  75. data/lib/watch_tower/server/public/assets/percentage-d8589e21a5fc85d32a445f531ff8ab95.png +0 -0
  76. data/lib/watch_tower/server/vendor/assets/javascripts/jquery-ui.js +11729 -0
  77. data/lib/watch_tower/server/vendor/assets/javascripts/jquery.js +8981 -0
  78. data/lib/watch_tower/server/vendor/assets/javascripts/jquery_ujs.js +363 -0
  79. data/lib/watch_tower/server/views/.gitkeep +0 -0
  80. data/lib/watch_tower/server/views/_file.haml +9 -0
  81. data/lib/watch_tower/server/views/_project.haml +13 -0
  82. data/lib/watch_tower/server/views/index.haml +7 -0
  83. data/lib/watch_tower/server/views/layout.haml +32 -0
  84. data/lib/watch_tower/server/views/project.haml +12 -0
  85. data/lib/watch_tower/templates/config.yml +146 -0
  86. data/lib/watch_tower/templates/watchtower.plist +23 -0
  87. data/lib/watch_tower/version.rb +8 -0
  88. data/spec/factories.rb +45 -0
  89. data/spec/spec_helper.rb +26 -0
  90. data/spec/support/active_record.rb +44 -0
  91. data/spec/support/factory_girl.rb +6 -0
  92. data/spec/support/launchy.rb +3 -0
  93. data/spec/support/sinatra.rb +10 -0
  94. data/spec/support/timecop.rb +7 -0
  95. data/spec/watch_tower/appscript_spec.rb +6 -0
  96. data/spec/watch_tower/cli/install_spec.rb +16 -0
  97. data/spec/watch_tower/cli/open_spec.rb +14 -0
  98. data/spec/watch_tower/cli/start_spec.rb +17 -0
  99. data/spec/watch_tower/cli_spec.rb +15 -0
  100. data/spec/watch_tower/config_spec.rb +25 -0
  101. data/spec/watch_tower/editor/textmate_spec.rb +43 -0
  102. data/spec/watch_tower/editor/xcode_spec.rb +43 -0
  103. data/spec/watch_tower/editor_spec.rb +19 -0
  104. data/spec/watch_tower/eye_spec.rb +130 -0
  105. data/spec/watch_tower/project/git_based_spec.rb +131 -0
  106. data/spec/watch_tower/project/path_based_spec.rb +111 -0
  107. data/spec/watch_tower/project_spec.rb +82 -0
  108. data/spec/watch_tower/server/app_spec.rb +186 -0
  109. data/spec/watch_tower/server/decorator/project_decorator_spec.rb +60 -0
  110. data/spec/watch_tower/server/models/file_spec.rb +284 -0
  111. data/spec/watch_tower/server/models/project_spec.rb +165 -0
  112. data/spec/watch_tower/server/models/time_entry_spec.rb +37 -0
  113. data/spec/watch_tower/server_spec.rb +4 -0
  114. data/watch_tower.gemspec +80 -0
  115. metadata +450 -0
@@ -0,0 +1,131 @@
1
+ require 'spec_helper'
2
+
3
+ class Project
4
+ describe GitBased do
5
+ before(:all) do
6
+ # Arguments
7
+ @code = '/home/user/Code'
8
+ @file_path = '/home/user/Code/OpenSource/watch_tower/lib/watch_tower/server/models/time_entries.rb'
9
+
10
+ # Expected results
11
+ @project_path = '/home/user/Code/OpenSource/watch_tower'
12
+ @project_git_folder_path = @project_path + '/.git'
13
+ @project_name = 'watch_tower'
14
+ end
15
+
16
+ before(:each) do
17
+ # Project.stubs(:expand_path).returns
18
+ end
19
+
20
+ describe "#project_git_folder_path" do
21
+ it "should respond to :project_git_folder_path" do
22
+ -> { subject.send(:project_git_folder_path) }.should_not raise_error NoMethodError
23
+ end
24
+
25
+ it "should return a path if exists" do
26
+ @file_path.split('/').each_index do |i|
27
+ path = @file_path.split('/')[0..i].join('/') + '/.git'
28
+ if @project_git_folder_path == path
29
+ File.stubs(:exists?).with(path).returns(true)
30
+ else
31
+ File.stubs(:exists?).with(path).returns(false)
32
+ end
33
+ end
34
+
35
+ subject.send(:project_git_folder_path, @file_path).should == @project_git_folder_path
36
+ end
37
+
38
+ it "should return nil if path does not exist" do
39
+ file_path = @file_path.gsub(%r{#{@code}}, '/some/other/path')
40
+ file_path.split('/').each_index do |i|
41
+ path = file_path.split('/')[0..i].join('/')
42
+ File.stubs(:exists?).with(path + '/.git').returns(false)
43
+ end
44
+
45
+ subject.send(:project_git_folder_path, file_path).should be_nil
46
+ end
47
+
48
+ it "should cache it" do
49
+ File.expects(:exists?).never
50
+
51
+ subject.send(:project_git_folder_path, @file_path).should == @project_git_folder_path
52
+ end
53
+ end
54
+
55
+
56
+ describe "#active_for_path?" do
57
+ it { should respond_to(:active_for_path?) }
58
+
59
+ it "should be able to determine if a path is git-ized" do
60
+ GitBased.expects(:project_git_folder_path).returns(@project_path)
61
+
62
+ subject.active_for_path?(@file_path).should be_true
63
+ end
64
+
65
+ it "should be able to determine if a path is not git-ized" do
66
+ GitBased.expects(:project_git_folder_path).returns(nil)
67
+
68
+ subject.active_for_path?(@file_path).should be_false
69
+ end
70
+ end
71
+
72
+ describe "#working_directory" do
73
+ it { should respond_to(:working_directory) }
74
+
75
+ it "should return the working directory of a path" do
76
+ GitBased.stubs(:project_git_folder_path).returns(@project_git_folder_path)
77
+
78
+ subject.working_directory(@file_path).should == @project_path
79
+ end
80
+
81
+ it "should cache it" do
82
+ GitBased.expects(:project_git_folder_path).never
83
+
84
+ subject.working_directory(@file_path).should == @project_path
85
+ end
86
+ end
87
+
88
+ describe "#project_name" do
89
+ it { should respond_to(:project_name) }
90
+
91
+ it "should return the working directory of a path" do
92
+ GitBased.stubs(:project_git_folder_path).returns(@project_git_folder_path)
93
+
94
+ subject.project_name(@file_path).should == @project_name
95
+ end
96
+
97
+ it "should cache it" do
98
+ GitBased.expects(:project_git_folder_path).never
99
+
100
+ subject.project_name(@file_path).should == @project_name
101
+ end
102
+ end
103
+
104
+ describe "#head" do
105
+ before(:each) do
106
+ GitBased.stubs(:active_for_path?).returns(true)
107
+ GitBased.stubs(:working_directory).returns(@project_path)
108
+ end
109
+
110
+ it { should respond_to :head }
111
+
112
+ it "should create a Git::Base object" do
113
+ commit = mock
114
+ git_base = mock
115
+ git_base.stubs(:log).returns([commit])
116
+ ::Git.expects(:open).with(@project_path).returns(git_base).once
117
+
118
+ subject.head(@project_path)
119
+ end
120
+
121
+ it "should return the head revision" do
122
+ commit = mock
123
+ git_base = mock
124
+ git_base.stubs(:log).returns([commit])
125
+ ::Git.stubs(:open).with(@project_path).returns(git_base)
126
+
127
+ subject.head(@project_path).should == commit
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+
3
+ class Project
4
+ describe PathBased do
5
+ before(:all) do
6
+ # Arguments
7
+ @code = '/home/user/Code'
8
+ @file_path = '/home/user/Code/OpenSource/watch_tower/lib/watch_tower/server/models/time_entries.rb'
9
+ @nested_project_layers = 2
10
+ @args = [@code, @file_path, @nested_project_layers]
11
+ @options = {
12
+ code: @code,
13
+ nested_project_layers: @nested_project_layers
14
+ }
15
+
16
+ # Expected results
17
+ @project_path = '/home/user/Code/OpenSource/watch_tower'
18
+ @project_name = 'watch_tower'
19
+ @project_path_parts = ['/home/user/Code', 'OpenSource', 'watch_tower']
20
+ end
21
+
22
+ before(:each) do
23
+ PathBased.stubs(:code_path).returns(@code)
24
+ PathBased.stubs(:code_path).returns(@code)
25
+ end
26
+
27
+ describe "#project_path_part" do
28
+ it "should respond to #project_path_part" do
29
+ -> { subject.send :project_path_part, *@args }.should_not raise_error NoMethodError
30
+ end
31
+
32
+ it "should be able to return the project name from the path Given the correct path" do
33
+ subject.send(:project_path_part, *@args).should == @project_path_parts
34
+ end
35
+
36
+ it "should raises PathNotUnderCodePath if the path is not nested under code" do
37
+ file_path = @file_path.gsub(%r{#{@code}}, '/some/other/path')
38
+ -> { subject.send(:project_path_part, @code, file_path, @nested_project_layers) }.should raise_error PathNotUnderCodePath
39
+ end
40
+
41
+ it "should cache the path it" do
42
+ file_path = @file_path
43
+ file_path.expects(:scan).never
44
+
45
+ subject.send(:project_path_part, @code, file_path, @nested_project_layers).should == @project_path_parts
46
+ end
47
+ end
48
+
49
+ describe "#project_name_from_nested_path" do
50
+ it "should respond to #project_name_from_nested_path" do
51
+ -> { subject.send :project_name_from_nested_path, *@args }.should_not raise_error NoMethodError
52
+ end
53
+
54
+ it "should be able to return the project path parts from the path Given the correct path" do
55
+ subject.send(:project_name_from_nested_path, *@args).should == @project_name
56
+ end
57
+
58
+ it "should raises PathNotUnderCodePath if the path is not nested under code" do
59
+ file_path = @file_path.gsub(%r{#{@code}}, '/some/other/path')
60
+ -> { subject.send(:project_name_from_nested_path, @code, file_path, @nested_project_layers) }.should raise_error PathNotUnderCodePath
61
+ end
62
+ end
63
+
64
+ describe "#project_path_from_nested_path" do
65
+ it "should respond to #project_path_from_nested_path" do
66
+ -> { subject.send :project_path_from_nested_path, *@args }.should_not raise_error NoMethodError
67
+ end
68
+
69
+ it "should be able to return the project name from the path Given the correct path" do
70
+ subject.send(:project_path_from_nested_path, *@args).should == @project_path
71
+ end
72
+
73
+ it "should raises PathNotUnderCodePath if the path is not nested under code" do
74
+ file_path = @file_path.gsub(%r{#{@code}}, '/some/other/path')
75
+ -> { subject.send(:project_path_from_nested_path, @code, file_path, @nested_project_layers) }.should raise_error PathNotUnderCodePath
76
+ end
77
+ end
78
+
79
+ describe "#working_directory" do
80
+ it { should respond_to :working_directory }
81
+
82
+ it "should return the project path from nested path of the given path" do
83
+ PathBased.expects(:project_path_from_nested_path).with(*@args).returns(@project_path).once
84
+
85
+ subject.working_directory(@file_path, @options).should == @project_path
86
+ end
87
+
88
+ it "should cache the path it" do
89
+ PathBased.expects(:project_path_from_nested_path).with(*@args).returns(@project_path).never
90
+
91
+ subject.working_directory(@file_path, @options).should == @project_path
92
+ end
93
+ end
94
+
95
+ describe "#project_name" do
96
+ it { should respond_to :project_name }
97
+
98
+ it "should return the project path from nested path of the given path" do
99
+ PathBased.expects(:project_name_from_nested_path).with(*@args).returns(@project_name).once
100
+
101
+ subject.project_name(@file_path, @options).should == @project_name
102
+ end
103
+
104
+ it "should cache the path it" do
105
+ PathBased.expects(:project_name_from_nested_path).with(*@args).returns(@project_name).never
106
+
107
+ subject.project_name(@file_path, @options).should == @project_name
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Project do
4
+ describe "Class Methods" do
5
+ subject { Project }
6
+
7
+ before(:all) do
8
+ # Arguments
9
+ @code = '/home/user/Code'
10
+ @file_path = '/home/user/Code/OpenSource/watch_tower/lib/watch_tower/server/models/time_entries.rb'
11
+
12
+ # Expected results
13
+ @project_path = '/home/user/Code/OpenSource/watch_tower'
14
+ @project_name = 'watch_tower'
15
+ end
16
+
17
+ before(:each) do
18
+ ::File.stubs(:exists?).returns(true)
19
+ end
20
+
21
+ describe "#new_from_path" do
22
+
23
+ it { should respond_to :new_from_path }
24
+
25
+ describe "path based" do
26
+ before(:each) do
27
+ Project::GitBased.expects(:active_for_path?).returns(false).once
28
+ Project::PathBased.expects(:working_directory).returns(@project_path).once
29
+ Project::PathBased.expects(:project_name).returns(@project_name).once
30
+ end
31
+
32
+ it "should create a project based off of git" do
33
+ p = subject.new_from_path(@file_path)
34
+ p.should be_instance_of subject
35
+ end
36
+
37
+ it "should return the name of the project" do
38
+ p = subject.new_from_path(@file_path)
39
+ p.name.should == @project_name
40
+ end
41
+
42
+ it "should return the path of the project" do
43
+ p = subject.new_from_path(@file_path)
44
+ p.path.should == @project_path
45
+ end
46
+ end
47
+
48
+ describe "git based" do
49
+ before(:each) do
50
+ Project::GitBased.expects(:active_for_path?).returns(true).once
51
+ Project::GitBased.expects(:working_directory).returns(@project_path).once
52
+ Project::GitBased.expects(:project_name).returns(@project_name).once
53
+ end
54
+
55
+ it "should create a project based off of git" do
56
+ p = subject.new_from_path(@file_path)
57
+ p.should be_instance_of subject
58
+ end
59
+
60
+ it "should return the name of the project" do
61
+ p = subject.new_from_path(@file_path)
62
+ p.name.should == @project_name
63
+ end
64
+
65
+ it "should return the path of the project" do
66
+ p = subject.new_from_path(@file_path)
67
+ p.path.should == @project_path
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "Instance Methods" do
74
+ subject { Project.new @project_name, @project_path }
75
+
76
+ it { should respond_to :name }
77
+ it { should respond_to :path }
78
+
79
+ its(:name) { should == @project_name }
80
+ its(:path) { should == @project_path }
81
+ end
82
+ end
@@ -0,0 +1,186 @@
1
+ require 'spec_helper'
2
+
3
+ module Server
4
+ describe App do
5
+ before(:each) do
6
+ @projects = {
7
+ empty: {files: [], time_entries:[] },
8
+ not_empty: {files: [], time_entries: []}
9
+ }
10
+
11
+ @projects[:not_empty][:project] = FactoryGirl.create(:project)
12
+ 2.times do
13
+ @projects[:not_empty][:files] << FactoryGirl.create(:file, project: @projects[:not_empty][:project])
14
+ end
15
+ 5.times do
16
+ @projects[:not_empty][:time_entries] << FactoryGirl.create(:time_entry, file: @projects[:not_empty][:files].first)
17
+ end
18
+ @projects[:not_empty][:duration] = FactoryGirl.create(:duration, file: @projects[:not_empty][:files].first)
19
+
20
+ @projects[:empty][:project] = FactoryGirl.create(:project)
21
+ 2.times do
22
+ @projects[:empty][:files] << FactoryGirl.create(:file, project: @projects[:empty][:project])
23
+ end
24
+ @projects[:empty][:time_entries] << FactoryGirl.create(:time_entry, file: @projects[:empty][:files].first)
25
+ @projects[:empty][:duration] = FactoryGirl.create(:duration, file: @projects[:empty][:files].first)
26
+ end
27
+
28
+ describe "#index" do
29
+ before(:each) do
30
+ visit '/'
31
+ end
32
+
33
+ it "should render the layout" do
34
+ page.should have_selector :xpath, '//html/head/title'
35
+ end
36
+
37
+ it "should have the correct title" do
38
+ within :xpath, '//html/head/title' do
39
+ page.should have_content "Watch Tower - Projects"
40
+ end
41
+ end
42
+
43
+ it "should have a projects section" do
44
+ within :xpath, '//html/body' do
45
+ page.should have_selector 'section#projects'
46
+ end
47
+ end
48
+
49
+ it "should display each project as an article" do
50
+ within 'section#projects' do
51
+ page.should have_selector '.project'
52
+ end
53
+ end
54
+
55
+ it "should display have a section for the project's name" do
56
+ within 'section#projects' do
57
+ page.should have_selector '.project > .name'
58
+ end
59
+ end
60
+
61
+ it "should display the name of each project" do
62
+ within 'section#projects .project > .name' do
63
+ page.should have_content @projects[:not_empty][:project].name.camelcase
64
+ end
65
+ end
66
+
67
+ it "should not show the project with an empty time entries" do
68
+ within 'section#projects' do
69
+ page.should_not have_content @projects[:empty][:project].name.camelcase
70
+ end
71
+ end
72
+
73
+ it "should display the elapsed time of each project" do
74
+ within 'section#projects' do
75
+ page.should have_selector '.project > .elapsed'
76
+ end
77
+ end
78
+
79
+ it "should display an image under each project's name to categorize percentage" do
80
+ within 'section#projects' do
81
+ page.should have_selector '.project > .percentage_img_container > .percentage > img'
82
+ end
83
+ end
84
+
85
+ it "should have link on each project's name" do
86
+ within 'section#projects .project .name' do
87
+ page.should have_selector('a')
88
+ end
89
+ end
90
+
91
+ it "should link to the project's page" do
92
+ within 'section#projects .project .name' do
93
+ page.should have_selector('a', href: "/project/#{@projects[:not_empty][:project].id}")
94
+ end
95
+ end
96
+ end
97
+
98
+ describe "#project" do
99
+ before(:each) do
100
+ visit "/project/#{@projects[:not_empty][:project].id}"
101
+ end
102
+
103
+ it "should render the layout" do
104
+ page.should have_selector :xpath, '//html/head/title'
105
+ end
106
+
107
+ it "should have the correct title" do
108
+ within :xpath, '//html/head/title' do
109
+ page.should have_content "Watch Tower - Project - #{@projects[:not_empty][:project].name.camelcase}"
110
+ end
111
+ end
112
+
113
+ it "should have a projects section" do
114
+ within :xpath, '//html/body' do
115
+ page.should have_selector 'article#project'
116
+ end
117
+ end
118
+
119
+ it "should have the an h1 for the project's name" do
120
+ within 'article#project' do
121
+ page.should have_selector 'header > h1.project_name'
122
+ end
123
+ end
124
+
125
+ it "should have the project's name in an h1" do
126
+ within 'article#project header > h1.project_name' do
127
+ page.should have_content @projects[:not_empty][:project].name.camelcase
128
+ end
129
+ end
130
+
131
+ it "should have the an h2 for the project's path" do
132
+ within 'article#project' do
133
+ page.should have_selector 'header > h2.project_path'
134
+ end
135
+ end
136
+
137
+ it "should have the project's path in an h2" do
138
+ within 'article#project header > h2.project_path' do
139
+ page.should have_content @projects[:not_empty][:project].path
140
+ end
141
+ end
142
+
143
+ it "should have a section for the files" do
144
+ within 'article#project' do
145
+ page.should have_selector 'section#files'
146
+ end
147
+ end
148
+
149
+ it "should have a div for the file's path" do
150
+ within 'article#project section#files article.file' do
151
+ page.should have_selector 'div.path'
152
+ end
153
+ end
154
+
155
+ it "should display the file's path" do
156
+ within 'article#project section#files article.file div.path' do
157
+ page.should have_content @projects[:not_empty][:files].first.path
158
+ end
159
+ end
160
+
161
+ it "should have a div for the file's elapsed time" do
162
+ within 'article#project section#files article.file' do
163
+ page.should have_selector 'div.elapsed'
164
+ end
165
+ end
166
+
167
+ it "should display the file's elaped time" do
168
+ within 'article#project section#files article.file div.elapsed' do
169
+ page.should have_content @projects[:not_empty][:files].first.elapsed_time.to_s
170
+ end
171
+ end
172
+
173
+ it "should display an image under each file's name to categorize percentage" do
174
+ within 'article#project section#files article.file' do
175
+ page.should have_selector '.percentage_img_container > .percentage > img'
176
+ end
177
+ end
178
+
179
+ it "should not display files having 0 seconds" do
180
+ within 'article#project section#files' do
181
+ page.should_not have_content @projects[:not_empty][:files].last.path
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end