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