fluent 0.1.0

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