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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +42 -0
- data/LICENSE +30 -0
- data/README.md +74 -0
- data/Rakefile +1 -0
- data/bin/lapis_lazuli +3 -0
- data/lapis_lazuli.gemspec +32 -0
- data/lib/lapis_lazuli/api.rb +52 -0
- data/lib/lapis_lazuli/argparse.rb +128 -0
- data/lib/lapis_lazuli/ast.rb +160 -0
- data/lib/lapis_lazuli/browser/error.rb +93 -0
- data/lib/lapis_lazuli/browser/find.rb +500 -0
- data/lib/lapis_lazuli/browser/interaction.rb +91 -0
- data/lib/lapis_lazuli/browser/screenshots.rb +70 -0
- data/lib/lapis_lazuli/browser/wait.rb +158 -0
- data/lib/lapis_lazuli/browser.rb +246 -0
- data/lib/lapis_lazuli/cli.rb +110 -0
- data/lib/lapis_lazuli/cucumber.rb +25 -0
- data/lib/lapis_lazuli/generators/cucumber/template/.gitignore +6 -0
- data/lib/lapis_lazuli/generators/cucumber/template/Gemfile +37 -0
- data/lib/lapis_lazuli/generators/cucumber/template/README.md +27 -0
- data/lib/lapis_lazuli/generators/cucumber/template/config/config.yml +29 -0
- data/lib/lapis_lazuli/generators/cucumber/template/config/cucumber.yml +34 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/example.feature +11 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/interaction_steps.rb +20 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/validation_steps.rb +21 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/support/env.rb +12 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/support/transition.rb +12 -0
- data/lib/lapis_lazuli/generators/cucumber.rb +128 -0
- data/lib/lapis_lazuli/generic/xpath.rb +49 -0
- data/lib/lapis_lazuli/options.rb +28 -0
- data/lib/lapis_lazuli/placeholders.rb +36 -0
- data/lib/lapis_lazuli/proxy.rb +179 -0
- data/lib/lapis_lazuli/runtime.rb +88 -0
- data/lib/lapis_lazuli/scenario.rb +88 -0
- data/lib/lapis_lazuli/storage.rb +59 -0
- data/lib/lapis_lazuli/version.rb +10 -0
- data/lib/lapis_lazuli/versions.rb +40 -0
- data/lib/lapis_lazuli/world/annotate.rb +45 -0
- data/lib/lapis_lazuli/world/api.rb +35 -0
- data/lib/lapis_lazuli/world/browser.rb +75 -0
- data/lib/lapis_lazuli/world/config.rb +292 -0
- data/lib/lapis_lazuli/world/error.rb +141 -0
- data/lib/lapis_lazuli/world/hooks.rb +109 -0
- data/lib/lapis_lazuli/world/logging.rb +53 -0
- data/lib/lapis_lazuli/world/proxy.rb +59 -0
- data/lib/lapis_lazuli/world/variable.rb +139 -0
- data/lib/lapis_lazuli.rb +75 -0
- data/test/.gitignore +8 -0
- data/test/Gemfile +42 -0
- data/test/README.md +35 -0
- data/test/config/config.yml +37 -0
- data/test/config/cucumber.yml +37 -0
- data/test/features/annotation.feature +23 -0
- data/test/features/browser.feature +10 -0
- data/test/features/button.feature +38 -0
- data/test/features/click.feature +35 -0
- data/test/features/error.feature +30 -0
- data/test/features/find.feature +92 -0
- data/test/features/har.feature +9 -0
- data/test/features/modules.feature +14 -0
- data/test/features/step_definitions/interaction_steps.rb +154 -0
- data/test/features/step_definitions/validation_steps.rb +350 -0
- data/test/features/support/env.rb +21 -0
- data/test/features/text_field.feature +32 -0
- data/test/features/timing.feature +47 -0
- data/test/features/variable.feature +11 -0
- data/test/features/xpath.feature +41 -0
- data/test/server/start.rb +17 -0
- data/test/server/www/button.html +22 -0
- data/test/server/www/error_html.html +9 -0
- data/test/server/www/find.html +66 -0
- data/test/server/www/javascript_error.html +12 -0
- data/test/server/www/text_fields.html +15 -0
- data/test/server/www/timing.html +32 -0
- data/test/server/www/xpath.html +22 -0
- 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
data/Gemfile
ADDED
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,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
|