lapis_lazuli 0.6.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 (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +42 -0
  5. data/LICENSE +30 -0
  6. data/README.md +74 -0
  7. data/Rakefile +1 -0
  8. data/bin/lapis_lazuli +3 -0
  9. data/lapis_lazuli.gemspec +32 -0
  10. data/lib/lapis_lazuli/api.rb +52 -0
  11. data/lib/lapis_lazuli/argparse.rb +128 -0
  12. data/lib/lapis_lazuli/ast.rb +160 -0
  13. data/lib/lapis_lazuli/browser/error.rb +93 -0
  14. data/lib/lapis_lazuli/browser/find.rb +500 -0
  15. data/lib/lapis_lazuli/browser/interaction.rb +91 -0
  16. data/lib/lapis_lazuli/browser/screenshots.rb +70 -0
  17. data/lib/lapis_lazuli/browser/wait.rb +158 -0
  18. data/lib/lapis_lazuli/browser.rb +246 -0
  19. data/lib/lapis_lazuli/cli.rb +110 -0
  20. data/lib/lapis_lazuli/cucumber.rb +25 -0
  21. data/lib/lapis_lazuli/generators/cucumber/template/.gitignore +6 -0
  22. data/lib/lapis_lazuli/generators/cucumber/template/Gemfile +37 -0
  23. data/lib/lapis_lazuli/generators/cucumber/template/README.md +27 -0
  24. data/lib/lapis_lazuli/generators/cucumber/template/config/config.yml +29 -0
  25. data/lib/lapis_lazuli/generators/cucumber/template/config/cucumber.yml +34 -0
  26. data/lib/lapis_lazuli/generators/cucumber/template/features/example.feature +11 -0
  27. data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/interaction_steps.rb +20 -0
  28. data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/validation_steps.rb +21 -0
  29. data/lib/lapis_lazuli/generators/cucumber/template/features/support/env.rb +12 -0
  30. data/lib/lapis_lazuli/generators/cucumber/template/features/support/transition.rb +12 -0
  31. data/lib/lapis_lazuli/generators/cucumber.rb +128 -0
  32. data/lib/lapis_lazuli/generic/xpath.rb +49 -0
  33. data/lib/lapis_lazuli/options.rb +28 -0
  34. data/lib/lapis_lazuli/placeholders.rb +36 -0
  35. data/lib/lapis_lazuli/proxy.rb +179 -0
  36. data/lib/lapis_lazuli/runtime.rb +88 -0
  37. data/lib/lapis_lazuli/scenario.rb +88 -0
  38. data/lib/lapis_lazuli/storage.rb +59 -0
  39. data/lib/lapis_lazuli/version.rb +10 -0
  40. data/lib/lapis_lazuli/versions.rb +40 -0
  41. data/lib/lapis_lazuli/world/annotate.rb +45 -0
  42. data/lib/lapis_lazuli/world/api.rb +35 -0
  43. data/lib/lapis_lazuli/world/browser.rb +75 -0
  44. data/lib/lapis_lazuli/world/config.rb +292 -0
  45. data/lib/lapis_lazuli/world/error.rb +141 -0
  46. data/lib/lapis_lazuli/world/hooks.rb +109 -0
  47. data/lib/lapis_lazuli/world/logging.rb +53 -0
  48. data/lib/lapis_lazuli/world/proxy.rb +59 -0
  49. data/lib/lapis_lazuli/world/variable.rb +139 -0
  50. data/lib/lapis_lazuli.rb +75 -0
  51. data/test/.gitignore +8 -0
  52. data/test/Gemfile +42 -0
  53. data/test/README.md +35 -0
  54. data/test/config/config.yml +37 -0
  55. data/test/config/cucumber.yml +37 -0
  56. data/test/features/annotation.feature +23 -0
  57. data/test/features/browser.feature +10 -0
  58. data/test/features/button.feature +38 -0
  59. data/test/features/click.feature +35 -0
  60. data/test/features/error.feature +30 -0
  61. data/test/features/find.feature +92 -0
  62. data/test/features/har.feature +9 -0
  63. data/test/features/modules.feature +14 -0
  64. data/test/features/step_definitions/interaction_steps.rb +154 -0
  65. data/test/features/step_definitions/validation_steps.rb +350 -0
  66. data/test/features/support/env.rb +21 -0
  67. data/test/features/text_field.feature +32 -0
  68. data/test/features/timing.feature +47 -0
  69. data/test/features/variable.feature +11 -0
  70. data/test/features/xpath.feature +41 -0
  71. data/test/server/start.rb +17 -0
  72. data/test/server/www/button.html +22 -0
  73. data/test/server/www/error_html.html +9 -0
  74. data/test/server/www/find.html +66 -0
  75. data/test/server/www/javascript_error.html +12 -0
  76. data/test/server/www/text_fields.html +15 -0
  77. data/test/server/www/timing.html +32 -0
  78. data/test/server/www/xpath.html +22 -0
  79. metadata +295 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b2a6cfbdb61af45b8f71d55cc4c1dbf39b4b93e8
4
+ data.tar.gz: 1bc6137ed31303b449740f200f34d10d750f9185
5
+ SHA512:
6
+ metadata.gz: da0360f61b3574674db6af2e43c4fab53b6ab66ff58d01c2632ad1b063357f8db6f24bbfb5ce1d07eaa9f04fc7a5a65e154c65ceb69269880ecd48af6ee9dd38
7
+ data.tar.gz: 3b70d1935eed1f0a9bc00d237c3e3ec158aaeacf670b2a2a453ad43beeab60283b3511e289b4322572bd66781b5fd30e86553356ea1d97e5f71265c15a1fdfff
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ InstalledFiles
7
+ _yardoc
8
+ coverage
9
+ doc/
10
+ lib/bundler/man
11
+ bundle
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ tmp
16
+ .ruby-version
17
+ test/storage
18
+ .*.sw*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in spritecuke.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,42 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ lapis_lazuli (0.6.1)
5
+ facets (~> 2.9)
6
+ faraday (~> 0.9.0)
7
+ faraday_middleware (~> 0.9.1)
8
+ json (~> 1.8.1)
9
+ multi_xml (~> 0.5.5)
10
+ teelogger (~> 0.3.0)
11
+ thor (~> 0.19)
12
+
13
+ GEM
14
+ remote: https://rubygems.org/
15
+ specs:
16
+ docile (1.1.5)
17
+ facets (2.9.3)
18
+ faraday (0.9.1)
19
+ multipart-post (>= 1.2, < 3)
20
+ faraday_middleware (0.9.1)
21
+ faraday (>= 0.7.4, < 0.10)
22
+ json (1.8.2)
23
+ multi_json (1.11.0)
24
+ multi_xml (0.5.5)
25
+ multipart-post (2.0.0)
26
+ rake (10.4.2)
27
+ simplecov (0.9.2)
28
+ docile (~> 1.1.0)
29
+ multi_json (~> 1.0)
30
+ simplecov-html (~> 0.9.0)
31
+ simplecov-html (0.9.0)
32
+ teelogger (0.3.0)
33
+ thor (0.19.1)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ bundler (~> 1.6)
40
+ lapis_lazuli!
41
+ rake
42
+ simplecov
data/LICENSE ADDED
@@ -0,0 +1,30 @@
1
+ Copyright spriteCloud B.V. (http://www.spritecloud.com/) and other LapisLazuli
2
+ contributors. All rights not covered below are reserved.
3
+
4
+ MIT +no-false-attribs License
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to
8
+ deal in the Software without restriction, including without limitation the
9
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
+ sell copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ Distributions of all or part of the Software intended to be used by the
17
+ recipients as they would use the unmodified Software, containing modifications
18
+ that substantially alter, remove, or disable functionality of the Software,
19
+ outside of the documented configuration mechanisms provided by the Software,
20
+ shall be modified such that the Original Author's bug reporting email addresses
21
+ and urls are either replaced with the contact information of the parties
22
+ responsible for the changes, or removed entirely.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30
+ IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # Lapis Lazuli
2
+
3
+ LapisLazuli provides cucumber helper functions and scaffolding for easier (web)
4
+ test automation suite development.
5
+
6
+ A lot of functionality is aimed at dealing better with [Watir](http://watir.com/),
7
+ such as:
8
+
9
+ - Easier/more reliable find and wait functionality for detecting web page elements.
10
+ - Easier browser handling
11
+ - Better error handling
12
+ - etc.
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'lapis_lazuli'
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ ```bash
25
+ $ bundle
26
+ ```
27
+
28
+ Or install it yourself as:
29
+
30
+ ```bash
31
+ $ gem install lapis_lazuli
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ The Lapis Lazuli project has two main purposes:
37
+
38
+ - Provide a repository of common test functions for test automation engineers.
39
+ - Make it easy to get started on a test automation project with these test
40
+ functions.
41
+
42
+ The first goal is fulfilled by the Lapis Lazuli module itself, which can be
43
+ imported in any cucumber project like this:
44
+
45
+ ```ruby
46
+ require 'lapis_lazuli'
47
+ World(LapisLazuli)
48
+ ```
49
+
50
+ All of Lapis Lazuli's helper functions will be available in your step definitions
51
+ then. However, you won't need to do this if you create a new Lapis Lazuli project.
52
+ Simple run:
53
+
54
+ ```bash
55
+ $ lapis_lazuli create <projectpath>
56
+ ```
57
+
58
+ And a cucumber project will be set up for you in the given path. The last path
59
+ name component will be considered the project name, so e.g. a path of
60
+ `projects/for_client/website1` will mean the project's name is going to be
61
+ `website1`.
62
+
63
+ Change to that newly created project directory and read the README.md file there
64
+ for further instructions.
65
+
66
+ Be sure to read [the Wiki](https://github.com/spriteCloud/lapis-lazuli/wiki) for
67
+ further documentation.
68
+
69
+ ## Contributing
70
+
71
+ Please see [the Wiki page on contributing](https://github.com/spriteCloud/lapis-lazuli/wiki/Contributing)
72
+
73
+ ## License
74
+ Copyright (c) 2013-2015 spriteCloud B.V. and other node-apinator contributors. See [the LICENSE file](LICENSE) for details.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/lapis_lazuli ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'lapis_lazuli/cli'
3
+ LapisLazuli::CLI.start
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lapis_lazuli/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "lapis_lazuli"
8
+ spec.version = LapisLazuli::VERSION
9
+ spec.authors = ["Onno Steenbergen", "Gijs Paulides", "Mark Barzilay", "Jens Finkhaeuser"]
10
+ spec.email = ["foss@spritecloud.com"]
11
+ spec.description = %q{Cucumber helper functions and scaffolding for easier test automation suite development.}
12
+ spec.summary = %q{Cucumber helper functions and scaffolding for easier test automation suite development.}
13
+ spec.homepage = "https://github.com/spriteCloud/lapis-lazuli"
14
+ spec.license = "MITNFA"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "simplecov"
24
+
25
+ spec.add_dependency "thor", "~> 0.19"
26
+ spec.add_dependency "facets", "~> 2.9"
27
+ spec.add_dependency "json", "~> 1.8.1"
28
+ spec.add_dependency "faraday", "~> 0.9.0"
29
+ spec.add_dependency "faraday_middleware", "~> 0.9.1"
30
+ spec.add_dependency "multi_xml", "~> 0.5.5"
31
+ spec.add_dependency "teelogger", "~> 0.3.0"
32
+ end
@@ -0,0 +1,52 @@
1
+ #
2
+ # LapisLazuli
3
+ # https://github.com/spriteCloud/lapis-lazuli
4
+ #
5
+ # Copyright (c) 2013-2014 spriteCloud B.V. and other LapisLazuli contributors.
6
+ # All rights reserved.
7
+ #
8
+
9
+ require "faraday"
10
+ require "faraday_middleware"
11
+ require "multi_xml"
12
+
13
+ module LapisLazuli
14
+ ##
15
+ # Proxy class to map to sc-proxy
16
+ class API
17
+ attr_reader :conn
18
+ def initialize()
19
+ end
20
+
21
+ def set_conn(url, options=nil, &block)
22
+ block = block_given? ? block : Proc.new do |conn|
23
+ conn.response :xml, :content_type => /\bxml$/
24
+ conn.response :json, :content_type => /\bjson$/
25
+
26
+ conn.adapter Faraday.default_adapter
27
+ end
28
+ @conn = Faraday.new(url, options, &block)
29
+ end
30
+
31
+ ##
32
+ # Map any missing method to the conn object or Faraday
33
+ def respond_to?(meth)
34
+ if !@conn.nil? and @conn.respond_to? meth
35
+ return true
36
+ end
37
+ return super
38
+ end
39
+
40
+ def method_missing(meth, *args, &block)
41
+ if !@conn.nil? and @conn.respond_to? meth
42
+ return @conn.send(meth.to_s, *args, &block)
43
+ end
44
+
45
+ begin
46
+ return Faraday.send(meth.to_s, *args, &block)
47
+ rescue NoMethodError
48
+ return super
49
+ end
50
+ end
51
+ end # class API
52
+ end # module LapisLazuli
@@ -0,0 +1,128 @@
1
+ #
2
+ # LapisLazuli
3
+ # https://github.com/spriteCloud/lapis-lazuli
4
+ #
5
+ # Copyright (c) 2013-2014 spriteCloud B.V. and other LapisLazuli contributors.
6
+ # All rights reserved.
7
+ #
8
+
9
+ require 'test/unit/assertions'
10
+
11
+ module LapisLazuli
12
+
13
+ ##
14
+ # Simple module that helps with function argument parsing.
15
+ module ArgParse
16
+ # Error related options.
17
+ ERROR_OPTIONS = {
18
+ :exception => nil,
19
+ :message => nil,
20
+ :groups => nil,
21
+ }
22
+
23
+ ##
24
+ # Parses its arguments, returning an options hash. Use it in a function that
25
+ # just accepts *args to handle both a single hash argument and a list of
26
+ # arguments:
27
+ #
28
+ # Example:
29
+ # def foo(*args)
30
+ # defaults = {}
31
+ # options = parse_args(defaults, "bar", *args)
32
+ # end
33
+ #
34
+ # The function essentially handles three distinct cases:
35
+ # 1. The arguments are a list:
36
+ # foo(1, 2)
37
+ # -> {"bar" => [1, 2]} merged with defaults
38
+ # 2. The first argument is a hash, and it contains "bar":
39
+ # foo(:x => 1, "bar" => [1, 2])
40
+ # -> {:x => 1, "bar" => [1, 2]} merged with defaults
41
+ # 3. The first argument is a hash and it does not contain "bar"
42
+ # foo(:x => 1)
43
+ # -> {"bar" => [{:x => 1}]} merged with defaults
44
+ #
45
+ # Either option ensures that the second parameter "bar" exists and is an
46
+ # array. Also, all defaults are merged into the options hash.
47
+ def parse_args(defaults, list, *args)
48
+ options = {}
49
+
50
+ # If we have a single hash argument, we'll treat it as defaults, and expect
51
+ # the list field to be an Array
52
+ if 1 == args.length and args[0].is_a? Hash
53
+ tmp = args[0]
54
+
55
+ if tmp.has_key? list
56
+ # Assert that the list argument is a list. Duh.
57
+ assert tmp[list].is_a?(Array), "Need to provide an Array for #{list}."
58
+
59
+ # Merge defaults
60
+ tmp = defaults.merge tmp
61
+
62
+ options = tmp
63
+ else
64
+ # No list means that we only have a single argument, which
65
+ # is meant to be the single list item. Any option with defaults
66
+ # must be taken from tmp, if it exists there.
67
+ options = defaults
68
+ tmp.each do |k, v|
69
+ if options.has_key? k
70
+ options[k] = tmp[k]
71
+ tmp.delete(k)
72
+ end
73
+ end
74
+ options[list] = [tmp]
75
+ end
76
+
77
+ else
78
+ options = defaults
79
+ options[list] = args
80
+ end
81
+
82
+ # Finally, prune options: remove all nil values
83
+ options.each do |k, v|
84
+ if v.nil?
85
+ options.delete k
86
+ end
87
+ end
88
+
89
+ return options
90
+ end
91
+
92
+
93
+ ##
94
+ # Simple way for dealing with an argument that can be either a list, or a
95
+ # single item: we distinguish based on whether the argument responds to 'each'.
96
+ # If the optional 'flatten' parameter is given, nested lists will also be
97
+ # flattened.
98
+ def make_list_from_item(item, flatten = false)
99
+ res = []
100
+ if item.respond_to?('each')
101
+ item.each do |e|
102
+ if flatten
103
+ res << make_list_from_item(e)
104
+ else
105
+ res << e
106
+ end
107
+ end
108
+ else
109
+ res << item
110
+ end
111
+ return res
112
+ end
113
+
114
+
115
+ ##
116
+ # Using make_list_from_item, apply the logic to all of an array. It
117
+ # effectively flattens nested arrays, if necessary, and does so
118
+ # recursively if the flatten parameter is true.
119
+ def make_list_from_nested(list, flatten = false)
120
+ all = []
121
+ list.each do |item|
122
+ all.concat(make_list_from_item(item, flatten))
123
+ end
124
+ return all
125
+ end
126
+
127
+ end # module ArgParse
128
+ end # module LapisLazuli
@@ -0,0 +1,160 @@
1
+ #
2
+ # LapisLazuli
3
+ # https://github.com/spriteCloud/lapis-lazuli
4
+ #
5
+ # Copyright (c) 2015 spriteCloud B.V. and other LapisLazuli contributors.
6
+ # All rights reserved.
7
+ #
8
+
9
+ # Hack for cucumber 2.0.x
10
+ begin
11
+ module Cucumber
12
+ module Core
13
+ module Ast
14
+ class ExamplesTable
15
+ public :example_rows
16
+ end # ExamplesTable
17
+ end # Ast
18
+ end # Core
19
+ end # Cucumber
20
+ rescue NameError
21
+ # Not cucumber 2.0.x
22
+ end
23
+
24
+
25
+ module LapisLazuli
26
+ ##
27
+ # Convenience module for dealing with aspects of the cucumber AST. From
28
+ # version 1.3.x to version 2.0.x, some changes were introduced here.
29
+ module Ast
30
+ ##
31
+ # Return a unique and human parsable ID for scenarios
32
+ def scenario_id(scenario)
33
+ # For 2.0.x, the best scenario ID is one prefixed by the file name + line
34
+ # number, followed by the feature name, scenario name, and table data (if
35
+ # applicable).
36
+ if is_cucumber_2?(scenario)
37
+ id = [scenario.location.to_s]
38
+ for i in 0 .. scenario.source.length - 1 do
39
+ part = scenario.source[i]
40
+ if part.respond_to?(:name)
41
+ id << part.name
42
+ elsif part.is_a?(Cucumber::Core::Ast::ExamplesTable::Row)
43
+ id << part.values.join("|")
44
+ end
45
+ end
46
+ return id
47
+ end
48
+
49
+ case scenario
50
+ when Cucumber::Ast::Scenario
51
+ return [
52
+ scenario.feature.file,
53
+ scenario.name
54
+ ]
55
+ when Cucumber::Ast::OutlineTable::ExampleRow
56
+ return [
57
+ scenario.scenario_outline.feature.file,
58
+ scenario.scenario_outline.name,
59
+ scenario.name
60
+ ]
61
+ end
62
+ end
63
+
64
+
65
+ ##
66
+ # Tests whether the given scenario object indicates we're using cucumber 2.x
67
+ def is_cucumber_2?(scenario)
68
+ begin
69
+ # The assumption - FIXME perhaps wrong - is that cucumber 1.3.x does not
70
+ # have this source array.
71
+ return (scenario.respond_to?(:source) and scenario.source.is_a?(Array))
72
+ rescue
73
+ return false
74
+ end
75
+ end
76
+
77
+
78
+ ##
79
+ # Tests whether the scenario object is a single scenario
80
+ def is_scenario?(scenario)
81
+ begin
82
+ # 1.3.x
83
+ return scenario.class == Cucumber::Ast::Scenario
84
+ rescue
85
+ # 2.0.x - everything is a Cucumber::Core::Test::Case
86
+ return (not scenario.outline?)
87
+ end
88
+ end
89
+
90
+
91
+ ##
92
+ # Tests whether the scenario object is a table row
93
+ def is_table_row?(scenario)
94
+ begin
95
+ # 1.3.x
96
+ return scenario.class == Cucumber::Ast::OutlineTable::ExampleRow
97
+ rescue
98
+ # 2.0.x - everything is a Cucumber::Core::Test::Case
99
+ return scenario.outline?
100
+ end
101
+ end
102
+
103
+
104
+ ##
105
+ # Tests whether this scenario is the last scenario of a feature
106
+ def is_last_scenario?(scenario)
107
+ if is_scenario?(scenario)
108
+ begin
109
+ # 2.0.x
110
+ return (scenario.feature.feature_elements.last.location == scenario.location)
111
+ rescue
112
+ # 1.3.x
113
+ return (scenario.feature.feature_elements.last == scenario)
114
+ end
115
+
116
+ elsif is_table_row?(scenario)
117
+ begin
118
+ # 2.0.x
119
+
120
+ # We can bail early if this scenario's line is < the last feature
121
+ # element's line
122
+ outline = scenario.feature.feature_elements.last
123
+ if scenario.source.last.location.line < outline.location.line
124
+ return false
125
+ end
126
+
127
+ # Now the last feature element needs to be an outline - this is a
128
+ # sanity check that makes later stuff easier
129
+ if not outline.respond_to? :examples_tables
130
+ return false
131
+ end
132
+
133
+ # The last row of the last examples tables is what we care about
134
+ last_row = outline.examples_tables.last.example_rows.last
135
+
136
+ # If the current scenario has the same location as the last example,
137
+ # then we're the last scenario.
138
+ return scenario.source.last.location.line == last_row.location.line
139
+
140
+ rescue
141
+ # 1.3.x
142
+ if scenario.scenario_outline.feature.feature_elements.last == scenario.scenario_outline
143
+ # And is this the last example in the table?
144
+ is_last_example = false
145
+ scenario.scenario_outline.each_example_row do |row|
146
+ if row == scenario
147
+ is_last_example = true
148
+ else
149
+ # Overwrite this again with 'false'
150
+ is_last_example = false
151
+ end
152
+ end
153
+ return is_last_example
154
+ end
155
+ end
156
+ end
157
+ raise "If you see this error it might indicate you're running an unsupported version of cucumber"
158
+ end
159
+ end # module Ast
160
+ end # module LapisLazuli
@@ -0,0 +1,93 @@
1
+ #
2
+ # LapisLazuli
3
+ # https://github.com/spriteCloud/lapis-lazuli
4
+ #
5
+ # Copyright (c) 2013-2014 spriteCloud B.V. and other LapisLazuli contributors.
6
+ # All rights reserved.
7
+ #
8
+
9
+ module LapisLazuli
10
+ module BrowserModule
11
+
12
+ ##
13
+ # Module with error handling related functionality (World)
14
+ module Error
15
+ ##
16
+ # Does this page have errors?
17
+ # Checks the pagetext for error_strings that are specified in the config
18
+ def has_error?
19
+ errors = self.get_html_errors
20
+ js_errors = self.get_js_errors
21
+ if not js_errors.nil?
22
+ errors += js_errors
23
+ end
24
+
25
+ if errors.length > 0 or self.get_http_status.to_i > 299
26
+ errors.each do |error|
27
+ if error.is_a? Hash
28
+ @world.log.debug("#{error["message"]} #{error["url"]} #{error["line"]} #{error["column"]}\n#{error["stack"]}")
29
+ else
30
+ @world.log.debug("#{error}")
31
+ end
32
+ end
33
+ return true
34
+ end
35
+ return false
36
+ end
37
+
38
+
39
+ ##
40
+ # Retrieve errors from HTML elements, using the error_strings config
41
+ # variable
42
+ def get_html_errors
43
+ result = []
44
+ # Need some error strings
45
+ if @world.has_env_or_config?("error_strings")
46
+ begin
47
+ # Get the HTML of the page
48
+ page_text = @browser.html
49
+ # Try to find all errors
50
+ @world.env_or_config("error_strings").each {|error|
51
+ if page_text.include? error
52
+ # Add to the result list
53
+ result.push error
54
+ end
55
+ }
56
+ rescue RuntimeError => err
57
+ # An error?
58
+ @world.log.debug "Cannot read the html for page #{@browser.url}: #{err}"
59
+ end
60
+ end
61
+ # By default we don't have errors
62
+ return result
63
+ end
64
+
65
+
66
+ ##
67
+ # If the proxy is supported, use it to retrieve JS errors.
68
+ def get_js_errors
69
+ return self.browser.execute_script <<-JS
70
+ try {
71
+ return lapis_lazuli.errors;
72
+ } catch(err){
73
+ return null;
74
+ }
75
+ JS
76
+ end
77
+
78
+
79
+ ##
80
+ # If the proxy is supported, use it get the HTTP status code.
81
+ def get_http_status
82
+ return self.browser.execute_script <<-JS
83
+ try{
84
+ return lapis_lazuli.http.statusCode;
85
+ } catch(err){
86
+ return null;
87
+ }
88
+ JS
89
+ end
90
+
91
+ end # module Error
92
+ end # module BrowserModule
93
+ end # module LapisLazuli