gurke 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []