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
@@ -0,0 +1,59 @@
|
|
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
|
+
module LapisLazuli
|
9
|
+
##
|
10
|
+
# Simple storage class
|
11
|
+
class Storage
|
12
|
+
@data
|
13
|
+
def initialize
|
14
|
+
@data = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def set(key, value)
|
18
|
+
@data[key] = value
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(key)
|
22
|
+
return @data[key]
|
23
|
+
end
|
24
|
+
|
25
|
+
def has?(key)
|
26
|
+
return @data.include? key
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Write all stored data to file
|
31
|
+
def writeToFile(filename)
|
32
|
+
# Make storage directory
|
33
|
+
dir = File.dirname(filename)
|
34
|
+
begin
|
35
|
+
Dir.mkdir dir
|
36
|
+
rescue SystemCallError => ex
|
37
|
+
# Swallow this error; it occurs (amongst other situations) when the
|
38
|
+
# directory exists. Checking for an existing directory beforehand is
|
39
|
+
# not concurrency safe.
|
40
|
+
end
|
41
|
+
|
42
|
+
File.open(filename, 'w') { |file|
|
43
|
+
# Write the JSON to the file
|
44
|
+
file.write(@data.to_json)
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# This will be called during the destruction of the world
|
50
|
+
def destroy(world)
|
51
|
+
filename = world.config("storage_dir", ".#{File::SEPARATOR}storage") +
|
52
|
+
File::SEPARATOR +
|
53
|
+
world.time[:timestamp] +
|
54
|
+
".json"
|
55
|
+
world.log.debug("Writing storage to: #{filename}")
|
56
|
+
self.writeToFile(filename)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,40 @@
|
|
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
|
+
require 'lapis_lazuli/api'
|
9
|
+
|
10
|
+
module LapisLazuli
|
11
|
+
|
12
|
+
##
|
13
|
+
# Given a versions string or hash, stores it for later use with the library.
|
14
|
+
attr_accessor :software_versions
|
15
|
+
extend self
|
16
|
+
|
17
|
+
##
|
18
|
+
# Connedt to the endpoint or to ENV['VERSION_ENDPOINT'], then retrieve the
|
19
|
+
# url. The contents should be the software versions used.
|
20
|
+
def self.fetch_versions(url, endpoint = nil)
|
21
|
+
# Set the connection endpoint. This is either the endpoint, or the
|
22
|
+
# environment variable 'VERSION_ENDPOINT'.
|
23
|
+
if ENV.has_key?('VERSION_ENDPOINT')
|
24
|
+
endpoint = ENV['VERSION_ENDPOINT']
|
25
|
+
end
|
26
|
+
|
27
|
+
# Connect to the endpoint
|
28
|
+
api = API.new
|
29
|
+
api.set_conn(endpoint)
|
30
|
+
|
31
|
+
# Fetch versions
|
32
|
+
response = api.get(url)
|
33
|
+
if 2 != response.status / 100
|
34
|
+
raise "Error retrieving software versions, got status code #{response.status}"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Store that stuff for later.
|
38
|
+
self.software_versions = response.body
|
39
|
+
end
|
40
|
+
end # module LapisLazuli
|
@@ -0,0 +1,45 @@
|
|
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 'json'
|
10
|
+
|
11
|
+
require 'lapis_lazuli/argparse'
|
12
|
+
|
13
|
+
module LapisLazuli
|
14
|
+
module WorldModule
|
15
|
+
##
|
16
|
+
# Module with annotation related functionality
|
17
|
+
#
|
18
|
+
# Annotations are embedded into the report via cucumber's embed function, and
|
19
|
+
# that means they're embedded at the step level.
|
20
|
+
#
|
21
|
+
# They're also stored at scenario scope, so one step in a scenario can access
|
22
|
+
# annotations made in another step.
|
23
|
+
module Annotate
|
24
|
+
|
25
|
+
include LapisLazuli::ArgParse
|
26
|
+
|
27
|
+
def annotate(*args)
|
28
|
+
@annotations ||= {}
|
29
|
+
|
30
|
+
scope = scenario.scope(true) || 'items'
|
31
|
+
stuff = parse_args({}, scope, *args)
|
32
|
+
|
33
|
+
for_scope = @annotations.fetch(scope, [])
|
34
|
+
for_scope << stuff[scope]
|
35
|
+
@annotations[scope] = for_scope
|
36
|
+
|
37
|
+
embed(JSON.generate(stuff), 'application/json')
|
38
|
+
end
|
39
|
+
|
40
|
+
def annotations
|
41
|
+
@annotations
|
42
|
+
end
|
43
|
+
end # module Annotate
|
44
|
+
end # module WorldModule
|
45
|
+
end # module LapisLazuli
|
@@ -0,0 +1,35 @@
|
|
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 "lapis_lazuli/api"
|
10
|
+
require "lapis_lazuli/runtime"
|
11
|
+
|
12
|
+
module LapisLazuli
|
13
|
+
module WorldModule
|
14
|
+
##
|
15
|
+
# Module managing an API instance
|
16
|
+
module API
|
17
|
+
|
18
|
+
##
|
19
|
+
# Has API?
|
20
|
+
def has_api?
|
21
|
+
a = Runtime::instance.get :api
|
22
|
+
return !a.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Get/create the API instance
|
27
|
+
def api
|
28
|
+
return Runtime.instance.set_if(self, :api) do
|
29
|
+
LapisLazuli::API.new
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end # module API
|
34
|
+
end # module WorldModule
|
35
|
+
end # module LapisLazuli
|
@@ -0,0 +1,75 @@
|
|
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 "lapis_lazuli/browser"
|
10
|
+
require "lapis_lazuli/runtime"
|
11
|
+
|
12
|
+
require "lapis_lazuli/world/config"
|
13
|
+
require "lapis_lazuli/world/logging"
|
14
|
+
require "lapis_lazuli/world/error"
|
15
|
+
require "lapis_lazuli/world/proxy"
|
16
|
+
|
17
|
+
module LapisLazuli
|
18
|
+
module WorldModule
|
19
|
+
##
|
20
|
+
# Module managing a browser instance
|
21
|
+
module Browser
|
22
|
+
include LapisLazuli::WorldModule::Config
|
23
|
+
include LapisLazuli::WorldModule::Logging
|
24
|
+
include LapisLazuli::WorldModule::Error
|
25
|
+
include LapisLazuli::WorldModule::Proxy
|
26
|
+
|
27
|
+
##
|
28
|
+
# Store extension modules for the browser
|
29
|
+
module ClassMethods
|
30
|
+
def browser_module(module_name)
|
31
|
+
@extensions ||= []
|
32
|
+
@extensions << module_name
|
33
|
+
end
|
34
|
+
|
35
|
+
def browser_modules
|
36
|
+
@extensions
|
37
|
+
end
|
38
|
+
end
|
39
|
+
extend ClassMethods
|
40
|
+
|
41
|
+
##
|
42
|
+
# Checks if there is a browser started
|
43
|
+
def has_browser?
|
44
|
+
b = Runtime.instance.get :browser
|
45
|
+
return (not b.nil? and b.is_open?)
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Get the current main browser
|
50
|
+
def browser(*args)
|
51
|
+
b = Runtime.instance.set_if(self, :browser) do
|
52
|
+
# Add LL to the arguments for the browser
|
53
|
+
browser_args = args.unshift(self)
|
54
|
+
# Create a new browser object
|
55
|
+
inst = LapisLazuli::Browser.new(*browser_args)
|
56
|
+
# Extend the instance
|
57
|
+
if not Browser.browser_modules.nil?
|
58
|
+
Browser.browser_modules.each do |ext|
|
59
|
+
inst.extend(ext)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
# Return the instance
|
63
|
+
inst
|
64
|
+
end
|
65
|
+
|
66
|
+
if not b.is_open?
|
67
|
+
b.start
|
68
|
+
end
|
69
|
+
|
70
|
+
return b
|
71
|
+
end
|
72
|
+
|
73
|
+
end # module Browser
|
74
|
+
end # module WorldModule
|
75
|
+
end # module LapisLazuli
|
@@ -0,0 +1,292 @@
|
|
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 "lapis_lazuli/options"
|
10
|
+
|
11
|
+
module LapisLazuli
|
12
|
+
module WorldModule
|
13
|
+
##
|
14
|
+
# Module with configuration loading related functions
|
15
|
+
#
|
16
|
+
# Manages the following:
|
17
|
+
# @config - internal configuration representation
|
18
|
+
# config_file - Needs to be set before config can be accessed.
|
19
|
+
# @env - loaded/detected config/test environment
|
20
|
+
module Config
|
21
|
+
##
|
22
|
+
# Explicitly store the configuration file name.
|
23
|
+
module ClassMethods
|
24
|
+
def config_file=(name)
|
25
|
+
@config_file = name
|
26
|
+
end
|
27
|
+
|
28
|
+
def config_file
|
29
|
+
return @config_file || "config/config.yml"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
extend ClassMethods
|
33
|
+
|
34
|
+
|
35
|
+
##
|
36
|
+
# The configuration is not a singleton, precisely, but it does not need to
|
37
|
+
# be created more than once. Note that explicitly calling load_config will
|
38
|
+
# still work to overwrite an existing configuration.
|
39
|
+
def init
|
40
|
+
# Guard against doing this more than once.
|
41
|
+
if not @config.nil?
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
if Config.config_file.nil?
|
46
|
+
raise "No configuration file provided, set LapisLazuli::WorldModule::Config.config_file"
|
47
|
+
end
|
48
|
+
|
49
|
+
load_config(Config.config_file)
|
50
|
+
|
51
|
+
if @config.nil?
|
52
|
+
raise "Could not load configuration."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
##
|
58
|
+
# Loads a config based on a filename
|
59
|
+
#
|
60
|
+
# Supports: YML, JSON
|
61
|
+
#
|
62
|
+
# Example:
|
63
|
+
# ENV['TEST_ENV'] = 'production'
|
64
|
+
# load_config("config/config.yml")
|
65
|
+
#
|
66
|
+
# Will try to load the following files:
|
67
|
+
# - config/config-production.yml
|
68
|
+
# - config/config-debug.yml
|
69
|
+
# - config/config-test.yml
|
70
|
+
# - config/config-local.yml
|
71
|
+
# - config/config.yml
|
72
|
+
def load_config(config_name)
|
73
|
+
# Split the filename
|
74
|
+
ext = File.extname(config_name)
|
75
|
+
dir, filename = File.split(config_name)
|
76
|
+
basename = File.basename(filename, ext)
|
77
|
+
|
78
|
+
# What are the suffixes to check
|
79
|
+
suffixes = [
|
80
|
+
"debug",
|
81
|
+
"test",
|
82
|
+
"local"
|
83
|
+
]
|
84
|
+
|
85
|
+
if ENV["TEST_ENV"]
|
86
|
+
@env = ENV["TEST_ENV"]
|
87
|
+
end
|
88
|
+
|
89
|
+
# Do we have an environment
|
90
|
+
if not @env.nil?
|
91
|
+
# Add it to the suffixes
|
92
|
+
suffixes.unshift(@env)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Turn suffixes into files to try
|
96
|
+
files = []
|
97
|
+
suffixes.each do |suffix|
|
98
|
+
files << "#{dir}#{File::SEPARATOR}#{basename}-#{suffix}#{ext}"
|
99
|
+
end
|
100
|
+
files << config_name
|
101
|
+
|
102
|
+
# Try all files in order
|
103
|
+
files.each do |file|
|
104
|
+
begin
|
105
|
+
# Try to load a config file
|
106
|
+
return self.load_config_from_file(file)
|
107
|
+
rescue
|
108
|
+
# Do nothing, load the next file
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
##
|
115
|
+
# Loads a config file
|
116
|
+
#
|
117
|
+
# Supports: YML, JSON
|
118
|
+
#
|
119
|
+
# Throws errors if:
|
120
|
+
# - Config file isn't readable
|
121
|
+
# - Environment doesn't exist in config
|
122
|
+
# - Default environment not set in config if no environment is set
|
123
|
+
def load_config_from_file(filename)
|
124
|
+
# Try to load the file from disk
|
125
|
+
begin
|
126
|
+
# Determine the extension
|
127
|
+
ext = File.extname(filename)
|
128
|
+
# Use the correct loader
|
129
|
+
if ext == ".yml"
|
130
|
+
@config = YAML.load_file(filename)
|
131
|
+
elsif ext == ".json"
|
132
|
+
json = File.read(filename)
|
133
|
+
@config = JSON.parse(json)
|
134
|
+
end
|
135
|
+
rescue RuntimeError => err
|
136
|
+
# Can't help you
|
137
|
+
raise "Error loading file: #{filename} #{err}"
|
138
|
+
end
|
139
|
+
|
140
|
+
# If we have an environment this config should have it
|
141
|
+
if not @env.nil? and not self.has_config?(@env)
|
142
|
+
raise "Environment doesn't exist in config file"
|
143
|
+
end
|
144
|
+
|
145
|
+
# If we don't have one then load the default
|
146
|
+
if @env.nil? and self.has_config?("default_env")
|
147
|
+
tmp = self.config("default_env")
|
148
|
+
if self.has_config?(tmp)
|
149
|
+
@env = tmp
|
150
|
+
else
|
151
|
+
raise "Default environment not present in config file"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
|
158
|
+
##
|
159
|
+
# Does the config have a variable?
|
160
|
+
# Uses config and catches any errors it raises
|
161
|
+
def has_config?(variable)
|
162
|
+
# Make sure the configured configuration is loaded, if possible
|
163
|
+
init
|
164
|
+
|
165
|
+
begin
|
166
|
+
value = self.config(variable)
|
167
|
+
return (not value.nil?)
|
168
|
+
rescue RuntimeError => err
|
169
|
+
return false
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# Get the configuration from the config,
|
175
|
+
# uses a dot seperator for object traversing
|
176
|
+
#
|
177
|
+
# Example:
|
178
|
+
# ll.config("test.google.url") => "www.google.com"
|
179
|
+
#
|
180
|
+
# Raises error if traversing the object is impossible
|
181
|
+
def config(variable=false, default=nil)
|
182
|
+
# Make sure the configured configuration is loaded, if possible
|
183
|
+
init
|
184
|
+
|
185
|
+
# No variable given? Return the entire object.
|
186
|
+
result = @config
|
187
|
+
if not variable
|
188
|
+
return result
|
189
|
+
end
|
190
|
+
|
191
|
+
# Environment variables for known options override the option.
|
192
|
+
if CONFIG_OPTIONS.has_key? variable
|
193
|
+
var = variable.upcase
|
194
|
+
if ENV.has_key? var
|
195
|
+
return ENV[var]
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Otherwise try to find it in the configuration object
|
200
|
+
variable.split(".").each do |part|
|
201
|
+
if default.nil? and result.nil?
|
202
|
+
raise "Unknown configuration variable '#{variable}' and no default given!"
|
203
|
+
end
|
204
|
+
break if result.nil?
|
205
|
+
result = result[part]
|
206
|
+
end
|
207
|
+
|
208
|
+
if default.nil? and result.nil?
|
209
|
+
if CONFIG_OPTIONS.has_key? variable
|
210
|
+
return CONFIG_OPTIONS[variable][0]
|
211
|
+
else
|
212
|
+
raise "Unknown configuration variable '#{variable}' and no default given!"
|
213
|
+
end
|
214
|
+
else
|
215
|
+
return result || default
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
##
|
220
|
+
# Does the environment have a certain config variable
|
221
|
+
def has_env?(variable)
|
222
|
+
# Make sure the configured configuration is loaded, if possible
|
223
|
+
init
|
224
|
+
|
225
|
+
if @env.nil?
|
226
|
+
return false
|
227
|
+
end
|
228
|
+
return self.has_config?("#{@env}.#{variable}")
|
229
|
+
end
|
230
|
+
|
231
|
+
##
|
232
|
+
# Returns current environment
|
233
|
+
def current_env
|
234
|
+
init
|
235
|
+
|
236
|
+
return @env
|
237
|
+
end
|
238
|
+
|
239
|
+
##
|
240
|
+
# Get a environment variable from the config file
|
241
|
+
# Alias for ll.config(ll.env + "." + variable)
|
242
|
+
def env(variable=false, default=nil)
|
243
|
+
# Make sure the configured configuration is loaded, if possible
|
244
|
+
init
|
245
|
+
|
246
|
+
if not variable
|
247
|
+
return self.config(@env)
|
248
|
+
end
|
249
|
+
|
250
|
+
# Environment variables for known options override environment specific
|
251
|
+
# options, too
|
252
|
+
if CONFIG_OPTIONS.has_key? variable
|
253
|
+
var = variable.upcase
|
254
|
+
if ENV.has_key? var
|
255
|
+
return ENV[var]
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
return self.config("#{@env}.#{variable}",default)
|
260
|
+
end
|
261
|
+
|
262
|
+
##
|
263
|
+
# Checks if a variabl exist in the env or config
|
264
|
+
def has_env_or_config?(variable)
|
265
|
+
# Make sure the configured configuration is loaded, if possible
|
266
|
+
init
|
267
|
+
|
268
|
+
return self.has_env?(variable) || self.has_config?(variable)
|
269
|
+
end
|
270
|
+
|
271
|
+
##
|
272
|
+
# Get a variable from the config
|
273
|
+
# First checks the environment section, before it checks the global part
|
274
|
+
def env_or_config(variable, default=nil)
|
275
|
+
# Make sure the configured configuration is loaded, if possible
|
276
|
+
init
|
277
|
+
|
278
|
+
if self.has_env?(variable)
|
279
|
+
return self.env(variable, default)
|
280
|
+
elsif self.has_config?(variable)
|
281
|
+
return self.config(variable, default)
|
282
|
+
else
|
283
|
+
return nil
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
|
289
|
+
|
290
|
+
end # module Config
|
291
|
+
end # module WorldModule
|
292
|
+
end # module LapisLazuli
|
@@ -0,0 +1,141 @@
|
|
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 WorldModule
|
11
|
+
##
|
12
|
+
# Module with error handling related functionality
|
13
|
+
module Error
|
14
|
+
##
|
15
|
+
# Throw an error based on some settings
|
16
|
+
#
|
17
|
+
# Examples:
|
18
|
+
# ll.error("Simple message") => "Simple message"
|
19
|
+
# ll.error(:message => "Simple message") => "Simple message"
|
20
|
+
# ll.error(:env => "test") => "Environment setting 'test' not found"
|
21
|
+
# ll.error(:env => "test", :exists => true) => "Environment setting 'test' found"
|
22
|
+
# ll.error(:screenshot => true, :message => "Simple") => "Simple", and screenshot is taken with the message name included.
|
23
|
+
def error(settings=nil)
|
24
|
+
# Default message
|
25
|
+
message = nil
|
26
|
+
groups = nil
|
27
|
+
|
28
|
+
# Default actions
|
29
|
+
screenshot = false
|
30
|
+
exception = nil
|
31
|
+
|
32
|
+
# Do we have settings
|
33
|
+
if not settings.nil?
|
34
|
+
# Simple string input
|
35
|
+
if settings.is_a? String
|
36
|
+
message = settings
|
37
|
+
elsif settings.is_a? Hash
|
38
|
+
if settings.has_key? :message
|
39
|
+
message = settings[:message]
|
40
|
+
end
|
41
|
+
# Environment errors
|
42
|
+
if settings.has_key? :env
|
43
|
+
# Does the value exist or not?
|
44
|
+
exists = ""
|
45
|
+
if not (settings.has_key?(:exists) or settings[:exists])
|
46
|
+
exists = ' not'
|
47
|
+
end
|
48
|
+
message = "Environment setting '#{settings[:env]}'" +
|
49
|
+
exists + " found"
|
50
|
+
end
|
51
|
+
|
52
|
+
if settings.has_key? :scenario
|
53
|
+
message = "Scenario failed: #{settings[:scenario]}"
|
54
|
+
elsif settings.has_key? :not_found
|
55
|
+
message = "Not found: #{settings[:not_found]}"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Grouping of errors
|
59
|
+
if settings.has_key? :groups
|
60
|
+
grouping = settings[:groups]
|
61
|
+
if grouping.is_a? String
|
62
|
+
groups = [grouping]
|
63
|
+
elsif grouping.is_a? Array
|
64
|
+
groups = grouping
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Exception message shouldn't get lost
|
69
|
+
if settings.has_key? :exception and not settings[:exception].nil?
|
70
|
+
exception = settings[:exception]
|
71
|
+
if message.nil?
|
72
|
+
message = settings[:exception].message
|
73
|
+
else
|
74
|
+
message = "#{message} - #{settings[:exception].message}"
|
75
|
+
end
|
76
|
+
elsif message.nil?
|
77
|
+
message = "An unknown error occurred."
|
78
|
+
end
|
79
|
+
|
80
|
+
# Check if we want to take a screenshot
|
81
|
+
if settings.has_key? :screenshot
|
82
|
+
screenshot = !!settings[:screenshot]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Include URL if we have a browser
|
88
|
+
if self.has_browser?
|
89
|
+
message += " (#{self.browser.url})"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Add the groups to the message
|
93
|
+
if not groups.nil?
|
94
|
+
message = "[#{groups.join("][")}] #{message}"
|
95
|
+
end
|
96
|
+
|
97
|
+
# Write the error to the log
|
98
|
+
if self.log
|
99
|
+
self.log.error(message)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Take screenshot, if necessary
|
103
|
+
if screenshot
|
104
|
+
self.browser.take_screenshot(message)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Start debugger, if necessary
|
108
|
+
if self.env_or_config("breakpoint_on_error")
|
109
|
+
self.start_debugger
|
110
|
+
end
|
111
|
+
|
112
|
+
# Raise the message
|
113
|
+
if not exception.nil?
|
114
|
+
# message already contains ex.message here - or it should
|
115
|
+
raise exception.class, message, exception.backtrace
|
116
|
+
else
|
117
|
+
raise message
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# If byebug (ruby >= 2.0) or debugger (ruby < 2.0) are installed, start
|
123
|
+
# the debugger now.
|
124
|
+
def start_debugger
|
125
|
+
# First try the more modern 'byebug'
|
126
|
+
begin
|
127
|
+
require "byebug"
|
128
|
+
byebug
|
129
|
+
rescue LoadError
|
130
|
+
# If that fails, try the older debugger
|
131
|
+
begin
|
132
|
+
require 'debugger'
|
133
|
+
debugger
|
134
|
+
rescue LoadError
|
135
|
+
self.log.info "No debugger found, can't break on failures."
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end # module Error
|
140
|
+
end # module WorldModule
|
141
|
+
end # module LapisLazuli
|