cutara 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.
@@ -0,0 +1,287 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'fileutils'
3
+ require 'cucumber/formatter/console'
4
+ require 'cucumber/formatter/io'
5
+ require 'gherkin/formatter/escaping'
6
+ require 'TarantulaUpdater'
7
+ require 'Helper'
8
+
9
+ module Cucumber
10
+ module Formatter
11
+ # This formatter prints features to plain text - exactly how they were parsed,
12
+ # just prettier. That means with proper indentation and alignment of table columns.
13
+ # it also updates Tarantula step results
14
+ #
15
+ # If the output is STDOUT (and not a file), there are bright colours to watch too.
16
+ #
17
+ module Duration
18
+ # Helper method for formatters that need to
19
+ # format a duration in seconds to the UNIX
20
+ # <tt>time</tt> format.
21
+ def format_duration_simple(seconds)
22
+ seconds
23
+ end
24
+ end
25
+ class CustomTarantulaFormatter
26
+ include FileUtils
27
+ include Console
28
+ include Io
29
+ include Gherkin::Formatter::Escaping
30
+ attr_writer :indent
31
+ attr_reader :runtime
32
+
33
+ def initialize(runtime, path_or_io, options)
34
+ @runtime, @io, @options = runtime, ensure_io(path_or_io, "pretty"), options
35
+ @exceptions = []
36
+ @indent = 0
37
+ @prefixes = options[:prefixes] || {}
38
+ @delayed_messages = []
39
+ @feature_name = nil
40
+ @scenario_index = 0
41
+ @scenario_exceptions = []
42
+ @scenario_undefined = false
43
+ @scenario_updated = false
44
+ TarantulaUpdater.config = YAML.load(File.open(SUPPORT+"/tarantula.yml"))
45
+ end
46
+
47
+ def after_features(features)
48
+ print_summary(features) unless @options[:autoformat]
49
+ @io.puts(format_duration_simple(features.duration)) if features && features.duration
50
+ resp = TarantulaUpdater.update_testcase_duration(ENV["project"], ENV["execution"], @feature_name, format_duration_simple(features.duration)) if features && features.duration
51
+ @io.puts ">>>>>>>>>>>>>>>" + resp.to_s
52
+ end
53
+
54
+ def before_feature(feature)
55
+ @scenario_index = 0
56
+ @exceptions = []
57
+ @indent = 0
58
+ if @options[:autoformat]
59
+ file = File.join(@options[:autoformat], feature.file)
60
+ dir = File.dirname(file)
61
+ mkdir_p(dir) unless File.directory?(dir)
62
+ @io = ensure_file(file, "pretty")
63
+ end
64
+ end
65
+
66
+ def comment_line(comment_line)
67
+ @io.puts(comment_line.indent(@indent))
68
+ @io.flush
69
+ end
70
+
71
+ def after_tags(tags)
72
+ if @indent == 1
73
+ @io.puts
74
+ @io.flush
75
+ end
76
+ end
77
+
78
+ def tag_name(tag_name)
79
+ tag = format_string(tag_name, :tag).indent(@indent)
80
+ @io.print(tag)
81
+ @io.flush
82
+ @indent = 1
83
+ end
84
+
85
+ def feature_name(keyword, name)
86
+ @feature_name = name
87
+ @io.puts("#{keyword}: #{name}")
88
+ @io.puts
89
+ @io.flush
90
+ end
91
+
92
+ def before_feature_element(feature_element)
93
+ @indent = 2
94
+ @scenario_indent = 2
95
+ end
96
+
97
+ def after_feature_element(feature_element)
98
+ @io.puts
99
+ @io.flush
100
+ end
101
+
102
+ def before_background(background)
103
+ @indent = 2
104
+ @scenario_indent = 2
105
+ @in_background = true
106
+ end
107
+
108
+ def after_background(background)
109
+ @in_background = nil
110
+ @io.puts
111
+ @io.flush
112
+ end
113
+
114
+ def background_name(keyword, name, file_colon_line, source_indent)
115
+ print_feature_element_name(keyword, name, file_colon_line, source_indent)
116
+ end
117
+
118
+ def before_examples_array(examples_array)
119
+ @indent = 4
120
+ @io.puts
121
+ @visiting_first_example_name = true
122
+ end
123
+
124
+ def examples_name(keyword, name)
125
+ @io.puts unless @visiting_first_example_name
126
+ @visiting_first_example_name = false
127
+ names = name.strip.empty? ? [name.strip] : name.split("\n")
128
+ @io.puts(" #{keyword}: #{names[0]}")
129
+ names[1..-1].each {|s| @io.puts " #{s}" } unless names.empty?
130
+ @io.flush
131
+ @indent = 6
132
+ @scenario_indent = 6
133
+ end
134
+
135
+ def before_outline_table(outline_table)
136
+ @table = outline_table
137
+ end
138
+
139
+ def after_outline_table(outline_table)
140
+ @table = nil
141
+ @indent = 4
142
+ end
143
+
144
+ def scenario_name(keyword, name, file_colon_line, source_indent)
145
+ @scenario_index += 1
146
+ @scenario_exceptions = []
147
+ @scenario_undefined = false
148
+ print_feature_element_name(keyword, name, file_colon_line, source_indent)
149
+ end
150
+
151
+ def before_step(step)
152
+ @current_step = step
153
+ @indent = 6
154
+ end
155
+
156
+ def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
157
+ @hide_this_step = false
158
+ if exception
159
+ if @exceptions.include?(exception)
160
+ @hide_this_step = true
161
+ return
162
+ end
163
+ @exceptions << exception
164
+ @scenario_exceptions << exception
165
+ end
166
+ if status != :failed && @in_background ^ background
167
+ @hide_this_step = true
168
+ return
169
+ end
170
+ if status == :undefined
171
+ @scenario_undefined = true
172
+ end
173
+ @status = status
174
+ end
175
+
176
+ def step_name(keyword, step_match, status, source_indent, background, file_colon_line)
177
+ return if @hide_this_step
178
+ source_indent = nil unless @options[:source]
179
+ name_to_report = format_step(keyword, step_match, status, source_indent)
180
+ @io.puts(name_to_report.indent(@scenario_indent + 2))
181
+ print_messages
182
+ end
183
+
184
+ def doc_string(string)
185
+ return if @hide_this_step
186
+ s = %{"""\n#{string}\n"""}.indent(@indent)
187
+ s = s.split("\n").map{|l| l =~ /^\s+$/ ? '' : l}.join("\n")
188
+ @io.puts(format_string(s, @current_step.status))
189
+ @io.flush
190
+ end
191
+
192
+ def exception(exception, status)
193
+ return if @hide_this_step
194
+ print_exception(exception, status, @indent)
195
+ @io.flush
196
+ end
197
+
198
+ def before_multiline_arg(multiline_arg)
199
+ return if @options[:no_multiline] || @hide_this_step
200
+ @table = multiline_arg
201
+ end
202
+
203
+ def after_multiline_arg(multiline_arg)
204
+ @table = nil
205
+ end
206
+
207
+ def before_table_row(table_row)
208
+ return if !@table || @hide_this_step
209
+ @col_index = 0
210
+ @io.print ' |'.indent(@indent-2)
211
+ end
212
+
213
+ def after_table_row(table_row)
214
+ return if !@table || @hide_this_step
215
+ print_table_row_messages
216
+ @io.puts
217
+ if table_row.exception && !@exceptions.include?(table_row.exception)
218
+ print_exception(table_row.exception, table_row.status, @indent)
219
+ end
220
+ end
221
+
222
+ def after_table_cell(cell)
223
+ return unless @table
224
+ @col_index += 1
225
+ end
226
+
227
+ def table_cell_value(value, status)
228
+ return if !@table || @hide_this_step
229
+ status ||= @status || :passed
230
+ width = @table.col_width(@col_index)
231
+ cell_text = escape_cell(value.to_s || '')
232
+ padded = cell_text + (' ' * (width - cell_text.unpack('U*').length))
233
+ prefix = cell_prefix(status)
234
+ @io.print(' ' + format_string("#{prefix}#{padded}", status) + ::Cucumber::Term::ANSIColor.reset(" |"))
235
+ @io.flush
236
+ end
237
+
238
+ def after_steps(steps)
239
+ return if @scenario_updated
240
+ result = "PASSED"
241
+ message = ''
242
+ position = @scenario_index
243
+ if not @scenario_exceptions.empty?
244
+ result = "FAILED"
245
+ message = @scenario_exceptions.inspect
246
+ @scenario_updated = true
247
+ elsif @scenario_undefined
248
+ result = "NOT_IMPL"
249
+ message = "Undefined cucumber sentence found"
250
+ @scenario_updated = true
251
+ end
252
+ if @in_background
253
+ message += " !INSIDE BACKGROUND!"
254
+ position = 1
255
+ end
256
+ resp = TarantulaUpdater.update_testcase_step(ENV["project"], ENV["execution"], @feature_name, position, result, message)
257
+ @io.puts ">>>>>>>>>>>>>>>" + resp.to_s
258
+ end
259
+
260
+ private
261
+
262
+ def print_feature_element_name(keyword, name, file_colon_line, source_indent)
263
+ @io.puts if @scenario_indent == 6
264
+ names = name.empty? ? [name] : name.split("\n")
265
+ line = "#{keyword}: #{names[0]}".indent(@scenario_indent)
266
+ @io.print(line)
267
+ if @options[:source]
268
+ line_comment = " # #{file_colon_line}".indent(source_indent)
269
+ @io.print(format_string(line_comment, :comment))
270
+ end
271
+ @io.puts
272
+ names[1..-1].each {|s| @io.puts " #{s}"}
273
+ @io.flush
274
+ end
275
+
276
+ def cell_prefix(status)
277
+ @prefixes[status]
278
+ end
279
+
280
+ def print_summary(features)
281
+ print_stats(features, @options)
282
+ print_snippets(@options)
283
+ print_passing_wip(@options)
284
+ end
285
+ end
286
+ end
287
+ end
@@ -0,0 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Cutara
3
+ class ExecutionStepError < StandardError; end
4
+ end
@@ -0,0 +1,82 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'babosa'
3
+
4
+ ROOT = Dir.pwd + "/features"
5
+ PAGES = ROOT + "/pages"
6
+ STEPS = ROOT + "/step_definitions"
7
+ SUPPORT = ROOT + "/support"
8
+ ASSETS = File.dirname(__FILE__)+"/../assets"
9
+
10
+ class String
11
+ @supported_languages = [:english,:bulgarian,:danish,:german,:greek,:macedonian,:norwegian,:romanian,:russian,:serbian,:spanish,:swedish,:ukrainian]
12
+ @@label_language = :russian
13
+
14
+ def self.label_language=(l)
15
+ raise ArgumentError, "unsupported language, supported languages: #{@supported_languages.inspect}\nmore: https://github.com/norman/babosa.git"\
16
+ unless @supported_languages.include? l
17
+ @@label_language = l
18
+ end
19
+
20
+ def self.label_language
21
+ @@label_language
22
+ end
23
+
24
+ def to_label
25
+ if String.label_language == :english
26
+ return self.to_slug.to_ruby_method.downcase
27
+ else
28
+ return self.to_slug.transliterate(String.label_language).to_ruby_method.downcase
29
+ end
30
+ end
31
+
32
+ def to_action
33
+ 'fire_'+self.to_label
34
+ end
35
+
36
+ def to_validator
37
+ 'validate_'+self.to_label
38
+ end
39
+
40
+ def to_input
41
+ 'feed_'+self.to_label
42
+ end
43
+
44
+ def to_press_action
45
+ 'press_'+self.to_label
46
+ end
47
+
48
+ def to_select
49
+ 'select_from_'+self.to_label
50
+ end
51
+
52
+ def to_each
53
+ self.to_label+'_each'
54
+ end
55
+
56
+ def to_open_subpage
57
+ self.to_label+'_open'
58
+ end
59
+
60
+ def to_params
61
+ params = {}
62
+ self.split(",").collect(&:strip).sort.each{|p|
63
+ params[p.split("=")[0].strip.to_sym] = p.split("=")[1].strip
64
+ }
65
+ params
66
+ end
67
+ end
68
+
69
+ class Dir
70
+ def recursive_each &block
71
+ self.each do |dir|
72
+ dirpath = self.path + '/' + dir
73
+ if File.directory?(dirpath) then
74
+ if dir != '.' && dir != '..' then
75
+ Dir.new(dirpath).recursive_each &block
76
+ end
77
+ else
78
+ block.call dirpath
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,62 @@
1
+ require "active_support/core_ext/hash"
2
+ require 'httparty'
3
+ require 'Helper'
4
+
5
+ class TarantulaUpdater
6
+ include HTTParty
7
+
8
+ @config = nil
9
+ # debug_output $stdout
10
+ headers 'Content-type' => 'application/xml', 'Accept' => 'application/xml'
11
+
12
+ def self.config= hash
13
+ @config = hash
14
+ end
15
+
16
+ def self.get_tests options
17
+ options = options.merge({ "language" => @config["language"] })
18
+ params = {
19
+ :basic_auth => { :username => @config["username"], :password => @config["password"] },
20
+ :body => options.to_xml(:skip_types => true, :root => "request")
21
+ }
22
+ response = self.post(@config["server"]+'/api/get_scenarios', params)
23
+ raise response.body unless response.code == 200
24
+ response
25
+ end
26
+
27
+ def self.update_testcase_step(project, execution, testcase, step_position, result, comment)
28
+ body = {
29
+ :project => project,
30
+ :execution => execution,
31
+ :testcase => testcase,
32
+ :position => step_position,
33
+ :result => result,
34
+ :comment => comment,
35
+ }.to_xml(:skip_types => true, :root => "request")
36
+
37
+ params = {
38
+ :basic_auth => { :username => @config["username"], :password => @config["password"] },
39
+ :body => body
40
+ }
41
+ response = self.post(@config["server"]+'/api/update_testcase_step', params)
42
+ raise response.body unless response.code == 200
43
+ response
44
+ end
45
+
46
+ def self.update_testcase_duration(project, execution, testcase, duration)
47
+ body = {
48
+ :project => project,
49
+ :execution => execution,
50
+ :testcase => testcase,
51
+ :duration => duration
52
+ }.to_xml(:skip_types => true, :root => "request")
53
+
54
+ params = {
55
+ :basic_auth => { :username => @config["username"], :password => @config["password"] },
56
+ :body => body
57
+ }
58
+ response = self.post(@config["server"]+'/api/update_testcase_duration', params)
59
+ raise response.body unless response.code == 200
60
+ response
61
+ end
62
+ end
@@ -0,0 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Cutara
3
+ VERSION = "0.0.1"
4
+ end
@@ -0,0 +1,43 @@
1
+ require 'TarantulaUpdater'
2
+ require 'Helper'
3
+ require "rexml/document"
4
+ include REXML
5
+ include FileUtils::Verbose
6
+
7
+ @lang = YAML.load(File.open(SUPPORT+"/tarantula.yml"))["language"] if File.exist? SUPPORT+'/tarantula.yml'
8
+ namespace "cutara" do
9
+ desc "Builds cucumber project"
10
+ task :build, [:project, :testcase, :execution] => :download do
11
+ mkdir_p(PAGES) unless File.exists?(PAGES)
12
+ mkdir_p(STEPS) unless File.exists?(STEPS)
13
+ cp "#{ASSETS}/env.rb", SUPPORT
14
+ steps_source = ASSETS + "/step_definitions/" + @lang
15
+ Dir.glob("#{steps_source}/*") {|f| cp File.expand_path(f), STEPS }
16
+ end
17
+
18
+ desc "Downloads cucumber scenarios from tarantula"
19
+ task :download, :project, :testcase, :execution do |t, args|
20
+ raise "arguments: [project*,testcase,execution]" if args.empty?
21
+
22
+ unless File.exist?(SUPPORT+"/tarantula.yml")
23
+ mkdir_p(SUPPORT) unless File.exists?(SUPPORT) # including ROOT dir
24
+ cp "#{ASSETS}/tarantula.yml", SUPPORT
25
+ raise "Please update #{SUPPORT}/tarantula.yml and rerun the task"
26
+ end
27
+ TarantulaUpdater.config = YAML.load(File.open(SUPPORT+"/tarantula.yml"))
28
+ query = {}
29
+ args.each{ |k,v| query[k.to_s]=v }
30
+ resp = TarantulaUpdater.get_tests(query)
31
+ resp = REXML::Document.new resp.body
32
+ resp.elements.each('test/test') do |test|
33
+ title = test.elements['title'].text
34
+ body = test.elements['body'].text
35
+ file = File.new(ROOT+"/#{title.to_label}.feature", "w+")
36
+ file.puts "# language: #{@lang}"
37
+ file.puts body
38
+ file.close
39
+ end
40
+ end
41
+
42
+ end
43
+