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.
Files changed (54) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +1 -1
  3. data/lapis_lazuli.gemspec +10 -8
  4. data/lib/lapis_lazuli/api.rb +1 -1
  5. data/lib/lapis_lazuli/argparse.rb +1 -1
  6. data/lib/lapis_lazuli/browser.rb +37 -61
  7. data/lib/lapis_lazuli/browser/error.rb +89 -62
  8. data/lib/lapis_lazuli/browser/find.rb +1 -2
  9. data/lib/lapis_lazuli/cli.rb +1 -1
  10. data/lib/lapis_lazuli/cucumber.rb +1 -1
  11. data/lib/lapis_lazuli/generators/cucumber.rb +1 -1
  12. data/lib/lapis_lazuli/generators/cucumber/template/README.md +2 -0
  13. data/lib/lapis_lazuli/generators/cucumber/template/config/config.yml +6 -21
  14. data/lib/lapis_lazuli/generators/cucumber/template/config/cucumber.yml +42 -13
  15. data/lib/lapis_lazuli/generators/cucumber/template/config/users.yml +21 -0
  16. data/lib/lapis_lazuli/generators/cucumber/template/features/1_basic.feature +49 -0
  17. data/lib/lapis_lazuli/generators/cucumber/template/features/2_account.feature +38 -0
  18. data/lib/lapis_lazuli/generators/cucumber/template/features/3_todo_list.feature +23 -0
  19. data/lib/lapis_lazuli/generators/cucumber/template/features/helpers/authentication_helper.rb +122 -0
  20. data/lib/lapis_lazuli/generators/cucumber/template/features/helpers/navigation_helper.rb +64 -0
  21. data/lib/lapis_lazuli/generators/cucumber/template/features/helpers/registration_helper.rb +102 -0
  22. data/lib/lapis_lazuli/generators/cucumber/template/features/helpers/user_helper.rb +74 -0
  23. data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/account_steps.rb +60 -0
  24. data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/basic_steps.rb +70 -0
  25. data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/todo_steps.rb +27 -0
  26. data/lib/lapis_lazuli/generators/cucumber/template/features/support/env.rb +3 -2
  27. data/lib/lapis_lazuli/generic/xpath.rb +1 -1
  28. data/lib/lapis_lazuli/options.rb +3 -2
  29. data/lib/lapis_lazuli/placeholders.rb +1 -1
  30. data/lib/lapis_lazuli/proxy.rb +1 -1
  31. data/lib/lapis_lazuli/runtime.rb +1 -1
  32. data/lib/lapis_lazuli/scenario.rb +1 -1
  33. data/lib/lapis_lazuli/storage.rb +1 -1
  34. data/lib/lapis_lazuli/version.rb +2 -2
  35. data/lib/lapis_lazuli/versions.rb +1 -1
  36. data/lib/lapis_lazuli/world/config.rb +348 -334
  37. data/lib/lapis_lazuli/world/hooks.rb +85 -84
  38. data/lib/lapis_lazuli/world/logging.rb +1 -1
  39. data/test/Gemfile +2 -16
  40. data/test/config/config.yml +7 -6
  41. data/test/config/cucumber.yml +6 -8
  42. data/test/features/bindings.feature +1 -1
  43. data/test/features/browser.feature +1 -1
  44. data/test/features/step_definitions/interaction_steps.rb +5 -2
  45. data/test/features/step_definitions/validation_steps.rb +2 -2
  46. data/test/features/support/env.rb +21 -1
  47. data/test/results/latest_results.json +0 -0
  48. metadata +74 -28
  49. data/lib/lapis_lazuli/generators/cucumber/template/features/account.feature +0 -26
  50. data/lib/lapis_lazuli/generators/cucumber/template/features/example.feature +0 -30
  51. data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/interaction_steps.rb +0 -165
  52. data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/precondition_steps.rb +0 -63
  53. data/lib/lapis_lazuli/generators/cucumber/template/features/step_definitions/validation_steps.rb +0 -67
  54. 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 |
@@ -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
@@ -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
-
@@ -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