lapis_lazuli 1.1.0 → 2.0.0
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 +4 -4
- data/lib/lapis_lazuli/browser/find.rb +18 -9
- data/lib/lapis_lazuli/browser/screenshots.rb +73 -53
- data/lib/lapis_lazuli/generators/cucumber/template/config/config.yml +3 -2
- data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/validation_steps.rb +1 -1
- data/lib/lapis_lazuli/version.rb +1 -1
- data/lib/lapis_lazuli/world/error.rb +1 -1
- data/test/config/config.yml +2 -1
- data/test/features/bindings.feature +6 -6
- data/test/features/multifind.feature +52 -0
- data/test/features/screenshot.feature +35 -0
- data/test/features/step_definitions/interaction_steps.rb +8 -0
- data/test/features/step_definitions/multifind_steps.rb +136 -0
- data/test/features/step_definitions/validation_steps.rb +8 -9
- data/test/server/www/screenshot.html +147 -0
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05f31ca8e6b595e90bfdf4dd47a474e72a4cd1d3
|
4
|
+
data.tar.gz: 6e26fbb44ea553ea4e457f9f799c77da3a74ba20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4ecd69d51356464a628bb503d15135433960f56dcfcb2d1e5eb3875c16eb1241a72fd0bf9d1d77488461a99f5e6ef810ec41c33994b578b604273001d5e0ee5
|
7
|
+
data.tar.gz: 10b5b4124a3722b5b10222b4c8b3f7c9ff59454e04d15b97a35a124f84d478b0396bf86f7fe6737ef245474aa38fc999c5270ff289d4f105e28d0893a947d63b
|
@@ -109,7 +109,7 @@ module BrowserModule
|
|
109
109
|
def multi_find_all(*args)
|
110
110
|
# Parse args into options
|
111
111
|
options = {
|
112
|
-
:mode => :
|
112
|
+
:mode => :match_any,
|
113
113
|
}
|
114
114
|
options = parse_find_options(options, *args)
|
115
115
|
throw_opt, options = do_throw?(options)
|
@@ -170,7 +170,7 @@ module BrowserModule
|
|
170
170
|
:pick => :first,
|
171
171
|
:throw => true,
|
172
172
|
:mode => :match_one,
|
173
|
-
:error => nil
|
173
|
+
:error => nil
|
174
174
|
}
|
175
175
|
|
176
176
|
##
|
@@ -185,7 +185,7 @@ module BrowserModule
|
|
185
185
|
# Verify/sanitize common options
|
186
186
|
if options.has_key? :mode
|
187
187
|
options[:mode] = options[:mode].to_sym
|
188
|
-
assert [:match_all, :match_one].include?(options[:mode]), ":mode needs to be one of :match_one or :
|
188
|
+
assert [:match_all, :match_one, :match_any].include?(options[:mode]), ":mode needs to be one of :match_one, :match_all or :match_any"
|
189
189
|
end
|
190
190
|
|
191
191
|
if options.has_key? :pick
|
@@ -349,9 +349,8 @@ module BrowserModule
|
|
349
349
|
def find_lambda_filtered(options)
|
350
350
|
options = options.dup
|
351
351
|
|
352
|
-
filter_by = options.fetch(:filter_by,
|
352
|
+
filter_by = options.fetch(:filter_by, :present?)
|
353
353
|
options.delete(:filter_by)
|
354
|
-
|
355
354
|
options, inner = find_lambda(options)
|
356
355
|
|
357
356
|
# Wrap into filter function
|
@@ -420,15 +419,14 @@ module BrowserModule
|
|
420
419
|
s, func = find_lambda_filtered(selector)
|
421
420
|
lambdas << func
|
422
421
|
end
|
423
|
-
|
424
422
|
# Depending on mode, we need to execute something slightly different
|
425
423
|
case options[:mode]
|
426
|
-
when :match_all
|
424
|
+
when :match_all, :match_any
|
427
425
|
return options, lambda {
|
428
426
|
all = []
|
429
427
|
lambdas.each do |func|
|
430
428
|
res = func.call
|
431
|
-
if 0 == res.length
|
429
|
+
if 0 == res.length and options[:mode] == :match_all
|
432
430
|
all = []
|
433
431
|
break
|
434
432
|
end
|
@@ -485,7 +483,18 @@ module BrowserModule
|
|
485
483
|
ret = func.call
|
486
484
|
|
487
485
|
if throw_opt and (ret.nil? or ret.length <= 0)
|
488
|
-
|
486
|
+
msg = "Cannot find elements with selectors: "
|
487
|
+
if selectors[:selectors].length < 2
|
488
|
+
msg += "#{selectors[:selectors]}\n"
|
489
|
+
else
|
490
|
+
msg += "\n"
|
491
|
+
selectors[:selectors].each do |s|
|
492
|
+
msg += "- #{s} \n"
|
493
|
+
end
|
494
|
+
end
|
495
|
+
selectors.delete(:selectors)
|
496
|
+
msg += "With the options: #{selectors}"
|
497
|
+
raise msg
|
489
498
|
end
|
490
499
|
|
491
500
|
return ret
|
@@ -7,70 +7,90 @@
|
|
7
7
|
#
|
8
8
|
|
9
9
|
module LapisLazuli
|
10
|
-
module BrowserModule
|
10
|
+
module BrowserModule
|
11
11
|
|
12
|
-
##
|
13
|
-
# Screenshot functionality for browser
|
14
|
-
module Screenshots
|
15
12
|
##
|
16
|
-
#
|
17
|
-
|
18
|
-
|
13
|
+
# Screenshot functionality for browser
|
14
|
+
module Screenshots
|
15
|
+
##
|
16
|
+
# Returns the name of the screenshot, if take_screenshot is called now.
|
17
|
+
def screenshot_name(suffix="")
|
18
|
+
dir = world.env_or_config("screenshot_dir")
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
# Generate the file name according to the new or old scheme.
|
21
|
+
case world.env_or_config("screenshot_scheme")
|
22
|
+
when "new"
|
23
|
+
# For non-cucumber cases: we don't have world.scenario.data
|
24
|
+
if not world.scenario.data.nil?
|
25
|
+
name = world.scenario.id
|
26
|
+
end
|
27
|
+
# FIXME random makes this non-repeatable, sadly
|
28
|
+
name = "#{world.scenario.time[:iso_short]}-#{@browser.object_id}-#{name}-#{Random.rand(10000).to_s}.png"
|
29
|
+
else # 'old' and default
|
30
|
+
# For non-cucumber cases: we don't have world.scenario.data
|
31
|
+
if not world.scenario.data.nil?
|
32
|
+
name = world.scenario.data.name.gsub(/^.*(\\|\/)/, '').gsub(/[^\w\.\-]/, '_').squeeze('_')
|
33
|
+
end
|
34
|
+
name = world.time[:timestamp] + "_" + name + '.png'
|
26
35
|
end
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
name = world.scenario.data.name.gsub(/^.*(\\|\/)/, '').gsub(/[^\w\.\-]/, '_').squeeze('_')
|
33
|
-
end
|
34
|
-
name = world.time[:timestamp] + "_" + name + '.png'
|
36
|
+
|
37
|
+
# Full file location
|
38
|
+
fileloc = "#{dir}#{File::SEPARATOR}#{name}"
|
39
|
+
|
40
|
+
return fileloc
|
35
41
|
end
|
36
42
|
|
37
|
-
|
38
|
-
|
43
|
+
##
|
44
|
+
# Taking a screenshot of the current page.
|
45
|
+
# Using the name as defined at the start of every scenario
|
46
|
+
def take_screenshot(suffix="")
|
47
|
+
# If the target directory does not exist, create it.
|
48
|
+
dir = world.env_or_config("screenshot_dir")
|
49
|
+
begin
|
50
|
+
Dir.mkdir dir
|
51
|
+
rescue SystemCallError => ex
|
52
|
+
# Swallow this error; it occurs (amongst other situations) when the
|
53
|
+
# directory exists. Checking for an existing directory beforehand is
|
54
|
+
# not concurrency safe.
|
55
|
+
end
|
39
56
|
|
40
|
-
|
41
|
-
end
|
57
|
+
fileloc = self.screenshot_name(suffix)
|
42
58
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
59
|
+
# Write screenshot
|
60
|
+
begin
|
61
|
+
# First make sure the window size is the full page size
|
62
|
+
if world.env_or_config("screenshots_height") == 'full'
|
63
|
+
original_height = @browser.window.size.height
|
64
|
+
width = @browser.window.size.width
|
65
|
+
target_height = @browser.execute_script('
|
66
|
+
var body = document.body,
|
67
|
+
html = document.documentElement;
|
68
|
+
return Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight );
|
69
|
+
')
|
70
|
+
if target_height > original_height
|
71
|
+
@browser.window.resize_to(width, target_height)
|
72
|
+
end
|
73
|
+
end
|
56
74
|
|
57
|
-
|
75
|
+
# Save the screenshot
|
76
|
+
@browser.screenshot.save fileloc
|
58
77
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
78
|
+
if world.env_or_config("screenshots_height") == 'full'
|
79
|
+
if target_height > original_height
|
80
|
+
@browser.window.resize_to(width, original_height)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
world.log.debug "Screenshot saved: #{fileloc}"
|
64
84
|
|
65
|
-
|
66
|
-
|
67
|
-
|
85
|
+
# Try to store the screenshot name
|
86
|
+
if world.respond_to? :annotate
|
87
|
+
world.annotate :screenshot => fileloc
|
88
|
+
end
|
89
|
+
rescue RuntimeError => e
|
90
|
+
world.log.debug "Failed to save screenshot to '#{fileloc}'. Error message #{e.message}"
|
68
91
|
end
|
69
|
-
|
70
|
-
world.log.debug "Failed to save screenshot to '#{fileloc}'. Error message #{e.message}"
|
92
|
+
return fileloc
|
71
93
|
end
|
72
|
-
|
73
|
-
|
74
|
-
end # module Screenshots
|
75
|
-
end # module BrowserModule
|
94
|
+
end # module Screenshots
|
95
|
+
end # module BrowserModule
|
76
96
|
end # module LapisLazuli
|
@@ -11,6 +11,7 @@
|
|
11
11
|
default_env: production # defines the environment
|
12
12
|
default_device: desktop720 # See devices.yml for your options
|
13
13
|
close_browser_after: end # Can be `scenario`, `feature` or `end`
|
14
|
+
screenshots_height: full # When 'full' the window will be resized to max height before taking a screenshot
|
14
15
|
|
15
16
|
################################################################################
|
16
17
|
# List of error strings. `browser.html_error` will return an array of detected strings.
|
@@ -36,7 +37,7 @@ uat:
|
|
36
37
|
|
37
38
|
production:
|
38
39
|
pages:
|
39
|
-
root: https://spritecloud.com
|
40
|
+
root: https://www.spritecloud.com
|
40
41
|
home: /
|
41
42
|
about-us: /about-us/
|
42
43
|
testing: /testing/
|
@@ -58,4 +59,4 @@ users:
|
|
58
59
|
password: test_RAND_
|
59
60
|
gender: 'Female'
|
60
61
|
experience: 'Ruby,Gherkin'
|
61
|
-
biography: 'Hello, I am a randomized user, today is _TIMESTAMP_ seconds after the existance of computers'
|
62
|
+
biography: 'Hello, I am a randomized user, today is _TIMESTAMP_ seconds after the existance of computers'
|
data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/validation_steps.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
# validation_steps.rb is used to confirm that certain elements are displayed on the page.
|
7
7
|
|
8
|
-
Then(
|
8
|
+
Then(/^text "([^"]*)" should display$/) do |string|
|
9
9
|
# Note: The following is *really* slow, as it'll apply the regex to all
|
10
10
|
# elements in the page, one after the other. Of course, if any element
|
11
11
|
# includes the regex, all its parent elements also will, so you have
|
data/lib/lapis_lazuli/version.rb
CHANGED
data/test/config/config.yml
CHANGED
@@ -9,8 +9,9 @@
|
|
9
9
|
################################################################################
|
10
10
|
# Set the global variables
|
11
11
|
default_env: production # defines the environment
|
12
|
-
default_device: desktop720
|
12
|
+
default_device: desktop720 # set the default browser dimensions and/or user agent (See devices.yml)
|
13
13
|
screenshots_dir: screenshots # where to save the screenshots
|
14
|
+
screenshots_height: full # When 'full' the window will be resized to max height before taking a screenshot
|
14
15
|
step_pause_time: 1 # Waiting time in seconds defined after a step completes
|
15
16
|
make_screenshot_on_failed_scenario: true # make a screenshot after a scenario fails
|
16
17
|
old_portal: true
|
@@ -5,14 +5,14 @@ I want to run a webserver with some test files
|
|
5
5
|
And test if I can parse bindings when starting the browsers
|
6
6
|
|
7
7
|
@bindings_01
|
8
|
-
Scenario: Custom user-agent firefox
|
8
|
+
Scenario: bindings_01 - Custom user-agent firefox
|
9
9
|
Given I use browser bindings "1"
|
10
10
|
And I navigate to URL "http://whatsmyua.com/"
|
11
11
|
Then within 2 seconds I should see "CUSTOM-USER-AGENT"
|
12
12
|
And I close the browser
|
13
13
|
|
14
14
|
@bindings_02
|
15
|
-
Scenario: Custom user-agent chrome
|
15
|
+
Scenario: bindings_02 - Custom user-agent chrome
|
16
16
|
Given I use browser bindings "2"
|
17
17
|
And I navigate to URL "http://whatsmyua.com/"
|
18
18
|
Then within 2 seconds I should see "CUSTOM-CHROME-USER-AGENT"
|
@@ -20,22 +20,22 @@ And test if I can parse bindings when starting the browsers
|
|
20
20
|
|
21
21
|
# Known issue with maximizing the window using the chrome option --start-maximized
|
22
22
|
@bindings_03 @maximize_issue
|
23
|
-
Scenario: Custom user-agent chrome
|
23
|
+
Scenario: bindings_03 - Custom user-agent chrome
|
24
24
|
Given I use browser bindings "3"
|
25
25
|
And I navigate to URL "http://whatsmyua.com/"
|
26
26
|
Then the browser window size should be "full screen"
|
27
27
|
And I close the browser
|
28
28
|
|
29
29
|
@bindings_04
|
30
|
-
Scenario: Using a pre-defined device (iphone5)
|
30
|
+
Scenario: bindings_04 - Using a pre-defined device (iphone5)
|
31
31
|
Given I restart the browser to device setting "iphone5"
|
32
32
|
When I navigate to URL "http://whatsmyua.com"
|
33
|
-
Then within 2 seconds I should see "
|
33
|
+
Then within 2 seconds I should see "CPU iPhone OS 5_0 like Mac OS X"
|
34
34
|
And the browser window size should be "640x1136"
|
35
35
|
And I close the browser
|
36
36
|
|
37
37
|
@bindings_05
|
38
|
-
Scenario: Using a pre-defined device (desktop1080)
|
38
|
+
Scenario: bindings_05 - Using a pre-defined device (desktop1080)
|
39
39
|
Given I restart the browser to device setting "desktop1080"
|
40
40
|
When I navigate to URL "http://whatsmyua.com"
|
41
41
|
Then within 2 seconds I should see "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3" disappear
|
@@ -0,0 +1,52 @@
|
|
1
|
+
@multifind @p
|
2
|
+
Feature: testing multifind
|
3
|
+
|
4
|
+
@multifind01
|
5
|
+
Scenario: multifind01 - multifind with 1 results
|
6
|
+
Given I navigate to the find test page
|
7
|
+
Then the user expects a result in a multi_find lookup
|
8
|
+
|
9
|
+
@multifind02
|
10
|
+
Scenario: multifind02 - multifind no results
|
11
|
+
Given I navigate to the find test page
|
12
|
+
Then the user expects an error in a multi_find lookup
|
13
|
+
|
14
|
+
@multifind03
|
15
|
+
Scenario: multifind03 - multifind with no results and no error
|
16
|
+
Given I navigate to the find test page
|
17
|
+
Then the user expects no error in a multi_find lookup
|
18
|
+
|
19
|
+
@multifind04
|
20
|
+
Scenario: multifind04 - multifind all with 8 results
|
21
|
+
Given I navigate to the find test page
|
22
|
+
Then the user expects 8 results in a multi_find_all lookup
|
23
|
+
|
24
|
+
@multifind05
|
25
|
+
Scenario: multifind05 - multifind all with 1 results
|
26
|
+
Given I navigate to the find test page
|
27
|
+
Then the user expects 1 results in a multi_find_all lookup
|
28
|
+
|
29
|
+
@multifind06
|
30
|
+
Scenario: multifind06 - multifind all with 5 results
|
31
|
+
Given I navigate to the find test page
|
32
|
+
Then the user expects 5 existing results in a multi_find_all lookup
|
33
|
+
|
34
|
+
@multifind07
|
35
|
+
Scenario: multifind07 - multifind all with no results
|
36
|
+
Given I navigate to the find test page
|
37
|
+
Then the user expects an error in a multi_find_all lookup
|
38
|
+
|
39
|
+
@multifind08
|
40
|
+
Scenario: multifind08 - multifind all with no results and no error
|
41
|
+
Given I navigate to the find test page
|
42
|
+
Then the user expects no error in a multi_find_all lookup
|
43
|
+
|
44
|
+
@multifind09
|
45
|
+
Scenario: multifind09 - multifind all natching all elements with no results
|
46
|
+
Given I navigate to the find test page
|
47
|
+
Then the user expects an error in a multi_find_all lookup matching all elements
|
48
|
+
|
49
|
+
@multifind10
|
50
|
+
Scenario: multifind10 - multifind all natching all elements with no error
|
51
|
+
Given I navigate to the find test page
|
52
|
+
Then the user expects no error in a multi_find_all lookup matching all elements
|
@@ -0,0 +1,35 @@
|
|
1
|
+
@screenshot @p
|
2
|
+
Feature: Screenshot
|
3
|
+
When I want to test the Lapis Lazuli library
|
4
|
+
I want to run a webserver with some test files
|
5
|
+
And execute the each library function searches for elements.
|
6
|
+
|
7
|
+
@screenshot_01
|
8
|
+
Scenario: screenshot_01 - Successfull scenario with screenshots
|
9
|
+
Given I navigate to the screenshot test page
|
10
|
+
When I take a screenshot
|
11
|
+
Then I take a screenshot
|
12
|
+
|
13
|
+
@screenshot_02
|
14
|
+
Scenario: screenshot_02 - Taking a screenshot on a failed scenario
|
15
|
+
Given I navigate to the screenshot test page
|
16
|
+
Then I fail this step
|
17
|
+
|
18
|
+
@screenshot_03
|
19
|
+
Scenario Outline: screenshot_03 - Successfull scenario outlines with screenshots
|
20
|
+
Given I navigate to the screenshot test page
|
21
|
+
When I take a screenshot
|
22
|
+
Then I take a screenshot
|
23
|
+
Examples:
|
24
|
+
| fails |
|
25
|
+
| failing once |
|
26
|
+
| failing twice |
|
27
|
+
|
28
|
+
@screenshot_04
|
29
|
+
Scenario Outline: screenshot_04 - Failing in a scenario outline
|
30
|
+
Given I navigate to the screenshot test page
|
31
|
+
Then I fail this step
|
32
|
+
Examples:
|
33
|
+
| fails |
|
34
|
+
| failing once |
|
35
|
+
| failing twice |
|
@@ -214,4 +214,12 @@ end
|
|
214
214
|
|
215
215
|
Given(/^I restart the browser to device setting "(.*?)"$/) do |device|
|
216
216
|
browser.restart :chrome, device: device
|
217
|
+
end
|
218
|
+
|
219
|
+
When(/^I take a screenshot$/) do
|
220
|
+
browser.take_screenshot
|
221
|
+
end
|
222
|
+
|
223
|
+
When(/^I fail this step$/) do
|
224
|
+
error 'This step fails because it is suppose to'
|
217
225
|
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
Given(/^the user expects a result in a multi_find lookup$/) do
|
2
|
+
elm = browser.multi_find(
|
3
|
+
:selectors => [
|
4
|
+
{:input => {:type => 'notexist'}},
|
5
|
+
{:like => [:a, :text, 'Link']}
|
6
|
+
]
|
7
|
+
)
|
8
|
+
unless elm.text == 'Rel Link'
|
9
|
+
error "Expected element with text `blog`, but received `#{elm.text}`"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Given(/^the user expects an error in a multi_find lookup$/) do
|
14
|
+
err = ''
|
15
|
+
begin
|
16
|
+
elm = browser.multi_find(
|
17
|
+
:selectors => [
|
18
|
+
{:input => {:type => 'notexist'}},
|
19
|
+
{:like => [:a, :id, 'notexist2']}
|
20
|
+
]
|
21
|
+
)
|
22
|
+
err = "Expected an error looking for elements with no results."
|
23
|
+
rescue RuntimeError => e
|
24
|
+
puts "Caught expected error: #{e.message}"
|
25
|
+
end
|
26
|
+
error err unless err.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
Given(/^the user expects no error in a multi_find lookup$/) do
|
30
|
+
elm = browser.multi_find(
|
31
|
+
:selectors => [
|
32
|
+
{:input => {:type => 'notexist'}},
|
33
|
+
{:like => [:a, :id, 'notexist2']}
|
34
|
+
],
|
35
|
+
:throw => false
|
36
|
+
)
|
37
|
+
unless elm.nil?
|
38
|
+
error "Expected the result to be nil."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Given(/^the user expects 8 results in a multi_find_all lookup$/) do
|
43
|
+
elm = browser.multi_find_all(
|
44
|
+
:selectors => [
|
45
|
+
{:like => [:div, :name, 'count']},
|
46
|
+
{:like => [:a, :text, 'Link']}
|
47
|
+
]
|
48
|
+
)
|
49
|
+
unless elm.length == 8
|
50
|
+
error "Expected 2 elements, but received `#{elm.length}`"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
Given(/^the user expects 1 results in a multi_find_all lookup$/) do
|
55
|
+
elm = browser.multi_find_all(
|
56
|
+
:selectors => [
|
57
|
+
{:input => {:type => 'notexist'}},
|
58
|
+
{:like => [:a, :text, 'Link']}
|
59
|
+
]
|
60
|
+
)
|
61
|
+
unless elm[0].text == 'Rel Link'
|
62
|
+
error "Expected element with text `blog`, but received `#{elm.text}`"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Given(/^the user expects 5 existing results in a multi_find_all lookup$$/) do
|
67
|
+
elm = browser.multi_find_all(
|
68
|
+
:selectors => [
|
69
|
+
{:like => [:a, :id, 'notexists']},
|
70
|
+
{:like => [:div, :name, 'count'], :filter_by => :exists?},
|
71
|
+
]
|
72
|
+
)
|
73
|
+
unless elm.length == 5
|
74
|
+
error "Expected 5 elements, but received `#{elm.length}`"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
Given(/^the user expects an error in a multi_find_all lookup$/) do
|
79
|
+
err = ''
|
80
|
+
begin
|
81
|
+
elm = browser.multi_find_all(
|
82
|
+
:selectors => [
|
83
|
+
{:input => {:type => 'notexist'}},
|
84
|
+
{:like => [:a, :id, 'notexist2']}
|
85
|
+
]
|
86
|
+
)
|
87
|
+
err = "Expected an error looking for elements with no results."
|
88
|
+
rescue RuntimeError => e
|
89
|
+
puts "Caught expected error: #{e.message}"
|
90
|
+
end
|
91
|
+
error err unless err.empty?
|
92
|
+
end
|
93
|
+
|
94
|
+
Given(/^the user expects no error in a multi_find_all lookup$/) do
|
95
|
+
elm = browser.multi_find_all(
|
96
|
+
:selectors => [
|
97
|
+
{:input => {:type => 'notexist'}},
|
98
|
+
{:like => [:a, :id, 'notexist2']}
|
99
|
+
],
|
100
|
+
:throw => false
|
101
|
+
)
|
102
|
+
unless elm.length == 0
|
103
|
+
error "Expected to receive 0 results."
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
Given(/^the user expects an error in a multi_find_all lookup matching all elements$/) do
|
108
|
+
err = ''
|
109
|
+
begin
|
110
|
+
elm = browser.multi_find_all(
|
111
|
+
:selectors => [
|
112
|
+
{:input => {:type => 'texta'}},
|
113
|
+
{:like => [:a, :text, 'Link']}
|
114
|
+
],
|
115
|
+
:mode => :match_all
|
116
|
+
)
|
117
|
+
err = "Expected an error matching all elements with results."
|
118
|
+
rescue RuntimeError => e
|
119
|
+
puts "Caught expected error: #{e.message}"
|
120
|
+
end
|
121
|
+
error err unless err.empty?
|
122
|
+
end
|
123
|
+
Given(/^the user expects no error in a multi_find_all lookup matching all elements$/) do
|
124
|
+
|
125
|
+
elm = browser.multi_find_all(
|
126
|
+
:selectors => [
|
127
|
+
{:input => {:type => 'texta'}},
|
128
|
+
{:like => [:a, :text, 'Link']}
|
129
|
+
],
|
130
|
+
:mode => :match_all,
|
131
|
+
:throw => false
|
132
|
+
)
|
133
|
+
unless elm.length == 0
|
134
|
+
error "Expected to receive 0 results."
|
135
|
+
end
|
136
|
+
end
|
@@ -67,6 +67,7 @@ Then(/(first|last|random|[0-9]+[a-z]+) (.*) should (not )?be present$/) do |inde
|
|
67
67
|
options[type.to_sym] = {}
|
68
68
|
# Pick the correct one
|
69
69
|
options[:pick] = pick
|
70
|
+
options[:filter_by] = :exists?
|
70
71
|
# Execute the find
|
71
72
|
type_element = browser.find(options)
|
72
73
|
# Find all
|
@@ -76,7 +77,7 @@ Then(/(first|last|random|[0-9]+[a-z]+) (.*) should (not )?be present$/) do |inde
|
|
76
77
|
all_present = browser.find_all(options)
|
77
78
|
|
78
79
|
if hidden and type_element.present?
|
79
|
-
error("Hidden element is visible")
|
80
|
+
error("Hidden element is visible using selectors: #{options}")
|
80
81
|
elsif not hidden and not type_element.present?
|
81
82
|
error("Element is hidden")
|
82
83
|
elsif hidden and not type_element.present? and
|
@@ -94,10 +95,9 @@ Then(/^within (\d+) seconds I should see "([^"]+?)"( disappear)?$/) do |timeout,
|
|
94
95
|
else
|
95
96
|
condition = :until
|
96
97
|
end
|
97
|
-
|
98
98
|
browser.wait(
|
99
99
|
:timeout => timeout,
|
100
|
-
:
|
100
|
+
:html => /#{text}/,
|
101
101
|
:condition => condition,
|
102
102
|
:groups => ["wait #{condition.to_s}"]
|
103
103
|
)
|
@@ -215,8 +215,7 @@ Then(/^I expect a (\d+) status code$/) do |expected|
|
|
215
215
|
scenario.check_browser_errors = false
|
216
216
|
elsif browser.get_http_status != expected
|
217
217
|
error(
|
218
|
-
:message => "Incorrect status code: #{browser.get_http_status}"
|
219
|
-
:groups => ["error"]
|
218
|
+
:message => "Incorrect status code: #{browser.get_http_status}"
|
220
219
|
)
|
221
220
|
end
|
222
221
|
end
|
@@ -234,13 +233,13 @@ end
|
|
234
233
|
|
235
234
|
Then(/^the firefox browser named "(.*?)" has a profile$/) do |name|
|
236
235
|
if scenario.storage.has? name
|
237
|
-
|
238
|
-
if
|
239
|
-
if
|
236
|
+
b = scenario.storage.get name
|
237
|
+
if b.browser_name == "remote"
|
238
|
+
if b.driver.capabilities.firefox_profile.nil?
|
240
239
|
raise "Remote Firefox Profile is not set"
|
241
240
|
end
|
242
241
|
else
|
243
|
-
if
|
242
|
+
if !b.optional_data.has_key? "profile" and !b.optional_data.has_key? :profile
|
244
243
|
raise "No profile found in the optional data"
|
245
244
|
end
|
246
245
|
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
|
3
|
+
<html lang="en">
|
4
|
+
<head>
|
5
|
+
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<h1>Screenshot test page</h1>
|
9
|
+
|
10
|
+
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam,
|
11
|
+
feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies
|
12
|
+
mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat
|
13
|
+
wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros
|
14
|
+
ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.
|
15
|
+
Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam
|
16
|
+
erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus</p>
|
17
|
+
<ul>
|
18
|
+
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
|
19
|
+
<li>Aliquam tincidunt mauris eu risus.</li>
|
20
|
+
<li>Vestibulum auctor dapibus neque.</li>
|
21
|
+
</ul>
|
22
|
+
<h1>HTML Ipsum Presents</h1>
|
23
|
+
|
24
|
+
<p><strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas.
|
25
|
+
Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas
|
26
|
+
semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien
|
27
|
+
ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi.
|
28
|
+
Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a
|
29
|
+
href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.</p>
|
30
|
+
|
31
|
+
<h2>Header Level 2</h2>
|
32
|
+
|
33
|
+
<ol>
|
34
|
+
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
|
35
|
+
<li>Aliquam tincidunt mauris eu risus.</li>
|
36
|
+
</ol>
|
37
|
+
|
38
|
+
<blockquote><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet
|
39
|
+
congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus
|
40
|
+
est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.</p></blockquote>
|
41
|
+
|
42
|
+
<h3>Header Level 3</h3>
|
43
|
+
|
44
|
+
<ul>
|
45
|
+
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
|
46
|
+
<li>Aliquam tincidunt mauris eu risus.</li>
|
47
|
+
</ul>
|
48
|
+
|
49
|
+
<pre><code>
|
50
|
+
#header h1 a {
|
51
|
+
display: block;
|
52
|
+
width: 300px;
|
53
|
+
height: 80px;
|
54
|
+
}
|
55
|
+
</code></pre>
|
56
|
+
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam,
|
57
|
+
feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies
|
58
|
+
mi vitae est. Mauris placerat eleifend leo.</p>
|
59
|
+
<ul>
|
60
|
+
<li>Morbi in sem quis dui placerat ornare. Pellentesque odio nisi, euismod in, pharetra a, ultricies in, diam. Sed
|
61
|
+
arcu. Cras consequat.
|
62
|
+
</li>
|
63
|
+
<li>Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam
|
64
|
+
erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus.
|
65
|
+
</li>
|
66
|
+
<li>Phasellus ultrices nulla quis nibh. Quisque a lectus. Donec consectetuer ligula vulputate sem tristique cursus.
|
67
|
+
Nam nulla quam, gravida non, commodo a, sodales sit amet, nisi.
|
68
|
+
</li>
|
69
|
+
<li>Pellentesque fermentum dolor. Aliquam quam lectus, facilisis auctor, ultrices ut, elementum vulputate, nunc.
|
70
|
+
</li>
|
71
|
+
</ul>
|
72
|
+
<form action="#" method="post">
|
73
|
+
<div>
|
74
|
+
<label for="name">Text Input:</label>
|
75
|
+
<input type="text" name="name" id="name" value="" tabindex="1"/>
|
76
|
+
</div>
|
77
|
+
|
78
|
+
<div>
|
79
|
+
<h4>Radio Button Choice</h4>
|
80
|
+
|
81
|
+
<label for="radio-choice-1">Choice 1</label>
|
82
|
+
<input type="radio" name="radio-choice-1" id="radio-choice-1" tabindex="2" value="choice-1"/>
|
83
|
+
|
84
|
+
<label for="radio-choice-2">Choice 2</label>
|
85
|
+
<input type="radio" name="radio-choice-2" id="radio-choice-2" tabindex="3" value="choice-2"/>
|
86
|
+
</div>
|
87
|
+
|
88
|
+
<div>
|
89
|
+
<label for="select-choice">Select Dropdown Choice:</label>
|
90
|
+
<select name="select-choice" id="select-choice">
|
91
|
+
<option value="Choice 1">Choice 1</option>
|
92
|
+
<option value="Choice 2">Choice 2</option>
|
93
|
+
<option value="Choice 3">Choice 3</option>
|
94
|
+
</select>
|
95
|
+
</div>
|
96
|
+
|
97
|
+
<div>
|
98
|
+
<label for="textarea">Textarea:</label>
|
99
|
+
<textarea cols="40" rows="8" name="textarea" id="textarea"></textarea>
|
100
|
+
</div>
|
101
|
+
|
102
|
+
<div>
|
103
|
+
<label for="checkbox">Checkbox:</label>
|
104
|
+
<input type="checkbox" name="checkbox" id="checkbox"/>
|
105
|
+
</div>
|
106
|
+
|
107
|
+
<div>
|
108
|
+
<input type="submit" value="Submit"/>
|
109
|
+
</div>
|
110
|
+
</form>
|
111
|
+
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>
|
112
|
+
<ol>
|
113
|
+
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
|
114
|
+
<li>Aliquam tincidunt mauris eu risus.</li>
|
115
|
+
<li>Vestibulum auctor dapibus neque.</li>
|
116
|
+
</ol>
|
117
|
+
<dl>
|
118
|
+
<dt>Definition list</dt>
|
119
|
+
<dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
|
120
|
+
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
121
|
+
commodo consequat.
|
122
|
+
</dd>
|
123
|
+
<dt>Lorem ipsum dolor sit amet</dt>
|
124
|
+
<dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
|
125
|
+
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
126
|
+
commodo consequat.
|
127
|
+
</dd>
|
128
|
+
</dl>
|
129
|
+
<nav>
|
130
|
+
<ul>
|
131
|
+
<li><a href="#nowhere" title="Lorum ipsum dolor sit amet">Lorem</a></li>
|
132
|
+
<li><a href="#nowhere" title="Aliquam tincidunt mauris eu risus">Aliquam</a></li>
|
133
|
+
<li><a href="#nowhere" title="Morbi in sem quis dui placerat ornare">Morbi</a></li>
|
134
|
+
<li><a href="#nowhere" title="Praesent dapibus, neque id cursus faucibus">Praesent</a></li>
|
135
|
+
<li><a href="#nowhere" title="Pellentesque fermentum dolor">Pellentesque</a></li>
|
136
|
+
</ul>
|
137
|
+
</nav>
|
138
|
+
<nav>
|
139
|
+
<ul>
|
140
|
+
<li><a href="#">Home</a></li>
|
141
|
+
<li><a href="#">About</a></li>
|
142
|
+
<li><a href="#">Clients</a></li>
|
143
|
+
<li><a href="#">Contact Us</a></li>
|
144
|
+
</ul>
|
145
|
+
</nav>
|
146
|
+
</body>
|
147
|
+
</html>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lapis_lazuli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Onno Steenbergen
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2017-
|
14
|
+
date: 2017-07-14 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -277,7 +277,10 @@ files:
|
|
277
277
|
- test/features/find.feature
|
278
278
|
- test/features/har.feature
|
279
279
|
- test/features/modules.feature
|
280
|
+
- test/features/multifind.feature
|
281
|
+
- test/features/screenshot.feature
|
280
282
|
- test/features/step_definitions/interaction_steps.rb
|
283
|
+
- test/features/step_definitions/multifind_steps.rb
|
281
284
|
- test/features/step_definitions/validation_steps.rb
|
282
285
|
- test/features/support/env.rb
|
283
286
|
- test/features/text_field.feature
|
@@ -289,6 +292,7 @@ files:
|
|
289
292
|
- test/server/www/error_html.html
|
290
293
|
- test/server/www/find.html
|
291
294
|
- test/server/www/javascript_error.html
|
295
|
+
- test/server/www/screenshot.html
|
292
296
|
- test/server/www/text_fields.html
|
293
297
|
- test/server/www/timing.html
|
294
298
|
- test/server/www/xpath.html
|
@@ -312,7 +316,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
312
316
|
version: '0'
|
313
317
|
requirements: []
|
314
318
|
rubyforge_project:
|
315
|
-
rubygems_version: 2.6.
|
319
|
+
rubygems_version: 2.6.12
|
316
320
|
signing_key:
|
317
321
|
specification_version: 4
|
318
322
|
summary: Cucumber helper functions and scaffolding for easier test automation suite
|
@@ -334,7 +338,10 @@ test_files:
|
|
334
338
|
- test/features/find.feature
|
335
339
|
- test/features/har.feature
|
336
340
|
- test/features/modules.feature
|
341
|
+
- test/features/multifind.feature
|
342
|
+
- test/features/screenshot.feature
|
337
343
|
- test/features/step_definitions/interaction_steps.rb
|
344
|
+
- test/features/step_definitions/multifind_steps.rb
|
338
345
|
- test/features/step_definitions/validation_steps.rb
|
339
346
|
- test/features/support/env.rb
|
340
347
|
- test/features/text_field.feature
|
@@ -346,6 +353,7 @@ test_files:
|
|
346
353
|
- test/server/www/error_html.html
|
347
354
|
- test/server/www/find.html
|
348
355
|
- test/server/www/javascript_error.html
|
356
|
+
- test/server/www/screenshot.html
|
349
357
|
- test/server/www/text_fields.html
|
350
358
|
- test/server/www/timing.html
|
351
359
|
- test/server/www/xpath.html
|