lapis_lazuli 2.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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