├── .gitignore ├── .rspec ├── .ruby-gemset ├── .travis.yml ├── CHANGELOG.md ├── Capfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── client ├── full │ ├── howitzer_stat.css │ ├── howitzer_stat.js │ └── howitzer_stat_settings.js ├── layout.html └── min │ ├── howitzer_stat.min.css │ ├── howitzer_stat.min.js │ └── howitzer_stat_settings.min.js ├── config.ru ├── config ├── default.yml ├── deploy.rb ├── sexy_settings_config.rb └── unicorn.rb ├── lib ├── howitzer_stat.rb └── howitzer_stat │ ├── cache_refreshing_job.rb │ ├── cucumber_parser.rb │ ├── data_cacher.rb │ ├── init.rb │ ├── page_identifier.rb │ ├── page_refreshing_job.rb │ ├── version.rb │ └── web_server.rb └── spec ├── spec_helper.rb └── unit └── lib └── howitzer_stat ├── cache_refreshing_job_spec.rb ├── data_cacher_spec.rb └── page_identifier_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | coverage 6 | InstalledFiles 7 | lib/bundler/man 8 | pkg 9 | rdoc 10 | spec/reports 11 | test/tmp 12 | test/version_tmp 13 | tmp 14 | demo 15 | log 16 | 17 | # YARD artifacts 18 | .yardoc 19 | _yardoc 20 | doc/ 21 | config/custom.yml 22 | .DS_Store 23 | .ruby-version 24 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format Fuubar 2 | --profile 3 | --color 4 | --order random -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | howitzer_stat 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - "1.9.3" 4 | - "2.0.0" 5 | - "2.1.0" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## In git 2 | 3 | ### New Features 4 | 5 | ## [v0.0.1](https://github.com/romikoops/howitzer_stat/tree/v0.0.1) 6 | 7 | Initial version 8 | -------------------------------------------------------------------------------- /Capfile: -------------------------------------------------------------------------------- 1 | load 'deploy' 2 | # Uncomment if you are using Rails' asset pipeline 3 | # load 'deploy/assets' 4 | Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) } 5 | load 'config/deploy' # remove this line to skip loading any of the default tasks 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "sexy_settings" 4 | gem 'sinatra' 5 | gem 'json' 6 | gem 'unicorn' 7 | gem 'rake' 8 | gem 'capistrano', '2.15.5' 9 | gem 'capistrano_colors' 10 | gem 'cucumber' 11 | gem 'simplecov', require: false 12 | gem 'rspec', require: false 13 | gem 'fuubar', require: false 14 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | builder (3.2.2) 5 | capistrano (2.15.5) 6 | highline 7 | net-scp (>= 1.0.0) 8 | net-sftp (>= 2.0.0) 9 | net-ssh (>= 2.0.14) 10 | net-ssh-gateway (>= 1.1.0) 11 | capistrano_colors (0.5.5) 12 | cucumber (1.3.10) 13 | builder (>= 2.1.2) 14 | diff-lcs (>= 1.1.3) 15 | gherkin (~> 2.12) 16 | multi_json (>= 1.7.5, < 2.0) 17 | multi_test (>= 0.0.2) 18 | diff-lcs (1.2.5) 19 | docile (1.1.2) 20 | fuubar (1.3.2) 21 | rspec (>= 2.14.0, < 3.1.0) 22 | ruby-progressbar (~> 1.3) 23 | gherkin (2.12.2) 24 | multi_json (~> 1.3) 25 | highline (1.6.20) 26 | json (1.8.1) 27 | kgio (2.9.2) 28 | multi_json (1.8.2) 29 | multi_test (0.0.3) 30 | net-scp (1.1.2) 31 | net-ssh (>= 2.6.5) 32 | net-sftp (2.1.2) 33 | net-ssh (>= 2.6.5) 34 | net-ssh (2.7.0) 35 | net-ssh-gateway (1.2.0) 36 | net-ssh (>= 2.6.5) 37 | rack (1.5.2) 38 | rack-protection (1.5.1) 39 | rack 40 | raindrops (0.13.0) 41 | rake (0.9.6) 42 | rspec (2.14.1) 43 | rspec-core (~> 2.14.0) 44 | rspec-expectations (~> 2.14.0) 45 | rspec-mocks (~> 2.14.0) 46 | rspec-core (2.14.7) 47 | rspec-expectations (2.14.4) 48 | diff-lcs (>= 1.1.3, < 2.0) 49 | rspec-mocks (2.14.4) 50 | ruby-progressbar (1.4.0) 51 | sexy_settings (0.0.1) 52 | simplecov (0.8.2) 53 | docile (~> 1.1.0) 54 | multi_json 55 | simplecov-html (~> 0.8.0) 56 | simplecov-html (0.8.0) 57 | sinatra (1.4.4) 58 | rack (~> 1.4) 59 | rack-protection (~> 1.4) 60 | tilt (~> 1.3, >= 1.3.4) 61 | tilt (1.4.1) 62 | unicorn (4.8.2) 63 | kgio (~> 2.6) 64 | rack 65 | raindrops (~> 0.7) 66 | 67 | PLATFORMS 68 | ruby 69 | 70 | DEPENDENCIES 71 | capistrano (= 2.15.5) 72 | capistrano_colors 73 | cucumber 74 | fuubar 75 | json 76 | rake 77 | rspec 78 | sexy_settings 79 | simplecov 80 | sinatra 81 | unicorn 82 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Roman Parashchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Howitzer Stat 2 | =============================== 3 | 4 | [![Build Status](https://travis-ci.org/strongqa/howitzer_stat.png?branch=master)](https://travis-ci.org/strongqa/howitzer_stat) 5 | [![Dependency Status](https://gemnasium.com/romikoops/howitzer_stat.png)](https://gemnasium.com/romikoops/howitzer_stat) 6 | 7 | [Howitzer](http://strongqa.github.io/howitzer/) extension used for automated tests coverage visualization of web application pages. 8 | 9 | This extension consists of 2 components: 10 | - REST web service based on Sinatra 11 | - Client files (js, css, html markup) intended for injection to a testable web application 12 | 13 | ## Requirements 14 | 15 | **Ruby 1.9.3+** 16 | 17 | ## Demo 18 | 19 | * Screenshot1 20 | * Screenshot2 21 | * Screenshot3 22 | 23 | Real demo application is coming soon... 24 | 25 | 26 | ## Documentation 27 | 28 | * [Ruby installation in production](https://github.com/strongqa/howitzer_stat/wiki/Ruby-installation-in-production) 29 | * [Deployment to production](https://github.com/strongqa/howitzer_stat/wiki/Deployment-to-production) 30 | * [Client integration](https://github.com/strongqa/howitzer_stat/wiki/Client-integration) 31 | * [Settings List](https://github.com/strongqa/howitzer_stat/wiki/Settings-List) 32 | * [REST API Documentation](https://github.com/strongqa/howitzer_stat/wiki/REST-API) 33 | * [Howitzer](http://strongqa.github.io/howitzer) 34 | 35 | ## Limitations 36 | 37 | * Not many branches and environments are supported. 38 | * Currently only Cucumber scenario can be applied. 39 | * The extension is to be covered by unit tests (both client and server part). 40 | * The Demo web application with HowitzerStat is not available. 41 | 42 | We expect to eliminate these limitations in the upcoming releases. 43 | 44 | ## Contributing 45 | 46 | 1. Fork the project. 47 | 2. Create a new feature branch (`git checkout -b my-new-feature`) 48 | 3. Commit your changes (`git commit -am 'Added some feature'`) 49 | 4. Push the branch (`git push origin my-new-feature`) 50 | 5. Create a new pull request. 51 | 52 | ### Development Environment 53 | 54 | * Create `config/custom.yml` with the following properties: 55 | 56 | ``` 57 | path_to_source: ./demo 58 | port: 7000 59 | domain: localhost 60 | ``` 61 | 62 | * Specify a correct path to the real howitzer based project (path_to_source setting). 63 | * Run a service: 64 | 65 | `unicorn -p 7000` 66 | 67 | * Navigate to url `http://localhost:7000/test?page=SomePage` 68 | 69 | where *SomePage* is one of the Ruby page classes. 70 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require "bundler" 3 | Bundler.setup 4 | 5 | require 'rake' 6 | require 'rspec/core/rake_task' 7 | RSpec::Core::RakeTask.new(:spec) { |spec| } 8 | task :default => :spec -------------------------------------------------------------------------------- /client/full/howitzer_stat.css: -------------------------------------------------------------------------------- 1 | #hs_popup__close { 2 | width: 24px; 3 | height: 24px; 4 | background: #4f4f4f; 5 | -moz-border-radius: 14px; 6 | -webkit-border-radius: 14px; 7 | border-radius: 14px; 8 | color: #ffffff; 9 | font-size: 16px; 10 | position: absolute; 11 | top: 2px; 12 | right: 2px; 13 | text-align: center; 14 | line-height: 24px; 15 | text-transform: uppercase; 16 | cursor: pointer; 17 | } 18 | 19 | #hs_tooltip { 20 | position: fixed; 21 | top:0; 22 | left:0; 23 | padding: 0; 24 | margin: 0; 25 | display: block; 26 | z-index: 2147483640; 27 | } 28 | 29 | .hs-button, .hs-button-active { 30 | display: block; 31 | z-index: 2147483640; 32 | text-align: center; 33 | color: #797979; 34 | background-color: ghostwhite; 35 | border: 1px solid #888888; 36 | } 37 | 38 | #hs_tooltip li:last-child, 39 | #hs_tooltip li:last-child :hover{ 40 | border-bottom-right-radius: 10px; 41 | } 42 | 43 | .hs-button-active :hover { 44 | background: #800000; 45 | color: white; 46 | cursor: pointer; 47 | } 48 | 49 | #hs_result { 50 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 51 | color: #555; 52 | line-height: 1; 53 | font-size: 12px; 54 | } 55 | 56 | .hs-number { 57 | color: #666; 58 | font-family: Consolas, monospace, serif; 59 | padding: 0 5px; 60 | line-height: 1.5em; 61 | font-size: 11px; 62 | } 63 | 64 | .hs-number.error { 65 | color: red; 66 | } 67 | .hs-button.active .stat-number{ color: #fff; font-weight: bold; } 68 | 69 | #hs_popup { 70 | display: block; 71 | z-index: 2147483641; 72 | background: #fff; 73 | border: 1px solid #aaa; 74 | padding: 5px 10px; 75 | text-align: left; 76 | line-height: 18px; 77 | overflow: auto; 78 | -webkit-box-shadow: 0 1px 15px #555555; 79 | box-shadow: 0px 1px 15px #555555; 80 | margin: 10px 5% 0; 81 | position: absolute; 82 | top: 0; 83 | width: 88.5%; 84 | } 85 | 86 | #hs_popup p.narrative { 87 | font-style: italic; 88 | background: #F5F5DC; 89 | padding: 5px 20px; 90 | } 91 | 92 | #hs_popup .scenario { 93 | margin-top: 1px; 94 | } 95 | 96 | #hs_popup .scenario h3 { 97 | background: #65C400; 98 | color: #fff; 99 | padding: 3px 5px; 100 | margin: 10px 0; 101 | font-weight: 400; 102 | font-size: 15px; 103 | line-height: 20px; 104 | } 105 | #hs_popup #templateTarget {font-size: 10px;color: black;} 106 | #hs_popup .used-step {font-weight: bold;} 107 | #hs_popup .cucumber, 108 | #hs_popup td, 109 | #hs_popup th { 110 | font: normal 13px "Helvetica Neue",Helvetica,Arial,sans-serif;background: white;color: black; 111 | } 112 | #hs_popup .cucumber .scenario h3, 113 | #hs_popup td .scenario h3, 114 | #hs_popup th .scenario h3 { 115 | padding:3px;margin:0; background: #65C400; 116 | } 117 | #hs_popup .cucumber div.feature, 118 | #hs_popup td div.feature, 119 | #hs_popup th div.feature { 120 | padding:2px;margin:0px 10px 5px 10px; 121 | } 122 | #hs_popup .cucumber .step_name, 123 | #hs_popup td .step_name, 124 | #hs_popup th .step_name { 125 | float:left; 126 | } 127 | #hs_popup .cucumber .step_file, 128 | #hs_popup td .step_file, 129 | #hs_popup th .step_file { 130 | text-align:right;color:#999999; 131 | } 132 | #hs_popup .cucumber .scenario_file, 133 | #hs_popup td .scenario_file, 134 | #hs_popup th .scenario_file { 135 | float:right;color:#999999; 136 | } 137 | #hs_popup .cucumber .scenario_file { 138 | margin-right: 5px; 139 | } 140 | #hs_popup .cucumber .tag, 141 | #hs_popup td .tag, 142 | #hs_popup th .tag { 143 | font-weight: bold;color:#246ac1; 144 | } 145 | #hs_popup .cucumber table, 146 | #hs_popup td table, 147 | #hs_popup th table { 148 | border-collapse:collapse; 149 | } 150 | #hs_popup .cucumber table td, 151 | #hs_popup td table td, 152 | #hs_popup th table td { 153 | padding: 3px 10px 3px 10px; border: 1px solid #cccccc; 154 | } 155 | #hs_popup .cucumber ol, 156 | #hs_popup td ol, 157 | #hs_popup th ol { 158 | list-style:none;margin:0px;padding: 0px; 159 | } 160 | #hs_popup .cucumber ol li.step, 161 | #hs_popup td ol li.step, 162 | #hs_popup th ol li.step { 163 | padding: 3px 5px 3px 18px; 164 | margin: 3px 0px 3px 5px; 165 | } 166 | 167 | #hs_popup li.background { 168 | border-left-color: gray !important; 169 | } 170 | 171 | #hs_popup .cucumber ol li.passed, 172 | #hs_popup td ol li.passed, 173 | #hs_popup th ol li.passed, 174 | #hs_popup .cucumber ol li .passed_blue[span*="used-step"] { 175 | border-left: 5px solid #00ffff; 176 | border-bottom: 1px solid #00ffff; 177 | background: #caffff; 178 | } 179 | 180 | #hs_popup .cucumber ol li.skipped, 181 | #hs_popup td ol li.skipped, 182 | #hs_popup th ol li.skipped { 183 | background: #F0FFFF; 184 | border-bottom: 1px solid #00FFFF; 185 | border-left: 5px solid #00FFFF; 186 | color: #001111; 187 | } 188 | 189 | #hs_popup .skipped .keyword, 190 | #hs_popup .passed .keyword { 191 | color: #BE5E25; 192 | font-weight: bold; 193 | } 194 | 195 | #hs_popup .step table { 196 | margin-top: 10px; 197 | margin-right: 18px; 198 | } 199 | 200 | #hs_popup table tr:nth-child(odd) td { 201 | background-color: #f0ffff; 202 | } 203 | 204 | #hs_popup table tr { 205 | word-break: break-all; 206 | word-wrap: break-word; 207 | white-space: pre; 208 | white-space: pre-wrap; 209 | } 210 | 211 | #hs_popup .cucumber table tr:first-of-type td { 212 | font-weight: bold; 213 | text-align: center; 214 | background-color: #e5e5e5; 215 | } 216 | 217 | #hs_popup pre.val { 218 | background: #fff; 219 | font-style: italic; 220 | border: 1px solid #ccc; 221 | padding: 5px 5px; 222 | border-radius: 2px; 223 | color: blue; 224 | margin-right: 18px; 225 | } 226 | 227 | #hs_popup a.hs_popup__link, 228 | #hs_popup a:visited.hs_popup__link { 229 | display: block; 230 | float: left; 231 | margin: 10px 10px; 232 | color: red; 233 | text-decoration: underline; 234 | } 235 | 236 | #hs_popup a:hover.hs_popup__link { 237 | text-decoration: none; 238 | } 239 | 240 | #hs_popup .clearfix { 241 | clear: both; 242 | } 243 | 244 | #hs_popup a, 245 | #hs_popup a:visited { 246 | color: #1E678A; 247 | text-decoration: none; 248 | } 249 | 250 | #hs_popup a:hover { 251 | text-decoration: underline; 252 | } 253 | 254 | #hs_popup .feature-container .scenario_file { 255 | line-height: 36px; 256 | } 257 | 258 | #hs_popup .scenario .scenario_file { 259 | line-height: 26px; 260 | } -------------------------------------------------------------------------------- /client/full/howitzer_stat.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | // - General - 3 | 4 | var xdr = function (method, data, callback, errback) { 5 | var req; 6 | var url = buildUrl(data); 7 | if (XMLHttpRequest) { 8 | req = new XMLHttpRequest(); 9 | if('withCredentials' in req) { 10 | req.withCredentials = true; 11 | req.open(method, url, true); 12 | req.onerror = function(){ 13 | errback(new Error('Is service running?')); 14 | }; 15 | req.onreadystatechange = function() { 16 | if (req.readyState == 4) { 17 | if (req.status >= 200 && req.status < 400) { 18 | callback(req.responseText); 19 | } else if ( req.status != 0) { //we just ignore it 20 | errback(new Error('Response returned with non-OK status')); 21 | } 22 | } 23 | }; 24 | req.send(data); 25 | } 26 | } else if(XDomainRequest) { 27 | req = new XDomainRequest(); 28 | req.open(method, url); 29 | req.onerror = errback; 30 | req.onload = function() { 31 | callback(req.responseText); 32 | }; 33 | req.send(data); 34 | } else { 35 | errback(new Error('CORS not supported')); 36 | } 37 | }; 38 | 39 | var buildUrl = function(data){ 40 | if (data.pageName) { 41 | url = window.howitzer_stat_url + "/pages/" + data.pageName; 42 | } else { 43 | url = window.howitzer_stat_url + "/page_classes" 44 | if (data.url && data.title) { url += "?url=" + data.url + "&title=" + data.title; } 45 | } 46 | return url; 47 | }; 48 | 49 | // - Tooltip - 50 | 51 | var addButton = function(text) { 52 | var pageNameElement = document.createElement('div'); 53 | pageNameElement.setAttribute('class','hs-number'); 54 | pageNameElement.innerHTML = text || 'Not Found'; 55 | 56 | var statButton = document.createElement('li'); 57 | if (text == null) { 58 | statButton.setAttribute('class', 'hs-button'); 59 | } else { 60 | statButton.setAttribute('class', 'hs-button-active'); 61 | statButton.setAttribute('style', 'display: block;'); 62 | statButton.setAttribute('data-page-name', text); 63 | statButton.addEventListener('click', function () { 64 | if (isCurrentPageCached()) { 65 | hideToolTip(); 66 | showPopup(); 67 | } else { 68 | setStatusInfo('Loading'); 69 | var currentPage = this.getAttribute('data-page-name'); 70 | cacheCurrentPage(currentPage); 71 | var data = {pageName: currentPage}; 72 | xdr('GET', data, featuresByClassNameHandler, errorHandler); 73 | } 74 | }); 75 | } 76 | statButton.appendChild(pageNameElement); 77 | getToolTipEl().appendChild(statButton); 78 | }; 79 | 80 | var clearToolTip = function() { 81 | getToolTipEl().innerHTML = ''; 82 | }; 83 | 84 | var setStatusInfo = function(text) { 85 | getToolTipEl().innerHTML = '
  • ' + text + '...
  • '; 86 | }; 87 | 88 | var setStatusError = function(text) { 89 | var errorMsg = text == null ? 'Error' : text; 90 | getToolTipEl().innerHTML = '
  • ' + errorMsg + '
  • '; 91 | }; 92 | 93 | var cacheCurrentPage = function(text){ 94 | getToolTipEl().setAttribute('data-active-page', text); 95 | }; 96 | 97 | var isCurrentPageCached = function() { 98 | return !!getToolTipEl().getAttribute('data-active-page'); 99 | }; 100 | 101 | var getToolTipEl = function() { 102 | return document.getElementById('hs_tooltip') 103 | }; 104 | 105 | var hideToolTip = function() { 106 | getToolTipEl().setAttribute("style", "display: none") 107 | }; 108 | 109 | var showToolTip = function() { 110 | getToolTipEl().setAttribute("style", "display: block") 111 | }; 112 | 113 | // - Popup - 114 | var popupEl = function() { 115 | return document.getElementById('hs_popup'); 116 | }; 117 | 118 | var templateEl = function() { 119 | return document.getElementById('cucumberStat'); 120 | }; 121 | 122 | var closeBtnEl = function() { 123 | return document.getElementById('hs_popup__close'); 124 | }; 125 | 126 | var collapseAllEl = function() { 127 | return document.getElementById('hs_collapse_all'); 128 | }; 129 | 130 | var expandAllEl = function() { 131 | return document.getElementById('hs_expand_all'); 132 | }; 133 | 134 | var collapsibleElList = function() { 135 | return document.getElementsByClassName('collapsible'); 136 | }; 137 | 138 | var featureContainerElList = function() { 139 | return document.getElementsByClassName('feature-container'); 140 | }; 141 | 142 | var scenarioElList = function() { 143 | return document.getElementsByClassName('scenario'); 144 | }; 145 | 146 | var fileLinkElList = function() { 147 | return document.getElementsByClassName('web_url'); 148 | }; 149 | 150 | var featureDescriptionEl = function(uid) { 151 | return document.getElementById('fd_' + uid); 152 | }; 153 | 154 | var scenarioContainerEl = function(uid) { 155 | return document.getElementById('sce_items_' + uid); 156 | }; 157 | 158 | var closePopup = function() { 159 | popupEl().setAttribute('style','display: none;'); 160 | }; 161 | 162 | var showPopup = function() { 163 | popupEl().setAttribute('style','display: block;'); 164 | }; 165 | 166 | var collapseOrExpand = function(el) { 167 | if (el) { 168 | if (el.getAttribute('style').lastIndexOf('none') == -1) { 169 | el.setAttribute('style', 'display: none;'); 170 | } else { 171 | el.setAttribute('style', ''); 172 | } 173 | } 174 | }; 175 | 176 | var collapseOrExpandScenario = function(uid) { 177 | collapseOrExpand(scenarioContainerEl(uid)); 178 | }; 179 | 180 | var collapseOrExpandFeature = function(uid) { 181 | collapseOrExpand(featureDescriptionEl(uid)); 182 | }; 183 | 184 | var collapseAll = function() { 185 | _.each(collapsibleElList(), function (el){ el.setAttribute('style', 'display: none;')}); 186 | }; 187 | 188 | var expandAll = function() { 189 | _.each(collapsibleElList(), function (el){ el.setAttribute('style', '')}); 190 | }; 191 | 192 | // - Handlers 193 | 194 | var errorHandler = function(error){ 195 | console.log(error); 196 | setStatusError(error.message) 197 | }; 198 | 199 | var pageClassesByTitleAndUrlHandler = function(data) { 200 | clearToolTip(); 201 | var page_list = JSON.parse(data).page; 202 | if (page_list.length == 0) { addButton(null);} 203 | _.each(page_list, function (pageName){ addButton(pageName)}); 204 | }; 205 | 206 | var featuresByClassNameHandler = function(data){ 207 | var activePage = getToolTipEl().getAttribute('data-active-page'); 208 | hideToolTip(); 209 | clearToolTip(); 210 | addButton(activePage); 211 | 212 | var pageData = JSON.parse(data); 213 | if (pageData.features == ''){ 214 | popupEl().innerHTML = 'There is no tests that include this page.'; 215 | } else { 216 | popupEl().innerHTML = _.template(templateEl().innerHTML, pageData); 217 | } 218 | closeBtnEl().addEventListener('click', function () { 219 | closePopup(); 220 | showToolTip(); 221 | }); 222 | 223 | collapseAllEl().addEventListener('click', function(e){ 224 | collapseAll(); 225 | e.preventDefault(); 226 | }); 227 | 228 | expandAllEl().addEventListener('click', function(e){ 229 | expandAll(); 230 | e.preventDefault(); 231 | }); 232 | 233 | _.each(featureContainerElList(), function(el){ 234 | var uid = el.id.replace('feature_container_', ''); 235 | el.addEventListener('click', function(e){ 236 | e.preventDefault(); 237 | collapseOrExpandFeature(uid); 238 | }) 239 | }); 240 | 241 | _.each(fileLinkElList(), function(el){ 242 | el.addEventListener('click', function(e){ 243 | e.stopPropagation(); 244 | }) 245 | }); 246 | 247 | _.each(scenarioElList(), function(el){ 248 | var uid = el.id.replace('sce_', ''); 249 | el.addEventListener('click', function(e){ 250 | e.preventDefault(); 251 | collapseOrExpandScenario(uid); 252 | }) 253 | }); 254 | 255 | collapseAll(); 256 | showPopup(); 257 | }; 258 | window.onload = function () { 259 | var baseHtml = '
      ' + "\n" + '