gurke 1.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e85f846008f8a50b146bf69dca846d1e7fd57549
4
+ data.tar.gz: 71265a8d33673e0df171d924be526d98aef0d2cd
5
+ SHA512:
6
+ metadata.gz: 0c010846e3ed562d0bd1c1c52abdd47c0b38e27b35913de6c4490898baee435cd3c7149483e810831c762651586b7170a883c818042b0636da63925358014259
7
+ data.tar.gz: ff7a64e2be4a0086c3a569d1c80150c07da7b1404725d9119487a37e9a8967735c3db821f2fd9091a70481aa8bf33f9c248060ccaea8ac25b26d06c7bf66cb0b
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea
19
+ *.iml
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gurke-formatters-headless.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jan Graichen
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # Gurke
2
+
3
+ **Gurke** is a highly opinionated cucumber toolkit overtaking cucumbers formatter to add webm flv video recording with headless (xvfb), multiple output formatters, global available current step and scenario and additional hooks.
4
+
5
+ Unfinished, not recommended, highly dangerous!
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'gurke'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install gurke
20
+
21
+ ## Usage
22
+
23
+ ```
24
+ require 'gurke'
25
+
26
+ require 'cucumber/formatter/pretty'
27
+ require 'cucumber/formatter/junit'
28
+ require 'gurke/formatters/headless'
29
+
30
+ class MyExternalTool < ::Gurke::Formatters::Base
31
+ def quiet?
32
+ options[:quiet]
33
+ end
34
+
35
+ def before_features(features)
36
+ puts 'BUUUH!' unless quiet?
37
+ end
38
+ end
39
+
40
+ Gurke::Formatter.config do
41
+ use Cucumber::Formatter::Pretty
42
+ use Cucumber::Formatter::JUnit
43
+ use MyExternalTool, quiet: true
44
+ use Gurke::Formatters::Headless, dir: 'report/html', recording: true, record_all: true
45
+ end
46
+ ```
47
+
48
+ ```
49
+ Gurke.current.step
50
+ Gurke.current.scenario
51
+
52
+ Gurke.before :features do |*args|
53
+ # ...
54
+ end
55
+
56
+ Gurke.before :feature_element do |*args|
57
+ # ...
58
+ end
59
+
60
+ Gurke.after :step_result do |*args|
61
+ # ...
62
+ end
63
+
64
+ #...
65
+
66
+ ```
67
+
68
+ ## TODO
69
+
70
+ * Headless Dir & HTML Template
71
+
72
+ ## Contributing
73
+
74
+ Don't even think about it.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/gurke.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'gurke'
7
+ spec.version = '1.0.0'
8
+ spec.authors = ['Jan Graichen']
9
+ spec.email = %w(jg@altimos.de)
10
+ spec.description = %q{A description}
11
+ spec.summary = %q{A summary}
12
+ spec.homepage = 'https://github.com/jgraichen/gurke'
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = %w(lib)
19
+
20
+ spec.add_dependency 'cucumber'
21
+ spec.add_dependency 'activesupport'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.3'
24
+ spec.add_development_dependency 'rake'
25
+ end
@@ -0,0 +1,31 @@
1
+ module Gurke
2
+ class Current
3
+ attr_accessor :scenario, :step
4
+
5
+ class << self
6
+ def instance
7
+ @instance ||= new
8
+ end
9
+
10
+ def scenario
11
+ instance.scenario
12
+ end
13
+
14
+ def step
15
+ instance.step
16
+ end
17
+ end
18
+
19
+ class Formatter < Gurke::Formatters::Base
20
+ def before_scenario(scenario)
21
+ Current.instance.scenario = scenario
22
+ end
23
+
24
+ def before_step(step)
25
+ Current.instance.step = step
26
+ end
27
+ end
28
+
29
+ ::Gurke::Formatter.use Formatter
30
+ end
31
+ end
@@ -0,0 +1,177 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+ require 'gurke/formatters/base'
3
+
4
+ module Gurke
5
+ class Formatter
6
+ attr_reader :runtime, :options
7
+ attr_reader :current_feature, :current_step
8
+
9
+ def initialize(runtime, path_or_io, options)
10
+ @runtime, @path_or_io, @options = runtime, path_or_io, options
11
+
12
+ self.class.formatters.each do |klass, opts|
13
+ if klass.respond_to?(:gurkig?) && klass.gurkig?
14
+ formatters << klass.new(self, opts)
15
+ else
16
+ legacy << klass.new(runtime, path_or_io, options)
17
+ end
18
+ end
19
+
20
+ self.class.instance = self
21
+ end
22
+
23
+ def formatters
24
+ @formatters ||= []
25
+ end
26
+
27
+ def legacy
28
+ @legacy ||= []
29
+ end
30
+
31
+ ## -- Before callbacks --
32
+
33
+ def before_features(features)
34
+ invoke :before, :features, [features]
35
+ end
36
+
37
+ def before_feature(feature)
38
+ invoke :before, :feature, [feature]
39
+ end
40
+
41
+ def before_tags(tags)
42
+ invoke :before, :tags, [tags]
43
+ end
44
+
45
+ def before_background(background)
46
+ invoke :before, :background, [background]
47
+ end
48
+
49
+ def before_steps(steps)
50
+ invoke :before, :steps, [steps]
51
+ end
52
+
53
+ def before_step(step)
54
+ invoke :before, :step, [step]
55
+ end
56
+
57
+ def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
58
+ invoke :before, :step_result, [keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line]
59
+ end
60
+
61
+ def before_feature_element(element)
62
+ invoke :before, :feature_element, [element]
63
+ invoke :before, :scenario, args: [element]
64
+ end
65
+
66
+ ## -- Element callbacks --
67
+
68
+ def manual_step(step, opts)
69
+ invoke nil, :manual_step, args: [step, opts]
70
+ end
71
+
72
+ def feature_name(name, description)
73
+ invoke nil, :feature_name, [name, description]
74
+ end
75
+
76
+ def tag_name(name)
77
+ invoke nil, :tag_name, [name]
78
+ end
79
+
80
+ def background_name(keyword, name, file_colon_line, source_indent)
81
+ invoke nil, :background_name, [keyword, name, file_colon_line, source_indent]
82
+ end
83
+
84
+ def scenario_name(keyword, name, file_colon_line, source_indent)
85
+ invoke nil, :scenario_name, [keyword, name, file_colon_line, source_indent]
86
+ end
87
+
88
+ def step_name(keyword, step_match, status, source_indent, background, file_colon_line)
89
+ invoke nil, :step_name, [keyword, step_match, status, source_indent, background, file_colon_line]
90
+ end
91
+
92
+ def exception(exception, status)
93
+ invoke nil, :exception, [exception, status]
94
+ end
95
+
96
+ ## -- After callbacks --
97
+
98
+ def after_feature_element(element)
99
+ invoke :after, :feature_element, [element]
100
+ invoke :before, :scenario, args: [element]
101
+ end
102
+
103
+ def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
104
+ invoke :after, :step_result, [keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line]
105
+ end
106
+
107
+ def after_step(step)
108
+ invoke :after, :step, [step]
109
+ end
110
+
111
+ def after_steps(steps)
112
+ invoke :after, :steps, [steps]
113
+ end
114
+
115
+ def after_background(background)
116
+ invoke :after, :background, [background]
117
+ end
118
+
119
+ def after_tags(tags)
120
+ invoke :after, :tags, [tags]
121
+ end
122
+
123
+ def after_feature(feature)
124
+ invoke :after, :feature, [feature]
125
+ end
126
+
127
+ def after_features(features)
128
+ invoke :after, :features, [features]
129
+ end
130
+
131
+ private
132
+ def invoke(type, name, args = {})
133
+ args = { args: args, legacy: args } if Array === args
134
+
135
+ if args[:args]
136
+ (type == :after ? formatters.reverse : formatters).each do |fmt|
137
+ mth = type.nil? ? name : "#{type}_#{name}"
138
+ fmt.send mth, *args[:args] if fmt.respond_to? mth
139
+ end
140
+ end
141
+
142
+ if args[:legacy]
143
+ legacy.each do |fmt|
144
+ mth = type.nil? ? name : "#{type}_#{name}"
145
+ fmt.send mth, *args[:legacy] if fmt.respond_to? mth
146
+ end
147
+ end
148
+ end
149
+
150
+ class << self
151
+ attr_reader :legacy_formatter
152
+ attr_accessor :instance
153
+
154
+ def formatters
155
+ @formatters ||= {}
156
+ end
157
+
158
+ def config(&block)
159
+ instance_eval &block
160
+ end
161
+
162
+ def use(formatter, options = {})
163
+ klass = lookup_formatter(formatter)
164
+ raise InvalidArgument.new 'Cannot find formatters `#{formatters}\'.' unless klass
165
+
166
+ formatters[klass] = options
167
+ end
168
+
169
+ private
170
+ def lookup_formatter(formatter)
171
+ return formatter if formatter.is_a? Class
172
+ formatter.camelize.safe_constantize
173
+ end
174
+ end
175
+ end
176
+ end
177
+
@@ -0,0 +1,17 @@
1
+ module Gurke
2
+ module Formatters
3
+ class Base
4
+ attr_reader :main, :options
5
+
6
+ def initialize(main, options)
7
+ @main, @options = main, options
8
+ end
9
+
10
+ class << self
11
+ def gurkig?
12
+ true
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,97 @@
1
+ require 'fileutils'
2
+ require 'headless'
3
+
4
+ module Gurke
5
+ module Formatters
6
+ class Headless < Base
7
+ attr_reader :tmpdir
8
+
9
+ def initialize(*args)
10
+ super
11
+
12
+ @tmpdir = options.delete(:tmpdir) { |el| Dir.mktmpdir }
13
+ @headless = ::Headless.new video: video_options
14
+ @index = 0
15
+ end
16
+
17
+ def video_options
18
+ {
19
+ codec: 'libvpx',
20
+ log_file_path: File.join(tmpdir, 'ffmpeg.log'),
21
+ tmp_file_path: File.join(tmpdir, 'ffmpeg.tmp.webm')
22
+ }
23
+ end
24
+
25
+ def dir
26
+ File.mkdir
27
+ end
28
+
29
+ def recording?
30
+ !!options[:recording]
31
+ end
32
+
33
+ def record_all?
34
+ !!options[:record_all]
35
+ end
36
+
37
+ # -- Start / Stop --
38
+
39
+ def before_features(features)
40
+ @headless.start
41
+ at_exit { destroy }
42
+ end
43
+
44
+ def after_features(features)
45
+ destroy
46
+
47
+ # TODO: Dir / Template / Whatever - just test atm
48
+ end
49
+
50
+ # -- Intercept scenarios --
51
+
52
+ def before_feature_element(scenario)
53
+ if recording?
54
+ @headless.video.start_capture
55
+ end
56
+ end
57
+
58
+ def after_feature_element(scenario)
59
+ if recording?
60
+ if scenario.failed? || record_all?
61
+ # TODO: Dir / Template / Whatever - just test atm
62
+ file = File.join('report', "#{scenario.name}.flv")
63
+ @headless.video.stop_and_save file
64
+ else
65
+ @headless.video.stop_and_discard
66
+ end
67
+ end
68
+
69
+ # TODO: Dir / Template / Whatever - just test atm
70
+ end
71
+
72
+ # -- Intercept steps --
73
+
74
+ def manual_step(step, opts)
75
+ take_sceenshot step
76
+ end
77
+
78
+ def after_step(step)
79
+ take_sceenshot step
80
+ end
81
+
82
+ private
83
+ def destroy
84
+ @headless.destroy if @headless
85
+ end
86
+
87
+ def take_sceenshot(step)
88
+ return if step.background?
89
+
90
+ filename = "#{step.keyword}#{step.name}".downcase.gsub(/[^A-z0-9]+/, '_')
91
+
92
+ # TODO: Dir / Template / Whatever - just test atm
93
+ @headless.take_screenshot "report/#{@index += 1}_#{filename}.png"
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,42 @@
1
+ module Gurke
2
+ class Hooks
3
+ attr_reader :hooks
4
+
5
+ def initialize
6
+ @hooks = {}
7
+ end
8
+
9
+ def add(target, &block)
10
+ target.to_s.tap do |target|
11
+ hooks[target] ||= []
12
+ hooks[target] << block
13
+ end
14
+ end
15
+
16
+ def invoke(target, *args)
17
+ return unless hooks[target]
18
+
19
+ hooks[target].each do |hook|
20
+ hook.call *args
21
+ end
22
+ end
23
+
24
+ class << self
25
+ def before; @before ||= new end
26
+ def after; @after ||= new end
27
+ end
28
+
29
+ class Formatter < Formatters::Base
30
+ %w(features feature scenario step).each do |name|
31
+ define_method "before_#{name}" do |*args|
32
+ Hooks.before.invoke name, *args
33
+ end
34
+ define_method "after_#{name}" do |*args|
35
+ Hooks.after.invoke name, *args
36
+ end
37
+ end
38
+ end
39
+
40
+ ::Gurke::Formatter.use Formatter
41
+ end
42
+ end
@@ -0,0 +1,16 @@
1
+ # Patch configuration to always use
2
+ module Cucumber
3
+ module Cli
4
+ class Configuration
5
+ alias_method :orig_formatter_class, :formatter_class
6
+ def formatter_class(format)
7
+ unless @__gurke_original_formatter_registered
8
+ ::Gurke::Formatter.use orig_formatter_class(format)
9
+ @__gurke_original_formatter_registered = true
10
+ end
11
+
12
+ ::Gurke::Formatter
13
+ end
14
+ end
15
+ end
16
+ end
data/lib/gurke.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'cucumber'
2
+
3
+ require 'gurke/patch/cucumber_cli_configuration'
4
+ require 'gurke/formatter'
5
+
6
+ require 'gurke/current'
7
+ require 'gurke/hooks'
8
+
9
+
10
+ module Gurke
11
+ class << self
12
+ def current
13
+ @current ||= Gurke::Current.instance
14
+ end
15
+
16
+ def before(stage, &block)
17
+ Hooks.before.add stage, &block
18
+ end
19
+
20
+ def after(stage, &block)
21
+ Hooks.after.add stage, &block
22
+ end
23
+
24
+ def step!(opts = {})
25
+ if (fmt = Gurke::Formatter.instance)
26
+ fmt.manual_step current.step, opts
27
+ end
28
+ end
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gurke
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jan Graichen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cucumber
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A description
70
+ email:
71
+ - jg@altimos.de
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - gurke.gemspec
82
+ - lib/gurke.rb
83
+ - lib/gurke/current.rb
84
+ - lib/gurke/formatter.rb
85
+ - lib/gurke/formatters/base.rb
86
+ - lib/gurke/formatters/headless.rb
87
+ - lib/gurke/hooks.rb
88
+ - lib/gurke/patch/cucumber_cli_configuration.rb
89
+ homepage: https://github.com/jgraichen/gurke
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.1.11
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: A summary
113
+ test_files: []