fluent 0.1.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 (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.travis.yml +14 -0
  4. data/Gemfile +5 -0
  5. data/HISTORY.md +19 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +40 -0
  8. data/Rakefile +13 -0
  9. data/fluent.gemspec +32 -0
  10. data/lib/fluent.rb +82 -0
  11. data/lib/fluent/errors.rb +8 -0
  12. data/lib/fluent/generators.rb +155 -0
  13. data/lib/fluent/logger.rb +5 -0
  14. data/lib/fluent/platform_watir.rb +18 -0
  15. data/lib/fluent/platform_watir/platform_object.rb +112 -0
  16. data/lib/fluent/platform_watir/platform_web_elements/select_list.rb +30 -0
  17. data/lib/fluent/platform_watir/platform_web_elements/web_element.rb +21 -0
  18. data/lib/fluent/platforms.rb +31 -0
  19. data/lib/fluent/version.rb +3 -0
  20. data/lib/fluent/web_elements/button.rb +16 -0
  21. data/lib/fluent/web_elements/checkbox.rb +16 -0
  22. data/lib/fluent/web_elements/link.rb +16 -0
  23. data/lib/fluent/web_elements/option.rb +16 -0
  24. data/lib/fluent/web_elements/paragraph.rb +16 -0
  25. data/lib/fluent/web_elements/radio.rb +16 -0
  26. data/lib/fluent/web_elements/select_list.rb +20 -0
  27. data/lib/fluent/web_elements/text_field.rb +16 -0
  28. data/lib/fluent/web_elements/web_element.rb +33 -0
  29. data/spec/fluent_spec.rb +9 -0
  30. data/spec/generators/button_generators_spec.rb +77 -0
  31. data/spec/generators/checkbox_generators_spec.rb +88 -0
  32. data/spec/generators/link_generators_spec.rb +64 -0
  33. data/spec/generators/paragraph_generators_spec.rb +65 -0
  34. data/spec/generators/radio_generators_spec.rb +85 -0
  35. data/spec/generators/select_list_generators_spec.rb +120 -0
  36. data/spec/generators/text_field_generators_spec.rb +81 -0
  37. data/spec/generators_spec.rb +42 -0
  38. data/spec/mock_app.rb +14 -0
  39. data/spec/platform_object_spec.rb +23 -0
  40. data/spec/spec_helper.rb +17 -0
  41. data/spec/web_element_spec.rb +23 -0
  42. data/spec/web_element_watir_spec.rb +32 -0
  43. metadata +183 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 517921e222ad7a40ccb585b10e1b951e014a8959
4
+ data.tar.gz: b4685be3d80ab1d3602f83fcbf0bfca5fde45ebd
5
+ SHA512:
6
+ metadata.gz: a390c6b5f7273ea9c881a52dfb4c357f6e839afdd1988d143979a82fc3e4b3374209a221ce238180c2c6085e6535d540947c1556f64c300f2e4f8973a836a3a9
7
+ data.tar.gz: e327f85cd71bc75d8364668b3c90d6cb98fb3397057132874f5aa1534e2548d18ebab0fa25f1cbeba11a6eac23745c2df5c4209b79030dac410cdf9dc86aac60
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .idea
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ output/
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
@@ -0,0 +1,14 @@
1
+ script: "rake"
2
+
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+
7
+ branches:
8
+ only:
9
+ - master
10
+ - develop
11
+
12
+ notifications:
13
+ recipients:
14
+ - jeffnyman@gmail.com
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'coveralls', require: false
4
+
5
+ gemspec
@@ -0,0 +1,19 @@
1
+ Change Log and History
2
+ ======================
3
+
4
+ Version 0.1.0 / 2013-10-18
5
+ --------------------------
6
+
7
+ Initial development release of Fluent. At this point, the basic moving parts have been put in place in order for the framework to be usable.
8
+
9
+ Fluent ...
10
+
11
+ * ... can be included in page or activity definitions.
12
+
13
+ * ... is able to create platform objects based on a driver library.
14
+
15
+ * ... allows element definitions to be created.
16
+
17
+ * ... uses generators to create actions based on element definitions.
18
+
19
+ At this point, the only test library supported is Watir-WebDriver. The web elements that Fluent can recognize are button, checkbox, link, paragraph, radio, select_list, and text_field. The assertions that Fluent allows are url_is and title_is.
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jeff Nyman
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,40 @@
1
+ Fluent
2
+ ======
3
+
4
+ [![Build Status](https://secure.travis-ci.org/jnyman/fluent.png)](http://travis-ci.org/jnyman/fluent)
5
+ [![Dependency Status](https://gemnasium.com/jnyman/fluent.png)](https://gemnasium.com/jnyman/fluent)
6
+ [![Gem Version](https://badge.fury.io/rb/fluent.png)](http://badge.fury.io/rb/fluent)
7
+ [![Coverage Status](https://coveralls.io/repos/jnyman/fluent/badge.png?branch=master)](https://coveralls.io/r/jnyman/fluent)
8
+
9
+ Fluent provides a semantic domain-specific language that can be used to construct a fluent interface for test execution libraries.
10
+
11
+ See the [Fluent wiki](https://github.com/jnyman/fluent/wiki) for details on how to use the framework.
12
+
13
+ Installation
14
+ ------------
15
+
16
+ Generally you will just install Fluent as a gem:
17
+
18
+ $ gem install fluent
19
+
20
+ If your application uses a Gemfile, add the following line to it:
21
+
22
+ gem 'fluent'
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ Contributing
29
+ ------------
30
+
31
+ 1. Fork the project.
32
+ 2. Create a branch for your change.
33
+ 3. Make your feature additions or bug fixes in your branch.
34
+ 4. Create unit tests (in spec) for your changes.
35
+ 5. Create acceptance tests (in specs) for your changes.
36
+ 6. Commit your changes.
37
+ 7. Push to the branch.
38
+ 8. Create a new [pull request](https://help.github.com/articles/using-pull-requests).
39
+
40
+ Do note that pull requests are very welcome and are considered better than bug reports. Please create a topic branch for every separate change that you make. When you make commits, do not change the rakefile, version or history information.
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new do |config|
6
+ options = %w(--color)
7
+ options += %w(--format documentation)
8
+ options += %w(--format nested --out output/fluent-test-report.txt)
9
+ options += %w(--format html --out output/fluent-test-report.html)
10
+ config.rspec_opts = options
11
+ end
12
+
13
+ task :default => :spec
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fluent/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'fluent'
8
+ spec.version = Fluent::VERSION
9
+ spec.author = 'Jeff Nyman'
10
+ spec.email = 'jeffnyman@gmail.com'
11
+ spec.description = %q{Provides a semantic DSL to construct a fluent interface for test execution libraries.}
12
+ spec.summary = %q{A Semantically Clean Fluent Interface Test Framework}
13
+ spec.homepage = 'https://github.com/jnyman/fluent'
14
+ spec.license = 'MIT'
15
+ spec.platform = Gem::Platform::RUBY
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = %w(lib)
21
+
22
+ spec.required_ruby_version = '>= 1.9.3'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.3'
25
+ spec.add_development_dependency 'rake'
26
+
27
+ spec.add_development_dependency 'rspec', '~> 2.0'
28
+ spec.add_development_dependency 'simplecov', '~> 0.7'
29
+
30
+ spec.add_runtime_dependency 'watir-webdriver', '0.6.4'
31
+ spec.add_runtime_dependency 'selenium-webdriver', '2.37.0'
32
+ end
@@ -0,0 +1,82 @@
1
+ require 'fluent/version'
2
+ require 'fluent/errors'
3
+ require 'fluent/logger'
4
+ require 'fluent/platforms'
5
+ require 'fluent/generators'
6
+
7
+ require 'watir-webdriver'
8
+ require 'selenium-webdriver'
9
+
10
+ module Fluent
11
+ include Platforms
12
+
13
+ # Browser drivers will be:
14
+ # [Watir::Browser] or [Selenium::WebDriver::Driver]
15
+ #
16
+ # @return [Object] browser driver reference
17
+ attr_reader :browser
18
+
19
+ # Platform references will be:
20
+ # [Fluent::Platforms::WatirWebDriver::PlatformObject]
21
+ # [Fluent::Platforms::SeleniumWebDriver::PlatformObject]
22
+ #
23
+ # @return [Object] platform reference
24
+ attr_reader :platform
25
+
26
+ def self.version
27
+ "Fluent v#{Fluent::VERSION}"
28
+ end
29
+
30
+ # The included callback is used to provide the core functionality of the
31
+ # library to any class or module that includes the Fluent library. The
32
+ # calling class or module is extended with logic that the library makes
33
+ # available as class methods. Those classes become page definitions or
34
+ # activity definitions.
35
+ #
36
+ # @param caller [Class] the class including the library
37
+ def self.included(caller)
38
+ caller.extend Fluent::Generators
39
+
40
+ Fluent.trace("#{caller.class} #{caller} is now Fluent.")
41
+ end
42
+
43
+ # The initialize method will be invoked when a definition includes Fluent.
44
+ # A few key things are happening here that are critical to everything
45
+ # working properly:
46
+ # (1) A browser instance is being created.
47
+ # (2) A platform object is created for that browser.
48
+ #
49
+ # @param browser [Object] a browser instance with a tool driver
50
+ def initialize(browser=nil)
51
+ @browser = browser
52
+ @browser = Watir::Browser.new if browser.nil? or browser == :watir
53
+ @browser = Selenium::WebDriver.for :firefox if browser == :selenium
54
+
55
+ Fluent::trace("Fluent attached to browser: #{@browser}")
56
+
57
+ establish_platform_object_for @browser
58
+ end
59
+
60
+ def self.can_be_enabled
61
+ @can_be_enabled ||= [:button, :text_field, :checkbox, :select_list, :radio]
62
+ end
63
+
64
+ def self.can_be_enabled?(method)
65
+ can_be_enabled.include? method.to_sym
66
+ end
67
+
68
+ private
69
+
70
+ # This method is crucial in that it sets up the platform instance that
71
+ # will be used by just about every module that makes calls to any
72
+ # platform-specific functionality.
73
+ #
74
+ # @param browser [Object] a browser instance with a tool driver
75
+ # @return [Object] a platform object to execute tests against
76
+ def establish_platform_object_for(browser)
77
+ @platform = get_platform_for browser
78
+
79
+ Fluent::trace("Fluent platform object: #{@platform}")
80
+ @platform
81
+ end
82
+ end
@@ -0,0 +1,8 @@
1
+ module Fluent
2
+ module Errors
3
+ class NoUrlForDefinition < StandardError; end
4
+ class NoTitleForDefinition < StandardError; end
5
+ class TitleNotMatched < StandardError; end
6
+ class UnableToCreatePlatform < StandardError; end
7
+ end
8
+ end
@@ -0,0 +1,155 @@
1
+ module Fluent
2
+ module Generators
3
+
4
+ def url_is(url=nil)
5
+ msg = "The url_is assertion is empty on the definition #{self}."
6
+ raise Fluent::Errors::NoUrlForDefinition, msg if url.nil?
7
+
8
+ define_method('view') do
9
+ platform.visit(url)
10
+ end
11
+ end
12
+
13
+ def title_is(title=nil)
14
+ msg = "The title_is assertion is empty on the definition #{self}."
15
+ raise Fluent::Errors::NoTitleForDefinition, msg if title.nil?
16
+
17
+ define_method('check_title') do
18
+ msg = "Expected title: '#{title}'; Actual title: '#{browser.title}'"
19
+ valid_title = title == browser.title if title.kind_of?(String)
20
+ valid_title = title =~ browser.title if title.kind_of?(Regexp)
21
+ raise Fluent::Errors::TitleNotMatched, msg unless valid_title
22
+ valid_title
23
+ end
24
+ end
25
+
26
+ def link(identifier, locator)
27
+ define_method(identifier) do
28
+ return platform.link_click(locator)
29
+ end
30
+
31
+ common_definition_methods(identifier, locator, __method__)
32
+ end
33
+
34
+ def paragraph(identifier, locator)
35
+ define_method(identifier) do
36
+ return platform.paragraph_text(locator)
37
+ end
38
+
39
+ common_definition_methods(identifier, locator, __method__)
40
+ end
41
+
42
+ def button(identifier, locator)
43
+ define_method(identifier) do
44
+ return platform.button_click(locator)
45
+ end
46
+
47
+ common_definition_methods(identifier, locator, __method__)
48
+ end
49
+
50
+ def text_field(identifier, locator)
51
+ define_method(identifier) do
52
+ return platform.text_field_get(locator)
53
+ end
54
+
55
+ define_method("#{identifier}=") do |value|
56
+ return platform.text_field_set(locator, value)
57
+ end
58
+
59
+ common_definition_methods(identifier, locator, __method__)
60
+ end
61
+
62
+ def checkbox(identifier, locator)
63
+ define_method("#{identifier}_checked?") do
64
+ return platform.checkbox_check_state(locator)
65
+ end
66
+
67
+ define_method("check_#{identifier}") do
68
+ return platform.checkbox_check(locator)
69
+ end
70
+
71
+ define_method("uncheck_#{identifier}") do
72
+ return platform.checkbox_uncheck(locator)
73
+ end
74
+
75
+ common_definition_methods(identifier, locator, __method__)
76
+ end
77
+
78
+ def select_list(identifier, locator)
79
+ define_method(identifier) do
80
+ return platform.select_list_get_selected(locator)
81
+ end
82
+
83
+ alias_method "#{identifier}_option?".to_sym, "#{identifier}".to_sym
84
+
85
+ define_method("#{identifier}=") do |value|
86
+ return platform.select_list_set(locator, value)
87
+ end
88
+
89
+ define_method("#{identifier}_options?") do
90
+ web_object = self.send("#{identifier}_object")
91
+ (web_object && web_object.options) ? web_object.options.collect(&:text) : []
92
+ end
93
+
94
+ define_method("#{identifier}_value?") do
95
+ return platform.select_list_get_value(locator)
96
+ end
97
+
98
+ common_definition_methods(identifier, locator, __method__)
99
+ end
100
+
101
+ def radio(identifier, locator)
102
+ define_method("select_#{identifier}") do
103
+ return platform.radio_select(locator)
104
+ end
105
+
106
+ define_method("#{identifier}_selected?") do
107
+ return platform.radio_check_state(locator)
108
+ end
109
+
110
+ alias_method "#{identifier}_set?".to_sym, "#{identifier}_selected?".to_sym
111
+ alias_method "set_#{identifier}".to_sym, "select_#{identifier}".to_sym
112
+
113
+ common_definition_methods(identifier, locator, __method__)
114
+ end
115
+
116
+ alias_method :radio_button, :radio
117
+
118
+ def common_definition_methods(identifier, locator, method)
119
+ define_method("#{identifier}_object") do
120
+ platform.send(method, locator)
121
+ end
122
+
123
+ define_method("#{identifier}_exists?") do
124
+ platform.send(method, locator).exists?
125
+ end
126
+
127
+ define_method("#{identifier}_visible?") do
128
+ platform.send(method, locator).visible?
129
+ end
130
+
131
+ alias_method "#{identifier}_#{method}".to_sym, "#{identifier}_object".to_sym
132
+ alias_method "#{identifier}_element".to_sym, "#{identifier}_object".to_sym
133
+
134
+ alias_method "#{identifier}?".to_sym, "#{identifier}_exists?".to_sym
135
+ alias_method "#{identifier}_?".to_sym, "#{identifier}_visible?".to_sym
136
+
137
+ alias_method "#{identifier}_#{method}_exists?".to_sym, "#{identifier}_exists?".to_sym
138
+ alias_method "#{identifier}_#{method}_visible?".to_sym, "#{identifier}_visible?".to_sym
139
+
140
+ alias_method "#{identifier}_#{method}?".to_sym, "#{identifier}_exists?".to_sym
141
+ alias_method "#{identifier}_#{method}_?".to_sym, "#{identifier}_visible?".to_sym
142
+
143
+ if Fluent.can_be_enabled?(method)
144
+ define_method("#{identifier}_enabled?") do
145
+ platform.send(method, locator).enabled?
146
+ end
147
+
148
+ alias_method "#{identifier}!".to_sym, "#{identifier}_enabled?".to_sym
149
+ alias_method "#{identifier}_#{method}_enabled?".to_sym, "#{identifier}_enabled?".to_sym
150
+ alias_method "#{identifier}_#{method}!".to_sym, "#{identifier}_exists?".to_sym
151
+ end
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,5 @@
1
+ module Fluent
2
+ def self.trace(message, level=1)
3
+ puts('*' * level + " #{message}") if ENV['FLUENT_TRACE'] == 'on'
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ module Fluent
2
+ module Platforms
3
+ module WatirWebDriver
4
+
5
+ def self.create_platform_object_for(browser)
6
+ require 'fluent/platform_watir/platform_object'
7
+ return WatirWebDriver::PlatformObject.new(browser)
8
+ end
9
+
10
+ def self.works_with?(browser)
11
+ browser.is_a?(::Watir::Browser)
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+
18
+ Fluent::Platforms.register(:watir_webdriver, Fluent::Platforms::WatirWebDriver)