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
@@ -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
|