lapis_lazuli 2.0.1 → 3.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 +5 -5
- data/README.md +1 -1
- data/lapis_lazuli.gemspec +10 -8
- data/lib/lapis_lazuli/api.rb +1 -1
- data/lib/lapis_lazuli/argparse.rb +1 -1
- data/lib/lapis_lazuli/browser.rb +37 -61
- data/lib/lapis_lazuli/browser/error.rb +89 -62
- data/lib/lapis_lazuli/browser/find.rb +1 -2
- data/lib/lapis_lazuli/cli.rb +1 -1
- data/lib/lapis_lazuli/cucumber.rb +1 -1
- data/lib/lapis_lazuli/generators/cucumber.rb +1 -1
- data/lib/lapis_lazuli/generators/cucumber/template/README.md +2 -0
- data/lib/lapis_lazuli/generators/cucumber/template/config/config.yml +6 -21
- data/lib/lapis_lazuli/generators/cucumber/template/config/cucumber.yml +42 -13
- data/lib/lapis_lazuli/generators/cucumber/template/config/users.yml +21 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/1_basic.feature +49 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/2_account.feature +38 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/3_todo_list.feature +23 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/helpers/authentication_helper.rb +122 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/helpers/navigation_helper.rb +64 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/helpers/registration_helper.rb +102 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/helpers/user_helper.rb +74 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/account_steps.rb +60 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/basic_steps.rb +70 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/todo_steps.rb +27 -0
- data/lib/lapis_lazuli/generators/cucumber/template/features/support/env.rb +3 -2
- data/lib/lapis_lazuli/generic/xpath.rb +1 -1
- data/lib/lapis_lazuli/options.rb +3 -2
- data/lib/lapis_lazuli/placeholders.rb +1 -1
- data/lib/lapis_lazuli/proxy.rb +1 -1
- data/lib/lapis_lazuli/runtime.rb +1 -1
- data/lib/lapis_lazuli/scenario.rb +1 -1
- data/lib/lapis_lazuli/storage.rb +1 -1
- data/lib/lapis_lazuli/version.rb +2 -2
- data/lib/lapis_lazuli/versions.rb +1 -1
- data/lib/lapis_lazuli/world/config.rb +348 -334
- data/lib/lapis_lazuli/world/hooks.rb +85 -84
- data/lib/lapis_lazuli/world/logging.rb +1 -1
- data/test/Gemfile +2 -16
- data/test/config/config.yml +7 -6
- data/test/config/cucumber.yml +6 -8
- data/test/features/bindings.feature +1 -1
- data/test/features/browser.feature +1 -1
- data/test/features/step_definitions/interaction_steps.rb +5 -2
- data/test/features/step_definitions/validation_steps.rb +2 -2
- data/test/features/support/env.rb +21 -1
- data/test/results/latest_results.json +0 -0
- metadata +74 -28
- data/lib/lapis_lazuli/generators/cucumber/template/features/account.feature +0 -26
- data/lib/lapis_lazuli/generators/cucumber/template/features/example.feature +0 -30
- data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/interaction_steps.rb +0 -165
- data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/precondition_steps.rb +0 -63
- data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/validation_steps.rb +0 -67
- data/lib/lapis_lazuli/generators/cucumber/template/features/support/functions.rb +0 -68
@@ -1,26 +0,0 @@
|
|
1
|
-
@account
|
2
|
-
Feature: User accounts
|
3
|
-
This feature will make sure the user account functionality is working as expected
|
4
|
-
By checking registration, login and logout functionality
|
5
|
-
|
6
|
-
# This is a best practise example. Please note the following
|
7
|
-
# By defining a register, log-in and log-out state, we can easily re-use all these preconditions
|
8
|
-
# All the scenario's aren't completed, but it should be easy to implement it into your own project.
|
9
|
-
|
10
|
-
@account01 @log_in #@pause # You can add @pause to have a break between every step.
|
11
|
-
Scenario: account01 - Logging in
|
12
|
-
Given the user is logged out
|
13
|
-
When "default-user" logs in
|
14
|
-
Then the page should display as logged in state
|
15
|
-
|
16
|
-
@account02 @log_out
|
17
|
-
Scenario: account01 - Logging out
|
18
|
-
Given "default-user" is logged in
|
19
|
-
When the user clicks on the logout button
|
20
|
-
Then the page should display as logged out state
|
21
|
-
|
22
|
-
@account03 @registration
|
23
|
-
Scenario: account03 - Registation
|
24
|
-
Given the user is logged out
|
25
|
-
When "random-user" registers for a new account
|
26
|
-
Then the page should display as logged in state
|
@@ -1,30 +0,0 @@
|
|
1
|
-
@example @p
|
2
|
-
Feature: Example Feature
|
3
|
-
When I want to learn how to make test cases
|
4
|
-
As a user of the test automation tool
|
5
|
-
I want to run and adjust the tests below
|
6
|
-
|
7
|
-
@example01
|
8
|
-
Scenario: example01 - Spritecloud search
|
9
|
-
Given the user navigates to "blog"
|
10
|
-
When the user searches for "lapis lazuli"
|
11
|
-
Then text "Open Source" should display
|
12
|
-
|
13
|
-
@example02
|
14
|
-
Scenario: example02 - Going to a search result
|
15
|
-
Given the user has searched for "lapis lazuli" on "blog"
|
16
|
-
When the user clicks on link "/announcing-lapislazuli/"
|
17
|
-
Then text "Let's talk about testing" should display
|
18
|
-
|
19
|
-
@example03
|
20
|
-
Scenario Outline: example03 - checking multiple pages for the logo
|
21
|
-
Given the user navigates to "<page>"
|
22
|
-
When the user clicks on the spritecloud logo
|
23
|
-
Then the user should be on page "home"
|
24
|
-
Scenarios:
|
25
|
-
| page |
|
26
|
-
| blog |
|
27
|
-
| home |
|
28
|
-
| about-us |
|
29
|
-
| testing |
|
30
|
-
| functional-testing |
|
data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/interaction_steps.rb
DELETED
@@ -1,165 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# Copyright <%= config[:year] %> spriteCloud B.V. All rights reserved.
|
3
|
-
# Generated by LapisLazuli, version <%= config[:lapis_lazuli][:version] %>
|
4
|
-
# Author: "<%= config[:user] %>" <<%= config[:email] %>>
|
5
|
-
|
6
|
-
# interactions_steps.rb is used to interact with elements on the page.
|
7
|
-
|
8
|
-
Given(/^the user navigates to "(.*?)"$/) do |page|
|
9
|
-
# Get the value of the configuration (see /config/config.yml)
|
10
|
-
|
11
|
-
# First grab the root URL defined in the config
|
12
|
-
url = env('pages.root')
|
13
|
-
# Then add the page specific part to the URL
|
14
|
-
url += env("pages.#{page}")
|
15
|
-
|
16
|
-
# Go to the URL
|
17
|
-
browser.goto url
|
18
|
-
end
|
19
|
-
|
20
|
-
Given(/^the user navigates to the "(.*?)" page$/) do |page|
|
21
|
-
# Get the value of the configuration (see /config/config.yml)
|
22
|
-
url = env("#{page}")
|
23
|
-
|
24
|
-
# Go to the URL
|
25
|
-
browser.goto url
|
26
|
-
end
|
27
|
-
|
28
|
-
Given(/^the user searches for "(.*?)"$/) do |query|
|
29
|
-
# Get the input element
|
30
|
-
searchbox = browser.find(:text_field => {:name => "s"})
|
31
|
-
# Make sure the input field is empty
|
32
|
-
searchbox.clear rescue log.debug "Could not clear searchbox"
|
33
|
-
# Fill in the query
|
34
|
-
searchbox.send_keys(query)
|
35
|
-
# Press enter to submit the search
|
36
|
-
searchbox.send_keys(:enter)
|
37
|
-
end
|
38
|
-
|
39
|
-
When(/^the user clicks on link "(.*?)"$/) do |url|
|
40
|
-
# Search for the element that includes the expected text
|
41
|
-
browser.wait(
|
42
|
-
:like => {
|
43
|
-
:element => :a,
|
44
|
-
:attribute => :href,
|
45
|
-
:include => url
|
46
|
-
}
|
47
|
-
).click
|
48
|
-
end
|
49
|
-
|
50
|
-
When(/^the user clicks on the spritecloud logo$/) do
|
51
|
-
# Search for the logo
|
52
|
-
logo = browser.find(
|
53
|
-
:like => [:img, :id, 'logo'],
|
54
|
-
:message => 'Unable to find the logo on this page.'
|
55
|
-
)
|
56
|
-
# And click the logo
|
57
|
-
logo.click
|
58
|
-
end
|
59
|
-
|
60
|
-
# A step definition is a regex, to learn more about this go to http://rubular.com/
|
61
|
-
# The following step definition accepts both:
|
62
|
-
# - the user logs in > will use the last stored user data
|
63
|
-
# - "user-x" logs in > will load user data from config.yml
|
64
|
-
When(/^"?(.*?|the user)"? logs in$/) do |user_tag|
|
65
|
-
if user_tag != 'the user'
|
66
|
-
# Set the user data
|
67
|
-
set_user_data(user_tag)
|
68
|
-
end
|
69
|
-
# Fill in the user form
|
70
|
-
browser.find(
|
71
|
-
:like => [:input, :id, 'login-username']
|
72
|
-
).set(get_user_data('username'))
|
73
|
-
browser.find(
|
74
|
-
:like => [:input, :id, 'login-password']
|
75
|
-
).set(get_user_data('password'))
|
76
|
-
|
77
|
-
# Press the submit button
|
78
|
-
browser.find(
|
79
|
-
:like => [:button, :id, 'button-login']
|
80
|
-
).click
|
81
|
-
end
|
82
|
-
|
83
|
-
When(/^the user clicks on the logout button$/) do
|
84
|
-
# pending # This is an example
|
85
|
-
|
86
|
-
# First get the header to use as a context for the logout button
|
87
|
-
header = browser.wait(:like => [:nav, :class, 'navbar-fixed-top'])
|
88
|
-
|
89
|
-
# Then click the logout button (in this case, first a drop down needs to be clicked, before the logout button shows)
|
90
|
-
browser.find(
|
91
|
-
:like => [:a, :id, 'user_dropdown'],
|
92
|
-
:context => header,
|
93
|
-
:message => 'Unable to click on the user icon'
|
94
|
-
).click
|
95
|
-
dropdown = browser.wait(
|
96
|
-
:like => [:ul, :class, 'dropdown-menu'],
|
97
|
-
:timeout => 5,
|
98
|
-
:message => 'The user dropdown didn`t become present.'
|
99
|
-
)
|
100
|
-
browser.find(
|
101
|
-
:like => [:a, :id, 'link-logout'],
|
102
|
-
:context => dropdown,
|
103
|
-
:error => 'Failed to click the logout button.'
|
104
|
-
).click
|
105
|
-
end
|
106
|
-
|
107
|
-
When(/^"(.*?)" registers for a new account$/) do |user_tag|
|
108
|
-
# pending # Write code here that turns the phrase above into concrete actions
|
109
|
-
|
110
|
-
# Set the user data
|
111
|
-
set_user_data(user_tag)
|
112
|
-
|
113
|
-
# Go to the registration page
|
114
|
-
step 'the user navigates to the "training-page" page'
|
115
|
-
browser.find(:like => [:button, :id, 'button-register']).click
|
116
|
-
|
117
|
-
# Fill in the form
|
118
|
-
|
119
|
-
# Get the form container and use it as a context to find the fields
|
120
|
-
form = browser.wait(:like => [:form, :id, 'form-register'])
|
121
|
-
|
122
|
-
# Fill in the details
|
123
|
-
browser.find(:element => {:name => 'username'}, :context => form).set get_user_data('username')
|
124
|
-
browser.find(:element => {:name => 'password'}, :context => form).set get_user_data('password')
|
125
|
-
|
126
|
-
# Select gender
|
127
|
-
browser.find(
|
128
|
-
:label => {:text => /#{get_user_data('gender')}/i},
|
129
|
-
:context => form,
|
130
|
-
:message => "Unable to find gender `#{get_user_data('gender')}`, are you sure it's an option to select??"
|
131
|
-
).click
|
132
|
-
|
133
|
-
# Select experiences from the multi-select list
|
134
|
-
multi_selector = browser.find(:like => [:select, :id, "register-experience"], :context => form)
|
135
|
-
experiences = get_user_data('experience')
|
136
|
-
# Experiences is a list of words comma separated, EG `Ruby,Cucumber,Watir`
|
137
|
-
# The following function will cut text at every comma, and loop trough every separate word
|
138
|
-
experiences.split(',').each do |exp|
|
139
|
-
option = browser.find(
|
140
|
-
:option => {:value => /#{exp}/i},
|
141
|
-
:context => multi_selector
|
142
|
-
)
|
143
|
-
option.click
|
144
|
-
end
|
145
|
-
|
146
|
-
# Fill in the biagraphy
|
147
|
-
browser.find(
|
148
|
-
:like => [:textarea, :id, 'register-bio']
|
149
|
-
).send_keys(get_user_data('biography'))
|
150
|
-
|
151
|
-
# Click the accept policy checkbox
|
152
|
-
browser.find(:like => [:input, :id, 'register-complete-all']).click
|
153
|
-
|
154
|
-
# Press the submit button
|
155
|
-
browser.find(:button => {:id => 'button-save'}).click
|
156
|
-
|
157
|
-
# Wait for the success message to display
|
158
|
-
browser.wait(
|
159
|
-
:like => [:div, :class, 'alert-success'],
|
160
|
-
:message => 'The successfully registered message did not display.'
|
161
|
-
)
|
162
|
-
|
163
|
-
# The website we're testing on, doesn't log in the user automatically. So let's trigger that step manually
|
164
|
-
step 'the user logs in'
|
165
|
-
end
|
data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/precondition_steps.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# Copyright <%= config[:year] %> spriteCloud B.V. All rights reserved.
|
3
|
-
# Generated by LapisLazuli, version <%= config[:lapis_lazuli][:version] %>
|
4
|
-
# Author: "<%= config[:user] %>" <<%= config[:email] %>>
|
5
|
-
|
6
|
-
# precondition_steps.rb is used to define steps that contain multiple steps to come to a certain start of a scenrario.
|
7
|
-
# For example: "Given the user is logged in" will contain all steps done before logging in
|
8
|
-
|
9
|
-
Given(/^the user has searched for "(.*?)" on "(.*?)"$/) do |query, page|
|
10
|
-
# Run step to go to page
|
11
|
-
step "the user navigates to \"#{page}\""
|
12
|
-
# Run step to search
|
13
|
-
step "the user searches for \"#{query}\""
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
Given(/^the user is logged out$/) do
|
18
|
-
# In this step we want to make sure that the user is not logged in.
|
19
|
-
# If the user is not logged in, then this step does nothing, else it will trigger the logout step.
|
20
|
-
|
21
|
-
# Make this step independent by going to the homepage
|
22
|
-
step 'the user navigates to the "training-page" page'
|
23
|
-
|
24
|
-
# Check if the user is already logged in
|
25
|
-
loggedin = browser.find(
|
26
|
-
:like => [:img, :id, 'user-gravatar'],
|
27
|
-
:throw => false # This will prevent that the lookup will thow an error if it fails
|
28
|
-
)
|
29
|
-
if !loggedin.nil?
|
30
|
-
# Then try clicking the logout button
|
31
|
-
begin
|
32
|
-
step 'the user clicks on the logout button'
|
33
|
-
rescue Exception => e
|
34
|
-
# Ignoring the error, since it probably means we're already logged out.
|
35
|
-
log.debug "Logout failed, so I should already be logged out: #{e}"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
# And confirm we've successfully logged out
|
40
|
-
step 'the page should display as logged out state'
|
41
|
-
end
|
42
|
-
|
43
|
-
Given(/^(".*?"|the user) is logged in$/) do |user_tag|
|
44
|
-
# First, make sure we're not logged into another account
|
45
|
-
step 'the user is logged out'
|
46
|
-
# Note: This could be more efficient, often you're already logged in with the correct user.
|
47
|
-
# So a different solution would be to check if the correct user is already logged in:
|
48
|
-
# set_user_data(user_tag)
|
49
|
-
# logged_in? = browser.find(
|
50
|
-
# :span => {:text => get_user_data('username')},
|
51
|
-
# :throw => false
|
52
|
-
# )
|
53
|
-
# if logged_in? skip the rest
|
54
|
-
|
55
|
-
# Then follow the login steps
|
56
|
-
step "#{user_tag} logs in"
|
57
|
-
|
58
|
-
# And confirm the login was successful
|
59
|
-
step 'the page should display as logged in state'
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
|
-
|
data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/validation_steps.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# Copyright <%= config[:year] %> spriteCloud B.V. All rights reserved.
|
3
|
-
# Generated by LapisLazuli, version <%= config[:lapis_lazuli][:version] %>
|
4
|
-
# Author: "<%= config[:user] %>" <<%= config[:email] %>>
|
5
|
-
|
6
|
-
# validation_steps.rb is used to confirm that certain elements are displayed on the page.
|
7
|
-
|
8
|
-
Then(/^text "([^"]*)" should display$/) do |string|
|
9
|
-
# Note: The following is *really* slow, as it'll apply the regex to all
|
10
|
-
# elements in the page, one after the other. Of course, if any element
|
11
|
-
# includes the regex, all its parent elements also will, so you have
|
12
|
-
# tons of matches to process.
|
13
|
-
#
|
14
|
-
# browser.wait(:text => /#{string}/i)
|
15
|
-
|
16
|
-
# Instead, you will want to search only the root element for some
|
17
|
-
# text, e.g.
|
18
|
-
#
|
19
|
-
# browser.wait(:html => {:text => /#{string}/i})
|
20
|
-
|
21
|
-
# There's a shortcut for that in find/wait:
|
22
|
-
browser.wait(:html => /#{string}/i)
|
23
|
-
end
|
24
|
-
|
25
|
-
Then(/^the user should be on page "(.*?)"$/) do |page|
|
26
|
-
# Get the expected url
|
27
|
-
expected_url = env('pages.root')
|
28
|
-
expected_url += env("pages.#{page}")
|
29
|
-
|
30
|
-
# A custom loop that waits 5 seconds until the expected_url is the same as the current url
|
31
|
-
start = Time.now
|
32
|
-
while browser.url != expected_url
|
33
|
-
break if (Time.now - start).to_i >= 5
|
34
|
-
sleep(0.1)
|
35
|
-
end
|
36
|
-
|
37
|
-
# Check if they are the same
|
38
|
-
if browser.url != expected_url
|
39
|
-
error("The current URL and expected URL were not the same: \n Current: #{browser.url}\n Expected: #{expected_url}")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
Then(/^the page should display as logged (in|out) state$/) do |logged|
|
45
|
-
# pending # Write code here that turns the phrase above into concrete actions
|
46
|
-
|
47
|
-
# Adjust variable for checking logged in or logged out state.
|
48
|
-
if logged == 'in'
|
49
|
-
condition = :until
|
50
|
-
message = 'Unable to find profile picture, the user wasnt logged in successfully'
|
51
|
-
elsif logged == 'out'
|
52
|
-
condition = :while
|
53
|
-
message = 'The profile picture is present, indicating that the user did not log out successfully'
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
|
-
# Try to find a way to confirm that a user is logged out.
|
58
|
-
# Easiest way is to a reversed check on an element that is only present when you're logged in
|
59
|
-
# For example, the profile picture
|
60
|
-
browser.wait(
|
61
|
-
:img => {:class => 'user-gravatar'},
|
62
|
-
:condition => condition,
|
63
|
-
:timeout => 5,
|
64
|
-
:message => message
|
65
|
-
)
|
66
|
-
# Lapis lazuli will automatically create a screenshot if this step fails.
|
67
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
# Sometimes you're repeating a piece of code over and over again.
|
2
|
-
# At that point you should consider making it a function.
|
3
|
-
|
4
|
-
# Define a the user data to use.
|
5
|
-
def set_user_data(data)
|
6
|
-
# Load the user data from the configuration file
|
7
|
-
user_data = config("users.#{data}")
|
8
|
-
|
9
|
-
# Replace all random and time values in the data
|
10
|
-
user_data = replace_hash_constants(user_data)
|
11
|
-
|
12
|
-
# Put it in the global variable
|
13
|
-
$USER_DATA = user_data
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
# Get the data for the requested field.
|
18
|
-
def get_user_data(field)
|
19
|
-
# Make sure the user data is set before this function was called.
|
20
|
-
if $USER_DATA.nil?
|
21
|
-
error "No user data was set when get_user_data() was called for #{field}."
|
22
|
-
end
|
23
|
-
# Check if the specifically requested field is defined
|
24
|
-
if $USER_DATA[field].nil?
|
25
|
-
error "The requested user data `#{field}` does not exist. Are you sure it's defined in ./config/config.yml ?"
|
26
|
-
end
|
27
|
-
# Return te requested data
|
28
|
-
return $USER_DATA[field]
|
29
|
-
end
|
30
|
-
|
31
|
-
# Replace random or time values of a complete hash
|
32
|
-
def replace_hash_constants(hash)
|
33
|
-
if hash.respond_to? :each
|
34
|
-
new_hash = {}
|
35
|
-
hash.each do |key, value|
|
36
|
-
new_hash[key] = replace_constants(value)
|
37
|
-
end
|
38
|
-
else
|
39
|
-
new_hash = replace_constants(hash)
|
40
|
-
end
|
41
|
-
return new_hash
|
42
|
-
end
|
43
|
-
|
44
|
-
# replace certain constants in a string, for example '_TIMESTAMP_' becomes '154875631'
|
45
|
-
def replace_constants(value)
|
46
|
-
epoch = Time.now.to_i
|
47
|
-
alpha = number_to_letter(epoch)
|
48
|
-
timestamp = Time.now.strftime("D%Y-%M-%d-T%H-%M-%S")
|
49
|
-
value = value.to_s
|
50
|
-
old_val = value
|
51
|
-
value = value.sub('_RAND_', epoch.to_s)
|
52
|
-
value = value.sub('_TIMESTAMP_', timestamp)
|
53
|
-
value = value.sub('_RAND-ALPHA_', alpha)
|
54
|
-
unless value == old_val
|
55
|
-
log.debug "#{old_val} > #{value}"
|
56
|
-
end
|
57
|
-
return value
|
58
|
-
end
|
59
|
-
|
60
|
-
def number_to_letter(numbers)
|
61
|
-
num_string = numbers.to_s
|
62
|
-
alpha26 = ("a".."j").to_a
|
63
|
-
letters = ''
|
64
|
-
num_string.scan(/./).each do |number|
|
65
|
-
letters += alpha26[number.to_i]
|
66
|
-
end
|
67
|
-
return letters
|
68
|
-
end
|