citronella 0.0.3 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66f8d6b39216fe199746a210493b62325bf34f0e02747978a7fe43481cd0441e
4
- data.tar.gz: 321d811f98c49faabc0b9d168d6ecb793a284d6dd794ba99cdcfe22c41d919c4
3
+ metadata.gz: c7ef1f78d05ad8a27657474af4a584e56c30921d217f863cd85fb06e163f358a
4
+ data.tar.gz: 3e8992f2bdec5de5479ed4b62ca2b42feabacfce598c736fb117a9f41ef79967
5
5
  SHA512:
6
- metadata.gz: 34e52701c765f24d210bc22b84cad46bf49821852c1c61815a3885da22190bb3b3fb221f371486a8c8e0ee428e7aaaba33c1c5de1735d3a7003b4de2e3e457b6
7
- data.tar.gz: 10fd8a98f877d3a1bbb71fa1de30c2292c58422feeec31cfb6a426e9f96294cff11966df5284f47b0bb839e107e7d0dff95ffea2f932c3a19bc6ae5b47e49ae2
6
+ metadata.gz: 9db842a70045cd3cd25592c9a18e27690aa3d22759b99abe7bc9823e16f49fe0cc1a5d45a3ab0c33381a41cb8728c3d844352ff8e9e520cdec64ea7b9f297889
7
+ data.tar.gz: c06316aef0e0343f3d3ee04598b481e047d5b0ef2c808750425e7cf3f76f766747247b00f2acbd11814f01c680228d48fa87b6551a549e197bd23b584d970b0e
data/Gemfile CHANGED
@@ -4,4 +4,5 @@ source "https://rubygems.org"
4
4
 
5
5
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6
6
 
7
- gem "selenium-webdriver"
7
+ gem 'selenium-webdriver'
8
+ gem 'test-unit'
data/README.md CHANGED
@@ -1,6 +1,221 @@
1
1
  # Citronella
2
2
 
3
- Webdriver extension with a page object wrapper.
3
+ [![Gem Version](https://badge.fury.io/rb/citronella.svg)](http://badge.fury.io/rb/citronella)
4
+
5
+ webdriver extension with a page object wrapper.
6
+
7
+ ## Example Tests
8
+ ```ruby
9
+ require 'test/unit'
10
+ require "selenium-webdriver"
11
+ require 'citronella'
12
+ require_relative '../pages/contents_page'
13
+
14
+
15
+ class NavigationTest < Test::Unit::TestCase
16
+ def setup
17
+ options = Selenium::WebDriver::Chrome::Options.new
18
+ driver = Selenium::WebDriver.for :chrome, options: options
19
+ @web = Citronella::Web::WebPage.new(driver)
20
+ @web.page = ContentsPage
21
+ @web.driver.navigate.to('https://rubygems.org')
22
+ end
23
+
24
+ def teardown
25
+ @web.driver.quit
26
+ end
27
+
28
+ def test_navigation
29
+ @web.page.home_page.releases_button.click
30
+ assert_includes(@web.driver.title, 'Releases')
31
+
32
+ @web.page.release_page.gems_button.click
33
+ assert_includes(@web.driver.title, 'Gem')
34
+
35
+ @web.page.gems_page.sign_in_button.click
36
+ assert_includes(@web.driver.title, 'Sign in')
37
+
38
+ @web.page.sign_in_page.sign_up_button.click
39
+ assert_includes(@web.driver.title, 'Sign up')
40
+
41
+ @web.page.sign_up_page.guides_button.click
42
+ assert_includes(@web.driver.title, 'Guides')
43
+
44
+ @web.page.guides_page.blog_button.click
45
+ assert_includes(@web.driver.title, 'Blog')
46
+ end
47
+ end
48
+ ```
49
+ Even though this module is mainly designed for the page object model, it can also be used without it for quick prototyping or mockups, etc.
50
+ ```ruby
51
+ require 'test/unit'
52
+ require "selenium-webdriver"
53
+ require 'citronella'
54
+
55
+
56
+ class PackageSearchTest < Test::Unit::TestCase
57
+ def setup
58
+ options = Selenium::WebDriver::Chrome::Options.new
59
+ driver = Selenium::WebDriver.for :chrome, options: options
60
+ @web = Citronella::Web::WebPage.new(driver)
61
+ end
62
+
63
+ def teardown
64
+ @web.driver.quit
65
+ end
66
+
67
+ def test_search_package
68
+ @web.driver.navigate.to "https://rubygems.org/"
69
+ @web.locate(id: 'home_query').get_element.send_keys('citronella')
70
+ @web.locate(class: 'home__search__icon').get_element.click
71
+ assert(@web.locate(class: 'gems__gem__name').get_element.text, 'citronella')
72
+ end
73
+ end
74
+ ```
75
+ ___
76
+ ## Install Package
77
+
78
+ ```bash
79
+ gem install citronella
80
+ ```
81
+
82
+ ___
83
+ ## Documentation
84
+
85
+ There are only two modules imported in this package:
86
+
87
+ * The first module is for the tests.
88
+
89
+ ```ruby
90
+ require 'test/unit'
91
+ require "selenium-webdriver"
92
+ require 'citronella'
93
+
94
+ class NavigationTest < Test::Unit::TestCase
95
+ def setup
96
+ options = Selenium::WebDriver::Chrome::Options.new
97
+ driver = Selenium::WebDriver.for :chrome, options: options
98
+ @web = Citronella::Web::WebPage.new(driver)
99
+ end
100
+
101
+ def teardown
102
+ @web.driver.quit
103
+ end
104
+ end
105
+ ```
106
+
107
+ * The last module is for the page object model.
108
+
109
+ ```ruby
110
+ require 'citronella'
111
+ require_relative '../components/header_menu'
112
+
113
+ class HomePage
114
+ include HeaderMenu
115
+
116
+ def search_button
117
+ ui(class: 'home__search__icon')
118
+ end
119
+
120
+ def code_link_button
121
+ ui(css: 'div.nav--v > a:nth-child(3)')
122
+ end
123
+ end
124
+ ```
125
+
126
+ ___
127
+ ## Page Object Design / Strategy
128
+ see full [Page object](https://github.com/heyclore/citronella/tree/main/ruby/examples/page_object/pages) example
129
+ ```ruby
130
+ require "selenium-webdriver"
131
+ require 'citronella'
132
+
133
+ module HeaderMenu
134
+ def home_logo
135
+ ui(class: 'header__logo')
136
+ end
137
+
138
+ def search_input
139
+ ui(id: 'home_query')
140
+ end
141
+
142
+ def gems_button
143
+ ui(css: 'a[href="/gems"]')
144
+ end
145
+ end
146
+
147
+ class HomePage
148
+ include HeaderMenu
149
+
150
+ def search_button
151
+ ui(class: 'home__search__icon')
152
+ end
153
+
154
+ def code_link_button
155
+ ui(css: 'div.nav--v > a:nth-child(3)')
156
+ end
157
+ end
158
+
159
+ class SearchPage
160
+ include HeaderMenu
161
+
162
+ def search_lists
163
+ ui(class: 'gems__gem__name')
164
+ end
165
+ end
166
+
167
+ class ContentsPage
168
+ def home_page
169
+ HomePage
170
+ end
171
+
172
+ def search_page
173
+ SearchPage
174
+ end
175
+ end
176
+
177
+ options = Selenium::WebDriver::Chrome::Options.new
178
+ driver = Selenium::WebDriver.for :chrome, options: options
179
+ web = Citronella::Web::WebPage.new(driver)
180
+ web.page = ContentsPage
181
+ web.driver.navigate.to('https://rubygems.org')
182
+ web.page.home_page.search_input.send_keys('citronella', return_key=true)
183
+ puts web.page.search_page.search_list.get_element.text
184
+ ```
185
+ ___
186
+ ## Usage
187
+
188
+ ### citronella.WebPage
189
+
190
+ ###### Args:
191
+ - driver / webdriver
192
+
193
+ ###### Kwargs (optional):
194
+ - webdriver_wait `number(seconds)`, default value is `10`
195
+ - logger `bool`, default value is `true`
196
+
197
+ ###### Method Lists:
198
+ | Method Name | Args* | Kwargs** | Note |
199
+ | ------------------ |:-----------:|:----------------:|:----:|
200
+ | driver | - | - | return selenium `webdriver` object |
201
+ | locate | - | how: what | similar as`driver.get_element` as input & return [citronella.WebUi](https://github.com/heyclore/citronella/tree/main/ruby#citronellaui--citronellawebui)|
202
+ | page | Page Object | - | setter |
203
+ | page | - | - | getter |
204
+ | webdriver_wait | number(sec) | - | |
205
+ | ready_state | number(sec) | - | execute javascript `document.readyState` manually |
206
+
207
+ ### citronella.ui / citronella.WebUi
208
+
209
+ ###### Kwargs:
210
+ - how: what
211
+
212
+ ###### Method Lists:
213
+ | Method Name | Args* | Kwargs** | Note |
214
+ | ------------- |:------:|:------------------:|:----:|
215
+ | send_keys | text | clear `bool`, return_key `bool` | |
216
+ | click | - | - | |
217
+ | get_element | - | - | |
218
+ | get_elements | - | - | |
4
219
 
5
220
 
6
221
  ## Testing powered by
data/citronella.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'citronella'
3
- s.version = '0.0.3'
3
+ s.version = '1.0.0'
4
4
 
5
5
  s.authors = ['heyclore']
6
6
  s.email = 'cloore@gmail.com'
@@ -10,9 +10,9 @@ Gem::Specification.new do |s|
10
10
  Webdriver extension with a page object wrapper
11
11
  DESCRIPTION
12
12
 
13
- s.licenses = 'GPL-2.0'
13
+ s.licenses = 'MIT'
14
14
  s.required_ruby_version = '>= 2.7.0'
15
- s.homepage = 'https://github.com/heyclore/citronella#readme'
15
+ s.homepage = 'https://github.com/heyclore/citronella/tree/main/ruby#readme'
16
16
  s.metadata = {
17
17
  'source_code_uri' => 'https://github.com/heyclore/citronella/tree/main/ruby',
18
18
  'github_repo' => 'https://github.com/heyclore/citronella',
data/lib/citronella.rb CHANGED
@@ -1,2 +1,25 @@
1
+ #MIT License
2
+ #
3
+ #Copyright (c) 2023 Eko Purnomo
4
+ #
5
+ #Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ #of this software and associated documentation files (the "Software"), to deal
7
+ #in the Software without restriction, including without limitation the rights
8
+ #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ #copies of the Software, and to permit persons to whom the Software is
10
+ #furnished to do so, subject to the following conditions:
11
+ #
12
+ #The above copyright notice and this permission notice shall be included in all
13
+ #copies or substantial portions of the Software.
14
+ #
15
+ #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ #SOFTWARE.
22
+
23
+
1
24
  require_relative 'web_page'
2
25
  require_relative 'ui'
data/lib/logger.rb ADDED
@@ -0,0 +1,41 @@
1
+ #MIT License
2
+ #
3
+ #Copyright (c) 2023 Eko Purnomo
4
+ #
5
+ #Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ #of this software and associated documentation files (the "Software"), to deal
7
+ #in the Software without restriction, including without limitation the rights
8
+ #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ #copies of the Software, and to permit persons to whom the Software is
10
+ #furnished to do so, subject to the following conditions:
11
+ #
12
+ #The above copyright notice and this permission notice shall be included in all
13
+ #copies or substantial portions of the Software.
14
+ #
15
+ #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ #SOFTWARE.
22
+
23
+
24
+ require 'logger'
25
+
26
+ module Citronella
27
+ module Log
28
+ # A wrapper for UI methods.
29
+ #
30
+ # @param [Boolean] logger Flag indicating whether to log actions.
31
+ # @param [String] class_name The name of the class.
32
+ # @param [String] function_name The name of the function.
33
+ # @param [String] name The name of the action.
34
+ #
35
+ def self.logger(logger, class_name, function_name, name)
36
+ if logger
37
+ Logger.new(STDOUT, level: Logger::INFO).info("#{class_name} => #{function_name} => #{name}")
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,58 @@
1
+ #MIT License
2
+ #
3
+ #Copyright (c) 2023 Eko Purnomo
4
+ #
5
+ #Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ #of this software and associated documentation files (the "Software"), to deal
7
+ #in the Software without restriction, including without limitation the rights
8
+ #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ #copies of the Software, and to permit persons to whom the Software is
10
+ #furnished to do so, subject to the following conditions:
11
+ #
12
+ #The above copyright notice and this permission notice shall be included in all
13
+ #copies or substantial portions of the Software.
14
+ #
15
+ #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ #SOFTWARE.
22
+
23
+
24
+ require_relative 'web_ui.rb'
25
+
26
+ module Citronella
27
+ module Wrapper
28
+ class PageDecorator
29
+ # A wrapper for page object class.
30
+ #
31
+ # @param [Webdriver] driver The web driver object.
32
+ # @param [Integer] webdriver_wait The timeout for webdriver wait.
33
+ # @param [PageObject] page The page object class.
34
+ # @param [Boolean] logger A flag indicating whether to log actions.
35
+ #
36
+ def initialize(driver, webdriver_wait, page, logger)
37
+ @driver = driver
38
+ @webdriver_wait = webdriver_wait
39
+ @page = page
40
+ @logger = logger
41
+ end
42
+
43
+ # Looks up the attribute/method name inside the page object.
44
+ #
45
+ # @return [PageDecorator, WebUi]
46
+ #
47
+ def method_missing(attr)
48
+ original_method = @page.new.method(attr)
49
+ args = original_method.call
50
+ if args.instance_of?(Class)
51
+ return PageDecorator.new(@driver, @webdriver_wait, args, @logger)
52
+ end
53
+ Citronella::Ui::WebUi.new(@driver, @webdriver_wait, @logger,
54
+ args, attr, @page.name)
55
+ end
56
+ end
57
+ end
58
+ end
data/lib/ui.rb CHANGED
@@ -1,4 +1,33 @@
1
+ #MIT License
2
+ #
3
+ #Copyright (c) 2023 Eko Purnomo
4
+ #
5
+ #Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ #of this software and associated documentation files (the "Software"), to deal
7
+ #in the Software without restriction, including without limitation the rights
8
+ #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ #copies of the Software, and to permit persons to whom the Software is
10
+ #furnished to do so, subject to the following conditions:
11
+ #
12
+ #The above copyright notice and this permission notice shall be included in all
13
+ #copies or substantial portions of the Software.
14
+ #
15
+ #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ #SOFTWARE.
22
+
23
+
24
+ # A wrapper for driver.find_element or driver.find_elements.
25
+ #
26
+ # @overload ui(args)
27
+ # @param locator [Symbol] The locator type.
28
+ # @param value [String] The locator value.
29
+ # @return [Citronella::Ui::WebUi] The web element object.
30
+ #
1
31
  def ui(args)
2
- baz = Struct.new(:page, :exception, :locator)
3
- baz.new(args.delete(:page), args.delete(:exception), args)
32
+ args
4
33
  end
data/lib/web_page.rb CHANGED
@@ -1,24 +1,112 @@
1
- require_relative 'page_store'
2
- require_relative 'page_wrapper'
1
+ #MIT License
2
+ #
3
+ #Copyright (c) 2023 Eko Purnomo
4
+ #
5
+ #Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ #of this software and associated documentation files (the "Software"), to deal
7
+ #in the Software without restriction, including without limitation the rights
8
+ #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ #copies of the Software, and to permit persons to whom the Software is
10
+ #furnished to do so, subject to the following conditions:
11
+ #
12
+ #The above copyright notice and this permission notice shall be included in all
13
+ #copies or substantial portions of the Software.
14
+ #
15
+ #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ #SOFTWARE.
22
+
23
+
24
+ require_relative 'page_decorator'
25
+ require_relative 'web_ui'
3
26
 
4
27
  module Citronella
5
- class WebPage
6
- def initialize(driver, webdriver_wait=10)
7
- @driver = driver
8
- @webdriver_wait = webdriver_wait
9
- @pages = Citronella::PagesStore::PagesList.new
10
- end
28
+ module Web
29
+ # An object class that is used across the tests.
30
+ # `webdriver_wait` is set to '10' seconds by default.
31
+ # `logger` is set to 'true' by default.
32
+ #
33
+ # @param [Webdriver] driver The web driver object.
34
+ # @param [Integer] webdriver_wait The timeout for webdriver wait.
35
+ # @param [Boolean] logger A flag indicating whether to log actions.
36
+ #
37
+ # Usage:
38
+ # driver = Selenium::WebDriver.for :chrome
39
+ # web = WebPage.new(driver)
40
+ #
41
+ class WebPage
42
+ def initialize(driver, webdriver_wait:10, logger:true)
43
+ @driver = driver
44
+ @webdriver_wait = webdriver_wait
45
+ @page = nil
46
+ @logger = logger
47
+ end
11
48
 
12
- def driver
13
- @driver
14
- end
49
+ # Returns the original Selenium driver.
50
+ #
51
+ # @return [Webdriver] The web driver object.
52
+ #
53
+ def driver
54
+ @driver
55
+ end
15
56
 
16
- def page_object(x)
17
- @pages.get << x
18
- end
57
+ # Returns the wrapped page object model.
58
+ #
59
+ # @return [Citronella::Wrapper::PageDecorator] The page object model.
60
+ #
61
+ def page
62
+ Citronella::Wrapper::PageDecorator.new(@driver, @webdriver_wait, @page,
63
+ @logger)
64
+ end
65
+
66
+ # Sets the page object model.
67
+ #
68
+ # @param [PageObject] page The page object model.
69
+ #
70
+ def page=(page)
71
+ @page = page
72
+ end
73
+
74
+ # An alternative way for testing without using page objects.
75
+ # It returns a WebUi class, but can't use `page` and may cause an error.
76
+ # It's good for quick prototypes or writing tests.
77
+ #
78
+ # @param [Hash] args The locator details.
79
+ # @return [Citronella::Ui::WebUi] The web element.
80
+ #
81
+ # Usage:
82
+ # web.ui(name: 'q').get_element.text
83
+ # web.ui(name: 'q').get_element.click
84
+ #
85
+ def locate(args)
86
+ Citronella::Ui::WebUi.new(@driver, @webdriver_wait, @logger, args,
87
+ __method__.to_s,
88
+ self.class.name.split('::').last.to_s)
89
+ end
90
+
91
+ # Executes JavaScript to wait for the page to fully load.
92
+ #
93
+ # @param [Integer] wait The number of times to check the page's ready state.
94
+ #
95
+ def ready_state(wait)
96
+ wait.times do |i|
97
+ return if driver.execute_script(
98
+ "return document.readyState") == "complete"
99
+ sleep(1)
100
+ end
101
+ end
19
102
 
20
- def page
21
- Citronella::PageWrapper.ui_decorator(@driver, @webdriver_wait, @pages)
103
+ # Overrides the `webdriver_wait` value.
104
+ #
105
+ # @param [Integer] wait The new value for `webdriver_wait`.
106
+ #
107
+ def webdriver_wait(wait)
108
+ @webdriver_wait = wait
109
+ end
22
110
  end
23
111
  end
24
112
  end
data/lib/web_ui.rb ADDED
@@ -0,0 +1,109 @@
1
+ #MIT License
2
+ #
3
+ #Copyright (c) 2023 Eko Purnomo
4
+ #
5
+ #Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ #of this software and associated documentation files (the "Software"), to deal
7
+ #in the Software without restriction, including without limitation the rights
8
+ #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ #copies of the Software, and to permit persons to whom the Software is
10
+ #furnished to do so, subject to the following conditions:
11
+ #
12
+ #The above copyright notice and this permission notice shall be included in all
13
+ #copies or substantial portions of the Software.
14
+ #
15
+ #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ #SOFTWARE.
22
+
23
+
24
+ require_relative 'logger'
25
+
26
+ module Citronella
27
+ module Ui
28
+ class WebUi
29
+ #
30
+ # @param [Webdriver] driver The web driver object.
31
+ # @param [Integer] webdriver_wait The timeout for webdriver wait.
32
+ # @param [Boolean] logger A flag indicating whether to log actions.
33
+ # @param [Hash] locator The locator for the web element.
34
+ # @param [String] function_name The name of the function.
35
+ # @param [String] class_name The name of the class.
36
+ #
37
+ def initialize(driver, webdriver_wait, logger, locator, function_name,
38
+ class_name)
39
+ @driver = driver
40
+ @wait = webdriver_wait
41
+ @logger = logger
42
+ @locator = locator
43
+ @function_name = function_name
44
+ @class_name = class_name
45
+ end
46
+
47
+ # Waits for a web element to be available and returns it.
48
+ #
49
+ # @param [Webdriver] ele The web driver object.
50
+ # @param [Boolean] displayed Flag indicating whether to wait for the element to be displayed.
51
+ # @return [Webdriver::Element] The web element.
52
+ #
53
+ private def webdriver_wait(ele, displayed=false)
54
+ el = Selenium::WebDriver::Wait.new(timeout: @wait).until { ele }
55
+ if displayed
56
+ @wait.times do
57
+ break if el.displayed?
58
+ sleep(1)
59
+ end
60
+ end
61
+ el
62
+ end
63
+
64
+ # Sends keys to the web element.
65
+ #
66
+ # @param [String] text The text to be sent.
67
+ # @param [Boolean] clear Flag indicating whether to clear the field before sending keys.
68
+ # @param [Boolean] return_key Flag indicating whether to send a return key.
69
+ #
70
+ def send_keys(text, clear=false, return_key=false)
71
+ Citronella::Log.logger(@logger, @class_name, @function_name, __method__)
72
+ el = webdriver_wait(@driver.find_element(@locator), displayed=true)
73
+ el.send_keys text
74
+
75
+ if return_key
76
+ el.send_keys :return
77
+ end
78
+ end
79
+
80
+ # Clicks on the web element.
81
+ #
82
+ def click
83
+ Citronella::Log.logger(@logger, @class_name, @function_name, __method__)
84
+ el = webdriver_wait(@driver.find_element(@locator), displayed=true)
85
+ el.click
86
+ end
87
+
88
+ # Returns a web element using find_element method.
89
+ #
90
+ # @return [Webdriver::Element] The web element.
91
+ #
92
+ def get_element
93
+ Citronella::Log.logger(@logger, @class_name, @function_name,
94
+ __method__.to_s)
95
+ webdriver_wait(@driver.find_element(@locator))
96
+ end
97
+
98
+ # Returns a list of web elements using find_elements method.
99
+ #
100
+ # @return [Array<Webdriver::Element>] The list of web elements.
101
+ #
102
+ def get_elements
103
+ Citronella::Log.logger(@logger, @class_name, @function_name,
104
+ __method__.to_s)
105
+ webdriver_wait(@driver.find_elements(@locator))
106
+ end
107
+ end
108
+ end
109
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: citronella
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - heyclore
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-07 00:00:00.000000000 Z
11
+ date: 2023-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: selenium-webdriver
@@ -34,14 +34,14 @@ files:
34
34
  - README.md
35
35
  - citronella.gemspec
36
36
  - lib/citronella.rb
37
- - lib/page_store.rb
38
- - lib/page_wrapper.rb
37
+ - lib/logger.rb
38
+ - lib/page_decorator.rb
39
39
  - lib/ui.rb
40
- - lib/ui_object.rb
41
40
  - lib/web_page.rb
42
- homepage: https://github.com/heyclore/citronella#readme
41
+ - lib/web_ui.rb
42
+ homepage: https://github.com/heyclore/citronella/tree/main/ruby#readme
43
43
  licenses:
44
- - GPL-2.0
44
+ - MIT
45
45
  metadata:
46
46
  source_code_uri: https://github.com/heyclore/citronella/tree/main/ruby
47
47
  github_repo: https://github.com/heyclore/citronella
data/lib/page_store.rb DELETED
@@ -1,17 +0,0 @@
1
- module Citronella
2
- module PagesStore
3
- class PagesList
4
- def initialize
5
- @page_lists = []
6
- end
7
-
8
- def get
9
- if @page_lists.length > 5
10
- @page_lists.shift
11
- end
12
- @page_lists
13
- end
14
- end
15
- end
16
- end
17
-
data/lib/page_wrapper.rb DELETED
@@ -1,30 +0,0 @@
1
- require_relative 'ui_object.rb'
2
-
3
- module Citronella
4
- module PageWrapper
5
- def self.method_wrapper(klass, method_name, driver, webdriver_wait, pages)
6
- original_method = klass.instance_method(method_name)
7
- klass.define_method(method_name) do
8
- puts method_name
9
- args = original_method.bind(self).call
10
- Citronella::UiObject::Ui.new(driver, webdriver_wait, pages,
11
- args.locator, args.page, args.exception)
12
- end
13
- end
14
-
15
- def self.class_decorator(klass, driver, webdriver_wait, pages)
16
- return if klass.instance_variable_defined?(:@decorated)
17
- klass.instance_variable_set(:@decorated, true)
18
- return if klass.name == "Object"
19
- lists = klass.instance_methods(false)
20
- lists.each { |method| method_wrapper(klass, method, driver, webdriver_wait, pages) }
21
- class_decorator(klass.superclass, driver, webdriver_wait, pages)
22
- end
23
-
24
- def self.ui_decorator(driver, webdriver_wait, pages)
25
- klass = pages.get.last
26
- class_decorator(klass, driver, webdriver_wait, pages)
27
- klass.new
28
- end
29
- end
30
- end
data/lib/ui_object.rb DELETED
@@ -1,43 +0,0 @@
1
- module Citronella
2
- module UiObject
3
- class Ui
4
- def initialize(driver, webdriver_wait, pages, locator, page, exception)
5
- @driver = driver
6
- @webdriver_wait = Selenium::WebDriver::Wait.new(timeout: webdriver_wait)
7
- @pages = pages
8
- @locator = locator
9
- @page = page
10
- @exception = exception
11
- end
12
-
13
- def send_keys(text, enter: false)
14
- @webdriver_wait.until { @driver.find_element(@locator).displayed? }
15
- el = @driver.find_element(@locator)
16
- el.send_keys text
17
-
18
- if enter
19
- el.send_keys :return
20
-
21
- if @page
22
- @pages.get << @page
23
- end
24
- end
25
- end
26
-
27
- def click
28
- @webdriver_wait.until { @driver.find_element(@locator).displayed? }
29
- @driver.find_element(@locator).click
30
-
31
- if @page
32
- @pages.get << @page
33
- end
34
- end
35
-
36
- def get_elements
37
- @webdriver_wait.until { @driver.find_element(@locator).displayed? }
38
- @driver.find_elements(@locator)
39
- end
40
- end
41
- end
42
- end
43
-