ui_changed 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 (194) hide show
  1. data/app/assets/javascripts/ui_changed/application.js +17 -0
  2. data/app/assets/javascripts/ui_changed/screenshots.js +280 -0
  3. data/app/assets/stylesheets/scaffold.css +56 -0
  4. data/app/assets/stylesheets/ui_changed/application.css.scss +17 -0
  5. data/app/assets/stylesheets/ui_changed/screenshot_ignore_urls.css +4 -0
  6. data/app/assets/stylesheets/ui_changed/screenshots.css +24 -0
  7. data/app/controllers/ui_changed/application_controller.rb +4 -0
  8. data/app/controllers/ui_changed/screenshot_ignore_urls_controller.rb +61 -0
  9. data/app/controllers/ui_changed/screenshots_controller.rb +266 -0
  10. data/app/controllers/ui_changed/screenshots_controller_base.rb +26 -0
  11. data/app/helpers/ui_changed/application_helper.rb +45 -0
  12. data/app/helpers/ui_changed/screenshot_ignore_urls_helper.rb +4 -0
  13. data/app/helpers/ui_changed/screenshots_helper.rb +4 -0
  14. data/app/mailers/ui_changed/notifications_mailer.rb +57 -0
  15. data/app/models/ui_changed/all_screenshot.rb +11 -0
  16. data/app/models/ui_changed/config_helper.rb +12 -0
  17. data/app/models/ui_changed/screenshot.rb +258 -0
  18. data/app/models/ui_changed/screenshot_ignore_url.rb +15 -0
  19. data/app/views/layouts/ui_changed/application.html.haml +15 -0
  20. data/app/views/ui_changed/screenshot_ignore_urls/index.haml +21 -0
  21. data/app/views/ui_changed/screenshots/_side_nav.haml +32 -0
  22. data/app/views/ui_changed/screenshots/_top_buttons.haml +36 -0
  23. data/app/views/ui_changed/screenshots/diff.haml +17 -0
  24. data/app/views/ui_changed/screenshots/diffs.haml +35 -0
  25. data/app/views/ui_changed/screenshots/index.haml +31 -0
  26. data/app/views/ui_changed/screenshots/screenshots.haml +30 -0
  27. data/app/workers/ui_changed/compare.rb +11 -0
  28. data/app/workers/ui_changed/crawl_control.rb +11 -0
  29. data/app/workers/ui_changed/crawl_test.rb +11 -0
  30. data/app/workers/ui_changed/worker_base.rb +206 -0
  31. data/config/initializers/load_config.rb +1 -0
  32. data/config/routes.rb +40 -0
  33. data/db/migrate/20130203000059_create_ui_changed_screenshots.rb +18 -0
  34. data/db/migrate/20130203001050_create_ui_changed_screenshot_ignore_urls.rb +9 -0
  35. data/lib/generators/ui_changed/resque_generator.rb +11 -0
  36. data/lib/generators/ui_changed/templates/resque.rb +7 -0
  37. data/lib/tasks/ui_changed_tasks.rake +42 -0
  38. data/lib/ui_changed/engine.rb +18 -0
  39. data/lib/ui_changed/railtie.rb +12 -0
  40. data/lib/ui_changed/version.rb +3 -0
  41. data/lib/ui_changed.rb +5 -0
  42. data/spec/dummy/README.rdoc +261 -0
  43. data/spec/dummy/Rakefile +7 -0
  44. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  45. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  46. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  47. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  48. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  49. data/spec/dummy/chromedriver.log +486 -0
  50. data/spec/dummy/config/application.rb +59 -0
  51. data/spec/dummy/config/boot.rb +10 -0
  52. data/spec/dummy/config/database.yml +20 -0
  53. data/spec/dummy/config/environment.rb +5 -0
  54. data/spec/dummy/config/environments/development.rb +37 -0
  55. data/spec/dummy/config/environments/production.rb +67 -0
  56. data/spec/dummy/config/environments/test.rb +37 -0
  57. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  58. data/spec/dummy/config/initializers/inflections.rb +15 -0
  59. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  60. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  61. data/spec/dummy/config/initializers/session_store.rb +8 -0
  62. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  63. data/spec/dummy/config/locales/en.yml +5 -0
  64. data/spec/dummy/config/routes.rb +4 -0
  65. data/spec/dummy/config/ui_changed.yml +25 -0
  66. data/spec/dummy/config.ru +4 -0
  67. data/spec/dummy/db/development.sqlite3 +0 -0
  68. data/spec/dummy/db/schema.rb +37 -0
  69. data/spec/dummy/log/development.log +28757 -0
  70. data/spec/dummy/log/test.log +47119 -0
  71. data/spec/dummy/public/404.html +26 -0
  72. data/spec/dummy/public/422.html +26 -0
  73. data/spec/dummy/public/500.html +25 -0
  74. data/spec/dummy/public/favicon.ico +0 -0
  75. data/spec/dummy/script/rails +6 -0
  76. data/spec/dummy/tmp/cache/assets/C25/650/sprockets%2F2146cc379ac52d93283881b087238840 +0 -0
  77. data/spec/dummy/tmp/cache/assets/C88/A00/sprockets%2F1576563f31b9463de3b98380b65316ec +0 -0
  78. data/spec/dummy/tmp/cache/assets/C9B/6B0/sprockets%2F14ad16343013da7f4c5807074f60da43 +0 -0
  79. data/spec/dummy/tmp/cache/assets/CB1/9B0/sprockets%2F11e63881c7fd93eb64b28b031752f184 +0 -0
  80. data/spec/dummy/tmp/cache/assets/CB6/C00/sprockets%2Fb3476726ad470583738cd4b345f805fa +0 -0
  81. data/spec/dummy/tmp/cache/assets/CB7/210/sprockets%2F138a8a31cd8188425abf378b7580856b +0 -0
  82. data/spec/dummy/tmp/cache/assets/CC0/7C0/sprockets%2Fdb1c954004648bf1999b7ef93c470907 +0 -0
  83. data/spec/dummy/tmp/cache/assets/CC1/7E0/sprockets%2F552f5b296379701887bf62b61e1eef55 +0 -0
  84. data/spec/dummy/tmp/cache/assets/CC2/E90/sprockets%2F5ca8fbc29937906ce87a35703a588175 +0 -0
  85. data/spec/dummy/tmp/cache/assets/CCE/6B0/sprockets%2F3c43115c074131cc27dff45ad1436d39 +0 -0
  86. data/spec/dummy/tmp/cache/assets/CE1/C50/sprockets%2Fb8c09b0556e29fb12b443f9491758ba1 +0 -0
  87. data/spec/dummy/tmp/cache/assets/CE2/4F0/sprockets%2F6cf98982c6e31026cd1b25b10d91d955 +0 -0
  88. data/spec/dummy/tmp/cache/assets/CE2/C60/sprockets%2F05ee6fb6374ce346eb036fa585800159 +0 -0
  89. data/spec/dummy/tmp/cache/assets/CE4/590/sprockets%2F3f8762728eca1e27313d667a68da61d2 +0 -0
  90. data/spec/dummy/tmp/cache/assets/CE7/120/sprockets%2F91db081288bd6181c67f7f600d8ac179 +0 -0
  91. data/spec/dummy/tmp/cache/assets/CE9/6D0/sprockets%2F8eeb2f4e707f4444d25caf8597182412 +0 -0
  92. data/spec/dummy/tmp/cache/assets/CF1/2F0/sprockets%2F84b5d275d61e77e4c8e971305e71b4d9 +0 -0
  93. data/spec/dummy/tmp/cache/assets/CF5/010/sprockets%2Ff9d2179a39f51f93bc6f88003845d72f +0 -0
  94. data/spec/dummy/tmp/cache/assets/D05/6A0/sprockets%2F8d3a80f374b4052fa19d7903c0615dda +0 -0
  95. data/spec/dummy/tmp/cache/assets/D06/890/sprockets%2F078f78e2e12080050f3bc2eab77b24d8 +0 -0
  96. data/spec/dummy/tmp/cache/assets/D0E/710/sprockets%2F98ad5b57d4c0b614b15d44e16c20988c +0 -0
  97. data/spec/dummy/tmp/cache/assets/D18/E30/sprockets%2F373b25f3feb8e02173177a3258fa9f8f +0 -0
  98. data/spec/dummy/tmp/cache/assets/D1B/200/sprockets%2Feb488fd44186315924274c9fbddf26c1 +0 -0
  99. data/spec/dummy/tmp/cache/assets/D2B/650/sprockets%2F17e0bd2471845003ab1d326b9df4fb2d +0 -0
  100. data/spec/dummy/tmp/cache/assets/D33/A80/sprockets%2Fe0e3c435fb1e0437fd54f6118152dbd4 +0 -0
  101. data/spec/dummy/tmp/cache/assets/D51/3D0/sprockets%2F0b8889dd27a294e91ac45d88f45ab19e +0 -0
  102. data/spec/dummy/tmp/cache/assets/D52/FC0/sprockets%2Fc7ee307174bd9ce8d84a7a714989de50 +0 -0
  103. data/spec/dummy/tmp/cache/assets/D57/590/sprockets%2Fa5889cfed7da6867603309e46febf336 +0 -0
  104. data/spec/dummy/tmp/cache/assets/D62/A70/sprockets%2F9da26ba4665f1bd1946b15f4fb7c00a2 +0 -0
  105. data/spec/dummy/tmp/cache/assets/D64/280/sprockets%2F41468fda40a48db35907717ec1cae4aa +0 -0
  106. data/spec/dummy/tmp/cache/assets/D65/BE0/sprockets%2Facc8f0cfb7c0b17255efd15087505b18 +0 -0
  107. data/spec/dummy/tmp/cache/assets/D6C/9E0/sprockets%2F8168f977dd050ba2afddd02af6139c71 +0 -0
  108. data/spec/dummy/tmp/cache/assets/D70/3A0/sprockets%2Fe4a9a1e8cb76dfec37b1f404f8519240 +0 -0
  109. data/spec/dummy/tmp/cache/assets/D74/BE0/sprockets%2Fd7aee2b6e1730859c0e0467f1d7cce93 +0 -0
  110. data/spec/dummy/tmp/cache/assets/D78/BC0/sprockets%2F207af09f77a5d6abe8dc1e03949835fc +0 -0
  111. data/spec/dummy/tmp/cache/assets/D84/D90/sprockets%2Fb8af3475f4baf9fd7b6a7c46c7451868 +0 -0
  112. data/spec/dummy/tmp/cache/assets/D8B/A20/sprockets%2F3ed551887fcdca6e97a755b75f945c6d +0 -0
  113. data/spec/dummy/tmp/cache/assets/D8E/0D0/sprockets%2F8742e2ef2bd56a3d1d0bb872b3cc217a +0 -0
  114. data/spec/dummy/tmp/cache/assets/D9F/BC0/sprockets%2F2f95d2d7024aadccb97622d868ec4db2 +0 -0
  115. data/spec/dummy/tmp/cache/assets/D9F/DC0/sprockets%2F37e94b5bc0f9440b90d05da4e4feee63 +0 -0
  116. data/spec/dummy/tmp/cache/assets/DB5/B70/sprockets%2F9b6928fa917be6edb53695facf9037db +0 -0
  117. data/spec/dummy/tmp/cache/assets/DC6/940/sprockets%2Facd26daf8801a48cf5d6b0d441da38d6 +0 -0
  118. data/spec/dummy/tmp/cache/assets/DED/010/sprockets%2F63ff0e07c5aa4b10d7defd921c0cf41d +0 -0
  119. data/spec/dummy/tmp/cache/assets/DFB/070/sprockets%2F827a36ec30d2db41fb4174a9c3dfeffe +0 -0
  120. data/spec/dummy/tmp/cache/assets/DFD/DD0/sprockets%2F20e429deffdda56940cc5c6cab9d73a3 +0 -0
  121. data/spec/dummy/tmp/cache/assets/E89/3E0/sprockets%2Fea640cb8bbbf5cfa9435ddeebd7b42a8 +0 -0
  122. data/spec/dummy/tmp/cache/sass/2d87c55fb19cbf8c06f79a1d11d9921f7ccdf621/bootstrap-responsive.scssc +0 -0
  123. data/spec/dummy/tmp/cache/sass/2d87c55fb19cbf8c06f79a1d11d9921f7ccdf621/bootstrap.scssc +0 -0
  124. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_accordion.scssc +0 -0
  125. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_alerts.scssc +0 -0
  126. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_breadcrumbs.scssc +0 -0
  127. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_button-groups.scssc +0 -0
  128. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_buttons.scssc +0 -0
  129. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_carousel.scssc +0 -0
  130. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_close.scssc +0 -0
  131. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_code.scssc +0 -0
  132. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_component-animations.scssc +0 -0
  133. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_dropdowns.scssc +0 -0
  134. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_forms.scssc +0 -0
  135. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_grid.scssc +0 -0
  136. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_hero-unit.scssc +0 -0
  137. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_labels-badges.scssc +0 -0
  138. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_layouts.scssc +0 -0
  139. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_media.scssc +0 -0
  140. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_mixins.scssc +0 -0
  141. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_modals.scssc +0 -0
  142. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_navbar.scssc +0 -0
  143. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_navs.scssc +0 -0
  144. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_pager.scssc +0 -0
  145. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_pagination.scssc +0 -0
  146. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_popovers.scssc +0 -0
  147. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_progress-bars.scssc +0 -0
  148. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_reset.scssc +0 -0
  149. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_responsive-1200px-min.scssc +0 -0
  150. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_responsive-767px-max.scssc +0 -0
  151. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_responsive-768px-979px.scssc +0 -0
  152. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_responsive-navbar.scssc +0 -0
  153. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_responsive-utilities.scssc +0 -0
  154. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_scaffolding.scssc +0 -0
  155. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_sprites.scssc +0 -0
  156. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_tables.scssc +0 -0
  157. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_thumbnails.scssc +0 -0
  158. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_tooltip.scssc +0 -0
  159. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_type.scssc +0 -0
  160. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_utilities.scssc +0 -0
  161. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_variables.scssc +0 -0
  162. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/_wells.scssc +0 -0
  163. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/bootstrap.scssc +0 -0
  164. data/spec/dummy/tmp/cache/sass/90f0768cf7e8daaf11afd7e1e4fcba1811609e39/responsive.scssc +0 -0
  165. data/spec/dummy/tmp/cache/sass/94c49ca37a72afd14b662ec7a424412bc283c3cf/application.css.scssc +0 -0
  166. data/spec/dummy/tmp/cache/sass/a83afe1449c73975e2fd619cb5f810eada3c2894/_font-awesome.sassc +0 -0
  167. data/spec/models/screenshot_actions_spec.rb +126 -0
  168. data/spec/models/screenshots_ignore_url_spec.rb +24 -0
  169. data/spec/models/screenshots_spec.rb +144 -0
  170. data/spec/routing/screenshots_spec.rb +71 -0
  171. data/spec/spec_helper.rb +66 -0
  172. data/spec/support/factories/screenshot.rb +14 -0
  173. data/spec/support/factories/screenshot_ignore_url.rb +5 -0
  174. data/spec/test_screenshots/control/image_1.png +0 -0
  175. data/spec/test_screenshots/control/image_1_small.png +0 -0
  176. data/spec/test_screenshots/control/image_2.png +0 -0
  177. data/spec/test_screenshots/control/image_2_small.png +0 -0
  178. data/spec/test_screenshots/control/image_3.png +0 -0
  179. data/spec/test_screenshots/control/image_3_small.png +0 -0
  180. data/spec/test_screenshots/control/image_4.png +0 -0
  181. data/spec/test_screenshots/control/image_4_small.png +0 -0
  182. data/spec/test_screenshots/control/image_5.png +0 -0
  183. data/spec/test_screenshots/control/image_5_small.png +0 -0
  184. data/spec/test_screenshots/test/image_10.png +0 -0
  185. data/spec/test_screenshots/test/image_10_small.png +0 -0
  186. data/spec/test_screenshots/test/image_6.png +0 -0
  187. data/spec/test_screenshots/test/image_6_small.png +0 -0
  188. data/spec/test_screenshots/test/image_7.png +0 -0
  189. data/spec/test_screenshots/test/image_7_small.png +0 -0
  190. data/spec/test_screenshots/test/image_8.png +0 -0
  191. data/spec/test_screenshots/test/image_8_small.png +0 -0
  192. data/spec/test_screenshots/test/image_9.png +0 -0
  193. data/spec/test_screenshots/test/image_9_small.png +0 -0
  194. metadata +610 -0
@@ -0,0 +1,266 @@
1
+ require_dependency "ui_changed/application_controller"
2
+ require 'anemone'
3
+ require 'fileutils'
4
+
5
+ module UiChanged
6
+ class ScreenshotsController < ScreenshotsControllerBase
7
+
8
+ # GET /screenshots
9
+ def index
10
+ @crawl_working = is_any_job_running_or_queued ? "true" : "false"
11
+ end
12
+
13
+ # GET /screenshots/crawl_status.json
14
+ def crawl_status
15
+ first_status = crawl_statuses.first
16
+ screenshots = []
17
+ if first_status
18
+ screenshots = UiChanged::Screenshot.where("created_at > ?", first_status.time).order("id desc").limit(50).reverse
19
+ end
20
+
21
+ job = job_running
22
+ if job != nil
23
+ job_running_status = job.status
24
+ if job.name && job.name.include?("Control")
25
+ job_running_type = "control"
26
+ elsif job.name &&job.name.include?("Test")
27
+ job_running_type = "test"
28
+ elsif job.name
29
+ job_running_type = "compare"
30
+ end
31
+ end
32
+
33
+ diff_count = UiChanged::Screenshot.not_in_ignored.where(:diff_found => true).count
34
+ control_count = UiChanged::Screenshot.not_in_ignored.where(:is_control => true).count
35
+ test_count = UiChanged::Screenshot.not_in_ignored.where(:is_test => true).count
36
+ compare_count = UiChanged::Screenshot.not_in_ignored.where(:is_compare => true).count
37
+
38
+ render :json => [{
39
+ :screenshots => screenshots,
40
+ :counts => {
41
+ :diff => diff_count,
42
+ :control => control_count,
43
+ :test => test_count,
44
+ :compare => compare_count,
45
+ },
46
+ :worker => {
47
+ :running_status => job_running_status,
48
+ :running_type => job_running_type,
49
+ :first_status => first_status ? first_status.status : ""
50
+ }
51
+ }]
52
+ end
53
+
54
+ # POST /screenshots/ignored
55
+ def cancel
56
+ # there has got to be a sexy ruby way of doing this
57
+ crawl_statuses.each do |job|
58
+ next unless is_job_running(job.status)
59
+ job_id = job.uuid
60
+ puts 'cancelling job_id: ' + job_id.to_s
61
+ Resque::Plugins::Status::Hash.kill(job_id)
62
+ end
63
+
64
+ # and for good measure
65
+ `redis-cli FLUSHALL`
66
+
67
+ head :ok
68
+ end
69
+
70
+ # GET /screenshots/diffs
71
+ def diffs
72
+ params[:sort] ||= "image_file_size desc"
73
+ @diffs = UiChanged::Screenshot.search(params[:search]).not_in_ignored.where(:diff_found => true).paginate(:page => params[:page],
74
+ :per_page => params[:per_page],
75
+ :order => params[:sort])
76
+ @all_screenshots = []
77
+ @diffs.each do |diff|
78
+ control = UiChanged::Screenshot.find(diff.control_id)
79
+ test = UiChanged::Screenshot.find(diff.test_id)
80
+ @all_screenshots << UiChanged::AllScreenshot.new(control, test, diff)
81
+ end
82
+ end
83
+
84
+ # GET /screenshots/compares
85
+ def compares
86
+ params[:sort] ||= "url asc"
87
+ @screenshots = UiChanged::Screenshot.search(params[:search]).not_in_ignored.where(:is_compare => true)
88
+ .paginate(:page => params[:page],
89
+ :per_page => params[:per_page],
90
+ :order => params[:sort])
91
+ @type = "Compare"
92
+ render "ui_changed/screenshots/screenshots"
93
+ end
94
+
95
+ # GET /screenshots/controls
96
+ def controls
97
+ params[:sort] ||= "url asc"
98
+ @screenshots = UiChanged::Screenshot.search(params[:search]).not_in_ignored.where(:is_control => true)
99
+ .paginate(:page => params[:page],
100
+ :per_page => params[:per_page],
101
+ :order => params[:sort])
102
+ @type = "Control"
103
+ render "ui_changed/screenshots/screenshots"
104
+ end
105
+
106
+ # GET /screenshots/tests
107
+ def tests
108
+ params[:sort] ||= "url asc"
109
+ @screenshots = UiChanged::Screenshot.search(params[:search]).not_in_ignored.where(:is_test => true)
110
+ .paginate(:page => params[:page],
111
+ :per_page => params[:per_page],
112
+ :order => params[:sort])
113
+ @type = "Test"
114
+ render "ui_changed/screenshots/screenshots"
115
+ end
116
+
117
+ # GET /screenshots/diff
118
+ def diff
119
+ @diff = UiChanged::Screenshot.find(params[:diff_id])
120
+ @control = UiChanged::Screenshot.find(@diff.control_id)
121
+ @test = UiChanged::Screenshot.find(@diff.test_id)
122
+ end
123
+
124
+ # DELETE /screenshots/destroy
125
+ def destroy
126
+ UiChanged::Screenshot.destroy_entries_and_images(params[:id].split(","))
127
+ head :ok
128
+ end
129
+
130
+ # DELETE /screenshots/destroy_all_controls
131
+ def destroy_all_controls
132
+ UiChanged::Screenshot.delete_all_controls
133
+ head :ok
134
+ end
135
+
136
+ # DELETE /screenshots/destroy_all_tests
137
+ def destroy_all_tests
138
+ UiChanged::Screenshot.delete_all_tests
139
+ head :ok
140
+ end
141
+
142
+ # DELETE /screenshots/destroy_all_compares
143
+ def destroy_all_compares
144
+ UiChanged::Screenshot.delete_all_compares
145
+ head :ok
146
+ end
147
+
148
+ # remove all diffs & tests
149
+ # DELETE /screenshots/remove_all_diffs_and_tests
150
+ def remove_all_diffs_and_tests
151
+ UiChanged::Screenshot.remove_all_diffs_and_tests
152
+ head :ok
153
+ end
154
+
155
+ # DELETE /screenshots/remove_diff_and_test
156
+ def remove_diff_and_test
157
+ UiChanged::Screenshot.remove_diffs_and_tests(params[:id].split(","))
158
+ head :ok
159
+ end
160
+
161
+ # set tests as controls and DELETE controls and DELETE diffs
162
+ # POST /screenshots/set_all_tests_as_control
163
+ def set_all_tests_as_control
164
+ UiChanged::Screenshot.set_all_tests_as_controls
165
+ head :ok
166
+ end
167
+
168
+ # POST /screenshots/set_test_as_control
169
+ def set_test_as_control
170
+ UiChanged::Screenshot.set_tests_as_controls(params[:id].split(","))
171
+ head :ok
172
+ end
173
+
174
+ # crawling & comparing
175
+
176
+ # POST /screenshots/start_all
177
+ def start_all
178
+ UiChanged::Screenshot.async_crawl_and_compare
179
+ head :ok
180
+ end
181
+
182
+ # POST /screenshots/start_control
183
+ def start_control
184
+ UiChanged::Screenshot.start_async_crawl_for_control
185
+ head :ok
186
+ end
187
+
188
+ # POST /screenshots/start_test
189
+ def start_test
190
+ UiChanged::Screenshot.start_async_crawl_for_test
191
+ head :ok
192
+ end
193
+
194
+ # POST /screenshots/start_control_test
195
+ def start_control_test
196
+ UiChanged::Screenshot.start_async_crawl_for_control_and_test
197
+ head :ok
198
+ end
199
+
200
+ # POST /screenshots/start_control_compare
201
+ def start_control_compare
202
+ UiChanged::Screenshot.start_async_crawl_for_control_and_compare
203
+ head :ok
204
+ end
205
+
206
+ # POST /screenshots/start_test_compare
207
+ def start_test_compare
208
+ UiChanged::Screenshot.start_async_crawl_for_test_and_compare
209
+ head :ok
210
+ end
211
+
212
+ # POST /screenshots/start_compare
213
+ def start_compare
214
+ UiChanged::Screenshot.start_async_compare
215
+ head :ok
216
+ end
217
+
218
+ private
219
+
220
+ def crawl_statuses
221
+ Resque::Plugins::Status::Hash.statuses
222
+ end
223
+
224
+ def job_running
225
+ currently_running = nil
226
+ crawl_statuses.each do |job|
227
+ if is_job_running(job.status)
228
+ currently_running = job
229
+ break
230
+ end
231
+ end
232
+ currently_running
233
+ end
234
+
235
+ def all_running
236
+ all = []
237
+ crawl_statuses.each do |job|
238
+ if is_job_running(job.status)
239
+ all << job
240
+ end
241
+ end
242
+ all
243
+ end
244
+
245
+ def job_running_status
246
+ job = job_running
247
+ return unless job != nil
248
+ job.status
249
+ end
250
+
251
+ def is_any_job_running_or_queued
252
+ crawl_statuses.each do |job|
253
+ return true unless !is_job_running_or_queued(job.status)
254
+ end
255
+ return false
256
+ end
257
+
258
+ def is_job_running_or_queued(status)
259
+ return status == "working" || status == "queued"
260
+ end
261
+
262
+ def is_job_running(status)
263
+ return status == "working"
264
+ end
265
+ end
266
+ end
@@ -0,0 +1,26 @@
1
+ module UiChanged
2
+ class ScreenshotsControllerBase < ApplicationController
3
+ before_filter :authenticate
4
+ before_filter :screenshot_counts, only: [:index, :diffs, :compares, :controls, :tests, :ignored, :settings, :diff]
5
+
6
+ def screenshot_counts
7
+ @search = params[:search]
8
+ @diff_count = UiChanged::Screenshot.not_in_ignored.where(:diff_found => true).count
9
+ @control_count = UiChanged::Screenshot.not_in_ignored.where(:is_control => true).count
10
+ @test_count = UiChanged::Screenshot.not_in_ignored.where(:is_test => true).count
11
+ @compare_count = UiChanged::Screenshot.not_in_ignored.where(:is_compare => true).count
12
+ @ignore_count = UiChanged::ScreenshotIgnoreUrl.count
13
+ end
14
+
15
+ protected
16
+
17
+ def authenticate
18
+ if !UiChanged::ConfigHelper.auth_username
19
+ return true
20
+ end
21
+ authenticate_or_request_with_http_basic do |username, password|
22
+ username == UiChanged::ConfigHelper.auth_username && password == UiChanged::ConfigHelper.auth_password
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,45 @@
1
+ module UiChanged
2
+ module ApplicationHelper
3
+ def remove_all_path(request_fullpath)
4
+ if request_fullpath.include?(screenshot_controls_path)
5
+ screenshot_destroy_all_controls_path
6
+ elsif request_fullpath.include?(screenshot_tests_path)
7
+ screenshot_destroy_all_tests_path
8
+ elsif request_fullpath.include?(screenshot_compares_path)
9
+ screenshot_destroy_all_compares_path
10
+ elsif request_fullpath.include?(screenshot_ignore_urls_path)
11
+ screenshot_ignore_url_destroy_all_path
12
+ end
13
+ end
14
+ def ignore_all_urls_path(request_fullpath)
15
+ if request_fullpath.include?(screenshot_controls_path)
16
+ screenshot_ignore_url_add_all_controls_path
17
+ elsif request_fullpath.include?(screenshot_tests_path)
18
+ screenshot_ignore_url_add_all_tests_path
19
+ elsif request_fullpath.include?(screenshot_compares_path)
20
+ screenshot_ignore_url_add_all_compares_path
21
+ elsif request_fullpath.include?(screenshot_diffs_path)
22
+ screenshot_ignore_url_add_all_diffs_path
23
+ end
24
+ end
25
+
26
+ def show_remove_test_and_diff(request_fullpath)
27
+ request_fullpath.include?(screenshot_diffs_path) || request_fullpath.include?(screenshot_diff_path)
28
+ end
29
+ def show_remove(request_fullpath)
30
+ request_fullpath.include?(screenshot_controls_path) ||
31
+ request_fullpath.include?(screenshot_tests_path) ||
32
+ request_fullpath.include?(screenshot_compares_path) ||
33
+ request_fullpath.include?(screenshot_ignore_urls_path)
34
+ end
35
+ def show_set_test_as_control(request_fullpath)
36
+ request_fullpath.include?(screenshot_diffs_path) || request_fullpath.include?(screenshot_diff_path) || request_fullpath.include?(screenshot_tests_path)
37
+ end
38
+ def show_ignore_url(request_fullpath)
39
+ request_fullpath.include?(screenshot_diffs_path) ||
40
+ request_fullpath.include?(screenshot_controls_path) ||
41
+ request_fullpath.include?(screenshot_tests_path) ||
42
+ request_fullpath.include?(screenshot_compares_path)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,4 @@
1
+ module UiChanged
2
+ module ScreenshotIgnoreUrlsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module UiChanged
2
+ module ScreenshotsHelper
3
+ end
4
+ end
@@ -0,0 +1,57 @@
1
+ module UiChanged
2
+ class NotificationsMailer < ActionMailer::Base
3
+ include Resque::Mailer
4
+
5
+ default :from => "ui_changed@ui_changed.com"
6
+ default :to => UiChanged::ConfigHelper.email_results_to
7
+
8
+ def new_controls_message
9
+ if !UiChanged::ConfigHelper.email_after_control_crawl
10
+ puts '----------- NOT sending email after control crawl -------------'
11
+ return
12
+ end
13
+ count = UiChanged::Screenshot.where(:is_control => true).count
14
+
15
+ puts '----------- sending email message after control crawl -------------'
16
+ mail(:subject => "Ui_Changed - saved #{count} control screenshots", :body => "Click here to view them: http://localhost:3000/ui_changed/screenshots/controls")
17
+ end
18
+
19
+ def new_tests_message
20
+ if !UiChanged::ConfigHelper.email_after_test_crawl
21
+ puts '----------- NOT sending email after test crawl -------------'
22
+ return
23
+ end
24
+ count = UiChanged::Screenshot.where(:is_test => true).count
25
+
26
+ puts '----------- sending email message after test crawl -------------'
27
+ mail(:subject => "Ui_Changed - saved #{count} test screenshots", :body => "Click here to view them: http://localhost:3000/ui_changed/screenshots/tests")
28
+ end
29
+
30
+ def new_compares_message
31
+ if !UiChanged::ConfigHelper.email_after_compare
32
+ puts '----------- NOT sending email after compare -------------'
33
+ return
34
+ end
35
+ count = UiChanged::Screenshot.where(:is_compare => true).count
36
+
37
+ puts '----------- sending email message after compare -------------'
38
+ mail(:subject => "Ui_Changed - saved #{count} compare screenshots", :body => "Click here to view them: http://localhost:3000/ui_changed/screenshots/compares")
39
+ end
40
+
41
+ def new_diffs_message
42
+ if !UiChanged::ConfigHelper.email_after_compare_with_diffs
43
+ puts '----------- NOT sending email after compare with diffs -------------'
44
+ return
45
+ end
46
+ count = UiChanged::Screenshot.where(:diff_found => true).count
47
+
48
+ if !UiChanged::ConfigHelper.email_after_compare_with_diffs_on_zero_found && count == 0
49
+ puts '----------- NOT sending email message after compare with diffs b/c zero [diffs] found -------------'
50
+ return
51
+ end
52
+
53
+ puts '----------- sending email message after compare with diffs -------------'
54
+ mail(:subject => "Ui_Changed - found #{count} diffs", :body => "Click here to view them: http://localhost:3000/ui_changed/screenshots/diffs")
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,11 @@
1
+ module UiChanged
2
+ class AllScreenshot
3
+ attr_accessor :control_ss, :test_ss, :diff_ss
4
+
5
+ def initialize(control_ss, test_ss, diff_ss)
6
+ @control_ss = control_ss
7
+ @test_ss = test_ss
8
+ @diff_ss = diff_ss
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module UiChanged
2
+ class ConfigHelper
3
+ MTC_CONFIG.each do |config|
4
+ # set the path
5
+ if Rails.env.test? && config[0].end_with?("_path")
6
+ define_singleton_method config[0], lambda { "#{Rails.root}/#{config[1]}" }
7
+ else
8
+ define_singleton_method config[0], lambda { config[1] }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,258 @@
1
+ require 'anemone'
2
+ require 'selenium-webdriver'
3
+ require 'fileutils'
4
+
5
+ module UiChanged
6
+ class Screenshot < ActiveRecord::Base
7
+ attr_accessible :url,
8
+ :is_control,
9
+ :is_test,
10
+ :is_compare,
11
+ :diff_found,
12
+ :control_id,
13
+ :test_id,
14
+ :image_file_name,
15
+ :image_file_size,
16
+ :image_content_type,
17
+ :displayable_image_path_full,
18
+ :displayable_image_path_small_full
19
+
20
+ validates :url, :presence => true, :format => URI::regexp(%w(http https))
21
+ validates :image_file_name, :presence => true
22
+ validates :image_file_size, :presence => true
23
+ validates :image_content_type, :presence => true
24
+
25
+ validate :check_only_one_type
26
+ validate :check_diff_found
27
+ validate :check_compare_ids
28
+ validate :check_image_content_type
29
+
30
+ def check_only_one_type
31
+ types = [is_control, is_test, is_compare]
32
+ if types.count(true) != 1
33
+ errors[:base] << 'screenshot can only have one is value set to true'
34
+ end
35
+ end
36
+ def check_diff_found
37
+ if diff_found && !( !is_control && !is_test && is_compare )
38
+ errors[:base] << 'when diff found is set it must be of type is_compare'
39
+ end
40
+ end
41
+ def check_compare_ids
42
+ if is_compare && (control_id == nil || test_id == nil)
43
+ errors[:base] << 'is_compare screenshots must have their control_id and test_id set'
44
+ end
45
+ end
46
+ def check_image_content_type
47
+ errors.add(:image_content_type, "can only be png") unless image_content_type == "png"
48
+ end
49
+
50
+ self.per_page = 15
51
+
52
+ class << self
53
+
54
+ def start_async_crawl_for_control
55
+ UiChanged::CrawlControl.create
56
+ end
57
+
58
+ def start_async_crawl_for_test
59
+ UiChanged::CrawlTest.create
60
+ end
61
+ def start_async_crawl_for_control_and_test
62
+ start_async_crawl_for_control
63
+ start_async_crawl_for_test
64
+ end
65
+ def start_async_crawl_for_control_and_compare
66
+ start_async_crawl_for_control
67
+ start_async_compare
68
+ end
69
+ def start_async_crawl_for_test_and_compare
70
+ start_async_crawl_for_test
71
+ start_async_compare
72
+ end
73
+ def start_async_compare
74
+ UiChanged::Compare.create
75
+ end
76
+
77
+ def async_crawl_and_compare
78
+ start_async_crawl_for_control
79
+ start_async_crawl_for_test
80
+ start_async_compare
81
+ end
82
+
83
+ def search(search)
84
+ UiChanged::Screenshot.where('ui_changed_screenshots.url LIKE ?', "%#{search}%")
85
+ end
86
+ def set_all_tests_as_controls
87
+ delete_all_controls
88
+ move_all_test_images_to_control
89
+ UiChanged::Screenshot.update_all({:is_control => true, :is_test => false}, {:is_test => true})
90
+ end
91
+ def set_tests_as_controls(test_ids)
92
+ test_ids.each do |test_id|
93
+ set_test_as_control(test_id)
94
+ end
95
+ end
96
+ def set_test_as_control(test_id)
97
+ test_ss = UiChanged::Screenshot.find(test_id)
98
+ control_ss = UiChanged::Screenshot.find_by_url_and_is_control(test_ss.url, true)
99
+ compare_ss = UiChanged::Screenshot.find_by_test_id(test_ss.id)
100
+
101
+ unless !control_ss
102
+ control_ss.remove_image
103
+ control_ss.destroy
104
+ end
105
+ unless !compare_ss
106
+ compare_ss.remove_image
107
+ compare_ss.destroy
108
+ end
109
+
110
+ test_ss.is_control = true
111
+ test_ss.is_test = false
112
+ test_ss.save
113
+ # move test ss's to control dir
114
+ test_ss.move_test_image_to_control
115
+ end
116
+
117
+ # delete all entries & images
118
+ def delete_all_controls
119
+ UiChanged::Screenshot.delete_all(:is_control => true)
120
+ UiChanged::Screenshot.delete_all(:is_compare => true)
121
+ FileUtils.rm_rf(Dir.glob(UiChanged::ConfigHelper.control_path + '*'))
122
+ FileUtils.rm_rf(Dir.glob(UiChanged::ConfigHelper.compare_path + '*'))
123
+ end
124
+ def delete_all_tests
125
+ UiChanged::Screenshot.delete_all(:is_test => true)
126
+ UiChanged::Screenshot.delete_all(:is_compare => true)
127
+ FileUtils.rm_rf(Dir.glob(UiChanged::ConfigHelper.test_path + '*'))
128
+ FileUtils.rm_rf(Dir.glob(UiChanged::ConfigHelper.compare_path + '*'))
129
+ end
130
+ def delete_all_compares
131
+ UiChanged::Screenshot.delete_all(:is_compare => true)
132
+ FileUtils.rm_rf(Dir.glob(UiChanged::ConfigHelper.compare_path + '*'))
133
+ end
134
+
135
+ def destroy_entries_and_images(ids)
136
+ ids.each do |id|
137
+ destroy_entry_and_image(id)
138
+ end
139
+ end
140
+ def destroy_entry_and_image(id)
141
+ ss = UiChanged::Screenshot.find(id)
142
+
143
+ # remove the corresponding compare screenshot
144
+ if ss.is_control
145
+ compare_ss = UiChanged::Screenshot.find_by_control_id(ss.id)
146
+ if compare_ss
147
+ compare_ss.remove_image
148
+ compare_ss.destroy
149
+ end
150
+ elsif ss.is_test
151
+ compare_ss = UiChanged::Screenshot.find_by_test_id(ss.id)
152
+ if compare_ss
153
+ compare_ss.remove_image
154
+ compare_ss.destroy
155
+ end
156
+ end
157
+
158
+ ss.remove_image
159
+ ss.destroy
160
+ end
161
+
162
+ def remove_all_diffs_and_tests
163
+ delete_all_compares
164
+ delete_all_tests
165
+ end
166
+ def remove_diffs_and_tests(diff_ids)
167
+ diff_ids.split(",").each do |diff_id|
168
+ remove_diff_and_test(diff_id.first.to_i)
169
+ end
170
+ end
171
+ def remove_diff_and_test(diff_id)
172
+ ss_diff = UiChanged::Screenshot.find(diff_id)
173
+ ss_test = UiChanged::Screenshot.find(ss_diff.test_id)
174
+ ss_diff.remove_image
175
+ ss_diff.destroy
176
+
177
+ ss_test.remove_image
178
+ ss_test.destroy
179
+ end
180
+
181
+ def move_all_test_images_to_control
182
+ # delete all control images
183
+ FileUtils.rm_rf(Dir.glob(UiChanged::ConfigHelper.control_path + '*'))
184
+
185
+ # move all test images to control directory
186
+ Dir.foreach(UiChanged::ConfigHelper.test_path) do |img|
187
+ next if img == '.' || img == '..'
188
+ # do work on real items
189
+ UiChanged::Screenshot.move_test_image_to_control(img)
190
+ end
191
+ end
192
+
193
+ def move_test_image_to_control(image_file_name_full)
194
+ FileUtils.mv(UiChanged::ConfigHelper.test_path + image_file_name_full,
195
+ UiChanged::ConfigHelper.control_path + image_file_name_full)
196
+ end
197
+
198
+ def not_in_ignored
199
+ UiChanged::Screenshot.joins("LEFT JOIN ui_changed_screenshot_ignore_urls siu ON siu.url = ui_changed_screenshots.url").where('siu.id is null')
200
+ end
201
+ end
202
+
203
+ def remove_image
204
+ FileUtils.rm(image_path_full)
205
+ FileUtils.rm(image_path_small_full)
206
+ end
207
+
208
+ def move_test_image_to_control
209
+ UiChanged::Screenshot.move_test_image_to_control(image_file_name_full)
210
+ UiChanged::Screenshot.move_test_image_to_control(image_file_name_small_full)
211
+ end
212
+
213
+ def image_path_base
214
+ if is_control
215
+ UiChanged::ConfigHelper.control_path
216
+ elsif is_compare
217
+ UiChanged::ConfigHelper.compare_path
218
+ else
219
+ UiChanged::ConfigHelper.test_path
220
+ end
221
+ end
222
+
223
+ def displayable_image_path_full
224
+ image_path_full.sub('public','')
225
+ end
226
+
227
+ def displayable_image_path_small_full
228
+ image_path_small_full.sub('public','')
229
+ end
230
+
231
+ def image_path_full
232
+ image_path_base + image_file_name_full
233
+ end
234
+
235
+ def image_path_small_full
236
+ image_path_base + image_file_name_small_full
237
+ end
238
+
239
+ def image_file_name_full
240
+ if image_file_name == nil || image_content_type == nil
241
+ return "default.png"
242
+ end
243
+ image_file_name + "." + image_content_type
244
+ end
245
+
246
+ def image_file_name_small_full
247
+ if image_file_name == nil || image_content_type == nil
248
+ return "default.png"
249
+ end
250
+ image_file_name + "_small." + image_content_type
251
+ end
252
+
253
+ def as_json(*a)
254
+ self.attributes.merge({"displayable_image_path_full" => self.displayable_image_path_full})
255
+ end
256
+
257
+ end
258
+ end