lapis_lazuli 0.6.1

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